aboutsummaryrefslogtreecommitdiff
path: root/sys/compat
diff options
context:
space:
mode:
Diffstat (limited to 'sys/compat')
-rw-r--r--sys/compat/cloudabi/cloudabi_clock.c135
-rw-r--r--sys/compat/cloudabi/cloudabi_errno.c123
-rw-r--r--sys/compat/cloudabi/cloudabi_fd.c475
-rw-r--r--sys/compat/cloudabi/cloudabi_file.c763
-rw-r--r--sys/compat/cloudabi/cloudabi_futex.c1165
-rw-r--r--sys/compat/cloudabi/cloudabi_mem.c167
-rw-r--r--sys/compat/cloudabi/cloudabi_proc.c148
-rw-r--r--sys/compat/cloudabi/cloudabi_proto.h36
-rw-r--r--sys/compat/cloudabi/cloudabi_random.c53
-rw-r--r--sys/compat/cloudabi/cloudabi_sock.c186
-rw-r--r--sys/compat/cloudabi/cloudabi_thread.c69
-rw-r--r--sys/compat/cloudabi/cloudabi_util.h87
-rw-r--r--sys/compat/cloudabi/cloudabi_vdso.c90
-rw-r--r--sys/compat/cloudabi/cloudabi_vdso.lds51
-rw-r--r--sys/compat/cloudabi32/Makefile6
-rw-r--r--sys/compat/cloudabi32/cloudabi32_fd.c145
-rw-r--r--sys/compat/cloudabi32/cloudabi32_module.c184
-rw-r--r--sys/compat/cloudabi32/cloudabi32_poll.c340
-rw-r--r--sys/compat/cloudabi32/cloudabi32_proto.h420
-rw-r--r--sys/compat/cloudabi32/cloudabi32_sock.c128
-rw-r--r--sys/compat/cloudabi32/cloudabi32_syscall.h57
-rw-r--r--sys/compat/cloudabi32/cloudabi32_syscalls.c58
-rw-r--r--sys/compat/cloudabi32/cloudabi32_sysent.c66
-rw-r--r--sys/compat/cloudabi32/cloudabi32_systrace_args.c1458
-rw-r--r--sys/compat/cloudabi32/cloudabi32_thread.c77
-rw-r--r--sys/compat/cloudabi32/cloudabi32_util.h51
-rw-r--r--sys/compat/cloudabi32/syscalls.conf15
-rw-r--r--sys/compat/cloudabi64/Makefile6
-rw-r--r--sys/compat/cloudabi64/cloudabi64_fd.c145
-rw-r--r--sys/compat/cloudabi64/cloudabi64_module.c184
-rw-r--r--sys/compat/cloudabi64/cloudabi64_poll.c340
-rw-r--r--sys/compat/cloudabi64/cloudabi64_proto.h420
-rw-r--r--sys/compat/cloudabi64/cloudabi64_sock.c128
-rw-r--r--sys/compat/cloudabi64/cloudabi64_syscall.h57
-rw-r--r--sys/compat/cloudabi64/cloudabi64_syscalls.c58
-rw-r--r--sys/compat/cloudabi64/cloudabi64_sysent.c66
-rw-r--r--sys/compat/cloudabi64/cloudabi64_systrace_args.c1458
-rw-r--r--sys/compat/cloudabi64/cloudabi64_thread.c77
-rw-r--r--sys/compat/cloudabi64/cloudabi64_util.h51
-rw-r--r--sys/compat/cloudabi64/syscalls.conf15
-rw-r--r--sys/compat/freebsd32/Makefile7
-rw-r--r--sys/compat/freebsd32/freebsd32.h432
-rw-r--r--sys/compat/freebsd32/freebsd32_capability.c157
-rw-r--r--sys/compat/freebsd32/freebsd32_ioctl.c247
-rw-r--r--sys/compat/freebsd32/freebsd32_ioctl.h63
-rw-r--r--sys/compat/freebsd32/freebsd32_ipc.h193
-rw-r--r--sys/compat/freebsd32/freebsd32_misc.c3845
-rw-r--r--sys/compat/freebsd32/freebsd32_misc.h49
-rw-r--r--sys/compat/freebsd32/freebsd32_proto.h1484
-rw-r--r--sys/compat/freebsd32/freebsd32_signal.h68
-rw-r--r--sys/compat/freebsd32/freebsd32_syscall.h509
-rw-r--r--sys/compat/freebsd32/freebsd32_syscalls.c619
-rw-r--r--sys/compat/freebsd32/freebsd32_sysent.c672
-rw-r--r--sys/compat/freebsd32/freebsd32_systrace_args.c11110
-rw-r--r--sys/compat/freebsd32/freebsd32_util.h127
-rw-r--r--sys/compat/freebsd32/syscalls.conf13
-rw-r--r--sys/compat/freebsd32/syscalls.master1178
-rw-r--r--sys/compat/ia32/ia32_genassym.c27
-rw-r--r--sys/compat/ia32/ia32_signal.h211
-rw-r--r--sys/compat/ia32/ia32_sysvec.c233
-rw-r--r--sys/compat/ia32/ia32_util.h59
-rw-r--r--sys/compat/lindebugfs/lindebugfs.c319
-rw-r--r--sys/compat/linprocfs/linprocfs.c2106
-rw-r--r--sys/compat/linsysfs/linsysfs.c708
-rw-r--r--sys/compat/linux/check_error.d144
-rw-r--r--sys/compat/linux/check_internal_locks.d97
-rw-r--r--sys/compat/linux/linux.c629
-rw-r--r--sys/compat/linux/linux.h208
-rw-r--r--sys/compat/linux/linux_common.c92
-rw-r--r--sys/compat/linux/linux_common.h45
-rw-r--r--sys/compat/linux/linux_dtrace.h92
-rw-r--r--sys/compat/linux/linux_dummy.c155
-rw-r--r--sys/compat/linux/linux_emul.c383
-rw-r--r--sys/compat/linux/linux_emul.h82
-rw-r--r--sys/compat/linux/linux_errno.c41
-rw-r--r--sys/compat/linux/linux_errno.h185
-rw-r--r--sys/compat/linux/linux_errno.inc329
-rw-r--r--sys/compat/linux/linux_event.c981
-rw-r--r--sys/compat/linux/linux_event.h71
-rw-r--r--sys/compat/linux/linux_file.c2024
-rw-r--r--sys/compat/linux/linux_file.h184
-rw-r--r--sys/compat/linux/linux_fork.c449
-rw-r--r--sys/compat/linux/linux_futex.c1319
-rw-r--r--sys/compat/linux/linux_futex.h86
-rw-r--r--sys/compat/linux/linux_getcwd.c84
-rw-r--r--sys/compat/linux/linux_ioctl.c3806
-rw-r--r--sys/compat/linux/linux_ioctl.h809
-rw-r--r--sys/compat/linux/linux_ipc.c930
-rw-r--r--sys/compat/linux/linux_ipc.h97
-rw-r--r--sys/compat/linux/linux_ipc64.h158
-rw-r--r--sys/compat/linux/linux_mib.c579
-rw-r--r--sys/compat/linux/linux_mib.h73
-rw-r--r--sys/compat/linux/linux_misc.c2643
-rw-r--r--sys/compat/linux/linux_misc.h188
-rw-r--r--sys/compat/linux/linux_mmap.c426
-rw-r--r--sys/compat/linux/linux_mmap.h73
-rw-r--r--sys/compat/linux/linux_persona.h56
-rw-r--r--sys/compat/linux/linux_signal.c744
-rw-r--r--sys/compat/linux/linux_signal.h51
-rw-r--r--sys/compat/linux/linux_socket.c2224
-rw-r--r--sys/compat/linux/linux_socket.h318
-rw-r--r--sys/compat/linux/linux_stats.c723
-rw-r--r--sys/compat/linux/linux_sysctl.c195
-rw-r--r--sys/compat/linux/linux_sysproto.h38
-rw-r--r--sys/compat/linux/linux_time.c655
-rw-r--r--sys/compat/linux/linux_timer.c168
-rw-r--r--sys/compat/linux/linux_timer.h118
-rw-r--r--sys/compat/linux/linux_uid16.c439
-rw-r--r--sys/compat/linux/linux_util.c321
-rw-r--r--sys/compat/linux/linux_util.h187
-rw-r--r--sys/compat/linux/linux_vdso.c244
-rw-r--r--sys/compat/linux/linux_vdso.h65
-rw-r--r--sys/compat/linux/linux_videodev2_compat.h137
-rw-r--r--sys/compat/linux/linux_videodev_compat.h59
-rw-r--r--sys/compat/linux/stats_timing.d93
-rw-r--r--sys/compat/linux/trace_futexes.d182
-rw-r--r--sys/compat/linuxkpi/common/include/acpi/acpi.h100
-rw-r--r--sys/compat/linuxkpi/common/include/acpi/acpi_bus.h52
-rw-r--r--sys/compat/linuxkpi/common/include/acpi/video.h38
-rw-r--r--sys/compat/linuxkpi/common/include/asm/atomic-long.h133
-rw-r--r--sys/compat/linuxkpi/common/include/asm/atomic.h320
-rw-r--r--sys/compat/linuxkpi/common/include/asm/atomic64.h148
-rw-r--r--sys/compat/linuxkpi/common/include/asm/byteorder.h94
-rw-r--r--sys/compat/linuxkpi/common/include/asm/fcntl.h36
-rw-r--r--sys/compat/linuxkpi/common/include/asm/fpu/api.h68
-rw-r--r--sys/compat/linuxkpi/common/include/asm/io.h36
-rw-r--r--sys/compat/linuxkpi/common/include/asm/msr.h37
-rw-r--r--sys/compat/linuxkpi/common/include/asm/pgtable.h43
-rw-r--r--sys/compat/linuxkpi/common/include/asm/smp.h48
-rw-r--r--sys/compat/linuxkpi/common/include/asm/types.h64
-rw-r--r--sys/compat/linuxkpi/common/include/asm/uaccess.h72
-rw-r--r--sys/compat/linuxkpi/common/include/asm/unaligned.h78
-rw-r--r--sys/compat/linuxkpi/common/include/linux/acpi.h46
-rw-r--r--sys/compat/linuxkpi/common/include/linux/atomic.h36
-rw-r--r--sys/compat/linuxkpi/common/include/linux/backlight.h94
-rw-r--r--sys/compat/linuxkpi/common/include/linux/bitfield.h105
-rw-r--r--sys/compat/linuxkpi/common/include/linux/bitmap.h354
-rw-r--r--sys/compat/linuxkpi/common/include/linux/bitops.h410
-rw-r--r--sys/compat/linuxkpi/common/include/linux/bottom_half.h34
-rw-r--r--sys/compat/linuxkpi/common/include/linux/cache.h37
-rw-r--r--sys/compat/linuxkpi/common/include/linux/cdev.h152
-rw-r--r--sys/compat/linuxkpi/common/include/linux/clocksource.h38
-rw-r--r--sys/compat/linuxkpi/common/include/linux/compat.h59
-rw-r--r--sys/compat/linuxkpi/common/include/linux/compiler.h117
-rw-r--r--sys/compat/linuxkpi/common/include/linux/completion.h69
-rw-r--r--sys/compat/linuxkpi/common/include/linux/dcache.h46
-rw-r--r--sys/compat/linuxkpi/common/include/linux/debugfs.h51
-rw-r--r--sys/compat/linuxkpi/common/include/linux/delay.h76
-rw-r--r--sys/compat/linuxkpi/common/include/linux/device.h608
-rw-r--r--sys/compat/linuxkpi/common/include/linux/dma-attrs.h56
-rw-r--r--sys/compat/linuxkpi/common/include/linux/dma-mapping.h294
-rw-r--r--sys/compat/linuxkpi/common/include/linux/dmapool.h85
-rw-r--r--sys/compat/linuxkpi/common/include/linux/dmi.h46
-rw-r--r--sys/compat/linuxkpi/common/include/linux/err.h83
-rw-r--r--sys/compat/linuxkpi/common/include/linux/errno.h62
-rw-r--r--sys/compat/linuxkpi/common/include/linux/etherdevice.h117
-rw-r--r--sys/compat/linuxkpi/common/include/linux/export.h33
-rw-r--r--sys/compat/linuxkpi/common/include/linux/file.h190
-rw-r--r--sys/compat/linuxkpi/common/include/linux/firmware.h105
-rw-r--r--sys/compat/linuxkpi/common/include/linux/fs.h304
-rw-r--r--sys/compat/linuxkpi/common/include/linux/gcd.h50
-rw-r--r--sys/compat/linuxkpi/common/include/linux/gfp.h187
-rw-r--r--sys/compat/linuxkpi/common/include/linux/hardirq.h43
-rw-r--r--sys/compat/linuxkpi/common/include/linux/hrtimer.h89
-rw-r--r--sys/compat/linuxkpi/common/include/linux/idr.h150
-rw-r--r--sys/compat/linuxkpi/common/include/linux/if_arp.h37
-rw-r--r--sys/compat/linuxkpi/common/include/linux/if_ether.h55
-rw-r--r--sys/compat/linuxkpi/common/include/linux/if_vlan.h59
-rw-r--r--sys/compat/linuxkpi/common/include/linux/in.h47
-rw-r--r--sys/compat/linuxkpi/common/include/linux/in6.h36
-rw-r--r--sys/compat/linuxkpi/common/include/linux/inetdevice.h93
-rw-r--r--sys/compat/linuxkpi/common/include/linux/interrupt.h215
-rw-r--r--sys/compat/linuxkpi/common/include/linux/io-mapping.h117
-rw-r--r--sys/compat/linuxkpi/common/include/linux/io.h481
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ioctl.h38
-rw-r--r--sys/compat/linuxkpi/common/include/linux/irq_work.h67
-rw-r--r--sys/compat/linuxkpi/common/include/linux/irqreturn.h40
-rw-r--r--sys/compat/linuxkpi/common/include/linux/jhash.h146
-rw-r--r--sys/compat/linuxkpi/common/include/linux/jiffies.h166
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kdev_t.h46
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kernel.h638
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kmod.h51
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kobject.h168
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kref.h131
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kthread.h73
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ktime.h259
-rw-r--r--sys/compat/linuxkpi/common/include/linux/list.h498
-rw-r--r--sys/compat/linuxkpi/common/include/linux/llist.h101
-rw-r--r--sys/compat/linuxkpi/common/include/linux/lockdep.h88
-rw-r--r--sys/compat/linuxkpi/common/include/linux/log2.h131
-rw-r--r--sys/compat/linuxkpi/common/include/linux/math64.h103
-rw-r--r--sys/compat/linuxkpi/common/include/linux/miscdevice.h76
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mm.h266
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mm_types.h82
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mod_devicetable.h72
-rw-r--r--sys/compat/linuxkpi/common/include/linux/module.h105
-rw-r--r--sys/compat/linuxkpi/common/include/linux/moduleparam.h133
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mutex.h176
-rw-r--r--sys/compat/linuxkpi/common/include/linux/net.h79
-rw-r--r--sys/compat/linuxkpi/common/include/linux/net_dim.h410
-rw-r--r--sys/compat/linuxkpi/common/include/linux/netdevice.h143
-rw-r--r--sys/compat/linuxkpi/common/include/linux/notifier.h57
-rw-r--r--sys/compat/linuxkpi/common/include/linux/numa.h36
-rw-r--r--sys/compat/linuxkpi/common/include/linux/overflow.h65
-rw-r--r--sys/compat/linuxkpi/common/include/linux/page.h96
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pagemap.h45
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pci.h1165
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pfn.h44
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pfn_t.h56
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pid.h70
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pm.h52
-rw-r--r--sys/compat/linuxkpi/common/include/linux/poll.h48
-rw-r--r--sys/compat/linuxkpi/common/include/linux/power_supply.h44
-rw-r--r--sys/compat/linuxkpi/common/include/linux/preempt.h43
-rw-r--r--sys/compat/linuxkpi/common/include/linux/prefetch.h36
-rw-r--r--sys/compat/linuxkpi/common/include/linux/printk.h130
-rw-r--r--sys/compat/linuxkpi/common/include/linux/radix-tree.h85
-rw-r--r--sys/compat/linuxkpi/common/include/linux/random.h72
-rw-r--r--sys/compat/linuxkpi/common/include/linux/rbtree.h101
-rw-r--r--sys/compat/linuxkpi/common/include/linux/rculist.h141
-rw-r--r--sys/compat/linuxkpi/common/include/linux/rcupdate.h120
-rw-r--r--sys/compat/linuxkpi/common/include/linux/refcount.h82
-rw-r--r--sys/compat/linuxkpi/common/include/linux/rwlock.h68
-rw-r--r--sys/compat/linuxkpi/common/include/linux/rwsem.h84
-rw-r--r--sys/compat/linuxkpi/common/include/linux/scatterlist.h536
-rw-r--r--sys/compat/linuxkpi/common/include/linux/sched.h198
-rw-r--r--sys/compat/linuxkpi/common/include/linux/semaphore.h70
-rw-r--r--sys/compat/linuxkpi/common/include/linux/seq_file.h88
-rw-r--r--sys/compat/linuxkpi/common/include/linux/shmem_fs.h55
-rw-r--r--sys/compat/linuxkpi/common/include/linux/shrinker.h56
-rw-r--r--sys/compat/linuxkpi/common/include/linux/sizes.h51
-rw-r--r--sys/compat/linuxkpi/common/include/linux/slab.h209
-rw-r--r--sys/compat/linuxkpi/common/include/linux/smp.h39
-rw-r--r--sys/compat/linuxkpi/common/include/linux/socket.h69
-rw-r--r--sys/compat/linuxkpi/common/include/linux/spinlock.h163
-rw-r--r--sys/compat/linuxkpi/common/include/linux/srcu.h56
-rw-r--r--sys/compat/linuxkpi/common/include/linux/string.h170
-rw-r--r--sys/compat/linuxkpi/common/include/linux/swap.h52
-rw-r--r--sys/compat/linuxkpi/common/include/linux/sysfs.h299
-rw-r--r--sys/compat/linuxkpi/common/include/linux/time.h135
-rw-r--r--sys/compat/linuxkpi/common/include/linux/timer.h94
-rw-r--r--sys/compat/linuxkpi/common/include/linux/types.h89
-rw-r--r--sys/compat/linuxkpi/common/include/linux/uaccess.h96
-rw-r--r--sys/compat/linuxkpi/common/include/linux/usb.h318
-rw-r--r--sys/compat/linuxkpi/common/include/linux/vmalloc.h43
-rw-r--r--sys/compat/linuxkpi/common/include/linux/wait.h313
-rw-r--r--sys/compat/linuxkpi/common/include/linux/wait_bit.h64
-rw-r--r--sys/compat/linuxkpi/common/include/linux/workqueue.h259
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ww_mutex.h144
-rw-r--r--sys/compat/linuxkpi/common/include/linux/xarray.h100
-rw-r--r--sys/compat/linuxkpi/common/include/net/if_inet6.h53
-rw-r--r--sys/compat/linuxkpi/common/include/net/ip.h103
-rw-r--r--sys/compat/linuxkpi/common/include/net/ipv6.h113
-rw-r--r--sys/compat/linuxkpi/common/include/net/netevent.h75
-rw-r--r--sys/compat/linuxkpi/common/include/net/tcp.h40
-rw-r--r--sys/compat/linuxkpi/common/src/linux_acpi.c243
-rw-r--r--sys/compat/linuxkpi/common/src/linux_compat.c2566
-rw-r--r--sys/compat/linuxkpi/common/src/linux_current.c263
-rw-r--r--sys/compat/linuxkpi/common/src/linux_devres.c226
-rw-r--r--sys/compat/linuxkpi/common/src/linux_dmi.c140
-rw-r--r--sys/compat/linuxkpi/common/src/linux_firmware.c178
-rw-r--r--sys/compat/linuxkpi/common/src/linux_fpu.c50
-rw-r--r--sys/compat/linuxkpi/common/src/linux_hrtimer.c122
-rw-r--r--sys/compat/linuxkpi/common/src/linux_idr.c809
-rw-r--r--sys/compat/linuxkpi/common/src/linux_kmod.c36
-rw-r--r--sys/compat/linuxkpi/common/src/linux_kthread.c167
-rw-r--r--sys/compat/linuxkpi/common/src/linux_lock.c173
-rw-r--r--sys/compat/linuxkpi/common/src/linux_page.c277
-rw-r--r--sys/compat/linuxkpi/common/src/linux_pci.c1107
-rw-r--r--sys/compat/linuxkpi/common/src/linux_radix.c385
-rw-r--r--sys/compat/linuxkpi/common/src/linux_rcu.c421
-rw-r--r--sys/compat/linuxkpi/common/src/linux_schedule.c432
-rw-r--r--sys/compat/linuxkpi/common/src/linux_seq_file.c156
-rw-r--r--sys/compat/linuxkpi/common/src/linux_shmemfs.c128
-rw-r--r--sys/compat/linuxkpi/common/src/linux_shrinker.c125
-rw-r--r--sys/compat/linuxkpi/common/src/linux_slab.c155
-rw-r--r--sys/compat/linuxkpi/common/src/linux_tasklet.c253
-rw-r--r--sys/compat/linuxkpi/common/src/linux_usb.c1720
-rw-r--r--sys/compat/linuxkpi/common/src/linux_work.c738
-rw-r--r--sys/compat/linuxkpi/common/src/linux_xarray.c391
-rw-r--r--sys/compat/x86bios/x86bios.c864
-rw-r--r--sys/compat/x86bios/x86bios.h157
282 files changed, 88664 insertions, 0 deletions
diff --git a/sys/compat/cloudabi/cloudabi_clock.c b/sys/compat/cloudabi/cloudabi_clock.c
new file mode 100644
index 000000000000..508640f950e5
--- /dev/null
+++ b/sys/compat/cloudabi/cloudabi_clock.c
@@ -0,0 +1,135 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/stdint.h>
+#include <sys/systm.h>
+#include <sys/syscallsubr.h>
+
+#include <contrib/cloudabi/cloudabi_types_common.h>
+
+#include <compat/cloudabi/cloudabi_proto.h>
+#include <compat/cloudabi/cloudabi_util.h>
+
+/* Converts a CloudABI clock ID to a FreeBSD clock ID. */
+static int
+cloudabi_convert_clockid(cloudabi_clockid_t in, clockid_t *out)
+{
+ switch (in) {
+ case CLOUDABI_CLOCK_MONOTONIC:
+ *out = CLOCK_MONOTONIC;
+ return (0);
+ case CLOUDABI_CLOCK_PROCESS_CPUTIME_ID:
+ *out = CLOCK_PROCESS_CPUTIME_ID;
+ return (0);
+ case CLOUDABI_CLOCK_REALTIME:
+ *out = CLOCK_REALTIME;
+ return (0);
+ case CLOUDABI_CLOCK_THREAD_CPUTIME_ID:
+ *out = CLOCK_THREAD_CPUTIME_ID;
+ return (0);
+ default:
+ return (EINVAL);
+ }
+}
+
+/* Converts a struct timespec to a CloudABI timestamp. */
+int
+cloudabi_convert_timespec(const struct timespec *in, cloudabi_timestamp_t *out)
+{
+ cloudabi_timestamp_t s, ns;
+
+ if (in->tv_sec < 0) {
+ /* Timestamps from before the Epoch cannot be expressed. */
+ *out = 0;
+ return (EOVERFLOW);
+ }
+ s = in->tv_sec;
+ ns = in->tv_nsec;
+ if (s > UINT64_MAX / 1000000000 ||
+ (s == UINT64_MAX / 1000000000 && ns > UINT64_MAX % 1000000000)) {
+ /* Addition of seconds and nanoseconds would overflow. */
+ *out = UINT64_MAX;
+ return (EOVERFLOW);
+ }
+ *out = s * 1000000000 + ns;
+ return (0);
+}
+
+/* Fetches the time value of a clock. */
+int
+cloudabi_clock_time_get(struct thread *td, cloudabi_clockid_t clock_id,
+ cloudabi_timestamp_t *ret)
+{
+ struct timespec ts;
+ int error;
+ clockid_t clockid;
+
+ error = cloudabi_convert_clockid(clock_id, &clockid);
+ if (error != 0)
+ return (error);
+ error = kern_clock_gettime(td, clockid, &ts);
+ if (error != 0)
+ return (error);
+ return (cloudabi_convert_timespec(&ts, ret));
+}
+
+int
+cloudabi_sys_clock_res_get(struct thread *td,
+ struct cloudabi_sys_clock_res_get_args *uap)
+{
+ struct timespec ts;
+ cloudabi_timestamp_t cts;
+ int error;
+ clockid_t clockid;
+
+ error = cloudabi_convert_clockid(uap->clock_id, &clockid);
+ if (error != 0)
+ return (error);
+ error = kern_clock_getres(td, clockid, &ts);
+ if (error != 0)
+ return (error);
+ error = cloudabi_convert_timespec(&ts, &cts);
+ if (error != 0)
+ return (error);
+ memcpy(td->td_retval, &cts, sizeof(cts));
+ return (0);
+}
+
+int
+cloudabi_sys_clock_time_get(struct thread *td,
+ struct cloudabi_sys_clock_time_get_args *uap)
+{
+ cloudabi_timestamp_t ts;
+ int error;
+
+ error = cloudabi_clock_time_get(td, uap->clock_id, &ts);
+ memcpy(td->td_retval, &ts, sizeof(ts));
+ return (error);
+}
diff --git a/sys/compat/cloudabi/cloudabi_errno.c b/sys/compat/cloudabi/cloudabi_errno.c
new file mode 100644
index 000000000000..10304bad4af5
--- /dev/null
+++ b/sys/compat/cloudabi/cloudabi_errno.c
@@ -0,0 +1,123 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include <contrib/cloudabi/cloudabi_types_common.h>
+
+#include <compat/cloudabi/cloudabi_util.h>
+
+/* Converts a FreeBSD errno to a CloudABI errno. */
+cloudabi_errno_t
+cloudabi_convert_errno(int error)
+{
+ static const int table[] = {
+ [E2BIG] = CLOUDABI_E2BIG,
+ [EACCES] = CLOUDABI_EACCES,
+ [EADDRINUSE] = CLOUDABI_EADDRINUSE,
+ [EADDRNOTAVAIL] = CLOUDABI_EADDRNOTAVAIL,
+ [EAFNOSUPPORT] = CLOUDABI_EAFNOSUPPORT,
+ [EAGAIN] = CLOUDABI_EAGAIN,
+ [EALREADY] = CLOUDABI_EALREADY,
+ [EBADF] = CLOUDABI_EBADF,
+ [EBADMSG] = CLOUDABI_EBADMSG,
+ [EBUSY] = CLOUDABI_EBUSY,
+ [ECANCELED] = CLOUDABI_ECANCELED,
+ [ECHILD] = CLOUDABI_ECHILD,
+ [ECONNABORTED] = CLOUDABI_ECONNABORTED,
+ [ECONNREFUSED] = CLOUDABI_ECONNREFUSED,
+ [ECONNRESET] = CLOUDABI_ECONNRESET,
+ [EDEADLK] = CLOUDABI_EDEADLK,
+ [EDESTADDRREQ] = CLOUDABI_EDESTADDRREQ,
+ [EDOM] = CLOUDABI_EDOM,
+ [EDQUOT] = CLOUDABI_EDQUOT,
+ [EEXIST] = CLOUDABI_EEXIST,
+ [EFAULT] = CLOUDABI_EFAULT,
+ [EFBIG] = CLOUDABI_EFBIG,
+ [EHOSTUNREACH] = CLOUDABI_EHOSTUNREACH,
+ [EIDRM] = CLOUDABI_EIDRM,
+ [EILSEQ] = CLOUDABI_EILSEQ,
+ [EINPROGRESS] = CLOUDABI_EINPROGRESS,
+ [EINTEGRITY] = CLOUDABI_EINVAL,
+ [EINTR] = CLOUDABI_EINTR,
+ [EINVAL] = CLOUDABI_EINVAL,
+ [EIO] = CLOUDABI_EIO,
+ [EISCONN] = CLOUDABI_EISCONN,
+ [EISDIR] = CLOUDABI_EISDIR,
+ [ELOOP] = CLOUDABI_ELOOP,
+ [EMFILE] = CLOUDABI_EMFILE,
+ [EMLINK] = CLOUDABI_EMLINK,
+ [EMSGSIZE] = CLOUDABI_EMSGSIZE,
+ [EMULTIHOP] = CLOUDABI_EMULTIHOP,
+ [ENAMETOOLONG] = CLOUDABI_ENAMETOOLONG,
+ [ENETDOWN] = CLOUDABI_ENETDOWN,
+ [ENETRESET] = CLOUDABI_ENETRESET,
+ [ENETUNREACH] = CLOUDABI_ENETUNREACH,
+ [ENFILE] = CLOUDABI_ENFILE,
+ [ENOBUFS] = CLOUDABI_ENOBUFS,
+ [ENODEV] = CLOUDABI_ENODEV,
+ [ENOENT] = CLOUDABI_ENOENT,
+ [ENOEXEC] = CLOUDABI_ENOEXEC,
+ [ENOLCK] = CLOUDABI_ENOLCK,
+ [ENOLINK] = CLOUDABI_ENOLINK,
+ [ENOMEM] = CLOUDABI_ENOMEM,
+ [ENOMSG] = CLOUDABI_ENOMSG,
+ [ENOPROTOOPT] = CLOUDABI_ENOPROTOOPT,
+ [ENOSPC] = CLOUDABI_ENOSPC,
+ [ENOSYS] = CLOUDABI_ENOSYS,
+ [ENOTCONN] = CLOUDABI_ENOTCONN,
+ [ENOTDIR] = CLOUDABI_ENOTDIR,
+ [ENOTEMPTY] = CLOUDABI_ENOTEMPTY,
+ [ENOTRECOVERABLE] = CLOUDABI_ENOTRECOVERABLE,
+ [ENOTSOCK] = CLOUDABI_ENOTSOCK,
+ [ENOTSUP] = CLOUDABI_ENOTSUP,
+ [ENOTTY] = CLOUDABI_ENOTTY,
+ [ENXIO] = CLOUDABI_ENXIO,
+ [EOVERFLOW] = CLOUDABI_EOVERFLOW,
+ [EOWNERDEAD] = CLOUDABI_EOWNERDEAD,
+ [EPERM] = CLOUDABI_EPERM,
+ [EPIPE] = CLOUDABI_EPIPE,
+ [EPROTO] = CLOUDABI_EPROTO,
+ [EPROTONOSUPPORT] = CLOUDABI_EPROTONOSUPPORT,
+ [EPROTOTYPE] = CLOUDABI_EPROTOTYPE,
+ [ERANGE] = CLOUDABI_ERANGE,
+ [EROFS] = CLOUDABI_EROFS,
+ [ESPIPE] = CLOUDABI_ESPIPE,
+ [ESRCH] = CLOUDABI_ESRCH,
+ [ESTALE] = CLOUDABI_ESTALE,
+ [ETIMEDOUT] = CLOUDABI_ETIMEDOUT,
+ [ETXTBSY] = CLOUDABI_ETXTBSY,
+ [EXDEV] = CLOUDABI_EXDEV,
+ [ENOTCAPABLE] = CLOUDABI_ENOTCAPABLE,
+ };
+
+ /* Unknown error: fall back to returning ENOSYS. */
+ if (error < 0 || error >= nitems(table) || table[error] == 0)
+ return (error == 0 ? 0 : CLOUDABI_ENOSYS);
+ return (table[error]);
+}
diff --git a/sys/compat/cloudabi/cloudabi_fd.c b/sys/compat/cloudabi/cloudabi_fd.c
new file mode 100644
index 000000000000..ba93db3c0bfd
--- /dev/null
+++ b/sys/compat/cloudabi/cloudabi_fd.c
@@ -0,0 +1,475 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/capsicum.h>
+#include <sys/fcntl.h>
+#include <sys/filedesc.h>
+#include <sys/proc.h>
+#include <sys/mman.h>
+#include <sys/socketvar.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysproto.h>
+#include <sys/systm.h>
+#include <sys/unistd.h>
+#include <sys/vnode.h>
+
+#include <contrib/cloudabi/cloudabi_types_common.h>
+
+#include <compat/cloudabi/cloudabi_proto.h>
+#include <compat/cloudabi/cloudabi_util.h>
+
+/* Translation between CloudABI and Capsicum rights. */
+#define RIGHTS_MAPPINGS \
+ MAPPING(CLOUDABI_RIGHT_FD_DATASYNC, CAP_FSYNC) \
+ MAPPING(CLOUDABI_RIGHT_FD_READ, CAP_READ) \
+ MAPPING(CLOUDABI_RIGHT_FD_SEEK, CAP_SEEK) \
+ MAPPING(CLOUDABI_RIGHT_FD_STAT_PUT_FLAGS, CAP_FCNTL) \
+ MAPPING(CLOUDABI_RIGHT_FD_SYNC, CAP_FSYNC) \
+ MAPPING(CLOUDABI_RIGHT_FD_TELL, CAP_SEEK_TELL) \
+ MAPPING(CLOUDABI_RIGHT_FD_WRITE, CAP_WRITE) \
+ MAPPING(CLOUDABI_RIGHT_FILE_ADVISE) \
+ MAPPING(CLOUDABI_RIGHT_FILE_ALLOCATE, CAP_WRITE) \
+ MAPPING(CLOUDABI_RIGHT_FILE_CREATE_DIRECTORY, CAP_MKDIRAT) \
+ MAPPING(CLOUDABI_RIGHT_FILE_CREATE_FILE, CAP_CREATE) \
+ MAPPING(CLOUDABI_RIGHT_FILE_LINK_SOURCE, CAP_LINKAT_SOURCE) \
+ MAPPING(CLOUDABI_RIGHT_FILE_LINK_TARGET, CAP_LINKAT_TARGET) \
+ MAPPING(CLOUDABI_RIGHT_FILE_OPEN, CAP_LOOKUP) \
+ MAPPING(CLOUDABI_RIGHT_FILE_READDIR, CAP_READ) \
+ MAPPING(CLOUDABI_RIGHT_FILE_READLINK, CAP_LOOKUP) \
+ MAPPING(CLOUDABI_RIGHT_FILE_RENAME_SOURCE, CAP_RENAMEAT_SOURCE) \
+ MAPPING(CLOUDABI_RIGHT_FILE_RENAME_TARGET, CAP_RENAMEAT_TARGET) \
+ MAPPING(CLOUDABI_RIGHT_FILE_STAT_FGET, CAP_FSTAT) \
+ MAPPING(CLOUDABI_RIGHT_FILE_STAT_FPUT_SIZE, CAP_FTRUNCATE) \
+ MAPPING(CLOUDABI_RIGHT_FILE_STAT_FPUT_TIMES, CAP_FUTIMES) \
+ MAPPING(CLOUDABI_RIGHT_FILE_STAT_GET, CAP_FSTATAT) \
+ MAPPING(CLOUDABI_RIGHT_FILE_STAT_PUT_TIMES, CAP_FUTIMESAT) \
+ MAPPING(CLOUDABI_RIGHT_FILE_SYMLINK, CAP_SYMLINKAT) \
+ MAPPING(CLOUDABI_RIGHT_FILE_UNLINK, CAP_UNLINKAT) \
+ MAPPING(CLOUDABI_RIGHT_MEM_MAP, CAP_MMAP) \
+ MAPPING(CLOUDABI_RIGHT_MEM_MAP_EXEC, CAP_MMAP_X) \
+ MAPPING(CLOUDABI_RIGHT_POLL_FD_READWRITE, CAP_EVENT) \
+ MAPPING(CLOUDABI_RIGHT_POLL_PROC_TERMINATE, CAP_EVENT) \
+ MAPPING(CLOUDABI_RIGHT_PROC_EXEC, CAP_FEXECVE) \
+ MAPPING(CLOUDABI_RIGHT_SOCK_SHUTDOWN, CAP_SHUTDOWN) \
+
+int
+cloudabi_sys_fd_close(struct thread *td, struct cloudabi_sys_fd_close_args *uap)
+{
+
+ return (kern_close(td, uap->fd));
+}
+
+int
+cloudabi_sys_fd_create1(struct thread *td,
+ struct cloudabi_sys_fd_create1_args *uap)
+{
+ struct filecaps fcaps = {};
+
+ switch (uap->type) {
+ case CLOUDABI_FILETYPE_SHARED_MEMORY:
+ cap_rights_init(&fcaps.fc_rights, CAP_FSTAT, CAP_FTRUNCATE,
+ CAP_MMAP_RWX);
+ return (kern_shm_open(td, SHM_ANON, O_RDWR | O_CLOEXEC, 0,
+ &fcaps));
+ default:
+ return (EINVAL);
+ }
+}
+
+int
+cloudabi_sys_fd_create2(struct thread *td,
+ struct cloudabi_sys_fd_create2_args *uap)
+{
+ int fds[2];
+ int error, type;
+
+ switch (uap->type) {
+ case CLOUDABI_FILETYPE_SOCKET_DGRAM:
+ type = SOCK_DGRAM;
+ break;
+ case CLOUDABI_FILETYPE_SOCKET_STREAM:
+ type = SOCK_STREAM;
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ error = kern_socketpair(td, AF_UNIX, type, 0, fds);
+ if (error == 0) {
+ td->td_retval[0] = fds[0];
+ td->td_retval[1] = fds[1];
+ }
+ return (0);
+}
+
+int
+cloudabi_sys_fd_datasync(struct thread *td,
+ struct cloudabi_sys_fd_datasync_args *uap)
+{
+
+ return (kern_fsync(td, uap->fd, false));
+}
+
+int
+cloudabi_sys_fd_dup(struct thread *td, struct cloudabi_sys_fd_dup_args *uap)
+{
+
+ return (kern_dup(td, FDDUP_NORMAL, 0, uap->from, 0));
+}
+
+int
+cloudabi_sys_fd_replace(struct thread *td,
+ struct cloudabi_sys_fd_replace_args *uap)
+{
+ int error;
+
+ /*
+ * CloudABI's equivalent to dup2(). CloudABI processes should
+ * not depend on hardcoded file descriptor layouts, but simply
+ * use the file descriptor numbers that are allocated by the
+ * kernel. Duplicating file descriptors to arbitrary numbers
+ * should not be done.
+ *
+ * Invoke kern_dup() with FDDUP_MUSTREPLACE, so that we return
+ * EBADF when duplicating to a nonexistent file descriptor. Also
+ * clear the return value, as this system call yields no return
+ * value.
+ */
+ error = kern_dup(td, FDDUP_MUSTREPLACE, 0, uap->from, uap->to);
+ td->td_retval[0] = 0;
+ return (error);
+}
+
+int
+cloudabi_sys_fd_seek(struct thread *td, struct cloudabi_sys_fd_seek_args *uap)
+{
+ int whence;
+
+ switch (uap->whence) {
+ case CLOUDABI_WHENCE_CUR:
+ whence = SEEK_CUR;
+ break;
+ case CLOUDABI_WHENCE_END:
+ whence = SEEK_END;
+ break;
+ case CLOUDABI_WHENCE_SET:
+ whence = SEEK_SET;
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ return (kern_lseek(td, uap->fd, uap->offset, whence));
+}
+
+/* Converts a file descriptor to a CloudABI file descriptor type. */
+cloudabi_filetype_t
+cloudabi_convert_filetype(const struct file *fp)
+{
+ struct socket *so;
+ struct vnode *vp;
+
+ switch (fp->f_type) {
+ case DTYPE_FIFO:
+ return (CLOUDABI_FILETYPE_SOCKET_STREAM);
+ case DTYPE_PIPE:
+ return (CLOUDABI_FILETYPE_SOCKET_STREAM);
+ case DTYPE_PROCDESC:
+ return (CLOUDABI_FILETYPE_PROCESS);
+ case DTYPE_SHM:
+ return (CLOUDABI_FILETYPE_SHARED_MEMORY);
+ case DTYPE_SOCKET:
+ so = fp->f_data;
+ switch (so->so_type) {
+ case SOCK_DGRAM:
+ return (CLOUDABI_FILETYPE_SOCKET_DGRAM);
+ case SOCK_STREAM:
+ return (CLOUDABI_FILETYPE_SOCKET_STREAM);
+ default:
+ return (CLOUDABI_FILETYPE_UNKNOWN);
+ }
+ case DTYPE_VNODE:
+ vp = fp->f_vnode;
+ switch (vp->v_type) {
+ case VBLK:
+ return (CLOUDABI_FILETYPE_BLOCK_DEVICE);
+ case VCHR:
+ return (CLOUDABI_FILETYPE_CHARACTER_DEVICE);
+ case VDIR:
+ return (CLOUDABI_FILETYPE_DIRECTORY);
+ case VFIFO:
+ return (CLOUDABI_FILETYPE_SOCKET_STREAM);
+ case VLNK:
+ return (CLOUDABI_FILETYPE_SYMBOLIC_LINK);
+ case VREG:
+ return (CLOUDABI_FILETYPE_REGULAR_FILE);
+ case VSOCK:
+ return (CLOUDABI_FILETYPE_SOCKET_STREAM);
+ default:
+ return (CLOUDABI_FILETYPE_UNKNOWN);
+ }
+ default:
+ return (CLOUDABI_FILETYPE_UNKNOWN);
+ }
+}
+
+/* Removes rights that conflict with the file descriptor type. */
+void
+cloudabi_remove_conflicting_rights(cloudabi_filetype_t filetype,
+ cloudabi_rights_t *base, cloudabi_rights_t *inheriting)
+{
+
+ /*
+ * CloudABI has a small number of additional rights bits to
+ * disambiguate between multiple purposes. Remove the bits that
+ * don't apply to the type of the file descriptor.
+ *
+ * As file descriptor access modes (O_ACCMODE) has been fully
+ * replaced by rights bits, CloudABI distinguishes between
+ * rights that apply to the file descriptor itself (base) versus
+ * rights of new file descriptors derived from them
+ * (inheriting). The code below approximates the pair by
+ * decomposing depending on the file descriptor type.
+ *
+ * We need to be somewhat accurate about which actions can
+ * actually be performed on the file descriptor, as functions
+ * like fcntl(fd, F_GETFL) are emulated on top of this.
+ */
+ switch (filetype) {
+ case CLOUDABI_FILETYPE_DIRECTORY:
+ *base &= CLOUDABI_RIGHT_FD_STAT_PUT_FLAGS |
+ CLOUDABI_RIGHT_FD_SYNC | CLOUDABI_RIGHT_FILE_ADVISE |
+ CLOUDABI_RIGHT_FILE_CREATE_DIRECTORY |
+ CLOUDABI_RIGHT_FILE_CREATE_FILE |
+ CLOUDABI_RIGHT_FILE_LINK_SOURCE |
+ CLOUDABI_RIGHT_FILE_LINK_TARGET |
+ CLOUDABI_RIGHT_FILE_OPEN |
+ CLOUDABI_RIGHT_FILE_READDIR |
+ CLOUDABI_RIGHT_FILE_READLINK |
+ CLOUDABI_RIGHT_FILE_RENAME_SOURCE |
+ CLOUDABI_RIGHT_FILE_RENAME_TARGET |
+ CLOUDABI_RIGHT_FILE_STAT_FGET |
+ CLOUDABI_RIGHT_FILE_STAT_FPUT_TIMES |
+ CLOUDABI_RIGHT_FILE_STAT_GET |
+ CLOUDABI_RIGHT_FILE_STAT_PUT_TIMES |
+ CLOUDABI_RIGHT_FILE_SYMLINK |
+ CLOUDABI_RIGHT_FILE_UNLINK |
+ CLOUDABI_RIGHT_POLL_FD_READWRITE;
+ *inheriting &= CLOUDABI_RIGHT_FD_DATASYNC |
+ CLOUDABI_RIGHT_FD_READ |
+ CLOUDABI_RIGHT_FD_SEEK |
+ CLOUDABI_RIGHT_FD_STAT_PUT_FLAGS |
+ CLOUDABI_RIGHT_FD_SYNC |
+ CLOUDABI_RIGHT_FD_TELL |
+ CLOUDABI_RIGHT_FD_WRITE |
+ CLOUDABI_RIGHT_FILE_ADVISE |
+ CLOUDABI_RIGHT_FILE_ALLOCATE |
+ CLOUDABI_RIGHT_FILE_CREATE_DIRECTORY |
+ CLOUDABI_RIGHT_FILE_CREATE_FILE |
+ CLOUDABI_RIGHT_FILE_LINK_SOURCE |
+ CLOUDABI_RIGHT_FILE_LINK_TARGET |
+ CLOUDABI_RIGHT_FILE_OPEN |
+ CLOUDABI_RIGHT_FILE_READDIR |
+ CLOUDABI_RIGHT_FILE_READLINK |
+ CLOUDABI_RIGHT_FILE_RENAME_SOURCE |
+ CLOUDABI_RIGHT_FILE_RENAME_TARGET |
+ CLOUDABI_RIGHT_FILE_STAT_FGET |
+ CLOUDABI_RIGHT_FILE_STAT_FPUT_SIZE |
+ CLOUDABI_RIGHT_FILE_STAT_FPUT_TIMES |
+ CLOUDABI_RIGHT_FILE_STAT_GET |
+ CLOUDABI_RIGHT_FILE_STAT_PUT_TIMES |
+ CLOUDABI_RIGHT_FILE_SYMLINK |
+ CLOUDABI_RIGHT_FILE_UNLINK |
+ CLOUDABI_RIGHT_MEM_MAP |
+ CLOUDABI_RIGHT_MEM_MAP_EXEC |
+ CLOUDABI_RIGHT_POLL_FD_READWRITE |
+ CLOUDABI_RIGHT_PROC_EXEC;
+ break;
+ case CLOUDABI_FILETYPE_PROCESS:
+ *base &= ~(CLOUDABI_RIGHT_FILE_ADVISE |
+ CLOUDABI_RIGHT_POLL_FD_READWRITE);
+ *inheriting = 0;
+ break;
+ case CLOUDABI_FILETYPE_REGULAR_FILE:
+ *base &= CLOUDABI_RIGHT_FD_DATASYNC |
+ CLOUDABI_RIGHT_FD_READ |
+ CLOUDABI_RIGHT_FD_SEEK |
+ CLOUDABI_RIGHT_FD_STAT_PUT_FLAGS |
+ CLOUDABI_RIGHT_FD_SYNC |
+ CLOUDABI_RIGHT_FD_TELL |
+ CLOUDABI_RIGHT_FD_WRITE |
+ CLOUDABI_RIGHT_FILE_ADVISE |
+ CLOUDABI_RIGHT_FILE_ALLOCATE |
+ CLOUDABI_RIGHT_FILE_STAT_FGET |
+ CLOUDABI_RIGHT_FILE_STAT_FPUT_SIZE |
+ CLOUDABI_RIGHT_FILE_STAT_FPUT_TIMES |
+ CLOUDABI_RIGHT_MEM_MAP |
+ CLOUDABI_RIGHT_MEM_MAP_EXEC |
+ CLOUDABI_RIGHT_POLL_FD_READWRITE |
+ CLOUDABI_RIGHT_PROC_EXEC;
+ *inheriting = 0;
+ break;
+ case CLOUDABI_FILETYPE_SHARED_MEMORY:
+ *base &= ~(CLOUDABI_RIGHT_FD_SEEK |
+ CLOUDABI_RIGHT_FD_TELL |
+ CLOUDABI_RIGHT_FILE_ADVISE |
+ CLOUDABI_RIGHT_FILE_ALLOCATE |
+ CLOUDABI_RIGHT_FILE_READDIR);
+ *inheriting = 0;
+ break;
+ case CLOUDABI_FILETYPE_SOCKET_DGRAM:
+ case CLOUDABI_FILETYPE_SOCKET_STREAM:
+ *base &= CLOUDABI_RIGHT_FD_READ |
+ CLOUDABI_RIGHT_FD_STAT_PUT_FLAGS |
+ CLOUDABI_RIGHT_FD_WRITE |
+ CLOUDABI_RIGHT_FILE_STAT_FGET |
+ CLOUDABI_RIGHT_POLL_FD_READWRITE |
+ CLOUDABI_RIGHT_SOCK_SHUTDOWN;
+ break;
+ default:
+ *inheriting = 0;
+ break;
+ }
+}
+
+/* Converts FreeBSD's Capsicum rights to CloudABI's set of rights. */
+static void
+convert_capabilities(const cap_rights_t *capabilities,
+ cloudabi_filetype_t filetype, cloudabi_rights_t *base,
+ cloudabi_rights_t *inheriting)
+{
+ cloudabi_rights_t rights;
+
+ /* Convert FreeBSD bits to CloudABI bits. */
+ rights = 0;
+#define MAPPING(cloudabi, ...) do { \
+ if (cap_rights_is_set(capabilities, ##__VA_ARGS__)) \
+ rights |= (cloudabi); \
+} while (0);
+ RIGHTS_MAPPINGS
+#undef MAPPING
+
+ *base = rights;
+ *inheriting = rights;
+ cloudabi_remove_conflicting_rights(filetype, base, inheriting);
+}
+
+int
+cloudabi_sys_fd_stat_get(struct thread *td,
+ struct cloudabi_sys_fd_stat_get_args *uap)
+{
+ cloudabi_fdstat_t fsb = {0};
+ struct file *fp;
+ cap_rights_t rights;
+ struct filecaps fcaps;
+ int error, oflags;
+
+ /* Obtain file descriptor properties. */
+ error = fget_cap(td, uap->fd, cap_rights_init(&rights), &fp,
+ &fcaps);
+ if (error != 0)
+ return (error);
+ oflags = OFLAGS(fp->f_flag);
+ fsb.fs_filetype = cloudabi_convert_filetype(fp);
+ fdrop(fp, td);
+
+ /* Convert file descriptor flags. */
+ if (oflags & O_APPEND)
+ fsb.fs_flags |= CLOUDABI_FDFLAG_APPEND;
+ if (oflags & O_NONBLOCK)
+ fsb.fs_flags |= CLOUDABI_FDFLAG_NONBLOCK;
+ if (oflags & O_SYNC)
+ fsb.fs_flags |= CLOUDABI_FDFLAG_SYNC;
+
+ /* Convert capabilities to CloudABI rights. */
+ convert_capabilities(&fcaps.fc_rights, fsb.fs_filetype,
+ &fsb.fs_rights_base, &fsb.fs_rights_inheriting);
+ filecaps_free(&fcaps);
+ return (copyout(&fsb, (void *)uap->buf, sizeof(fsb)));
+}
+
+/* Converts CloudABI rights to a set of Capsicum capabilities. */
+int
+cloudabi_convert_rights(cloudabi_rights_t in, cap_rights_t *out)
+{
+
+ cap_rights_init(out);
+#define MAPPING(cloudabi, ...) do { \
+ if (in & (cloudabi)) { \
+ cap_rights_set(out, ##__VA_ARGS__); \
+ in &= ~(cloudabi); \
+ } \
+} while (0);
+ RIGHTS_MAPPINGS
+#undef MAPPING
+ if (in != 0)
+ return (ENOTCAPABLE);
+ return (0);
+}
+
+int
+cloudabi_sys_fd_stat_put(struct thread *td,
+ struct cloudabi_sys_fd_stat_put_args *uap)
+{
+ cloudabi_fdstat_t fsb;
+ cap_rights_t rights;
+ int error, oflags;
+
+ error = copyin(uap->buf, &fsb, sizeof(fsb));
+ if (error != 0)
+ return (error);
+
+ if (uap->flags == CLOUDABI_FDSTAT_FLAGS) {
+ /* Convert flags. */
+ oflags = 0;
+ if (fsb.fs_flags & CLOUDABI_FDFLAG_APPEND)
+ oflags |= O_APPEND;
+ if (fsb.fs_flags & CLOUDABI_FDFLAG_NONBLOCK)
+ oflags |= O_NONBLOCK;
+ if (fsb.fs_flags & (CLOUDABI_FDFLAG_SYNC |
+ CLOUDABI_FDFLAG_DSYNC | CLOUDABI_FDFLAG_RSYNC))
+ oflags |= O_SYNC;
+ return (kern_fcntl(td, uap->fd, F_SETFL, oflags));
+ } else if (uap->flags == CLOUDABI_FDSTAT_RIGHTS) {
+ /* Convert rights. */
+ error = cloudabi_convert_rights(
+ fsb.fs_rights_base | fsb.fs_rights_inheriting, &rights);
+ if (error != 0)
+ return (error);
+ return (kern_cap_rights_limit(td, uap->fd, &rights));
+ }
+ return (EINVAL);
+}
+
+int
+cloudabi_sys_fd_sync(struct thread *td, struct cloudabi_sys_fd_sync_args *uap)
+{
+
+ return (kern_fsync(td, uap->fd, true));
+}
diff --git a/sys/compat/cloudabi/cloudabi_file.c b/sys/compat/cloudabi/cloudabi_file.c
new file mode 100644
index 000000000000..f7d93bc85cad
--- /dev/null
+++ b/sys/compat/cloudabi/cloudabi_file.c
@@ -0,0 +1,763 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/capsicum.h>
+#include <sys/dirent.h>
+#include <sys/fcntl.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/stat.h>
+#include <sys/syscallsubr.h>
+#include <sys/uio.h>
+#include <sys/vnode.h>
+
+#include <contrib/cloudabi/cloudabi_types_common.h>
+
+#include <compat/cloudabi/cloudabi_proto.h>
+#include <compat/cloudabi/cloudabi_util.h>
+
+#include <security/mac/mac_framework.h>
+
+static MALLOC_DEFINE(M_CLOUDABI_PATH, "cloudabipath", "CloudABI pathnames");
+
+/*
+ * Copying pathnames from userspace to kernelspace.
+ *
+ * Unlike most operating systems, CloudABI doesn't use null-terminated
+ * pathname strings. Processes always pass pathnames to the kernel by
+ * providing a base pointer and a length. This has a couple of reasons:
+ *
+ * - It makes it easier to use CloudABI in combination with programming
+ * languages other than C, that may use non-null terminated strings.
+ * - It allows for calling system calls on individual components of the
+ * pathname without modifying the input string.
+ *
+ * The function below copies in pathname strings and null-terminates it.
+ * It also ensure that the string itself does not contain any null
+ * bytes.
+ *
+ * TODO(ed): Add an abstraction to vfs_lookup.c that allows us to pass
+ * in unterminated pathname strings, so we can do away with
+ * the copying.
+ */
+
+static int
+copyin_path(const char *uaddr, size_t len, char **result)
+{
+ char *buf;
+ int error;
+
+ if (len >= PATH_MAX)
+ return (ENAMETOOLONG);
+ buf = malloc(len + 1, M_CLOUDABI_PATH, M_WAITOK);
+ error = copyin(uaddr, buf, len);
+ if (error != 0) {
+ free(buf, M_CLOUDABI_PATH);
+ return (error);
+ }
+ if (memchr(buf, '\0', len) != NULL) {
+ free(buf, M_CLOUDABI_PATH);
+ return (EINVAL);
+ }
+ buf[len] = '\0';
+ *result = buf;
+ return (0);
+}
+
+static void
+cloudabi_freestr(char *buf)
+{
+
+ free(buf, M_CLOUDABI_PATH);
+}
+
+int
+cloudabi_sys_file_advise(struct thread *td,
+ struct cloudabi_sys_file_advise_args *uap)
+{
+ int advice;
+
+ switch (uap->advice) {
+ case CLOUDABI_ADVICE_DONTNEED:
+ advice = POSIX_FADV_DONTNEED;
+ break;
+ case CLOUDABI_ADVICE_NOREUSE:
+ advice = POSIX_FADV_NOREUSE;
+ break;
+ case CLOUDABI_ADVICE_NORMAL:
+ advice = POSIX_FADV_NORMAL;
+ break;
+ case CLOUDABI_ADVICE_RANDOM:
+ advice = POSIX_FADV_RANDOM;
+ break;
+ case CLOUDABI_ADVICE_SEQUENTIAL:
+ advice = POSIX_FADV_SEQUENTIAL;
+ break;
+ case CLOUDABI_ADVICE_WILLNEED:
+ advice = POSIX_FADV_WILLNEED;
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ return (kern_posix_fadvise(td, uap->fd, uap->offset, uap->len, advice));
+}
+
+int
+cloudabi_sys_file_allocate(struct thread *td,
+ struct cloudabi_sys_file_allocate_args *uap)
+{
+
+ return (kern_posix_fallocate(td, uap->fd, uap->offset, uap->len));
+}
+
+int
+cloudabi_sys_file_create(struct thread *td,
+ struct cloudabi_sys_file_create_args *uap)
+{
+ char *path;
+ int error;
+
+ error = copyin_path(uap->path, uap->path_len, &path);
+ if (error != 0)
+ return (error);
+
+ /*
+ * CloudABI processes cannot interact with UNIX credentials and
+ * permissions. Depend on the umask that is set prior to
+ * execution to restrict the file permissions.
+ */
+ switch (uap->type) {
+ case CLOUDABI_FILETYPE_DIRECTORY:
+ error = kern_mkdirat(td, uap->fd, path, UIO_SYSSPACE, 0777);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ cloudabi_freestr(path);
+ return (error);
+}
+
+int
+cloudabi_sys_file_link(struct thread *td,
+ struct cloudabi_sys_file_link_args *uap)
+{
+ char *path1, *path2;
+ int error;
+
+ error = copyin_path(uap->path1, uap->path1_len, &path1);
+ if (error != 0)
+ return (error);
+ error = copyin_path(uap->path2, uap->path2_len, &path2);
+ if (error != 0) {
+ cloudabi_freestr(path1);
+ return (error);
+ }
+
+ error = kern_linkat(td, uap->fd1.fd, uap->fd2, path1, path2,
+ UIO_SYSSPACE, (uap->fd1.flags & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) ?
+ FOLLOW : NOFOLLOW);
+ cloudabi_freestr(path1);
+ cloudabi_freestr(path2);
+ return (error);
+}
+
+int
+cloudabi_sys_file_open(struct thread *td,
+ struct cloudabi_sys_file_open_args *uap)
+{
+ cloudabi_fdstat_t fds;
+ cap_rights_t rights;
+ struct filecaps fcaps = {};
+ struct nameidata nd;
+ struct file *fp;
+ struct vnode *vp;
+ char *path;
+ int error, fd, fflags;
+ bool read, write;
+
+ error = copyin(uap->fds, &fds, sizeof(fds));
+ if (error != 0)
+ return (error);
+
+ /* All the requested rights should be set on the descriptor. */
+ error = cloudabi_convert_rights(
+ fds.fs_rights_base | fds.fs_rights_inheriting, &rights);
+ if (error != 0)
+ return (error);
+ cap_rights_set_one(&rights, CAP_LOOKUP);
+
+ /* Convert rights to corresponding access mode. */
+ read = (fds.fs_rights_base & (CLOUDABI_RIGHT_FD_READ |
+ CLOUDABI_RIGHT_FILE_READDIR | CLOUDABI_RIGHT_MEM_MAP_EXEC)) != 0;
+ write = (fds.fs_rights_base & (CLOUDABI_RIGHT_FD_DATASYNC |
+ CLOUDABI_RIGHT_FD_WRITE | CLOUDABI_RIGHT_FILE_ALLOCATE |
+ CLOUDABI_RIGHT_FILE_STAT_FPUT_SIZE)) != 0;
+ fflags = write ? read ? FREAD | FWRITE : FWRITE : FREAD;
+
+ /* Convert open flags. */
+ if ((uap->oflags & CLOUDABI_O_CREAT) != 0) {
+ fflags |= O_CREAT;
+ cap_rights_set_one(&rights, CAP_CREATE);
+ }
+ if ((uap->oflags & CLOUDABI_O_DIRECTORY) != 0)
+ fflags |= O_DIRECTORY;
+ if ((uap->oflags & CLOUDABI_O_EXCL) != 0)
+ fflags |= O_EXCL;
+ if ((uap->oflags & CLOUDABI_O_TRUNC) != 0) {
+ fflags |= O_TRUNC;
+ cap_rights_set_one(&rights, CAP_FTRUNCATE);
+ }
+ if ((fds.fs_flags & CLOUDABI_FDFLAG_APPEND) != 0)
+ fflags |= O_APPEND;
+ if ((fds.fs_flags & CLOUDABI_FDFLAG_NONBLOCK) != 0)
+ fflags |= O_NONBLOCK;
+ if ((fds.fs_flags & (CLOUDABI_FDFLAG_SYNC | CLOUDABI_FDFLAG_DSYNC |
+ CLOUDABI_FDFLAG_RSYNC)) != 0) {
+ fflags |= O_SYNC;
+ cap_rights_set_one(&rights, CAP_FSYNC);
+ }
+ if ((uap->dirfd.flags & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) == 0)
+ fflags |= O_NOFOLLOW;
+ if (write && (fflags & (O_APPEND | O_TRUNC)) == 0)
+ cap_rights_set_one(&rights, CAP_SEEK);
+
+ /* Allocate new file descriptor. */
+ error = falloc_noinstall(td, &fp);
+ if (error != 0)
+ return (error);
+ fp->f_flag = fflags & FMASK;
+
+ /* Open path. */
+ error = copyin_path(uap->path, uap->path_len, &path);
+ if (error != 0) {
+ fdrop(fp, td);
+ return (error);
+ }
+ NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, uap->dirfd.fd,
+ &rights, td);
+ error = vn_open(&nd, &fflags, 0777 & ~td->td_proc->p_pd->pd_cmask, fp);
+ cloudabi_freestr(path);
+ if (error != 0) {
+ /* Custom operations provided. */
+ if (error == ENXIO && fp->f_ops != &badfileops)
+ goto success;
+
+ /*
+ * POSIX compliance: return ELOOP in case openat() is
+ * called on a symbolic link and O_NOFOLLOW is set.
+ */
+ if (error == EMLINK)
+ error = ELOOP;
+ fdrop(fp, td);
+ return (error);
+ }
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ filecaps_free(&nd.ni_filecaps);
+ fp->f_vnode = vp = nd.ni_vp;
+
+ /* Install vnode operations if no custom operations are provided. */
+ if (fp->f_ops == &badfileops) {
+ fp->f_seqcount[UIO_READ] = 1;
+ fp->f_seqcount[UIO_WRITE] = 1;
+ finit(fp, (fflags & FMASK) | (fp->f_flag & FHASLOCK),
+ DTYPE_VNODE, vp, &vnops);
+ }
+ VOP_UNLOCK(vp);
+
+ /* Truncate file. */
+ if (fflags & O_TRUNC) {
+ error = fo_truncate(fp, 0, td->td_ucred, td);
+ if (error != 0) {
+ fdrop(fp, td);
+ return (error);
+ }
+ }
+
+success:
+ /* Determine which Capsicum rights to set on the file descriptor. */
+ cloudabi_remove_conflicting_rights(cloudabi_convert_filetype(fp),
+ &fds.fs_rights_base, &fds.fs_rights_inheriting);
+ cloudabi_convert_rights(fds.fs_rights_base | fds.fs_rights_inheriting,
+ &fcaps.fc_rights);
+ if (cap_rights_is_set(&fcaps.fc_rights))
+ fcaps.fc_fcntls = CAP_FCNTL_SETFL;
+
+ error = finstall(td, fp, &fd, fflags, &fcaps);
+ fdrop(fp, td);
+ if (error != 0)
+ return (error);
+ td->td_retval[0] = fd;
+ return (0);
+}
+
+/* Converts a FreeBSD directory entry structure and writes it to userspace. */
+static int
+write_dirent(struct dirent *bde, cloudabi_dircookie_t cookie, struct uio *uio)
+{
+ cloudabi_dirent_t cde = {
+ .d_next = cookie,
+ .d_ino = bde->d_fileno,
+ .d_namlen = bde->d_namlen,
+ };
+ size_t len;
+ int error;
+
+ /* Convert file type. */
+ switch (bde->d_type) {
+ case DT_BLK:
+ cde.d_type = CLOUDABI_FILETYPE_BLOCK_DEVICE;
+ break;
+ case DT_CHR:
+ cde.d_type = CLOUDABI_FILETYPE_CHARACTER_DEVICE;
+ break;
+ case DT_DIR:
+ cde.d_type = CLOUDABI_FILETYPE_DIRECTORY;
+ break;
+ case DT_FIFO:
+ cde.d_type = CLOUDABI_FILETYPE_SOCKET_STREAM;
+ break;
+ case DT_LNK:
+ cde.d_type = CLOUDABI_FILETYPE_SYMBOLIC_LINK;
+ break;
+ case DT_REG:
+ cde.d_type = CLOUDABI_FILETYPE_REGULAR_FILE;
+ break;
+ case DT_SOCK:
+ /* The exact socket type cannot be derived. */
+ cde.d_type = CLOUDABI_FILETYPE_SOCKET_STREAM;
+ break;
+ default:
+ cde.d_type = CLOUDABI_FILETYPE_UNKNOWN;
+ break;
+ }
+
+ /* Write directory entry structure. */
+ len = sizeof(cde) < uio->uio_resid ? sizeof(cde) : uio->uio_resid;
+ error = uiomove(&cde, len, uio);
+ if (error != 0)
+ return (error);
+
+ /* Write filename. */
+ len = bde->d_namlen < uio->uio_resid ? bde->d_namlen : uio->uio_resid;
+ return (uiomove(bde->d_name, len, uio));
+}
+
+int
+cloudabi_sys_file_readdir(struct thread *td,
+ struct cloudabi_sys_file_readdir_args *uap)
+{
+ struct iovec iov = {
+ .iov_base = uap->buf,
+ .iov_len = uap->buf_len
+ };
+ struct uio uio = {
+ .uio_iov = &iov,
+ .uio_iovcnt = 1,
+ .uio_resid = iov.iov_len,
+ .uio_segflg = UIO_USERSPACE,
+ .uio_rw = UIO_READ,
+ .uio_td = td
+ };
+ struct file *fp;
+ struct vnode *vp;
+ void *readbuf;
+ cloudabi_dircookie_t offset;
+ int error;
+
+ /* Obtain directory vnode. */
+ error = getvnode(td, uap->fd, &cap_read_rights, &fp);
+ if (error != 0) {
+ if (error == EINVAL)
+ return (ENOTDIR);
+ return (error);
+ }
+ if ((fp->f_flag & FREAD) == 0) {
+ fdrop(fp, td);
+ return (EBADF);
+ }
+
+ /*
+ * Call VOP_READDIR() and convert resulting data until the user
+ * provided buffer is filled.
+ */
+ readbuf = malloc(MAXBSIZE, M_TEMP, M_WAITOK);
+ offset = uap->cookie;
+ vp = fp->f_vnode;
+ while (uio.uio_resid > 0) {
+ struct iovec readiov = {
+ .iov_base = readbuf,
+ .iov_len = MAXBSIZE
+ };
+ struct uio readuio = {
+ .uio_iov = &readiov,
+ .uio_iovcnt = 1,
+ .uio_rw = UIO_READ,
+ .uio_segflg = UIO_SYSSPACE,
+ .uio_td = td,
+ .uio_resid = MAXBSIZE,
+ .uio_offset = offset
+ };
+ struct dirent *bde;
+ unsigned long *cookies, *cookie;
+ size_t readbuflen;
+ int eof, ncookies;
+
+ /* Validate file type. */
+ vn_lock(vp, LK_SHARED | LK_RETRY);
+ if (vp->v_type != VDIR) {
+ VOP_UNLOCK(vp);
+ error = ENOTDIR;
+ goto done;
+ }
+#ifdef MAC
+ error = mac_vnode_check_readdir(td->td_ucred, vp);
+ if (error != 0) {
+ VOP_UNLOCK(vp);
+ goto done;
+ }
+#endif /* MAC */
+
+ /* Read new directory entries. */
+ cookies = NULL;
+ ncookies = 0;
+ error = VOP_READDIR(vp, &readuio, fp->f_cred, &eof,
+ &ncookies, &cookies);
+ VOP_UNLOCK(vp);
+ if (error != 0)
+ goto done;
+
+ /* Convert entries to CloudABI's format. */
+ readbuflen = MAXBSIZE - readuio.uio_resid;
+ bde = readbuf;
+ cookie = cookies;
+ while (readbuflen >= offsetof(struct dirent, d_name) &&
+ uio.uio_resid > 0 && ncookies > 0) {
+ /* Ensure that the returned offset always increases. */
+ if (readbuflen >= bde->d_reclen && bde->d_fileno != 0 &&
+ *cookie > offset) {
+ error = write_dirent(bde, *cookie, &uio);
+ if (error != 0) {
+ free(cookies, M_TEMP);
+ goto done;
+ }
+ }
+
+ if (offset < *cookie)
+ offset = *cookie;
+ ++cookie;
+ --ncookies;
+ readbuflen -= bde->d_reclen;
+ bde = (struct dirent *)((char *)bde + bde->d_reclen);
+ }
+ free(cookies, M_TEMP);
+ if (eof)
+ break;
+ }
+
+done:
+ fdrop(fp, td);
+ free(readbuf, M_TEMP);
+ if (error != 0)
+ return (error);
+
+ /* Return number of bytes copied to userspace. */
+ td->td_retval[0] = uap->buf_len - uio.uio_resid;
+ return (0);
+}
+
+int
+cloudabi_sys_file_readlink(struct thread *td,
+ struct cloudabi_sys_file_readlink_args *uap)
+{
+ char *path;
+ int error;
+
+ error = copyin_path(uap->path, uap->path_len, &path);
+ if (error != 0)
+ return (error);
+
+ error = kern_readlinkat(td, uap->fd, path, UIO_SYSSPACE,
+ uap->buf, UIO_USERSPACE, uap->buf_len);
+ cloudabi_freestr(path);
+ return (error);
+}
+
+int
+cloudabi_sys_file_rename(struct thread *td,
+ struct cloudabi_sys_file_rename_args *uap)
+{
+ char *old, *new;
+ int error;
+
+ error = copyin_path(uap->path1, uap->path1_len, &old);
+ if (error != 0)
+ return (error);
+ error = copyin_path(uap->path2, uap->path2_len, &new);
+ if (error != 0) {
+ cloudabi_freestr(old);
+ return (error);
+ }
+
+ error = kern_renameat(td, uap->fd1, old, uap->fd2, new,
+ UIO_SYSSPACE);
+ cloudabi_freestr(old);
+ cloudabi_freestr(new);
+ return (error);
+}
+
+/* Converts a FreeBSD stat structure to a CloudABI stat structure. */
+static void
+convert_stat(const struct stat *sb, cloudabi_filestat_t *csb)
+{
+ cloudabi_filestat_t res = {
+ .st_dev = sb->st_dev,
+ .st_ino = sb->st_ino,
+ .st_nlink = sb->st_nlink,
+ .st_size = sb->st_size,
+ };
+
+ cloudabi_convert_timespec(&sb->st_atim, &res.st_atim);
+ cloudabi_convert_timespec(&sb->st_mtim, &res.st_mtim);
+ cloudabi_convert_timespec(&sb->st_ctim, &res.st_ctim);
+ *csb = res;
+}
+
+int
+cloudabi_sys_file_stat_fget(struct thread *td,
+ struct cloudabi_sys_file_stat_fget_args *uap)
+{
+ struct stat sb;
+ cloudabi_filestat_t csb;
+ struct file *fp;
+ cloudabi_filetype_t filetype;
+ int error;
+
+ memset(&csb, 0, sizeof(csb));
+
+ /* Fetch file descriptor attributes. */
+ error = fget(td, uap->fd, &cap_fstat_rights, &fp);
+ if (error != 0)
+ return (error);
+ error = fo_stat(fp, &sb, td->td_ucred, td);
+ if (error != 0) {
+ fdrop(fp, td);
+ return (error);
+ }
+ filetype = cloudabi_convert_filetype(fp);
+ fdrop(fp, td);
+
+ /* Convert attributes to CloudABI's format. */
+ convert_stat(&sb, &csb);
+ csb.st_filetype = filetype;
+ return (copyout(&csb, uap->buf, sizeof(csb)));
+}
+
+/* Converts timestamps to arguments to futimens() and utimensat(). */
+static void
+convert_utimens_arguments(const cloudabi_filestat_t *fs,
+ cloudabi_fsflags_t flags, struct timespec *ts)
+{
+
+ if ((flags & CLOUDABI_FILESTAT_ATIM_NOW) != 0) {
+ ts[0].tv_nsec = UTIME_NOW;
+ } else if ((flags & CLOUDABI_FILESTAT_ATIM) != 0) {
+ ts[0].tv_sec = fs->st_atim / 1000000000;
+ ts[0].tv_nsec = fs->st_atim % 1000000000;
+ } else {
+ ts[0].tv_nsec = UTIME_OMIT;
+ }
+
+ if ((flags & CLOUDABI_FILESTAT_MTIM_NOW) != 0) {
+ ts[1].tv_nsec = UTIME_NOW;
+ } else if ((flags & CLOUDABI_FILESTAT_MTIM) != 0) {
+ ts[1].tv_sec = fs->st_mtim / 1000000000;
+ ts[1].tv_nsec = fs->st_mtim % 1000000000;
+ } else {
+ ts[1].tv_nsec = UTIME_OMIT;
+ }
+}
+
+int
+cloudabi_sys_file_stat_fput(struct thread *td,
+ struct cloudabi_sys_file_stat_fput_args *uap)
+{
+ cloudabi_filestat_t fs;
+ struct timespec ts[2];
+ int error;
+
+ error = copyin(uap->buf, &fs, sizeof(fs));
+ if (error != 0)
+ return (error);
+
+ /*
+ * Only support truncation and timestamp modification separately
+ * for now, to prevent unnecessary code duplication.
+ */
+ if ((uap->flags & CLOUDABI_FILESTAT_SIZE) != 0) {
+ /* Call into kern_ftruncate() for file truncation. */
+ if ((uap->flags & ~CLOUDABI_FILESTAT_SIZE) != 0)
+ return (EINVAL);
+ return (kern_ftruncate(td, uap->fd, fs.st_size));
+ } else if ((uap->flags & (CLOUDABI_FILESTAT_ATIM |
+ CLOUDABI_FILESTAT_ATIM_NOW | CLOUDABI_FILESTAT_MTIM |
+ CLOUDABI_FILESTAT_MTIM_NOW)) != 0) {
+ /* Call into kern_futimens() for timestamp modification. */
+ if ((uap->flags & ~(CLOUDABI_FILESTAT_ATIM |
+ CLOUDABI_FILESTAT_ATIM_NOW | CLOUDABI_FILESTAT_MTIM |
+ CLOUDABI_FILESTAT_MTIM_NOW)) != 0)
+ return (EINVAL);
+ convert_utimens_arguments(&fs, uap->flags, ts);
+ return (kern_futimens(td, uap->fd, ts, UIO_SYSSPACE));
+ }
+ return (EINVAL);
+}
+
+int
+cloudabi_sys_file_stat_get(struct thread *td,
+ struct cloudabi_sys_file_stat_get_args *uap)
+{
+ struct stat sb;
+ cloudabi_filestat_t csb;
+ char *path;
+ int error;
+
+ memset(&csb, 0, sizeof(csb));
+
+ error = copyin_path(uap->path, uap->path_len, &path);
+ if (error != 0)
+ return (error);
+
+ error = kern_statat(td,
+ (uap->fd.flags & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0 ? 0 :
+ AT_SYMLINK_NOFOLLOW, uap->fd.fd, path, UIO_SYSSPACE, &sb, NULL);
+ cloudabi_freestr(path);
+ if (error != 0)
+ return (error);
+
+ /* Convert results and return them. */
+ convert_stat(&sb, &csb);
+ if (S_ISBLK(sb.st_mode))
+ csb.st_filetype = CLOUDABI_FILETYPE_BLOCK_DEVICE;
+ else if (S_ISCHR(sb.st_mode))
+ csb.st_filetype = CLOUDABI_FILETYPE_CHARACTER_DEVICE;
+ else if (S_ISDIR(sb.st_mode))
+ csb.st_filetype = CLOUDABI_FILETYPE_DIRECTORY;
+ else if (S_ISFIFO(sb.st_mode))
+ csb.st_filetype = CLOUDABI_FILETYPE_SOCKET_STREAM;
+ else if (S_ISREG(sb.st_mode))
+ csb.st_filetype = CLOUDABI_FILETYPE_REGULAR_FILE;
+ else if (S_ISSOCK(sb.st_mode)) {
+ /* Inaccurate, but the best that we can do. */
+ csb.st_filetype = CLOUDABI_FILETYPE_SOCKET_STREAM;
+ } else if (S_ISLNK(sb.st_mode))
+ csb.st_filetype = CLOUDABI_FILETYPE_SYMBOLIC_LINK;
+ else
+ csb.st_filetype = CLOUDABI_FILETYPE_UNKNOWN;
+ return (copyout(&csb, uap->buf, sizeof(csb)));
+}
+
+int
+cloudabi_sys_file_stat_put(struct thread *td,
+ struct cloudabi_sys_file_stat_put_args *uap)
+{
+ cloudabi_filestat_t fs;
+ struct timespec ts[2];
+ char *path;
+ int error;
+
+ /*
+ * Only support timestamp modification for now, as there is no
+ * truncateat().
+ */
+ if ((uap->flags & ~(CLOUDABI_FILESTAT_ATIM |
+ CLOUDABI_FILESTAT_ATIM_NOW | CLOUDABI_FILESTAT_MTIM |
+ CLOUDABI_FILESTAT_MTIM_NOW)) != 0)
+ return (EINVAL);
+
+ error = copyin(uap->buf, &fs, sizeof(fs));
+ if (error != 0)
+ return (error);
+ error = copyin_path(uap->path, uap->path_len, &path);
+ if (error != 0)
+ return (error);
+
+ convert_utimens_arguments(&fs, uap->flags, ts);
+ error = kern_utimensat(td, uap->fd.fd, path, UIO_SYSSPACE, ts,
+ UIO_SYSSPACE, (uap->fd.flags & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) ?
+ 0 : AT_SYMLINK_NOFOLLOW);
+ cloudabi_freestr(path);
+ return (error);
+}
+
+int
+cloudabi_sys_file_symlink(struct thread *td,
+ struct cloudabi_sys_file_symlink_args *uap)
+{
+ char *path1, *path2;
+ int error;
+
+ error = copyin_path(uap->path1, uap->path1_len, &path1);
+ if (error != 0)
+ return (error);
+ error = copyin_path(uap->path2, uap->path2_len, &path2);
+ if (error != 0) {
+ cloudabi_freestr(path1);
+ return (error);
+ }
+
+ error = kern_symlinkat(td, path1, uap->fd, path2, UIO_SYSSPACE);
+ cloudabi_freestr(path1);
+ cloudabi_freestr(path2);
+ return (error);
+}
+
+int
+cloudabi_sys_file_unlink(struct thread *td,
+ struct cloudabi_sys_file_unlink_args *uap)
+{
+ char *path;
+ int error;
+
+ error = copyin_path(uap->path, uap->path_len, &path);
+ if (error != 0)
+ return (error);
+
+ if (uap->flags & CLOUDABI_UNLINK_REMOVEDIR)
+ error = kern_frmdirat(td, uap->fd, path, FD_NONE,
+ UIO_SYSSPACE, 0);
+ else
+ error = kern_funlinkat(td, uap->fd, path, FD_NONE,
+ UIO_SYSSPACE, 0, 0);
+ cloudabi_freestr(path);
+ return (error);
+}
diff --git a/sys/compat/cloudabi/cloudabi_futex.c b/sys/compat/cloudabi/cloudabi_futex.c
new file mode 100644
index 000000000000..153e8bce8495
--- /dev/null
+++ b/sys/compat/cloudabi/cloudabi_futex.c
@@ -0,0 +1,1165 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/sx.h>
+#include <sys/systm.h>
+#include <sys/umtx.h>
+
+#include <contrib/cloudabi/cloudabi_types_common.h>
+
+#include <compat/cloudabi/cloudabi_proto.h>
+#include <compat/cloudabi/cloudabi_util.h>
+
+/*
+ * Futexes for CloudABI.
+ *
+ * On most systems, futexes are implemented as objects of a single type
+ * on which a set of operations can be performed. CloudABI makes a clear
+ * distinction between locks and condition variables. A lock may have
+ * zero or more associated condition variables. A condition variable is
+ * always associated with exactly one lock. There is a strict topology.
+ * This approach has two advantages:
+ *
+ * - This topology is guaranteed to be acyclic. Requeueing of threads
+ * only happens in one direction (from condition variables to locks).
+ * This eases locking.
+ * - It means that a futex object for a lock exists when it is unlocked,
+ * but has threads waiting on associated condition variables. Threads
+ * can be requeued to a lock even if the thread performing the wakeup
+ * does not have the lock mapped in its address space.
+ *
+ * This futex implementation only implements a single lock type, namely
+ * a read-write lock. A regular mutex type would not be necessary, as
+ * the read-write lock is as efficient as a mutex if used as such.
+ * Userspace futex locks are 32 bits in size:
+ *
+ * - 1 bit: has threads waiting in kernel-space.
+ * - 1 bit: is write-locked.
+ * - 30 bits:
+ * - if write-locked: thread ID of owner.
+ * - if not write-locked: number of read locks held.
+ *
+ * Condition variables are also 32 bits in size. Its value is modified
+ * by kernel-space exclusively. Zero indicates that it has no waiting
+ * threads. Non-zero indicates the opposite.
+ *
+ * This implementation is optimal, in the sense that it only wakes up
+ * threads if they can actually continue execution. It does not suffer
+ * from the thundering herd problem. If multiple threads waiting on a
+ * condition variable need to be woken up, only a single thread is
+ * scheduled. All other threads are 'donated' to this thread. After the
+ * thread manages to reacquire the lock, it requeues its donated threads
+ * to the lock.
+ *
+ * TODO(ed): Integrate this functionality into kern_umtx.c instead.
+ * TODO(ed): Store futex objects in a hash table.
+ * TODO(ed): Add actual priority inheritance.
+ * TODO(ed): Let futex_queue also take priorities into account.
+ * TODO(ed): Make locking fine-grained.
+ * TODO(ed): Perform sleeps until an actual absolute point in time,
+ * instead of converting the timestamp to a relative value.
+ */
+
+struct futex_address;
+struct futex_condvar;
+struct futex_lock;
+struct futex_queue;
+struct futex_waiter;
+
+/* Identifier of a location in memory. */
+struct futex_address {
+ struct umtx_key fa_key;
+};
+
+/* A set of waiting threads. */
+struct futex_queue {
+ STAILQ_HEAD(, futex_waiter) fq_list;
+ unsigned int fq_count;
+};
+
+/* Condition variables. */
+struct futex_condvar {
+ /* Address of the condition variable. */
+ struct futex_address fc_address;
+
+ /* The lock the waiters should be moved to when signalled. */
+ struct futex_lock * fc_lock;
+
+ /* Threads waiting on the condition variable. */
+ struct futex_queue fc_waiters;
+ /*
+ * Number of threads blocked on this condition variable, or
+ * being blocked on the lock after being requeued.
+ */
+ unsigned int fc_waitcount;
+
+ /* Global list pointers. */
+ LIST_ENTRY(futex_condvar) fc_next;
+};
+
+/* Read-write locks. */
+struct futex_lock {
+ /* Address of the lock. */
+ struct futex_address fl_address;
+
+ /*
+ * Current owner of the lock. LOCK_UNMANAGED if the lock is
+ * currently not owned by the kernel. LOCK_OWNER_UNKNOWN in case
+ * the owner is not known (e.g., when the lock is read-locked).
+ */
+ cloudabi_tid_t fl_owner;
+#define LOCK_UNMANAGED 0x0
+#define LOCK_OWNER_UNKNOWN 0x1
+
+ /* Writers blocked on the lock. */
+ struct futex_queue fl_writers;
+ /* Readers blocked on the lock. */
+ struct futex_queue fl_readers;
+ /* Number of threads blocked on this lock + condition variables. */
+ unsigned int fl_waitcount;
+
+ /* Global list pointers. */
+ LIST_ENTRY(futex_lock) fl_next;
+};
+
+/* Information associated with a thread blocked on an object. */
+struct futex_waiter {
+ /* Thread ID. */
+ cloudabi_tid_t fw_tid;
+ /* Condition variable used for waiting. */
+ struct cv fw_wait;
+
+ /* Queue this waiter is currently placed in. */
+ struct futex_queue * fw_queue;
+ /* List pointers of fw_queue. */
+ STAILQ_ENTRY(futex_waiter) fw_next;
+
+ /* Lock has been acquired. */
+ bool fw_locked;
+ /* If not locked, threads that should block after acquiring. */
+ struct futex_queue fw_donated;
+};
+
+/* Global data structures. */
+static MALLOC_DEFINE(M_FUTEX, "futex", "CloudABI futex");
+
+static struct sx futex_global_lock;
+SX_SYSINIT(futex_global_lock, &futex_global_lock, "CloudABI futex global lock");
+
+static LIST_HEAD(, futex_lock) futex_lock_list =
+ LIST_HEAD_INITIALIZER(&futex_lock_list);
+static LIST_HEAD(, futex_condvar) futex_condvar_list =
+ LIST_HEAD_INITIALIZER(&futex_condvar_list);
+
+/* Utility functions. */
+static void futex_lock_assert(const struct futex_lock *);
+static struct futex_lock *futex_lock_lookup_locked(struct futex_address *);
+static void futex_lock_release(struct futex_lock *);
+static int futex_lock_tryrdlock(struct futex_lock *, cloudabi_lock_t *);
+static int futex_lock_unmanage(struct futex_lock *, cloudabi_lock_t *);
+static int futex_lock_update_owner(struct futex_lock *, cloudabi_lock_t *);
+static int futex_lock_wake_up_next(struct futex_lock *, cloudabi_lock_t *);
+static unsigned int futex_queue_count(const struct futex_queue *);
+static void futex_queue_init(struct futex_queue *);
+static void futex_queue_requeue(struct futex_queue *, struct futex_queue *,
+ unsigned int);
+static int futex_queue_sleep(struct futex_queue *, struct futex_lock *,
+ struct futex_waiter *, struct thread *, cloudabi_clockid_t,
+ cloudabi_timestamp_t, cloudabi_timestamp_t, bool);
+static cloudabi_tid_t futex_queue_tid_best(const struct futex_queue *);
+static void futex_queue_wake_up_all(struct futex_queue *);
+static void futex_queue_wake_up_best(struct futex_queue *);
+static void futex_queue_wake_up_donate(struct futex_queue *, unsigned int);
+static int futex_user_load(uint32_t *, uint32_t *);
+static int futex_user_store(uint32_t *, uint32_t);
+static int futex_user_cmpxchg(uint32_t *, uint32_t, uint32_t *, uint32_t);
+
+/*
+ * futex_address operations.
+ */
+
+static int
+futex_address_create(struct futex_address *fa, struct thread *td,
+ const void *object, cloudabi_scope_t scope)
+{
+
+ KASSERT(td == curthread,
+ ("Can only create umtx keys for the current thread"));
+ switch (scope) {
+ case CLOUDABI_SCOPE_PRIVATE:
+ return (umtx_key_get(object, TYPE_FUTEX, THREAD_SHARE,
+ &fa->fa_key));
+ case CLOUDABI_SCOPE_SHARED:
+ return (umtx_key_get(object, TYPE_FUTEX, AUTO_SHARE,
+ &fa->fa_key));
+ default:
+ return (EINVAL);
+ }
+}
+
+static void
+futex_address_free(struct futex_address *fa)
+{
+
+ umtx_key_release(&fa->fa_key);
+}
+
+static bool
+futex_address_match(const struct futex_address *fa1,
+ const struct futex_address *fa2)
+{
+
+ return (umtx_key_match(&fa1->fa_key, &fa2->fa_key));
+}
+
+/*
+ * futex_condvar operations.
+ */
+
+static void
+futex_condvar_assert(const struct futex_condvar *fc)
+{
+
+ KASSERT(fc->fc_waitcount >= futex_queue_count(&fc->fc_waiters),
+ ("Total number of waiters cannot be smaller than the wait queue"));
+ futex_lock_assert(fc->fc_lock);
+}
+
+static int
+futex_condvar_lookup(struct thread *td, const cloudabi_condvar_t *address,
+ cloudabi_scope_t scope, struct futex_condvar **fcret)
+{
+ struct futex_address fa_condvar;
+ struct futex_condvar *fc;
+ int error;
+
+ error = futex_address_create(&fa_condvar, td, address, scope);
+ if (error != 0)
+ return (error);
+
+ sx_xlock(&futex_global_lock);
+ LIST_FOREACH(fc, &futex_condvar_list, fc_next) {
+ if (futex_address_match(&fc->fc_address, &fa_condvar)) {
+ /* Found matching lock object. */
+ futex_address_free(&fa_condvar);
+ futex_condvar_assert(fc);
+ *fcret = fc;
+ return (0);
+ }
+ }
+ sx_xunlock(&futex_global_lock);
+ futex_address_free(&fa_condvar);
+ return (ENOENT);
+}
+
+static int
+futex_condvar_lookup_or_create(struct thread *td,
+ const cloudabi_condvar_t *condvar, cloudabi_scope_t condvar_scope,
+ const cloudabi_lock_t *lock, cloudabi_scope_t lock_scope,
+ struct futex_condvar **fcret)
+{
+ struct futex_address fa_condvar, fa_lock;
+ struct futex_condvar *fc;
+ struct futex_lock *fl;
+ int error;
+
+ error = futex_address_create(&fa_condvar, td, condvar, condvar_scope);
+ if (error != 0)
+ return (error);
+ error = futex_address_create(&fa_lock, td, lock, lock_scope);
+ if (error != 0) {
+ futex_address_free(&fa_condvar);
+ return (error);
+ }
+
+ sx_xlock(&futex_global_lock);
+ LIST_FOREACH(fc, &futex_condvar_list, fc_next) {
+ if (!futex_address_match(&fc->fc_address, &fa_condvar))
+ continue;
+ fl = fc->fc_lock;
+ if (!futex_address_match(&fl->fl_address, &fa_lock)) {
+ /* Condition variable is owned by a different lock. */
+ futex_address_free(&fa_condvar);
+ futex_address_free(&fa_lock);
+ sx_xunlock(&futex_global_lock);
+ return (EINVAL);
+ }
+
+ /* Found fully matching condition variable. */
+ futex_address_free(&fa_condvar);
+ futex_address_free(&fa_lock);
+ futex_condvar_assert(fc);
+ *fcret = fc;
+ return (0);
+ }
+
+ /* None found. Create new condition variable object. */
+ fc = malloc(sizeof(*fc), M_FUTEX, M_WAITOK);
+ fc->fc_address = fa_condvar;
+ fc->fc_lock = futex_lock_lookup_locked(&fa_lock);
+ futex_queue_init(&fc->fc_waiters);
+ fc->fc_waitcount = 0;
+ LIST_INSERT_HEAD(&futex_condvar_list, fc, fc_next);
+ *fcret = fc;
+ return (0);
+}
+
+static void
+futex_condvar_release(struct futex_condvar *fc)
+{
+ struct futex_lock *fl;
+
+ futex_condvar_assert(fc);
+ fl = fc->fc_lock;
+ if (fc->fc_waitcount == 0) {
+ /* Condition variable has no waiters. Deallocate it. */
+ futex_address_free(&fc->fc_address);
+ LIST_REMOVE(fc, fc_next);
+ free(fc, M_FUTEX);
+ }
+ futex_lock_release(fl);
+}
+
+static int
+futex_condvar_unmanage(struct futex_condvar *fc,
+ cloudabi_condvar_t *condvar)
+{
+
+ if (futex_queue_count(&fc->fc_waiters) != 0)
+ return (0);
+ return (futex_user_store(condvar, CLOUDABI_CONDVAR_HAS_NO_WAITERS));
+}
+
+/*
+ * futex_lock operations.
+ */
+
+static void
+futex_lock_assert(const struct futex_lock *fl)
+{
+
+ /*
+ * A futex lock can only be kernel-managed if it has waiters.
+ * Vice versa: if a futex lock has waiters, it must be
+ * kernel-managed.
+ */
+ KASSERT((fl->fl_owner == LOCK_UNMANAGED) ==
+ (futex_queue_count(&fl->fl_readers) == 0 &&
+ futex_queue_count(&fl->fl_writers) == 0),
+ ("Managed locks must have waiting threads"));
+ KASSERT(fl->fl_waitcount != 0 || fl->fl_owner == LOCK_UNMANAGED,
+ ("Lock with no waiters must be unmanaged"));
+}
+
+static int
+futex_lock_lookup(struct thread *td, const cloudabi_lock_t *address,
+ cloudabi_scope_t scope, struct futex_lock **flret)
+{
+ struct futex_address fa;
+ int error;
+
+ error = futex_address_create(&fa, td, address, scope);
+ if (error != 0)
+ return (error);
+
+ sx_xlock(&futex_global_lock);
+ *flret = futex_lock_lookup_locked(&fa);
+ return (0);
+}
+
+static struct futex_lock *
+futex_lock_lookup_locked(struct futex_address *fa)
+{
+ struct futex_lock *fl;
+
+ LIST_FOREACH(fl, &futex_lock_list, fl_next) {
+ if (futex_address_match(&fl->fl_address, fa)) {
+ /* Found matching lock object. */
+ futex_address_free(fa);
+ futex_lock_assert(fl);
+ return (fl);
+ }
+ }
+
+ /* None found. Create new lock object. */
+ fl = malloc(sizeof(*fl), M_FUTEX, M_WAITOK);
+ fl->fl_address = *fa;
+ fl->fl_owner = LOCK_UNMANAGED;
+ futex_queue_init(&fl->fl_readers);
+ futex_queue_init(&fl->fl_writers);
+ fl->fl_waitcount = 0;
+ LIST_INSERT_HEAD(&futex_lock_list, fl, fl_next);
+ return (fl);
+}
+
+static int
+futex_lock_rdlock(struct futex_lock *fl, struct thread *td,
+ cloudabi_lock_t *lock, cloudabi_clockid_t clock_id,
+ cloudabi_timestamp_t timeout, cloudabi_timestamp_t precision, bool abstime)
+{
+ struct futex_waiter fw;
+ int error;
+
+ error = futex_lock_tryrdlock(fl, lock);
+ if (error == EBUSY) {
+ /* Suspend execution. */
+ KASSERT(fl->fl_owner != LOCK_UNMANAGED,
+ ("Attempted to sleep on an unmanaged lock"));
+ error = futex_queue_sleep(&fl->fl_readers, fl, &fw, td,
+ clock_id, timeout, precision, abstime);
+ KASSERT((error == 0) == fw.fw_locked,
+ ("Should have locked write lock on success"));
+ KASSERT(futex_queue_count(&fw.fw_donated) == 0,
+ ("Lock functions cannot receive threads"));
+ }
+ if (error != 0)
+ futex_lock_unmanage(fl, lock);
+ return (error);
+}
+
+static void
+futex_lock_release(struct futex_lock *fl)
+{
+
+ futex_lock_assert(fl);
+ if (fl->fl_waitcount == 0) {
+ /* Lock object is unreferenced. Deallocate it. */
+ KASSERT(fl->fl_owner == LOCK_UNMANAGED,
+ ("Attempted to free a managed lock"));
+ futex_address_free(&fl->fl_address);
+ LIST_REMOVE(fl, fl_next);
+ free(fl, M_FUTEX);
+ }
+ sx_xunlock(&futex_global_lock);
+}
+
+static int
+futex_lock_unmanage(struct futex_lock *fl, cloudabi_lock_t *lock)
+{
+ cloudabi_lock_t cmp, old;
+ int error;
+
+ if (futex_queue_count(&fl->fl_readers) == 0 &&
+ futex_queue_count(&fl->fl_writers) == 0) {
+ /* Lock should be unmanaged. */
+ fl->fl_owner = LOCK_UNMANAGED;
+
+ /* Clear kernel-managed bit. */
+ error = futex_user_load(lock, &old);
+ if (error != 0)
+ return (error);
+ for (;;) {
+ cmp = old;
+ error = futex_user_cmpxchg(lock, cmp, &old,
+ cmp & ~CLOUDABI_LOCK_KERNEL_MANAGED);
+ if (error != 0)
+ return (error);
+ if (old == cmp)
+ break;
+ }
+ }
+ return (0);
+}
+
+/* Sets an owner of a lock, based on a userspace lock value. */
+static void
+futex_lock_set_owner(struct futex_lock *fl, cloudabi_lock_t lock)
+{
+
+ /* Lock has no explicit owner. */
+ if ((lock & ~CLOUDABI_LOCK_WRLOCKED) == 0) {
+ fl->fl_owner = LOCK_OWNER_UNKNOWN;
+ return;
+ }
+ lock &= ~(CLOUDABI_LOCK_WRLOCKED | CLOUDABI_LOCK_KERNEL_MANAGED);
+
+ /* Don't allow userspace to silently unlock. */
+ if (lock == LOCK_UNMANAGED) {
+ fl->fl_owner = LOCK_OWNER_UNKNOWN;
+ return;
+ }
+ fl->fl_owner = lock;
+}
+
+static int
+futex_lock_unlock(struct futex_lock *fl, struct thread *td,
+ cloudabi_lock_t *lock)
+{
+ int error;
+
+ /* Validate that this thread is allowed to unlock. */
+ error = futex_lock_update_owner(fl, lock);
+ if (error != 0)
+ return (error);
+ if (fl->fl_owner != LOCK_UNMANAGED && fl->fl_owner != td->td_tid)
+ return (EPERM);
+ return (futex_lock_wake_up_next(fl, lock));
+}
+
+/* Syncs in the owner of the lock from userspace if needed. */
+static int
+futex_lock_update_owner(struct futex_lock *fl, cloudabi_lock_t *address)
+{
+ cloudabi_lock_t lock;
+ int error;
+
+ if (fl->fl_owner == LOCK_OWNER_UNKNOWN) {
+ error = futex_user_load(address, &lock);
+ if (error != 0)
+ return (error);
+ futex_lock_set_owner(fl, lock);
+ }
+ return (0);
+}
+
+static int
+futex_lock_tryrdlock(struct futex_lock *fl, cloudabi_lock_t *address)
+{
+ cloudabi_lock_t old, cmp;
+ int error;
+
+ if (fl->fl_owner != LOCK_UNMANAGED) {
+ /* Lock is already acquired. */
+ return (EBUSY);
+ }
+
+ old = CLOUDABI_LOCK_UNLOCKED;
+ for (;;) {
+ if ((old & CLOUDABI_LOCK_KERNEL_MANAGED) != 0) {
+ /*
+ * Userspace lock is kernel-managed, even though
+ * the kernel disagrees.
+ */
+ return (EINVAL);
+ }
+
+ if ((old & CLOUDABI_LOCK_WRLOCKED) == 0) {
+ /*
+ * Lock is not write-locked. Attempt to acquire
+ * it by increasing the read count.
+ */
+ cmp = old;
+ error = futex_user_cmpxchg(address, cmp, &old, cmp + 1);
+ if (error != 0)
+ return (error);
+ if (old == cmp) {
+ /* Success. */
+ return (0);
+ }
+ } else {
+ /* Lock is write-locked. Make it kernel-managed. */
+ cmp = old;
+ error = futex_user_cmpxchg(address, cmp, &old,
+ cmp | CLOUDABI_LOCK_KERNEL_MANAGED);
+ if (error != 0)
+ return (error);
+ if (old == cmp) {
+ /* Success. */
+ futex_lock_set_owner(fl, cmp);
+ return (EBUSY);
+ }
+ }
+ }
+}
+
+static int
+futex_lock_trywrlock(struct futex_lock *fl, cloudabi_lock_t *address,
+ cloudabi_tid_t tid, bool force_kernel_managed)
+{
+ cloudabi_lock_t old, new, cmp;
+ int error;
+
+ if (fl->fl_owner == tid) {
+ /* Attempted to acquire lock recursively. */
+ return (EDEADLK);
+ }
+ if (fl->fl_owner != LOCK_UNMANAGED) {
+ /* Lock is already acquired. */
+ return (EBUSY);
+ }
+
+ old = CLOUDABI_LOCK_UNLOCKED;
+ for (;;) {
+ if ((old & CLOUDABI_LOCK_KERNEL_MANAGED) != 0) {
+ /*
+ * Userspace lock is kernel-managed, even though
+ * the kernel disagrees.
+ */
+ return (EINVAL);
+ }
+ if (old == (tid | CLOUDABI_LOCK_WRLOCKED)) {
+ /* Attempted to acquire lock recursively. */
+ return (EDEADLK);
+ }
+
+ if (old == CLOUDABI_LOCK_UNLOCKED) {
+ /* Lock is unlocked. Attempt to acquire it. */
+ new = tid | CLOUDABI_LOCK_WRLOCKED;
+ if (force_kernel_managed)
+ new |= CLOUDABI_LOCK_KERNEL_MANAGED;
+ error = futex_user_cmpxchg(address,
+ CLOUDABI_LOCK_UNLOCKED, &old, new);
+ if (error != 0)
+ return (error);
+ if (old == CLOUDABI_LOCK_UNLOCKED) {
+ /* Success. */
+ if (force_kernel_managed)
+ fl->fl_owner = tid;
+ return (0);
+ }
+ } else {
+ /* Lock is still locked. Make it kernel-managed. */
+ cmp = old;
+ error = futex_user_cmpxchg(address, cmp, &old,
+ cmp | CLOUDABI_LOCK_KERNEL_MANAGED);
+ if (error != 0)
+ return (error);
+ if (old == cmp) {
+ /* Success. */
+ futex_lock_set_owner(fl, cmp);
+ return (EBUSY);
+ }
+ }
+ }
+}
+
+static int
+futex_lock_wake_up_next(struct futex_lock *fl, cloudabi_lock_t *lock)
+{
+ cloudabi_tid_t tid;
+ int error;
+
+ /*
+ * Determine which thread(s) to wake up. Prefer waking up
+ * writers over readers to prevent write starvation.
+ */
+ if (futex_queue_count(&fl->fl_writers) > 0) {
+ /* Transfer ownership to a single write-locker. */
+ if (futex_queue_count(&fl->fl_writers) > 1 ||
+ futex_queue_count(&fl->fl_readers) > 0) {
+ /* Lock should remain managed afterwards. */
+ tid = futex_queue_tid_best(&fl->fl_writers);
+ error = futex_user_store(lock,
+ tid | CLOUDABI_LOCK_WRLOCKED |
+ CLOUDABI_LOCK_KERNEL_MANAGED);
+ if (error != 0)
+ return (error);
+
+ futex_queue_wake_up_best(&fl->fl_writers);
+ fl->fl_owner = tid;
+ } else {
+ /* Lock can become unmanaged afterwards. */
+ error = futex_user_store(lock,
+ futex_queue_tid_best(&fl->fl_writers) |
+ CLOUDABI_LOCK_WRLOCKED);
+ if (error != 0)
+ return (error);
+
+ futex_queue_wake_up_best(&fl->fl_writers);
+ fl->fl_owner = LOCK_UNMANAGED;
+ }
+ } else {
+ /* Transfer ownership to all read-lockers (if any). */
+ error = futex_user_store(lock,
+ futex_queue_count(&fl->fl_readers));
+ if (error != 0)
+ return (error);
+
+ /* Wake up all threads. */
+ futex_queue_wake_up_all(&fl->fl_readers);
+ fl->fl_owner = LOCK_UNMANAGED;
+ }
+ return (0);
+}
+
+static int
+futex_lock_wrlock(struct futex_lock *fl, struct thread *td,
+ cloudabi_lock_t *lock, cloudabi_clockid_t clock_id,
+ cloudabi_timestamp_t timeout, cloudabi_timestamp_t precision, bool abstime,
+ struct futex_queue *donated)
+{
+ struct futex_waiter fw;
+ int error;
+
+ error = futex_lock_trywrlock(fl, lock, td->td_tid,
+ futex_queue_count(donated) > 0);
+
+ if (error == 0 || error == EBUSY) {
+ /* Put donated threads in queue before suspending. */
+ KASSERT(futex_queue_count(donated) == 0 ||
+ fl->fl_owner != LOCK_UNMANAGED,
+ ("Lock should be managed if we are going to donate"));
+ futex_queue_requeue(donated, &fl->fl_writers, UINT_MAX);
+ } else {
+ /*
+ * This thread cannot deal with the donated threads.
+ * Wake up the next thread and let it try it by itself.
+ */
+ futex_queue_wake_up_donate(donated, UINT_MAX);
+ }
+
+ if (error == EBUSY) {
+ /* Suspend execution if the lock was busy. */
+ KASSERT(fl->fl_owner != LOCK_UNMANAGED,
+ ("Attempted to sleep on an unmanaged lock"));
+ error = futex_queue_sleep(&fl->fl_writers, fl, &fw, td,
+ clock_id, timeout, precision, abstime);
+ KASSERT((error == 0) == fw.fw_locked,
+ ("Should have locked write lock on success"));
+ KASSERT(futex_queue_count(&fw.fw_donated) == 0,
+ ("Lock functions cannot receive threads"));
+ }
+ if (error != 0)
+ futex_lock_unmanage(fl, lock);
+ return (error);
+}
+
+/*
+ * futex_queue operations.
+ */
+
+static cloudabi_tid_t
+futex_queue_tid_best(const struct futex_queue *fq)
+{
+
+ return (STAILQ_FIRST(&fq->fq_list)->fw_tid);
+}
+
+static unsigned int
+futex_queue_count(const struct futex_queue *fq)
+{
+
+ return (fq->fq_count);
+}
+
+static void
+futex_queue_init(struct futex_queue *fq)
+{
+
+ STAILQ_INIT(&fq->fq_list);
+ fq->fq_count = 0;
+}
+
+/* Converts a relative timestamp to an sbintime. */
+static sbintime_t
+futex_queue_convert_timestamp_relative(cloudabi_timestamp_t ts)
+{
+ cloudabi_timestamp_t s, ns;
+
+ s = ts / 1000000000;
+ ns = ts % 1000000000;
+ if (s > INT32_MAX)
+ return (INT64_MAX);
+ return ((s << 32) + (ns << 32) / 1000000000);
+}
+
+/* Converts an absolute timestamp and precision to a pair of sbintime values. */
+static int
+futex_queue_convert_timestamp(struct thread *td, cloudabi_clockid_t clock_id,
+ cloudabi_timestamp_t timeout, cloudabi_timestamp_t precision,
+ sbintime_t *sbttimeout, sbintime_t *sbtprecision, bool abstime)
+{
+ cloudabi_timestamp_t now;
+ int error;
+
+ if (abstime) {
+ /* Make the time relative. */
+ error = cloudabi_clock_time_get(td, clock_id, &now);
+ if (error != 0)
+ return (error);
+ timeout = timeout < now ? 0 : timeout - now;
+ }
+
+ *sbttimeout = futex_queue_convert_timestamp_relative(timeout);
+ *sbtprecision = futex_queue_convert_timestamp_relative(precision);
+ return (0);
+}
+
+static int
+futex_queue_sleep(struct futex_queue *fq, struct futex_lock *fl,
+ struct futex_waiter *fw, struct thread *td, cloudabi_clockid_t clock_id,
+ cloudabi_timestamp_t timeout, cloudabi_timestamp_t precision, bool abstime)
+{
+ sbintime_t sbttimeout, sbtprecision;
+ int error;
+
+ /* Initialize futex_waiter object. */
+ fw->fw_tid = td->td_tid;
+ fw->fw_locked = false;
+ futex_queue_init(&fw->fw_donated);
+
+ if (timeout != UINT64_MAX) {
+ /* Convert timeout duration. */
+ error = futex_queue_convert_timestamp(td, clock_id, timeout,
+ precision, &sbttimeout, &sbtprecision, abstime);
+ if (error != 0)
+ return (error);
+ }
+
+ /* Place object in the queue. */
+ fw->fw_queue = fq;
+ STAILQ_INSERT_TAIL(&fq->fq_list, fw, fw_next);
+ ++fq->fq_count;
+
+ cv_init(&fw->fw_wait, "futex");
+ ++fl->fl_waitcount;
+
+ futex_lock_assert(fl);
+ if (timeout == UINT64_MAX) {
+ /* Wait without a timeout. */
+ error = cv_wait_sig(&fw->fw_wait, &futex_global_lock);
+ } else {
+ /* Wait respecting the timeout. */
+ error = cv_timedwait_sig_sbt(&fw->fw_wait, &futex_global_lock,
+ sbttimeout, sbtprecision, 0);
+ futex_lock_assert(fl);
+ if (error == EWOULDBLOCK &&
+ fw->fw_queue != NULL && fw->fw_queue != fq) {
+ /*
+ * We got signalled on a condition variable, but
+ * observed a timeout while waiting to reacquire
+ * the lock. In other words, we didn't actually
+ * time out. Go back to sleep and wait for the
+ * lock to be reacquired.
+ */
+ error = cv_wait_sig(&fw->fw_wait, &futex_global_lock);
+ }
+ }
+ futex_lock_assert(fl);
+
+ --fl->fl_waitcount;
+ cv_destroy(&fw->fw_wait);
+
+ fq = fw->fw_queue;
+ if (fq == NULL) {
+ /* Thread got dequeued, so we've slept successfully. */
+ return (0);
+ }
+
+ /* Thread is still enqueued. Remove it. */
+ KASSERT(error != 0, ("Woken up thread is still enqueued"));
+ STAILQ_REMOVE(&fq->fq_list, fw, futex_waiter, fw_next);
+ --fq->fq_count;
+ return (error == EWOULDBLOCK ? ETIMEDOUT : error);
+}
+
+/* Moves up to nwaiters waiters from one queue to another. */
+static void
+futex_queue_requeue(struct futex_queue *fqfrom, struct futex_queue *fqto,
+ unsigned int nwaiters)
+{
+ struct futex_waiter *fw;
+
+ /* Move waiters to the target queue. */
+ while (nwaiters-- > 0 && !STAILQ_EMPTY(&fqfrom->fq_list)) {
+ fw = STAILQ_FIRST(&fqfrom->fq_list);
+ STAILQ_REMOVE_HEAD(&fqfrom->fq_list, fw_next);
+ --fqfrom->fq_count;
+
+ fw->fw_queue = fqto;
+ STAILQ_INSERT_TAIL(&fqto->fq_list, fw, fw_next);
+ ++fqto->fq_count;
+ }
+}
+
+/* Wakes up all waiters in a queue. */
+static void
+futex_queue_wake_up_all(struct futex_queue *fq)
+{
+ struct futex_waiter *fw;
+
+ STAILQ_FOREACH(fw, &fq->fq_list, fw_next) {
+ fw->fw_locked = true;
+ fw->fw_queue = NULL;
+ cv_signal(&fw->fw_wait);
+ }
+
+ STAILQ_INIT(&fq->fq_list);
+ fq->fq_count = 0;
+}
+
+/*
+ * Wakes up the best waiter (i.e., the waiter having the highest
+ * priority) in a queue.
+ */
+static void
+futex_queue_wake_up_best(struct futex_queue *fq)
+{
+ struct futex_waiter *fw;
+
+ fw = STAILQ_FIRST(&fq->fq_list);
+ fw->fw_locked = true;
+ fw->fw_queue = NULL;
+ cv_signal(&fw->fw_wait);
+
+ STAILQ_REMOVE_HEAD(&fq->fq_list, fw_next);
+ --fq->fq_count;
+}
+
+static void
+futex_queue_wake_up_donate(struct futex_queue *fq, unsigned int nwaiters)
+{
+ struct futex_waiter *fw;
+
+ fw = STAILQ_FIRST(&fq->fq_list);
+ if (fw == NULL)
+ return;
+ fw->fw_locked = false;
+ fw->fw_queue = NULL;
+ cv_signal(&fw->fw_wait);
+
+ STAILQ_REMOVE_HEAD(&fq->fq_list, fw_next);
+ --fq->fq_count;
+ futex_queue_requeue(fq, &fw->fw_donated, nwaiters);
+}
+
+/*
+ * futex_user operations. Used to adjust values in userspace.
+ */
+
+static int
+futex_user_load(uint32_t *obj, uint32_t *val)
+{
+
+ return (fueword32(obj, val) != 0 ? EFAULT : 0);
+}
+
+static int
+futex_user_store(uint32_t *obj, uint32_t val)
+{
+
+ return (suword32(obj, val) != 0 ? EFAULT : 0);
+}
+
+static int
+futex_user_cmpxchg(uint32_t *obj, uint32_t cmp, uint32_t *old, uint32_t new)
+{
+
+ return (casueword32(obj, cmp, old, new) != 0 ? EFAULT : 0);
+}
+
+/*
+ * Blocking calls: acquiring locks, waiting on condition variables.
+ */
+
+int
+cloudabi_futex_condvar_wait(struct thread *td, cloudabi_condvar_t *condvar,
+ cloudabi_scope_t condvar_scope, cloudabi_lock_t *lock,
+ cloudabi_scope_t lock_scope, cloudabi_clockid_t clock_id,
+ cloudabi_timestamp_t timeout, cloudabi_timestamp_t precision, bool abstime)
+{
+ struct futex_condvar *fc;
+ struct futex_lock *fl;
+ struct futex_waiter fw;
+ int error, error2;
+
+ /* Lookup condition variable object. */
+ error = futex_condvar_lookup_or_create(td, condvar, condvar_scope, lock,
+ lock_scope, &fc);
+ if (error != 0)
+ return (error);
+ fl = fc->fc_lock;
+
+ /*
+ * Set the condition variable to something other than
+ * CLOUDABI_CONDVAR_HAS_NO_WAITERS to make userspace threads
+ * call into the kernel to perform wakeups.
+ */
+ error = futex_user_store(condvar, ~CLOUDABI_CONDVAR_HAS_NO_WAITERS);
+ if (error != 0) {
+ futex_condvar_release(fc);
+ return (error);
+ }
+
+ /* Drop the lock. */
+ error = futex_lock_unlock(fl, td, lock);
+ if (error != 0) {
+ futex_condvar_unmanage(fc, condvar);
+ futex_condvar_release(fc);
+ return (error);
+ }
+
+ /* Go to sleep. */
+ ++fc->fc_waitcount;
+ error = futex_queue_sleep(&fc->fc_waiters, fc->fc_lock, &fw, td,
+ clock_id, timeout, precision, abstime);
+ if (fw.fw_locked) {
+ /* Waited and got the lock assigned to us. */
+ KASSERT(futex_queue_count(&fw.fw_donated) == 0,
+ ("Received threads while being locked"));
+ } else if (error == 0 || error == ETIMEDOUT) {
+ if (error != 0)
+ futex_condvar_unmanage(fc, condvar);
+ /*
+ * Got woken up without having the lock assigned to us.
+ * This can happen in two cases:
+ *
+ * 1. We observed a timeout on a condition variable.
+ * 2. We got signalled on a condition variable while the
+ * associated lock is unlocked. We are the first
+ * thread that gets woken up. This thread is
+ * responsible for reacquiring the userspace lock.
+ */
+ error2 = futex_lock_wrlock(fl, td, lock,
+ CLOUDABI_CLOCK_MONOTONIC, UINT64_MAX, 0, abstime,
+ &fw.fw_donated);
+ if (error2 != 0)
+ error = error2;
+ } else {
+ KASSERT(futex_queue_count(&fw.fw_donated) == 0,
+ ("Received threads on error"));
+ futex_condvar_unmanage(fc, condvar);
+ futex_lock_unmanage(fl, lock);
+ }
+ --fc->fc_waitcount;
+ futex_condvar_release(fc);
+ return (error);
+}
+
+int
+cloudabi_futex_lock_rdlock(struct thread *td, cloudabi_lock_t *lock,
+ cloudabi_scope_t scope, cloudabi_clockid_t clock_id,
+ cloudabi_timestamp_t timeout, cloudabi_timestamp_t precision, bool abstime)
+{
+ struct futex_lock *fl;
+ int error;
+
+ /* Look up lock object. */
+ error = futex_lock_lookup(td, lock, scope, &fl);
+ if (error != 0)
+ return (error);
+
+ error = futex_lock_rdlock(fl, td, lock, clock_id, timeout,
+ precision, abstime);
+ futex_lock_release(fl);
+ return (error);
+}
+
+int
+cloudabi_futex_lock_wrlock(struct thread *td, cloudabi_lock_t *lock,
+ cloudabi_scope_t scope, cloudabi_clockid_t clock_id,
+ cloudabi_timestamp_t timeout, cloudabi_timestamp_t precision, bool abstime)
+{
+ struct futex_lock *fl;
+ struct futex_queue fq;
+ int error;
+
+ /* Look up lock object. */
+ error = futex_lock_lookup(td, lock, scope, &fl);
+ if (error != 0)
+ return (error);
+
+ futex_queue_init(&fq);
+ error = futex_lock_wrlock(fl, td, lock, clock_id, timeout,
+ precision, abstime, &fq);
+ futex_lock_release(fl);
+ return (error);
+}
+
+/*
+ * Non-blocking calls: releasing locks, signalling condition variables.
+ */
+
+int
+cloudabi_sys_condvar_signal(struct thread *td,
+ struct cloudabi_sys_condvar_signal_args *uap)
+{
+ struct futex_condvar *fc;
+ struct futex_lock *fl;
+ cloudabi_nthreads_t nwaiters;
+ int error;
+
+ nwaiters = uap->nwaiters;
+ if (nwaiters == 0) {
+ /* No threads to wake up. */
+ return (0);
+ }
+
+ /* Look up futex object. */
+ error = futex_condvar_lookup(td, uap->condvar, uap->scope, &fc);
+ if (error != 0) {
+ /* Race condition: condition variable with no waiters. */
+ return (error == ENOENT ? 0 : error);
+ }
+ fl = fc->fc_lock;
+
+ if (fl->fl_owner == LOCK_UNMANAGED) {
+ /*
+ * The lock is currently not managed by the kernel,
+ * meaning we must attempt to acquire the userspace lock
+ * first. We cannot requeue threads to an unmanaged lock,
+ * as these threads will then never be scheduled.
+ *
+ * Unfortunately, the memory address of the lock is
+ * unknown from this context, meaning that we cannot
+ * acquire the lock on behalf of the first thread to be
+ * scheduled. The lock may even not be mapped within the
+ * address space of the current thread.
+ *
+ * To solve this, wake up a single waiter that will
+ * attempt to acquire the lock. Donate all of the other
+ * waiters that need to be woken up to this waiter, so
+ * it can requeue them after acquiring the lock.
+ */
+ futex_queue_wake_up_donate(&fc->fc_waiters, nwaiters - 1);
+ } else {
+ /*
+ * Lock is already managed by the kernel. This makes it
+ * easy, as we can requeue the threads from the
+ * condition variable directly to the associated lock.
+ */
+ futex_queue_requeue(&fc->fc_waiters, &fl->fl_writers, nwaiters);
+ }
+
+ /* Clear userspace condition variable if all waiters are gone. */
+ error = futex_condvar_unmanage(fc, uap->condvar);
+ futex_condvar_release(fc);
+ return (error);
+}
+
+int
+cloudabi_sys_lock_unlock(struct thread *td,
+ struct cloudabi_sys_lock_unlock_args *uap)
+{
+ struct futex_lock *fl;
+ int error;
+
+ error = futex_lock_lookup(td, uap->lock, uap->scope, &fl);
+ if (error != 0)
+ return (error);
+ error = futex_lock_unlock(fl, td, uap->lock);
+ futex_lock_release(fl);
+ return (error);
+}
diff --git a/sys/compat/cloudabi/cloudabi_mem.c b/sys/compat/cloudabi/cloudabi_mem.c
new file mode 100644
index 000000000000..426adb6ff43f
--- /dev/null
+++ b/sys/compat/cloudabi/cloudabi_mem.c
@@ -0,0 +1,167 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/proc.h>
+#include <sys/syscallsubr.h>
+
+#include <contrib/cloudabi/cloudabi_types_common.h>
+
+#include <compat/cloudabi/cloudabi_proto.h>
+
+/* Converts CloudABI's memory protection flags to FreeBSD's. */
+static int
+convert_mprot(cloudabi_mprot_t in, int *out)
+{
+
+ /* Unknown protection flags. */
+ if ((in & ~(CLOUDABI_PROT_EXEC | CLOUDABI_PROT_WRITE |
+ CLOUDABI_PROT_READ)) != 0)
+ return (ENOTSUP);
+ /* W^X: Write and exec cannot be enabled at the same time. */
+ if ((in & (CLOUDABI_PROT_EXEC | CLOUDABI_PROT_WRITE)) ==
+ (CLOUDABI_PROT_EXEC | CLOUDABI_PROT_WRITE))
+ return (ENOTSUP);
+
+ *out = 0;
+ if (in & CLOUDABI_PROT_EXEC)
+ *out |= PROT_EXEC;
+ if (in & CLOUDABI_PROT_WRITE)
+ *out |= PROT_WRITE;
+ if (in & CLOUDABI_PROT_READ)
+ *out |= PROT_READ;
+ return (0);
+}
+
+int
+cloudabi_sys_mem_advise(struct thread *td,
+ struct cloudabi_sys_mem_advise_args *uap)
+{
+ int behav;
+
+ switch (uap->advice) {
+ case CLOUDABI_ADVICE_DONTNEED:
+ behav = MADV_DONTNEED;
+ break;
+ case CLOUDABI_ADVICE_NORMAL:
+ behav = MADV_NORMAL;
+ break;
+ case CLOUDABI_ADVICE_RANDOM:
+ behav = MADV_RANDOM;
+ break;
+ case CLOUDABI_ADVICE_SEQUENTIAL:
+ behav = MADV_SEQUENTIAL;
+ break;
+ case CLOUDABI_ADVICE_WILLNEED:
+ behav = MADV_WILLNEED;
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ return (kern_madvise(td, (uintptr_t)uap->mapping, uap->mapping_len,
+ behav));
+}
+
+int
+cloudabi_sys_mem_map(struct thread *td, struct cloudabi_sys_mem_map_args *uap)
+{
+ int error, flags, prot;
+
+ /* Translate flags. */
+ flags = 0;
+ if (uap->flags & CLOUDABI_MAP_ANON)
+ flags |= MAP_ANON;
+ if (uap->flags & CLOUDABI_MAP_FIXED)
+ flags |= MAP_FIXED;
+ if (uap->flags & CLOUDABI_MAP_PRIVATE)
+ flags |= MAP_PRIVATE;
+ if (uap->flags & CLOUDABI_MAP_SHARED)
+ flags |= MAP_SHARED;
+
+ /* Translate protection. */
+ error = convert_mprot(uap->prot, &prot);
+ if (error != 0)
+ return (error);
+
+ return (kern_mmap(td, &(struct mmap_req){
+ .mr_hint = (uintptr_t)uap->addr,
+ .mr_len = uap->len,
+ .mr_prot = prot,
+ .mr_flags = flags,
+ .mr_fd = uap->fd,
+ .mr_pos = uap->off,
+ }));
+}
+
+int
+cloudabi_sys_mem_protect(struct thread *td,
+ struct cloudabi_sys_mem_protect_args *uap)
+{
+ int error, prot;
+
+ /* Translate protection. */
+ error = convert_mprot(uap->prot, &prot);
+ if (error != 0)
+ return (error);
+
+ return (kern_mprotect(td, (uintptr_t)uap->mapping, uap->mapping_len,
+ prot));
+}
+
+int
+cloudabi_sys_mem_sync(struct thread *td, struct cloudabi_sys_mem_sync_args *uap)
+{
+ int flags;
+
+ /* Convert flags. */
+ switch (uap->flags & (CLOUDABI_MS_ASYNC | CLOUDABI_MS_SYNC)) {
+ case CLOUDABI_MS_ASYNC:
+ flags = MS_ASYNC;
+ break;
+ case CLOUDABI_MS_SYNC:
+ flags = MS_SYNC;
+ break;
+ default:
+ return (EINVAL);
+ }
+ if ((uap->flags & CLOUDABI_MS_INVALIDATE) != 0)
+ flags |= MS_INVALIDATE;
+
+ return (kern_msync(td, (uintptr_t)uap->mapping, uap->mapping_len,
+ flags));
+}
+
+int
+cloudabi_sys_mem_unmap(struct thread *td,
+ struct cloudabi_sys_mem_unmap_args *uap)
+{
+
+ return (kern_munmap(td, (uintptr_t)uap->mapping, uap->mapping_len));
+}
diff --git a/sys/compat/cloudabi/cloudabi_proc.c b/sys/compat/cloudabi/cloudabi_proc.c
new file mode 100644
index 000000000000..378409edaeff
--- /dev/null
+++ b/sys/compat/cloudabi/cloudabi_proc.c
@@ -0,0 +1,148 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/capsicum.h>
+#include <sys/filedesc.h>
+#include <sys/imgact.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/signalvar.h>
+#include <sys/syscallsubr.h>
+#include <sys/unistd.h>
+
+#include <contrib/cloudabi/cloudabi_types_common.h>
+
+#include <compat/cloudabi/cloudabi_proto.h>
+
+int
+cloudabi_sys_proc_exec(struct thread *td,
+ struct cloudabi_sys_proc_exec_args *uap)
+{
+ struct image_args args;
+ struct vmspace *oldvmspace;
+ int error;
+
+ error = pre_execve(td, &oldvmspace);
+ if (error != 0)
+ return (error);
+ error = exec_copyin_data_fds(td, &args, uap->data, uap->data_len,
+ uap->fds, uap->fds_len);
+ if (error == 0) {
+ args.fd = uap->fd;
+ error = kern_execve(td, &args, NULL, oldvmspace);
+ }
+ post_execve(td, error, oldvmspace);
+ return (error);
+}
+
+int
+cloudabi_sys_proc_exit(struct thread *td,
+ struct cloudabi_sys_proc_exit_args *uap)
+{
+
+ exit1(td, uap->rval, 0);
+ /* NOTREACHED */
+}
+
+int
+cloudabi_sys_proc_fork(struct thread *td,
+ struct cloudabi_sys_proc_fork_args *uap)
+{
+ struct fork_req fr;
+ struct filecaps fcaps = {};
+ int error, fd;
+
+ cap_rights_init(&fcaps.fc_rights, CAP_FSTAT, CAP_EVENT);
+ bzero(&fr, sizeof(fr));
+ fr.fr_flags = RFFDG | RFPROC | RFPROCDESC;
+ fr.fr_pd_fd = &fd;
+ fr.fr_pd_fcaps = &fcaps;
+ error = fork1(td, &fr);
+ if (error != 0)
+ return (error);
+ /* Return the file descriptor to the parent process. */
+ td->td_retval[0] = fd;
+ return (0);
+}
+
+int
+cloudabi_sys_proc_raise(struct thread *td,
+ struct cloudabi_sys_proc_raise_args *uap)
+{
+ static const int signals[] = {
+ [CLOUDABI_SIGABRT] = SIGABRT,
+ [CLOUDABI_SIGALRM] = SIGALRM,
+ [CLOUDABI_SIGBUS] = SIGBUS,
+ [CLOUDABI_SIGCHLD] = SIGCHLD,
+ [CLOUDABI_SIGCONT] = SIGCONT,
+ [CLOUDABI_SIGFPE] = SIGFPE,
+ [CLOUDABI_SIGHUP] = SIGHUP,
+ [CLOUDABI_SIGILL] = SIGILL,
+ [CLOUDABI_SIGINT] = SIGINT,
+ [CLOUDABI_SIGKILL] = SIGKILL,
+ [CLOUDABI_SIGPIPE] = SIGPIPE,
+ [CLOUDABI_SIGQUIT] = SIGQUIT,
+ [CLOUDABI_SIGSEGV] = SIGSEGV,
+ [CLOUDABI_SIGSTOP] = SIGSTOP,
+ [CLOUDABI_SIGSYS] = SIGSYS,
+ [CLOUDABI_SIGTERM] = SIGTERM,
+ [CLOUDABI_SIGTRAP] = SIGTRAP,
+ [CLOUDABI_SIGTSTP] = SIGTSTP,
+ [CLOUDABI_SIGTTIN] = SIGTTIN,
+ [CLOUDABI_SIGTTOU] = SIGTTOU,
+ [CLOUDABI_SIGURG] = SIGURG,
+ [CLOUDABI_SIGUSR1] = SIGUSR1,
+ [CLOUDABI_SIGUSR2] = SIGUSR2,
+ [CLOUDABI_SIGVTALRM] = SIGVTALRM,
+ [CLOUDABI_SIGXCPU] = SIGXCPU,
+ [CLOUDABI_SIGXFSZ] = SIGXFSZ,
+ };
+ ksiginfo_t ksi;
+ struct proc *p;
+
+ if (uap->sig >= nitems(signals) || signals[uap->sig] == 0) {
+ /* Invalid signal, or the null signal. */
+ return (uap->sig == 0 ? 0 : EINVAL);
+ }
+
+ p = td->td_proc;
+ ksiginfo_init(&ksi);
+ ksi.ksi_signo = signals[uap->sig];
+ ksi.ksi_code = SI_USER;
+ ksi.ksi_pid = p->p_pid;
+ ksi.ksi_uid = td->td_ucred->cr_ruid;
+ PROC_LOCK(p);
+ pksignal(p, ksi.ksi_signo, &ksi);
+ PROC_UNLOCK(p);
+ return (0);
+}
+
+MODULE_VERSION(cloudabi, 1);
diff --git a/sys/compat/cloudabi/cloudabi_proto.h b/sys/compat/cloudabi/cloudabi_proto.h
new file mode 100644
index 000000000000..95271fd3a575
--- /dev/null
+++ b/sys/compat/cloudabi/cloudabi_proto.h
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * This should provide all prototypes for the machine-independent system
+ * calls. Unfortunately, we don't have a separate system call table for
+ * those, so rely on the system call table from COMPAT_CLOUDABI64.
+ */
+
+#include <contrib/cloudabi/cloudabi64_types.h>
+
+#include <compat/cloudabi64/cloudabi64_proto.h>
diff --git a/sys/compat/cloudabi/cloudabi_random.c b/sys/compat/cloudabi/cloudabi_random.c
new file mode 100644
index 000000000000..02a3252a1b54
--- /dev/null
+++ b/sys/compat/cloudabi/cloudabi_random.c
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/random.h>
+#include <sys/uio.h>
+
+#include <compat/cloudabi/cloudabi_proto.h>
+
+int
+cloudabi_sys_random_get(struct thread *td,
+ struct cloudabi_sys_random_get_args *uap)
+{
+ struct iovec iov = {
+ .iov_base = uap->buf,
+ .iov_len = uap->buf_len
+ };
+ struct uio uio = {
+ .uio_iov = &iov,
+ .uio_iovcnt = 1,
+ .uio_resid = iov.iov_len,
+ .uio_segflg = UIO_USERSPACE,
+ .uio_rw = UIO_READ,
+ .uio_td = td
+ };
+
+ return (read_random_uio(&uio, false));
+}
diff --git a/sys/compat/cloudabi/cloudabi_sock.c b/sys/compat/cloudabi/cloudabi_sock.c
new file mode 100644
index 000000000000..f9f9f0510f2a
--- /dev/null
+++ b/sys/compat/cloudabi/cloudabi_sock.c
@@ -0,0 +1,186 @@
+/*-
+ * Copyright (c) 2015-2017 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/capsicum.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/syscallsubr.h>
+#include <sys/systm.h>
+
+#include <net/vnet.h>
+
+#include <netinet/in.h>
+
+#include <contrib/cloudabi/cloudabi_types_common.h>
+
+#include <compat/cloudabi/cloudabi_proto.h>
+#include <compat/cloudabi/cloudabi_util.h>
+
+int
+cloudabi_sys_sock_shutdown(struct thread *td,
+ struct cloudabi_sys_sock_shutdown_args *uap)
+{
+ int how;
+
+ switch (uap->how) {
+ case CLOUDABI_SHUT_RD:
+ how = SHUT_RD;
+ break;
+ case CLOUDABI_SHUT_WR:
+ how = SHUT_WR;
+ break;
+ case CLOUDABI_SHUT_RD | CLOUDABI_SHUT_WR:
+ how = SHUT_RDWR;
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ return (kern_shutdown(td, uap->sock, how));
+}
+
+int
+cloudabi_sock_recv(struct thread *td, cloudabi_fd_t fd, struct iovec *data,
+ size_t datalen, cloudabi_fd_t *fds, size_t fdslen,
+ cloudabi_riflags_t flags, size_t *rdatalen, size_t *rfdslen,
+ cloudabi_roflags_t *rflags)
+{
+ struct msghdr hdr = {
+ .msg_iov = data,
+ .msg_iovlen = datalen,
+ };
+ struct mbuf *control;
+ int error;
+
+ /* Convert flags. */
+ if (flags & CLOUDABI_SOCK_RECV_PEEK)
+ hdr.msg_flags |= MSG_PEEK;
+ if (flags & CLOUDABI_SOCK_RECV_WAITALL)
+ hdr.msg_flags |= MSG_WAITALL;
+
+ control = NULL;
+ error = kern_recvit(td, fd, &hdr, UIO_SYSSPACE,
+ fdslen > 0 ? &control : NULL);
+ if (error != 0)
+ return (error);
+
+ /* Convert return values. */
+ *rdatalen = td->td_retval[0];
+ td->td_retval[0] = 0;
+ *rfdslen = 0;
+ *rflags = 0;
+ if (hdr.msg_flags & MSG_TRUNC)
+ *rflags |= CLOUDABI_SOCK_RECV_DATA_TRUNCATED;
+
+ /* Extract file descriptors from SCM_RIGHTS messages. */
+ if (control != NULL) {
+ struct cmsghdr *chdr;
+
+ hdr.msg_control = mtod(control, void *);
+ hdr.msg_controllen = control->m_len;
+ for (chdr = CMSG_FIRSTHDR(&hdr); chdr != NULL;
+ chdr = CMSG_NXTHDR(&hdr, chdr)) {
+ if (chdr->cmsg_level == SOL_SOCKET &&
+ chdr->cmsg_type == SCM_RIGHTS) {
+ size_t nfds;
+
+ nfds = (chdr->cmsg_len - CMSG_LEN(0)) /
+ sizeof(int);
+ if (nfds > fdslen) {
+ /* Unable to store file descriptors. */
+ *rflags |=
+ CLOUDABI_SOCK_RECV_FDS_TRUNCATED;
+ m_dispose_extcontrolm(control);
+ break;
+ }
+ error = copyout(CMSG_DATA(chdr), fds,
+ nfds * sizeof(int));
+ if (error != 0)
+ break;
+ fds += nfds;
+ fdslen -= nfds;
+ *rfdslen += nfds;
+ }
+ }
+ if (control != NULL) {
+ if (error != 0)
+ m_dispose_extcontrolm(control);
+ m_free(control);
+ }
+ }
+ return (error);
+}
+
+int
+cloudabi_sock_send(struct thread *td, cloudabi_fd_t fd, struct iovec *data,
+ size_t datalen, const cloudabi_fd_t *fds, size_t fdslen, size_t *rdatalen)
+{
+ struct msghdr hdr = {
+ .msg_iov = data,
+ .msg_iovlen = datalen,
+ };
+ struct mbuf *control;
+ int error;
+
+ /* Convert file descriptor array to an SCM_RIGHTS message. */
+ if (fdslen > MCLBYTES || CMSG_SPACE(fdslen * sizeof(int)) > MCLBYTES) {
+ return (EINVAL);
+ } else if (fdslen > 0) {
+ struct cmsghdr *chdr;
+
+ control = m_get2(CMSG_SPACE(fdslen * sizeof(int)),
+ M_WAITOK, MT_CONTROL, 0);
+ control->m_len = CMSG_SPACE(fdslen * sizeof(int));
+
+ chdr = mtod(control, struct cmsghdr *);
+ chdr->cmsg_len = CMSG_LEN(fdslen * sizeof(int));
+ chdr->cmsg_level = SOL_SOCKET;
+ chdr->cmsg_type = SCM_RIGHTS;
+ error = copyin(fds, CMSG_DATA(chdr), fdslen * sizeof(int));
+ if (error != 0) {
+ m_free(control);
+ return (error);
+ }
+ } else {
+ control = NULL;
+ }
+
+ error = kern_sendit(td, fd, &hdr, MSG_NOSIGNAL, control, UIO_USERSPACE);
+ if (error != 0)
+ return (error);
+ *rdatalen = td->td_retval[0];
+ td->td_retval[0] = 0;
+ return (0);
+}
diff --git a/sys/compat/cloudabi/cloudabi_thread.c b/sys/compat/cloudabi/cloudabi_thread.c
new file mode 100644
index 000000000000..e70549b6e332
--- /dev/null
+++ b/sys/compat/cloudabi/cloudabi_thread.c
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/sched.h>
+#include <sys/syscallsubr.h>
+#include <sys/umtx.h>
+
+#include <contrib/cloudabi/cloudabi_types_common.h>
+
+#include <compat/cloudabi/cloudabi_proto.h>
+
+int
+cloudabi_sys_thread_exit(struct thread *td,
+ struct cloudabi_sys_thread_exit_args *uap)
+{
+ struct cloudabi_sys_lock_unlock_args cloudabi_sys_lock_unlock_args = {
+ .lock = uap->lock,
+ .scope = uap->scope,
+ };
+
+ umtx_thread_exit(td);
+
+ /* Wake up joining thread. */
+ cloudabi_sys_lock_unlock(td, &cloudabi_sys_lock_unlock_args);
+
+ /*
+ * Attempt to terminate the thread. Terminate the process if
+ * it's the last thread.
+ */
+ kern_thr_exit(td);
+ exit1(td, 0, 0);
+ /* NOTREACHED */
+}
+
+int
+cloudabi_sys_thread_yield(struct thread *td,
+ struct cloudabi_sys_thread_yield_args *uap)
+{
+
+ sched_relinquish(td);
+ return (0);
+}
diff --git a/sys/compat/cloudabi/cloudabi_util.h b/sys/compat/cloudabi/cloudabi_util.h
new file mode 100644
index 000000000000..0f07dc53fa29
--- /dev/null
+++ b/sys/compat/cloudabi/cloudabi_util.h
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2015-2017 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _CLOUDABI_UTIL_H_
+#define _CLOUDABI_UTIL_H_
+
+#include <sys/socket.h>
+
+#include <contrib/cloudabi/cloudabi_types_common.h>
+
+struct file;
+struct sysentvec;
+struct thread;
+struct timespec;
+
+/* Fetches the time value of a clock. */
+int cloudabi_clock_time_get(struct thread *, cloudabi_clockid_t,
+ cloudabi_timestamp_t *);
+
+/* Converts a FreeBSD errno to a CloudABI errno. */
+cloudabi_errno_t cloudabi_convert_errno(int);
+
+/* Converts a file descriptor to a CloudABI file descriptor type. */
+cloudabi_filetype_t cloudabi_convert_filetype(const struct file *);
+
+/* Converts CloudABI rights to a set of Capsicum capabilities. */
+int cloudabi_convert_rights(cloudabi_rights_t, cap_rights_t *);
+
+/* Removes rights that conflict with the file descriptor type. */
+void cloudabi_remove_conflicting_rights(cloudabi_filetype_t,
+ cloudabi_rights_t *, cloudabi_rights_t *);
+
+/* Converts a struct timespec to a CloudABI timestamp. */
+int cloudabi_convert_timespec(const struct timespec *, cloudabi_timestamp_t *);
+
+/*
+ * Blocking futex functions.
+ *
+ * These functions are called by CloudABI's polling system calls to
+ * sleep on a lock or condition variable.
+ */
+int cloudabi_futex_condvar_wait(struct thread *, cloudabi_condvar_t *,
+ cloudabi_scope_t, cloudabi_lock_t *, cloudabi_scope_t, cloudabi_clockid_t,
+ cloudabi_timestamp_t, cloudabi_timestamp_t, bool);
+int cloudabi_futex_lock_rdlock(struct thread *, cloudabi_lock_t *,
+ cloudabi_scope_t, cloudabi_clockid_t, cloudabi_timestamp_t,
+ cloudabi_timestamp_t, bool);
+int cloudabi_futex_lock_wrlock(struct thread *, cloudabi_lock_t *,
+ cloudabi_scope_t, cloudabi_clockid_t, cloudabi_timestamp_t,
+ cloudabi_timestamp_t, bool);
+
+/* Socket operations. */
+int cloudabi_sock_recv(struct thread *, cloudabi_fd_t, struct iovec *, size_t,
+ cloudabi_fd_t *, size_t, cloudabi_riflags_t, size_t *, size_t *,
+ cloudabi_roflags_t *);
+int cloudabi_sock_send(struct thread *, cloudabi_fd_t, struct iovec *, size_t,
+ const cloudabi_fd_t *, size_t, size_t *);
+
+/* vDSO setup and teardown. */
+void cloudabi_vdso_init(struct sysentvec *, char *, char *);
+void cloudabi_vdso_destroy(struct sysentvec *);
+
+#endif
diff --git a/sys/compat/cloudabi/cloudabi_vdso.c b/sys/compat/cloudabi/cloudabi_vdso.c
new file mode 100644
index 000000000000..ab621b3c18b0
--- /dev/null
+++ b/sys/compat/cloudabi/cloudabi_vdso.c
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (c) 2016 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/lock.h>
+#include <sys/sysent.h>
+#include <sys/rwlock.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+
+#include <compat/cloudabi/cloudabi_util.h>
+
+void
+cloudabi_vdso_init(struct sysentvec *sv, char *begin, char *end)
+{
+ vm_page_t m;
+ vm_object_t obj;
+ vm_offset_t addr;
+ size_t i, pages, pages_length, vdso_length;
+
+ /* Determine the number of pages needed to store the vDSO. */
+ vdso_length = end - begin;
+ pages = howmany(vdso_length, PAGE_SIZE);
+ pages_length = pages * PAGE_SIZE;
+
+ /* Allocate a VM object and fill it with the vDSO. */
+ obj = vm_pager_allocate(OBJT_PHYS, 0, pages_length,
+ VM_PROT_DEFAULT, 0, NULL);
+ addr = kva_alloc(PAGE_SIZE);
+ for (i = 0; i < pages; ++i) {
+ VM_OBJECT_WLOCK(obj);
+ m = vm_page_grab(obj, i, VM_ALLOC_ZERO);
+ VM_OBJECT_WUNLOCK(obj);
+ vm_page_valid(m);
+ vm_page_xunbusy(m);
+
+ pmap_qenter(addr, &m, 1);
+ memcpy((void *)addr, begin + i * PAGE_SIZE,
+ MIN(vdso_length - i * PAGE_SIZE, PAGE_SIZE));
+ pmap_qremove(addr, 1);
+ }
+ kva_free(addr, PAGE_SIZE);
+
+ /*
+ * Place the vDSO at the top of the address space. The user
+ * stack can start right below it.
+ */
+ sv->sv_shared_page_base = sv->sv_maxuser - pages_length;
+ sv->sv_shared_page_len = pages_length;
+ sv->sv_shared_page_obj = obj;
+ sv->sv_usrstack = sv->sv_shared_page_base;
+}
+
+void
+cloudabi_vdso_destroy(struct sysentvec *sv)
+{
+
+ vm_object_deallocate(sv->sv_shared_page_obj);
+}
diff --git a/sys/compat/cloudabi/cloudabi_vdso.lds b/sys/compat/cloudabi/cloudabi_vdso.lds
new file mode 100644
index 000000000000..807c48859bf2
--- /dev/null
+++ b/sys/compat/cloudabi/cloudabi_vdso.lds
@@ -0,0 +1,51 @@
+/*
+ * Linker script for the vDSO for CloudABI.
+ * Based on sys/amd64/linux/linux_vdso.lds.s
+ *
+ * $FreeBSD$
+ */
+
+SECTIONS
+{
+ . = . + SIZEOF_HEADERS;
+
+ .hash : { *(.hash) } :text
+ .gnu.hash : { *(.gnu.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+
+ .note : { *(.note.*) } :text :note
+
+ .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
+ .eh_frame : { KEEP (*(.eh_frame)) } :text
+
+ .dynamic : { *(.dynamic) } :text :dynamic
+
+ .rodata : { *(.rodata*) } :text
+ .data : {
+ *(.data*)
+ *(.sdata*)
+ *(.got.plt) *(.got)
+ *(.gnu.linkonce.d.*)
+ *(.bss*)
+ *(.dynbss*)
+ *(.gnu.linkonce.b.*)
+ }
+
+ .altinstructions : { *(.altinstructions) }
+ .altinstr_replacement : { *(.altinstr_replacement) }
+
+ . = ALIGN(0x100);
+ .text : { *(.test .text*) } :text =0x90909090
+}
+
+PHDRS
+{
+ text PT_LOAD FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */
+ dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
+ note PT_NOTE FLAGS(4); /* PF_R */
+ eh_frame_hdr PT_GNU_EH_FRAME;
+}
diff --git a/sys/compat/cloudabi32/Makefile b/sys/compat/cloudabi32/Makefile
new file mode 100644
index 000000000000..9b059738c45d
--- /dev/null
+++ b/sys/compat/cloudabi32/Makefile
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+SYSENT_FILE= ${SYSDIR}/contrib/cloudabi/syscalls32.master
+GENERATED_PREFIX= cloudabi32_
+
+.include "../../conf/sysent.mk"
diff --git a/sys/compat/cloudabi32/cloudabi32_fd.c b/sys/compat/cloudabi32/cloudabi32_fd.c
new file mode 100644
index 000000000000..19907a95b07e
--- /dev/null
+++ b/sys/compat/cloudabi32/cloudabi32_fd.c
@@ -0,0 +1,145 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/malloc.h>
+#include <sys/syscallsubr.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
+
+#include <contrib/cloudabi/cloudabi32_types.h>
+
+#include <compat/cloudabi32/cloudabi32_proto.h>
+#include <compat/cloudabi32/cloudabi32_util.h>
+
+/* Copies in 32-bit iovec structures from userspace. */
+static int
+cloudabi32_copyinuio(const cloudabi32_iovec_t *iovp, size_t iovcnt,
+ struct uio **uiop)
+{
+ cloudabi32_iovec_t iovobj;
+ struct uio *uio;
+ struct iovec *iov;
+ size_t i;
+ int error;
+
+ /* Allocate uio and iovecs. */
+ if (iovcnt > UIO_MAXIOV)
+ return (EINVAL);
+ uio = malloc(sizeof(struct uio) + iovcnt * sizeof(struct iovec),
+ M_IOV, M_WAITOK);
+ iov = (struct iovec *)(uio + 1);
+
+ /* Initialize uio. */
+ uio->uio_iov = iov;
+ uio->uio_iovcnt = iovcnt;
+ uio->uio_segflg = UIO_USERSPACE;
+ uio->uio_offset = -1;
+ uio->uio_resid = 0;
+
+ /* Copy in iovecs. */
+ for (i = 0; i < iovcnt; i++) {
+ error = copyin(&iovp[i], &iovobj, sizeof(iovobj));
+ if (error != 0) {
+ free(uio, M_IOV);
+ return (error);
+ }
+ iov[i].iov_base = TO_PTR(iovobj.buf);
+ iov[i].iov_len = iovobj.buf_len;
+ if (iov[i].iov_len > INT32_MAX - uio->uio_resid) {
+ free(uio, M_IOV);
+ return (EINVAL);
+ }
+ uio->uio_resid += iov[i].iov_len;
+ }
+
+ *uiop = uio;
+ return (0);
+}
+
+int
+cloudabi32_sys_fd_pread(struct thread *td,
+ struct cloudabi32_sys_fd_pread_args *uap)
+{
+ struct uio *uio;
+ int error;
+
+ error = cloudabi32_copyinuio(uap->iovs, uap->iovs_len, &uio);
+ if (error != 0)
+ return (error);
+ error = kern_preadv(td, uap->fd, uio, uap->offset);
+ free(uio, M_IOV);
+ return (error);
+}
+
+int
+cloudabi32_sys_fd_pwrite(struct thread *td,
+ struct cloudabi32_sys_fd_pwrite_args *uap)
+{
+ struct uio *uio;
+ int error;
+
+ error = cloudabi32_copyinuio(TO_PTR(uap->iovs), uap->iovs_len, &uio);
+ if (error != 0)
+ return (error);
+ error = kern_pwritev(td, uap->fd, uio, uap->offset);
+ free(uio, M_IOV);
+ return (error);
+}
+
+int
+cloudabi32_sys_fd_read(struct thread *td,
+ struct cloudabi32_sys_fd_read_args *uap)
+{
+ struct uio *uio;
+ int error;
+
+ error = cloudabi32_copyinuio(uap->iovs, uap->iovs_len, &uio);
+ if (error != 0)
+ return (error);
+ error = kern_readv(td, uap->fd, uio);
+ free(uio, M_IOV);
+ return (error);
+}
+
+int
+cloudabi32_sys_fd_write(struct thread *td,
+ struct cloudabi32_sys_fd_write_args *uap)
+{
+ struct uio *uio;
+ int error;
+
+ error = cloudabi32_copyinuio(TO_PTR(uap->iovs), uap->iovs_len, &uio);
+ if (error != 0)
+ return (error);
+ error = kern_writev(td, uap->fd, uio);
+ free(uio, M_IOV);
+ return (error);
+}
diff --git a/sys/compat/cloudabi32/cloudabi32_module.c b/sys/compat/cloudabi32/cloudabi32_module.c
new file mode 100644
index 000000000000..3463101193a5
--- /dev/null
+++ b/sys/compat/cloudabi32/cloudabi32_module.c
@@ -0,0 +1,184 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/imgact.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/proc.h>
+#include <sys/smp.h>
+#include <sys/sysctl.h>
+#include <sys/sysent.h>
+#include <sys/systm.h>
+
+#include <contrib/cloudabi/cloudabi32_types.h>
+
+#include <compat/cloudabi/cloudabi_util.h>
+
+#include <compat/cloudabi32/cloudabi32_util.h>
+
+extern char _binary_cloudabi32_vdso_o_start[];
+extern char _binary_cloudabi32_vdso_o_end[];
+
+int
+cloudabi32_copyout_strings(struct image_params *imgp, uintptr_t *stack_base)
+{
+ struct image_args *args;
+ uintptr_t begin;
+ size_t len;
+
+ /* Copy out program arguments. */
+ args = imgp->args;
+ len = exec_args_get_begin_envv(args) - args->begin_argv;
+ begin = rounddown2(imgp->sysent->sv_usrstack - len, sizeof(register_t));
+ *stack_base = begin;
+ return (copyout(args->begin_argv, (void *)begin, len));
+}
+
+int
+cloudabi32_fixup(uintptr_t *stack_base, struct image_params *imgp)
+{
+ char canarybuf[64], pidbuf[16];
+ Elf32_Auxargs *args;
+ struct thread *td;
+ void *argdata, *canary, *pid;
+ size_t argdatalen;
+ int error;
+
+ /*
+ * CloudABI executables do not store the FreeBSD OS release
+ * number in their header. Set the OS release number to the
+ * latest version of FreeBSD, so that system calls behave as if
+ * called natively.
+ */
+ td = curthread;
+ td->td_proc->p_osrel = __FreeBSD_version;
+
+ argdata = (void *)*stack_base;
+
+ /* Store canary for stack smashing protection. */
+ arc4rand(canarybuf, sizeof(canarybuf), 0);
+ *stack_base -= roundup(sizeof(canarybuf), sizeof(register_t));
+ canary = (void *)*stack_base;
+ error = copyout(canarybuf, canary, sizeof(canarybuf));
+ if (error != 0)
+ return (error);
+
+ /*
+ * Generate a random UUID that identifies the process. Right now
+ * we don't store this UUID in the kernel. Ideally, it should be
+ * exposed through ps(1).
+ */
+ arc4rand(pidbuf, sizeof(pidbuf), 0);
+ pidbuf[6] = (pidbuf[6] & 0x0f) | 0x40;
+ pidbuf[8] = (pidbuf[8] & 0x3f) | 0x80;
+ *stack_base -= roundup(sizeof(pidbuf), sizeof(register_t));
+ pid = (void *)*stack_base;
+ error = copyout(pidbuf, pid, sizeof(pidbuf));
+ if (error != 0)
+ return (error);
+
+ /*
+ * Compute length of program arguments. As the argument data is
+ * binary safe, we had to add a trailing null byte in
+ * exec_copyin_data_fds(). Undo this by reducing the length.
+ */
+ args = (Elf32_Auxargs *)imgp->auxargs;
+ argdatalen = exec_args_get_begin_envv(imgp->args) -
+ imgp->args->begin_argv;
+ if (argdatalen > 0)
+ --argdatalen;
+
+ /* Write out an auxiliary vector. */
+ cloudabi32_auxv_t auxv[] = {
+#define VAL(type, val) { .a_type = (type), .a_val = (val) }
+#define PTR(type, ptr) { .a_type = (type), .a_ptr = (uintptr_t)(ptr) }
+ PTR(CLOUDABI_AT_ARGDATA, argdata),
+ VAL(CLOUDABI_AT_ARGDATALEN, argdatalen),
+ VAL(CLOUDABI_AT_BASE, args->base),
+ PTR(CLOUDABI_AT_CANARY, canary),
+ VAL(CLOUDABI_AT_CANARYLEN, sizeof(canarybuf)),
+ VAL(CLOUDABI_AT_NCPUS, mp_ncpus),
+ VAL(CLOUDABI_AT_PAGESZ, args->pagesz),
+ PTR(CLOUDABI_AT_PHDR, args->phdr),
+ VAL(CLOUDABI_AT_PHNUM, args->phnum),
+ PTR(CLOUDABI_AT_PID, pid),
+ PTR(CLOUDABI_AT_SYSINFO_EHDR,
+ imgp->proc->p_sysent->sv_shared_page_base),
+ VAL(CLOUDABI_AT_TID, td->td_tid),
+#undef VAL
+#undef PTR
+ { .a_type = CLOUDABI_AT_NULL },
+ };
+ *stack_base -= roundup(sizeof(auxv), sizeof(register_t));
+ error = copyout(auxv, (void *)*stack_base, sizeof(auxv));
+ if (error != 0)
+ return (error);
+
+ /* Reserve space for storing the TCB. */
+ *stack_base -= roundup(sizeof(cloudabi32_tcb_t), sizeof(register_t));
+ return (0);
+}
+
+static int
+cloudabi32_modevent(module_t mod, int type, void *data)
+{
+
+ switch (type) {
+ case MOD_LOAD:
+ cloudabi_vdso_init(cloudabi32_brand.sysvec,
+ _binary_cloudabi32_vdso_o_start,
+ _binary_cloudabi32_vdso_o_end);
+ if (elf32_insert_brand_entry(&cloudabi32_brand) < 0) {
+ printf("Failed to add CloudABI ELF brand handler\n");
+ return (EINVAL);
+ }
+ return (0);
+ case MOD_UNLOAD:
+ if (elf32_brand_inuse(&cloudabi32_brand))
+ return (EBUSY);
+ if (elf32_remove_brand_entry(&cloudabi32_brand) < 0) {
+ printf("Failed to remove CloudABI ELF brand handler\n");
+ return (EINVAL);
+ }
+ cloudabi_vdso_destroy(cloudabi32_brand.sysvec);
+ return (0);
+ default:
+ return (EOPNOTSUPP);
+ }
+}
+
+static moduledata_t cloudabi32_module = {
+ "cloudabi32",
+ cloudabi32_modevent,
+ NULL
+};
+
+DECLARE_MODULE_TIED(cloudabi32, cloudabi32_module, SI_SUB_EXEC, SI_ORDER_ANY);
+MODULE_DEPEND(cloudabi32, cloudabi, 1, 1, 1);
+FEATURE(cloudabi32, "CloudABI 32bit support");
diff --git a/sys/compat/cloudabi32/cloudabi32_poll.c b/sys/compat/cloudabi32/cloudabi32_poll.c
new file mode 100644
index 000000000000..2fda78f8adf9
--- /dev/null
+++ b/sys/compat/cloudabi32/cloudabi32_poll.c
@@ -0,0 +1,340 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/syscallsubr.h>
+
+#include <contrib/cloudabi/cloudabi32_types.h>
+
+#include <compat/cloudabi/cloudabi_util.h>
+
+#include <compat/cloudabi32/cloudabi32_proto.h>
+#include <compat/cloudabi32/cloudabi32_util.h>
+
+/* Converts a FreeBSD signal number to a CloudABI signal number. */
+static cloudabi_signal_t
+convert_signal(int sig)
+{
+ static const cloudabi_signal_t signals[] = {
+ [SIGABRT] = CLOUDABI_SIGABRT,
+ [SIGALRM] = CLOUDABI_SIGALRM,
+ [SIGBUS] = CLOUDABI_SIGBUS,
+ [SIGCHLD] = CLOUDABI_SIGCHLD,
+ [SIGCONT] = CLOUDABI_SIGCONT,
+ [SIGFPE] = CLOUDABI_SIGFPE,
+ [SIGHUP] = CLOUDABI_SIGHUP,
+ [SIGILL] = CLOUDABI_SIGILL,
+ [SIGINT] = CLOUDABI_SIGINT,
+ [SIGKILL] = CLOUDABI_SIGKILL,
+ [SIGPIPE] = CLOUDABI_SIGPIPE,
+ [SIGQUIT] = CLOUDABI_SIGQUIT,
+ [SIGSEGV] = CLOUDABI_SIGSEGV,
+ [SIGSTOP] = CLOUDABI_SIGSTOP,
+ [SIGSYS] = CLOUDABI_SIGSYS,
+ [SIGTERM] = CLOUDABI_SIGTERM,
+ [SIGTRAP] = CLOUDABI_SIGTRAP,
+ [SIGTSTP] = CLOUDABI_SIGTSTP,
+ [SIGTTIN] = CLOUDABI_SIGTTIN,
+ [SIGTTOU] = CLOUDABI_SIGTTOU,
+ [SIGURG] = CLOUDABI_SIGURG,
+ [SIGUSR1] = CLOUDABI_SIGUSR1,
+ [SIGUSR2] = CLOUDABI_SIGUSR2,
+ [SIGVTALRM] = CLOUDABI_SIGVTALRM,
+ [SIGXCPU] = CLOUDABI_SIGXCPU,
+ [SIGXFSZ] = CLOUDABI_SIGXFSZ,
+ };
+
+ /* Convert unknown signals to SIGABRT. */
+ if (sig < 0 || sig >= nitems(signals) || signals[sig] == 0)
+ return (SIGABRT);
+ return (signals[sig]);
+}
+
+struct cloudabi32_kevent_args {
+ const cloudabi32_subscription_t *in;
+ cloudabi_event_t *out;
+};
+
+/* Converts CloudABI's subscription objects to FreeBSD's struct kevent. */
+static int
+cloudabi32_kevent_copyin(void *arg, struct kevent *kevp, int count)
+{
+ cloudabi32_subscription_t sub;
+ struct cloudabi32_kevent_args *args;
+ cloudabi_timestamp_t ts;
+ int error;
+
+ args = arg;
+ while (count-- > 0) {
+ /* TODO(ed): Copy in multiple entries at once. */
+ error = copyin(args->in++, &sub, sizeof(sub));
+ if (error != 0)
+ return (error);
+
+ memset(kevp, 0, sizeof(*kevp));
+ kevp->udata = TO_PTR(sub.userdata);
+ switch (sub.type) {
+ case CLOUDABI_EVENTTYPE_CLOCK:
+ kevp->filter = EVFILT_TIMER;
+ kevp->ident = sub.clock.identifier;
+ kevp->fflags = NOTE_NSECONDS;
+ if ((sub.clock.flags &
+ CLOUDABI_SUBSCRIPTION_CLOCK_ABSTIME) != 0 &&
+ sub.clock.timeout > 0) {
+ /* Convert absolute timestamp to a relative. */
+ error = cloudabi_clock_time_get(curthread,
+ sub.clock.clock_id, &ts);
+ if (error != 0)
+ return (error);
+ ts = ts > sub.clock.timeout ? 0 :
+ sub.clock.timeout - ts;
+ } else {
+ /* Relative timestamp. */
+ ts = sub.clock.timeout;
+ }
+ kevp->data = ts > INTPTR_MAX ? INTPTR_MAX : ts;
+ break;
+ case CLOUDABI_EVENTTYPE_FD_READ:
+ kevp->filter = EVFILT_READ;
+ kevp->ident = sub.fd_readwrite.fd;
+ kevp->fflags = NOTE_FILE_POLL;
+ break;
+ case CLOUDABI_EVENTTYPE_FD_WRITE:
+ kevp->filter = EVFILT_WRITE;
+ kevp->ident = sub.fd_readwrite.fd;
+ break;
+ case CLOUDABI_EVENTTYPE_PROC_TERMINATE:
+ kevp->filter = EVFILT_PROCDESC;
+ kevp->ident = sub.proc_terminate.fd;
+ kevp->fflags = NOTE_EXIT;
+ break;
+ }
+ kevp->flags = EV_ADD | EV_ONESHOT;
+ ++kevp;
+ }
+ return (0);
+}
+
+/* Converts FreeBSD's struct kevent to CloudABI's event objects. */
+static int
+cloudabi32_kevent_copyout(void *arg, struct kevent *kevp, int count)
+{
+ cloudabi_event_t ev;
+ struct cloudabi32_kevent_args *args;
+ int error;
+
+ args = arg;
+ while (count-- > 0) {
+ /* Convert fields that should always be present. */
+ memset(&ev, 0, sizeof(ev));
+ ev.userdata = (uintptr_t)kevp->udata;
+ switch (kevp->filter) {
+ case EVFILT_TIMER:
+ ev.type = CLOUDABI_EVENTTYPE_CLOCK;
+ break;
+ case EVFILT_READ:
+ ev.type = CLOUDABI_EVENTTYPE_FD_READ;
+ break;
+ case EVFILT_WRITE:
+ ev.type = CLOUDABI_EVENTTYPE_FD_WRITE;
+ break;
+ case EVFILT_PROCDESC:
+ ev.type = CLOUDABI_EVENTTYPE_PROC_TERMINATE;
+ break;
+ }
+
+ if ((kevp->flags & EV_ERROR) == 0) {
+ /* Success. */
+ switch (kevp->filter) {
+ case EVFILT_READ:
+ case EVFILT_WRITE:
+ ev.fd_readwrite.nbytes = kevp->data;
+ if ((kevp->flags & EV_EOF) != 0) {
+ ev.fd_readwrite.flags |=
+ CLOUDABI_EVENT_FD_READWRITE_HANGUP;
+ }
+ break;
+ case EVFILT_PROCDESC:
+ if (WIFSIGNALED(kevp->data)) {
+ /* Process got signalled. */
+ ev.proc_terminate.signal =
+ convert_signal(WTERMSIG(kevp->data));
+ ev.proc_terminate.exitcode = 0;
+ } else {
+ /* Process exited. */
+ ev.proc_terminate.signal = 0;
+ ev.proc_terminate.exitcode =
+ WEXITSTATUS(kevp->data);
+ }
+ break;
+ }
+ } else {
+ /* Error. */
+ ev.error = cloudabi_convert_errno(kevp->data);
+ }
+ ++kevp;
+
+ /* TODO(ed): Copy out multiple entries at once. */
+ error = copyout(&ev, args->out++, sizeof(ev));
+ if (error != 0)
+ return (error);
+ }
+ return (0);
+}
+
+int
+cloudabi32_sys_poll(struct thread *td, struct cloudabi32_sys_poll_args *uap)
+{
+ struct cloudabi32_kevent_args args = {
+ .in = uap->in,
+ .out = uap->out,
+ };
+ struct kevent_copyops copyops = {
+ .k_copyin = cloudabi32_kevent_copyin,
+ .k_copyout = cloudabi32_kevent_copyout,
+ .arg = &args,
+ };
+
+ /*
+ * Bandaid to support CloudABI futex constructs that are not
+ * implemented through FreeBSD's kqueue().
+ */
+ if (uap->nsubscriptions == 1) {
+ cloudabi32_subscription_t sub;
+ cloudabi_event_t ev = {};
+ int error;
+
+ error = copyin(uap->in, &sub, sizeof(sub));
+ if (error != 0)
+ return (error);
+ ev.userdata = sub.userdata;
+ ev.type = sub.type;
+ if (sub.type == CLOUDABI_EVENTTYPE_CONDVAR) {
+ /* Wait on a condition variable. */
+ ev.error = cloudabi_convert_errno(
+ cloudabi_futex_condvar_wait(
+ td, TO_PTR(sub.condvar.condvar),
+ sub.condvar.condvar_scope,
+ TO_PTR(sub.condvar.lock),
+ sub.condvar.lock_scope,
+ CLOUDABI_CLOCK_MONOTONIC, UINT64_MAX, 0, true));
+ td->td_retval[0] = 1;
+ return (copyout(&ev, uap->out, sizeof(ev)));
+ } else if (sub.type == CLOUDABI_EVENTTYPE_LOCK_RDLOCK) {
+ /* Acquire a read lock. */
+ ev.error = cloudabi_convert_errno(
+ cloudabi_futex_lock_rdlock(
+ td, TO_PTR(sub.lock.lock),
+ sub.lock.lock_scope, CLOUDABI_CLOCK_MONOTONIC,
+ UINT64_MAX, 0, true));
+ td->td_retval[0] = 1;
+ return (copyout(&ev, uap->out, sizeof(ev)));
+ } else if (sub.type == CLOUDABI_EVENTTYPE_LOCK_WRLOCK) {
+ /* Acquire a write lock. */
+ ev.error = cloudabi_convert_errno(
+ cloudabi_futex_lock_wrlock(
+ td, TO_PTR(sub.lock.lock),
+ sub.lock.lock_scope, CLOUDABI_CLOCK_MONOTONIC,
+ UINT64_MAX, 0, true));
+ td->td_retval[0] = 1;
+ return (copyout(&ev, uap->out, sizeof(ev)));
+ }
+ } else if (uap->nsubscriptions == 2) {
+ cloudabi32_subscription_t sub[2];
+ cloudabi_event_t ev[2] = {};
+ int error;
+
+ error = copyin(uap->in, &sub, sizeof(sub));
+ if (error != 0)
+ return (error);
+ ev[0].userdata = sub[0].userdata;
+ ev[0].type = sub[0].type;
+ ev[1].userdata = sub[1].userdata;
+ ev[1].type = sub[1].type;
+ if (sub[0].type == CLOUDABI_EVENTTYPE_CONDVAR &&
+ sub[1].type == CLOUDABI_EVENTTYPE_CLOCK) {
+ /* Wait for a condition variable with timeout. */
+ error = cloudabi_futex_condvar_wait(
+ td, TO_PTR(sub[0].condvar.condvar),
+ sub[0].condvar.condvar_scope,
+ TO_PTR(sub[0].condvar.lock),
+ sub[0].condvar.lock_scope, sub[1].clock.clock_id,
+ sub[1].clock.timeout, sub[1].clock.precision,
+ (sub[1].clock.flags &
+ CLOUDABI_SUBSCRIPTION_CLOCK_ABSTIME) != 0);
+ if (error == ETIMEDOUT) {
+ td->td_retval[0] = 1;
+ return (copyout(&ev[1], uap->out,
+ sizeof(ev[1])));
+ }
+
+ ev[0].error = cloudabi_convert_errno(error);
+ td->td_retval[0] = 1;
+ return (copyout(&ev[0], uap->out, sizeof(ev[0])));
+ } else if (sub[0].type == CLOUDABI_EVENTTYPE_LOCK_RDLOCK &&
+ sub[1].type == CLOUDABI_EVENTTYPE_CLOCK) {
+ /* Acquire a read lock with a timeout. */
+ error = cloudabi_futex_lock_rdlock(
+ td, TO_PTR(sub[0].lock.lock),
+ sub[0].lock.lock_scope, sub[1].clock.clock_id,
+ sub[1].clock.timeout, sub[1].clock.precision,
+ (sub[1].clock.flags &
+ CLOUDABI_SUBSCRIPTION_CLOCK_ABSTIME) != 0);
+ if (error == ETIMEDOUT) {
+ td->td_retval[0] = 1;
+ return (copyout(&ev[1], uap->out,
+ sizeof(ev[1])));
+ }
+
+ ev[0].error = cloudabi_convert_errno(error);
+ td->td_retval[0] = 1;
+ return (copyout(&ev[0], uap->out, sizeof(ev[0])));
+ } else if (sub[0].type == CLOUDABI_EVENTTYPE_LOCK_WRLOCK &&
+ sub[1].type == CLOUDABI_EVENTTYPE_CLOCK) {
+ /* Acquire a write lock with a timeout. */
+ error = cloudabi_futex_lock_wrlock(
+ td, TO_PTR(sub[0].lock.lock),
+ sub[0].lock.lock_scope, sub[1].clock.clock_id,
+ sub[1].clock.timeout, sub[1].clock.precision,
+ (sub[1].clock.flags &
+ CLOUDABI_SUBSCRIPTION_CLOCK_ABSTIME) != 0);
+ if (error == ETIMEDOUT) {
+ td->td_retval[0] = 1;
+ return (copyout(&ev[1], uap->out,
+ sizeof(ev[1])));
+ }
+
+ ev[0].error = cloudabi_convert_errno(error);
+ td->td_retval[0] = 1;
+ return (copyout(&ev[0], uap->out, sizeof(ev[0])));
+ }
+ }
+
+ return (kern_kevent_anonymous(td, uap->nsubscriptions, &copyops));
+}
diff --git a/sys/compat/cloudabi32/cloudabi32_proto.h b/sys/compat/cloudabi32/cloudabi32_proto.h
new file mode 100644
index 000000000000..453c6db1fd8b
--- /dev/null
+++ b/sys/compat/cloudabi32/cloudabi32_proto.h
@@ -0,0 +1,420 @@
+/*
+ * System call prototypes.
+ *
+ * DO NOT EDIT-- this file is automatically @generated.
+ * $FreeBSD$
+ */
+
+#ifndef _CLOUDABI32_SYSPROTO_H_
+#define _CLOUDABI32_SYSPROTO_H_
+
+#include <sys/signal.h>
+#include <sys/acl.h>
+#include <sys/cpuset.h>
+#include <sys/domainset.h>
+#include <sys/_ffcounter.h>
+#include <sys/_semaphore.h>
+#include <sys/ucontext.h>
+#include <sys/wait.h>
+
+#include <bsm/audit_kevents.h>
+
+struct proc;
+
+struct thread;
+
+#define PAD_(t) (sizeof(register_t) <= sizeof(t) ? \
+ 0 : sizeof(register_t) - sizeof(t))
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define PADL_(t) 0
+#define PADR_(t) PAD_(t)
+#else
+#define PADL_(t) PAD_(t)
+#define PADR_(t) 0
+#endif
+
+struct cloudabi_sys_clock_res_get_args {
+ char clock_id_l_[PADL_(cloudabi_clockid_t)]; cloudabi_clockid_t clock_id; char clock_id_r_[PADR_(cloudabi_clockid_t)];
+};
+struct cloudabi_sys_clock_time_get_args {
+ char clock_id_l_[PADL_(cloudabi_clockid_t)]; cloudabi_clockid_t clock_id; char clock_id_r_[PADR_(cloudabi_clockid_t)];
+ char precision_l_[PADL_(cloudabi_timestamp_t)]; cloudabi_timestamp_t precision; char precision_r_[PADR_(cloudabi_timestamp_t)];
+};
+struct cloudabi_sys_condvar_signal_args {
+ char condvar_l_[PADL_(cloudabi_condvar_t *)]; cloudabi_condvar_t * condvar; char condvar_r_[PADR_(cloudabi_condvar_t *)];
+ char scope_l_[PADL_(cloudabi_scope_t)]; cloudabi_scope_t scope; char scope_r_[PADR_(cloudabi_scope_t)];
+ char nwaiters_l_[PADL_(cloudabi_nthreads_t)]; cloudabi_nthreads_t nwaiters; char nwaiters_r_[PADR_(cloudabi_nthreads_t)];
+};
+struct cloudabi_sys_fd_close_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+};
+struct cloudabi_sys_fd_create1_args {
+ char type_l_[PADL_(cloudabi_filetype_t)]; cloudabi_filetype_t type; char type_r_[PADR_(cloudabi_filetype_t)];
+};
+struct cloudabi_sys_fd_create2_args {
+ char type_l_[PADL_(cloudabi_filetype_t)]; cloudabi_filetype_t type; char type_r_[PADR_(cloudabi_filetype_t)];
+};
+struct cloudabi_sys_fd_datasync_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+};
+struct cloudabi_sys_fd_dup_args {
+ char from_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t from; char from_r_[PADR_(cloudabi_fd_t)];
+};
+struct cloudabi32_sys_fd_pread_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char iovs_l_[PADL_(const cloudabi32_iovec_t *)]; const cloudabi32_iovec_t * iovs; char iovs_r_[PADR_(const cloudabi32_iovec_t *)];
+ char iovs_len_l_[PADL_(size_t)]; size_t iovs_len; char iovs_len_r_[PADR_(size_t)];
+ char offset_l_[PADL_(cloudabi_filesize_t)]; cloudabi_filesize_t offset; char offset_r_[PADR_(cloudabi_filesize_t)];
+};
+struct cloudabi32_sys_fd_pwrite_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char iovs_l_[PADL_(const cloudabi32_ciovec_t *)]; const cloudabi32_ciovec_t * iovs; char iovs_r_[PADR_(const cloudabi32_ciovec_t *)];
+ char iovs_len_l_[PADL_(size_t)]; size_t iovs_len; char iovs_len_r_[PADR_(size_t)];
+ char offset_l_[PADL_(cloudabi_filesize_t)]; cloudabi_filesize_t offset; char offset_r_[PADR_(cloudabi_filesize_t)];
+};
+struct cloudabi32_sys_fd_read_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char iovs_l_[PADL_(const cloudabi32_iovec_t *)]; const cloudabi32_iovec_t * iovs; char iovs_r_[PADR_(const cloudabi32_iovec_t *)];
+ char iovs_len_l_[PADL_(size_t)]; size_t iovs_len; char iovs_len_r_[PADR_(size_t)];
+};
+struct cloudabi_sys_fd_replace_args {
+ char from_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t from; char from_r_[PADR_(cloudabi_fd_t)];
+ char to_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t to; char to_r_[PADR_(cloudabi_fd_t)];
+};
+struct cloudabi_sys_fd_seek_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char offset_l_[PADL_(cloudabi_filedelta_t)]; cloudabi_filedelta_t offset; char offset_r_[PADR_(cloudabi_filedelta_t)];
+ char whence_l_[PADL_(cloudabi_whence_t)]; cloudabi_whence_t whence; char whence_r_[PADR_(cloudabi_whence_t)];
+};
+struct cloudabi_sys_fd_stat_get_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char buf_l_[PADL_(cloudabi_fdstat_t *)]; cloudabi_fdstat_t * buf; char buf_r_[PADR_(cloudabi_fdstat_t *)];
+};
+struct cloudabi_sys_fd_stat_put_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char buf_l_[PADL_(const cloudabi_fdstat_t *)]; const cloudabi_fdstat_t * buf; char buf_r_[PADR_(const cloudabi_fdstat_t *)];
+ char flags_l_[PADL_(cloudabi_fdsflags_t)]; cloudabi_fdsflags_t flags; char flags_r_[PADR_(cloudabi_fdsflags_t)];
+};
+struct cloudabi_sys_fd_sync_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+};
+struct cloudabi32_sys_fd_write_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char iovs_l_[PADL_(const cloudabi32_ciovec_t *)]; const cloudabi32_ciovec_t * iovs; char iovs_r_[PADR_(const cloudabi32_ciovec_t *)];
+ char iovs_len_l_[PADL_(size_t)]; size_t iovs_len; char iovs_len_r_[PADR_(size_t)];
+};
+struct cloudabi_sys_file_advise_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char offset_l_[PADL_(cloudabi_filesize_t)]; cloudabi_filesize_t offset; char offset_r_[PADR_(cloudabi_filesize_t)];
+ char len_l_[PADL_(cloudabi_filesize_t)]; cloudabi_filesize_t len; char len_r_[PADR_(cloudabi_filesize_t)];
+ char advice_l_[PADL_(cloudabi_advice_t)]; cloudabi_advice_t advice; char advice_r_[PADR_(cloudabi_advice_t)];
+};
+struct cloudabi_sys_file_allocate_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char offset_l_[PADL_(cloudabi_filesize_t)]; cloudabi_filesize_t offset; char offset_r_[PADR_(cloudabi_filesize_t)];
+ char len_l_[PADL_(cloudabi_filesize_t)]; cloudabi_filesize_t len; char len_r_[PADR_(cloudabi_filesize_t)];
+};
+struct cloudabi_sys_file_create_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char path_len_l_[PADL_(size_t)]; size_t path_len; char path_len_r_[PADR_(size_t)];
+ char type_l_[PADL_(cloudabi_filetype_t)]; cloudabi_filetype_t type; char type_r_[PADR_(cloudabi_filetype_t)];
+};
+struct cloudabi_sys_file_link_args {
+ char fd1_l_[PADL_(cloudabi_lookup_t)]; cloudabi_lookup_t fd1; char fd1_r_[PADR_(cloudabi_lookup_t)];
+ char path1_l_[PADL_(const char *)]; const char * path1; char path1_r_[PADR_(const char *)];
+ char path1_len_l_[PADL_(size_t)]; size_t path1_len; char path1_len_r_[PADR_(size_t)];
+ char fd2_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd2; char fd2_r_[PADR_(cloudabi_fd_t)];
+ char path2_l_[PADL_(const char *)]; const char * path2; char path2_r_[PADR_(const char *)];
+ char path2_len_l_[PADL_(size_t)]; size_t path2_len; char path2_len_r_[PADR_(size_t)];
+};
+struct cloudabi_sys_file_open_args {
+ char dirfd_l_[PADL_(cloudabi_lookup_t)]; cloudabi_lookup_t dirfd; char dirfd_r_[PADR_(cloudabi_lookup_t)];
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char path_len_l_[PADL_(size_t)]; size_t path_len; char path_len_r_[PADR_(size_t)];
+ char oflags_l_[PADL_(cloudabi_oflags_t)]; cloudabi_oflags_t oflags; char oflags_r_[PADR_(cloudabi_oflags_t)];
+ char fds_l_[PADL_(const cloudabi_fdstat_t *)]; const cloudabi_fdstat_t * fds; char fds_r_[PADR_(const cloudabi_fdstat_t *)];
+};
+struct cloudabi_sys_file_readdir_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char buf_l_[PADL_(void *)]; void * buf; char buf_r_[PADR_(void *)];
+ char buf_len_l_[PADL_(size_t)]; size_t buf_len; char buf_len_r_[PADR_(size_t)];
+ char cookie_l_[PADL_(cloudabi_dircookie_t)]; cloudabi_dircookie_t cookie; char cookie_r_[PADR_(cloudabi_dircookie_t)];
+};
+struct cloudabi_sys_file_readlink_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char path_len_l_[PADL_(size_t)]; size_t path_len; char path_len_r_[PADR_(size_t)];
+ char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)];
+ char buf_len_l_[PADL_(size_t)]; size_t buf_len; char buf_len_r_[PADR_(size_t)];
+};
+struct cloudabi_sys_file_rename_args {
+ char fd1_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd1; char fd1_r_[PADR_(cloudabi_fd_t)];
+ char path1_l_[PADL_(const char *)]; const char * path1; char path1_r_[PADR_(const char *)];
+ char path1_len_l_[PADL_(size_t)]; size_t path1_len; char path1_len_r_[PADR_(size_t)];
+ char fd2_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd2; char fd2_r_[PADR_(cloudabi_fd_t)];
+ char path2_l_[PADL_(const char *)]; const char * path2; char path2_r_[PADR_(const char *)];
+ char path2_len_l_[PADL_(size_t)]; size_t path2_len; char path2_len_r_[PADR_(size_t)];
+};
+struct cloudabi_sys_file_stat_fget_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char buf_l_[PADL_(cloudabi_filestat_t *)]; cloudabi_filestat_t * buf; char buf_r_[PADR_(cloudabi_filestat_t *)];
+};
+struct cloudabi_sys_file_stat_fput_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char buf_l_[PADL_(const cloudabi_filestat_t *)]; const cloudabi_filestat_t * buf; char buf_r_[PADR_(const cloudabi_filestat_t *)];
+ char flags_l_[PADL_(cloudabi_fsflags_t)]; cloudabi_fsflags_t flags; char flags_r_[PADR_(cloudabi_fsflags_t)];
+};
+struct cloudabi_sys_file_stat_get_args {
+ char fd_l_[PADL_(cloudabi_lookup_t)]; cloudabi_lookup_t fd; char fd_r_[PADR_(cloudabi_lookup_t)];
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char path_len_l_[PADL_(size_t)]; size_t path_len; char path_len_r_[PADR_(size_t)];
+ char buf_l_[PADL_(cloudabi_filestat_t *)]; cloudabi_filestat_t * buf; char buf_r_[PADR_(cloudabi_filestat_t *)];
+};
+struct cloudabi_sys_file_stat_put_args {
+ char fd_l_[PADL_(cloudabi_lookup_t)]; cloudabi_lookup_t fd; char fd_r_[PADR_(cloudabi_lookup_t)];
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char path_len_l_[PADL_(size_t)]; size_t path_len; char path_len_r_[PADR_(size_t)];
+ char buf_l_[PADL_(const cloudabi_filestat_t *)]; const cloudabi_filestat_t * buf; char buf_r_[PADR_(const cloudabi_filestat_t *)];
+ char flags_l_[PADL_(cloudabi_fsflags_t)]; cloudabi_fsflags_t flags; char flags_r_[PADR_(cloudabi_fsflags_t)];
+};
+struct cloudabi_sys_file_symlink_args {
+ char path1_l_[PADL_(const char *)]; const char * path1; char path1_r_[PADR_(const char *)];
+ char path1_len_l_[PADL_(size_t)]; size_t path1_len; char path1_len_r_[PADR_(size_t)];
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char path2_l_[PADL_(const char *)]; const char * path2; char path2_r_[PADR_(const char *)];
+ char path2_len_l_[PADL_(size_t)]; size_t path2_len; char path2_len_r_[PADR_(size_t)];
+};
+struct cloudabi_sys_file_unlink_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char path_len_l_[PADL_(size_t)]; size_t path_len; char path_len_r_[PADR_(size_t)];
+ char flags_l_[PADL_(cloudabi_ulflags_t)]; cloudabi_ulflags_t flags; char flags_r_[PADR_(cloudabi_ulflags_t)];
+};
+struct cloudabi_sys_lock_unlock_args {
+ char lock_l_[PADL_(cloudabi_lock_t *)]; cloudabi_lock_t * lock; char lock_r_[PADR_(cloudabi_lock_t *)];
+ char scope_l_[PADL_(cloudabi_scope_t)]; cloudabi_scope_t scope; char scope_r_[PADR_(cloudabi_scope_t)];
+};
+struct cloudabi_sys_mem_advise_args {
+ char mapping_l_[PADL_(void *)]; void * mapping; char mapping_r_[PADR_(void *)];
+ char mapping_len_l_[PADL_(size_t)]; size_t mapping_len; char mapping_len_r_[PADR_(size_t)];
+ char advice_l_[PADL_(cloudabi_advice_t)]; cloudabi_advice_t advice; char advice_r_[PADR_(cloudabi_advice_t)];
+};
+struct cloudabi_sys_mem_map_args {
+ char addr_l_[PADL_(void *)]; void * addr; char addr_r_[PADR_(void *)];
+ char len_l_[PADL_(size_t)]; size_t len; char len_r_[PADR_(size_t)];
+ char prot_l_[PADL_(cloudabi_mprot_t)]; cloudabi_mprot_t prot; char prot_r_[PADR_(cloudabi_mprot_t)];
+ char flags_l_[PADL_(cloudabi_mflags_t)]; cloudabi_mflags_t flags; char flags_r_[PADR_(cloudabi_mflags_t)];
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char off_l_[PADL_(cloudabi_filesize_t)]; cloudabi_filesize_t off; char off_r_[PADR_(cloudabi_filesize_t)];
+};
+struct cloudabi_sys_mem_protect_args {
+ char mapping_l_[PADL_(void *)]; void * mapping; char mapping_r_[PADR_(void *)];
+ char mapping_len_l_[PADL_(size_t)]; size_t mapping_len; char mapping_len_r_[PADR_(size_t)];
+ char prot_l_[PADL_(cloudabi_mprot_t)]; cloudabi_mprot_t prot; char prot_r_[PADR_(cloudabi_mprot_t)];
+};
+struct cloudabi_sys_mem_sync_args {
+ char mapping_l_[PADL_(void *)]; void * mapping; char mapping_r_[PADR_(void *)];
+ char mapping_len_l_[PADL_(size_t)]; size_t mapping_len; char mapping_len_r_[PADR_(size_t)];
+ char flags_l_[PADL_(cloudabi_msflags_t)]; cloudabi_msflags_t flags; char flags_r_[PADR_(cloudabi_msflags_t)];
+};
+struct cloudabi_sys_mem_unmap_args {
+ char mapping_l_[PADL_(void *)]; void * mapping; char mapping_r_[PADR_(void *)];
+ char mapping_len_l_[PADL_(size_t)]; size_t mapping_len; char mapping_len_r_[PADR_(size_t)];
+};
+struct cloudabi32_sys_poll_args {
+ char in_l_[PADL_(const cloudabi32_subscription_t *)]; const cloudabi32_subscription_t * in; char in_r_[PADR_(const cloudabi32_subscription_t *)];
+ char out_l_[PADL_(cloudabi_event_t *)]; cloudabi_event_t * out; char out_r_[PADR_(cloudabi_event_t *)];
+ char nsubscriptions_l_[PADL_(size_t)]; size_t nsubscriptions; char nsubscriptions_r_[PADR_(size_t)];
+};
+struct cloudabi_sys_proc_exec_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char data_l_[PADL_(const void *)]; const void * data; char data_r_[PADR_(const void *)];
+ char data_len_l_[PADL_(size_t)]; size_t data_len; char data_len_r_[PADR_(size_t)];
+ char fds_l_[PADL_(const cloudabi_fd_t *)]; const cloudabi_fd_t * fds; char fds_r_[PADR_(const cloudabi_fd_t *)];
+ char fds_len_l_[PADL_(size_t)]; size_t fds_len; char fds_len_r_[PADR_(size_t)];
+};
+struct cloudabi_sys_proc_exit_args {
+ char rval_l_[PADL_(cloudabi_exitcode_t)]; cloudabi_exitcode_t rval; char rval_r_[PADR_(cloudabi_exitcode_t)];
+};
+struct cloudabi_sys_proc_fork_args {
+ register_t dummy;
+};
+struct cloudabi_sys_proc_raise_args {
+ char sig_l_[PADL_(cloudabi_signal_t)]; cloudabi_signal_t sig; char sig_r_[PADR_(cloudabi_signal_t)];
+};
+struct cloudabi_sys_random_get_args {
+ char buf_l_[PADL_(void *)]; void * buf; char buf_r_[PADR_(void *)];
+ char buf_len_l_[PADL_(size_t)]; size_t buf_len; char buf_len_r_[PADR_(size_t)];
+};
+struct cloudabi32_sys_sock_recv_args {
+ char sock_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t sock; char sock_r_[PADR_(cloudabi_fd_t)];
+ char in_l_[PADL_(const cloudabi32_recv_in_t *)]; const cloudabi32_recv_in_t * in; char in_r_[PADR_(const cloudabi32_recv_in_t *)];
+ char out_l_[PADL_(cloudabi32_recv_out_t *)]; cloudabi32_recv_out_t * out; char out_r_[PADR_(cloudabi32_recv_out_t *)];
+};
+struct cloudabi32_sys_sock_send_args {
+ char sock_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t sock; char sock_r_[PADR_(cloudabi_fd_t)];
+ char in_l_[PADL_(const cloudabi32_send_in_t *)]; const cloudabi32_send_in_t * in; char in_r_[PADR_(const cloudabi32_send_in_t *)];
+ char out_l_[PADL_(cloudabi32_send_out_t *)]; cloudabi32_send_out_t * out; char out_r_[PADR_(cloudabi32_send_out_t *)];
+};
+struct cloudabi_sys_sock_shutdown_args {
+ char sock_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t sock; char sock_r_[PADR_(cloudabi_fd_t)];
+ char how_l_[PADL_(cloudabi_sdflags_t)]; cloudabi_sdflags_t how; char how_r_[PADR_(cloudabi_sdflags_t)];
+};
+struct cloudabi32_sys_thread_create_args {
+ char attr_l_[PADL_(cloudabi32_threadattr_t *)]; cloudabi32_threadattr_t * attr; char attr_r_[PADR_(cloudabi32_threadattr_t *)];
+};
+struct cloudabi_sys_thread_exit_args {
+ char lock_l_[PADL_(cloudabi_lock_t *)]; cloudabi_lock_t * lock; char lock_r_[PADR_(cloudabi_lock_t *)];
+ char scope_l_[PADL_(cloudabi_scope_t)]; cloudabi_scope_t scope; char scope_r_[PADR_(cloudabi_scope_t)];
+};
+struct cloudabi_sys_thread_yield_args {
+ register_t dummy;
+};
+int cloudabi_sys_clock_res_get(struct thread *, struct cloudabi_sys_clock_res_get_args *);
+int cloudabi_sys_clock_time_get(struct thread *, struct cloudabi_sys_clock_time_get_args *);
+int cloudabi_sys_condvar_signal(struct thread *, struct cloudabi_sys_condvar_signal_args *);
+int cloudabi_sys_fd_close(struct thread *, struct cloudabi_sys_fd_close_args *);
+int cloudabi_sys_fd_create1(struct thread *, struct cloudabi_sys_fd_create1_args *);
+int cloudabi_sys_fd_create2(struct thread *, struct cloudabi_sys_fd_create2_args *);
+int cloudabi_sys_fd_datasync(struct thread *, struct cloudabi_sys_fd_datasync_args *);
+int cloudabi_sys_fd_dup(struct thread *, struct cloudabi_sys_fd_dup_args *);
+int cloudabi32_sys_fd_pread(struct thread *, struct cloudabi32_sys_fd_pread_args *);
+int cloudabi32_sys_fd_pwrite(struct thread *, struct cloudabi32_sys_fd_pwrite_args *);
+int cloudabi32_sys_fd_read(struct thread *, struct cloudabi32_sys_fd_read_args *);
+int cloudabi_sys_fd_replace(struct thread *, struct cloudabi_sys_fd_replace_args *);
+int cloudabi_sys_fd_seek(struct thread *, struct cloudabi_sys_fd_seek_args *);
+int cloudabi_sys_fd_stat_get(struct thread *, struct cloudabi_sys_fd_stat_get_args *);
+int cloudabi_sys_fd_stat_put(struct thread *, struct cloudabi_sys_fd_stat_put_args *);
+int cloudabi_sys_fd_sync(struct thread *, struct cloudabi_sys_fd_sync_args *);
+int cloudabi32_sys_fd_write(struct thread *, struct cloudabi32_sys_fd_write_args *);
+int cloudabi_sys_file_advise(struct thread *, struct cloudabi_sys_file_advise_args *);
+int cloudabi_sys_file_allocate(struct thread *, struct cloudabi_sys_file_allocate_args *);
+int cloudabi_sys_file_create(struct thread *, struct cloudabi_sys_file_create_args *);
+int cloudabi_sys_file_link(struct thread *, struct cloudabi_sys_file_link_args *);
+int cloudabi_sys_file_open(struct thread *, struct cloudabi_sys_file_open_args *);
+int cloudabi_sys_file_readdir(struct thread *, struct cloudabi_sys_file_readdir_args *);
+int cloudabi_sys_file_readlink(struct thread *, struct cloudabi_sys_file_readlink_args *);
+int cloudabi_sys_file_rename(struct thread *, struct cloudabi_sys_file_rename_args *);
+int cloudabi_sys_file_stat_fget(struct thread *, struct cloudabi_sys_file_stat_fget_args *);
+int cloudabi_sys_file_stat_fput(struct thread *, struct cloudabi_sys_file_stat_fput_args *);
+int cloudabi_sys_file_stat_get(struct thread *, struct cloudabi_sys_file_stat_get_args *);
+int cloudabi_sys_file_stat_put(struct thread *, struct cloudabi_sys_file_stat_put_args *);
+int cloudabi_sys_file_symlink(struct thread *, struct cloudabi_sys_file_symlink_args *);
+int cloudabi_sys_file_unlink(struct thread *, struct cloudabi_sys_file_unlink_args *);
+int cloudabi_sys_lock_unlock(struct thread *, struct cloudabi_sys_lock_unlock_args *);
+int cloudabi_sys_mem_advise(struct thread *, struct cloudabi_sys_mem_advise_args *);
+int cloudabi_sys_mem_map(struct thread *, struct cloudabi_sys_mem_map_args *);
+int cloudabi_sys_mem_protect(struct thread *, struct cloudabi_sys_mem_protect_args *);
+int cloudabi_sys_mem_sync(struct thread *, struct cloudabi_sys_mem_sync_args *);
+int cloudabi_sys_mem_unmap(struct thread *, struct cloudabi_sys_mem_unmap_args *);
+int cloudabi32_sys_poll(struct thread *, struct cloudabi32_sys_poll_args *);
+int cloudabi_sys_proc_exec(struct thread *, struct cloudabi_sys_proc_exec_args *);
+int cloudabi_sys_proc_exit(struct thread *, struct cloudabi_sys_proc_exit_args *);
+int cloudabi_sys_proc_fork(struct thread *, struct cloudabi_sys_proc_fork_args *);
+int cloudabi_sys_proc_raise(struct thread *, struct cloudabi_sys_proc_raise_args *);
+int cloudabi_sys_random_get(struct thread *, struct cloudabi_sys_random_get_args *);
+int cloudabi32_sys_sock_recv(struct thread *, struct cloudabi32_sys_sock_recv_args *);
+int cloudabi32_sys_sock_send(struct thread *, struct cloudabi32_sys_sock_send_args *);
+int cloudabi_sys_sock_shutdown(struct thread *, struct cloudabi_sys_sock_shutdown_args *);
+int cloudabi32_sys_thread_create(struct thread *, struct cloudabi32_sys_thread_create_args *);
+int cloudabi_sys_thread_exit(struct thread *, struct cloudabi_sys_thread_exit_args *);
+int cloudabi_sys_thread_yield(struct thread *, struct cloudabi_sys_thread_yield_args *);
+
+#ifdef COMPAT_43
+
+
+#endif /* COMPAT_43 */
+
+
+#ifdef COMPAT_FREEBSD4
+
+
+#endif /* COMPAT_FREEBSD4 */
+
+
+#ifdef COMPAT_FREEBSD6
+
+
+#endif /* COMPAT_FREEBSD6 */
+
+
+#ifdef COMPAT_FREEBSD7
+
+
+#endif /* COMPAT_FREEBSD7 */
+
+
+#ifdef COMPAT_FREEBSD10
+
+
+#endif /* COMPAT_FREEBSD10 */
+
+
+#ifdef COMPAT_FREEBSD11
+
+
+#endif /* COMPAT_FREEBSD11 */
+
+
+#ifdef COMPAT_FREEBSD12
+
+
+#endif /* COMPAT_FREEBSD12 */
+
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_clock_res_get AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_clock_time_get AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_condvar_signal AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_fd_close AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_fd_create1 AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_fd_create2 AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_fd_datasync AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_fd_dup AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi32_sys_fd_pread AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi32_sys_fd_pwrite AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi32_sys_fd_read AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_fd_replace AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_fd_seek AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_fd_stat_get AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_fd_stat_put AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_fd_sync AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi32_sys_fd_write AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_file_advise AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_file_allocate AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_file_create AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_file_link AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_file_open AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_file_readdir AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_file_readlink AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_file_rename AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_file_stat_fget AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_file_stat_fput AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_file_stat_get AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_file_stat_put AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_file_symlink AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_file_unlink AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_lock_unlock AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_mem_advise AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_mem_map AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_mem_protect AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_mem_sync AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_mem_unmap AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi32_sys_poll AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_proc_exec AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_proc_exit AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_proc_fork AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_proc_raise AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_random_get AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi32_sys_sock_recv AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi32_sys_sock_send AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_sock_shutdown AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi32_sys_thread_create AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_thread_exit AUE_NULL
+#define CLOUDABI32_SYS_AUE_cloudabi_sys_thread_yield AUE_NULL
+
+#undef PAD_
+#undef PADL_
+#undef PADR_
+
+#endif /* !_CLOUDABI32_SYSPROTO_H_ */
diff --git a/sys/compat/cloudabi32/cloudabi32_sock.c b/sys/compat/cloudabi32/cloudabi32_sock.c
new file mode 100644
index 000000000000..97cb4478cf57
--- /dev/null
+++ b/sys/compat/cloudabi32/cloudabi32_sock.c
@@ -0,0 +1,128 @@
+/*-
+ * Copyright (c) 2015-2017 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
+
+#include <contrib/cloudabi/cloudabi32_types.h>
+
+#include <compat/cloudabi/cloudabi_util.h>
+
+#include <compat/cloudabi32/cloudabi32_proto.h>
+#include <compat/cloudabi32/cloudabi32_util.h>
+
+static MALLOC_DEFINE(M_SOCKET, "socket", "CloudABI socket");
+
+int
+cloudabi32_sys_sock_recv(struct thread *td,
+ struct cloudabi32_sys_sock_recv_args *uap)
+{
+ cloudabi32_recv_in_t ri;
+ cloudabi32_recv_out_t ro = {};
+ cloudabi32_iovec_t iovobj;
+ struct iovec *iov;
+ const cloudabi32_iovec_t *user_iov;
+ size_t i, rdatalen, rfdslen;
+ int error;
+
+ error = copyin(uap->in, &ri, sizeof(ri));
+ if (error != 0)
+ return (error);
+
+ /* Convert iovecs to native format. */
+ if (ri.ri_data_len > UIO_MAXIOV)
+ return (EINVAL);
+ iov = mallocarray(ri.ri_data_len, sizeof(struct iovec),
+ M_SOCKET, M_WAITOK);
+ user_iov = TO_PTR(ri.ri_data);
+ for (i = 0; i < ri.ri_data_len; i++) {
+ error = copyin(&user_iov[i], &iovobj, sizeof(iovobj));
+ if (error != 0) {
+ free(iov, M_SOCKET);
+ return (error);
+ }
+ iov[i].iov_base = TO_PTR(iovobj.buf);
+ iov[i].iov_len = iovobj.buf_len;
+ }
+
+ error = cloudabi_sock_recv(td, uap->sock, iov, ri.ri_data_len,
+ TO_PTR(ri.ri_fds), ri.ri_fds_len, ri.ri_flags, &rdatalen,
+ &rfdslen, &ro.ro_flags);
+ free(iov, M_SOCKET);
+ if (error != 0)
+ return (error);
+
+ ro.ro_datalen = rdatalen;
+ ro.ro_fdslen = rfdslen;
+ return (copyout(&ro, uap->out, sizeof(ro)));
+}
+
+int
+cloudabi32_sys_sock_send(struct thread *td,
+ struct cloudabi32_sys_sock_send_args *uap)
+{
+ cloudabi32_send_in_t si;
+ cloudabi32_send_out_t so = {};
+ cloudabi32_ciovec_t iovobj;
+ struct iovec *iov;
+ const cloudabi32_ciovec_t *user_iov;
+ size_t datalen, i;
+ int error;
+
+ error = copyin(uap->in, &si, sizeof(si));
+ if (error != 0)
+ return (error);
+
+ /* Convert iovecs to native format. */
+ if (si.si_data_len > UIO_MAXIOV)
+ return (EINVAL);
+ iov = mallocarray(si.si_data_len, sizeof(struct iovec),
+ M_SOCKET, M_WAITOK);
+ user_iov = TO_PTR(si.si_data);
+ for (i = 0; i < si.si_data_len; i++) {
+ error = copyin(&user_iov[i], &iovobj, sizeof(iovobj));
+ if (error != 0) {
+ free(iov, M_SOCKET);
+ return (error);
+ }
+ iov[i].iov_base = TO_PTR(iovobj.buf);
+ iov[i].iov_len = iovobj.buf_len;
+ }
+
+ error = cloudabi_sock_send(td, uap->sock, iov, si.si_data_len,
+ TO_PTR(si.si_fds), si.si_fds_len, &datalen);
+ free(iov, M_SOCKET);
+ if (error != 0)
+ return (error);
+
+ so.so_datalen = datalen;
+ return (copyout(&so, uap->out, sizeof(so)));
+}
diff --git a/sys/compat/cloudabi32/cloudabi32_syscall.h b/sys/compat/cloudabi32/cloudabi32_syscall.h
new file mode 100644
index 000000000000..b7496fa011a9
--- /dev/null
+++ b/sys/compat/cloudabi32/cloudabi32_syscall.h
@@ -0,0 +1,57 @@
+/*
+ * System call numbers.
+ *
+ * DO NOT EDIT-- this file is automatically @generated.
+ * $FreeBSD$
+ */
+
+#define CLOUDABI32_SYS_cloudabi_sys_clock_res_get 0
+#define CLOUDABI32_SYS_cloudabi_sys_clock_time_get 1
+#define CLOUDABI32_SYS_cloudabi_sys_condvar_signal 2
+#define CLOUDABI32_SYS_cloudabi_sys_fd_close 3
+#define CLOUDABI32_SYS_cloudabi_sys_fd_create1 4
+#define CLOUDABI32_SYS_cloudabi_sys_fd_create2 5
+#define CLOUDABI32_SYS_cloudabi_sys_fd_datasync 6
+#define CLOUDABI32_SYS_cloudabi_sys_fd_dup 7
+#define CLOUDABI32_SYS_cloudabi32_sys_fd_pread 8
+#define CLOUDABI32_SYS_cloudabi32_sys_fd_pwrite 9
+#define CLOUDABI32_SYS_cloudabi32_sys_fd_read 10
+#define CLOUDABI32_SYS_cloudabi_sys_fd_replace 11
+#define CLOUDABI32_SYS_cloudabi_sys_fd_seek 12
+#define CLOUDABI32_SYS_cloudabi_sys_fd_stat_get 13
+#define CLOUDABI32_SYS_cloudabi_sys_fd_stat_put 14
+#define CLOUDABI32_SYS_cloudabi_sys_fd_sync 15
+#define CLOUDABI32_SYS_cloudabi32_sys_fd_write 16
+#define CLOUDABI32_SYS_cloudabi_sys_file_advise 17
+#define CLOUDABI32_SYS_cloudabi_sys_file_allocate 18
+#define CLOUDABI32_SYS_cloudabi_sys_file_create 19
+#define CLOUDABI32_SYS_cloudabi_sys_file_link 20
+#define CLOUDABI32_SYS_cloudabi_sys_file_open 21
+#define CLOUDABI32_SYS_cloudabi_sys_file_readdir 22
+#define CLOUDABI32_SYS_cloudabi_sys_file_readlink 23
+#define CLOUDABI32_SYS_cloudabi_sys_file_rename 24
+#define CLOUDABI32_SYS_cloudabi_sys_file_stat_fget 25
+#define CLOUDABI32_SYS_cloudabi_sys_file_stat_fput 26
+#define CLOUDABI32_SYS_cloudabi_sys_file_stat_get 27
+#define CLOUDABI32_SYS_cloudabi_sys_file_stat_put 28
+#define CLOUDABI32_SYS_cloudabi_sys_file_symlink 29
+#define CLOUDABI32_SYS_cloudabi_sys_file_unlink 30
+#define CLOUDABI32_SYS_cloudabi_sys_lock_unlock 31
+#define CLOUDABI32_SYS_cloudabi_sys_mem_advise 32
+#define CLOUDABI32_SYS_cloudabi_sys_mem_map 33
+#define CLOUDABI32_SYS_cloudabi_sys_mem_protect 34
+#define CLOUDABI32_SYS_cloudabi_sys_mem_sync 35
+#define CLOUDABI32_SYS_cloudabi_sys_mem_unmap 36
+#define CLOUDABI32_SYS_cloudabi32_sys_poll 37
+#define CLOUDABI32_SYS_cloudabi_sys_proc_exec 38
+#define CLOUDABI32_SYS_cloudabi_sys_proc_exit 39
+#define CLOUDABI32_SYS_cloudabi_sys_proc_fork 40
+#define CLOUDABI32_SYS_cloudabi_sys_proc_raise 41
+#define CLOUDABI32_SYS_cloudabi_sys_random_get 42
+#define CLOUDABI32_SYS_cloudabi32_sys_sock_recv 43
+#define CLOUDABI32_SYS_cloudabi32_sys_sock_send 44
+#define CLOUDABI32_SYS_cloudabi_sys_sock_shutdown 45
+#define CLOUDABI32_SYS_cloudabi32_sys_thread_create 46
+#define CLOUDABI32_SYS_cloudabi_sys_thread_exit 47
+#define CLOUDABI32_SYS_cloudabi_sys_thread_yield 48
+#define CLOUDABI32_SYS_MAXSYSCALL 49
diff --git a/sys/compat/cloudabi32/cloudabi32_syscalls.c b/sys/compat/cloudabi32/cloudabi32_syscalls.c
new file mode 100644
index 000000000000..3ee4a286b001
--- /dev/null
+++ b/sys/compat/cloudabi32/cloudabi32_syscalls.c
@@ -0,0 +1,58 @@
+/*
+ * System call names.
+ *
+ * DO NOT EDIT-- this file is automatically @generated.
+ * $FreeBSD$
+ */
+
+const char *cloudabi32_syscallnames[] = {
+ "cloudabi_sys_clock_res_get", /* 0 = cloudabi_sys_clock_res_get */
+ "cloudabi_sys_clock_time_get", /* 1 = cloudabi_sys_clock_time_get */
+ "cloudabi_sys_condvar_signal", /* 2 = cloudabi_sys_condvar_signal */
+ "cloudabi_sys_fd_close", /* 3 = cloudabi_sys_fd_close */
+ "cloudabi_sys_fd_create1", /* 4 = cloudabi_sys_fd_create1 */
+ "cloudabi_sys_fd_create2", /* 5 = cloudabi_sys_fd_create2 */
+ "cloudabi_sys_fd_datasync", /* 6 = cloudabi_sys_fd_datasync */
+ "cloudabi_sys_fd_dup", /* 7 = cloudabi_sys_fd_dup */
+ "cloudabi32_sys_fd_pread", /* 8 = cloudabi32_sys_fd_pread */
+ "cloudabi32_sys_fd_pwrite", /* 9 = cloudabi32_sys_fd_pwrite */
+ "cloudabi32_sys_fd_read", /* 10 = cloudabi32_sys_fd_read */
+ "cloudabi_sys_fd_replace", /* 11 = cloudabi_sys_fd_replace */
+ "cloudabi_sys_fd_seek", /* 12 = cloudabi_sys_fd_seek */
+ "cloudabi_sys_fd_stat_get", /* 13 = cloudabi_sys_fd_stat_get */
+ "cloudabi_sys_fd_stat_put", /* 14 = cloudabi_sys_fd_stat_put */
+ "cloudabi_sys_fd_sync", /* 15 = cloudabi_sys_fd_sync */
+ "cloudabi32_sys_fd_write", /* 16 = cloudabi32_sys_fd_write */
+ "cloudabi_sys_file_advise", /* 17 = cloudabi_sys_file_advise */
+ "cloudabi_sys_file_allocate", /* 18 = cloudabi_sys_file_allocate */
+ "cloudabi_sys_file_create", /* 19 = cloudabi_sys_file_create */
+ "cloudabi_sys_file_link", /* 20 = cloudabi_sys_file_link */
+ "cloudabi_sys_file_open", /* 21 = cloudabi_sys_file_open */
+ "cloudabi_sys_file_readdir", /* 22 = cloudabi_sys_file_readdir */
+ "cloudabi_sys_file_readlink", /* 23 = cloudabi_sys_file_readlink */
+ "cloudabi_sys_file_rename", /* 24 = cloudabi_sys_file_rename */
+ "cloudabi_sys_file_stat_fget", /* 25 = cloudabi_sys_file_stat_fget */
+ "cloudabi_sys_file_stat_fput", /* 26 = cloudabi_sys_file_stat_fput */
+ "cloudabi_sys_file_stat_get", /* 27 = cloudabi_sys_file_stat_get */
+ "cloudabi_sys_file_stat_put", /* 28 = cloudabi_sys_file_stat_put */
+ "cloudabi_sys_file_symlink", /* 29 = cloudabi_sys_file_symlink */
+ "cloudabi_sys_file_unlink", /* 30 = cloudabi_sys_file_unlink */
+ "cloudabi_sys_lock_unlock", /* 31 = cloudabi_sys_lock_unlock */
+ "cloudabi_sys_mem_advise", /* 32 = cloudabi_sys_mem_advise */
+ "cloudabi_sys_mem_map", /* 33 = cloudabi_sys_mem_map */
+ "cloudabi_sys_mem_protect", /* 34 = cloudabi_sys_mem_protect */
+ "cloudabi_sys_mem_sync", /* 35 = cloudabi_sys_mem_sync */
+ "cloudabi_sys_mem_unmap", /* 36 = cloudabi_sys_mem_unmap */
+ "cloudabi32_sys_poll", /* 37 = cloudabi32_sys_poll */
+ "cloudabi_sys_proc_exec", /* 38 = cloudabi_sys_proc_exec */
+ "cloudabi_sys_proc_exit", /* 39 = cloudabi_sys_proc_exit */
+ "cloudabi_sys_proc_fork", /* 40 = cloudabi_sys_proc_fork */
+ "cloudabi_sys_proc_raise", /* 41 = cloudabi_sys_proc_raise */
+ "cloudabi_sys_random_get", /* 42 = cloudabi_sys_random_get */
+ "cloudabi32_sys_sock_recv", /* 43 = cloudabi32_sys_sock_recv */
+ "cloudabi32_sys_sock_send", /* 44 = cloudabi32_sys_sock_send */
+ "cloudabi_sys_sock_shutdown", /* 45 = cloudabi_sys_sock_shutdown */
+ "cloudabi32_sys_thread_create", /* 46 = cloudabi32_sys_thread_create */
+ "cloudabi_sys_thread_exit", /* 47 = cloudabi_sys_thread_exit */
+ "cloudabi_sys_thread_yield", /* 48 = cloudabi_sys_thread_yield */
+};
diff --git a/sys/compat/cloudabi32/cloudabi32_sysent.c b/sys/compat/cloudabi32/cloudabi32_sysent.c
new file mode 100644
index 000000000000..7f07ed8e9236
--- /dev/null
+++ b/sys/compat/cloudabi32/cloudabi32_sysent.c
@@ -0,0 +1,66 @@
+/*
+ * System call switch table.
+ *
+ * DO NOT EDIT-- this file is automatically @generated.
+ * $FreeBSD$
+ */
+
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <contrib/cloudabi/cloudabi32_types.h>
+#include <compat/cloudabi32/cloudabi32_proto.h>
+
+#define AS(name) (sizeof(struct name) / sizeof(register_t))
+
+/* The casts are bogus but will do for now. */
+struct sysent cloudabi32_sysent[] = {
+ { .sy_narg = AS(cloudabi_sys_clock_res_get_args), .sy_call = (sy_call_t *)cloudabi_sys_clock_res_get, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 0 = cloudabi_sys_clock_res_get */
+ { .sy_narg = AS(cloudabi_sys_clock_time_get_args), .sy_call = (sy_call_t *)cloudabi_sys_clock_time_get, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 1 = cloudabi_sys_clock_time_get */
+ { .sy_narg = AS(cloudabi_sys_condvar_signal_args), .sy_call = (sy_call_t *)cloudabi_sys_condvar_signal, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 2 = cloudabi_sys_condvar_signal */
+ { .sy_narg = AS(cloudabi_sys_fd_close_args), .sy_call = (sy_call_t *)cloudabi_sys_fd_close, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 3 = cloudabi_sys_fd_close */
+ { .sy_narg = AS(cloudabi_sys_fd_create1_args), .sy_call = (sy_call_t *)cloudabi_sys_fd_create1, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 4 = cloudabi_sys_fd_create1 */
+ { .sy_narg = AS(cloudabi_sys_fd_create2_args), .sy_call = (sy_call_t *)cloudabi_sys_fd_create2, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 5 = cloudabi_sys_fd_create2 */
+ { .sy_narg = AS(cloudabi_sys_fd_datasync_args), .sy_call = (sy_call_t *)cloudabi_sys_fd_datasync, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 6 = cloudabi_sys_fd_datasync */
+ { .sy_narg = AS(cloudabi_sys_fd_dup_args), .sy_call = (sy_call_t *)cloudabi_sys_fd_dup, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 7 = cloudabi_sys_fd_dup */
+ { .sy_narg = AS(cloudabi32_sys_fd_pread_args), .sy_call = (sy_call_t *)cloudabi32_sys_fd_pread, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 8 = cloudabi32_sys_fd_pread */
+ { .sy_narg = AS(cloudabi32_sys_fd_pwrite_args), .sy_call = (sy_call_t *)cloudabi32_sys_fd_pwrite, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 9 = cloudabi32_sys_fd_pwrite */
+ { .sy_narg = AS(cloudabi32_sys_fd_read_args), .sy_call = (sy_call_t *)cloudabi32_sys_fd_read, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 10 = cloudabi32_sys_fd_read */
+ { .sy_narg = AS(cloudabi_sys_fd_replace_args), .sy_call = (sy_call_t *)cloudabi_sys_fd_replace, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 11 = cloudabi_sys_fd_replace */
+ { .sy_narg = AS(cloudabi_sys_fd_seek_args), .sy_call = (sy_call_t *)cloudabi_sys_fd_seek, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 12 = cloudabi_sys_fd_seek */
+ { .sy_narg = AS(cloudabi_sys_fd_stat_get_args), .sy_call = (sy_call_t *)cloudabi_sys_fd_stat_get, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 13 = cloudabi_sys_fd_stat_get */
+ { .sy_narg = AS(cloudabi_sys_fd_stat_put_args), .sy_call = (sy_call_t *)cloudabi_sys_fd_stat_put, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 14 = cloudabi_sys_fd_stat_put */
+ { .sy_narg = AS(cloudabi_sys_fd_sync_args), .sy_call = (sy_call_t *)cloudabi_sys_fd_sync, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 15 = cloudabi_sys_fd_sync */
+ { .sy_narg = AS(cloudabi32_sys_fd_write_args), .sy_call = (sy_call_t *)cloudabi32_sys_fd_write, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 16 = cloudabi32_sys_fd_write */
+ { .sy_narg = AS(cloudabi_sys_file_advise_args), .sy_call = (sy_call_t *)cloudabi_sys_file_advise, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 17 = cloudabi_sys_file_advise */
+ { .sy_narg = AS(cloudabi_sys_file_allocate_args), .sy_call = (sy_call_t *)cloudabi_sys_file_allocate, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 18 = cloudabi_sys_file_allocate */
+ { .sy_narg = AS(cloudabi_sys_file_create_args), .sy_call = (sy_call_t *)cloudabi_sys_file_create, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 19 = cloudabi_sys_file_create */
+ { .sy_narg = AS(cloudabi_sys_file_link_args), .sy_call = (sy_call_t *)cloudabi_sys_file_link, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 20 = cloudabi_sys_file_link */
+ { .sy_narg = AS(cloudabi_sys_file_open_args), .sy_call = (sy_call_t *)cloudabi_sys_file_open, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 21 = cloudabi_sys_file_open */
+ { .sy_narg = AS(cloudabi_sys_file_readdir_args), .sy_call = (sy_call_t *)cloudabi_sys_file_readdir, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 22 = cloudabi_sys_file_readdir */
+ { .sy_narg = AS(cloudabi_sys_file_readlink_args), .sy_call = (sy_call_t *)cloudabi_sys_file_readlink, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 23 = cloudabi_sys_file_readlink */
+ { .sy_narg = AS(cloudabi_sys_file_rename_args), .sy_call = (sy_call_t *)cloudabi_sys_file_rename, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 24 = cloudabi_sys_file_rename */
+ { .sy_narg = AS(cloudabi_sys_file_stat_fget_args), .sy_call = (sy_call_t *)cloudabi_sys_file_stat_fget, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 25 = cloudabi_sys_file_stat_fget */
+ { .sy_narg = AS(cloudabi_sys_file_stat_fput_args), .sy_call = (sy_call_t *)cloudabi_sys_file_stat_fput, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 26 = cloudabi_sys_file_stat_fput */
+ { .sy_narg = AS(cloudabi_sys_file_stat_get_args), .sy_call = (sy_call_t *)cloudabi_sys_file_stat_get, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 27 = cloudabi_sys_file_stat_get */
+ { .sy_narg = AS(cloudabi_sys_file_stat_put_args), .sy_call = (sy_call_t *)cloudabi_sys_file_stat_put, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 28 = cloudabi_sys_file_stat_put */
+ { .sy_narg = AS(cloudabi_sys_file_symlink_args), .sy_call = (sy_call_t *)cloudabi_sys_file_symlink, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 29 = cloudabi_sys_file_symlink */
+ { .sy_narg = AS(cloudabi_sys_file_unlink_args), .sy_call = (sy_call_t *)cloudabi_sys_file_unlink, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 30 = cloudabi_sys_file_unlink */
+ { .sy_narg = AS(cloudabi_sys_lock_unlock_args), .sy_call = (sy_call_t *)cloudabi_sys_lock_unlock, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 31 = cloudabi_sys_lock_unlock */
+ { .sy_narg = AS(cloudabi_sys_mem_advise_args), .sy_call = (sy_call_t *)cloudabi_sys_mem_advise, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 32 = cloudabi_sys_mem_advise */
+ { .sy_narg = AS(cloudabi_sys_mem_map_args), .sy_call = (sy_call_t *)cloudabi_sys_mem_map, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 33 = cloudabi_sys_mem_map */
+ { .sy_narg = AS(cloudabi_sys_mem_protect_args), .sy_call = (sy_call_t *)cloudabi_sys_mem_protect, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 34 = cloudabi_sys_mem_protect */
+ { .sy_narg = AS(cloudabi_sys_mem_sync_args), .sy_call = (sy_call_t *)cloudabi_sys_mem_sync, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 35 = cloudabi_sys_mem_sync */
+ { .sy_narg = AS(cloudabi_sys_mem_unmap_args), .sy_call = (sy_call_t *)cloudabi_sys_mem_unmap, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 36 = cloudabi_sys_mem_unmap */
+ { .sy_narg = AS(cloudabi32_sys_poll_args), .sy_call = (sy_call_t *)cloudabi32_sys_poll, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 37 = cloudabi32_sys_poll */
+ { .sy_narg = AS(cloudabi_sys_proc_exec_args), .sy_call = (sy_call_t *)cloudabi_sys_proc_exec, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 38 = cloudabi_sys_proc_exec */
+ { .sy_narg = AS(cloudabi_sys_proc_exit_args), .sy_call = (sy_call_t *)cloudabi_sys_proc_exit, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 39 = cloudabi_sys_proc_exit */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)cloudabi_sys_proc_fork, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 40 = cloudabi_sys_proc_fork */
+ { .sy_narg = AS(cloudabi_sys_proc_raise_args), .sy_call = (sy_call_t *)cloudabi_sys_proc_raise, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 41 = cloudabi_sys_proc_raise */
+ { .sy_narg = AS(cloudabi_sys_random_get_args), .sy_call = (sy_call_t *)cloudabi_sys_random_get, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 42 = cloudabi_sys_random_get */
+ { .sy_narg = AS(cloudabi32_sys_sock_recv_args), .sy_call = (sy_call_t *)cloudabi32_sys_sock_recv, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 43 = cloudabi32_sys_sock_recv */
+ { .sy_narg = AS(cloudabi32_sys_sock_send_args), .sy_call = (sy_call_t *)cloudabi32_sys_sock_send, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 44 = cloudabi32_sys_sock_send */
+ { .sy_narg = AS(cloudabi_sys_sock_shutdown_args), .sy_call = (sy_call_t *)cloudabi_sys_sock_shutdown, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 45 = cloudabi_sys_sock_shutdown */
+ { .sy_narg = AS(cloudabi32_sys_thread_create_args), .sy_call = (sy_call_t *)cloudabi32_sys_thread_create, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 46 = cloudabi32_sys_thread_create */
+ { .sy_narg = AS(cloudabi_sys_thread_exit_args), .sy_call = (sy_call_t *)cloudabi_sys_thread_exit, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 47 = cloudabi_sys_thread_exit */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)cloudabi_sys_thread_yield, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 48 = cloudabi_sys_thread_yield */
+};
diff --git a/sys/compat/cloudabi32/cloudabi32_systrace_args.c b/sys/compat/cloudabi32/cloudabi32_systrace_args.c
new file mode 100644
index 000000000000..112def9ce390
--- /dev/null
+++ b/sys/compat/cloudabi32/cloudabi32_systrace_args.c
@@ -0,0 +1,1458 @@
+/*
+ * System call argument to DTrace register array converstion.
+ *
+ * DO NOT EDIT-- this file is automatically @generated.
+ * $FreeBSD$
+ * This file is part of the DTrace syscall provider.
+ */
+
+static void
+systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
+{
+ int64_t *iarg = (int64_t *) uarg;
+ switch (sysnum) {
+ /* cloudabi_sys_clock_res_get */
+ case 0: {
+ struct cloudabi_sys_clock_res_get_args *p = params;
+ iarg[0] = p->clock_id; /* cloudabi_clockid_t */
+ *n_args = 1;
+ break;
+ }
+ /* cloudabi_sys_clock_time_get */
+ case 1: {
+ struct cloudabi_sys_clock_time_get_args *p = params;
+ iarg[0] = p->clock_id; /* cloudabi_clockid_t */
+ iarg[1] = p->precision; /* cloudabi_timestamp_t */
+ *n_args = 2;
+ break;
+ }
+ /* cloudabi_sys_condvar_signal */
+ case 2: {
+ struct cloudabi_sys_condvar_signal_args *p = params;
+ uarg[0] = (intptr_t) p->condvar; /* cloudabi_condvar_t * */
+ iarg[1] = p->scope; /* cloudabi_scope_t */
+ iarg[2] = p->nwaiters; /* cloudabi_nthreads_t */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi_sys_fd_close */
+ case 3: {
+ struct cloudabi_sys_fd_close_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ *n_args = 1;
+ break;
+ }
+ /* cloudabi_sys_fd_create1 */
+ case 4: {
+ struct cloudabi_sys_fd_create1_args *p = params;
+ iarg[0] = p->type; /* cloudabi_filetype_t */
+ *n_args = 1;
+ break;
+ }
+ /* cloudabi_sys_fd_create2 */
+ case 5: {
+ struct cloudabi_sys_fd_create2_args *p = params;
+ iarg[0] = p->type; /* cloudabi_filetype_t */
+ *n_args = 1;
+ break;
+ }
+ /* cloudabi_sys_fd_datasync */
+ case 6: {
+ struct cloudabi_sys_fd_datasync_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ *n_args = 1;
+ break;
+ }
+ /* cloudabi_sys_fd_dup */
+ case 7: {
+ struct cloudabi_sys_fd_dup_args *p = params;
+ iarg[0] = p->from; /* cloudabi_fd_t */
+ *n_args = 1;
+ break;
+ }
+ /* cloudabi32_sys_fd_pread */
+ case 8: {
+ struct cloudabi32_sys_fd_pread_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->iovs; /* const cloudabi32_iovec_t * */
+ uarg[2] = p->iovs_len; /* size_t */
+ iarg[3] = p->offset; /* cloudabi_filesize_t */
+ *n_args = 4;
+ break;
+ }
+ /* cloudabi32_sys_fd_pwrite */
+ case 9: {
+ struct cloudabi32_sys_fd_pwrite_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->iovs; /* const cloudabi32_ciovec_t * */
+ uarg[2] = p->iovs_len; /* size_t */
+ iarg[3] = p->offset; /* cloudabi_filesize_t */
+ *n_args = 4;
+ break;
+ }
+ /* cloudabi32_sys_fd_read */
+ case 10: {
+ struct cloudabi32_sys_fd_read_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->iovs; /* const cloudabi32_iovec_t * */
+ uarg[2] = p->iovs_len; /* size_t */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi_sys_fd_replace */
+ case 11: {
+ struct cloudabi_sys_fd_replace_args *p = params;
+ iarg[0] = p->from; /* cloudabi_fd_t */
+ iarg[1] = p->to; /* cloudabi_fd_t */
+ *n_args = 2;
+ break;
+ }
+ /* cloudabi_sys_fd_seek */
+ case 12: {
+ struct cloudabi_sys_fd_seek_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ iarg[1] = p->offset; /* cloudabi_filedelta_t */
+ iarg[2] = p->whence; /* cloudabi_whence_t */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi_sys_fd_stat_get */
+ case 13: {
+ struct cloudabi_sys_fd_stat_get_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->buf; /* cloudabi_fdstat_t * */
+ *n_args = 2;
+ break;
+ }
+ /* cloudabi_sys_fd_stat_put */
+ case 14: {
+ struct cloudabi_sys_fd_stat_put_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->buf; /* const cloudabi_fdstat_t * */
+ iarg[2] = p->flags; /* cloudabi_fdsflags_t */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi_sys_fd_sync */
+ case 15: {
+ struct cloudabi_sys_fd_sync_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ *n_args = 1;
+ break;
+ }
+ /* cloudabi32_sys_fd_write */
+ case 16: {
+ struct cloudabi32_sys_fd_write_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->iovs; /* const cloudabi32_ciovec_t * */
+ uarg[2] = p->iovs_len; /* size_t */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi_sys_file_advise */
+ case 17: {
+ struct cloudabi_sys_file_advise_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ iarg[1] = p->offset; /* cloudabi_filesize_t */
+ iarg[2] = p->len; /* cloudabi_filesize_t */
+ iarg[3] = p->advice; /* cloudabi_advice_t */
+ *n_args = 4;
+ break;
+ }
+ /* cloudabi_sys_file_allocate */
+ case 18: {
+ struct cloudabi_sys_file_allocate_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ iarg[1] = p->offset; /* cloudabi_filesize_t */
+ iarg[2] = p->len; /* cloudabi_filesize_t */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi_sys_file_create */
+ case 19: {
+ struct cloudabi_sys_file_create_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ uarg[2] = p->path_len; /* size_t */
+ iarg[3] = p->type; /* cloudabi_filetype_t */
+ *n_args = 4;
+ break;
+ }
+ /* cloudabi_sys_file_link */
+ case 20: {
+ struct cloudabi_sys_file_link_args *p = params;
+ iarg[0] = p->fd1; /* cloudabi_lookup_t */
+ uarg[1] = (intptr_t) p->path1; /* const char * */
+ uarg[2] = p->path1_len; /* size_t */
+ iarg[3] = p->fd2; /* cloudabi_fd_t */
+ uarg[4] = (intptr_t) p->path2; /* const char * */
+ uarg[5] = p->path2_len; /* size_t */
+ *n_args = 6;
+ break;
+ }
+ /* cloudabi_sys_file_open */
+ case 21: {
+ struct cloudabi_sys_file_open_args *p = params;
+ iarg[0] = p->dirfd; /* cloudabi_lookup_t */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ uarg[2] = p->path_len; /* size_t */
+ iarg[3] = p->oflags; /* cloudabi_oflags_t */
+ uarg[4] = (intptr_t) p->fds; /* const cloudabi_fdstat_t * */
+ *n_args = 5;
+ break;
+ }
+ /* cloudabi_sys_file_readdir */
+ case 22: {
+ struct cloudabi_sys_file_readdir_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->buf; /* void * */
+ uarg[2] = p->buf_len; /* size_t */
+ iarg[3] = p->cookie; /* cloudabi_dircookie_t */
+ *n_args = 4;
+ break;
+ }
+ /* cloudabi_sys_file_readlink */
+ case 23: {
+ struct cloudabi_sys_file_readlink_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ uarg[2] = p->path_len; /* size_t */
+ uarg[3] = (intptr_t) p->buf; /* char * */
+ uarg[4] = p->buf_len; /* size_t */
+ *n_args = 5;
+ break;
+ }
+ /* cloudabi_sys_file_rename */
+ case 24: {
+ struct cloudabi_sys_file_rename_args *p = params;
+ iarg[0] = p->fd1; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->path1; /* const char * */
+ uarg[2] = p->path1_len; /* size_t */
+ iarg[3] = p->fd2; /* cloudabi_fd_t */
+ uarg[4] = (intptr_t) p->path2; /* const char * */
+ uarg[5] = p->path2_len; /* size_t */
+ *n_args = 6;
+ break;
+ }
+ /* cloudabi_sys_file_stat_fget */
+ case 25: {
+ struct cloudabi_sys_file_stat_fget_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->buf; /* cloudabi_filestat_t * */
+ *n_args = 2;
+ break;
+ }
+ /* cloudabi_sys_file_stat_fput */
+ case 26: {
+ struct cloudabi_sys_file_stat_fput_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->buf; /* const cloudabi_filestat_t * */
+ iarg[2] = p->flags; /* cloudabi_fsflags_t */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi_sys_file_stat_get */
+ case 27: {
+ struct cloudabi_sys_file_stat_get_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_lookup_t */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ uarg[2] = p->path_len; /* size_t */
+ uarg[3] = (intptr_t) p->buf; /* cloudabi_filestat_t * */
+ *n_args = 4;
+ break;
+ }
+ /* cloudabi_sys_file_stat_put */
+ case 28: {
+ struct cloudabi_sys_file_stat_put_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_lookup_t */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ uarg[2] = p->path_len; /* size_t */
+ uarg[3] = (intptr_t) p->buf; /* const cloudabi_filestat_t * */
+ iarg[4] = p->flags; /* cloudabi_fsflags_t */
+ *n_args = 5;
+ break;
+ }
+ /* cloudabi_sys_file_symlink */
+ case 29: {
+ struct cloudabi_sys_file_symlink_args *p = params;
+ uarg[0] = (intptr_t) p->path1; /* const char * */
+ uarg[1] = p->path1_len; /* size_t */
+ iarg[2] = p->fd; /* cloudabi_fd_t */
+ uarg[3] = (intptr_t) p->path2; /* const char * */
+ uarg[4] = p->path2_len; /* size_t */
+ *n_args = 5;
+ break;
+ }
+ /* cloudabi_sys_file_unlink */
+ case 30: {
+ struct cloudabi_sys_file_unlink_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ uarg[2] = p->path_len; /* size_t */
+ iarg[3] = p->flags; /* cloudabi_ulflags_t */
+ *n_args = 4;
+ break;
+ }
+ /* cloudabi_sys_lock_unlock */
+ case 31: {
+ struct cloudabi_sys_lock_unlock_args *p = params;
+ uarg[0] = (intptr_t) p->lock; /* cloudabi_lock_t * */
+ iarg[1] = p->scope; /* cloudabi_scope_t */
+ *n_args = 2;
+ break;
+ }
+ /* cloudabi_sys_mem_advise */
+ case 32: {
+ struct cloudabi_sys_mem_advise_args *p = params;
+ uarg[0] = (intptr_t) p->mapping; /* void * */
+ uarg[1] = p->mapping_len; /* size_t */
+ iarg[2] = p->advice; /* cloudabi_advice_t */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi_sys_mem_map */
+ case 33: {
+ struct cloudabi_sys_mem_map_args *p = params;
+ uarg[0] = (intptr_t) p->addr; /* void * */
+ uarg[1] = p->len; /* size_t */
+ iarg[2] = p->prot; /* cloudabi_mprot_t */
+ iarg[3] = p->flags; /* cloudabi_mflags_t */
+ iarg[4] = p->fd; /* cloudabi_fd_t */
+ iarg[5] = p->off; /* cloudabi_filesize_t */
+ *n_args = 6;
+ break;
+ }
+ /* cloudabi_sys_mem_protect */
+ case 34: {
+ struct cloudabi_sys_mem_protect_args *p = params;
+ uarg[0] = (intptr_t) p->mapping; /* void * */
+ uarg[1] = p->mapping_len; /* size_t */
+ iarg[2] = p->prot; /* cloudabi_mprot_t */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi_sys_mem_sync */
+ case 35: {
+ struct cloudabi_sys_mem_sync_args *p = params;
+ uarg[0] = (intptr_t) p->mapping; /* void * */
+ uarg[1] = p->mapping_len; /* size_t */
+ iarg[2] = p->flags; /* cloudabi_msflags_t */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi_sys_mem_unmap */
+ case 36: {
+ struct cloudabi_sys_mem_unmap_args *p = params;
+ uarg[0] = (intptr_t) p->mapping; /* void * */
+ uarg[1] = p->mapping_len; /* size_t */
+ *n_args = 2;
+ break;
+ }
+ /* cloudabi32_sys_poll */
+ case 37: {
+ struct cloudabi32_sys_poll_args *p = params;
+ uarg[0] = (intptr_t) p->in; /* const cloudabi32_subscription_t * */
+ uarg[1] = (intptr_t) p->out; /* cloudabi_event_t * */
+ uarg[2] = p->nsubscriptions; /* size_t */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi_sys_proc_exec */
+ case 38: {
+ struct cloudabi_sys_proc_exec_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->data; /* const void * */
+ uarg[2] = p->data_len; /* size_t */
+ uarg[3] = (intptr_t) p->fds; /* const cloudabi_fd_t * */
+ uarg[4] = p->fds_len; /* size_t */
+ *n_args = 5;
+ break;
+ }
+ /* cloudabi_sys_proc_exit */
+ case 39: {
+ struct cloudabi_sys_proc_exit_args *p = params;
+ iarg[0] = p->rval; /* cloudabi_exitcode_t */
+ *n_args = 1;
+ break;
+ }
+ /* cloudabi_sys_proc_fork */
+ case 40: {
+ *n_args = 0;
+ break;
+ }
+ /* cloudabi_sys_proc_raise */
+ case 41: {
+ struct cloudabi_sys_proc_raise_args *p = params;
+ iarg[0] = p->sig; /* cloudabi_signal_t */
+ *n_args = 1;
+ break;
+ }
+ /* cloudabi_sys_random_get */
+ case 42: {
+ struct cloudabi_sys_random_get_args *p = params;
+ uarg[0] = (intptr_t) p->buf; /* void * */
+ uarg[1] = p->buf_len; /* size_t */
+ *n_args = 2;
+ break;
+ }
+ /* cloudabi32_sys_sock_recv */
+ case 43: {
+ struct cloudabi32_sys_sock_recv_args *p = params;
+ iarg[0] = p->sock; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->in; /* const cloudabi32_recv_in_t * */
+ uarg[2] = (intptr_t) p->out; /* cloudabi32_recv_out_t * */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi32_sys_sock_send */
+ case 44: {
+ struct cloudabi32_sys_sock_send_args *p = params;
+ iarg[0] = p->sock; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->in; /* const cloudabi32_send_in_t * */
+ uarg[2] = (intptr_t) p->out; /* cloudabi32_send_out_t * */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi_sys_sock_shutdown */
+ case 45: {
+ struct cloudabi_sys_sock_shutdown_args *p = params;
+ iarg[0] = p->sock; /* cloudabi_fd_t */
+ iarg[1] = p->how; /* cloudabi_sdflags_t */
+ *n_args = 2;
+ break;
+ }
+ /* cloudabi32_sys_thread_create */
+ case 46: {
+ struct cloudabi32_sys_thread_create_args *p = params;
+ uarg[0] = (intptr_t) p->attr; /* cloudabi32_threadattr_t * */
+ *n_args = 1;
+ break;
+ }
+ /* cloudabi_sys_thread_exit */
+ case 47: {
+ struct cloudabi_sys_thread_exit_args *p = params;
+ uarg[0] = (intptr_t) p->lock; /* cloudabi_lock_t * */
+ iarg[1] = p->scope; /* cloudabi_scope_t */
+ *n_args = 2;
+ break;
+ }
+ /* cloudabi_sys_thread_yield */
+ case 48: {
+ *n_args = 0;
+ break;
+ }
+ default:
+ *n_args = 0;
+ break;
+ };
+}
+static void
+systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
+{
+ const char *p = NULL;
+ switch (sysnum) {
+ /* cloudabi_sys_clock_res_get */
+ case 0:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_clockid_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_clock_time_get */
+ case 1:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_clockid_t";
+ break;
+ case 1:
+ p = "cloudabi_timestamp_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_condvar_signal */
+ case 2:
+ switch(ndx) {
+ case 0:
+ p = "userland cloudabi_condvar_t *";
+ break;
+ case 1:
+ p = "cloudabi_scope_t";
+ break;
+ case 2:
+ p = "cloudabi_nthreads_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_fd_close */
+ case 3:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_fd_create1 */
+ case 4:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_filetype_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_fd_create2 */
+ case 5:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_filetype_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_fd_datasync */
+ case 6:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_fd_dup */
+ case 7:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi32_sys_fd_pread */
+ case 8:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const cloudabi32_iovec_t *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "cloudabi_filesize_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi32_sys_fd_pwrite */
+ case 9:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const cloudabi32_ciovec_t *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "cloudabi_filesize_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi32_sys_fd_read */
+ case 10:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const cloudabi32_iovec_t *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_fd_replace */
+ case 11:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "cloudabi_fd_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_fd_seek */
+ case 12:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "cloudabi_filedelta_t";
+ break;
+ case 2:
+ p = "cloudabi_whence_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_fd_stat_get */
+ case 13:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland cloudabi_fdstat_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_fd_stat_put */
+ case 14:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const cloudabi_fdstat_t *";
+ break;
+ case 2:
+ p = "cloudabi_fdsflags_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_fd_sync */
+ case 15:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi32_sys_fd_write */
+ case 16:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const cloudabi32_ciovec_t *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_advise */
+ case 17:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "cloudabi_filesize_t";
+ break;
+ case 2:
+ p = "cloudabi_filesize_t";
+ break;
+ case 3:
+ p = "cloudabi_advice_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_allocate */
+ case 18:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "cloudabi_filesize_t";
+ break;
+ case 2:
+ p = "cloudabi_filesize_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_create */
+ case 19:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "cloudabi_filetype_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_link */
+ case 20:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_lookup_t";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "cloudabi_fd_t";
+ break;
+ case 4:
+ p = "userland const char *";
+ break;
+ case 5:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_open */
+ case 21:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_lookup_t";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "cloudabi_oflags_t";
+ break;
+ case 4:
+ p = "userland const cloudabi_fdstat_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_readdir */
+ case 22:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland void *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "cloudabi_dircookie_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_readlink */
+ case 23:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "userland char *";
+ break;
+ case 4:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_rename */
+ case 24:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "cloudabi_fd_t";
+ break;
+ case 4:
+ p = "userland const char *";
+ break;
+ case 5:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_stat_fget */
+ case 25:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland cloudabi_filestat_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_stat_fput */
+ case 26:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const cloudabi_filestat_t *";
+ break;
+ case 2:
+ p = "cloudabi_fsflags_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_stat_get */
+ case 27:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_lookup_t";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "userland cloudabi_filestat_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_stat_put */
+ case 28:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_lookup_t";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "userland const cloudabi_filestat_t *";
+ break;
+ case 4:
+ p = "cloudabi_fsflags_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_symlink */
+ case 29:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "cloudabi_fd_t";
+ break;
+ case 3:
+ p = "userland const char *";
+ break;
+ case 4:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_unlink */
+ case 30:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "cloudabi_ulflags_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_lock_unlock */
+ case 31:
+ switch(ndx) {
+ case 0:
+ p = "userland cloudabi_lock_t *";
+ break;
+ case 1:
+ p = "cloudabi_scope_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_mem_advise */
+ case 32:
+ switch(ndx) {
+ case 0:
+ p = "userland void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "cloudabi_advice_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_mem_map */
+ case 33:
+ switch(ndx) {
+ case 0:
+ p = "userland void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "cloudabi_mprot_t";
+ break;
+ case 3:
+ p = "cloudabi_mflags_t";
+ break;
+ case 4:
+ p = "cloudabi_fd_t";
+ break;
+ case 5:
+ p = "cloudabi_filesize_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_mem_protect */
+ case 34:
+ switch(ndx) {
+ case 0:
+ p = "userland void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "cloudabi_mprot_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_mem_sync */
+ case 35:
+ switch(ndx) {
+ case 0:
+ p = "userland void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "cloudabi_msflags_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_mem_unmap */
+ case 36:
+ switch(ndx) {
+ case 0:
+ p = "userland void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi32_sys_poll */
+ case 37:
+ switch(ndx) {
+ case 0:
+ p = "userland const cloudabi32_subscription_t *";
+ break;
+ case 1:
+ p = "userland cloudabi_event_t *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_proc_exec */
+ case 38:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const void *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "userland const cloudabi_fd_t *";
+ break;
+ case 4:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_proc_exit */
+ case 39:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_exitcode_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_proc_fork */
+ case 40:
+ break;
+ /* cloudabi_sys_proc_raise */
+ case 41:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_signal_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_random_get */
+ case 42:
+ switch(ndx) {
+ case 0:
+ p = "userland void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi32_sys_sock_recv */
+ case 43:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const cloudabi32_recv_in_t *";
+ break;
+ case 2:
+ p = "userland cloudabi32_recv_out_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi32_sys_sock_send */
+ case 44:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const cloudabi32_send_in_t *";
+ break;
+ case 2:
+ p = "userland cloudabi32_send_out_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_sock_shutdown */
+ case 45:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "cloudabi_sdflags_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi32_sys_thread_create */
+ case 46:
+ switch(ndx) {
+ case 0:
+ p = "userland cloudabi32_threadattr_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_thread_exit */
+ case 47:
+ switch(ndx) {
+ case 0:
+ p = "userland cloudabi_lock_t *";
+ break;
+ case 1:
+ p = "cloudabi_scope_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_thread_yield */
+ case 48:
+ break;
+ default:
+ break;
+ };
+ if (p != NULL)
+ strlcpy(desc, p, descsz);
+}
+static void
+systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
+{
+ const char *p = NULL;
+ switch (sysnum) {
+ /* cloudabi_sys_clock_res_get */
+ case 0:
+ if (ndx == 0 || ndx == 1)
+ p = "cloudabi_timestamp_t";
+ break;
+ /* cloudabi_sys_clock_time_get */
+ case 1:
+ if (ndx == 0 || ndx == 1)
+ p = "cloudabi_timestamp_t";
+ break;
+ /* cloudabi_sys_condvar_signal */
+ case 2:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_fd_close */
+ case 3:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_fd_create1 */
+ case 4:
+ if (ndx == 0 || ndx == 1)
+ p = "cloudabi_fd_t";
+ break;
+ /* cloudabi_sys_fd_create2 */
+ case 5:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_fd_datasync */
+ case 6:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_fd_dup */
+ case 7:
+ if (ndx == 0 || ndx == 1)
+ p = "cloudabi_fd_t";
+ break;
+ /* cloudabi32_sys_fd_pread */
+ case 8:
+ if (ndx == 0 || ndx == 1)
+ p = "size_t";
+ break;
+ /* cloudabi32_sys_fd_pwrite */
+ case 9:
+ if (ndx == 0 || ndx == 1)
+ p = "size_t";
+ break;
+ /* cloudabi32_sys_fd_read */
+ case 10:
+ if (ndx == 0 || ndx == 1)
+ p = "size_t";
+ break;
+ /* cloudabi_sys_fd_replace */
+ case 11:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_fd_seek */
+ case 12:
+ if (ndx == 0 || ndx == 1)
+ p = "cloudabi_filesize_t";
+ break;
+ /* cloudabi_sys_fd_stat_get */
+ case 13:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_fd_stat_put */
+ case 14:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_fd_sync */
+ case 15:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi32_sys_fd_write */
+ case 16:
+ if (ndx == 0 || ndx == 1)
+ p = "size_t";
+ break;
+ /* cloudabi_sys_file_advise */
+ case 17:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_file_allocate */
+ case 18:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_file_create */
+ case 19:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_file_link */
+ case 20:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_file_open */
+ case 21:
+ if (ndx == 0 || ndx == 1)
+ p = "cloudabi_fd_t";
+ break;
+ /* cloudabi_sys_file_readdir */
+ case 22:
+ if (ndx == 0 || ndx == 1)
+ p = "size_t";
+ break;
+ /* cloudabi_sys_file_readlink */
+ case 23:
+ if (ndx == 0 || ndx == 1)
+ p = "size_t";
+ break;
+ /* cloudabi_sys_file_rename */
+ case 24:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_file_stat_fget */
+ case 25:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_file_stat_fput */
+ case 26:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_file_stat_get */
+ case 27:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_file_stat_put */
+ case 28:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_file_symlink */
+ case 29:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_file_unlink */
+ case 30:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_lock_unlock */
+ case 31:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_mem_advise */
+ case 32:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_mem_map */
+ case 33:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_mem_protect */
+ case 34:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_mem_sync */
+ case 35:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_mem_unmap */
+ case 36:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi32_sys_poll */
+ case 37:
+ if (ndx == 0 || ndx == 1)
+ p = "size_t";
+ break;
+ /* cloudabi_sys_proc_exec */
+ case 38:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_proc_exit */
+ case 39:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_proc_fork */
+ case 40:
+ /* cloudabi_sys_proc_raise */
+ case 41:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_random_get */
+ case 42:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi32_sys_sock_recv */
+ case 43:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi32_sys_sock_send */
+ case 44:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_sock_shutdown */
+ case 45:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi32_sys_thread_create */
+ case 46:
+ if (ndx == 0 || ndx == 1)
+ p = "cloudabi_tid_t";
+ break;
+ /* cloudabi_sys_thread_exit */
+ case 47:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_thread_yield */
+ case 48:
+ default:
+ break;
+ };
+ if (p != NULL)
+ strlcpy(desc, p, descsz);
+}
diff --git a/sys/compat/cloudabi32/cloudabi32_thread.c b/sys/compat/cloudabi32/cloudabi32_thread.c
new file mode 100644
index 000000000000..233700b40f1f
--- /dev/null
+++ b/sys/compat/cloudabi32/cloudabi32_thread.c
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+
+#include <contrib/cloudabi/cloudabi32_types.h>
+
+#include <compat/cloudabi32/cloudabi32_proto.h>
+#include <compat/cloudabi32/cloudabi32_util.h>
+
+struct thread_create_args {
+ cloudabi32_threadattr_t attr;
+ uint32_t tcb;
+ lwpid_t tid;
+};
+
+static int
+initialize_thread(struct thread *td, void *thunk)
+{
+ struct thread_create_args *args = thunk;
+
+ /* Save the thread ID, so it can be returned. */
+ args->tid = td->td_tid;
+
+ /* Set up initial register contents. */
+ return (cloudabi32_thread_setregs(td, &args->attr, args->tcb));
+}
+
+int
+cloudabi32_sys_thread_create(struct thread *td,
+ struct cloudabi32_sys_thread_create_args *uap)
+{
+ struct thread_create_args args;
+ int error;
+
+ error = copyin(uap->attr, &args.attr, sizeof(args.attr));
+ if (error != 0)
+ return (error);
+
+ /* Remove some space on the top of the stack for the TCB. */
+ args.tcb = rounddown(args.attr.stack + args.attr.stack_len -
+ sizeof(cloudabi32_tcb_t), _Alignof(cloudabi32_tcb_t));
+ args.attr.stack_len = args.tcb - args.attr.stack;
+
+ error = thread_create(td, NULL, initialize_thread, &args);
+ if (error != 0)
+ return (error);
+ td->td_retval[0] = args.tid;
+ return (0);
+}
diff --git a/sys/compat/cloudabi32/cloudabi32_util.h b/sys/compat/cloudabi32/cloudabi32_util.h
new file mode 100644
index 000000000000..917356468311
--- /dev/null
+++ b/sys/compat/cloudabi32/cloudabi32_util.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _CLOUDABI32_UTIL_H_
+#define _CLOUDABI32_UTIL_H_
+
+#include <sys/types.h>
+#define __ELF_WORD_SIZE 32
+#include <sys/imgact_elf.h>
+
+#include <contrib/cloudabi/cloudabi32_types.h>
+
+struct image_params;
+struct thread;
+
+extern Elf32_Brandinfo cloudabi32_brand;
+
+#define TO_PTR(x) ((void *)(uintptr_t)(x))
+
+/* Stack initialization during process execution. */
+int cloudabi32_copyout_strings(struct image_params *, uintptr_t *);
+int cloudabi32_fixup(uintptr_t *, struct image_params *);
+
+int cloudabi32_thread_setregs(struct thread *,
+ const cloudabi32_threadattr_t *, uint32_t);
+
+#endif
diff --git a/sys/compat/cloudabi32/syscalls.conf b/sys/compat/cloudabi32/syscalls.conf
new file mode 100644
index 000000000000..8e6522a63cef
--- /dev/null
+++ b/sys/compat/cloudabi32/syscalls.conf
@@ -0,0 +1,15 @@
+# $FreeBSD$
+sysnames="cloudabi32_syscalls.c"
+sysproto="cloudabi32_proto.h"
+sysproto_h=_CLOUDABI32_SYSPROTO_H_
+syshdr="cloudabi32_syscall.h"
+syssw="cloudabi32_sysent.c"
+sysmk="/dev/null"
+syscallprefix="CLOUDABI32_SYS_"
+switchname="cloudabi32_sysent"
+namesname="cloudabi32_syscallnames"
+systrace="cloudabi32_systrace_args.c"
+
+# Allow all system calls in capabilities mode. Extract the names of the
+# system calls from syscalls.master.
+capenabled=`sed -n -e 's/.*\<\(cloudabi[0-9]*_sys_[a-z0-9_]*\)\>.*/\1/p' $1 | tr '\n' ','`
diff --git a/sys/compat/cloudabi64/Makefile b/sys/compat/cloudabi64/Makefile
new file mode 100644
index 000000000000..e3379384942c
--- /dev/null
+++ b/sys/compat/cloudabi64/Makefile
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+SYSENT_FILE= ${SYSDIR}/contrib/cloudabi/syscalls64.master
+GENERATED_PREFIX= cloudabi64_
+
+.include "../../conf/sysent.mk"
diff --git a/sys/compat/cloudabi64/cloudabi64_fd.c b/sys/compat/cloudabi64/cloudabi64_fd.c
new file mode 100644
index 000000000000..ea403cf3559f
--- /dev/null
+++ b/sys/compat/cloudabi64/cloudabi64_fd.c
@@ -0,0 +1,145 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/malloc.h>
+#include <sys/syscallsubr.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
+
+#include <contrib/cloudabi/cloudabi64_types.h>
+
+#include <compat/cloudabi64/cloudabi64_proto.h>
+#include <compat/cloudabi64/cloudabi64_util.h>
+
+/* Copies in 64-bit iovec structures from userspace. */
+static int
+cloudabi64_copyinuio(const cloudabi64_iovec_t *iovp, size_t iovcnt,
+ struct uio **uiop)
+{
+ cloudabi64_iovec_t iovobj;
+ struct uio *uio;
+ struct iovec *iov;
+ size_t i;
+ int error;
+
+ /* Allocate uio and iovecs. */
+ if (iovcnt > UIO_MAXIOV)
+ return (EINVAL);
+ uio = malloc(sizeof(struct uio) + iovcnt * sizeof(struct iovec),
+ M_IOV, M_WAITOK);
+ iov = (struct iovec *)(uio + 1);
+
+ /* Initialize uio. */
+ uio->uio_iov = iov;
+ uio->uio_iovcnt = iovcnt;
+ uio->uio_segflg = UIO_USERSPACE;
+ uio->uio_offset = -1;
+ uio->uio_resid = 0;
+
+ /* Copy in iovecs. */
+ for (i = 0; i < iovcnt; i++) {
+ error = copyin(&iovp[i], &iovobj, sizeof(iovobj));
+ if (error != 0) {
+ free(uio, M_IOV);
+ return (error);
+ }
+ iov[i].iov_base = TO_PTR(iovobj.buf);
+ iov[i].iov_len = iovobj.buf_len;
+ if (iov[i].iov_len > INT64_MAX - uio->uio_resid) {
+ free(uio, M_IOV);
+ return (EINVAL);
+ }
+ uio->uio_resid += iov[i].iov_len;
+ }
+
+ *uiop = uio;
+ return (0);
+}
+
+int
+cloudabi64_sys_fd_pread(struct thread *td,
+ struct cloudabi64_sys_fd_pread_args *uap)
+{
+ struct uio *uio;
+ int error;
+
+ error = cloudabi64_copyinuio(uap->iovs, uap->iovs_len, &uio);
+ if (error != 0)
+ return (error);
+ error = kern_preadv(td, uap->fd, uio, uap->offset);
+ free(uio, M_IOV);
+ return (error);
+}
+
+int
+cloudabi64_sys_fd_pwrite(struct thread *td,
+ struct cloudabi64_sys_fd_pwrite_args *uap)
+{
+ struct uio *uio;
+ int error;
+
+ error = cloudabi64_copyinuio(TO_PTR(uap->iovs), uap->iovs_len, &uio);
+ if (error != 0)
+ return (error);
+ error = kern_pwritev(td, uap->fd, uio, uap->offset);
+ free(uio, M_IOV);
+ return (error);
+}
+
+int
+cloudabi64_sys_fd_read(struct thread *td,
+ struct cloudabi64_sys_fd_read_args *uap)
+{
+ struct uio *uio;
+ int error;
+
+ error = cloudabi64_copyinuio(uap->iovs, uap->iovs_len, &uio);
+ if (error != 0)
+ return (error);
+ error = kern_readv(td, uap->fd, uio);
+ free(uio, M_IOV);
+ return (error);
+}
+
+int
+cloudabi64_sys_fd_write(struct thread *td,
+ struct cloudabi64_sys_fd_write_args *uap)
+{
+ struct uio *uio;
+ int error;
+
+ error = cloudabi64_copyinuio(TO_PTR(uap->iovs), uap->iovs_len, &uio);
+ if (error != 0)
+ return (error);
+ error = kern_writev(td, uap->fd, uio);
+ free(uio, M_IOV);
+ return (error);
+}
diff --git a/sys/compat/cloudabi64/cloudabi64_module.c b/sys/compat/cloudabi64/cloudabi64_module.c
new file mode 100644
index 000000000000..ed0c85b4aba5
--- /dev/null
+++ b/sys/compat/cloudabi64/cloudabi64_module.c
@@ -0,0 +1,184 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/imgact.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/proc.h>
+#include <sys/smp.h>
+#include <sys/sysctl.h>
+#include <sys/sysent.h>
+#include <sys/systm.h>
+
+#include <contrib/cloudabi/cloudabi64_types.h>
+
+#include <compat/cloudabi/cloudabi_util.h>
+
+#include <compat/cloudabi64/cloudabi64_util.h>
+
+extern char _binary_cloudabi64_vdso_o_start[];
+extern char _binary_cloudabi64_vdso_o_end[];
+
+int
+cloudabi64_copyout_strings(struct image_params *imgp, uintptr_t *stack_base)
+{
+ struct image_args *args;
+ uintptr_t begin;
+ size_t len;
+
+ /* Copy out program arguments. */
+ args = imgp->args;
+ len = exec_args_get_begin_envv(args) - args->begin_argv;
+ begin = rounddown2(imgp->sysent->sv_usrstack - len, sizeof(register_t));
+ *stack_base = begin;
+ return (copyout(args->begin_argv, (void *)begin, len));
+}
+
+int
+cloudabi64_fixup(uintptr_t *stack_base, struct image_params *imgp)
+{
+ char canarybuf[64], pidbuf[16];
+ Elf64_Auxargs *args;
+ struct thread *td;
+ void *argdata, *canary, *pid;
+ size_t argdatalen;
+ int error;
+
+ /*
+ * CloudABI executables do not store the FreeBSD OS release
+ * number in their header. Set the OS release number to the
+ * latest version of FreeBSD, so that system calls behave as if
+ * called natively.
+ */
+ td = curthread;
+ td->td_proc->p_osrel = __FreeBSD_version;
+
+ argdata = (void *)*stack_base;
+
+ /* Store canary for stack smashing protection. */
+ arc4rand(canarybuf, sizeof(canarybuf), 0);
+ *stack_base -= roundup(sizeof(canarybuf), sizeof(register_t));
+ canary = (void *)*stack_base;
+ error = copyout(canarybuf, canary, sizeof(canarybuf));
+ if (error != 0)
+ return (error);
+
+ /*
+ * Generate a random UUID that identifies the process. Right now
+ * we don't store this UUID in the kernel. Ideally, it should be
+ * exposed through ps(1).
+ */
+ arc4rand(pidbuf, sizeof(pidbuf), 0);
+ pidbuf[6] = (pidbuf[6] & 0x0f) | 0x40;
+ pidbuf[8] = (pidbuf[8] & 0x3f) | 0x80;
+ *stack_base -= roundup(sizeof(pidbuf), sizeof(register_t));
+ pid = (void *)*stack_base;
+ error = copyout(pidbuf, pid, sizeof(pidbuf));
+ if (error != 0)
+ return (error);
+
+ /*
+ * Compute length of program arguments. As the argument data is
+ * binary safe, we had to add a trailing null byte in
+ * exec_copyin_data_fds(). Undo this by reducing the length.
+ */
+ args = (Elf64_Auxargs *)imgp->auxargs;
+ argdatalen = exec_args_get_begin_envv(imgp->args) -
+ imgp->args->begin_argv;
+ if (argdatalen > 0)
+ --argdatalen;
+
+ /* Write out an auxiliary vector. */
+ cloudabi64_auxv_t auxv[] = {
+#define VAL(type, val) { .a_type = (type), .a_val = (val) }
+#define PTR(type, ptr) { .a_type = (type), .a_ptr = (uintptr_t)(ptr) }
+ PTR(CLOUDABI_AT_ARGDATA, argdata),
+ VAL(CLOUDABI_AT_ARGDATALEN, argdatalen),
+ VAL(CLOUDABI_AT_BASE, args->base),
+ PTR(CLOUDABI_AT_CANARY, canary),
+ VAL(CLOUDABI_AT_CANARYLEN, sizeof(canarybuf)),
+ VAL(CLOUDABI_AT_NCPUS, mp_ncpus),
+ VAL(CLOUDABI_AT_PAGESZ, args->pagesz),
+ PTR(CLOUDABI_AT_PHDR, args->phdr),
+ VAL(CLOUDABI_AT_PHNUM, args->phnum),
+ PTR(CLOUDABI_AT_PID, pid),
+ PTR(CLOUDABI_AT_SYSINFO_EHDR,
+ imgp->proc->p_sysent->sv_shared_page_base),
+ VAL(CLOUDABI_AT_TID, td->td_tid),
+#undef VAL
+#undef PTR
+ { .a_type = CLOUDABI_AT_NULL },
+ };
+ *stack_base -= roundup(sizeof(auxv), sizeof(register_t));
+ error = copyout(auxv, (void *)*stack_base, sizeof(auxv));
+ if (error != 0)
+ return (error);
+
+ /* Reserve space for storing the TCB. */
+ *stack_base -= roundup(sizeof(cloudabi64_tcb_t), sizeof(register_t));
+ return (0);
+}
+
+static int
+cloudabi64_modevent(module_t mod, int type, void *data)
+{
+
+ switch (type) {
+ case MOD_LOAD:
+ cloudabi_vdso_init(cloudabi64_brand.sysvec,
+ _binary_cloudabi64_vdso_o_start,
+ _binary_cloudabi64_vdso_o_end);
+ if (elf64_insert_brand_entry(&cloudabi64_brand) < 0) {
+ printf("Failed to add CloudABI ELF brand handler\n");
+ return (EINVAL);
+ }
+ return (0);
+ case MOD_UNLOAD:
+ if (elf64_brand_inuse(&cloudabi64_brand))
+ return (EBUSY);
+ if (elf64_remove_brand_entry(&cloudabi64_brand) < 0) {
+ printf("Failed to remove CloudABI ELF brand handler\n");
+ return (EINVAL);
+ }
+ cloudabi_vdso_destroy(cloudabi64_brand.sysvec);
+ return (0);
+ default:
+ return (EOPNOTSUPP);
+ }
+}
+
+static moduledata_t cloudabi64_module = {
+ "cloudabi64",
+ cloudabi64_modevent,
+ NULL
+};
+
+DECLARE_MODULE_TIED(cloudabi64, cloudabi64_module, SI_SUB_EXEC, SI_ORDER_ANY);
+MODULE_DEPEND(cloudabi64, cloudabi, 1, 1, 1);
+FEATURE(cloudabi64, "CloudABI 64bit support");
diff --git a/sys/compat/cloudabi64/cloudabi64_poll.c b/sys/compat/cloudabi64/cloudabi64_poll.c
new file mode 100644
index 000000000000..2d3d87f3ac7f
--- /dev/null
+++ b/sys/compat/cloudabi64/cloudabi64_poll.c
@@ -0,0 +1,340 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/syscallsubr.h>
+
+#include <contrib/cloudabi/cloudabi64_types.h>
+
+#include <compat/cloudabi/cloudabi_util.h>
+
+#include <compat/cloudabi64/cloudabi64_proto.h>
+#include <compat/cloudabi64/cloudabi64_util.h>
+
+/* Converts a FreeBSD signal number to a CloudABI signal number. */
+static cloudabi_signal_t
+convert_signal(int sig)
+{
+ static const cloudabi_signal_t signals[] = {
+ [SIGABRT] = CLOUDABI_SIGABRT,
+ [SIGALRM] = CLOUDABI_SIGALRM,
+ [SIGBUS] = CLOUDABI_SIGBUS,
+ [SIGCHLD] = CLOUDABI_SIGCHLD,
+ [SIGCONT] = CLOUDABI_SIGCONT,
+ [SIGFPE] = CLOUDABI_SIGFPE,
+ [SIGHUP] = CLOUDABI_SIGHUP,
+ [SIGILL] = CLOUDABI_SIGILL,
+ [SIGINT] = CLOUDABI_SIGINT,
+ [SIGKILL] = CLOUDABI_SIGKILL,
+ [SIGPIPE] = CLOUDABI_SIGPIPE,
+ [SIGQUIT] = CLOUDABI_SIGQUIT,
+ [SIGSEGV] = CLOUDABI_SIGSEGV,
+ [SIGSTOP] = CLOUDABI_SIGSTOP,
+ [SIGSYS] = CLOUDABI_SIGSYS,
+ [SIGTERM] = CLOUDABI_SIGTERM,
+ [SIGTRAP] = CLOUDABI_SIGTRAP,
+ [SIGTSTP] = CLOUDABI_SIGTSTP,
+ [SIGTTIN] = CLOUDABI_SIGTTIN,
+ [SIGTTOU] = CLOUDABI_SIGTTOU,
+ [SIGURG] = CLOUDABI_SIGURG,
+ [SIGUSR1] = CLOUDABI_SIGUSR1,
+ [SIGUSR2] = CLOUDABI_SIGUSR2,
+ [SIGVTALRM] = CLOUDABI_SIGVTALRM,
+ [SIGXCPU] = CLOUDABI_SIGXCPU,
+ [SIGXFSZ] = CLOUDABI_SIGXFSZ,
+ };
+
+ /* Convert unknown signals to SIGABRT. */
+ if (sig < 0 || sig >= nitems(signals) || signals[sig] == 0)
+ return (SIGABRT);
+ return (signals[sig]);
+}
+
+struct cloudabi64_kevent_args {
+ const cloudabi64_subscription_t *in;
+ cloudabi_event_t *out;
+};
+
+/* Converts CloudABI's subscription objects to FreeBSD's struct kevent. */
+static int
+cloudabi64_kevent_copyin(void *arg, struct kevent *kevp, int count)
+{
+ cloudabi64_subscription_t sub;
+ struct cloudabi64_kevent_args *args;
+ cloudabi_timestamp_t ts;
+ int error;
+
+ args = arg;
+ while (count-- > 0) {
+ /* TODO(ed): Copy in multiple entries at once. */
+ error = copyin(args->in++, &sub, sizeof(sub));
+ if (error != 0)
+ return (error);
+
+ memset(kevp, 0, sizeof(*kevp));
+ kevp->udata = TO_PTR(sub.userdata);
+ switch (sub.type) {
+ case CLOUDABI_EVENTTYPE_CLOCK:
+ kevp->filter = EVFILT_TIMER;
+ kevp->ident = sub.clock.identifier;
+ kevp->fflags = NOTE_NSECONDS;
+ if ((sub.clock.flags &
+ CLOUDABI_SUBSCRIPTION_CLOCK_ABSTIME) != 0 &&
+ sub.clock.timeout > 0) {
+ /* Convert absolute timestamp to a relative. */
+ error = cloudabi_clock_time_get(curthread,
+ sub.clock.clock_id, &ts);
+ if (error != 0)
+ return (error);
+ ts = ts > sub.clock.timeout ? 0 :
+ sub.clock.timeout - ts;
+ } else {
+ /* Relative timestamp. */
+ ts = sub.clock.timeout;
+ }
+ kevp->data = ts > INTPTR_MAX ? INTPTR_MAX : ts;
+ break;
+ case CLOUDABI_EVENTTYPE_FD_READ:
+ kevp->filter = EVFILT_READ;
+ kevp->ident = sub.fd_readwrite.fd;
+ kevp->fflags = NOTE_FILE_POLL;
+ break;
+ case CLOUDABI_EVENTTYPE_FD_WRITE:
+ kevp->filter = EVFILT_WRITE;
+ kevp->ident = sub.fd_readwrite.fd;
+ break;
+ case CLOUDABI_EVENTTYPE_PROC_TERMINATE:
+ kevp->filter = EVFILT_PROCDESC;
+ kevp->ident = sub.proc_terminate.fd;
+ kevp->fflags = NOTE_EXIT;
+ break;
+ }
+ kevp->flags = EV_ADD | EV_ONESHOT;
+ ++kevp;
+ }
+ return (0);
+}
+
+/* Converts FreeBSD's struct kevent to CloudABI's event objects. */
+static int
+cloudabi64_kevent_copyout(void *arg, struct kevent *kevp, int count)
+{
+ cloudabi_event_t ev;
+ struct cloudabi64_kevent_args *args;
+ int error;
+
+ args = arg;
+ while (count-- > 0) {
+ /* Convert fields that should always be present. */
+ memset(&ev, 0, sizeof(ev));
+ ev.userdata = (uintptr_t)kevp->udata;
+ switch (kevp->filter) {
+ case EVFILT_TIMER:
+ ev.type = CLOUDABI_EVENTTYPE_CLOCK;
+ break;
+ case EVFILT_READ:
+ ev.type = CLOUDABI_EVENTTYPE_FD_READ;
+ break;
+ case EVFILT_WRITE:
+ ev.type = CLOUDABI_EVENTTYPE_FD_WRITE;
+ break;
+ case EVFILT_PROCDESC:
+ ev.type = CLOUDABI_EVENTTYPE_PROC_TERMINATE;
+ break;
+ }
+
+ if ((kevp->flags & EV_ERROR) == 0) {
+ /* Success. */
+ switch (kevp->filter) {
+ case EVFILT_READ:
+ case EVFILT_WRITE:
+ ev.fd_readwrite.nbytes = kevp->data;
+ if ((kevp->flags & EV_EOF) != 0) {
+ ev.fd_readwrite.flags |=
+ CLOUDABI_EVENT_FD_READWRITE_HANGUP;
+ }
+ break;
+ case EVFILT_PROCDESC:
+ if (WIFSIGNALED(kevp->data)) {
+ /* Process got signalled. */
+ ev.proc_terminate.signal =
+ convert_signal(WTERMSIG(kevp->data));
+ ev.proc_terminate.exitcode = 0;
+ } else {
+ /* Process exited. */
+ ev.proc_terminate.signal = 0;
+ ev.proc_terminate.exitcode =
+ WEXITSTATUS(kevp->data);
+ }
+ break;
+ }
+ } else {
+ /* Error. */
+ ev.error = cloudabi_convert_errno(kevp->data);
+ }
+ ++kevp;
+
+ /* TODO(ed): Copy out multiple entries at once. */
+ error = copyout(&ev, args->out++, sizeof(ev));
+ if (error != 0)
+ return (error);
+ }
+ return (0);
+}
+
+int
+cloudabi64_sys_poll(struct thread *td, struct cloudabi64_sys_poll_args *uap)
+{
+ struct cloudabi64_kevent_args args = {
+ .in = uap->in,
+ .out = uap->out,
+ };
+ struct kevent_copyops copyops = {
+ .k_copyin = cloudabi64_kevent_copyin,
+ .k_copyout = cloudabi64_kevent_copyout,
+ .arg = &args,
+ };
+
+ /*
+ * Bandaid to support CloudABI futex constructs that are not
+ * implemented through FreeBSD's kqueue().
+ */
+ if (uap->nsubscriptions == 1) {
+ cloudabi64_subscription_t sub;
+ cloudabi_event_t ev = {};
+ int error;
+
+ error = copyin(uap->in, &sub, sizeof(sub));
+ if (error != 0)
+ return (error);
+ ev.userdata = sub.userdata;
+ ev.type = sub.type;
+ if (sub.type == CLOUDABI_EVENTTYPE_CONDVAR) {
+ /* Wait on a condition variable. */
+ ev.error = cloudabi_convert_errno(
+ cloudabi_futex_condvar_wait(
+ td, TO_PTR(sub.condvar.condvar),
+ sub.condvar.condvar_scope,
+ TO_PTR(sub.condvar.lock),
+ sub.condvar.lock_scope,
+ CLOUDABI_CLOCK_MONOTONIC, UINT64_MAX, 0, true));
+ td->td_retval[0] = 1;
+ return (copyout(&ev, uap->out, sizeof(ev)));
+ } else if (sub.type == CLOUDABI_EVENTTYPE_LOCK_RDLOCK) {
+ /* Acquire a read lock. */
+ ev.error = cloudabi_convert_errno(
+ cloudabi_futex_lock_rdlock(
+ td, TO_PTR(sub.lock.lock),
+ sub.lock.lock_scope, CLOUDABI_CLOCK_MONOTONIC,
+ UINT64_MAX, 0, true));
+ td->td_retval[0] = 1;
+ return (copyout(&ev, uap->out, sizeof(ev)));
+ } else if (sub.type == CLOUDABI_EVENTTYPE_LOCK_WRLOCK) {
+ /* Acquire a write lock. */
+ ev.error = cloudabi_convert_errno(
+ cloudabi_futex_lock_wrlock(
+ td, TO_PTR(sub.lock.lock),
+ sub.lock.lock_scope, CLOUDABI_CLOCK_MONOTONIC,
+ UINT64_MAX, 0, true));
+ td->td_retval[0] = 1;
+ return (copyout(&ev, uap->out, sizeof(ev)));
+ }
+ } else if (uap->nsubscriptions == 2) {
+ cloudabi64_subscription_t sub[2];
+ cloudabi_event_t ev[2] = {};
+ int error;
+
+ error = copyin(uap->in, &sub, sizeof(sub));
+ if (error != 0)
+ return (error);
+ ev[0].userdata = sub[0].userdata;
+ ev[0].type = sub[0].type;
+ ev[1].userdata = sub[1].userdata;
+ ev[1].type = sub[1].type;
+ if (sub[0].type == CLOUDABI_EVENTTYPE_CONDVAR &&
+ sub[1].type == CLOUDABI_EVENTTYPE_CLOCK) {
+ /* Wait for a condition variable with timeout. */
+ error = cloudabi_futex_condvar_wait(
+ td, TO_PTR(sub[0].condvar.condvar),
+ sub[0].condvar.condvar_scope,
+ TO_PTR(sub[0].condvar.lock),
+ sub[0].condvar.lock_scope, sub[1].clock.clock_id,
+ sub[1].clock.timeout, sub[1].clock.precision,
+ (sub[1].clock.flags &
+ CLOUDABI_SUBSCRIPTION_CLOCK_ABSTIME) != 0);
+ if (error == ETIMEDOUT) {
+ td->td_retval[0] = 1;
+ return (copyout(&ev[1], uap->out,
+ sizeof(ev[1])));
+ }
+
+ ev[0].error = cloudabi_convert_errno(error);
+ td->td_retval[0] = 1;
+ return (copyout(&ev[0], uap->out, sizeof(ev[0])));
+ } else if (sub[0].type == CLOUDABI_EVENTTYPE_LOCK_RDLOCK &&
+ sub[1].type == CLOUDABI_EVENTTYPE_CLOCK) {
+ /* Acquire a read lock with a timeout. */
+ error = cloudabi_futex_lock_rdlock(
+ td, TO_PTR(sub[0].lock.lock),
+ sub[0].lock.lock_scope, sub[1].clock.clock_id,
+ sub[1].clock.timeout, sub[1].clock.precision,
+ (sub[1].clock.flags &
+ CLOUDABI_SUBSCRIPTION_CLOCK_ABSTIME) != 0);
+ if (error == ETIMEDOUT) {
+ td->td_retval[0] = 1;
+ return (copyout(&ev[1], uap->out,
+ sizeof(ev[1])));
+ }
+
+ ev[0].error = cloudabi_convert_errno(error);
+ td->td_retval[0] = 1;
+ return (copyout(&ev[0], uap->out, sizeof(ev[0])));
+ } else if (sub[0].type == CLOUDABI_EVENTTYPE_LOCK_WRLOCK &&
+ sub[1].type == CLOUDABI_EVENTTYPE_CLOCK) {
+ /* Acquire a write lock with a timeout. */
+ error = cloudabi_futex_lock_wrlock(
+ td, TO_PTR(sub[0].lock.lock),
+ sub[0].lock.lock_scope, sub[1].clock.clock_id,
+ sub[1].clock.timeout, sub[1].clock.precision,
+ (sub[1].clock.flags &
+ CLOUDABI_SUBSCRIPTION_CLOCK_ABSTIME) != 0);
+ if (error == ETIMEDOUT) {
+ td->td_retval[0] = 1;
+ return (copyout(&ev[1], uap->out,
+ sizeof(ev[1])));
+ }
+
+ ev[0].error = cloudabi_convert_errno(error);
+ td->td_retval[0] = 1;
+ return (copyout(&ev[0], uap->out, sizeof(ev[0])));
+ }
+ }
+
+ return (kern_kevent_anonymous(td, uap->nsubscriptions, &copyops));
+}
diff --git a/sys/compat/cloudabi64/cloudabi64_proto.h b/sys/compat/cloudabi64/cloudabi64_proto.h
new file mode 100644
index 000000000000..54bf9965a793
--- /dev/null
+++ b/sys/compat/cloudabi64/cloudabi64_proto.h
@@ -0,0 +1,420 @@
+/*
+ * System call prototypes.
+ *
+ * DO NOT EDIT-- this file is automatically @generated.
+ * $FreeBSD$
+ */
+
+#ifndef _CLOUDABI64_SYSPROTO_H_
+#define _CLOUDABI64_SYSPROTO_H_
+
+#include <sys/signal.h>
+#include <sys/acl.h>
+#include <sys/cpuset.h>
+#include <sys/domainset.h>
+#include <sys/_ffcounter.h>
+#include <sys/_semaphore.h>
+#include <sys/ucontext.h>
+#include <sys/wait.h>
+
+#include <bsm/audit_kevents.h>
+
+struct proc;
+
+struct thread;
+
+#define PAD_(t) (sizeof(register_t) <= sizeof(t) ? \
+ 0 : sizeof(register_t) - sizeof(t))
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define PADL_(t) 0
+#define PADR_(t) PAD_(t)
+#else
+#define PADL_(t) PAD_(t)
+#define PADR_(t) 0
+#endif
+
+struct cloudabi_sys_clock_res_get_args {
+ char clock_id_l_[PADL_(cloudabi_clockid_t)]; cloudabi_clockid_t clock_id; char clock_id_r_[PADR_(cloudabi_clockid_t)];
+};
+struct cloudabi_sys_clock_time_get_args {
+ char clock_id_l_[PADL_(cloudabi_clockid_t)]; cloudabi_clockid_t clock_id; char clock_id_r_[PADR_(cloudabi_clockid_t)];
+ char precision_l_[PADL_(cloudabi_timestamp_t)]; cloudabi_timestamp_t precision; char precision_r_[PADR_(cloudabi_timestamp_t)];
+};
+struct cloudabi_sys_condvar_signal_args {
+ char condvar_l_[PADL_(cloudabi_condvar_t *)]; cloudabi_condvar_t * condvar; char condvar_r_[PADR_(cloudabi_condvar_t *)];
+ char scope_l_[PADL_(cloudabi_scope_t)]; cloudabi_scope_t scope; char scope_r_[PADR_(cloudabi_scope_t)];
+ char nwaiters_l_[PADL_(cloudabi_nthreads_t)]; cloudabi_nthreads_t nwaiters; char nwaiters_r_[PADR_(cloudabi_nthreads_t)];
+};
+struct cloudabi_sys_fd_close_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+};
+struct cloudabi_sys_fd_create1_args {
+ char type_l_[PADL_(cloudabi_filetype_t)]; cloudabi_filetype_t type; char type_r_[PADR_(cloudabi_filetype_t)];
+};
+struct cloudabi_sys_fd_create2_args {
+ char type_l_[PADL_(cloudabi_filetype_t)]; cloudabi_filetype_t type; char type_r_[PADR_(cloudabi_filetype_t)];
+};
+struct cloudabi_sys_fd_datasync_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+};
+struct cloudabi_sys_fd_dup_args {
+ char from_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t from; char from_r_[PADR_(cloudabi_fd_t)];
+};
+struct cloudabi64_sys_fd_pread_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char iovs_l_[PADL_(const cloudabi64_iovec_t *)]; const cloudabi64_iovec_t * iovs; char iovs_r_[PADR_(const cloudabi64_iovec_t *)];
+ char iovs_len_l_[PADL_(size_t)]; size_t iovs_len; char iovs_len_r_[PADR_(size_t)];
+ char offset_l_[PADL_(cloudabi_filesize_t)]; cloudabi_filesize_t offset; char offset_r_[PADR_(cloudabi_filesize_t)];
+};
+struct cloudabi64_sys_fd_pwrite_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char iovs_l_[PADL_(const cloudabi64_ciovec_t *)]; const cloudabi64_ciovec_t * iovs; char iovs_r_[PADR_(const cloudabi64_ciovec_t *)];
+ char iovs_len_l_[PADL_(size_t)]; size_t iovs_len; char iovs_len_r_[PADR_(size_t)];
+ char offset_l_[PADL_(cloudabi_filesize_t)]; cloudabi_filesize_t offset; char offset_r_[PADR_(cloudabi_filesize_t)];
+};
+struct cloudabi64_sys_fd_read_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char iovs_l_[PADL_(const cloudabi64_iovec_t *)]; const cloudabi64_iovec_t * iovs; char iovs_r_[PADR_(const cloudabi64_iovec_t *)];
+ char iovs_len_l_[PADL_(size_t)]; size_t iovs_len; char iovs_len_r_[PADR_(size_t)];
+};
+struct cloudabi_sys_fd_replace_args {
+ char from_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t from; char from_r_[PADR_(cloudabi_fd_t)];
+ char to_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t to; char to_r_[PADR_(cloudabi_fd_t)];
+};
+struct cloudabi_sys_fd_seek_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char offset_l_[PADL_(cloudabi_filedelta_t)]; cloudabi_filedelta_t offset; char offset_r_[PADR_(cloudabi_filedelta_t)];
+ char whence_l_[PADL_(cloudabi_whence_t)]; cloudabi_whence_t whence; char whence_r_[PADR_(cloudabi_whence_t)];
+};
+struct cloudabi_sys_fd_stat_get_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char buf_l_[PADL_(cloudabi_fdstat_t *)]; cloudabi_fdstat_t * buf; char buf_r_[PADR_(cloudabi_fdstat_t *)];
+};
+struct cloudabi_sys_fd_stat_put_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char buf_l_[PADL_(const cloudabi_fdstat_t *)]; const cloudabi_fdstat_t * buf; char buf_r_[PADR_(const cloudabi_fdstat_t *)];
+ char flags_l_[PADL_(cloudabi_fdsflags_t)]; cloudabi_fdsflags_t flags; char flags_r_[PADR_(cloudabi_fdsflags_t)];
+};
+struct cloudabi_sys_fd_sync_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+};
+struct cloudabi64_sys_fd_write_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char iovs_l_[PADL_(const cloudabi64_ciovec_t *)]; const cloudabi64_ciovec_t * iovs; char iovs_r_[PADR_(const cloudabi64_ciovec_t *)];
+ char iovs_len_l_[PADL_(size_t)]; size_t iovs_len; char iovs_len_r_[PADR_(size_t)];
+};
+struct cloudabi_sys_file_advise_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char offset_l_[PADL_(cloudabi_filesize_t)]; cloudabi_filesize_t offset; char offset_r_[PADR_(cloudabi_filesize_t)];
+ char len_l_[PADL_(cloudabi_filesize_t)]; cloudabi_filesize_t len; char len_r_[PADR_(cloudabi_filesize_t)];
+ char advice_l_[PADL_(cloudabi_advice_t)]; cloudabi_advice_t advice; char advice_r_[PADR_(cloudabi_advice_t)];
+};
+struct cloudabi_sys_file_allocate_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char offset_l_[PADL_(cloudabi_filesize_t)]; cloudabi_filesize_t offset; char offset_r_[PADR_(cloudabi_filesize_t)];
+ char len_l_[PADL_(cloudabi_filesize_t)]; cloudabi_filesize_t len; char len_r_[PADR_(cloudabi_filesize_t)];
+};
+struct cloudabi_sys_file_create_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char path_len_l_[PADL_(size_t)]; size_t path_len; char path_len_r_[PADR_(size_t)];
+ char type_l_[PADL_(cloudabi_filetype_t)]; cloudabi_filetype_t type; char type_r_[PADR_(cloudabi_filetype_t)];
+};
+struct cloudabi_sys_file_link_args {
+ char fd1_l_[PADL_(cloudabi_lookup_t)]; cloudabi_lookup_t fd1; char fd1_r_[PADR_(cloudabi_lookup_t)];
+ char path1_l_[PADL_(const char *)]; const char * path1; char path1_r_[PADR_(const char *)];
+ char path1_len_l_[PADL_(size_t)]; size_t path1_len; char path1_len_r_[PADR_(size_t)];
+ char fd2_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd2; char fd2_r_[PADR_(cloudabi_fd_t)];
+ char path2_l_[PADL_(const char *)]; const char * path2; char path2_r_[PADR_(const char *)];
+ char path2_len_l_[PADL_(size_t)]; size_t path2_len; char path2_len_r_[PADR_(size_t)];
+};
+struct cloudabi_sys_file_open_args {
+ char dirfd_l_[PADL_(cloudabi_lookup_t)]; cloudabi_lookup_t dirfd; char dirfd_r_[PADR_(cloudabi_lookup_t)];
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char path_len_l_[PADL_(size_t)]; size_t path_len; char path_len_r_[PADR_(size_t)];
+ char oflags_l_[PADL_(cloudabi_oflags_t)]; cloudabi_oflags_t oflags; char oflags_r_[PADR_(cloudabi_oflags_t)];
+ char fds_l_[PADL_(const cloudabi_fdstat_t *)]; const cloudabi_fdstat_t * fds; char fds_r_[PADR_(const cloudabi_fdstat_t *)];
+};
+struct cloudabi_sys_file_readdir_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char buf_l_[PADL_(void *)]; void * buf; char buf_r_[PADR_(void *)];
+ char buf_len_l_[PADL_(size_t)]; size_t buf_len; char buf_len_r_[PADR_(size_t)];
+ char cookie_l_[PADL_(cloudabi_dircookie_t)]; cloudabi_dircookie_t cookie; char cookie_r_[PADR_(cloudabi_dircookie_t)];
+};
+struct cloudabi_sys_file_readlink_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char path_len_l_[PADL_(size_t)]; size_t path_len; char path_len_r_[PADR_(size_t)];
+ char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)];
+ char buf_len_l_[PADL_(size_t)]; size_t buf_len; char buf_len_r_[PADR_(size_t)];
+};
+struct cloudabi_sys_file_rename_args {
+ char fd1_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd1; char fd1_r_[PADR_(cloudabi_fd_t)];
+ char path1_l_[PADL_(const char *)]; const char * path1; char path1_r_[PADR_(const char *)];
+ char path1_len_l_[PADL_(size_t)]; size_t path1_len; char path1_len_r_[PADR_(size_t)];
+ char fd2_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd2; char fd2_r_[PADR_(cloudabi_fd_t)];
+ char path2_l_[PADL_(const char *)]; const char * path2; char path2_r_[PADR_(const char *)];
+ char path2_len_l_[PADL_(size_t)]; size_t path2_len; char path2_len_r_[PADR_(size_t)];
+};
+struct cloudabi_sys_file_stat_fget_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char buf_l_[PADL_(cloudabi_filestat_t *)]; cloudabi_filestat_t * buf; char buf_r_[PADR_(cloudabi_filestat_t *)];
+};
+struct cloudabi_sys_file_stat_fput_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char buf_l_[PADL_(const cloudabi_filestat_t *)]; const cloudabi_filestat_t * buf; char buf_r_[PADR_(const cloudabi_filestat_t *)];
+ char flags_l_[PADL_(cloudabi_fsflags_t)]; cloudabi_fsflags_t flags; char flags_r_[PADR_(cloudabi_fsflags_t)];
+};
+struct cloudabi_sys_file_stat_get_args {
+ char fd_l_[PADL_(cloudabi_lookup_t)]; cloudabi_lookup_t fd; char fd_r_[PADR_(cloudabi_lookup_t)];
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char path_len_l_[PADL_(size_t)]; size_t path_len; char path_len_r_[PADR_(size_t)];
+ char buf_l_[PADL_(cloudabi_filestat_t *)]; cloudabi_filestat_t * buf; char buf_r_[PADR_(cloudabi_filestat_t *)];
+};
+struct cloudabi_sys_file_stat_put_args {
+ char fd_l_[PADL_(cloudabi_lookup_t)]; cloudabi_lookup_t fd; char fd_r_[PADR_(cloudabi_lookup_t)];
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char path_len_l_[PADL_(size_t)]; size_t path_len; char path_len_r_[PADR_(size_t)];
+ char buf_l_[PADL_(const cloudabi_filestat_t *)]; const cloudabi_filestat_t * buf; char buf_r_[PADR_(const cloudabi_filestat_t *)];
+ char flags_l_[PADL_(cloudabi_fsflags_t)]; cloudabi_fsflags_t flags; char flags_r_[PADR_(cloudabi_fsflags_t)];
+};
+struct cloudabi_sys_file_symlink_args {
+ char path1_l_[PADL_(const char *)]; const char * path1; char path1_r_[PADR_(const char *)];
+ char path1_len_l_[PADL_(size_t)]; size_t path1_len; char path1_len_r_[PADR_(size_t)];
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char path2_l_[PADL_(const char *)]; const char * path2; char path2_r_[PADR_(const char *)];
+ char path2_len_l_[PADL_(size_t)]; size_t path2_len; char path2_len_r_[PADR_(size_t)];
+};
+struct cloudabi_sys_file_unlink_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char path_len_l_[PADL_(size_t)]; size_t path_len; char path_len_r_[PADR_(size_t)];
+ char flags_l_[PADL_(cloudabi_ulflags_t)]; cloudabi_ulflags_t flags; char flags_r_[PADR_(cloudabi_ulflags_t)];
+};
+struct cloudabi_sys_lock_unlock_args {
+ char lock_l_[PADL_(cloudabi_lock_t *)]; cloudabi_lock_t * lock; char lock_r_[PADR_(cloudabi_lock_t *)];
+ char scope_l_[PADL_(cloudabi_scope_t)]; cloudabi_scope_t scope; char scope_r_[PADR_(cloudabi_scope_t)];
+};
+struct cloudabi_sys_mem_advise_args {
+ char mapping_l_[PADL_(void *)]; void * mapping; char mapping_r_[PADR_(void *)];
+ char mapping_len_l_[PADL_(size_t)]; size_t mapping_len; char mapping_len_r_[PADR_(size_t)];
+ char advice_l_[PADL_(cloudabi_advice_t)]; cloudabi_advice_t advice; char advice_r_[PADR_(cloudabi_advice_t)];
+};
+struct cloudabi_sys_mem_map_args {
+ char addr_l_[PADL_(void *)]; void * addr; char addr_r_[PADR_(void *)];
+ char len_l_[PADL_(size_t)]; size_t len; char len_r_[PADR_(size_t)];
+ char prot_l_[PADL_(cloudabi_mprot_t)]; cloudabi_mprot_t prot; char prot_r_[PADR_(cloudabi_mprot_t)];
+ char flags_l_[PADL_(cloudabi_mflags_t)]; cloudabi_mflags_t flags; char flags_r_[PADR_(cloudabi_mflags_t)];
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char off_l_[PADL_(cloudabi_filesize_t)]; cloudabi_filesize_t off; char off_r_[PADR_(cloudabi_filesize_t)];
+};
+struct cloudabi_sys_mem_protect_args {
+ char mapping_l_[PADL_(void *)]; void * mapping; char mapping_r_[PADR_(void *)];
+ char mapping_len_l_[PADL_(size_t)]; size_t mapping_len; char mapping_len_r_[PADR_(size_t)];
+ char prot_l_[PADL_(cloudabi_mprot_t)]; cloudabi_mprot_t prot; char prot_r_[PADR_(cloudabi_mprot_t)];
+};
+struct cloudabi_sys_mem_sync_args {
+ char mapping_l_[PADL_(void *)]; void * mapping; char mapping_r_[PADR_(void *)];
+ char mapping_len_l_[PADL_(size_t)]; size_t mapping_len; char mapping_len_r_[PADR_(size_t)];
+ char flags_l_[PADL_(cloudabi_msflags_t)]; cloudabi_msflags_t flags; char flags_r_[PADR_(cloudabi_msflags_t)];
+};
+struct cloudabi_sys_mem_unmap_args {
+ char mapping_l_[PADL_(void *)]; void * mapping; char mapping_r_[PADR_(void *)];
+ char mapping_len_l_[PADL_(size_t)]; size_t mapping_len; char mapping_len_r_[PADR_(size_t)];
+};
+struct cloudabi64_sys_poll_args {
+ char in_l_[PADL_(const cloudabi64_subscription_t *)]; const cloudabi64_subscription_t * in; char in_r_[PADR_(const cloudabi64_subscription_t *)];
+ char out_l_[PADL_(cloudabi_event_t *)]; cloudabi_event_t * out; char out_r_[PADR_(cloudabi_event_t *)];
+ char nsubscriptions_l_[PADL_(size_t)]; size_t nsubscriptions; char nsubscriptions_r_[PADR_(size_t)];
+};
+struct cloudabi_sys_proc_exec_args {
+ char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char data_l_[PADL_(const void *)]; const void * data; char data_r_[PADR_(const void *)];
+ char data_len_l_[PADL_(size_t)]; size_t data_len; char data_len_r_[PADR_(size_t)];
+ char fds_l_[PADL_(const cloudabi_fd_t *)]; const cloudabi_fd_t * fds; char fds_r_[PADR_(const cloudabi_fd_t *)];
+ char fds_len_l_[PADL_(size_t)]; size_t fds_len; char fds_len_r_[PADR_(size_t)];
+};
+struct cloudabi_sys_proc_exit_args {
+ char rval_l_[PADL_(cloudabi_exitcode_t)]; cloudabi_exitcode_t rval; char rval_r_[PADR_(cloudabi_exitcode_t)];
+};
+struct cloudabi_sys_proc_fork_args {
+ register_t dummy;
+};
+struct cloudabi_sys_proc_raise_args {
+ char sig_l_[PADL_(cloudabi_signal_t)]; cloudabi_signal_t sig; char sig_r_[PADR_(cloudabi_signal_t)];
+};
+struct cloudabi_sys_random_get_args {
+ char buf_l_[PADL_(void *)]; void * buf; char buf_r_[PADR_(void *)];
+ char buf_len_l_[PADL_(size_t)]; size_t buf_len; char buf_len_r_[PADR_(size_t)];
+};
+struct cloudabi64_sys_sock_recv_args {
+ char sock_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t sock; char sock_r_[PADR_(cloudabi_fd_t)];
+ char in_l_[PADL_(const cloudabi64_recv_in_t *)]; const cloudabi64_recv_in_t * in; char in_r_[PADR_(const cloudabi64_recv_in_t *)];
+ char out_l_[PADL_(cloudabi64_recv_out_t *)]; cloudabi64_recv_out_t * out; char out_r_[PADR_(cloudabi64_recv_out_t *)];
+};
+struct cloudabi64_sys_sock_send_args {
+ char sock_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t sock; char sock_r_[PADR_(cloudabi_fd_t)];
+ char in_l_[PADL_(const cloudabi64_send_in_t *)]; const cloudabi64_send_in_t * in; char in_r_[PADR_(const cloudabi64_send_in_t *)];
+ char out_l_[PADL_(cloudabi64_send_out_t *)]; cloudabi64_send_out_t * out; char out_r_[PADR_(cloudabi64_send_out_t *)];
+};
+struct cloudabi_sys_sock_shutdown_args {
+ char sock_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t sock; char sock_r_[PADR_(cloudabi_fd_t)];
+ char how_l_[PADL_(cloudabi_sdflags_t)]; cloudabi_sdflags_t how; char how_r_[PADR_(cloudabi_sdflags_t)];
+};
+struct cloudabi64_sys_thread_create_args {
+ char attr_l_[PADL_(cloudabi64_threadattr_t *)]; cloudabi64_threadattr_t * attr; char attr_r_[PADR_(cloudabi64_threadattr_t *)];
+};
+struct cloudabi_sys_thread_exit_args {
+ char lock_l_[PADL_(cloudabi_lock_t *)]; cloudabi_lock_t * lock; char lock_r_[PADR_(cloudabi_lock_t *)];
+ char scope_l_[PADL_(cloudabi_scope_t)]; cloudabi_scope_t scope; char scope_r_[PADR_(cloudabi_scope_t)];
+};
+struct cloudabi_sys_thread_yield_args {
+ register_t dummy;
+};
+int cloudabi_sys_clock_res_get(struct thread *, struct cloudabi_sys_clock_res_get_args *);
+int cloudabi_sys_clock_time_get(struct thread *, struct cloudabi_sys_clock_time_get_args *);
+int cloudabi_sys_condvar_signal(struct thread *, struct cloudabi_sys_condvar_signal_args *);
+int cloudabi_sys_fd_close(struct thread *, struct cloudabi_sys_fd_close_args *);
+int cloudabi_sys_fd_create1(struct thread *, struct cloudabi_sys_fd_create1_args *);
+int cloudabi_sys_fd_create2(struct thread *, struct cloudabi_sys_fd_create2_args *);
+int cloudabi_sys_fd_datasync(struct thread *, struct cloudabi_sys_fd_datasync_args *);
+int cloudabi_sys_fd_dup(struct thread *, struct cloudabi_sys_fd_dup_args *);
+int cloudabi64_sys_fd_pread(struct thread *, struct cloudabi64_sys_fd_pread_args *);
+int cloudabi64_sys_fd_pwrite(struct thread *, struct cloudabi64_sys_fd_pwrite_args *);
+int cloudabi64_sys_fd_read(struct thread *, struct cloudabi64_sys_fd_read_args *);
+int cloudabi_sys_fd_replace(struct thread *, struct cloudabi_sys_fd_replace_args *);
+int cloudabi_sys_fd_seek(struct thread *, struct cloudabi_sys_fd_seek_args *);
+int cloudabi_sys_fd_stat_get(struct thread *, struct cloudabi_sys_fd_stat_get_args *);
+int cloudabi_sys_fd_stat_put(struct thread *, struct cloudabi_sys_fd_stat_put_args *);
+int cloudabi_sys_fd_sync(struct thread *, struct cloudabi_sys_fd_sync_args *);
+int cloudabi64_sys_fd_write(struct thread *, struct cloudabi64_sys_fd_write_args *);
+int cloudabi_sys_file_advise(struct thread *, struct cloudabi_sys_file_advise_args *);
+int cloudabi_sys_file_allocate(struct thread *, struct cloudabi_sys_file_allocate_args *);
+int cloudabi_sys_file_create(struct thread *, struct cloudabi_sys_file_create_args *);
+int cloudabi_sys_file_link(struct thread *, struct cloudabi_sys_file_link_args *);
+int cloudabi_sys_file_open(struct thread *, struct cloudabi_sys_file_open_args *);
+int cloudabi_sys_file_readdir(struct thread *, struct cloudabi_sys_file_readdir_args *);
+int cloudabi_sys_file_readlink(struct thread *, struct cloudabi_sys_file_readlink_args *);
+int cloudabi_sys_file_rename(struct thread *, struct cloudabi_sys_file_rename_args *);
+int cloudabi_sys_file_stat_fget(struct thread *, struct cloudabi_sys_file_stat_fget_args *);
+int cloudabi_sys_file_stat_fput(struct thread *, struct cloudabi_sys_file_stat_fput_args *);
+int cloudabi_sys_file_stat_get(struct thread *, struct cloudabi_sys_file_stat_get_args *);
+int cloudabi_sys_file_stat_put(struct thread *, struct cloudabi_sys_file_stat_put_args *);
+int cloudabi_sys_file_symlink(struct thread *, struct cloudabi_sys_file_symlink_args *);
+int cloudabi_sys_file_unlink(struct thread *, struct cloudabi_sys_file_unlink_args *);
+int cloudabi_sys_lock_unlock(struct thread *, struct cloudabi_sys_lock_unlock_args *);
+int cloudabi_sys_mem_advise(struct thread *, struct cloudabi_sys_mem_advise_args *);
+int cloudabi_sys_mem_map(struct thread *, struct cloudabi_sys_mem_map_args *);
+int cloudabi_sys_mem_protect(struct thread *, struct cloudabi_sys_mem_protect_args *);
+int cloudabi_sys_mem_sync(struct thread *, struct cloudabi_sys_mem_sync_args *);
+int cloudabi_sys_mem_unmap(struct thread *, struct cloudabi_sys_mem_unmap_args *);
+int cloudabi64_sys_poll(struct thread *, struct cloudabi64_sys_poll_args *);
+int cloudabi_sys_proc_exec(struct thread *, struct cloudabi_sys_proc_exec_args *);
+int cloudabi_sys_proc_exit(struct thread *, struct cloudabi_sys_proc_exit_args *);
+int cloudabi_sys_proc_fork(struct thread *, struct cloudabi_sys_proc_fork_args *);
+int cloudabi_sys_proc_raise(struct thread *, struct cloudabi_sys_proc_raise_args *);
+int cloudabi_sys_random_get(struct thread *, struct cloudabi_sys_random_get_args *);
+int cloudabi64_sys_sock_recv(struct thread *, struct cloudabi64_sys_sock_recv_args *);
+int cloudabi64_sys_sock_send(struct thread *, struct cloudabi64_sys_sock_send_args *);
+int cloudabi_sys_sock_shutdown(struct thread *, struct cloudabi_sys_sock_shutdown_args *);
+int cloudabi64_sys_thread_create(struct thread *, struct cloudabi64_sys_thread_create_args *);
+int cloudabi_sys_thread_exit(struct thread *, struct cloudabi_sys_thread_exit_args *);
+int cloudabi_sys_thread_yield(struct thread *, struct cloudabi_sys_thread_yield_args *);
+
+#ifdef COMPAT_43
+
+
+#endif /* COMPAT_43 */
+
+
+#ifdef COMPAT_FREEBSD4
+
+
+#endif /* COMPAT_FREEBSD4 */
+
+
+#ifdef COMPAT_FREEBSD6
+
+
+#endif /* COMPAT_FREEBSD6 */
+
+
+#ifdef COMPAT_FREEBSD7
+
+
+#endif /* COMPAT_FREEBSD7 */
+
+
+#ifdef COMPAT_FREEBSD10
+
+
+#endif /* COMPAT_FREEBSD10 */
+
+
+#ifdef COMPAT_FREEBSD11
+
+
+#endif /* COMPAT_FREEBSD11 */
+
+
+#ifdef COMPAT_FREEBSD12
+
+
+#endif /* COMPAT_FREEBSD12 */
+
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_clock_res_get AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_clock_time_get AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_condvar_signal AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_fd_close AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_fd_create1 AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_fd_create2 AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_fd_datasync AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_fd_dup AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi64_sys_fd_pread AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi64_sys_fd_pwrite AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi64_sys_fd_read AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_fd_replace AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_fd_seek AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_fd_stat_get AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_fd_stat_put AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_fd_sync AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi64_sys_fd_write AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_file_advise AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_file_allocate AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_file_create AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_file_link AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_file_open AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_file_readdir AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_file_readlink AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_file_rename AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_file_stat_fget AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_file_stat_fput AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_file_stat_get AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_file_stat_put AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_file_symlink AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_file_unlink AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_lock_unlock AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_mem_advise AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_mem_map AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_mem_protect AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_mem_sync AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_mem_unmap AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi64_sys_poll AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_proc_exec AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_proc_exit AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_proc_fork AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_proc_raise AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_random_get AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi64_sys_sock_recv AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi64_sys_sock_send AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_sock_shutdown AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi64_sys_thread_create AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_thread_exit AUE_NULL
+#define CLOUDABI64_SYS_AUE_cloudabi_sys_thread_yield AUE_NULL
+
+#undef PAD_
+#undef PADL_
+#undef PADR_
+
+#endif /* !_CLOUDABI64_SYSPROTO_H_ */
diff --git a/sys/compat/cloudabi64/cloudabi64_sock.c b/sys/compat/cloudabi64/cloudabi64_sock.c
new file mode 100644
index 000000000000..001adada384a
--- /dev/null
+++ b/sys/compat/cloudabi64/cloudabi64_sock.c
@@ -0,0 +1,128 @@
+/*-
+ * Copyright (c) 2015-2017 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
+
+#include <contrib/cloudabi/cloudabi64_types.h>
+
+#include <compat/cloudabi/cloudabi_util.h>
+
+#include <compat/cloudabi64/cloudabi64_proto.h>
+#include <compat/cloudabi64/cloudabi64_util.h>
+
+static MALLOC_DEFINE(M_SOCKET, "socket", "CloudABI socket");
+
+int
+cloudabi64_sys_sock_recv(struct thread *td,
+ struct cloudabi64_sys_sock_recv_args *uap)
+{
+ cloudabi64_recv_in_t ri;
+ cloudabi64_recv_out_t ro = {};
+ cloudabi64_iovec_t iovobj;
+ struct iovec *iov;
+ const cloudabi64_iovec_t *user_iov;
+ size_t i, rdatalen, rfdslen;
+ int error;
+
+ error = copyin(uap->in, &ri, sizeof(ri));
+ if (error != 0)
+ return (error);
+
+ /* Convert iovecs to native format. */
+ if (ri.ri_data_len > UIO_MAXIOV)
+ return (EINVAL);
+ iov = mallocarray(ri.ri_data_len, sizeof(struct iovec),
+ M_SOCKET, M_WAITOK);
+ user_iov = TO_PTR(ri.ri_data);
+ for (i = 0; i < ri.ri_data_len; i++) {
+ error = copyin(&user_iov[i], &iovobj, sizeof(iovobj));
+ if (error != 0) {
+ free(iov, M_SOCKET);
+ return (error);
+ }
+ iov[i].iov_base = TO_PTR(iovobj.buf);
+ iov[i].iov_len = iovobj.buf_len;
+ }
+
+ error = cloudabi_sock_recv(td, uap->sock, iov, ri.ri_data_len,
+ TO_PTR(ri.ri_fds), ri.ri_fds_len, ri.ri_flags, &rdatalen,
+ &rfdslen, &ro.ro_flags);
+ free(iov, M_SOCKET);
+ if (error != 0)
+ return (error);
+
+ ro.ro_datalen = rdatalen;
+ ro.ro_fdslen = rfdslen;
+ return (copyout(&ro, uap->out, sizeof(ro)));
+}
+
+int
+cloudabi64_sys_sock_send(struct thread *td,
+ struct cloudabi64_sys_sock_send_args *uap)
+{
+ cloudabi64_send_in_t si;
+ cloudabi64_send_out_t so = {};
+ cloudabi64_ciovec_t iovobj;
+ struct iovec *iov;
+ const cloudabi64_ciovec_t *user_iov;
+ size_t datalen, i;
+ int error;
+
+ error = copyin(uap->in, &si, sizeof(si));
+ if (error != 0)
+ return (error);
+
+ /* Convert iovecs to native format. */
+ if (si.si_data_len > UIO_MAXIOV)
+ return (EINVAL);
+ iov = mallocarray(si.si_data_len, sizeof(struct iovec),
+ M_SOCKET, M_WAITOK);
+ user_iov = TO_PTR(si.si_data);
+ for (i = 0; i < si.si_data_len; i++) {
+ error = copyin(&user_iov[i], &iovobj, sizeof(iovobj));
+ if (error != 0) {
+ free(iov, M_SOCKET);
+ return (error);
+ }
+ iov[i].iov_base = TO_PTR(iovobj.buf);
+ iov[i].iov_len = iovobj.buf_len;
+ }
+
+ error = cloudabi_sock_send(td, uap->sock, iov, si.si_data_len,
+ TO_PTR(si.si_fds), si.si_fds_len, &datalen);
+ free(iov, M_SOCKET);
+ if (error != 0)
+ return (error);
+
+ so.so_datalen = datalen;
+ return (copyout(&so, uap->out, sizeof(so)));
+}
diff --git a/sys/compat/cloudabi64/cloudabi64_syscall.h b/sys/compat/cloudabi64/cloudabi64_syscall.h
new file mode 100644
index 000000000000..9a3ba53797c6
--- /dev/null
+++ b/sys/compat/cloudabi64/cloudabi64_syscall.h
@@ -0,0 +1,57 @@
+/*
+ * System call numbers.
+ *
+ * DO NOT EDIT-- this file is automatically @generated.
+ * $FreeBSD$
+ */
+
+#define CLOUDABI64_SYS_cloudabi_sys_clock_res_get 0
+#define CLOUDABI64_SYS_cloudabi_sys_clock_time_get 1
+#define CLOUDABI64_SYS_cloudabi_sys_condvar_signal 2
+#define CLOUDABI64_SYS_cloudabi_sys_fd_close 3
+#define CLOUDABI64_SYS_cloudabi_sys_fd_create1 4
+#define CLOUDABI64_SYS_cloudabi_sys_fd_create2 5
+#define CLOUDABI64_SYS_cloudabi_sys_fd_datasync 6
+#define CLOUDABI64_SYS_cloudabi_sys_fd_dup 7
+#define CLOUDABI64_SYS_cloudabi64_sys_fd_pread 8
+#define CLOUDABI64_SYS_cloudabi64_sys_fd_pwrite 9
+#define CLOUDABI64_SYS_cloudabi64_sys_fd_read 10
+#define CLOUDABI64_SYS_cloudabi_sys_fd_replace 11
+#define CLOUDABI64_SYS_cloudabi_sys_fd_seek 12
+#define CLOUDABI64_SYS_cloudabi_sys_fd_stat_get 13
+#define CLOUDABI64_SYS_cloudabi_sys_fd_stat_put 14
+#define CLOUDABI64_SYS_cloudabi_sys_fd_sync 15
+#define CLOUDABI64_SYS_cloudabi64_sys_fd_write 16
+#define CLOUDABI64_SYS_cloudabi_sys_file_advise 17
+#define CLOUDABI64_SYS_cloudabi_sys_file_allocate 18
+#define CLOUDABI64_SYS_cloudabi_sys_file_create 19
+#define CLOUDABI64_SYS_cloudabi_sys_file_link 20
+#define CLOUDABI64_SYS_cloudabi_sys_file_open 21
+#define CLOUDABI64_SYS_cloudabi_sys_file_readdir 22
+#define CLOUDABI64_SYS_cloudabi_sys_file_readlink 23
+#define CLOUDABI64_SYS_cloudabi_sys_file_rename 24
+#define CLOUDABI64_SYS_cloudabi_sys_file_stat_fget 25
+#define CLOUDABI64_SYS_cloudabi_sys_file_stat_fput 26
+#define CLOUDABI64_SYS_cloudabi_sys_file_stat_get 27
+#define CLOUDABI64_SYS_cloudabi_sys_file_stat_put 28
+#define CLOUDABI64_SYS_cloudabi_sys_file_symlink 29
+#define CLOUDABI64_SYS_cloudabi_sys_file_unlink 30
+#define CLOUDABI64_SYS_cloudabi_sys_lock_unlock 31
+#define CLOUDABI64_SYS_cloudabi_sys_mem_advise 32
+#define CLOUDABI64_SYS_cloudabi_sys_mem_map 33
+#define CLOUDABI64_SYS_cloudabi_sys_mem_protect 34
+#define CLOUDABI64_SYS_cloudabi_sys_mem_sync 35
+#define CLOUDABI64_SYS_cloudabi_sys_mem_unmap 36
+#define CLOUDABI64_SYS_cloudabi64_sys_poll 37
+#define CLOUDABI64_SYS_cloudabi_sys_proc_exec 38
+#define CLOUDABI64_SYS_cloudabi_sys_proc_exit 39
+#define CLOUDABI64_SYS_cloudabi_sys_proc_fork 40
+#define CLOUDABI64_SYS_cloudabi_sys_proc_raise 41
+#define CLOUDABI64_SYS_cloudabi_sys_random_get 42
+#define CLOUDABI64_SYS_cloudabi64_sys_sock_recv 43
+#define CLOUDABI64_SYS_cloudabi64_sys_sock_send 44
+#define CLOUDABI64_SYS_cloudabi_sys_sock_shutdown 45
+#define CLOUDABI64_SYS_cloudabi64_sys_thread_create 46
+#define CLOUDABI64_SYS_cloudabi_sys_thread_exit 47
+#define CLOUDABI64_SYS_cloudabi_sys_thread_yield 48
+#define CLOUDABI64_SYS_MAXSYSCALL 49
diff --git a/sys/compat/cloudabi64/cloudabi64_syscalls.c b/sys/compat/cloudabi64/cloudabi64_syscalls.c
new file mode 100644
index 000000000000..5019ad930d52
--- /dev/null
+++ b/sys/compat/cloudabi64/cloudabi64_syscalls.c
@@ -0,0 +1,58 @@
+/*
+ * System call names.
+ *
+ * DO NOT EDIT-- this file is automatically @generated.
+ * $FreeBSD$
+ */
+
+const char *cloudabi64_syscallnames[] = {
+ "cloudabi_sys_clock_res_get", /* 0 = cloudabi_sys_clock_res_get */
+ "cloudabi_sys_clock_time_get", /* 1 = cloudabi_sys_clock_time_get */
+ "cloudabi_sys_condvar_signal", /* 2 = cloudabi_sys_condvar_signal */
+ "cloudabi_sys_fd_close", /* 3 = cloudabi_sys_fd_close */
+ "cloudabi_sys_fd_create1", /* 4 = cloudabi_sys_fd_create1 */
+ "cloudabi_sys_fd_create2", /* 5 = cloudabi_sys_fd_create2 */
+ "cloudabi_sys_fd_datasync", /* 6 = cloudabi_sys_fd_datasync */
+ "cloudabi_sys_fd_dup", /* 7 = cloudabi_sys_fd_dup */
+ "cloudabi64_sys_fd_pread", /* 8 = cloudabi64_sys_fd_pread */
+ "cloudabi64_sys_fd_pwrite", /* 9 = cloudabi64_sys_fd_pwrite */
+ "cloudabi64_sys_fd_read", /* 10 = cloudabi64_sys_fd_read */
+ "cloudabi_sys_fd_replace", /* 11 = cloudabi_sys_fd_replace */
+ "cloudabi_sys_fd_seek", /* 12 = cloudabi_sys_fd_seek */
+ "cloudabi_sys_fd_stat_get", /* 13 = cloudabi_sys_fd_stat_get */
+ "cloudabi_sys_fd_stat_put", /* 14 = cloudabi_sys_fd_stat_put */
+ "cloudabi_sys_fd_sync", /* 15 = cloudabi_sys_fd_sync */
+ "cloudabi64_sys_fd_write", /* 16 = cloudabi64_sys_fd_write */
+ "cloudabi_sys_file_advise", /* 17 = cloudabi_sys_file_advise */
+ "cloudabi_sys_file_allocate", /* 18 = cloudabi_sys_file_allocate */
+ "cloudabi_sys_file_create", /* 19 = cloudabi_sys_file_create */
+ "cloudabi_sys_file_link", /* 20 = cloudabi_sys_file_link */
+ "cloudabi_sys_file_open", /* 21 = cloudabi_sys_file_open */
+ "cloudabi_sys_file_readdir", /* 22 = cloudabi_sys_file_readdir */
+ "cloudabi_sys_file_readlink", /* 23 = cloudabi_sys_file_readlink */
+ "cloudabi_sys_file_rename", /* 24 = cloudabi_sys_file_rename */
+ "cloudabi_sys_file_stat_fget", /* 25 = cloudabi_sys_file_stat_fget */
+ "cloudabi_sys_file_stat_fput", /* 26 = cloudabi_sys_file_stat_fput */
+ "cloudabi_sys_file_stat_get", /* 27 = cloudabi_sys_file_stat_get */
+ "cloudabi_sys_file_stat_put", /* 28 = cloudabi_sys_file_stat_put */
+ "cloudabi_sys_file_symlink", /* 29 = cloudabi_sys_file_symlink */
+ "cloudabi_sys_file_unlink", /* 30 = cloudabi_sys_file_unlink */
+ "cloudabi_sys_lock_unlock", /* 31 = cloudabi_sys_lock_unlock */
+ "cloudabi_sys_mem_advise", /* 32 = cloudabi_sys_mem_advise */
+ "cloudabi_sys_mem_map", /* 33 = cloudabi_sys_mem_map */
+ "cloudabi_sys_mem_protect", /* 34 = cloudabi_sys_mem_protect */
+ "cloudabi_sys_mem_sync", /* 35 = cloudabi_sys_mem_sync */
+ "cloudabi_sys_mem_unmap", /* 36 = cloudabi_sys_mem_unmap */
+ "cloudabi64_sys_poll", /* 37 = cloudabi64_sys_poll */
+ "cloudabi_sys_proc_exec", /* 38 = cloudabi_sys_proc_exec */
+ "cloudabi_sys_proc_exit", /* 39 = cloudabi_sys_proc_exit */
+ "cloudabi_sys_proc_fork", /* 40 = cloudabi_sys_proc_fork */
+ "cloudabi_sys_proc_raise", /* 41 = cloudabi_sys_proc_raise */
+ "cloudabi_sys_random_get", /* 42 = cloudabi_sys_random_get */
+ "cloudabi64_sys_sock_recv", /* 43 = cloudabi64_sys_sock_recv */
+ "cloudabi64_sys_sock_send", /* 44 = cloudabi64_sys_sock_send */
+ "cloudabi_sys_sock_shutdown", /* 45 = cloudabi_sys_sock_shutdown */
+ "cloudabi64_sys_thread_create", /* 46 = cloudabi64_sys_thread_create */
+ "cloudabi_sys_thread_exit", /* 47 = cloudabi_sys_thread_exit */
+ "cloudabi_sys_thread_yield", /* 48 = cloudabi_sys_thread_yield */
+};
diff --git a/sys/compat/cloudabi64/cloudabi64_sysent.c b/sys/compat/cloudabi64/cloudabi64_sysent.c
new file mode 100644
index 000000000000..1edae8bb8281
--- /dev/null
+++ b/sys/compat/cloudabi64/cloudabi64_sysent.c
@@ -0,0 +1,66 @@
+/*
+ * System call switch table.
+ *
+ * DO NOT EDIT-- this file is automatically @generated.
+ * $FreeBSD$
+ */
+
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <contrib/cloudabi/cloudabi64_types.h>
+#include <compat/cloudabi64/cloudabi64_proto.h>
+
+#define AS(name) (sizeof(struct name) / sizeof(register_t))
+
+/* The casts are bogus but will do for now. */
+struct sysent cloudabi64_sysent[] = {
+ { .sy_narg = AS(cloudabi_sys_clock_res_get_args), .sy_call = (sy_call_t *)cloudabi_sys_clock_res_get, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 0 = cloudabi_sys_clock_res_get */
+ { .sy_narg = AS(cloudabi_sys_clock_time_get_args), .sy_call = (sy_call_t *)cloudabi_sys_clock_time_get, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 1 = cloudabi_sys_clock_time_get */
+ { .sy_narg = AS(cloudabi_sys_condvar_signal_args), .sy_call = (sy_call_t *)cloudabi_sys_condvar_signal, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 2 = cloudabi_sys_condvar_signal */
+ { .sy_narg = AS(cloudabi_sys_fd_close_args), .sy_call = (sy_call_t *)cloudabi_sys_fd_close, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 3 = cloudabi_sys_fd_close */
+ { .sy_narg = AS(cloudabi_sys_fd_create1_args), .sy_call = (sy_call_t *)cloudabi_sys_fd_create1, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 4 = cloudabi_sys_fd_create1 */
+ { .sy_narg = AS(cloudabi_sys_fd_create2_args), .sy_call = (sy_call_t *)cloudabi_sys_fd_create2, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 5 = cloudabi_sys_fd_create2 */
+ { .sy_narg = AS(cloudabi_sys_fd_datasync_args), .sy_call = (sy_call_t *)cloudabi_sys_fd_datasync, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 6 = cloudabi_sys_fd_datasync */
+ { .sy_narg = AS(cloudabi_sys_fd_dup_args), .sy_call = (sy_call_t *)cloudabi_sys_fd_dup, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 7 = cloudabi_sys_fd_dup */
+ { .sy_narg = AS(cloudabi64_sys_fd_pread_args), .sy_call = (sy_call_t *)cloudabi64_sys_fd_pread, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 8 = cloudabi64_sys_fd_pread */
+ { .sy_narg = AS(cloudabi64_sys_fd_pwrite_args), .sy_call = (sy_call_t *)cloudabi64_sys_fd_pwrite, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 9 = cloudabi64_sys_fd_pwrite */
+ { .sy_narg = AS(cloudabi64_sys_fd_read_args), .sy_call = (sy_call_t *)cloudabi64_sys_fd_read, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 10 = cloudabi64_sys_fd_read */
+ { .sy_narg = AS(cloudabi_sys_fd_replace_args), .sy_call = (sy_call_t *)cloudabi_sys_fd_replace, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 11 = cloudabi_sys_fd_replace */
+ { .sy_narg = AS(cloudabi_sys_fd_seek_args), .sy_call = (sy_call_t *)cloudabi_sys_fd_seek, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 12 = cloudabi_sys_fd_seek */
+ { .sy_narg = AS(cloudabi_sys_fd_stat_get_args), .sy_call = (sy_call_t *)cloudabi_sys_fd_stat_get, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 13 = cloudabi_sys_fd_stat_get */
+ { .sy_narg = AS(cloudabi_sys_fd_stat_put_args), .sy_call = (sy_call_t *)cloudabi_sys_fd_stat_put, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 14 = cloudabi_sys_fd_stat_put */
+ { .sy_narg = AS(cloudabi_sys_fd_sync_args), .sy_call = (sy_call_t *)cloudabi_sys_fd_sync, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 15 = cloudabi_sys_fd_sync */
+ { .sy_narg = AS(cloudabi64_sys_fd_write_args), .sy_call = (sy_call_t *)cloudabi64_sys_fd_write, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 16 = cloudabi64_sys_fd_write */
+ { .sy_narg = AS(cloudabi_sys_file_advise_args), .sy_call = (sy_call_t *)cloudabi_sys_file_advise, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 17 = cloudabi_sys_file_advise */
+ { .sy_narg = AS(cloudabi_sys_file_allocate_args), .sy_call = (sy_call_t *)cloudabi_sys_file_allocate, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 18 = cloudabi_sys_file_allocate */
+ { .sy_narg = AS(cloudabi_sys_file_create_args), .sy_call = (sy_call_t *)cloudabi_sys_file_create, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 19 = cloudabi_sys_file_create */
+ { .sy_narg = AS(cloudabi_sys_file_link_args), .sy_call = (sy_call_t *)cloudabi_sys_file_link, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 20 = cloudabi_sys_file_link */
+ { .sy_narg = AS(cloudabi_sys_file_open_args), .sy_call = (sy_call_t *)cloudabi_sys_file_open, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 21 = cloudabi_sys_file_open */
+ { .sy_narg = AS(cloudabi_sys_file_readdir_args), .sy_call = (sy_call_t *)cloudabi_sys_file_readdir, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 22 = cloudabi_sys_file_readdir */
+ { .sy_narg = AS(cloudabi_sys_file_readlink_args), .sy_call = (sy_call_t *)cloudabi_sys_file_readlink, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 23 = cloudabi_sys_file_readlink */
+ { .sy_narg = AS(cloudabi_sys_file_rename_args), .sy_call = (sy_call_t *)cloudabi_sys_file_rename, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 24 = cloudabi_sys_file_rename */
+ { .sy_narg = AS(cloudabi_sys_file_stat_fget_args), .sy_call = (sy_call_t *)cloudabi_sys_file_stat_fget, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 25 = cloudabi_sys_file_stat_fget */
+ { .sy_narg = AS(cloudabi_sys_file_stat_fput_args), .sy_call = (sy_call_t *)cloudabi_sys_file_stat_fput, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 26 = cloudabi_sys_file_stat_fput */
+ { .sy_narg = AS(cloudabi_sys_file_stat_get_args), .sy_call = (sy_call_t *)cloudabi_sys_file_stat_get, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 27 = cloudabi_sys_file_stat_get */
+ { .sy_narg = AS(cloudabi_sys_file_stat_put_args), .sy_call = (sy_call_t *)cloudabi_sys_file_stat_put, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 28 = cloudabi_sys_file_stat_put */
+ { .sy_narg = AS(cloudabi_sys_file_symlink_args), .sy_call = (sy_call_t *)cloudabi_sys_file_symlink, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 29 = cloudabi_sys_file_symlink */
+ { .sy_narg = AS(cloudabi_sys_file_unlink_args), .sy_call = (sy_call_t *)cloudabi_sys_file_unlink, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 30 = cloudabi_sys_file_unlink */
+ { .sy_narg = AS(cloudabi_sys_lock_unlock_args), .sy_call = (sy_call_t *)cloudabi_sys_lock_unlock, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 31 = cloudabi_sys_lock_unlock */
+ { .sy_narg = AS(cloudabi_sys_mem_advise_args), .sy_call = (sy_call_t *)cloudabi_sys_mem_advise, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 32 = cloudabi_sys_mem_advise */
+ { .sy_narg = AS(cloudabi_sys_mem_map_args), .sy_call = (sy_call_t *)cloudabi_sys_mem_map, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 33 = cloudabi_sys_mem_map */
+ { .sy_narg = AS(cloudabi_sys_mem_protect_args), .sy_call = (sy_call_t *)cloudabi_sys_mem_protect, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 34 = cloudabi_sys_mem_protect */
+ { .sy_narg = AS(cloudabi_sys_mem_sync_args), .sy_call = (sy_call_t *)cloudabi_sys_mem_sync, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 35 = cloudabi_sys_mem_sync */
+ { .sy_narg = AS(cloudabi_sys_mem_unmap_args), .sy_call = (sy_call_t *)cloudabi_sys_mem_unmap, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 36 = cloudabi_sys_mem_unmap */
+ { .sy_narg = AS(cloudabi64_sys_poll_args), .sy_call = (sy_call_t *)cloudabi64_sys_poll, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 37 = cloudabi64_sys_poll */
+ { .sy_narg = AS(cloudabi_sys_proc_exec_args), .sy_call = (sy_call_t *)cloudabi_sys_proc_exec, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 38 = cloudabi_sys_proc_exec */
+ { .sy_narg = AS(cloudabi_sys_proc_exit_args), .sy_call = (sy_call_t *)cloudabi_sys_proc_exit, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 39 = cloudabi_sys_proc_exit */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)cloudabi_sys_proc_fork, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 40 = cloudabi_sys_proc_fork */
+ { .sy_narg = AS(cloudabi_sys_proc_raise_args), .sy_call = (sy_call_t *)cloudabi_sys_proc_raise, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 41 = cloudabi_sys_proc_raise */
+ { .sy_narg = AS(cloudabi_sys_random_get_args), .sy_call = (sy_call_t *)cloudabi_sys_random_get, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 42 = cloudabi_sys_random_get */
+ { .sy_narg = AS(cloudabi64_sys_sock_recv_args), .sy_call = (sy_call_t *)cloudabi64_sys_sock_recv, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 43 = cloudabi64_sys_sock_recv */
+ { .sy_narg = AS(cloudabi64_sys_sock_send_args), .sy_call = (sy_call_t *)cloudabi64_sys_sock_send, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 44 = cloudabi64_sys_sock_send */
+ { .sy_narg = AS(cloudabi_sys_sock_shutdown_args), .sy_call = (sy_call_t *)cloudabi_sys_sock_shutdown, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 45 = cloudabi_sys_sock_shutdown */
+ { .sy_narg = AS(cloudabi64_sys_thread_create_args), .sy_call = (sy_call_t *)cloudabi64_sys_thread_create, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 46 = cloudabi64_sys_thread_create */
+ { .sy_narg = AS(cloudabi_sys_thread_exit_args), .sy_call = (sy_call_t *)cloudabi_sys_thread_exit, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 47 = cloudabi_sys_thread_exit */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)cloudabi_sys_thread_yield, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 48 = cloudabi_sys_thread_yield */
+};
diff --git a/sys/compat/cloudabi64/cloudabi64_systrace_args.c b/sys/compat/cloudabi64/cloudabi64_systrace_args.c
new file mode 100644
index 000000000000..fbb24daa5723
--- /dev/null
+++ b/sys/compat/cloudabi64/cloudabi64_systrace_args.c
@@ -0,0 +1,1458 @@
+/*
+ * System call argument to DTrace register array converstion.
+ *
+ * DO NOT EDIT-- this file is automatically @generated.
+ * $FreeBSD$
+ * This file is part of the DTrace syscall provider.
+ */
+
+static void
+systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
+{
+ int64_t *iarg = (int64_t *) uarg;
+ switch (sysnum) {
+ /* cloudabi_sys_clock_res_get */
+ case 0: {
+ struct cloudabi_sys_clock_res_get_args *p = params;
+ iarg[0] = p->clock_id; /* cloudabi_clockid_t */
+ *n_args = 1;
+ break;
+ }
+ /* cloudabi_sys_clock_time_get */
+ case 1: {
+ struct cloudabi_sys_clock_time_get_args *p = params;
+ iarg[0] = p->clock_id; /* cloudabi_clockid_t */
+ iarg[1] = p->precision; /* cloudabi_timestamp_t */
+ *n_args = 2;
+ break;
+ }
+ /* cloudabi_sys_condvar_signal */
+ case 2: {
+ struct cloudabi_sys_condvar_signal_args *p = params;
+ uarg[0] = (intptr_t) p->condvar; /* cloudabi_condvar_t * */
+ iarg[1] = p->scope; /* cloudabi_scope_t */
+ iarg[2] = p->nwaiters; /* cloudabi_nthreads_t */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi_sys_fd_close */
+ case 3: {
+ struct cloudabi_sys_fd_close_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ *n_args = 1;
+ break;
+ }
+ /* cloudabi_sys_fd_create1 */
+ case 4: {
+ struct cloudabi_sys_fd_create1_args *p = params;
+ iarg[0] = p->type; /* cloudabi_filetype_t */
+ *n_args = 1;
+ break;
+ }
+ /* cloudabi_sys_fd_create2 */
+ case 5: {
+ struct cloudabi_sys_fd_create2_args *p = params;
+ iarg[0] = p->type; /* cloudabi_filetype_t */
+ *n_args = 1;
+ break;
+ }
+ /* cloudabi_sys_fd_datasync */
+ case 6: {
+ struct cloudabi_sys_fd_datasync_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ *n_args = 1;
+ break;
+ }
+ /* cloudabi_sys_fd_dup */
+ case 7: {
+ struct cloudabi_sys_fd_dup_args *p = params;
+ iarg[0] = p->from; /* cloudabi_fd_t */
+ *n_args = 1;
+ break;
+ }
+ /* cloudabi64_sys_fd_pread */
+ case 8: {
+ struct cloudabi64_sys_fd_pread_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->iovs; /* const cloudabi64_iovec_t * */
+ uarg[2] = p->iovs_len; /* size_t */
+ iarg[3] = p->offset; /* cloudabi_filesize_t */
+ *n_args = 4;
+ break;
+ }
+ /* cloudabi64_sys_fd_pwrite */
+ case 9: {
+ struct cloudabi64_sys_fd_pwrite_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->iovs; /* const cloudabi64_ciovec_t * */
+ uarg[2] = p->iovs_len; /* size_t */
+ iarg[3] = p->offset; /* cloudabi_filesize_t */
+ *n_args = 4;
+ break;
+ }
+ /* cloudabi64_sys_fd_read */
+ case 10: {
+ struct cloudabi64_sys_fd_read_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->iovs; /* const cloudabi64_iovec_t * */
+ uarg[2] = p->iovs_len; /* size_t */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi_sys_fd_replace */
+ case 11: {
+ struct cloudabi_sys_fd_replace_args *p = params;
+ iarg[0] = p->from; /* cloudabi_fd_t */
+ iarg[1] = p->to; /* cloudabi_fd_t */
+ *n_args = 2;
+ break;
+ }
+ /* cloudabi_sys_fd_seek */
+ case 12: {
+ struct cloudabi_sys_fd_seek_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ iarg[1] = p->offset; /* cloudabi_filedelta_t */
+ iarg[2] = p->whence; /* cloudabi_whence_t */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi_sys_fd_stat_get */
+ case 13: {
+ struct cloudabi_sys_fd_stat_get_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->buf; /* cloudabi_fdstat_t * */
+ *n_args = 2;
+ break;
+ }
+ /* cloudabi_sys_fd_stat_put */
+ case 14: {
+ struct cloudabi_sys_fd_stat_put_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->buf; /* const cloudabi_fdstat_t * */
+ iarg[2] = p->flags; /* cloudabi_fdsflags_t */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi_sys_fd_sync */
+ case 15: {
+ struct cloudabi_sys_fd_sync_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ *n_args = 1;
+ break;
+ }
+ /* cloudabi64_sys_fd_write */
+ case 16: {
+ struct cloudabi64_sys_fd_write_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->iovs; /* const cloudabi64_ciovec_t * */
+ uarg[2] = p->iovs_len; /* size_t */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi_sys_file_advise */
+ case 17: {
+ struct cloudabi_sys_file_advise_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ iarg[1] = p->offset; /* cloudabi_filesize_t */
+ iarg[2] = p->len; /* cloudabi_filesize_t */
+ iarg[3] = p->advice; /* cloudabi_advice_t */
+ *n_args = 4;
+ break;
+ }
+ /* cloudabi_sys_file_allocate */
+ case 18: {
+ struct cloudabi_sys_file_allocate_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ iarg[1] = p->offset; /* cloudabi_filesize_t */
+ iarg[2] = p->len; /* cloudabi_filesize_t */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi_sys_file_create */
+ case 19: {
+ struct cloudabi_sys_file_create_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ uarg[2] = p->path_len; /* size_t */
+ iarg[3] = p->type; /* cloudabi_filetype_t */
+ *n_args = 4;
+ break;
+ }
+ /* cloudabi_sys_file_link */
+ case 20: {
+ struct cloudabi_sys_file_link_args *p = params;
+ iarg[0] = p->fd1; /* cloudabi_lookup_t */
+ uarg[1] = (intptr_t) p->path1; /* const char * */
+ uarg[2] = p->path1_len; /* size_t */
+ iarg[3] = p->fd2; /* cloudabi_fd_t */
+ uarg[4] = (intptr_t) p->path2; /* const char * */
+ uarg[5] = p->path2_len; /* size_t */
+ *n_args = 6;
+ break;
+ }
+ /* cloudabi_sys_file_open */
+ case 21: {
+ struct cloudabi_sys_file_open_args *p = params;
+ iarg[0] = p->dirfd; /* cloudabi_lookup_t */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ uarg[2] = p->path_len; /* size_t */
+ iarg[3] = p->oflags; /* cloudabi_oflags_t */
+ uarg[4] = (intptr_t) p->fds; /* const cloudabi_fdstat_t * */
+ *n_args = 5;
+ break;
+ }
+ /* cloudabi_sys_file_readdir */
+ case 22: {
+ struct cloudabi_sys_file_readdir_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->buf; /* void * */
+ uarg[2] = p->buf_len; /* size_t */
+ iarg[3] = p->cookie; /* cloudabi_dircookie_t */
+ *n_args = 4;
+ break;
+ }
+ /* cloudabi_sys_file_readlink */
+ case 23: {
+ struct cloudabi_sys_file_readlink_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ uarg[2] = p->path_len; /* size_t */
+ uarg[3] = (intptr_t) p->buf; /* char * */
+ uarg[4] = p->buf_len; /* size_t */
+ *n_args = 5;
+ break;
+ }
+ /* cloudabi_sys_file_rename */
+ case 24: {
+ struct cloudabi_sys_file_rename_args *p = params;
+ iarg[0] = p->fd1; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->path1; /* const char * */
+ uarg[2] = p->path1_len; /* size_t */
+ iarg[3] = p->fd2; /* cloudabi_fd_t */
+ uarg[4] = (intptr_t) p->path2; /* const char * */
+ uarg[5] = p->path2_len; /* size_t */
+ *n_args = 6;
+ break;
+ }
+ /* cloudabi_sys_file_stat_fget */
+ case 25: {
+ struct cloudabi_sys_file_stat_fget_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->buf; /* cloudabi_filestat_t * */
+ *n_args = 2;
+ break;
+ }
+ /* cloudabi_sys_file_stat_fput */
+ case 26: {
+ struct cloudabi_sys_file_stat_fput_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->buf; /* const cloudabi_filestat_t * */
+ iarg[2] = p->flags; /* cloudabi_fsflags_t */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi_sys_file_stat_get */
+ case 27: {
+ struct cloudabi_sys_file_stat_get_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_lookup_t */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ uarg[2] = p->path_len; /* size_t */
+ uarg[3] = (intptr_t) p->buf; /* cloudabi_filestat_t * */
+ *n_args = 4;
+ break;
+ }
+ /* cloudabi_sys_file_stat_put */
+ case 28: {
+ struct cloudabi_sys_file_stat_put_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_lookup_t */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ uarg[2] = p->path_len; /* size_t */
+ uarg[3] = (intptr_t) p->buf; /* const cloudabi_filestat_t * */
+ iarg[4] = p->flags; /* cloudabi_fsflags_t */
+ *n_args = 5;
+ break;
+ }
+ /* cloudabi_sys_file_symlink */
+ case 29: {
+ struct cloudabi_sys_file_symlink_args *p = params;
+ uarg[0] = (intptr_t) p->path1; /* const char * */
+ uarg[1] = p->path1_len; /* size_t */
+ iarg[2] = p->fd; /* cloudabi_fd_t */
+ uarg[3] = (intptr_t) p->path2; /* const char * */
+ uarg[4] = p->path2_len; /* size_t */
+ *n_args = 5;
+ break;
+ }
+ /* cloudabi_sys_file_unlink */
+ case 30: {
+ struct cloudabi_sys_file_unlink_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ uarg[2] = p->path_len; /* size_t */
+ iarg[3] = p->flags; /* cloudabi_ulflags_t */
+ *n_args = 4;
+ break;
+ }
+ /* cloudabi_sys_lock_unlock */
+ case 31: {
+ struct cloudabi_sys_lock_unlock_args *p = params;
+ uarg[0] = (intptr_t) p->lock; /* cloudabi_lock_t * */
+ iarg[1] = p->scope; /* cloudabi_scope_t */
+ *n_args = 2;
+ break;
+ }
+ /* cloudabi_sys_mem_advise */
+ case 32: {
+ struct cloudabi_sys_mem_advise_args *p = params;
+ uarg[0] = (intptr_t) p->mapping; /* void * */
+ uarg[1] = p->mapping_len; /* size_t */
+ iarg[2] = p->advice; /* cloudabi_advice_t */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi_sys_mem_map */
+ case 33: {
+ struct cloudabi_sys_mem_map_args *p = params;
+ uarg[0] = (intptr_t) p->addr; /* void * */
+ uarg[1] = p->len; /* size_t */
+ iarg[2] = p->prot; /* cloudabi_mprot_t */
+ iarg[3] = p->flags; /* cloudabi_mflags_t */
+ iarg[4] = p->fd; /* cloudabi_fd_t */
+ iarg[5] = p->off; /* cloudabi_filesize_t */
+ *n_args = 6;
+ break;
+ }
+ /* cloudabi_sys_mem_protect */
+ case 34: {
+ struct cloudabi_sys_mem_protect_args *p = params;
+ uarg[0] = (intptr_t) p->mapping; /* void * */
+ uarg[1] = p->mapping_len; /* size_t */
+ iarg[2] = p->prot; /* cloudabi_mprot_t */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi_sys_mem_sync */
+ case 35: {
+ struct cloudabi_sys_mem_sync_args *p = params;
+ uarg[0] = (intptr_t) p->mapping; /* void * */
+ uarg[1] = p->mapping_len; /* size_t */
+ iarg[2] = p->flags; /* cloudabi_msflags_t */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi_sys_mem_unmap */
+ case 36: {
+ struct cloudabi_sys_mem_unmap_args *p = params;
+ uarg[0] = (intptr_t) p->mapping; /* void * */
+ uarg[1] = p->mapping_len; /* size_t */
+ *n_args = 2;
+ break;
+ }
+ /* cloudabi64_sys_poll */
+ case 37: {
+ struct cloudabi64_sys_poll_args *p = params;
+ uarg[0] = (intptr_t) p->in; /* const cloudabi64_subscription_t * */
+ uarg[1] = (intptr_t) p->out; /* cloudabi_event_t * */
+ uarg[2] = p->nsubscriptions; /* size_t */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi_sys_proc_exec */
+ case 38: {
+ struct cloudabi_sys_proc_exec_args *p = params;
+ iarg[0] = p->fd; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->data; /* const void * */
+ uarg[2] = p->data_len; /* size_t */
+ uarg[3] = (intptr_t) p->fds; /* const cloudabi_fd_t * */
+ uarg[4] = p->fds_len; /* size_t */
+ *n_args = 5;
+ break;
+ }
+ /* cloudabi_sys_proc_exit */
+ case 39: {
+ struct cloudabi_sys_proc_exit_args *p = params;
+ iarg[0] = p->rval; /* cloudabi_exitcode_t */
+ *n_args = 1;
+ break;
+ }
+ /* cloudabi_sys_proc_fork */
+ case 40: {
+ *n_args = 0;
+ break;
+ }
+ /* cloudabi_sys_proc_raise */
+ case 41: {
+ struct cloudabi_sys_proc_raise_args *p = params;
+ iarg[0] = p->sig; /* cloudabi_signal_t */
+ *n_args = 1;
+ break;
+ }
+ /* cloudabi_sys_random_get */
+ case 42: {
+ struct cloudabi_sys_random_get_args *p = params;
+ uarg[0] = (intptr_t) p->buf; /* void * */
+ uarg[1] = p->buf_len; /* size_t */
+ *n_args = 2;
+ break;
+ }
+ /* cloudabi64_sys_sock_recv */
+ case 43: {
+ struct cloudabi64_sys_sock_recv_args *p = params;
+ iarg[0] = p->sock; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->in; /* const cloudabi64_recv_in_t * */
+ uarg[2] = (intptr_t) p->out; /* cloudabi64_recv_out_t * */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi64_sys_sock_send */
+ case 44: {
+ struct cloudabi64_sys_sock_send_args *p = params;
+ iarg[0] = p->sock; /* cloudabi_fd_t */
+ uarg[1] = (intptr_t) p->in; /* const cloudabi64_send_in_t * */
+ uarg[2] = (intptr_t) p->out; /* cloudabi64_send_out_t * */
+ *n_args = 3;
+ break;
+ }
+ /* cloudabi_sys_sock_shutdown */
+ case 45: {
+ struct cloudabi_sys_sock_shutdown_args *p = params;
+ iarg[0] = p->sock; /* cloudabi_fd_t */
+ iarg[1] = p->how; /* cloudabi_sdflags_t */
+ *n_args = 2;
+ break;
+ }
+ /* cloudabi64_sys_thread_create */
+ case 46: {
+ struct cloudabi64_sys_thread_create_args *p = params;
+ uarg[0] = (intptr_t) p->attr; /* cloudabi64_threadattr_t * */
+ *n_args = 1;
+ break;
+ }
+ /* cloudabi_sys_thread_exit */
+ case 47: {
+ struct cloudabi_sys_thread_exit_args *p = params;
+ uarg[0] = (intptr_t) p->lock; /* cloudabi_lock_t * */
+ iarg[1] = p->scope; /* cloudabi_scope_t */
+ *n_args = 2;
+ break;
+ }
+ /* cloudabi_sys_thread_yield */
+ case 48: {
+ *n_args = 0;
+ break;
+ }
+ default:
+ *n_args = 0;
+ break;
+ };
+}
+static void
+systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
+{
+ const char *p = NULL;
+ switch (sysnum) {
+ /* cloudabi_sys_clock_res_get */
+ case 0:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_clockid_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_clock_time_get */
+ case 1:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_clockid_t";
+ break;
+ case 1:
+ p = "cloudabi_timestamp_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_condvar_signal */
+ case 2:
+ switch(ndx) {
+ case 0:
+ p = "userland cloudabi_condvar_t *";
+ break;
+ case 1:
+ p = "cloudabi_scope_t";
+ break;
+ case 2:
+ p = "cloudabi_nthreads_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_fd_close */
+ case 3:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_fd_create1 */
+ case 4:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_filetype_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_fd_create2 */
+ case 5:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_filetype_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_fd_datasync */
+ case 6:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_fd_dup */
+ case 7:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi64_sys_fd_pread */
+ case 8:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const cloudabi64_iovec_t *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "cloudabi_filesize_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi64_sys_fd_pwrite */
+ case 9:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const cloudabi64_ciovec_t *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "cloudabi_filesize_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi64_sys_fd_read */
+ case 10:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const cloudabi64_iovec_t *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_fd_replace */
+ case 11:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "cloudabi_fd_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_fd_seek */
+ case 12:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "cloudabi_filedelta_t";
+ break;
+ case 2:
+ p = "cloudabi_whence_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_fd_stat_get */
+ case 13:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland cloudabi_fdstat_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_fd_stat_put */
+ case 14:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const cloudabi_fdstat_t *";
+ break;
+ case 2:
+ p = "cloudabi_fdsflags_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_fd_sync */
+ case 15:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi64_sys_fd_write */
+ case 16:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const cloudabi64_ciovec_t *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_advise */
+ case 17:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "cloudabi_filesize_t";
+ break;
+ case 2:
+ p = "cloudabi_filesize_t";
+ break;
+ case 3:
+ p = "cloudabi_advice_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_allocate */
+ case 18:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "cloudabi_filesize_t";
+ break;
+ case 2:
+ p = "cloudabi_filesize_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_create */
+ case 19:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "cloudabi_filetype_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_link */
+ case 20:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_lookup_t";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "cloudabi_fd_t";
+ break;
+ case 4:
+ p = "userland const char *";
+ break;
+ case 5:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_open */
+ case 21:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_lookup_t";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "cloudabi_oflags_t";
+ break;
+ case 4:
+ p = "userland const cloudabi_fdstat_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_readdir */
+ case 22:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland void *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "cloudabi_dircookie_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_readlink */
+ case 23:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "userland char *";
+ break;
+ case 4:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_rename */
+ case 24:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "cloudabi_fd_t";
+ break;
+ case 4:
+ p = "userland const char *";
+ break;
+ case 5:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_stat_fget */
+ case 25:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland cloudabi_filestat_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_stat_fput */
+ case 26:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const cloudabi_filestat_t *";
+ break;
+ case 2:
+ p = "cloudabi_fsflags_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_stat_get */
+ case 27:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_lookup_t";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "userland cloudabi_filestat_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_stat_put */
+ case 28:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_lookup_t";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "userland const cloudabi_filestat_t *";
+ break;
+ case 4:
+ p = "cloudabi_fsflags_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_symlink */
+ case 29:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "cloudabi_fd_t";
+ break;
+ case 3:
+ p = "userland const char *";
+ break;
+ case 4:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_file_unlink */
+ case 30:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "cloudabi_ulflags_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_lock_unlock */
+ case 31:
+ switch(ndx) {
+ case 0:
+ p = "userland cloudabi_lock_t *";
+ break;
+ case 1:
+ p = "cloudabi_scope_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_mem_advise */
+ case 32:
+ switch(ndx) {
+ case 0:
+ p = "userland void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "cloudabi_advice_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_mem_map */
+ case 33:
+ switch(ndx) {
+ case 0:
+ p = "userland void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "cloudabi_mprot_t";
+ break;
+ case 3:
+ p = "cloudabi_mflags_t";
+ break;
+ case 4:
+ p = "cloudabi_fd_t";
+ break;
+ case 5:
+ p = "cloudabi_filesize_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_mem_protect */
+ case 34:
+ switch(ndx) {
+ case 0:
+ p = "userland void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "cloudabi_mprot_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_mem_sync */
+ case 35:
+ switch(ndx) {
+ case 0:
+ p = "userland void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "cloudabi_msflags_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_mem_unmap */
+ case 36:
+ switch(ndx) {
+ case 0:
+ p = "userland void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi64_sys_poll */
+ case 37:
+ switch(ndx) {
+ case 0:
+ p = "userland const cloudabi64_subscription_t *";
+ break;
+ case 1:
+ p = "userland cloudabi_event_t *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_proc_exec */
+ case 38:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const void *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "userland const cloudabi_fd_t *";
+ break;
+ case 4:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_proc_exit */
+ case 39:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_exitcode_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_proc_fork */
+ case 40:
+ break;
+ /* cloudabi_sys_proc_raise */
+ case 41:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_signal_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_random_get */
+ case 42:
+ switch(ndx) {
+ case 0:
+ p = "userland void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi64_sys_sock_recv */
+ case 43:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const cloudabi64_recv_in_t *";
+ break;
+ case 2:
+ p = "userland cloudabi64_recv_out_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi64_sys_sock_send */
+ case 44:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "userland const cloudabi64_send_in_t *";
+ break;
+ case 2:
+ p = "userland cloudabi64_send_out_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_sock_shutdown */
+ case 45:
+ switch(ndx) {
+ case 0:
+ p = "cloudabi_fd_t";
+ break;
+ case 1:
+ p = "cloudabi_sdflags_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi64_sys_thread_create */
+ case 46:
+ switch(ndx) {
+ case 0:
+ p = "userland cloudabi64_threadattr_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_thread_exit */
+ case 47:
+ switch(ndx) {
+ case 0:
+ p = "userland cloudabi_lock_t *";
+ break;
+ case 1:
+ p = "cloudabi_scope_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cloudabi_sys_thread_yield */
+ case 48:
+ break;
+ default:
+ break;
+ };
+ if (p != NULL)
+ strlcpy(desc, p, descsz);
+}
+static void
+systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
+{
+ const char *p = NULL;
+ switch (sysnum) {
+ /* cloudabi_sys_clock_res_get */
+ case 0:
+ if (ndx == 0 || ndx == 1)
+ p = "cloudabi_timestamp_t";
+ break;
+ /* cloudabi_sys_clock_time_get */
+ case 1:
+ if (ndx == 0 || ndx == 1)
+ p = "cloudabi_timestamp_t";
+ break;
+ /* cloudabi_sys_condvar_signal */
+ case 2:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_fd_close */
+ case 3:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_fd_create1 */
+ case 4:
+ if (ndx == 0 || ndx == 1)
+ p = "cloudabi_fd_t";
+ break;
+ /* cloudabi_sys_fd_create2 */
+ case 5:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_fd_datasync */
+ case 6:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_fd_dup */
+ case 7:
+ if (ndx == 0 || ndx == 1)
+ p = "cloudabi_fd_t";
+ break;
+ /* cloudabi64_sys_fd_pread */
+ case 8:
+ if (ndx == 0 || ndx == 1)
+ p = "size_t";
+ break;
+ /* cloudabi64_sys_fd_pwrite */
+ case 9:
+ if (ndx == 0 || ndx == 1)
+ p = "size_t";
+ break;
+ /* cloudabi64_sys_fd_read */
+ case 10:
+ if (ndx == 0 || ndx == 1)
+ p = "size_t";
+ break;
+ /* cloudabi_sys_fd_replace */
+ case 11:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_fd_seek */
+ case 12:
+ if (ndx == 0 || ndx == 1)
+ p = "cloudabi_filesize_t";
+ break;
+ /* cloudabi_sys_fd_stat_get */
+ case 13:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_fd_stat_put */
+ case 14:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_fd_sync */
+ case 15:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi64_sys_fd_write */
+ case 16:
+ if (ndx == 0 || ndx == 1)
+ p = "size_t";
+ break;
+ /* cloudabi_sys_file_advise */
+ case 17:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_file_allocate */
+ case 18:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_file_create */
+ case 19:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_file_link */
+ case 20:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_file_open */
+ case 21:
+ if (ndx == 0 || ndx == 1)
+ p = "cloudabi_fd_t";
+ break;
+ /* cloudabi_sys_file_readdir */
+ case 22:
+ if (ndx == 0 || ndx == 1)
+ p = "size_t";
+ break;
+ /* cloudabi_sys_file_readlink */
+ case 23:
+ if (ndx == 0 || ndx == 1)
+ p = "size_t";
+ break;
+ /* cloudabi_sys_file_rename */
+ case 24:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_file_stat_fget */
+ case 25:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_file_stat_fput */
+ case 26:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_file_stat_get */
+ case 27:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_file_stat_put */
+ case 28:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_file_symlink */
+ case 29:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_file_unlink */
+ case 30:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_lock_unlock */
+ case 31:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_mem_advise */
+ case 32:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_mem_map */
+ case 33:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_mem_protect */
+ case 34:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_mem_sync */
+ case 35:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_mem_unmap */
+ case 36:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi64_sys_poll */
+ case 37:
+ if (ndx == 0 || ndx == 1)
+ p = "size_t";
+ break;
+ /* cloudabi_sys_proc_exec */
+ case 38:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_proc_exit */
+ case 39:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_proc_fork */
+ case 40:
+ /* cloudabi_sys_proc_raise */
+ case 41:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_random_get */
+ case 42:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi64_sys_sock_recv */
+ case 43:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi64_sys_sock_send */
+ case 44:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_sock_shutdown */
+ case 45:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi64_sys_thread_create */
+ case 46:
+ if (ndx == 0 || ndx == 1)
+ p = "cloudabi_tid_t";
+ break;
+ /* cloudabi_sys_thread_exit */
+ case 47:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* cloudabi_sys_thread_yield */
+ case 48:
+ default:
+ break;
+ };
+ if (p != NULL)
+ strlcpy(desc, p, descsz);
+}
diff --git a/sys/compat/cloudabi64/cloudabi64_thread.c b/sys/compat/cloudabi64/cloudabi64_thread.c
new file mode 100644
index 000000000000..4cb980b1530d
--- /dev/null
+++ b/sys/compat/cloudabi64/cloudabi64_thread.c
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+
+#include <contrib/cloudabi/cloudabi64_types.h>
+
+#include <compat/cloudabi64/cloudabi64_proto.h>
+#include <compat/cloudabi64/cloudabi64_util.h>
+
+struct thread_create_args {
+ cloudabi64_threadattr_t attr;
+ uint64_t tcb;
+ lwpid_t tid;
+};
+
+static int
+initialize_thread(struct thread *td, void *thunk)
+{
+ struct thread_create_args *args = thunk;
+
+ /* Save the thread ID, so it can be returned. */
+ args->tid = td->td_tid;
+
+ /* Set up initial register contents. */
+ return (cloudabi64_thread_setregs(td, &args->attr, args->tcb));
+}
+
+int
+cloudabi64_sys_thread_create(struct thread *td,
+ struct cloudabi64_sys_thread_create_args *uap)
+{
+ struct thread_create_args args;
+ int error;
+
+ error = copyin(uap->attr, &args.attr, sizeof(args.attr));
+ if (error != 0)
+ return (error);
+
+ /* Remove some space on the top of the stack for the TCB. */
+ args.tcb = rounddown(args.attr.stack + args.attr.stack_len -
+ sizeof(cloudabi64_tcb_t), _Alignof(cloudabi64_tcb_t));
+ args.attr.stack_len = args.tcb - args.attr.stack;
+
+ error = thread_create(td, NULL, initialize_thread, &args);
+ if (error != 0)
+ return (error);
+ td->td_retval[0] = args.tid;
+ return (0);
+}
diff --git a/sys/compat/cloudabi64/cloudabi64_util.h b/sys/compat/cloudabi64/cloudabi64_util.h
new file mode 100644
index 000000000000..27088392c75a
--- /dev/null
+++ b/sys/compat/cloudabi64/cloudabi64_util.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _CLOUDABI64_UTIL_H_
+#define _CLOUDABI64_UTIL_H_
+
+#include <sys/types.h>
+#define __ELF_WORD_SIZE 64
+#include <sys/imgact_elf.h>
+
+#include <contrib/cloudabi/cloudabi64_types.h>
+
+struct image_params;
+struct thread;
+
+extern Elf64_Brandinfo cloudabi64_brand;
+
+#define TO_PTR(x) ((void *)(uintptr_t)(x))
+
+/* Stack initialization during process execution. */
+int cloudabi64_copyout_strings(struct image_params *, uintptr_t *);
+int cloudabi64_fixup(uintptr_t *, struct image_params *);
+
+int cloudabi64_thread_setregs(struct thread *,
+ const cloudabi64_threadattr_t *, uint64_t);
+
+#endif
diff --git a/sys/compat/cloudabi64/syscalls.conf b/sys/compat/cloudabi64/syscalls.conf
new file mode 100644
index 000000000000..6b75dbb85d40
--- /dev/null
+++ b/sys/compat/cloudabi64/syscalls.conf
@@ -0,0 +1,15 @@
+# $FreeBSD$
+sysnames="cloudabi64_syscalls.c"
+sysproto="cloudabi64_proto.h"
+sysproto_h=_CLOUDABI64_SYSPROTO_H_
+syshdr="cloudabi64_syscall.h"
+syssw="cloudabi64_sysent.c"
+sysmk="/dev/null"
+syscallprefix="CLOUDABI64_SYS_"
+switchname="cloudabi64_sysent"
+namesname="cloudabi64_syscallnames"
+systrace="cloudabi64_systrace_args.c"
+
+# Allow all system calls in capabilities mode. Extract the names of the
+# system calls from syscalls.master.
+capenabled=`sed -n -e 's/.*\<\(cloudabi[0-9]*_sys_[a-z0-9_]*\)\>.*/\1/p' $1 | tr '\n' ','`
diff --git a/sys/compat/freebsd32/Makefile b/sys/compat/freebsd32/Makefile
new file mode 100644
index 000000000000..b0c5b818e1ee
--- /dev/null
+++ b/sys/compat/freebsd32/Makefile
@@ -0,0 +1,7 @@
+# Makefile for syscall tables
+#
+# $FreeBSD$
+
+GENERATED_PREFIX= freebsd32_
+
+.include "../../conf/sysent.mk"
diff --git a/sys/compat/freebsd32/freebsd32.h b/sys/compat/freebsd32/freebsd32.h
new file mode 100644
index 000000000000..4227d9037afb
--- /dev/null
+++ b/sys/compat/freebsd32/freebsd32.h
@@ -0,0 +1,432 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2001 Doug Rabson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _COMPAT_FREEBSD32_FREEBSD32_H_
+#define _COMPAT_FREEBSD32_FREEBSD32_H_
+
+#include <sys/abi_compat.h>
+#include <sys/procfs.h>
+#include <sys/socket.h>
+#include <sys/user.h>
+
+/*
+ * i386 is the only arch with a 32-bit time_t
+ */
+#ifdef __amd64__
+typedef int32_t time32_t;
+#else
+typedef int64_t time32_t;
+#endif
+
+struct timeval32 {
+ time32_t tv_sec;
+ int32_t tv_usec;
+};
+
+struct timespec32 {
+ time32_t tv_sec;
+ int32_t tv_nsec;
+};
+
+struct itimerspec32 {
+ struct timespec32 it_interval;
+ struct timespec32 it_value;
+};
+
+struct bintime32 {
+ time32_t sec;
+ uint32_t frac[2];
+};
+
+struct rusage32 {
+ struct timeval32 ru_utime;
+ struct timeval32 ru_stime;
+ int32_t ru_maxrss;
+ int32_t ru_ixrss;
+ int32_t ru_idrss;
+ int32_t ru_isrss;
+ int32_t ru_minflt;
+ int32_t ru_majflt;
+ int32_t ru_nswap;
+ int32_t ru_inblock;
+ int32_t ru_oublock;
+ int32_t ru_msgsnd;
+ int32_t ru_msgrcv;
+ int32_t ru_nsignals;
+ int32_t ru_nvcsw;
+ int32_t ru_nivcsw;
+};
+
+struct wrusage32 {
+ struct rusage32 wru_self;
+ struct rusage32 wru_children;
+};
+
+struct itimerval32 {
+ struct timeval32 it_interval;
+ struct timeval32 it_value;
+};
+
+struct umtx_time32 {
+ struct timespec32 _timeout;
+ uint32_t _flags;
+ uint32_t _clockid;
+};
+
+struct umtx_robust_lists_params_compat32 {
+ uint32_t robust_list_offset;
+ uint32_t robust_priv_list_offset;
+ uint32_t robust_inact_offset;
+};
+
+struct umutex32 {
+ volatile __lwpid_t m_owner; /* Owner of the mutex */
+ __uint32_t m_flags; /* Flags of the mutex */
+ __uint32_t m_ceilings[2]; /* Priority protect ceiling */
+ __uint32_t m_rb_lnk; /* Robust linkage */
+ __uint32_t m_pad;
+ __uint32_t m_spare[2];
+};
+
+#define FREEBSD4_MFSNAMELEN 16
+#define FREEBSD4_MNAMELEN (88 - 2 * sizeof(int32_t))
+
+/* 4.x version */
+struct statfs32 {
+ int32_t f_spare2;
+ int32_t f_bsize;
+ int32_t f_iosize;
+ int32_t f_blocks;
+ int32_t f_bfree;
+ int32_t f_bavail;
+ int32_t f_files;
+ int32_t f_ffree;
+ fsid_t f_fsid;
+ uid_t f_owner;
+ int32_t f_type;
+ int32_t f_flags;
+ int32_t f_syncwrites;
+ int32_t f_asyncwrites;
+ char f_fstypename[FREEBSD4_MFSNAMELEN];
+ char f_mntonname[FREEBSD4_MNAMELEN];
+ int32_t f_syncreads;
+ int32_t f_asyncreads;
+ int16_t f_spares1;
+ char f_mntfromname[FREEBSD4_MNAMELEN];
+ int16_t f_spares2 __packed;
+ int32_t f_spare[2];
+};
+
+struct iovec32 {
+ u_int32_t iov_base;
+ int iov_len;
+};
+
+struct msghdr32 {
+ u_int32_t msg_name;
+ socklen_t msg_namelen;
+ u_int32_t msg_iov;
+ int msg_iovlen;
+ u_int32_t msg_control;
+ socklen_t msg_controllen;
+ int msg_flags;
+};
+
+#if defined(__amd64__)
+#define __STAT32_TIME_T_EXT 1
+#endif
+
+struct stat32 {
+ dev_t st_dev;
+ ino_t st_ino;
+ nlink_t st_nlink;
+ mode_t st_mode;
+ u_int16_t st_padding0;
+ uid_t st_uid;
+ gid_t st_gid;
+ u_int32_t st_padding1;
+ dev_t st_rdev;
+#ifdef __STAT32_TIME_T_EXT
+ __int32_t st_atim_ext;
+#endif
+ struct timespec32 st_atim;
+#ifdef __STAT32_TIME_T_EXT
+ __int32_t st_mtim_ext;
+#endif
+ struct timespec32 st_mtim;
+#ifdef __STAT32_TIME_T_EXT
+ __int32_t st_ctim_ext;
+#endif
+ struct timespec32 st_ctim;
+#ifdef __STAT32_TIME_T_EXT
+ __int32_t st_btim_ext;
+#endif
+ struct timespec32 st_birthtim;
+ off_t st_size;
+ int64_t st_blocks;
+ u_int32_t st_blksize;
+ u_int32_t st_flags;
+ u_int64_t st_gen;
+ u_int64_t st_spare[10];
+};
+struct freebsd11_stat32 {
+ u_int32_t st_dev;
+ u_int32_t st_ino;
+ mode_t st_mode;
+ u_int16_t st_nlink;
+ uid_t st_uid;
+ gid_t st_gid;
+ u_int32_t st_rdev;
+ struct timespec32 st_atim;
+ struct timespec32 st_mtim;
+ struct timespec32 st_ctim;
+ off_t st_size;
+ int64_t st_blocks;
+ u_int32_t st_blksize;
+ u_int32_t st_flags;
+ u_int32_t st_gen;
+ int32_t st_lspare;
+ struct timespec32 st_birthtim;
+ unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec32));
+ unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec32));
+};
+
+struct ostat32 {
+ __uint16_t st_dev;
+ __uint32_t st_ino;
+ mode_t st_mode;
+ __uint16_t st_nlink;
+ __uint16_t st_uid;
+ __uint16_t st_gid;
+ __uint16_t st_rdev;
+ __int32_t st_size;
+ struct timespec32 st_atim;
+ struct timespec32 st_mtim;
+ struct timespec32 st_ctim;
+ __int32_t st_blksize;
+ __int32_t st_blocks;
+ u_int32_t st_flags;
+ __uint32_t st_gen;
+};
+
+struct jail32_v0 {
+ u_int32_t version;
+ uint32_t path;
+ uint32_t hostname;
+ u_int32_t ip_number;
+};
+
+struct jail32 {
+ uint32_t version;
+ uint32_t path;
+ uint32_t hostname;
+ uint32_t jailname;
+ uint32_t ip4s;
+ uint32_t ip6s;
+ uint32_t ip4;
+ uint32_t ip6;
+};
+
+struct sigaction32 {
+ u_int32_t sa_u;
+ int sa_flags;
+ sigset_t sa_mask;
+};
+
+struct thr_param32 {
+ uint32_t start_func;
+ uint32_t arg;
+ uint32_t stack_base;
+ uint32_t stack_size;
+ uint32_t tls_base;
+ uint32_t tls_size;
+ uint32_t child_tid;
+ uint32_t parent_tid;
+ int32_t flags;
+ uint32_t rtp;
+ uint32_t spare[3];
+};
+
+struct i386_ldt_args32 {
+ uint32_t start;
+ uint32_t descs;
+ uint32_t num;
+};
+
+struct mq_attr32 {
+ int mq_flags;
+ int mq_maxmsg;
+ int mq_msgsize;
+ int mq_curmsgs;
+ int __reserved[4];
+};
+
+struct kinfo_proc32 {
+ int ki_structsize;
+ int ki_layout;
+ uint32_t ki_args;
+ uint32_t ki_paddr;
+ uint32_t ki_addr;
+ uint32_t ki_tracep;
+ uint32_t ki_textvp;
+ uint32_t ki_fd;
+ uint32_t ki_vmspace;
+ uint32_t ki_wchan;
+ pid_t ki_pid;
+ pid_t ki_ppid;
+ pid_t ki_pgid;
+ pid_t ki_tpgid;
+ pid_t ki_sid;
+ pid_t ki_tsid;
+ short ki_jobc;
+ short ki_spare_short1;
+ uint32_t ki_tdev_freebsd11;
+ sigset_t ki_siglist;
+ sigset_t ki_sigmask;
+ sigset_t ki_sigignore;
+ sigset_t ki_sigcatch;
+ uid_t ki_uid;
+ uid_t ki_ruid;
+ uid_t ki_svuid;
+ gid_t ki_rgid;
+ gid_t ki_svgid;
+ short ki_ngroups;
+ short ki_spare_short2;
+ gid_t ki_groups[KI_NGROUPS];
+ uint32_t ki_size;
+ int32_t ki_rssize;
+ int32_t ki_swrss;
+ int32_t ki_tsize;
+ int32_t ki_dsize;
+ int32_t ki_ssize;
+ u_short ki_xstat;
+ u_short ki_acflag;
+ fixpt_t ki_pctcpu;
+ u_int ki_estcpu;
+ u_int ki_slptime;
+ u_int ki_swtime;
+ u_int ki_cow;
+ u_int64_t ki_runtime;
+ struct timeval32 ki_start;
+ struct timeval32 ki_childtime;
+ int ki_flag;
+ int ki_kiflag;
+ int ki_traceflag;
+ char ki_stat;
+ signed char ki_nice;
+ char ki_lock;
+ char ki_rqindex;
+ u_char ki_oncpu_old;
+ u_char ki_lastcpu_old;
+ char ki_tdname[TDNAMLEN+1];
+ char ki_wmesg[WMESGLEN+1];
+ char ki_login[LOGNAMELEN+1];
+ char ki_lockname[LOCKNAMELEN+1];
+ char ki_comm[COMMLEN+1];
+ char ki_emul[KI_EMULNAMELEN+1];
+ char ki_loginclass[LOGINCLASSLEN+1];
+ char ki_moretdname[MAXCOMLEN-TDNAMLEN+1];
+ char ki_sparestrings[46];
+ int ki_spareints[KI_NSPARE_INT];
+ uint64_t ki_tdev;
+ int ki_oncpu;
+ int ki_lastcpu;
+ int ki_tracer;
+ int ki_flag2;
+ int ki_fibnum;
+ u_int ki_cr_flags;
+ int ki_jid;
+ int ki_numthreads;
+ lwpid_t ki_tid;
+ struct priority ki_pri;
+ struct rusage32 ki_rusage;
+ struct rusage32 ki_rusage_ch;
+ uint32_t ki_pcb;
+ uint32_t ki_kstack;
+ uint32_t ki_udata;
+ uint32_t ki_tdaddr;
+ uint32_t ki_spareptrs[KI_NSPARE_PTR]; /* spare room for growth */
+ int ki_sparelongs[KI_NSPARE_LONG];
+ int ki_sflag;
+ int ki_tdflags;
+};
+
+struct kinfo_sigtramp32 {
+ uint32_t ksigtramp_start;
+ uint32_t ksigtramp_end;
+ uint32_t ksigtramp_spare[4];
+};
+
+struct kld32_file_stat_1 {
+ int version; /* set to sizeof(struct kld_file_stat_1) */
+ char name[MAXPATHLEN];
+ int refs;
+ int id;
+ uint32_t address; /* load address */
+ uint32_t size; /* size in bytes */
+};
+
+struct kld32_file_stat {
+ int version; /* set to sizeof(struct kld_file_stat) */
+ char name[MAXPATHLEN];
+ int refs;
+ int id;
+ uint32_t address; /* load address */
+ uint32_t size; /* size in bytes */
+ char pathname[MAXPATHLEN];
+};
+
+struct procctl_reaper_pids32 {
+ u_int rp_count;
+ u_int rp_pad0[15];
+ uint32_t rp_pids;
+};
+
+struct timex32 {
+ unsigned int modes;
+ int32_t offset;
+ int32_t freq;
+ int32_t maxerror;
+ int32_t esterror;
+ int status;
+ int32_t constant;
+ int32_t precision;
+ int32_t tolerance;
+ int32_t ppsfreq;
+ int32_t jitter;
+ int shift;
+ int32_t stabil;
+ int32_t jitcnt;
+ int32_t calcnt;
+ int32_t errcnt;
+ int32_t stbcnt;
+};
+
+#endif /* !_COMPAT_FREEBSD32_FREEBSD32_H_ */
diff --git a/sys/compat/freebsd32/freebsd32_capability.c b/sys/compat/freebsd32/freebsd32_capability.c
new file mode 100644
index 000000000000..9a39b4f4cd71
--- /dev/null
+++ b/sys/compat/freebsd32/freebsd32_capability.c
@@ -0,0 +1,157 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_capsicum.h"
+
+#include <sys/param.h>
+#include <sys/capsicum.h>
+#include <sys/filedesc.h>
+#include <sys/limits.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysproto.h>
+
+#include <security/audit/audit.h>
+
+#include <compat/freebsd32/freebsd32_proto.h>
+
+#ifdef CAPABILITIES
+
+MALLOC_DECLARE(M_FILECAPS);
+
+int
+freebsd32_cap_ioctls_limit(struct thread *td,
+ struct freebsd32_cap_ioctls_limit_args *uap)
+{
+ u_long *cmds;
+ uint32_t *cmds32;
+ size_t ncmds;
+ u_int i;
+ int error;
+
+ ncmds = uap->ncmds;
+
+ if (ncmds > 256) /* XXX: Is 256 sane? */
+ return (EINVAL);
+
+ if (ncmds == 0) {
+ cmds = NULL;
+ } else {
+ cmds32 = malloc(sizeof(cmds32[0]) * ncmds, M_FILECAPS, M_WAITOK);
+ error = copyin(uap->cmds, cmds32, sizeof(cmds32[0]) * ncmds);
+ if (error != 0) {
+ free(cmds32, M_FILECAPS);
+ return (error);
+ }
+ cmds = malloc(sizeof(cmds[0]) * ncmds, M_FILECAPS, M_WAITOK);
+ for (i = 0; i < ncmds; i++)
+ cmds[i] = cmds32[i];
+ free(cmds32, M_FILECAPS);
+ }
+
+ return (kern_cap_ioctls_limit(td, uap->fd, cmds, ncmds));
+}
+
+int
+freebsd32_cap_ioctls_get(struct thread *td,
+ struct freebsd32_cap_ioctls_get_args *uap)
+{
+ struct filedesc *fdp;
+ struct filedescent *fdep;
+ uint32_t *cmds32;
+ u_long *cmds;
+ size_t maxcmds;
+ int error, fd;
+ u_int i;
+
+ fd = uap->fd;
+ cmds32 = uap->cmds;
+ maxcmds = uap->maxcmds;
+
+ AUDIT_ARG_FD(fd);
+
+ fdp = td->td_proc->p_fd;
+ FILEDESC_SLOCK(fdp);
+
+ if (fget_locked(fdp, fd) == NULL) {
+ error = EBADF;
+ goto out;
+ }
+
+ /*
+ * If all ioctls are allowed (fde_nioctls == -1 && fde_ioctls == NULL)
+ * the only sane thing we can do is to not populate the given array and
+ * return CAP_IOCTLS_ALL (actually, INT_MAX).
+ */
+
+ fdep = &fdp->fd_ofiles[fd];
+ cmds = fdep->fde_ioctls;
+ if (cmds32 != NULL && cmds != NULL) {
+ for (i = 0; i < MIN(fdep->fde_nioctls, maxcmds); i++) {
+ error = suword32(&cmds32[i], cmds[i]);
+ if (error != 0)
+ goto out;
+ }
+ }
+ if (fdep->fde_nioctls == -1)
+ td->td_retval[0] = INT_MAX;
+ else
+ td->td_retval[0] = fdep->fde_nioctls;
+
+ error = 0;
+out:
+ FILEDESC_SUNLOCK(fdp);
+ return (error);
+}
+
+#else /* !CAPABILITIES */
+
+int
+freebsd32_cap_ioctls_limit(struct thread *td,
+ struct freebsd32_cap_ioctls_limit_args *uap)
+{
+
+ return (ENOSYS);
+}
+
+int
+freebsd32_cap_ioctls_get(struct thread *td,
+ struct freebsd32_cap_ioctls_get_args *uap)
+{
+
+ return (ENOSYS);
+}
+
+#endif /* CAPABILITIES */
diff --git a/sys/compat/freebsd32/freebsd32_ioctl.c b/sys/compat/freebsd32/freebsd32_ioctl.c
new file mode 100644
index 000000000000..b3ed457f7132
--- /dev/null
+++ b/sys/compat/freebsd32/freebsd32_ioctl.c
@@ -0,0 +1,247 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2008 David E. O'Brien
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/capsicum.h>
+#include <sys/cdio.h>
+#include <sys/fcntl.h>
+#include <sys/filio.h>
+#include <sys/file.h>
+#include <sys/ioccom.h>
+#include <sys/malloc.h>
+#include <sys/memrange.h>
+#include <sys/pciio.h>
+#include <sys/proc.h>
+#include <sys/syscall.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysctl.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
+
+#include <compat/freebsd32/freebsd32.h>
+#include <compat/freebsd32/freebsd32_ioctl.h>
+#include <compat/freebsd32/freebsd32_misc.h>
+#include <compat/freebsd32/freebsd32_proto.h>
+
+CTASSERT(sizeof(struct mem_range_op32) == 12);
+
+static int
+freebsd32_ioctl_memrange(struct thread *td,
+ struct freebsd32_ioctl_args *uap, struct file *fp)
+{
+ struct mem_range_op mro;
+ struct mem_range_op32 mro32;
+ int error;
+ u_long com;
+
+ if ((error = copyin(uap->data, &mro32, sizeof(mro32))) != 0)
+ return (error);
+
+ PTRIN_CP(mro32, mro, mo_desc);
+ CP(mro32, mro, mo_arg[0]);
+ CP(mro32, mro, mo_arg[1]);
+
+ com = 0;
+ switch (uap->com) {
+ case MEMRANGE_GET32:
+ com = MEMRANGE_GET;
+ break;
+
+ case MEMRANGE_SET32:
+ com = MEMRANGE_SET;
+ break;
+
+ default:
+ panic("%s: unknown MEMRANGE %#x", __func__, uap->com);
+ }
+
+ if ((error = fo_ioctl(fp, com, (caddr_t)&mro, td->td_ucred, td)) != 0)
+ return (error);
+
+ if ( (com & IOC_OUT) ) {
+ CP(mro, mro32, mo_arg[0]);
+ CP(mro, mro32, mo_arg[1]);
+
+ error = copyout(&mro32, uap->data, sizeof(mro32));
+ }
+
+ return (error);
+}
+
+static int
+freebsd32_ioctl_barmmap(struct thread *td,
+ struct freebsd32_ioctl_args *uap, struct file *fp)
+{
+ struct pci_bar_mmap32 pbm32;
+ struct pci_bar_mmap pbm;
+ int error;
+
+ error = copyin(uap->data, &pbm32, sizeof(pbm32));
+ if (error != 0)
+ return (error);
+ PTRIN_CP(pbm32, pbm, pbm_map_base);
+ CP(pbm32, pbm, pbm_sel);
+ CP(pbm32, pbm, pbm_reg);
+ CP(pbm32, pbm, pbm_flags);
+ CP(pbm32, pbm, pbm_memattr);
+ pbm.pbm_bar_length = PAIR32TO64(uint64_t, pbm32.pbm_bar_length);
+ error = fo_ioctl(fp, PCIOCBARMMAP, (caddr_t)&pbm, td->td_ucred, td);
+ if (error == 0) {
+ PTROUT_CP(pbm, pbm32, pbm_map_base);
+ CP(pbm, pbm32, pbm_map_length);
+#if BYTE_ORDER == LITTLE_ENDIAN
+ pbm32.pbm_bar_length1 = pbm.pbm_bar_length;
+ pbm32.pbm_bar_length2 = pbm.pbm_bar_length >> 32;
+#else
+ pbm32.pbm_bar_length1 = pbm.pbm_bar_length >> 32;
+ pbm32.pbm_bar_length2 = pbm.pbm_bar_length;
+#endif
+ CP(pbm, pbm32, pbm_bar_off);
+ error = copyout(&pbm32, uap->data, sizeof(pbm32));
+ }
+ return (error);
+}
+
+static int
+freebsd32_ioctl_sg(struct thread *td,
+ struct freebsd32_ioctl_args *uap, struct file *fp)
+{
+ struct sg_io_hdr io;
+ struct sg_io_hdr32 io32;
+ int error;
+
+ if ((error = copyin(uap->data, &io32, sizeof(io32))) != 0)
+ return (error);
+
+ CP(io32, io, interface_id);
+ CP(io32, io, dxfer_direction);
+ CP(io32, io, cmd_len);
+ CP(io32, io, mx_sb_len);
+ CP(io32, io, iovec_count);
+ CP(io32, io, dxfer_len);
+ PTRIN_CP(io32, io, dxferp);
+ PTRIN_CP(io32, io, cmdp);
+ PTRIN_CP(io32, io, sbp);
+ CP(io32, io, timeout);
+ CP(io32, io, flags);
+ CP(io32, io, pack_id);
+ PTRIN_CP(io32, io, usr_ptr);
+ CP(io32, io, status);
+ CP(io32, io, masked_status);
+ CP(io32, io, msg_status);
+ CP(io32, io, sb_len_wr);
+ CP(io32, io, host_status);
+ CP(io32, io, driver_status);
+ CP(io32, io, resid);
+ CP(io32, io, duration);
+ CP(io32, io, info);
+
+ if ((error = fo_ioctl(fp, SG_IO, (caddr_t)&io, td->td_ucred, td)) != 0)
+ return (error);
+
+ CP(io, io32, interface_id);
+ CP(io, io32, dxfer_direction);
+ CP(io, io32, cmd_len);
+ CP(io, io32, mx_sb_len);
+ CP(io, io32, iovec_count);
+ CP(io, io32, dxfer_len);
+ PTROUT_CP(io, io32, dxferp);
+ PTROUT_CP(io, io32, cmdp);
+ PTROUT_CP(io, io32, sbp);
+ CP(io, io32, timeout);
+ CP(io, io32, flags);
+ CP(io, io32, pack_id);
+ PTROUT_CP(io, io32, usr_ptr);
+ CP(io, io32, status);
+ CP(io, io32, masked_status);
+ CP(io, io32, msg_status);
+ CP(io, io32, sb_len_wr);
+ CP(io, io32, host_status);
+ CP(io, io32, driver_status);
+ CP(io, io32, resid);
+ CP(io, io32, duration);
+ CP(io, io32, info);
+
+ error = copyout(&io32, uap->data, sizeof(io32));
+
+ return (error);
+}
+
+int
+freebsd32_ioctl(struct thread *td, struct freebsd32_ioctl_args *uap)
+{
+ struct ioctl_args ap /*{
+ int fd;
+ u_long com;
+ caddr_t data;
+ }*/ ;
+ struct file *fp;
+ cap_rights_t rights;
+ int error;
+
+ error = fget(td, uap->fd, cap_rights_init_one(&rights, CAP_IOCTL), &fp);
+ if (error != 0)
+ return (error);
+ if ((fp->f_flag & (FREAD | FWRITE)) == 0) {
+ fdrop(fp, td);
+ return (EBADF);
+ }
+
+ switch (uap->com) {
+ case MEMRANGE_GET32: /* FALLTHROUGH */
+ case MEMRANGE_SET32:
+ error = freebsd32_ioctl_memrange(td, uap, fp);
+ break;
+
+ case SG_IO_32:
+ error = freebsd32_ioctl_sg(td, uap, fp);
+ break;
+
+ case PCIOCBARMMAP_32:
+ error = freebsd32_ioctl_barmmap(td, uap, fp);
+ break;
+
+ default:
+ fdrop(fp, td);
+ ap.fd = uap->fd;
+ ap.com = uap->com;
+ PTRIN_CP(*uap, ap, data);
+ return sys_ioctl(td, &ap);
+ }
+
+ fdrop(fp, td);
+ return (error);
+}
diff --git a/sys/compat/freebsd32/freebsd32_ioctl.h b/sys/compat/freebsd32/freebsd32_ioctl.h
new file mode 100644
index 000000000000..0c0b18496a04
--- /dev/null
+++ b/sys/compat/freebsd32/freebsd32_ioctl.h
@@ -0,0 +1,63 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2008 David E. O'Brien
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _COMPAT_FREEBSD32_IOCTL_H_
+#define _COMPAT_FREEBSD32_IOCTL_H_
+
+#include <cam/scsi/scsi_sg.h>
+
+typedef __uint32_t caddr_t32;
+
+struct mem_range_op32
+{
+ caddr_t32 mo_desc;
+ int mo_arg[2];
+};
+
+struct pci_bar_mmap32 {
+ uint32_t pbm_map_base;
+ uint32_t pbm_map_length;
+ uint32_t pbm_bar_length1, pbm_bar_length2;
+ int pbm_bar_off;
+ struct pcisel pbm_sel;
+ int pbm_reg;
+ int pbm_flags;
+ int pbm_memattr;
+};
+
+#define MEMRANGE_GET32 _IOWR('m', 50, struct mem_range_op32)
+#define MEMRANGE_SET32 _IOW('m', 51, struct mem_range_op32)
+#define SG_IO_32 _IOWR(SGIOC, 0x85, struct sg_io_hdr32)
+#define PCIOCBARMMAP_32 _IOWR('p', 8, struct pci_bar_mmap32)
+
+#endif /* _COMPAT_FREEBSD32_IOCTL_H_ */
diff --git a/sys/compat/freebsd32/freebsd32_ipc.h b/sys/compat/freebsd32/freebsd32_ipc.h
new file mode 100644
index 000000000000..ac469585cafe
--- /dev/null
+++ b/sys/compat/freebsd32/freebsd32_ipc.h
@@ -0,0 +1,193 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2002 Doug Rabson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _COMPAT_FREEBSD32_FREEBSD32_IPC_H_
+#define _COMPAT_FREEBSD32_FREEBSD32_IPC_H_
+
+struct ipc_perm32 {
+ uid_t cuid;
+ gid_t cgid;
+ uid_t uid;
+ gid_t gid;
+ mode_t mode;
+ uint16_t seq;
+ uint32_t key;
+};
+
+struct semid_ds32 {
+ struct ipc_perm32 sem_perm;
+ uint32_t __sem_base;
+ unsigned short sem_nsems;
+ int32_t sem_otime;
+ int32_t sem_ctime;
+};
+
+#ifdef _KERNEL
+struct semid_kernel32 {
+ /* Data structure exposed to user space. */
+ struct semid_ds32 u;
+
+ /* Kernel-private components of the semaphore. */
+ int32_t label;
+ int32_t cred;
+};
+#endif /* _KERNEL */
+
+union semun32 {
+ int val;
+ uint32_t buf;
+ uint32_t array;
+};
+
+struct msqid_ds32 {
+ struct ipc_perm32 msg_perm;
+ uint32_t __msg_first;
+ uint32_t __msg_last;
+ uint32_t msg_cbytes;
+ uint32_t msg_qnum;
+ uint32_t msg_qbytes;
+ pid_t msg_lspid;
+ pid_t msg_lrpid;
+ int32_t msg_stime;
+ int32_t msg_rtime;
+ int32_t msg_ctime;
+};
+
+#ifdef _KERNEL
+struct msqid_kernel32 {
+ /* Data structure exposed to user space. */
+ struct msqid_ds32 u;
+
+ /* Kernel-private components of the message queue. */
+ uint32_t label;
+ uint32_t cred;
+};
+#endif
+
+struct shmid_ds32 {
+ struct ipc_perm32 shm_perm;
+ int32_t shm_segsz;
+ pid_t shm_lpid;
+ pid_t shm_cpid;
+ unsigned int shm_nattch;
+ int32_t shm_atime;
+ int32_t shm_dtime;
+ int32_t shm_ctime;
+};
+
+#ifdef _KERNEL
+struct shmid_kernel32 {
+ struct shmid_ds32 u;
+ int32_t *object;
+ int32_t *label;
+ int32_t *cred;
+};
+#endif
+
+struct shm_info32 {
+ int32_t used_ids;
+ uint32_t shm_tot;
+ uint32_t shm_rss;
+ uint32_t shm_swp;
+ uint32_t swap_attempts;
+ uint32_t swap_successes;
+};
+
+struct shminfo32 {
+ uint32_t shmmax;
+ uint32_t shmmin;
+ uint32_t shmmni;
+ uint32_t shmseg;
+ uint32_t shmall;
+};
+
+#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
+ defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
+struct ipc_perm32_old {
+ uint16_t cuid;
+ uint16_t cgid;
+ uint16_t uid;
+ uint16_t gid;
+ uint16_t mode;
+ uint16_t seq;
+ uint32_t key;
+};
+
+struct semid_ds32_old {
+ struct ipc_perm32_old sem_perm;
+ uint32_t __sem_base;
+ unsigned short sem_nsems;
+ int32_t sem_otime;
+ int32_t sem_pad1;
+ int32_t sem_ctime;
+ int32_t sem_pad2;
+ int32_t sem_pad3[4];
+};
+
+struct msqid_ds32_old {
+ struct ipc_perm32_old msg_perm;
+ uint32_t __msg_first;
+ uint32_t __msg_last;
+ uint32_t msg_cbytes;
+ uint32_t msg_qnum;
+ uint32_t msg_qbytes;
+ pid_t msg_lspid;
+ pid_t msg_lrpid;
+ int32_t msg_stime;
+ int32_t msg_pad1;
+ int32_t msg_rtime;
+ int32_t msg_pad2;
+ int32_t msg_ctime;
+ int32_t msg_pad3;
+ int32_t msg_pad4[4];
+};
+
+struct shmid_ds32_old {
+ struct ipc_perm32_old shm_perm;
+ int32_t shm_segsz;
+ pid_t shm_lpid;
+ pid_t shm_cpid;
+ int16_t shm_nattch;
+ int32_t shm_atime;
+ int32_t shm_dtime;
+ int32_t shm_ctime;
+ uint32_t shm_internal;
+};
+
+void freebsd32_ipcperm_old_in(struct ipc_perm32_old *ip32,
+ struct ipc_perm *ip);
+void freebsd32_ipcperm_old_out(struct ipc_perm *ip,
+ struct ipc_perm32_old *ip32);
+#endif
+
+void freebsd32_ipcperm_in(struct ipc_perm32 *ip32, struct ipc_perm *ip);
+void freebsd32_ipcperm_out(struct ipc_perm *ip, struct ipc_perm32 *ip32);
+
+#endif /* !_COMPAT_FREEBSD32_FREEBSD32_IPC_H_ */
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
new file mode 100644
index 000000000000..c2caa7c10544
--- /dev/null
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -0,0 +1,3845 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2002 Doug Rabson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_inet.h"
+#include "opt_inet6.h"
+#include "opt_ktrace.h"
+
+#define __ELF_WORD_SIZE 32
+
+#ifdef COMPAT_FREEBSD11
+#define _WANT_FREEBSD11_KEVENT
+#endif
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/capsicum.h>
+#include <sys/clock.h>
+#include <sys/exec.h>
+#include <sys/fcntl.h>
+#include <sys/filedesc.h>
+#include <sys/imgact.h>
+#include <sys/jail.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/file.h> /* Must come after sys/malloc.h */
+#include <sys/imgact.h>
+#include <sys/mbuf.h>
+#include <sys/mman.h>
+#include <sys/module.h>
+#include <sys/mount.h>
+#include <sys/mutex.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/procctl.h>
+#include <sys/ptrace.h>
+#include <sys/reboot.h>
+#include <sys/resource.h>
+#include <sys/resourcevar.h>
+#include <sys/selinfo.h>
+#include <sys/eventvar.h> /* Must come after sys/selinfo.h */
+#include <sys/pipe.h> /* Must come after sys/selinfo.h */
+#include <sys/signal.h>
+#include <sys/signalvar.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysctl.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/systm.h>
+#include <sys/thr.h>
+#include <sys/timex.h>
+#include <sys/unistd.h>
+#include <sys/ucontext.h>
+#include <sys/umtx.h>
+#include <sys/vnode.h>
+#include <sys/wait.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+#ifdef KTRACE
+#include <sys/ktrace.h>
+#endif
+
+#ifdef INET
+#include <netinet/in.h>
+#endif
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_extern.h>
+
+#include <machine/cpu.h>
+#include <machine/elf.h>
+#ifdef __amd64__
+#include <machine/md_var.h>
+#endif
+
+#include <security/audit/audit.h>
+
+#include <compat/freebsd32/freebsd32_util.h>
+#include <compat/freebsd32/freebsd32.h>
+#include <compat/freebsd32/freebsd32_ipc.h>
+#include <compat/freebsd32/freebsd32_misc.h>
+#include <compat/freebsd32/freebsd32_signal.h>
+#include <compat/freebsd32/freebsd32_proto.h>
+
+FEATURE(compat_freebsd_32bit, "Compatible with 32-bit FreeBSD");
+
+struct ptrace_io_desc32 {
+ int piod_op;
+ uint32_t piod_offs;
+ uint32_t piod_addr;
+ uint32_t piod_len;
+};
+
+struct ptrace_sc_ret32 {
+ uint32_t sr_retval[2];
+ int sr_error;
+};
+
+struct ptrace_vm_entry32 {
+ int pve_entry;
+ int pve_timestamp;
+ uint32_t pve_start;
+ uint32_t pve_end;
+ uint32_t pve_offset;
+ u_int pve_prot;
+ u_int pve_pathlen;
+ int32_t pve_fileid;
+ u_int pve_fsid;
+ uint32_t pve_path;
+};
+
+#ifdef __amd64__
+CTASSERT(sizeof(struct timeval32) == 8);
+CTASSERT(sizeof(struct timespec32) == 8);
+CTASSERT(sizeof(struct itimerval32) == 16);
+CTASSERT(sizeof(struct bintime32) == 12);
+#endif
+CTASSERT(sizeof(struct statfs32) == 256);
+#ifdef __amd64__
+CTASSERT(sizeof(struct rusage32) == 72);
+#endif
+CTASSERT(sizeof(struct sigaltstack32) == 12);
+#ifdef __amd64__
+CTASSERT(sizeof(struct kevent32) == 56);
+#else
+CTASSERT(sizeof(struct kevent32) == 64);
+#endif
+CTASSERT(sizeof(struct iovec32) == 8);
+CTASSERT(sizeof(struct msghdr32) == 28);
+#ifdef __amd64__
+CTASSERT(sizeof(struct stat32) == 208);
+CTASSERT(sizeof(struct freebsd11_stat32) == 96);
+#endif
+CTASSERT(sizeof(struct sigaction32) == 24);
+
+static int freebsd32_kevent_copyout(void *arg, struct kevent *kevp, int count);
+static int freebsd32_kevent_copyin(void *arg, struct kevent *kevp, int count);
+static int freebsd32_user_clock_nanosleep(struct thread *td, clockid_t clock_id,
+ int flags, const struct timespec32 *ua_rqtp, struct timespec32 *ua_rmtp);
+
+void
+freebsd32_rusage_out(const struct rusage *s, struct rusage32 *s32)
+{
+
+ TV_CP(*s, *s32, ru_utime);
+ TV_CP(*s, *s32, ru_stime);
+ CP(*s, *s32, ru_maxrss);
+ CP(*s, *s32, ru_ixrss);
+ CP(*s, *s32, ru_idrss);
+ CP(*s, *s32, ru_isrss);
+ CP(*s, *s32, ru_minflt);
+ CP(*s, *s32, ru_majflt);
+ CP(*s, *s32, ru_nswap);
+ CP(*s, *s32, ru_inblock);
+ CP(*s, *s32, ru_oublock);
+ CP(*s, *s32, ru_msgsnd);
+ CP(*s, *s32, ru_msgrcv);
+ CP(*s, *s32, ru_nsignals);
+ CP(*s, *s32, ru_nvcsw);
+ CP(*s, *s32, ru_nivcsw);
+}
+
+int
+freebsd32_wait4(struct thread *td, struct freebsd32_wait4_args *uap)
+{
+ int error, status;
+ struct rusage32 ru32;
+ struct rusage ru, *rup;
+
+ if (uap->rusage != NULL)
+ rup = &ru;
+ else
+ rup = NULL;
+ error = kern_wait(td, uap->pid, &status, uap->options, rup);
+ if (error)
+ return (error);
+ if (uap->status != NULL)
+ error = copyout(&status, uap->status, sizeof(status));
+ if (uap->rusage != NULL && error == 0) {
+ freebsd32_rusage_out(&ru, &ru32);
+ error = copyout(&ru32, uap->rusage, sizeof(ru32));
+ }
+ return (error);
+}
+
+int
+freebsd32_wait6(struct thread *td, struct freebsd32_wait6_args *uap)
+{
+ struct wrusage32 wru32;
+ struct __wrusage wru, *wrup;
+ struct siginfo32 si32;
+ struct __siginfo si, *sip;
+ int error, status;
+
+ if (uap->wrusage != NULL)
+ wrup = &wru;
+ else
+ wrup = NULL;
+ if (uap->info != NULL) {
+ sip = &si;
+ bzero(sip, sizeof(*sip));
+ } else
+ sip = NULL;
+ error = kern_wait6(td, uap->idtype, PAIR32TO64(id_t, uap->id),
+ &status, uap->options, wrup, sip);
+ if (error != 0)
+ return (error);
+ if (uap->status != NULL)
+ error = copyout(&status, uap->status, sizeof(status));
+ if (uap->wrusage != NULL && error == 0) {
+ freebsd32_rusage_out(&wru.wru_self, &wru32.wru_self);
+ freebsd32_rusage_out(&wru.wru_children, &wru32.wru_children);
+ error = copyout(&wru32, uap->wrusage, sizeof(wru32));
+ }
+ if (uap->info != NULL && error == 0) {
+ siginfo_to_siginfo32 (&si, &si32);
+ error = copyout(&si32, uap->info, sizeof(si32));
+ }
+ return (error);
+}
+
+#ifdef COMPAT_FREEBSD4
+static void
+copy_statfs(struct statfs *in, struct statfs32 *out)
+{
+
+ statfs_scale_blocks(in, INT32_MAX);
+ bzero(out, sizeof(*out));
+ CP(*in, *out, f_bsize);
+ out->f_iosize = MIN(in->f_iosize, INT32_MAX);
+ CP(*in, *out, f_blocks);
+ CP(*in, *out, f_bfree);
+ CP(*in, *out, f_bavail);
+ out->f_files = MIN(in->f_files, INT32_MAX);
+ out->f_ffree = MIN(in->f_ffree, INT32_MAX);
+ CP(*in, *out, f_fsid);
+ CP(*in, *out, f_owner);
+ CP(*in, *out, f_type);
+ CP(*in, *out, f_flags);
+ out->f_syncwrites = MIN(in->f_syncwrites, INT32_MAX);
+ out->f_asyncwrites = MIN(in->f_asyncwrites, INT32_MAX);
+ strlcpy(out->f_fstypename,
+ in->f_fstypename, MFSNAMELEN);
+ strlcpy(out->f_mntonname,
+ in->f_mntonname, min(MNAMELEN, FREEBSD4_MNAMELEN));
+ out->f_syncreads = MIN(in->f_syncreads, INT32_MAX);
+ out->f_asyncreads = MIN(in->f_asyncreads, INT32_MAX);
+ strlcpy(out->f_mntfromname,
+ in->f_mntfromname, min(MNAMELEN, FREEBSD4_MNAMELEN));
+}
+#endif
+
+#ifdef COMPAT_FREEBSD4
+int
+freebsd4_freebsd32_getfsstat(struct thread *td,
+ struct freebsd4_freebsd32_getfsstat_args *uap)
+{
+ struct statfs *buf, *sp;
+ struct statfs32 stat32;
+ size_t count, size, copycount;
+ int error;
+
+ count = uap->bufsize / sizeof(struct statfs32);
+ size = count * sizeof(struct statfs);
+ error = kern_getfsstat(td, &buf, size, &count, UIO_SYSSPACE, uap->mode);
+ if (size > 0) {
+ sp = buf;
+ copycount = count;
+ while (copycount > 0 && error == 0) {
+ copy_statfs(sp, &stat32);
+ error = copyout(&stat32, uap->buf, sizeof(stat32));
+ sp++;
+ uap->buf++;
+ copycount--;
+ }
+ free(buf, M_STATFS);
+ }
+ if (error == 0)
+ td->td_retval[0] = count;
+ return (error);
+}
+#endif
+
+#ifdef COMPAT_FREEBSD10
+int
+freebsd10_freebsd32_pipe(struct thread *td,
+ struct freebsd10_freebsd32_pipe_args *uap) {
+ return (freebsd10_pipe(td, (struct freebsd10_pipe_args*)uap));
+}
+#endif
+
+int
+freebsd32_sigaltstack(struct thread *td,
+ struct freebsd32_sigaltstack_args *uap)
+{
+ struct sigaltstack32 s32;
+ struct sigaltstack ss, oss, *ssp;
+ int error;
+
+ if (uap->ss != NULL) {
+ error = copyin(uap->ss, &s32, sizeof(s32));
+ if (error)
+ return (error);
+ PTRIN_CP(s32, ss, ss_sp);
+ CP(s32, ss, ss_size);
+ CP(s32, ss, ss_flags);
+ ssp = &ss;
+ } else
+ ssp = NULL;
+ error = kern_sigaltstack(td, ssp, &oss);
+ if (error == 0 && uap->oss != NULL) {
+ PTROUT_CP(oss, s32, ss_sp);
+ CP(oss, s32, ss_size);
+ CP(oss, s32, ss_flags);
+ error = copyout(&s32, uap->oss, sizeof(s32));
+ }
+ return (error);
+}
+
+/*
+ * Custom version of exec_copyin_args() so that we can translate
+ * the pointers.
+ */
+int
+freebsd32_exec_copyin_args(struct image_args *args, const char *fname,
+ enum uio_seg segflg, u_int32_t *argv, u_int32_t *envv)
+{
+ char *argp, *envp;
+ u_int32_t *p32, arg;
+ int error;
+
+ bzero(args, sizeof(*args));
+ if (argv == NULL)
+ return (EFAULT);
+
+ /*
+ * Allocate demand-paged memory for the file name, argument, and
+ * environment strings.
+ */
+ error = exec_alloc_args(args);
+ if (error != 0)
+ return (error);
+
+ /*
+ * Copy the file name.
+ */
+ error = exec_args_add_fname(args, fname, segflg);
+ if (error != 0)
+ goto err_exit;
+
+ /*
+ * extract arguments first
+ */
+ p32 = argv;
+ for (;;) {
+ error = copyin(p32++, &arg, sizeof(arg));
+ if (error)
+ goto err_exit;
+ if (arg == 0)
+ break;
+ argp = PTRIN(arg);
+ error = exec_args_add_arg(args, argp, UIO_USERSPACE);
+ if (error != 0)
+ goto err_exit;
+ }
+
+ /*
+ * extract environment strings
+ */
+ if (envv) {
+ p32 = envv;
+ for (;;) {
+ error = copyin(p32++, &arg, sizeof(arg));
+ if (error)
+ goto err_exit;
+ if (arg == 0)
+ break;
+ envp = PTRIN(arg);
+ error = exec_args_add_env(args, envp, UIO_USERSPACE);
+ if (error != 0)
+ goto err_exit;
+ }
+ }
+
+ return (0);
+
+err_exit:
+ exec_free_args(args);
+ return (error);
+}
+
+int
+freebsd32_execve(struct thread *td, struct freebsd32_execve_args *uap)
+{
+ struct image_args eargs;
+ struct vmspace *oldvmspace;
+ int error;
+
+ error = pre_execve(td, &oldvmspace);
+ if (error != 0)
+ return (error);
+ error = freebsd32_exec_copyin_args(&eargs, uap->fname, UIO_USERSPACE,
+ uap->argv, uap->envv);
+ if (error == 0)
+ error = kern_execve(td, &eargs, NULL, oldvmspace);
+ post_execve(td, error, oldvmspace);
+ AUDIT_SYSCALL_EXIT(error == EJUSTRETURN ? 0 : error, td);
+ return (error);
+}
+
+int
+freebsd32_fexecve(struct thread *td, struct freebsd32_fexecve_args *uap)
+{
+ struct image_args eargs;
+ struct vmspace *oldvmspace;
+ int error;
+
+ error = pre_execve(td, &oldvmspace);
+ if (error != 0)
+ return (error);
+ error = freebsd32_exec_copyin_args(&eargs, NULL, UIO_SYSSPACE,
+ uap->argv, uap->envv);
+ if (error == 0) {
+ eargs.fd = uap->fd;
+ error = kern_execve(td, &eargs, NULL, oldvmspace);
+ }
+ post_execve(td, error, oldvmspace);
+ AUDIT_SYSCALL_EXIT(error == EJUSTRETURN ? 0 : error, td);
+ return (error);
+}
+
+int
+freebsd32_mknodat(struct thread *td, struct freebsd32_mknodat_args *uap)
+{
+
+ return (kern_mknodat(td, uap->fd, uap->path, UIO_USERSPACE,
+ uap->mode, PAIR32TO64(dev_t, uap->dev)));
+}
+
+int
+freebsd32_mprotect(struct thread *td, struct freebsd32_mprotect_args *uap)
+{
+ int prot;
+
+ prot = uap->prot;
+#if defined(__amd64__)
+ if (i386_read_exec && (prot & PROT_READ) != 0)
+ prot |= PROT_EXEC;
+#endif
+ return (kern_mprotect(td, (uintptr_t)PTRIN(uap->addr), uap->len,
+ prot));
+}
+
+int
+freebsd32_mmap(struct thread *td, struct freebsd32_mmap_args *uap)
+{
+ int prot;
+
+ prot = uap->prot;
+#if defined(__amd64__)
+ if (i386_read_exec && (prot & PROT_READ))
+ prot |= PROT_EXEC;
+#endif
+
+ return (kern_mmap(td, &(struct mmap_req){
+ .mr_hint = (uintptr_t)uap->addr,
+ .mr_len = uap->len,
+ .mr_prot = prot,
+ .mr_flags = uap->flags,
+ .mr_fd = uap->fd,
+ .mr_pos = PAIR32TO64(off_t, uap->pos),
+ }));
+}
+
+#ifdef COMPAT_FREEBSD6
+int
+freebsd6_freebsd32_mmap(struct thread *td,
+ struct freebsd6_freebsd32_mmap_args *uap)
+{
+ int prot;
+
+ prot = uap->prot;
+#if defined(__amd64__)
+ if (i386_read_exec && (prot & PROT_READ))
+ prot |= PROT_EXEC;
+#endif
+
+ return (kern_mmap(td, &(struct mmap_req){
+ .mr_hint = (uintptr_t)uap->addr,
+ .mr_len = uap->len,
+ .mr_prot = prot,
+ .mr_flags = uap->flags,
+ .mr_fd = uap->fd,
+ .mr_pos = PAIR32TO64(off_t, uap->pos),
+ }));
+}
+#endif
+
+int
+freebsd32_setitimer(struct thread *td, struct freebsd32_setitimer_args *uap)
+{
+ struct itimerval itv, oitv, *itvp;
+ struct itimerval32 i32;
+ int error;
+
+ if (uap->itv != NULL) {
+ error = copyin(uap->itv, &i32, sizeof(i32));
+ if (error)
+ return (error);
+ TV_CP(i32, itv, it_interval);
+ TV_CP(i32, itv, it_value);
+ itvp = &itv;
+ } else
+ itvp = NULL;
+ error = kern_setitimer(td, uap->which, itvp, &oitv);
+ if (error || uap->oitv == NULL)
+ return (error);
+ TV_CP(oitv, i32, it_interval);
+ TV_CP(oitv, i32, it_value);
+ return (copyout(&i32, uap->oitv, sizeof(i32)));
+}
+
+int
+freebsd32_getitimer(struct thread *td, struct freebsd32_getitimer_args *uap)
+{
+ struct itimerval itv;
+ struct itimerval32 i32;
+ int error;
+
+ error = kern_getitimer(td, uap->which, &itv);
+ if (error || uap->itv == NULL)
+ return (error);
+ TV_CP(itv, i32, it_interval);
+ TV_CP(itv, i32, it_value);
+ return (copyout(&i32, uap->itv, sizeof(i32)));
+}
+
+int
+freebsd32_select(struct thread *td, struct freebsd32_select_args *uap)
+{
+ struct timeval32 tv32;
+ struct timeval tv, *tvp;
+ int error;
+
+ if (uap->tv != NULL) {
+ error = copyin(uap->tv, &tv32, sizeof(tv32));
+ if (error)
+ return (error);
+ CP(tv32, tv, tv_sec);
+ CP(tv32, tv, tv_usec);
+ tvp = &tv;
+ } else
+ tvp = NULL;
+ /*
+ * XXX Do pointers need PTRIN()?
+ */
+ return (kern_select(td, uap->nd, uap->in, uap->ou, uap->ex, tvp,
+ sizeof(int32_t) * 8));
+}
+
+int
+freebsd32_pselect(struct thread *td, struct freebsd32_pselect_args *uap)
+{
+ struct timespec32 ts32;
+ struct timespec ts;
+ struct timeval tv, *tvp;
+ sigset_t set, *uset;
+ int error;
+
+ if (uap->ts != NULL) {
+ error = copyin(uap->ts, &ts32, sizeof(ts32));
+ if (error != 0)
+ return (error);
+ CP(ts32, ts, tv_sec);
+ CP(ts32, ts, tv_nsec);
+ TIMESPEC_TO_TIMEVAL(&tv, &ts);
+ tvp = &tv;
+ } else
+ tvp = NULL;
+ if (uap->sm != NULL) {
+ error = copyin(uap->sm, &set, sizeof(set));
+ if (error != 0)
+ return (error);
+ uset = &set;
+ } else
+ uset = NULL;
+ /*
+ * XXX Do pointers need PTRIN()?
+ */
+ error = kern_pselect(td, uap->nd, uap->in, uap->ou, uap->ex, tvp,
+ uset, sizeof(int32_t) * 8);
+ return (error);
+}
+
+/*
+ * Copy 'count' items into the destination list pointed to by uap->eventlist.
+ */
+static int
+freebsd32_kevent_copyout(void *arg, struct kevent *kevp, int count)
+{
+ struct freebsd32_kevent_args *uap;
+ struct kevent32 ks32[KQ_NEVENTS];
+ uint64_t e;
+ int i, j, error;
+
+ KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count));
+ uap = (struct freebsd32_kevent_args *)arg;
+
+ for (i = 0; i < count; i++) {
+ CP(kevp[i], ks32[i], ident);
+ CP(kevp[i], ks32[i], filter);
+ CP(kevp[i], ks32[i], flags);
+ CP(kevp[i], ks32[i], fflags);
+#if BYTE_ORDER == LITTLE_ENDIAN
+ ks32[i].data1 = kevp[i].data;
+ ks32[i].data2 = kevp[i].data >> 32;
+#else
+ ks32[i].data1 = kevp[i].data >> 32;
+ ks32[i].data2 = kevp[i].data;
+#endif
+ PTROUT_CP(kevp[i], ks32[i], udata);
+ for (j = 0; j < nitems(kevp->ext); j++) {
+ e = kevp[i].ext[j];
+#if BYTE_ORDER == LITTLE_ENDIAN
+ ks32[i].ext64[2 * j] = e;
+ ks32[i].ext64[2 * j + 1] = e >> 32;
+#else
+ ks32[i].ext64[2 * j] = e >> 32;
+ ks32[i].ext64[2 * j + 1] = e;
+#endif
+ }
+ }
+ error = copyout(ks32, uap->eventlist, count * sizeof *ks32);
+ if (error == 0)
+ uap->eventlist += count;
+ return (error);
+}
+
+/*
+ * Copy 'count' items from the list pointed to by uap->changelist.
+ */
+static int
+freebsd32_kevent_copyin(void *arg, struct kevent *kevp, int count)
+{
+ struct freebsd32_kevent_args *uap;
+ struct kevent32 ks32[KQ_NEVENTS];
+ uint64_t e;
+ int i, j, error;
+
+ KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count));
+ uap = (struct freebsd32_kevent_args *)arg;
+
+ error = copyin(uap->changelist, ks32, count * sizeof *ks32);
+ if (error)
+ goto done;
+ uap->changelist += count;
+
+ for (i = 0; i < count; i++) {
+ CP(ks32[i], kevp[i], ident);
+ CP(ks32[i], kevp[i], filter);
+ CP(ks32[i], kevp[i], flags);
+ CP(ks32[i], kevp[i], fflags);
+ kevp[i].data = PAIR32TO64(uint64_t, ks32[i].data);
+ PTRIN_CP(ks32[i], kevp[i], udata);
+ for (j = 0; j < nitems(kevp->ext); j++) {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ e = ks32[i].ext64[2 * j + 1];
+ e <<= 32;
+ e += ks32[i].ext64[2 * j];
+#else
+ e = ks32[i].ext64[2 * j];
+ e <<= 32;
+ e += ks32[i].ext64[2 * j + 1];
+#endif
+ kevp[i].ext[j] = e;
+ }
+ }
+done:
+ return (error);
+}
+
+int
+freebsd32_kevent(struct thread *td, struct freebsd32_kevent_args *uap)
+{
+ struct timespec32 ts32;
+ struct timespec ts, *tsp;
+ struct kevent_copyops k_ops = {
+ .arg = uap,
+ .k_copyout = freebsd32_kevent_copyout,
+ .k_copyin = freebsd32_kevent_copyin,
+ };
+#ifdef KTRACE
+ struct kevent32 *eventlist = uap->eventlist;
+#endif
+ int error;
+
+ if (uap->timeout) {
+ error = copyin(uap->timeout, &ts32, sizeof(ts32));
+ if (error)
+ return (error);
+ CP(ts32, ts, tv_sec);
+ CP(ts32, ts, tv_nsec);
+ tsp = &ts;
+ } else
+ tsp = NULL;
+#ifdef KTRACE
+ if (KTRPOINT(td, KTR_STRUCT_ARRAY))
+ ktrstructarray("kevent32", UIO_USERSPACE, uap->changelist,
+ uap->nchanges, sizeof(struct kevent32));
+#endif
+ error = kern_kevent(td, uap->fd, uap->nchanges, uap->nevents,
+ &k_ops, tsp);
+#ifdef KTRACE
+ if (error == 0 && KTRPOINT(td, KTR_STRUCT_ARRAY))
+ ktrstructarray("kevent32", UIO_USERSPACE, eventlist,
+ td->td_retval[0], sizeof(struct kevent32));
+#endif
+ return (error);
+}
+
+#ifdef COMPAT_FREEBSD11
+static int
+freebsd32_kevent11_copyout(void *arg, struct kevent *kevp, int count)
+{
+ struct freebsd11_freebsd32_kevent_args *uap;
+ struct kevent32_freebsd11 ks32[KQ_NEVENTS];
+ int i, error;
+
+ KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count));
+ uap = (struct freebsd11_freebsd32_kevent_args *)arg;
+
+ for (i = 0; i < count; i++) {
+ CP(kevp[i], ks32[i], ident);
+ CP(kevp[i], ks32[i], filter);
+ CP(kevp[i], ks32[i], flags);
+ CP(kevp[i], ks32[i], fflags);
+ CP(kevp[i], ks32[i], data);
+ PTROUT_CP(kevp[i], ks32[i], udata);
+ }
+ error = copyout(ks32, uap->eventlist, count * sizeof *ks32);
+ if (error == 0)
+ uap->eventlist += count;
+ return (error);
+}
+
+/*
+ * Copy 'count' items from the list pointed to by uap->changelist.
+ */
+static int
+freebsd32_kevent11_copyin(void *arg, struct kevent *kevp, int count)
+{
+ struct freebsd11_freebsd32_kevent_args *uap;
+ struct kevent32_freebsd11 ks32[KQ_NEVENTS];
+ int i, j, error;
+
+ KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count));
+ uap = (struct freebsd11_freebsd32_kevent_args *)arg;
+
+ error = copyin(uap->changelist, ks32, count * sizeof *ks32);
+ if (error)
+ goto done;
+ uap->changelist += count;
+
+ for (i = 0; i < count; i++) {
+ CP(ks32[i], kevp[i], ident);
+ CP(ks32[i], kevp[i], filter);
+ CP(ks32[i], kevp[i], flags);
+ CP(ks32[i], kevp[i], fflags);
+ CP(ks32[i], kevp[i], data);
+ PTRIN_CP(ks32[i], kevp[i], udata);
+ for (j = 0; j < nitems(kevp->ext); j++)
+ kevp[i].ext[j] = 0;
+ }
+done:
+ return (error);
+}
+
+int
+freebsd11_freebsd32_kevent(struct thread *td,
+ struct freebsd11_freebsd32_kevent_args *uap)
+{
+ struct timespec32 ts32;
+ struct timespec ts, *tsp;
+ struct kevent_copyops k_ops = {
+ .arg = uap,
+ .k_copyout = freebsd32_kevent11_copyout,
+ .k_copyin = freebsd32_kevent11_copyin,
+ };
+#ifdef KTRACE
+ struct kevent32_freebsd11 *eventlist = uap->eventlist;
+#endif
+ int error;
+
+ if (uap->timeout) {
+ error = copyin(uap->timeout, &ts32, sizeof(ts32));
+ if (error)
+ return (error);
+ CP(ts32, ts, tv_sec);
+ CP(ts32, ts, tv_nsec);
+ tsp = &ts;
+ } else
+ tsp = NULL;
+#ifdef KTRACE
+ if (KTRPOINT(td, KTR_STRUCT_ARRAY))
+ ktrstructarray("kevent32_freebsd11", UIO_USERSPACE,
+ uap->changelist, uap->nchanges,
+ sizeof(struct kevent32_freebsd11));
+#endif
+ error = kern_kevent(td, uap->fd, uap->nchanges, uap->nevents,
+ &k_ops, tsp);
+#ifdef KTRACE
+ if (error == 0 && KTRPOINT(td, KTR_STRUCT_ARRAY))
+ ktrstructarray("kevent32_freebsd11", UIO_USERSPACE,
+ eventlist, td->td_retval[0],
+ sizeof(struct kevent32_freebsd11));
+#endif
+ return (error);
+}
+#endif
+
+int
+freebsd32_gettimeofday(struct thread *td,
+ struct freebsd32_gettimeofday_args *uap)
+{
+ struct timeval atv;
+ struct timeval32 atv32;
+ struct timezone rtz;
+ int error = 0;
+
+ if (uap->tp) {
+ microtime(&atv);
+ CP(atv, atv32, tv_sec);
+ CP(atv, atv32, tv_usec);
+ error = copyout(&atv32, uap->tp, sizeof (atv32));
+ }
+ if (error == 0 && uap->tzp != NULL) {
+ rtz.tz_minuteswest = 0;
+ rtz.tz_dsttime = 0;
+ error = copyout(&rtz, uap->tzp, sizeof (rtz));
+ }
+ return (error);
+}
+
+int
+freebsd32_getrusage(struct thread *td, struct freebsd32_getrusage_args *uap)
+{
+ struct rusage32 s32;
+ struct rusage s;
+ int error;
+
+ error = kern_getrusage(td, uap->who, &s);
+ if (error == 0) {
+ freebsd32_rusage_out(&s, &s32);
+ error = copyout(&s32, uap->rusage, sizeof(s32));
+ }
+ return (error);
+}
+
+static void
+ptrace_lwpinfo_to32(const struct ptrace_lwpinfo *pl,
+ struct ptrace_lwpinfo32 *pl32)
+{
+
+ bzero(pl32, sizeof(*pl32));
+ pl32->pl_lwpid = pl->pl_lwpid;
+ pl32->pl_event = pl->pl_event;
+ pl32->pl_flags = pl->pl_flags;
+ pl32->pl_sigmask = pl->pl_sigmask;
+ pl32->pl_siglist = pl->pl_siglist;
+ siginfo_to_siginfo32(&pl->pl_siginfo, &pl32->pl_siginfo);
+ strcpy(pl32->pl_tdname, pl->pl_tdname);
+ pl32->pl_child_pid = pl->pl_child_pid;
+ pl32->pl_syscall_code = pl->pl_syscall_code;
+ pl32->pl_syscall_narg = pl->pl_syscall_narg;
+}
+
+static void
+ptrace_sc_ret_to32(const struct ptrace_sc_ret *psr,
+ struct ptrace_sc_ret32 *psr32)
+{
+
+ bzero(psr32, sizeof(*psr32));
+ psr32->sr_retval[0] = psr->sr_retval[0];
+ psr32->sr_retval[1] = psr->sr_retval[1];
+ psr32->sr_error = psr->sr_error;
+}
+
+int
+freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
+{
+ union {
+ struct ptrace_io_desc piod;
+ struct ptrace_lwpinfo pl;
+ struct ptrace_vm_entry pve;
+ struct dbreg32 dbreg;
+ struct fpreg32 fpreg;
+ struct reg32 reg;
+ register_t args[nitems(td->td_sa.args)];
+ struct ptrace_sc_ret psr;
+ int ptevents;
+ } r;
+ union {
+ struct ptrace_io_desc32 piod;
+ struct ptrace_lwpinfo32 pl;
+ struct ptrace_vm_entry32 pve;
+ uint32_t args[nitems(td->td_sa.args)];
+ struct ptrace_sc_ret32 psr;
+ } r32;
+ void *addr;
+ int data, error = 0, i;
+
+ AUDIT_ARG_PID(uap->pid);
+ AUDIT_ARG_CMD(uap->req);
+ AUDIT_ARG_VALUE(uap->data);
+ addr = &r;
+ data = uap->data;
+ switch (uap->req) {
+ case PT_GET_EVENT_MASK:
+ case PT_GET_SC_ARGS:
+ case PT_GET_SC_RET:
+ break;
+ case PT_LWPINFO:
+ if (uap->data > sizeof(r32.pl))
+ return (EINVAL);
+
+ /*
+ * Pass size of native structure in 'data'. Truncate
+ * if necessary to avoid siginfo.
+ */
+ data = sizeof(r.pl);
+ if (uap->data < offsetof(struct ptrace_lwpinfo32, pl_siginfo) +
+ sizeof(struct siginfo32))
+ data = offsetof(struct ptrace_lwpinfo, pl_siginfo);
+ break;
+ case PT_GETREGS:
+ bzero(&r.reg, sizeof(r.reg));
+ break;
+ case PT_GETFPREGS:
+ bzero(&r.fpreg, sizeof(r.fpreg));
+ break;
+ case PT_GETDBREGS:
+ bzero(&r.dbreg, sizeof(r.dbreg));
+ break;
+ case PT_SETREGS:
+ error = copyin(uap->addr, &r.reg, sizeof(r.reg));
+ break;
+ case PT_SETFPREGS:
+ error = copyin(uap->addr, &r.fpreg, sizeof(r.fpreg));
+ break;
+ case PT_SETDBREGS:
+ error = copyin(uap->addr, &r.dbreg, sizeof(r.dbreg));
+ break;
+ case PT_SET_EVENT_MASK:
+ if (uap->data != sizeof(r.ptevents))
+ error = EINVAL;
+ else
+ error = copyin(uap->addr, &r.ptevents, uap->data);
+ break;
+ case PT_IO:
+ error = copyin(uap->addr, &r32.piod, sizeof(r32.piod));
+ if (error)
+ break;
+ CP(r32.piod, r.piod, piod_op);
+ PTRIN_CP(r32.piod, r.piod, piod_offs);
+ PTRIN_CP(r32.piod, r.piod, piod_addr);
+ CP(r32.piod, r.piod, piod_len);
+ break;
+ case PT_VM_ENTRY:
+ error = copyin(uap->addr, &r32.pve, sizeof(r32.pve));
+ if (error)
+ break;
+
+ CP(r32.pve, r.pve, pve_entry);
+ CP(r32.pve, r.pve, pve_timestamp);
+ CP(r32.pve, r.pve, pve_start);
+ CP(r32.pve, r.pve, pve_end);
+ CP(r32.pve, r.pve, pve_offset);
+ CP(r32.pve, r.pve, pve_prot);
+ CP(r32.pve, r.pve, pve_pathlen);
+ CP(r32.pve, r.pve, pve_fileid);
+ CP(r32.pve, r.pve, pve_fsid);
+ PTRIN_CP(r32.pve, r.pve, pve_path);
+ break;
+ default:
+ addr = uap->addr;
+ break;
+ }
+ if (error)
+ return (error);
+
+ error = kern_ptrace(td, uap->req, uap->pid, addr, data);
+ if (error)
+ return (error);
+
+ switch (uap->req) {
+ case PT_VM_ENTRY:
+ CP(r.pve, r32.pve, pve_entry);
+ CP(r.pve, r32.pve, pve_timestamp);
+ CP(r.pve, r32.pve, pve_start);
+ CP(r.pve, r32.pve, pve_end);
+ CP(r.pve, r32.pve, pve_offset);
+ CP(r.pve, r32.pve, pve_prot);
+ CP(r.pve, r32.pve, pve_pathlen);
+ CP(r.pve, r32.pve, pve_fileid);
+ CP(r.pve, r32.pve, pve_fsid);
+ error = copyout(&r32.pve, uap->addr, sizeof(r32.pve));
+ break;
+ case PT_IO:
+ CP(r.piod, r32.piod, piod_len);
+ error = copyout(&r32.piod, uap->addr, sizeof(r32.piod));
+ break;
+ case PT_GETREGS:
+ error = copyout(&r.reg, uap->addr, sizeof(r.reg));
+ break;
+ case PT_GETFPREGS:
+ error = copyout(&r.fpreg, uap->addr, sizeof(r.fpreg));
+ break;
+ case PT_GETDBREGS:
+ error = copyout(&r.dbreg, uap->addr, sizeof(r.dbreg));
+ break;
+ case PT_GET_EVENT_MASK:
+ /* NB: The size in uap->data is validated in kern_ptrace(). */
+ error = copyout(&r.ptevents, uap->addr, uap->data);
+ break;
+ case PT_LWPINFO:
+ ptrace_lwpinfo_to32(&r.pl, &r32.pl);
+ error = copyout(&r32.pl, uap->addr, uap->data);
+ break;
+ case PT_GET_SC_ARGS:
+ for (i = 0; i < nitems(r.args); i++)
+ r32.args[i] = (uint32_t)r.args[i];
+ error = copyout(r32.args, uap->addr, MIN(uap->data,
+ sizeof(r32.args)));
+ break;
+ case PT_GET_SC_RET:
+ ptrace_sc_ret_to32(&r.psr, &r32.psr);
+ error = copyout(&r32.psr, uap->addr, MIN(uap->data,
+ sizeof(r32.psr)));
+ break;
+ }
+
+ return (error);
+}
+
+int
+freebsd32_copyinuio(struct iovec32 *iovp, u_int iovcnt, struct uio **uiop)
+{
+ struct iovec32 iov32;
+ struct iovec *iov;
+ struct uio *uio;
+ u_int iovlen;
+ int error, i;
+
+ *uiop = NULL;
+ if (iovcnt > UIO_MAXIOV)
+ return (EINVAL);
+ iovlen = iovcnt * sizeof(struct iovec);
+ uio = malloc(iovlen + sizeof *uio, M_IOV, M_WAITOK);
+ iov = (struct iovec *)(uio + 1);
+ for (i = 0; i < iovcnt; i++) {
+ error = copyin(&iovp[i], &iov32, sizeof(struct iovec32));
+ if (error) {
+ free(uio, M_IOV);
+ return (error);
+ }
+ iov[i].iov_base = PTRIN(iov32.iov_base);
+ iov[i].iov_len = iov32.iov_len;
+ }
+ uio->uio_iov = iov;
+ uio->uio_iovcnt = iovcnt;
+ uio->uio_segflg = UIO_USERSPACE;
+ uio->uio_offset = -1;
+ uio->uio_resid = 0;
+ for (i = 0; i < iovcnt; i++) {
+ if (iov->iov_len > INT_MAX - uio->uio_resid) {
+ free(uio, M_IOV);
+ return (EINVAL);
+ }
+ uio->uio_resid += iov->iov_len;
+ iov++;
+ }
+ *uiop = uio;
+ return (0);
+}
+
+int
+freebsd32_readv(struct thread *td, struct freebsd32_readv_args *uap)
+{
+ struct uio *auio;
+ int error;
+
+ error = freebsd32_copyinuio(uap->iovp, uap->iovcnt, &auio);
+ if (error)
+ return (error);
+ error = kern_readv(td, uap->fd, auio);
+ free(auio, M_IOV);
+ return (error);
+}
+
+int
+freebsd32_writev(struct thread *td, struct freebsd32_writev_args *uap)
+{
+ struct uio *auio;
+ int error;
+
+ error = freebsd32_copyinuio(uap->iovp, uap->iovcnt, &auio);
+ if (error)
+ return (error);
+ error = kern_writev(td, uap->fd, auio);
+ free(auio, M_IOV);
+ return (error);
+}
+
+int
+freebsd32_preadv(struct thread *td, struct freebsd32_preadv_args *uap)
+{
+ struct uio *auio;
+ int error;
+
+ error = freebsd32_copyinuio(uap->iovp, uap->iovcnt, &auio);
+ if (error)
+ return (error);
+ error = kern_preadv(td, uap->fd, auio, PAIR32TO64(off_t,uap->offset));
+ free(auio, M_IOV);
+ return (error);
+}
+
+int
+freebsd32_pwritev(struct thread *td, struct freebsd32_pwritev_args *uap)
+{
+ struct uio *auio;
+ int error;
+
+ error = freebsd32_copyinuio(uap->iovp, uap->iovcnt, &auio);
+ if (error)
+ return (error);
+ error = kern_pwritev(td, uap->fd, auio, PAIR32TO64(off_t,uap->offset));
+ free(auio, M_IOV);
+ return (error);
+}
+
+int
+freebsd32_copyiniov(struct iovec32 *iovp32, u_int iovcnt, struct iovec **iovp,
+ int error)
+{
+ struct iovec32 iov32;
+ struct iovec *iov;
+ u_int iovlen;
+ int i;
+
+ *iovp = NULL;
+ if (iovcnt > UIO_MAXIOV)
+ return (error);
+ iovlen = iovcnt * sizeof(struct iovec);
+ iov = malloc(iovlen, M_IOV, M_WAITOK);
+ for (i = 0; i < iovcnt; i++) {
+ error = copyin(&iovp32[i], &iov32, sizeof(struct iovec32));
+ if (error) {
+ free(iov, M_IOV);
+ return (error);
+ }
+ iov[i].iov_base = PTRIN(iov32.iov_base);
+ iov[i].iov_len = iov32.iov_len;
+ }
+ *iovp = iov;
+ return (0);
+}
+
+static int
+freebsd32_copyinmsghdr(struct msghdr32 *msg32, struct msghdr *msg)
+{
+ struct msghdr32 m32;
+ int error;
+
+ error = copyin(msg32, &m32, sizeof(m32));
+ if (error)
+ return (error);
+ msg->msg_name = PTRIN(m32.msg_name);
+ msg->msg_namelen = m32.msg_namelen;
+ msg->msg_iov = PTRIN(m32.msg_iov);
+ msg->msg_iovlen = m32.msg_iovlen;
+ msg->msg_control = PTRIN(m32.msg_control);
+ msg->msg_controllen = m32.msg_controllen;
+ msg->msg_flags = m32.msg_flags;
+ return (0);
+}
+
+static int
+freebsd32_copyoutmsghdr(struct msghdr *msg, struct msghdr32 *msg32)
+{
+ struct msghdr32 m32;
+ int error;
+
+ m32.msg_name = PTROUT(msg->msg_name);
+ m32.msg_namelen = msg->msg_namelen;
+ m32.msg_iov = PTROUT(msg->msg_iov);
+ m32.msg_iovlen = msg->msg_iovlen;
+ m32.msg_control = PTROUT(msg->msg_control);
+ m32.msg_controllen = msg->msg_controllen;
+ m32.msg_flags = msg->msg_flags;
+ error = copyout(&m32, msg32, sizeof(m32));
+ return (error);
+}
+
+#ifndef __mips__
+#define FREEBSD32_ALIGNBYTES (sizeof(int) - 1)
+#else
+#define FREEBSD32_ALIGNBYTES (sizeof(long) - 1)
+#endif
+#define FREEBSD32_ALIGN(p) \
+ (((u_long)(p) + FREEBSD32_ALIGNBYTES) & ~FREEBSD32_ALIGNBYTES)
+#define FREEBSD32_CMSG_SPACE(l) \
+ (FREEBSD32_ALIGN(sizeof(struct cmsghdr)) + FREEBSD32_ALIGN(l))
+
+#define FREEBSD32_CMSG_DATA(cmsg) ((unsigned char *)(cmsg) + \
+ FREEBSD32_ALIGN(sizeof(struct cmsghdr)))
+
+static size_t
+freebsd32_cmsg_convert(const struct cmsghdr *cm, void *data, socklen_t datalen)
+{
+ size_t copylen;
+ union {
+ struct timespec32 ts;
+ struct timeval32 tv;
+ struct bintime32 bt;
+ } tmp32;
+
+ union {
+ struct timespec ts;
+ struct timeval tv;
+ struct bintime bt;
+ } *in;
+
+ in = data;
+ copylen = 0;
+ switch (cm->cmsg_level) {
+ case SOL_SOCKET:
+ switch (cm->cmsg_type) {
+ case SCM_TIMESTAMP:
+ TV_CP(*in, tmp32, tv);
+ copylen = sizeof(tmp32.tv);
+ break;
+
+ case SCM_BINTIME:
+ BT_CP(*in, tmp32, bt);
+ copylen = sizeof(tmp32.bt);
+ break;
+
+ case SCM_REALTIME:
+ case SCM_MONOTONIC:
+ TS_CP(*in, tmp32, ts);
+ copylen = sizeof(tmp32.ts);
+ break;
+
+ default:
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ if (copylen == 0)
+ return (datalen);
+
+ KASSERT((datalen >= copylen), ("corrupted cmsghdr"));
+
+ bcopy(&tmp32, data, copylen);
+ return (copylen);
+}
+
+static int
+freebsd32_copy_msg_out(struct msghdr *msg, struct mbuf *control)
+{
+ struct cmsghdr *cm;
+ void *data;
+ socklen_t clen, datalen, datalen_out, oldclen;
+ int error;
+ caddr_t ctlbuf;
+ int len, maxlen, copylen;
+ struct mbuf *m;
+ error = 0;
+
+ len = msg->msg_controllen;
+ maxlen = msg->msg_controllen;
+ msg->msg_controllen = 0;
+
+ ctlbuf = msg->msg_control;
+ for (m = control; m != NULL && len > 0; m = m->m_next) {
+ cm = mtod(m, struct cmsghdr *);
+ clen = m->m_len;
+ while (cm != NULL) {
+ if (sizeof(struct cmsghdr) > clen ||
+ cm->cmsg_len > clen) {
+ error = EINVAL;
+ break;
+ }
+
+ data = CMSG_DATA(cm);
+ datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
+ datalen_out = freebsd32_cmsg_convert(cm, data, datalen);
+
+ /*
+ * Copy out the message header. Preserve the native
+ * message size in case we need to inspect the message
+ * contents later.
+ */
+ copylen = sizeof(struct cmsghdr);
+ if (len < copylen) {
+ msg->msg_flags |= MSG_CTRUNC;
+ m_dispose_extcontrolm(m);
+ goto exit;
+ }
+ oldclen = cm->cmsg_len;
+ cm->cmsg_len = FREEBSD32_ALIGN(sizeof(struct cmsghdr)) +
+ datalen_out;
+ error = copyout(cm, ctlbuf, copylen);
+ cm->cmsg_len = oldclen;
+ if (error != 0)
+ goto exit;
+
+ ctlbuf += FREEBSD32_ALIGN(copylen);
+ len -= FREEBSD32_ALIGN(copylen);
+
+ copylen = datalen_out;
+ if (len < copylen) {
+ msg->msg_flags |= MSG_CTRUNC;
+ m_dispose_extcontrolm(m);
+ break;
+ }
+
+ /* Copy out the message data. */
+ error = copyout(data, ctlbuf, copylen);
+ if (error)
+ goto exit;
+
+ ctlbuf += FREEBSD32_ALIGN(copylen);
+ len -= FREEBSD32_ALIGN(copylen);
+
+ if (CMSG_SPACE(datalen) < clen) {
+ clen -= CMSG_SPACE(datalen);
+ cm = (struct cmsghdr *)
+ ((caddr_t)cm + CMSG_SPACE(datalen));
+ } else {
+ clen = 0;
+ cm = NULL;
+ }
+
+ msg->msg_controllen +=
+ FREEBSD32_CMSG_SPACE(datalen_out);
+ }
+ }
+ if (len == 0 && m != NULL) {
+ msg->msg_flags |= MSG_CTRUNC;
+ m_dispose_extcontrolm(m);
+ }
+
+exit:
+ return (error);
+}
+
+int
+freebsd32_recvmsg(td, uap)
+ struct thread *td;
+ struct freebsd32_recvmsg_args /* {
+ int s;
+ struct msghdr32 *msg;
+ int flags;
+ } */ *uap;
+{
+ struct msghdr msg;
+ struct msghdr32 m32;
+ struct iovec *uiov, *iov;
+ struct mbuf *control = NULL;
+ struct mbuf **controlp;
+
+ int error;
+ error = copyin(uap->msg, &m32, sizeof(m32));
+ if (error)
+ return (error);
+ error = freebsd32_copyinmsghdr(uap->msg, &msg);
+ if (error)
+ return (error);
+ error = freebsd32_copyiniov(PTRIN(m32.msg_iov), m32.msg_iovlen, &iov,
+ EMSGSIZE);
+ if (error)
+ return (error);
+ msg.msg_flags = uap->flags;
+ uiov = msg.msg_iov;
+ msg.msg_iov = iov;
+
+ controlp = (msg.msg_control != NULL) ? &control : NULL;
+ error = kern_recvit(td, uap->s, &msg, UIO_USERSPACE, controlp);
+ if (error == 0) {
+ msg.msg_iov = uiov;
+
+ if (control != NULL)
+ error = freebsd32_copy_msg_out(&msg, control);
+ else
+ msg.msg_controllen = 0;
+
+ if (error == 0)
+ error = freebsd32_copyoutmsghdr(&msg, uap->msg);
+ }
+ free(iov, M_IOV);
+
+ if (control != NULL) {
+ if (error != 0)
+ m_dispose_extcontrolm(control);
+ m_freem(control);
+ }
+
+ return (error);
+}
+
+/*
+ * Copy-in the array of control messages constructed using alignment
+ * and padding suitable for a 32-bit environment and construct an
+ * mbuf using alignment and padding suitable for a 64-bit kernel.
+ * The alignment and padding are defined indirectly by CMSG_DATA(),
+ * CMSG_SPACE() and CMSG_LEN().
+ */
+static int
+freebsd32_copyin_control(struct mbuf **mp, caddr_t buf, u_int buflen)
+{
+ struct cmsghdr *cm;
+ struct mbuf *m;
+ void *in, *in1, *md;
+ u_int msglen, outlen;
+ int error;
+
+ if (buflen > MCLBYTES)
+ return (EINVAL);
+
+ in = malloc(buflen, M_TEMP, M_WAITOK);
+ error = copyin(buf, in, buflen);
+ if (error != 0)
+ goto out;
+
+ /*
+ * Make a pass over the input buffer to determine the amount of space
+ * required for 64 bit-aligned copies of the control messages.
+ */
+ in1 = in;
+ outlen = 0;
+ while (buflen > 0) {
+ if (buflen < sizeof(*cm)) {
+ error = EINVAL;
+ break;
+ }
+ cm = (struct cmsghdr *)in1;
+ if (cm->cmsg_len < FREEBSD32_ALIGN(sizeof(*cm))) {
+ error = EINVAL;
+ break;
+ }
+ msglen = FREEBSD32_ALIGN(cm->cmsg_len);
+ if (msglen > buflen || msglen < cm->cmsg_len) {
+ error = EINVAL;
+ break;
+ }
+ buflen -= msglen;
+
+ in1 = (char *)in1 + msglen;
+ outlen += CMSG_ALIGN(sizeof(*cm)) +
+ CMSG_ALIGN(msglen - FREEBSD32_ALIGN(sizeof(*cm)));
+ }
+ if (error == 0 && outlen > MCLBYTES) {
+ /*
+ * XXXMJ This implies that the upper limit on 32-bit aligned
+ * control messages is less than MCLBYTES, and so we are not
+ * perfectly compatible. However, there is no platform
+ * guarantee that mbuf clusters larger than MCLBYTES can be
+ * allocated.
+ */
+ error = EINVAL;
+ }
+ if (error != 0)
+ goto out;
+
+ m = m_get2(outlen, M_WAITOK, MT_CONTROL, 0);
+ m->m_len = outlen;
+ md = mtod(m, void *);
+
+ /*
+ * Make a second pass over input messages, copying them into the output
+ * buffer.
+ */
+ in1 = in;
+ while (outlen > 0) {
+ /* Copy the message header and align the length field. */
+ cm = md;
+ memcpy(cm, in1, sizeof(*cm));
+ msglen = cm->cmsg_len - FREEBSD32_ALIGN(sizeof(*cm));
+ cm->cmsg_len = CMSG_ALIGN(sizeof(*cm)) + msglen;
+
+ /* Copy the message body. */
+ in1 = (char *)in1 + FREEBSD32_ALIGN(sizeof(*cm));
+ md = (char *)md + CMSG_ALIGN(sizeof(*cm));
+ memcpy(md, in1, msglen);
+ in1 = (char *)in1 + FREEBSD32_ALIGN(msglen);
+ md = (char *)md + CMSG_ALIGN(msglen);
+ KASSERT(outlen >= CMSG_ALIGN(sizeof(*cm)) + CMSG_ALIGN(msglen),
+ ("outlen %u underflow, msglen %u", outlen, msglen));
+ outlen -= CMSG_ALIGN(sizeof(*cm)) + CMSG_ALIGN(msglen);
+ }
+
+ *mp = m;
+out:
+ free(in, M_TEMP);
+ return (error);
+}
+
+int
+freebsd32_sendmsg(struct thread *td,
+ struct freebsd32_sendmsg_args *uap)
+{
+ struct msghdr msg;
+ struct msghdr32 m32;
+ struct iovec *iov;
+ struct mbuf *control = NULL;
+ struct sockaddr *to = NULL;
+ int error;
+
+ error = copyin(uap->msg, &m32, sizeof(m32));
+ if (error)
+ return (error);
+ error = freebsd32_copyinmsghdr(uap->msg, &msg);
+ if (error)
+ return (error);
+ error = freebsd32_copyiniov(PTRIN(m32.msg_iov), m32.msg_iovlen, &iov,
+ EMSGSIZE);
+ if (error)
+ return (error);
+ msg.msg_iov = iov;
+ if (msg.msg_name != NULL) {
+ error = getsockaddr(&to, msg.msg_name, msg.msg_namelen);
+ if (error) {
+ to = NULL;
+ goto out;
+ }
+ msg.msg_name = to;
+ }
+
+ if (msg.msg_control) {
+ if (msg.msg_controllen < sizeof(struct cmsghdr)) {
+ error = EINVAL;
+ goto out;
+ }
+
+ error = freebsd32_copyin_control(&control, msg.msg_control,
+ msg.msg_controllen);
+ if (error)
+ goto out;
+
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ }
+
+ error = kern_sendit(td, uap->s, &msg, uap->flags, control,
+ UIO_USERSPACE);
+
+out:
+ free(iov, M_IOV);
+ if (to)
+ free(to, M_SONAME);
+ return (error);
+}
+
+int
+freebsd32_recvfrom(struct thread *td,
+ struct freebsd32_recvfrom_args *uap)
+{
+ struct msghdr msg;
+ struct iovec aiov;
+ int error;
+
+ if (uap->fromlenaddr) {
+ error = copyin(PTRIN(uap->fromlenaddr), &msg.msg_namelen,
+ sizeof(msg.msg_namelen));
+ if (error)
+ return (error);
+ } else {
+ msg.msg_namelen = 0;
+ }
+
+ msg.msg_name = PTRIN(uap->from);
+ msg.msg_iov = &aiov;
+ msg.msg_iovlen = 1;
+ aiov.iov_base = PTRIN(uap->buf);
+ aiov.iov_len = uap->len;
+ msg.msg_control = NULL;
+ msg.msg_flags = uap->flags;
+ error = kern_recvit(td, uap->s, &msg, UIO_USERSPACE, NULL);
+ if (error == 0 && uap->fromlenaddr)
+ error = copyout(&msg.msg_namelen, PTRIN(uap->fromlenaddr),
+ sizeof (msg.msg_namelen));
+ return (error);
+}
+
+int
+freebsd32_settimeofday(struct thread *td,
+ struct freebsd32_settimeofday_args *uap)
+{
+ struct timeval32 tv32;
+ struct timeval tv, *tvp;
+ struct timezone tz, *tzp;
+ int error;
+
+ if (uap->tv) {
+ error = copyin(uap->tv, &tv32, sizeof(tv32));
+ if (error)
+ return (error);
+ CP(tv32, tv, tv_sec);
+ CP(tv32, tv, tv_usec);
+ tvp = &tv;
+ } else
+ tvp = NULL;
+ if (uap->tzp) {
+ error = copyin(uap->tzp, &tz, sizeof(tz));
+ if (error)
+ return (error);
+ tzp = &tz;
+ } else
+ tzp = NULL;
+ return (kern_settimeofday(td, tvp, tzp));
+}
+
+int
+freebsd32_utimes(struct thread *td, struct freebsd32_utimes_args *uap)
+{
+ struct timeval32 s32[2];
+ struct timeval s[2], *sp;
+ int error;
+
+ if (uap->tptr != NULL) {
+ error = copyin(uap->tptr, s32, sizeof(s32));
+ if (error)
+ return (error);
+ CP(s32[0], s[0], tv_sec);
+ CP(s32[0], s[0], tv_usec);
+ CP(s32[1], s[1], tv_sec);
+ CP(s32[1], s[1], tv_usec);
+ sp = s;
+ } else
+ sp = NULL;
+ return (kern_utimesat(td, AT_FDCWD, uap->path, UIO_USERSPACE,
+ sp, UIO_SYSSPACE));
+}
+
+int
+freebsd32_lutimes(struct thread *td, struct freebsd32_lutimes_args *uap)
+{
+ struct timeval32 s32[2];
+ struct timeval s[2], *sp;
+ int error;
+
+ if (uap->tptr != NULL) {
+ error = copyin(uap->tptr, s32, sizeof(s32));
+ if (error)
+ return (error);
+ CP(s32[0], s[0], tv_sec);
+ CP(s32[0], s[0], tv_usec);
+ CP(s32[1], s[1], tv_sec);
+ CP(s32[1], s[1], tv_usec);
+ sp = s;
+ } else
+ sp = NULL;
+ return (kern_lutimes(td, uap->path, UIO_USERSPACE, sp, UIO_SYSSPACE));
+}
+
+int
+freebsd32_futimes(struct thread *td, struct freebsd32_futimes_args *uap)
+{
+ struct timeval32 s32[2];
+ struct timeval s[2], *sp;
+ int error;
+
+ if (uap->tptr != NULL) {
+ error = copyin(uap->tptr, s32, sizeof(s32));
+ if (error)
+ return (error);
+ CP(s32[0], s[0], tv_sec);
+ CP(s32[0], s[0], tv_usec);
+ CP(s32[1], s[1], tv_sec);
+ CP(s32[1], s[1], tv_usec);
+ sp = s;
+ } else
+ sp = NULL;
+ return (kern_futimes(td, uap->fd, sp, UIO_SYSSPACE));
+}
+
+int
+freebsd32_futimesat(struct thread *td, struct freebsd32_futimesat_args *uap)
+{
+ struct timeval32 s32[2];
+ struct timeval s[2], *sp;
+ int error;
+
+ if (uap->times != NULL) {
+ error = copyin(uap->times, s32, sizeof(s32));
+ if (error)
+ return (error);
+ CP(s32[0], s[0], tv_sec);
+ CP(s32[0], s[0], tv_usec);
+ CP(s32[1], s[1], tv_sec);
+ CP(s32[1], s[1], tv_usec);
+ sp = s;
+ } else
+ sp = NULL;
+ return (kern_utimesat(td, uap->fd, uap->path, UIO_USERSPACE,
+ sp, UIO_SYSSPACE));
+}
+
+int
+freebsd32_futimens(struct thread *td, struct freebsd32_futimens_args *uap)
+{
+ struct timespec32 ts32[2];
+ struct timespec ts[2], *tsp;
+ int error;
+
+ if (uap->times != NULL) {
+ error = copyin(uap->times, ts32, sizeof(ts32));
+ if (error)
+ return (error);
+ CP(ts32[0], ts[0], tv_sec);
+ CP(ts32[0], ts[0], tv_nsec);
+ CP(ts32[1], ts[1], tv_sec);
+ CP(ts32[1], ts[1], tv_nsec);
+ tsp = ts;
+ } else
+ tsp = NULL;
+ return (kern_futimens(td, uap->fd, tsp, UIO_SYSSPACE));
+}
+
+int
+freebsd32_utimensat(struct thread *td, struct freebsd32_utimensat_args *uap)
+{
+ struct timespec32 ts32[2];
+ struct timespec ts[2], *tsp;
+ int error;
+
+ if (uap->times != NULL) {
+ error = copyin(uap->times, ts32, sizeof(ts32));
+ if (error)
+ return (error);
+ CP(ts32[0], ts[0], tv_sec);
+ CP(ts32[0], ts[0], tv_nsec);
+ CP(ts32[1], ts[1], tv_sec);
+ CP(ts32[1], ts[1], tv_nsec);
+ tsp = ts;
+ } else
+ tsp = NULL;
+ return (kern_utimensat(td, uap->fd, uap->path, UIO_USERSPACE,
+ tsp, UIO_SYSSPACE, uap->flag));
+}
+
+int
+freebsd32_adjtime(struct thread *td, struct freebsd32_adjtime_args *uap)
+{
+ struct timeval32 tv32;
+ struct timeval delta, olddelta, *deltap;
+ int error;
+
+ if (uap->delta) {
+ error = copyin(uap->delta, &tv32, sizeof(tv32));
+ if (error)
+ return (error);
+ CP(tv32, delta, tv_sec);
+ CP(tv32, delta, tv_usec);
+ deltap = &delta;
+ } else
+ deltap = NULL;
+ error = kern_adjtime(td, deltap, &olddelta);
+ if (uap->olddelta && error == 0) {
+ CP(olddelta, tv32, tv_sec);
+ CP(olddelta, tv32, tv_usec);
+ error = copyout(&tv32, uap->olddelta, sizeof(tv32));
+ }
+ return (error);
+}
+
+#ifdef COMPAT_FREEBSD4
+int
+freebsd4_freebsd32_statfs(struct thread *td, struct freebsd4_freebsd32_statfs_args *uap)
+{
+ struct statfs32 s32;
+ struct statfs *sp;
+ int error;
+
+ sp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
+ error = kern_statfs(td, uap->path, UIO_USERSPACE, sp);
+ if (error == 0) {
+ copy_statfs(sp, &s32);
+ error = copyout(&s32, uap->buf, sizeof(s32));
+ }
+ free(sp, M_STATFS);
+ return (error);
+}
+#endif
+
+#ifdef COMPAT_FREEBSD4
+int
+freebsd4_freebsd32_fstatfs(struct thread *td, struct freebsd4_freebsd32_fstatfs_args *uap)
+{
+ struct statfs32 s32;
+ struct statfs *sp;
+ int error;
+
+ sp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
+ error = kern_fstatfs(td, uap->fd, sp);
+ if (error == 0) {
+ copy_statfs(sp, &s32);
+ error = copyout(&s32, uap->buf, sizeof(s32));
+ }
+ free(sp, M_STATFS);
+ return (error);
+}
+#endif
+
+#ifdef COMPAT_FREEBSD4
+int
+freebsd4_freebsd32_fhstatfs(struct thread *td, struct freebsd4_freebsd32_fhstatfs_args *uap)
+{
+ struct statfs32 s32;
+ struct statfs *sp;
+ fhandle_t fh;
+ int error;
+
+ if ((error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t))) != 0)
+ return (error);
+ sp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
+ error = kern_fhstatfs(td, fh, sp);
+ if (error == 0) {
+ copy_statfs(sp, &s32);
+ error = copyout(&s32, uap->buf, sizeof(s32));
+ }
+ free(sp, M_STATFS);
+ return (error);
+}
+#endif
+
+int
+freebsd32_pread(struct thread *td, struct freebsd32_pread_args *uap)
+{
+
+ return (kern_pread(td, uap->fd, uap->buf, uap->nbyte,
+ PAIR32TO64(off_t, uap->offset)));
+}
+
+int
+freebsd32_pwrite(struct thread *td, struct freebsd32_pwrite_args *uap)
+{
+
+ return (kern_pwrite(td, uap->fd, uap->buf, uap->nbyte,
+ PAIR32TO64(off_t, uap->offset)));
+}
+
+#ifdef COMPAT_43
+int
+ofreebsd32_lseek(struct thread *td, struct ofreebsd32_lseek_args *uap)
+{
+
+ return (kern_lseek(td, uap->fd, uap->offset, uap->whence));
+}
+#endif
+
+int
+freebsd32_lseek(struct thread *td, struct freebsd32_lseek_args *uap)
+{
+ int error;
+ off_t pos;
+
+ error = kern_lseek(td, uap->fd, PAIR32TO64(off_t, uap->offset),
+ uap->whence);
+ /* Expand the quad return into two parts for eax and edx */
+ pos = td->td_uretoff.tdu_off;
+ td->td_retval[RETVAL_LO] = pos & 0xffffffff; /* %eax */
+ td->td_retval[RETVAL_HI] = pos >> 32; /* %edx */
+ return error;
+}
+
+int
+freebsd32_truncate(struct thread *td, struct freebsd32_truncate_args *uap)
+{
+
+ return (kern_truncate(td, uap->path, UIO_USERSPACE,
+ PAIR32TO64(off_t, uap->length)));
+}
+
+int
+freebsd32_ftruncate(struct thread *td, struct freebsd32_ftruncate_args *uap)
+{
+
+ return (kern_ftruncate(td, uap->fd, PAIR32TO64(off_t, uap->length)));
+}
+
+#ifdef COMPAT_43
+int
+ofreebsd32_getdirentries(struct thread *td,
+ struct ofreebsd32_getdirentries_args *uap)
+{
+ struct ogetdirentries_args ap;
+ int error;
+ long loff;
+ int32_t loff_cut;
+
+ ap.fd = uap->fd;
+ ap.buf = uap->buf;
+ ap.count = uap->count;
+ ap.basep = NULL;
+ error = kern_ogetdirentries(td, &ap, &loff);
+ if (error == 0) {
+ loff_cut = loff;
+ error = copyout(&loff_cut, uap->basep, sizeof(int32_t));
+ }
+ return (error);
+}
+#endif
+
+#if defined(COMPAT_FREEBSD11)
+int
+freebsd11_freebsd32_getdirentries(struct thread *td,
+ struct freebsd11_freebsd32_getdirentries_args *uap)
+{
+ long base;
+ int32_t base32;
+ int error;
+
+ error = freebsd11_kern_getdirentries(td, uap->fd, uap->buf, uap->count,
+ &base, NULL);
+ if (error)
+ return (error);
+ if (uap->basep != NULL) {
+ base32 = base;
+ error = copyout(&base32, uap->basep, sizeof(int32_t));
+ }
+ return (error);
+}
+
+int
+freebsd11_freebsd32_getdents(struct thread *td,
+ struct freebsd11_freebsd32_getdents_args *uap)
+{
+ struct freebsd11_freebsd32_getdirentries_args ap;
+
+ ap.fd = uap->fd;
+ ap.buf = uap->buf;
+ ap.count = uap->count;
+ ap.basep = NULL;
+ return (freebsd11_freebsd32_getdirentries(td, &ap));
+}
+#endif /* COMPAT_FREEBSD11 */
+
+#ifdef COMPAT_FREEBSD6
+/* versions with the 'int pad' argument */
+int
+freebsd6_freebsd32_pread(struct thread *td, struct freebsd6_freebsd32_pread_args *uap)
+{
+
+ return (kern_pread(td, uap->fd, uap->buf, uap->nbyte,
+ PAIR32TO64(off_t, uap->offset)));
+}
+
+int
+freebsd6_freebsd32_pwrite(struct thread *td, struct freebsd6_freebsd32_pwrite_args *uap)
+{
+
+ return (kern_pwrite(td, uap->fd, uap->buf, uap->nbyte,
+ PAIR32TO64(off_t, uap->offset)));
+}
+
+int
+freebsd6_freebsd32_lseek(struct thread *td, struct freebsd6_freebsd32_lseek_args *uap)
+{
+ int error;
+ off_t pos;
+
+ error = kern_lseek(td, uap->fd, PAIR32TO64(off_t, uap->offset),
+ uap->whence);
+ /* Expand the quad return into two parts for eax and edx */
+ pos = *(off_t *)(td->td_retval);
+ td->td_retval[RETVAL_LO] = pos & 0xffffffff; /* %eax */
+ td->td_retval[RETVAL_HI] = pos >> 32; /* %edx */
+ return error;
+}
+
+int
+freebsd6_freebsd32_truncate(struct thread *td, struct freebsd6_freebsd32_truncate_args *uap)
+{
+
+ return (kern_truncate(td, uap->path, UIO_USERSPACE,
+ PAIR32TO64(off_t, uap->length)));
+}
+
+int
+freebsd6_freebsd32_ftruncate(struct thread *td, struct freebsd6_freebsd32_ftruncate_args *uap)
+{
+
+ return (kern_ftruncate(td, uap->fd, PAIR32TO64(off_t, uap->length)));
+}
+#endif /* COMPAT_FREEBSD6 */
+
+struct sf_hdtr32 {
+ uint32_t headers;
+ int hdr_cnt;
+ uint32_t trailers;
+ int trl_cnt;
+};
+
+static int
+freebsd32_do_sendfile(struct thread *td,
+ struct freebsd32_sendfile_args *uap, int compat)
+{
+ struct sf_hdtr32 hdtr32;
+ struct sf_hdtr hdtr;
+ struct uio *hdr_uio, *trl_uio;
+ struct file *fp;
+ cap_rights_t rights;
+ struct iovec32 *iov32;
+ off_t offset, sbytes;
+ int error;
+
+ offset = PAIR32TO64(off_t, uap->offset);
+ if (offset < 0)
+ return (EINVAL);
+
+ hdr_uio = trl_uio = NULL;
+
+ if (uap->hdtr != NULL) {
+ error = copyin(uap->hdtr, &hdtr32, sizeof(hdtr32));
+ if (error)
+ goto out;
+ PTRIN_CP(hdtr32, hdtr, headers);
+ CP(hdtr32, hdtr, hdr_cnt);
+ PTRIN_CP(hdtr32, hdtr, trailers);
+ CP(hdtr32, hdtr, trl_cnt);
+
+ if (hdtr.headers != NULL) {
+ iov32 = PTRIN(hdtr32.headers);
+ error = freebsd32_copyinuio(iov32,
+ hdtr32.hdr_cnt, &hdr_uio);
+ if (error)
+ goto out;
+#ifdef COMPAT_FREEBSD4
+ /*
+ * In FreeBSD < 5.0 the nbytes to send also included
+ * the header. If compat is specified subtract the
+ * header size from nbytes.
+ */
+ if (compat) {
+ if (uap->nbytes > hdr_uio->uio_resid)
+ uap->nbytes -= hdr_uio->uio_resid;
+ else
+ uap->nbytes = 0;
+ }
+#endif
+ }
+ if (hdtr.trailers != NULL) {
+ iov32 = PTRIN(hdtr32.trailers);
+ error = freebsd32_copyinuio(iov32,
+ hdtr32.trl_cnt, &trl_uio);
+ if (error)
+ goto out;
+ }
+ }
+
+ AUDIT_ARG_FD(uap->fd);
+
+ if ((error = fget_read(td, uap->fd,
+ cap_rights_init_one(&rights, CAP_PREAD), &fp)) != 0)
+ goto out;
+
+ error = fo_sendfile(fp, uap->s, hdr_uio, trl_uio, offset,
+ uap->nbytes, &sbytes, uap->flags, td);
+ fdrop(fp, td);
+
+ if (uap->sbytes != NULL)
+ copyout(&sbytes, uap->sbytes, sizeof(off_t));
+
+out:
+ if (hdr_uio)
+ free(hdr_uio, M_IOV);
+ if (trl_uio)
+ free(trl_uio, M_IOV);
+ return (error);
+}
+
+#ifdef COMPAT_FREEBSD4
+int
+freebsd4_freebsd32_sendfile(struct thread *td,
+ struct freebsd4_freebsd32_sendfile_args *uap)
+{
+ return (freebsd32_do_sendfile(td,
+ (struct freebsd32_sendfile_args *)uap, 1));
+}
+#endif
+
+int
+freebsd32_sendfile(struct thread *td, struct freebsd32_sendfile_args *uap)
+{
+
+ return (freebsd32_do_sendfile(td, uap, 0));
+}
+
+static void
+copy_stat(struct stat *in, struct stat32 *out)
+{
+
+ CP(*in, *out, st_dev);
+ CP(*in, *out, st_ino);
+ CP(*in, *out, st_mode);
+ CP(*in, *out, st_nlink);
+ CP(*in, *out, st_uid);
+ CP(*in, *out, st_gid);
+ CP(*in, *out, st_rdev);
+ TS_CP(*in, *out, st_atim);
+ TS_CP(*in, *out, st_mtim);
+ TS_CP(*in, *out, st_ctim);
+ CP(*in, *out, st_size);
+ CP(*in, *out, st_blocks);
+ CP(*in, *out, st_blksize);
+ CP(*in, *out, st_flags);
+ CP(*in, *out, st_gen);
+ TS_CP(*in, *out, st_birthtim);
+ out->st_padding0 = 0;
+ out->st_padding1 = 0;
+#ifdef __STAT32_TIME_T_EXT
+ out->st_atim_ext = 0;
+ out->st_mtim_ext = 0;
+ out->st_ctim_ext = 0;
+ out->st_btim_ext = 0;
+#endif
+ bzero(out->st_spare, sizeof(out->st_spare));
+}
+
+#ifdef COMPAT_43
+static void
+copy_ostat(struct stat *in, struct ostat32 *out)
+{
+
+ bzero(out, sizeof(*out));
+ CP(*in, *out, st_dev);
+ CP(*in, *out, st_ino);
+ CP(*in, *out, st_mode);
+ CP(*in, *out, st_nlink);
+ CP(*in, *out, st_uid);
+ CP(*in, *out, st_gid);
+ CP(*in, *out, st_rdev);
+ out->st_size = MIN(in->st_size, INT32_MAX);
+ TS_CP(*in, *out, st_atim);
+ TS_CP(*in, *out, st_mtim);
+ TS_CP(*in, *out, st_ctim);
+ CP(*in, *out, st_blksize);
+ CP(*in, *out, st_blocks);
+ CP(*in, *out, st_flags);
+ CP(*in, *out, st_gen);
+}
+#endif
+
+#ifdef COMPAT_43
+int
+ofreebsd32_stat(struct thread *td, struct ofreebsd32_stat_args *uap)
+{
+ struct stat sb;
+ struct ostat32 sb32;
+ int error;
+
+ error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE,
+ &sb, NULL);
+ if (error)
+ return (error);
+ copy_ostat(&sb, &sb32);
+ error = copyout(&sb32, uap->ub, sizeof (sb32));
+ return (error);
+}
+#endif
+
+int
+freebsd32_fstat(struct thread *td, struct freebsd32_fstat_args *uap)
+{
+ struct stat ub;
+ struct stat32 ub32;
+ int error;
+
+ error = kern_fstat(td, uap->fd, &ub);
+ if (error)
+ return (error);
+ copy_stat(&ub, &ub32);
+ error = copyout(&ub32, uap->ub, sizeof(ub32));
+ return (error);
+}
+
+#ifdef COMPAT_43
+int
+ofreebsd32_fstat(struct thread *td, struct ofreebsd32_fstat_args *uap)
+{
+ struct stat ub;
+ struct ostat32 ub32;
+ int error;
+
+ error = kern_fstat(td, uap->fd, &ub);
+ if (error)
+ return (error);
+ copy_ostat(&ub, &ub32);
+ error = copyout(&ub32, uap->ub, sizeof(ub32));
+ return (error);
+}
+#endif
+
+int
+freebsd32_fstatat(struct thread *td, struct freebsd32_fstatat_args *uap)
+{
+ struct stat ub;
+ struct stat32 ub32;
+ int error;
+
+ error = kern_statat(td, uap->flag, uap->fd, uap->path, UIO_USERSPACE,
+ &ub, NULL);
+ if (error)
+ return (error);
+ copy_stat(&ub, &ub32);
+ error = copyout(&ub32, uap->buf, sizeof(ub32));
+ return (error);
+}
+
+#ifdef COMPAT_43
+int
+ofreebsd32_lstat(struct thread *td, struct ofreebsd32_lstat_args *uap)
+{
+ struct stat sb;
+ struct ostat32 sb32;
+ int error;
+
+ error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path,
+ UIO_USERSPACE, &sb, NULL);
+ if (error)
+ return (error);
+ copy_ostat(&sb, &sb32);
+ error = copyout(&sb32, uap->ub, sizeof (sb32));
+ return (error);
+}
+#endif
+
+int
+freebsd32_fhstat(struct thread *td, struct freebsd32_fhstat_args *uap)
+{
+ struct stat sb;
+ struct stat32 sb32;
+ struct fhandle fh;
+ int error;
+
+ error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t));
+ if (error != 0)
+ return (error);
+ error = kern_fhstat(td, fh, &sb);
+ if (error != 0)
+ return (error);
+ copy_stat(&sb, &sb32);
+ error = copyout(&sb32, uap->sb, sizeof (sb32));
+ return (error);
+}
+
+#if defined(COMPAT_FREEBSD11)
+extern int ino64_trunc_error;
+
+static int
+freebsd11_cvtstat32(struct stat *in, struct freebsd11_stat32 *out)
+{
+
+ CP(*in, *out, st_ino);
+ if (in->st_ino != out->st_ino) {
+ switch (ino64_trunc_error) {
+ default:
+ case 0:
+ break;
+ case 1:
+ return (EOVERFLOW);
+ case 2:
+ out->st_ino = UINT32_MAX;
+ break;
+ }
+ }
+ CP(*in, *out, st_nlink);
+ if (in->st_nlink != out->st_nlink) {
+ switch (ino64_trunc_error) {
+ default:
+ case 0:
+ break;
+ case 1:
+ return (EOVERFLOW);
+ case 2:
+ out->st_nlink = UINT16_MAX;
+ break;
+ }
+ }
+ out->st_dev = in->st_dev;
+ if (out->st_dev != in->st_dev) {
+ switch (ino64_trunc_error) {
+ default:
+ break;
+ case 1:
+ return (EOVERFLOW);
+ }
+ }
+ CP(*in, *out, st_mode);
+ CP(*in, *out, st_uid);
+ CP(*in, *out, st_gid);
+ out->st_rdev = in->st_rdev;
+ if (out->st_rdev != in->st_rdev) {
+ switch (ino64_trunc_error) {
+ default:
+ break;
+ case 1:
+ return (EOVERFLOW);
+ }
+ }
+ TS_CP(*in, *out, st_atim);
+ TS_CP(*in, *out, st_mtim);
+ TS_CP(*in, *out, st_ctim);
+ CP(*in, *out, st_size);
+ CP(*in, *out, st_blocks);
+ CP(*in, *out, st_blksize);
+ CP(*in, *out, st_flags);
+ CP(*in, *out, st_gen);
+ TS_CP(*in, *out, st_birthtim);
+ out->st_lspare = 0;
+ bzero((char *)&out->st_birthtim + sizeof(out->st_birthtim),
+ sizeof(*out) - offsetof(struct freebsd11_stat32,
+ st_birthtim) - sizeof(out->st_birthtim));
+ return (0);
+}
+
+int
+freebsd11_freebsd32_stat(struct thread *td,
+ struct freebsd11_freebsd32_stat_args *uap)
+{
+ struct stat sb;
+ struct freebsd11_stat32 sb32;
+ int error;
+
+ error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE,
+ &sb, NULL);
+ if (error != 0)
+ return (error);
+ error = freebsd11_cvtstat32(&sb, &sb32);
+ if (error == 0)
+ error = copyout(&sb32, uap->ub, sizeof (sb32));
+ return (error);
+}
+
+int
+freebsd11_freebsd32_fstat(struct thread *td,
+ struct freebsd11_freebsd32_fstat_args *uap)
+{
+ struct stat sb;
+ struct freebsd11_stat32 sb32;
+ int error;
+
+ error = kern_fstat(td, uap->fd, &sb);
+ if (error != 0)
+ return (error);
+ error = freebsd11_cvtstat32(&sb, &sb32);
+ if (error == 0)
+ error = copyout(&sb32, uap->ub, sizeof (sb32));
+ return (error);
+}
+
+int
+freebsd11_freebsd32_fstatat(struct thread *td,
+ struct freebsd11_freebsd32_fstatat_args *uap)
+{
+ struct stat sb;
+ struct freebsd11_stat32 sb32;
+ int error;
+
+ error = kern_statat(td, uap->flag, uap->fd, uap->path, UIO_USERSPACE,
+ &sb, NULL);
+ if (error != 0)
+ return (error);
+ error = freebsd11_cvtstat32(&sb, &sb32);
+ if (error == 0)
+ error = copyout(&sb32, uap->buf, sizeof (sb32));
+ return (error);
+}
+
+int
+freebsd11_freebsd32_lstat(struct thread *td,
+ struct freebsd11_freebsd32_lstat_args *uap)
+{
+ struct stat sb;
+ struct freebsd11_stat32 sb32;
+ int error;
+
+ error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path,
+ UIO_USERSPACE, &sb, NULL);
+ if (error != 0)
+ return (error);
+ error = freebsd11_cvtstat32(&sb, &sb32);
+ if (error == 0)
+ error = copyout(&sb32, uap->ub, sizeof (sb32));
+ return (error);
+}
+
+int
+freebsd11_freebsd32_fhstat(struct thread *td,
+ struct freebsd11_freebsd32_fhstat_args *uap)
+{
+ struct stat sb;
+ struct freebsd11_stat32 sb32;
+ struct fhandle fh;
+ int error;
+
+ error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t));
+ if (error != 0)
+ return (error);
+ error = kern_fhstat(td, fh, &sb);
+ if (error != 0)
+ return (error);
+ error = freebsd11_cvtstat32(&sb, &sb32);
+ if (error == 0)
+ error = copyout(&sb32, uap->sb, sizeof (sb32));
+ return (error);
+}
+#endif
+
+int
+freebsd32___sysctl(struct thread *td, struct freebsd32___sysctl_args *uap)
+{
+ int error, name[CTL_MAXNAME];
+ size_t j, oldlen;
+ uint32_t tmp;
+
+ if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
+ return (EINVAL);
+ error = copyin(uap->name, name, uap->namelen * sizeof(int));
+ if (error)
+ return (error);
+ if (uap->oldlenp) {
+ error = fueword32(uap->oldlenp, &tmp);
+ oldlen = tmp;
+ } else {
+ oldlen = 0;
+ }
+ if (error != 0)
+ return (EFAULT);
+ error = userland_sysctl(td, name, uap->namelen,
+ uap->old, &oldlen, 1,
+ uap->new, uap->newlen, &j, SCTL_MASK32);
+ if (error)
+ return (error);
+ if (uap->oldlenp)
+ suword32(uap->oldlenp, j);
+ return (0);
+}
+
+int
+freebsd32___sysctlbyname(struct thread *td,
+ struct freebsd32___sysctlbyname_args *uap)
+{
+ size_t oldlen, rv;
+ int error;
+ uint32_t tmp;
+
+ if (uap->oldlenp != NULL) {
+ error = fueword32(uap->oldlenp, &tmp);
+ oldlen = tmp;
+ } else {
+ error = oldlen = 0;
+ }
+ if (error != 0)
+ return (EFAULT);
+ error = kern___sysctlbyname(td, uap->name, uap->namelen, uap->old,
+ &oldlen, uap->new, uap->newlen, &rv, SCTL_MASK32, 1);
+ if (error != 0)
+ return (error);
+ if (uap->oldlenp != NULL)
+ error = suword32(uap->oldlenp, rv);
+
+ return (error);
+}
+
+int
+freebsd32_jail(struct thread *td, struct freebsd32_jail_args *uap)
+{
+ uint32_t version;
+ int error;
+ struct jail j;
+
+ error = copyin(uap->jail, &version, sizeof(uint32_t));
+ if (error)
+ return (error);
+
+ switch (version) {
+ case 0:
+ {
+ /* FreeBSD single IPv4 jails. */
+ struct jail32_v0 j32_v0;
+
+ bzero(&j, sizeof(struct jail));
+ error = copyin(uap->jail, &j32_v0, sizeof(struct jail32_v0));
+ if (error)
+ return (error);
+ CP(j32_v0, j, version);
+ PTRIN_CP(j32_v0, j, path);
+ PTRIN_CP(j32_v0, j, hostname);
+ j.ip4s = htonl(j32_v0.ip_number); /* jail_v0 is host order */
+ break;
+ }
+
+ case 1:
+ /*
+ * Version 1 was used by multi-IPv4 jail implementations
+ * that never made it into the official kernel.
+ */
+ return (EINVAL);
+
+ case 2: /* JAIL_API_VERSION */
+ {
+ /* FreeBSD multi-IPv4/IPv6,noIP jails. */
+ struct jail32 j32;
+
+ error = copyin(uap->jail, &j32, sizeof(struct jail32));
+ if (error)
+ return (error);
+ CP(j32, j, version);
+ PTRIN_CP(j32, j, path);
+ PTRIN_CP(j32, j, hostname);
+ PTRIN_CP(j32, j, jailname);
+ CP(j32, j, ip4s);
+ CP(j32, j, ip6s);
+ PTRIN_CP(j32, j, ip4);
+ PTRIN_CP(j32, j, ip6);
+ break;
+ }
+
+ default:
+ /* Sci-Fi jails are not supported, sorry. */
+ return (EINVAL);
+ }
+ return (kern_jail(td, &j));
+}
+
+int
+freebsd32_jail_set(struct thread *td, struct freebsd32_jail_set_args *uap)
+{
+ struct uio *auio;
+ int error;
+
+ /* Check that we have an even number of iovecs. */
+ if (uap->iovcnt & 1)
+ return (EINVAL);
+
+ error = freebsd32_copyinuio(uap->iovp, uap->iovcnt, &auio);
+ if (error)
+ return (error);
+ error = kern_jail_set(td, auio, uap->flags);
+ free(auio, M_IOV);
+ return (error);
+}
+
+int
+freebsd32_jail_get(struct thread *td, struct freebsd32_jail_get_args *uap)
+{
+ struct iovec32 iov32;
+ struct uio *auio;
+ int error, i;
+
+ /* Check that we have an even number of iovecs. */
+ if (uap->iovcnt & 1)
+ return (EINVAL);
+
+ error = freebsd32_copyinuio(uap->iovp, uap->iovcnt, &auio);
+ if (error)
+ return (error);
+ error = kern_jail_get(td, auio, uap->flags);
+ if (error == 0)
+ for (i = 0; i < uap->iovcnt; i++) {
+ PTROUT_CP(auio->uio_iov[i], iov32, iov_base);
+ CP(auio->uio_iov[i], iov32, iov_len);
+ error = copyout(&iov32, uap->iovp + i, sizeof(iov32));
+ if (error != 0)
+ break;
+ }
+ free(auio, M_IOV);
+ return (error);
+}
+
+int
+freebsd32_sigaction(struct thread *td, struct freebsd32_sigaction_args *uap)
+{
+ struct sigaction32 s32;
+ struct sigaction sa, osa, *sap;
+ int error;
+
+ if (uap->act) {
+ error = copyin(uap->act, &s32, sizeof(s32));
+ if (error)
+ return (error);
+ sa.sa_handler = PTRIN(s32.sa_u);
+ CP(s32, sa, sa_flags);
+ CP(s32, sa, sa_mask);
+ sap = &sa;
+ } else
+ sap = NULL;
+ error = kern_sigaction(td, uap->sig, sap, &osa, 0);
+ if (error == 0 && uap->oact != NULL) {
+ s32.sa_u = PTROUT(osa.sa_handler);
+ CP(osa, s32, sa_flags);
+ CP(osa, s32, sa_mask);
+ error = copyout(&s32, uap->oact, sizeof(s32));
+ }
+ return (error);
+}
+
+#ifdef COMPAT_FREEBSD4
+int
+freebsd4_freebsd32_sigaction(struct thread *td,
+ struct freebsd4_freebsd32_sigaction_args *uap)
+{
+ struct sigaction32 s32;
+ struct sigaction sa, osa, *sap;
+ int error;
+
+ if (uap->act) {
+ error = copyin(uap->act, &s32, sizeof(s32));
+ if (error)
+ return (error);
+ sa.sa_handler = PTRIN(s32.sa_u);
+ CP(s32, sa, sa_flags);
+ CP(s32, sa, sa_mask);
+ sap = &sa;
+ } else
+ sap = NULL;
+ error = kern_sigaction(td, uap->sig, sap, &osa, KSA_FREEBSD4);
+ if (error == 0 && uap->oact != NULL) {
+ s32.sa_u = PTROUT(osa.sa_handler);
+ CP(osa, s32, sa_flags);
+ CP(osa, s32, sa_mask);
+ error = copyout(&s32, uap->oact, sizeof(s32));
+ }
+ return (error);
+}
+#endif
+
+#ifdef COMPAT_43
+struct osigaction32 {
+ u_int32_t sa_u;
+ osigset_t sa_mask;
+ int sa_flags;
+};
+
+#define ONSIG 32
+
+int
+ofreebsd32_sigaction(struct thread *td,
+ struct ofreebsd32_sigaction_args *uap)
+{
+ struct osigaction32 s32;
+ struct sigaction sa, osa, *sap;
+ int error;
+
+ if (uap->signum <= 0 || uap->signum >= ONSIG)
+ return (EINVAL);
+
+ if (uap->nsa) {
+ error = copyin(uap->nsa, &s32, sizeof(s32));
+ if (error)
+ return (error);
+ sa.sa_handler = PTRIN(s32.sa_u);
+ CP(s32, sa, sa_flags);
+ OSIG2SIG(s32.sa_mask, sa.sa_mask);
+ sap = &sa;
+ } else
+ sap = NULL;
+ error = kern_sigaction(td, uap->signum, sap, &osa, KSA_OSIGSET);
+ if (error == 0 && uap->osa != NULL) {
+ s32.sa_u = PTROUT(osa.sa_handler);
+ CP(osa, s32, sa_flags);
+ SIG2OSIG(osa.sa_mask, s32.sa_mask);
+ error = copyout(&s32, uap->osa, sizeof(s32));
+ }
+ return (error);
+}
+
+int
+ofreebsd32_sigprocmask(struct thread *td,
+ struct ofreebsd32_sigprocmask_args *uap)
+{
+ sigset_t set, oset;
+ int error;
+
+ OSIG2SIG(uap->mask, set);
+ error = kern_sigprocmask(td, uap->how, &set, &oset, SIGPROCMASK_OLD);
+ SIG2OSIG(oset, td->td_retval[0]);
+ return (error);
+}
+
+int
+ofreebsd32_sigpending(struct thread *td,
+ struct ofreebsd32_sigpending_args *uap)
+{
+ struct proc *p = td->td_proc;
+ sigset_t siglist;
+
+ PROC_LOCK(p);
+ siglist = p->p_siglist;
+ SIGSETOR(siglist, td->td_siglist);
+ PROC_UNLOCK(p);
+ SIG2OSIG(siglist, td->td_retval[0]);
+ return (0);
+}
+
+struct sigvec32 {
+ u_int32_t sv_handler;
+ int sv_mask;
+ int sv_flags;
+};
+
+int
+ofreebsd32_sigvec(struct thread *td,
+ struct ofreebsd32_sigvec_args *uap)
+{
+ struct sigvec32 vec;
+ struct sigaction sa, osa, *sap;
+ int error;
+
+ if (uap->signum <= 0 || uap->signum >= ONSIG)
+ return (EINVAL);
+
+ if (uap->nsv) {
+ error = copyin(uap->nsv, &vec, sizeof(vec));
+ if (error)
+ return (error);
+ sa.sa_handler = PTRIN(vec.sv_handler);
+ OSIG2SIG(vec.sv_mask, sa.sa_mask);
+ sa.sa_flags = vec.sv_flags;
+ sa.sa_flags ^= SA_RESTART;
+ sap = &sa;
+ } else
+ sap = NULL;
+ error = kern_sigaction(td, uap->signum, sap, &osa, KSA_OSIGSET);
+ if (error == 0 && uap->osv != NULL) {
+ vec.sv_handler = PTROUT(osa.sa_handler);
+ SIG2OSIG(osa.sa_mask, vec.sv_mask);
+ vec.sv_flags = osa.sa_flags;
+ vec.sv_flags &= ~SA_NOCLDWAIT;
+ vec.sv_flags ^= SA_RESTART;
+ error = copyout(&vec, uap->osv, sizeof(vec));
+ }
+ return (error);
+}
+
+int
+ofreebsd32_sigblock(struct thread *td,
+ struct ofreebsd32_sigblock_args *uap)
+{
+ sigset_t set, oset;
+
+ OSIG2SIG(uap->mask, set);
+ kern_sigprocmask(td, SIG_BLOCK, &set, &oset, 0);
+ SIG2OSIG(oset, td->td_retval[0]);
+ return (0);
+}
+
+int
+ofreebsd32_sigsetmask(struct thread *td,
+ struct ofreebsd32_sigsetmask_args *uap)
+{
+ sigset_t set, oset;
+
+ OSIG2SIG(uap->mask, set);
+ kern_sigprocmask(td, SIG_SETMASK, &set, &oset, 0);
+ SIG2OSIG(oset, td->td_retval[0]);
+ return (0);
+}
+
+int
+ofreebsd32_sigsuspend(struct thread *td,
+ struct ofreebsd32_sigsuspend_args *uap)
+{
+ sigset_t mask;
+
+ OSIG2SIG(uap->mask, mask);
+ return (kern_sigsuspend(td, mask));
+}
+
+struct sigstack32 {
+ u_int32_t ss_sp;
+ int ss_onstack;
+};
+
+int
+ofreebsd32_sigstack(struct thread *td,
+ struct ofreebsd32_sigstack_args *uap)
+{
+ struct sigstack32 s32;
+ struct sigstack nss, oss;
+ int error = 0, unss;
+
+ if (uap->nss != NULL) {
+ error = copyin(uap->nss, &s32, sizeof(s32));
+ if (error)
+ return (error);
+ nss.ss_sp = PTRIN(s32.ss_sp);
+ CP(s32, nss, ss_onstack);
+ unss = 1;
+ } else {
+ unss = 0;
+ }
+ oss.ss_sp = td->td_sigstk.ss_sp;
+ oss.ss_onstack = sigonstack(cpu_getstack(td));
+ if (unss) {
+ td->td_sigstk.ss_sp = nss.ss_sp;
+ td->td_sigstk.ss_size = 0;
+ td->td_sigstk.ss_flags |= (nss.ss_onstack & SS_ONSTACK);
+ td->td_pflags |= TDP_ALTSTACK;
+ }
+ if (uap->oss != NULL) {
+ s32.ss_sp = PTROUT(oss.ss_sp);
+ CP(oss, s32, ss_onstack);
+ error = copyout(&s32, uap->oss, sizeof(s32));
+ }
+ return (error);
+}
+#endif
+
+int
+freebsd32_nanosleep(struct thread *td, struct freebsd32_nanosleep_args *uap)
+{
+
+ return (freebsd32_user_clock_nanosleep(td, CLOCK_REALTIME,
+ TIMER_RELTIME, uap->rqtp, uap->rmtp));
+}
+
+int
+freebsd32_clock_nanosleep(struct thread *td,
+ struct freebsd32_clock_nanosleep_args *uap)
+{
+ int error;
+
+ error = freebsd32_user_clock_nanosleep(td, uap->clock_id, uap->flags,
+ uap->rqtp, uap->rmtp);
+ return (kern_posix_error(td, error));
+}
+
+static int
+freebsd32_user_clock_nanosleep(struct thread *td, clockid_t clock_id,
+ int flags, const struct timespec32 *ua_rqtp, struct timespec32 *ua_rmtp)
+{
+ struct timespec32 rmt32, rqt32;
+ struct timespec rmt, rqt;
+ int error, error2;
+
+ error = copyin(ua_rqtp, &rqt32, sizeof(rqt32));
+ if (error)
+ return (error);
+
+ CP(rqt32, rqt, tv_sec);
+ CP(rqt32, rqt, tv_nsec);
+
+ error = kern_clock_nanosleep(td, clock_id, flags, &rqt, &rmt);
+ if (error == EINTR && ua_rmtp != NULL && (flags & TIMER_ABSTIME) == 0) {
+ CP(rmt, rmt32, tv_sec);
+ CP(rmt, rmt32, tv_nsec);
+
+ error2 = copyout(&rmt32, ua_rmtp, sizeof(rmt32));
+ if (error2 != 0)
+ error = error2;
+ }
+ return (error);
+}
+
+int
+freebsd32_clock_gettime(struct thread *td,
+ struct freebsd32_clock_gettime_args *uap)
+{
+ struct timespec ats;
+ struct timespec32 ats32;
+ int error;
+
+ error = kern_clock_gettime(td, uap->clock_id, &ats);
+ if (error == 0) {
+ CP(ats, ats32, tv_sec);
+ CP(ats, ats32, tv_nsec);
+ error = copyout(&ats32, uap->tp, sizeof(ats32));
+ }
+ return (error);
+}
+
+int
+freebsd32_clock_settime(struct thread *td,
+ struct freebsd32_clock_settime_args *uap)
+{
+ struct timespec ats;
+ struct timespec32 ats32;
+ int error;
+
+ error = copyin(uap->tp, &ats32, sizeof(ats32));
+ if (error)
+ return (error);
+ CP(ats32, ats, tv_sec);
+ CP(ats32, ats, tv_nsec);
+
+ return (kern_clock_settime(td, uap->clock_id, &ats));
+}
+
+int
+freebsd32_clock_getres(struct thread *td,
+ struct freebsd32_clock_getres_args *uap)
+{
+ struct timespec ts;
+ struct timespec32 ts32;
+ int error;
+
+ if (uap->tp == NULL)
+ return (0);
+ error = kern_clock_getres(td, uap->clock_id, &ts);
+ if (error == 0) {
+ CP(ts, ts32, tv_sec);
+ CP(ts, ts32, tv_nsec);
+ error = copyout(&ts32, uap->tp, sizeof(ts32));
+ }
+ return (error);
+}
+
+int freebsd32_ktimer_create(struct thread *td,
+ struct freebsd32_ktimer_create_args *uap)
+{
+ struct sigevent32 ev32;
+ struct sigevent ev, *evp;
+ int error, id;
+
+ if (uap->evp == NULL) {
+ evp = NULL;
+ } else {
+ evp = &ev;
+ error = copyin(uap->evp, &ev32, sizeof(ev32));
+ if (error != 0)
+ return (error);
+ error = convert_sigevent32(&ev32, &ev);
+ if (error != 0)
+ return (error);
+ }
+ error = kern_ktimer_create(td, uap->clock_id, evp, &id, -1);
+ if (error == 0) {
+ error = copyout(&id, uap->timerid, sizeof(int));
+ if (error != 0)
+ kern_ktimer_delete(td, id);
+ }
+ return (error);
+}
+
+int
+freebsd32_ktimer_settime(struct thread *td,
+ struct freebsd32_ktimer_settime_args *uap)
+{
+ struct itimerspec32 val32, oval32;
+ struct itimerspec val, oval, *ovalp;
+ int error;
+
+ error = copyin(uap->value, &val32, sizeof(val32));
+ if (error != 0)
+ return (error);
+ ITS_CP(val32, val);
+ ovalp = uap->ovalue != NULL ? &oval : NULL;
+ error = kern_ktimer_settime(td, uap->timerid, uap->flags, &val, ovalp);
+ if (error == 0 && uap->ovalue != NULL) {
+ ITS_CP(oval, oval32);
+ error = copyout(&oval32, uap->ovalue, sizeof(oval32));
+ }
+ return (error);
+}
+
+int
+freebsd32_ktimer_gettime(struct thread *td,
+ struct freebsd32_ktimer_gettime_args *uap)
+{
+ struct itimerspec32 val32;
+ struct itimerspec val;
+ int error;
+
+ error = kern_ktimer_gettime(td, uap->timerid, &val);
+ if (error == 0) {
+ ITS_CP(val, val32);
+ error = copyout(&val32, uap->value, sizeof(val32));
+ }
+ return (error);
+}
+
+int
+freebsd32_clock_getcpuclockid2(struct thread *td,
+ struct freebsd32_clock_getcpuclockid2_args *uap)
+{
+ clockid_t clk_id;
+ int error;
+
+ error = kern_clock_getcpuclockid2(td, PAIR32TO64(id_t, uap->id),
+ uap->which, &clk_id);
+ if (error == 0)
+ error = copyout(&clk_id, uap->clock_id, sizeof(clockid_t));
+ return (error);
+}
+
+int
+freebsd32_thr_new(struct thread *td,
+ struct freebsd32_thr_new_args *uap)
+{
+ struct thr_param32 param32;
+ struct thr_param param;
+ int error;
+
+ if (uap->param_size < 0 ||
+ uap->param_size > sizeof(struct thr_param32))
+ return (EINVAL);
+ bzero(&param, sizeof(struct thr_param));
+ bzero(&param32, sizeof(struct thr_param32));
+ error = copyin(uap->param, &param32, uap->param_size);
+ if (error != 0)
+ return (error);
+ param.start_func = PTRIN(param32.start_func);
+ param.arg = PTRIN(param32.arg);
+ param.stack_base = PTRIN(param32.stack_base);
+ param.stack_size = param32.stack_size;
+ param.tls_base = PTRIN(param32.tls_base);
+ param.tls_size = param32.tls_size;
+ param.child_tid = PTRIN(param32.child_tid);
+ param.parent_tid = PTRIN(param32.parent_tid);
+ param.flags = param32.flags;
+ param.rtp = PTRIN(param32.rtp);
+ param.spare[0] = PTRIN(param32.spare[0]);
+ param.spare[1] = PTRIN(param32.spare[1]);
+ param.spare[2] = PTRIN(param32.spare[2]);
+
+ return (kern_thr_new(td, &param));
+}
+
+int
+freebsd32_thr_suspend(struct thread *td, struct freebsd32_thr_suspend_args *uap)
+{
+ struct timespec32 ts32;
+ struct timespec ts, *tsp;
+ int error;
+
+ error = 0;
+ tsp = NULL;
+ if (uap->timeout != NULL) {
+ error = copyin((const void *)uap->timeout, (void *)&ts32,
+ sizeof(struct timespec32));
+ if (error != 0)
+ return (error);
+ ts.tv_sec = ts32.tv_sec;
+ ts.tv_nsec = ts32.tv_nsec;
+ tsp = &ts;
+ }
+ return (kern_thr_suspend(td, tsp));
+}
+
+void
+siginfo_to_siginfo32(const siginfo_t *src, struct siginfo32 *dst)
+{
+ bzero(dst, sizeof(*dst));
+ dst->si_signo = src->si_signo;
+ dst->si_errno = src->si_errno;
+ dst->si_code = src->si_code;
+ dst->si_pid = src->si_pid;
+ dst->si_uid = src->si_uid;
+ dst->si_status = src->si_status;
+ dst->si_addr = (uintptr_t)src->si_addr;
+ dst->si_value.sival_int = src->si_value.sival_int;
+ dst->si_timerid = src->si_timerid;
+ dst->si_overrun = src->si_overrun;
+}
+
+#ifndef _FREEBSD32_SYSPROTO_H_
+struct freebsd32_sigqueue_args {
+ pid_t pid;
+ int signum;
+ /* union sigval32 */ int value;
+};
+#endif
+int
+freebsd32_sigqueue(struct thread *td, struct freebsd32_sigqueue_args *uap)
+{
+ union sigval sv;
+
+ /*
+ * On 32-bit ABIs, sival_int and sival_ptr are the same.
+ * On 64-bit little-endian ABIs, the low bits are the same.
+ * In 64-bit big-endian ABIs, sival_int overlaps with
+ * sival_ptr's HIGH bits. We choose to support sival_int
+ * rather than sival_ptr in this case as it seems to be
+ * more common.
+ */
+ bzero(&sv, sizeof(sv));
+ sv.sival_int = uap->value;
+
+ return (kern_sigqueue(td, uap->pid, uap->signum, &sv));
+}
+
+int
+freebsd32_sigtimedwait(struct thread *td, struct freebsd32_sigtimedwait_args *uap)
+{
+ struct timespec32 ts32;
+ struct timespec ts;
+ struct timespec *timeout;
+ sigset_t set;
+ ksiginfo_t ksi;
+ struct siginfo32 si32;
+ int error;
+
+ if (uap->timeout) {
+ error = copyin(uap->timeout, &ts32, sizeof(ts32));
+ if (error)
+ return (error);
+ ts.tv_sec = ts32.tv_sec;
+ ts.tv_nsec = ts32.tv_nsec;
+ timeout = &ts;
+ } else
+ timeout = NULL;
+
+ error = copyin(uap->set, &set, sizeof(set));
+ if (error)
+ return (error);
+
+ error = kern_sigtimedwait(td, set, &ksi, timeout);
+ if (error)
+ return (error);
+
+ if (uap->info) {
+ siginfo_to_siginfo32(&ksi.ksi_info, &si32);
+ error = copyout(&si32, uap->info, sizeof(struct siginfo32));
+ }
+
+ if (error == 0)
+ td->td_retval[0] = ksi.ksi_signo;
+ return (error);
+}
+
+/*
+ * MPSAFE
+ */
+int
+freebsd32_sigwaitinfo(struct thread *td, struct freebsd32_sigwaitinfo_args *uap)
+{
+ ksiginfo_t ksi;
+ struct siginfo32 si32;
+ sigset_t set;
+ int error;
+
+ error = copyin(uap->set, &set, sizeof(set));
+ if (error)
+ return (error);
+
+ error = kern_sigtimedwait(td, set, &ksi, NULL);
+ if (error)
+ return (error);
+
+ if (uap->info) {
+ siginfo_to_siginfo32(&ksi.ksi_info, &si32);
+ error = copyout(&si32, uap->info, sizeof(struct siginfo32));
+ }
+ if (error == 0)
+ td->td_retval[0] = ksi.ksi_signo;
+ return (error);
+}
+
+int
+freebsd32_cpuset_setid(struct thread *td,
+ struct freebsd32_cpuset_setid_args *uap)
+{
+
+ return (kern_cpuset_setid(td, uap->which,
+ PAIR32TO64(id_t, uap->id), uap->setid));
+}
+
+int
+freebsd32_cpuset_getid(struct thread *td,
+ struct freebsd32_cpuset_getid_args *uap)
+{
+
+ return (kern_cpuset_getid(td, uap->level, uap->which,
+ PAIR32TO64(id_t, uap->id), uap->setid));
+}
+
+int
+freebsd32_cpuset_getaffinity(struct thread *td,
+ struct freebsd32_cpuset_getaffinity_args *uap)
+{
+
+ return (kern_cpuset_getaffinity(td, uap->level, uap->which,
+ PAIR32TO64(id_t,uap->id), uap->cpusetsize, uap->mask));
+}
+
+int
+freebsd32_cpuset_setaffinity(struct thread *td,
+ struct freebsd32_cpuset_setaffinity_args *uap)
+{
+
+ return (kern_cpuset_setaffinity(td, uap->level, uap->which,
+ PAIR32TO64(id_t,uap->id), uap->cpusetsize, uap->mask));
+}
+
+int
+freebsd32_cpuset_getdomain(struct thread *td,
+ struct freebsd32_cpuset_getdomain_args *uap)
+{
+
+ return (kern_cpuset_getdomain(td, uap->level, uap->which,
+ PAIR32TO64(id_t,uap->id), uap->domainsetsize, uap->mask, uap->policy));
+}
+
+int
+freebsd32_cpuset_setdomain(struct thread *td,
+ struct freebsd32_cpuset_setdomain_args *uap)
+{
+
+ return (kern_cpuset_setdomain(td, uap->level, uap->which,
+ PAIR32TO64(id_t,uap->id), uap->domainsetsize, uap->mask, uap->policy));
+}
+
+int
+freebsd32_nmount(struct thread *td,
+ struct freebsd32_nmount_args /* {
+ struct iovec *iovp;
+ unsigned int iovcnt;
+ int flags;
+ } */ *uap)
+{
+ struct uio *auio;
+ uint64_t flags;
+ int error;
+
+ /*
+ * Mount flags are now 64-bits. On 32-bit archtectures only
+ * 32-bits are passed in, but from here on everything handles
+ * 64-bit flags correctly.
+ */
+ flags = uap->flags;
+
+ AUDIT_ARG_FFLAGS(flags);
+
+ /*
+ * Filter out MNT_ROOTFS. We do not want clients of nmount() in
+ * userspace to set this flag, but we must filter it out if we want
+ * MNT_UPDATE on the root file system to work.
+ * MNT_ROOTFS should only be set by the kernel when mounting its
+ * root file system.
+ */
+ flags &= ~MNT_ROOTFS;
+
+ /*
+ * check that we have an even number of iovec's
+ * and that we have at least two options.
+ */
+ if ((uap->iovcnt & 1) || (uap->iovcnt < 4))
+ return (EINVAL);
+
+ error = freebsd32_copyinuio(uap->iovp, uap->iovcnt, &auio);
+ if (error)
+ return (error);
+ error = vfs_donmount(td, flags, auio);
+
+ free(auio, M_IOV);
+ return error;
+}
+
+#if 0
+int
+freebsd32_xxx(struct thread *td, struct freebsd32_xxx_args *uap)
+{
+ struct yyy32 *p32, s32;
+ struct yyy *p = NULL, s;
+ struct xxx_arg ap;
+ int error;
+
+ if (uap->zzz) {
+ error = copyin(uap->zzz, &s32, sizeof(s32));
+ if (error)
+ return (error);
+ /* translate in */
+ p = &s;
+ }
+ error = kern_xxx(td, p);
+ if (error)
+ return (error);
+ if (uap->zzz) {
+ /* translate out */
+ error = copyout(&s32, p32, sizeof(s32));
+ }
+ return (error);
+}
+#endif
+
+int
+syscall32_module_handler(struct module *mod, int what, void *arg)
+{
+
+ return (kern_syscall_module_handler(freebsd32_sysent, mod, what, arg));
+}
+
+int
+syscall32_helper_register(struct syscall_helper_data *sd, int flags)
+{
+
+ return (kern_syscall_helper_register(freebsd32_sysent, sd, flags));
+}
+
+int
+syscall32_helper_unregister(struct syscall_helper_data *sd)
+{
+
+ return (kern_syscall_helper_unregister(freebsd32_sysent, sd));
+}
+
+int
+freebsd32_copyout_strings(struct image_params *imgp, uintptr_t *stack_base)
+{
+ int argc, envc, i;
+ u_int32_t *vectp;
+ char *stringp;
+ uintptr_t destp, ustringp;
+ struct freebsd32_ps_strings *arginfo;
+ char canary[sizeof(long) * 8];
+ int32_t pagesizes32[MAXPAGESIZES];
+ size_t execpath_len;
+ int error, szsigcode;
+
+ /*
+ * Calculate string base and vector table pointers.
+ * Also deal with signal trampoline code for this exec type.
+ */
+ if (imgp->execpath != NULL && imgp->auxargs != NULL)
+ execpath_len = strlen(imgp->execpath) + 1;
+ else
+ execpath_len = 0;
+ arginfo = (struct freebsd32_ps_strings *)curproc->p_sysent->
+ sv_psstrings;
+ imgp->ps_strings = arginfo;
+ if (imgp->proc->p_sysent->sv_sigcode_base == 0)
+ szsigcode = *(imgp->proc->p_sysent->sv_szsigcode);
+ else
+ szsigcode = 0;
+ destp = (uintptr_t)arginfo;
+
+ /*
+ * install sigcode
+ */
+ if (szsigcode != 0) {
+ destp -= szsigcode;
+ destp = rounddown2(destp, sizeof(uint32_t));
+ error = copyout(imgp->proc->p_sysent->sv_sigcode, (void *)destp,
+ szsigcode);
+ if (error != 0)
+ return (error);
+ }
+
+ /*
+ * Copy the image path for the rtld.
+ */
+ if (execpath_len != 0) {
+ destp -= execpath_len;
+ imgp->execpathp = (void *)destp;
+ error = copyout(imgp->execpath, imgp->execpathp, execpath_len);
+ if (error != 0)
+ return (error);
+ }
+
+ /*
+ * Prepare the canary for SSP.
+ */
+ arc4rand(canary, sizeof(canary), 0);
+ destp -= sizeof(canary);
+ imgp->canary = (void *)destp;
+ error = copyout(canary, imgp->canary, sizeof(canary));
+ if (error != 0)
+ return (error);
+ imgp->canarylen = sizeof(canary);
+
+ /*
+ * Prepare the pagesizes array.
+ */
+ for (i = 0; i < MAXPAGESIZES; i++)
+ pagesizes32[i] = (uint32_t)pagesizes[i];
+ destp -= sizeof(pagesizes32);
+ destp = rounddown2(destp, sizeof(uint32_t));
+ imgp->pagesizes = (void *)destp;
+ error = copyout(pagesizes32, imgp->pagesizes, sizeof(pagesizes32));
+ if (error != 0)
+ return (error);
+ imgp->pagesizeslen = sizeof(pagesizes32);
+
+ /*
+ * Allocate room for the argument and environment strings.
+ */
+ destp -= ARG_MAX - imgp->args->stringspace;
+ destp = rounddown2(destp, sizeof(uint32_t));
+ ustringp = destp;
+
+ exec_stackgap(imgp, &destp);
+
+ if (imgp->auxargs) {
+ /*
+ * Allocate room on the stack for the ELF auxargs
+ * array. It has up to AT_COUNT entries.
+ */
+ destp -= AT_COUNT * sizeof(Elf32_Auxinfo);
+ destp = rounddown2(destp, sizeof(uint32_t));
+ }
+
+ vectp = (uint32_t *)destp;
+
+ /*
+ * Allocate room for the argv[] and env vectors including the
+ * terminating NULL pointers.
+ */
+ vectp -= imgp->args->argc + 1 + imgp->args->envc + 1;
+
+ /*
+ * vectp also becomes our initial stack base
+ */
+ *stack_base = (uintptr_t)vectp;
+
+ stringp = imgp->args->begin_argv;
+ argc = imgp->args->argc;
+ envc = imgp->args->envc;
+ /*
+ * Copy out strings - arguments and environment.
+ */
+ error = copyout(stringp, (void *)ustringp,
+ ARG_MAX - imgp->args->stringspace);
+ if (error != 0)
+ return (error);
+
+ /*
+ * Fill in "ps_strings" struct for ps, w, etc.
+ */
+ imgp->argv = vectp;
+ if (suword32(&arginfo->ps_argvstr, (u_int32_t)(intptr_t)vectp) != 0 ||
+ suword32(&arginfo->ps_nargvstr, argc) != 0)
+ return (EFAULT);
+
+ /*
+ * Fill in argument portion of vector table.
+ */
+ for (; argc > 0; --argc) {
+ if (suword32(vectp++, ustringp) != 0)
+ return (EFAULT);
+ while (*stringp++ != 0)
+ ustringp++;
+ ustringp++;
+ }
+
+ /* a null vector table pointer separates the argp's from the envp's */
+ if (suword32(vectp++, 0) != 0)
+ return (EFAULT);
+
+ imgp->envv = vectp;
+ if (suword32(&arginfo->ps_envstr, (u_int32_t)(intptr_t)vectp) != 0 ||
+ suword32(&arginfo->ps_nenvstr, envc) != 0)
+ return (EFAULT);
+
+ /*
+ * Fill in environment portion of vector table.
+ */
+ for (; envc > 0; --envc) {
+ if (suword32(vectp++, ustringp) != 0)
+ return (EFAULT);
+ while (*stringp++ != 0)
+ ustringp++;
+ ustringp++;
+ }
+
+ /* end of vector table is a null pointer */
+ if (suword32(vectp, 0) != 0)
+ return (EFAULT);
+
+ if (imgp->auxargs) {
+ vectp++;
+ error = imgp->sysent->sv_copyout_auxargs(imgp,
+ (uintptr_t)vectp);
+ if (error != 0)
+ return (error);
+ }
+
+ return (0);
+}
+
+int
+freebsd32_kldstat(struct thread *td, struct freebsd32_kldstat_args *uap)
+{
+ struct kld_file_stat *stat;
+ struct kld32_file_stat *stat32;
+ int error, version;
+
+ if ((error = copyin(&uap->stat->version, &version, sizeof(version)))
+ != 0)
+ return (error);
+ if (version != sizeof(struct kld32_file_stat_1) &&
+ version != sizeof(struct kld32_file_stat))
+ return (EINVAL);
+
+ stat = malloc(sizeof(*stat), M_TEMP, M_WAITOK | M_ZERO);
+ stat32 = malloc(sizeof(*stat32), M_TEMP, M_WAITOK | M_ZERO);
+ error = kern_kldstat(td, uap->fileid, stat);
+ if (error == 0) {
+ bcopy(&stat->name[0], &stat32->name[0], sizeof(stat->name));
+ CP(*stat, *stat32, refs);
+ CP(*stat, *stat32, id);
+ PTROUT_CP(*stat, *stat32, address);
+ CP(*stat, *stat32, size);
+ bcopy(&stat->pathname[0], &stat32->pathname[0],
+ sizeof(stat->pathname));
+ stat32->version = version;
+ error = copyout(stat32, uap->stat, version);
+ }
+ free(stat, M_TEMP);
+ free(stat32, M_TEMP);
+ return (error);
+}
+
+int
+freebsd32_posix_fallocate(struct thread *td,
+ struct freebsd32_posix_fallocate_args *uap)
+{
+ int error;
+
+ error = kern_posix_fallocate(td, uap->fd,
+ PAIR32TO64(off_t, uap->offset), PAIR32TO64(off_t, uap->len));
+ return (kern_posix_error(td, error));
+}
+
+int
+freebsd32_posix_fadvise(struct thread *td,
+ struct freebsd32_posix_fadvise_args *uap)
+{
+ int error;
+
+ error = kern_posix_fadvise(td, uap->fd, PAIR32TO64(off_t, uap->offset),
+ PAIR32TO64(off_t, uap->len), uap->advice);
+ return (kern_posix_error(td, error));
+}
+
+int
+convert_sigevent32(struct sigevent32 *sig32, struct sigevent *sig)
+{
+
+ CP(*sig32, *sig, sigev_notify);
+ switch (sig->sigev_notify) {
+ case SIGEV_NONE:
+ break;
+ case SIGEV_THREAD_ID:
+ CP(*sig32, *sig, sigev_notify_thread_id);
+ /* FALLTHROUGH */
+ case SIGEV_SIGNAL:
+ CP(*sig32, *sig, sigev_signo);
+ PTRIN_CP(*sig32, *sig, sigev_value.sival_ptr);
+ break;
+ case SIGEV_KEVENT:
+ CP(*sig32, *sig, sigev_notify_kqueue);
+ CP(*sig32, *sig, sigev_notify_kevent_flags);
+ PTRIN_CP(*sig32, *sig, sigev_value.sival_ptr);
+ break;
+ default:
+ return (EINVAL);
+ }
+ return (0);
+}
+
+int
+freebsd32_procctl(struct thread *td, struct freebsd32_procctl_args *uap)
+{
+ void *data;
+ union {
+ struct procctl_reaper_status rs;
+ struct procctl_reaper_pids rp;
+ struct procctl_reaper_kill rk;
+ } x;
+ union {
+ struct procctl_reaper_pids32 rp;
+ } x32;
+ int error, error1, flags, signum;
+
+ if (uap->com >= PROC_PROCCTL_MD_MIN)
+ return (cpu_procctl(td, uap->idtype, PAIR32TO64(id_t, uap->id),
+ uap->com, PTRIN(uap->data)));
+
+ switch (uap->com) {
+ case PROC_ASLR_CTL:
+ case PROC_PROTMAX_CTL:
+ case PROC_SPROTECT:
+ case PROC_STACKGAP_CTL:
+ case PROC_TRACE_CTL:
+ case PROC_TRAPCAP_CTL:
+ error = copyin(PTRIN(uap->data), &flags, sizeof(flags));
+ if (error != 0)
+ return (error);
+ data = &flags;
+ break;
+ case PROC_REAP_ACQUIRE:
+ case PROC_REAP_RELEASE:
+ if (uap->data != NULL)
+ return (EINVAL);
+ data = NULL;
+ break;
+ case PROC_REAP_STATUS:
+ data = &x.rs;
+ break;
+ case PROC_REAP_GETPIDS:
+ error = copyin(uap->data, &x32.rp, sizeof(x32.rp));
+ if (error != 0)
+ return (error);
+ CP(x32.rp, x.rp, rp_count);
+ PTRIN_CP(x32.rp, x.rp, rp_pids);
+ data = &x.rp;
+ break;
+ case PROC_REAP_KILL:
+ error = copyin(uap->data, &x.rk, sizeof(x.rk));
+ if (error != 0)
+ return (error);
+ data = &x.rk;
+ break;
+ case PROC_ASLR_STATUS:
+ case PROC_PROTMAX_STATUS:
+ case PROC_STACKGAP_STATUS:
+ case PROC_TRACE_STATUS:
+ case PROC_TRAPCAP_STATUS:
+ data = &flags;
+ break;
+ case PROC_PDEATHSIG_CTL:
+ error = copyin(uap->data, &signum, sizeof(signum));
+ if (error != 0)
+ return (error);
+ data = &signum;
+ break;
+ case PROC_PDEATHSIG_STATUS:
+ data = &signum;
+ break;
+ default:
+ return (EINVAL);
+ }
+ error = kern_procctl(td, uap->idtype, PAIR32TO64(id_t, uap->id),
+ uap->com, data);
+ switch (uap->com) {
+ case PROC_REAP_STATUS:
+ if (error == 0)
+ error = copyout(&x.rs, uap->data, sizeof(x.rs));
+ break;
+ case PROC_REAP_KILL:
+ error1 = copyout(&x.rk, uap->data, sizeof(x.rk));
+ if (error == 0)
+ error = error1;
+ break;
+ case PROC_ASLR_STATUS:
+ case PROC_PROTMAX_STATUS:
+ case PROC_STACKGAP_STATUS:
+ case PROC_TRACE_STATUS:
+ case PROC_TRAPCAP_STATUS:
+ if (error == 0)
+ error = copyout(&flags, uap->data, sizeof(flags));
+ break;
+ case PROC_PDEATHSIG_STATUS:
+ if (error == 0)
+ error = copyout(&signum, uap->data, sizeof(signum));
+ break;
+ }
+ return (error);
+}
+
+int
+freebsd32_fcntl(struct thread *td, struct freebsd32_fcntl_args *uap)
+{
+ long tmp;
+
+ switch (uap->cmd) {
+ /*
+ * Do unsigned conversion for arg when operation
+ * interprets it as flags or pointer.
+ */
+ case F_SETLK_REMOTE:
+ case F_SETLKW:
+ case F_SETLK:
+ case F_GETLK:
+ case F_SETFD:
+ case F_SETFL:
+ case F_OGETLK:
+ case F_OSETLK:
+ case F_OSETLKW:
+ tmp = (unsigned int)(uap->arg);
+ break;
+ default:
+ tmp = uap->arg;
+ break;
+ }
+ return (kern_fcntl_freebsd(td, uap->fd, uap->cmd, tmp));
+}
+
+int
+freebsd32_ppoll(struct thread *td, struct freebsd32_ppoll_args *uap)
+{
+ struct timespec32 ts32;
+ struct timespec ts, *tsp;
+ sigset_t set, *ssp;
+ int error;
+
+ if (uap->ts != NULL) {
+ error = copyin(uap->ts, &ts32, sizeof(ts32));
+ if (error != 0)
+ return (error);
+ CP(ts32, ts, tv_sec);
+ CP(ts32, ts, tv_nsec);
+ tsp = &ts;
+ } else
+ tsp = NULL;
+ if (uap->set != NULL) {
+ error = copyin(uap->set, &set, sizeof(set));
+ if (error != 0)
+ return (error);
+ ssp = &set;
+ } else
+ ssp = NULL;
+
+ return (kern_poll(td, uap->fds, uap->nfds, tsp, ssp));
+}
+
+int
+freebsd32_sched_rr_get_interval(struct thread *td,
+ struct freebsd32_sched_rr_get_interval_args *uap)
+{
+ struct timespec ts;
+ struct timespec32 ts32;
+ int error;
+
+ error = kern_sched_rr_get_interval(td, uap->pid, &ts);
+ if (error == 0) {
+ CP(ts, ts32, tv_sec);
+ CP(ts, ts32, tv_nsec);
+ error = copyout(&ts32, uap->interval, sizeof(ts32));
+ }
+ return (error);
+}
+
+static void
+timex_to_32(struct timex32 *dst, struct timex *src)
+{
+ CP(*src, *dst, modes);
+ CP(*src, *dst, offset);
+ CP(*src, *dst, freq);
+ CP(*src, *dst, maxerror);
+ CP(*src, *dst, esterror);
+ CP(*src, *dst, status);
+ CP(*src, *dst, constant);
+ CP(*src, *dst, precision);
+ CP(*src, *dst, tolerance);
+ CP(*src, *dst, ppsfreq);
+ CP(*src, *dst, jitter);
+ CP(*src, *dst, shift);
+ CP(*src, *dst, stabil);
+ CP(*src, *dst, jitcnt);
+ CP(*src, *dst, calcnt);
+ CP(*src, *dst, errcnt);
+ CP(*src, *dst, stbcnt);
+}
+
+static void
+timex_from_32(struct timex *dst, struct timex32 *src)
+{
+ CP(*src, *dst, modes);
+ CP(*src, *dst, offset);
+ CP(*src, *dst, freq);
+ CP(*src, *dst, maxerror);
+ CP(*src, *dst, esterror);
+ CP(*src, *dst, status);
+ CP(*src, *dst, constant);
+ CP(*src, *dst, precision);
+ CP(*src, *dst, tolerance);
+ CP(*src, *dst, ppsfreq);
+ CP(*src, *dst, jitter);
+ CP(*src, *dst, shift);
+ CP(*src, *dst, stabil);
+ CP(*src, *dst, jitcnt);
+ CP(*src, *dst, calcnt);
+ CP(*src, *dst, errcnt);
+ CP(*src, *dst, stbcnt);
+}
+
+int
+freebsd32_ntp_adjtime(struct thread *td, struct freebsd32_ntp_adjtime_args *uap)
+{
+ struct timex tx;
+ struct timex32 tx32;
+ int error, retval;
+
+ error = copyin(uap->tp, &tx32, sizeof(tx32));
+ if (error == 0) {
+ timex_from_32(&tx, &tx32);
+ error = kern_ntp_adjtime(td, &tx, &retval);
+ if (error == 0) {
+ timex_to_32(&tx32, &tx);
+ error = copyout(&tx32, uap->tp, sizeof(tx32));
+ if (error == 0)
+ td->td_retval[0] = retval;
+ }
+ }
+ return (error);
+}
diff --git a/sys/compat/freebsd32/freebsd32_misc.h b/sys/compat/freebsd32/freebsd32_misc.h
new file mode 100644
index 000000000000..7db8fe6b84e0
--- /dev/null
+++ b/sys/compat/freebsd32/freebsd32_misc.h
@@ -0,0 +1,49 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _COMPAT_FREEBSD32_MISC_H_
+#define _COMPAT_FREEBSD32_MISC_H_
+
+#include <sys/endian.h>
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define PAIR32TO64(type, name) ((name ## 2) | ((type)(name ## 1) << 32))
+#define RETVAL_HI 0
+#define RETVAL_LO 1
+#else
+#define PAIR32TO64(type, name) ((name ## 1) | ((type)(name ## 2) << 32))
+#define RETVAL_HI 1
+#define RETVAL_LO 0
+#endif
+
+#endif /* !_COMPAT_FREEBSD32_MISC_H_ */
diff --git a/sys/compat/freebsd32/freebsd32_proto.h b/sys/compat/freebsd32/freebsd32_proto.h
new file mode 100644
index 000000000000..14a2fe794c94
--- /dev/null
+++ b/sys/compat/freebsd32/freebsd32_proto.h
@@ -0,0 +1,1484 @@
+/*
+ * System call prototypes.
+ *
+ * DO NOT EDIT-- this file is automatically @generated.
+ * $FreeBSD$
+ */
+
+#ifndef _FREEBSD32_SYSPROTO_H_
+#define _FREEBSD32_SYSPROTO_H_
+
+#include <sys/signal.h>
+#include <sys/acl.h>
+#include <sys/cpuset.h>
+#include <sys/domainset.h>
+#include <sys/_ffcounter.h>
+#include <sys/_semaphore.h>
+#include <sys/ucontext.h>
+#include <sys/wait.h>
+
+#include <bsm/audit_kevents.h>
+
+struct proc;
+
+struct thread;
+
+#define PAD_(t) (sizeof(register_t) <= sizeof(t) ? \
+ 0 : sizeof(register_t) - sizeof(t))
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define PADL_(t) 0
+#define PADR_(t) PAD_(t)
+#else
+#define PADL_(t) PAD_(t)
+#define PADR_(t) 0
+#endif
+
+#if !defined(PAD64_REQUIRED) && !defined(__amd64__)
+#define PAD64_REQUIRED
+#endif
+struct freebsd32_wait4_args {
+ char pid_l_[PADL_(int)]; int pid; char pid_r_[PADR_(int)];
+ char status_l_[PADL_(int *)]; int * status; char status_r_[PADR_(int *)];
+ char options_l_[PADL_(int)]; int options; char options_r_[PADR_(int)];
+ char rusage_l_[PADL_(struct rusage32 *)]; struct rusage32 * rusage; char rusage_r_[PADR_(struct rusage32 *)];
+};
+struct freebsd32_ptrace_args {
+ char req_l_[PADL_(int)]; int req; char req_r_[PADR_(int)];
+ char pid_l_[PADL_(pid_t)]; pid_t pid; char pid_r_[PADR_(pid_t)];
+ char addr_l_[PADL_(caddr_t)]; caddr_t addr; char addr_r_[PADR_(caddr_t)];
+ char data_l_[PADL_(int)]; int data; char data_r_[PADR_(int)];
+};
+struct freebsd32_recvmsg_args {
+ char s_l_[PADL_(int)]; int s; char s_r_[PADR_(int)];
+ char msg_l_[PADL_(struct msghdr32 *)]; struct msghdr32 * msg; char msg_r_[PADR_(struct msghdr32 *)];
+ char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
+};
+struct freebsd32_sendmsg_args {
+ char s_l_[PADL_(int)]; int s; char s_r_[PADR_(int)];
+ char msg_l_[PADL_(struct msghdr32 *)]; struct msghdr32 * msg; char msg_r_[PADR_(struct msghdr32 *)];
+ char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
+};
+struct freebsd32_recvfrom_args {
+ char s_l_[PADL_(int)]; int s; char s_r_[PADR_(int)];
+ char buf_l_[PADL_(void *)]; void * buf; char buf_r_[PADR_(void *)];
+ char len_l_[PADL_(uint32_t)]; uint32_t len; char len_r_[PADR_(uint32_t)];
+ char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
+ char from_l_[PADL_(struct sockaddr *)]; struct sockaddr * from; char from_r_[PADR_(struct sockaddr *)];
+ char fromlenaddr_l_[PADL_(uint32_t)]; uint32_t fromlenaddr; char fromlenaddr_r_[PADR_(uint32_t)];
+};
+struct freebsd10_freebsd32_pipe_args {
+ register_t dummy;
+};
+struct ofreebsd32_sigpending_args {
+ register_t dummy;
+};
+struct freebsd32_sigaltstack_args {
+ char ss_l_[PADL_(struct sigaltstack32 *)]; struct sigaltstack32 * ss; char ss_r_[PADR_(struct sigaltstack32 *)];
+ char oss_l_[PADL_(struct sigaltstack32 *)]; struct sigaltstack32 * oss; char oss_r_[PADR_(struct sigaltstack32 *)];
+};
+struct freebsd32_ioctl_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char com_l_[PADL_(uint32_t)]; uint32_t com; char com_r_[PADR_(uint32_t)];
+ char data_l_[PADL_(struct md_ioctl32 *)]; struct md_ioctl32 * data; char data_r_[PADR_(struct md_ioctl32 *)];
+};
+struct freebsd32_execve_args {
+ char fname_l_[PADL_(const char *)]; const char * fname; char fname_r_[PADR_(const char *)];
+ char argv_l_[PADL_(uint32_t *)]; uint32_t * argv; char argv_r_[PADR_(uint32_t *)];
+ char envv_l_[PADL_(uint32_t *)]; uint32_t * envv; char envv_r_[PADR_(uint32_t *)];
+};
+struct freebsd32_mprotect_args {
+ char addr_l_[PADL_(void *)]; void * addr; char addr_r_[PADR_(void *)];
+ char len_l_[PADL_(size_t)]; size_t len; char len_r_[PADR_(size_t)];
+ char prot_l_[PADL_(int)]; int prot; char prot_r_[PADR_(int)];
+};
+struct freebsd32_setitimer_args {
+ char which_l_[PADL_(u_int)]; u_int which; char which_r_[PADR_(u_int)];
+ char itv_l_[PADL_(struct itimerval32 *)]; struct itimerval32 * itv; char itv_r_[PADR_(struct itimerval32 *)];
+ char oitv_l_[PADL_(struct itimerval32 *)]; struct itimerval32 * oitv; char oitv_r_[PADR_(struct itimerval32 *)];
+};
+struct freebsd32_getitimer_args {
+ char which_l_[PADL_(u_int)]; u_int which; char which_r_[PADR_(u_int)];
+ char itv_l_[PADL_(struct itimerval32 *)]; struct itimerval32 * itv; char itv_r_[PADR_(struct itimerval32 *)];
+};
+struct freebsd32_fcntl_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char cmd_l_[PADL_(int)]; int cmd; char cmd_r_[PADR_(int)];
+ char arg_l_[PADL_(int)]; int arg; char arg_r_[PADR_(int)];
+};
+struct freebsd32_select_args {
+ char nd_l_[PADL_(int)]; int nd; char nd_r_[PADR_(int)];
+ char in_l_[PADL_(fd_set *)]; fd_set * in; char in_r_[PADR_(fd_set *)];
+ char ou_l_[PADL_(fd_set *)]; fd_set * ou; char ou_r_[PADR_(fd_set *)];
+ char ex_l_[PADL_(fd_set *)]; fd_set * ex; char ex_r_[PADR_(fd_set *)];
+ char tv_l_[PADL_(struct timeval32 *)]; struct timeval32 * tv; char tv_r_[PADR_(struct timeval32 *)];
+};
+struct freebsd32_gettimeofday_args {
+ char tp_l_[PADL_(struct timeval32 *)]; struct timeval32 * tp; char tp_r_[PADR_(struct timeval32 *)];
+ char tzp_l_[PADL_(struct timezone *)]; struct timezone * tzp; char tzp_r_[PADR_(struct timezone *)];
+};
+struct freebsd32_getrusage_args {
+ char who_l_[PADL_(int)]; int who; char who_r_[PADR_(int)];
+ char rusage_l_[PADL_(struct rusage32 *)]; struct rusage32 * rusage; char rusage_r_[PADR_(struct rusage32 *)];
+};
+struct freebsd32_readv_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char iovp_l_[PADL_(struct iovec32 *)]; struct iovec32 * iovp; char iovp_r_[PADR_(struct iovec32 *)];
+ char iovcnt_l_[PADL_(u_int)]; u_int iovcnt; char iovcnt_r_[PADR_(u_int)];
+};
+struct freebsd32_writev_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char iovp_l_[PADL_(struct iovec32 *)]; struct iovec32 * iovp; char iovp_r_[PADR_(struct iovec32 *)];
+ char iovcnt_l_[PADL_(u_int)]; u_int iovcnt; char iovcnt_r_[PADR_(u_int)];
+};
+struct freebsd32_settimeofday_args {
+ char tv_l_[PADL_(struct timeval32 *)]; struct timeval32 * tv; char tv_r_[PADR_(struct timeval32 *)];
+ char tzp_l_[PADL_(struct timezone *)]; struct timezone * tzp; char tzp_r_[PADR_(struct timezone *)];
+};
+struct freebsd32_utimes_args {
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char tptr_l_[PADL_(struct timeval32 *)]; struct timeval32 * tptr; char tptr_r_[PADR_(struct timeval32 *)];
+};
+struct freebsd32_adjtime_args {
+ char delta_l_[PADL_(struct timeval32 *)]; struct timeval32 * delta; char delta_r_[PADR_(struct timeval32 *)];
+ char olddelta_l_[PADL_(struct timeval32 *)]; struct timeval32 * olddelta; char olddelta_r_[PADR_(struct timeval32 *)];
+};
+struct freebsd32_sysarch_args {
+ char op_l_[PADL_(int)]; int op; char op_r_[PADR_(int)];
+ char parms_l_[PADL_(char *)]; char * parms; char parms_r_[PADR_(char *)];
+};
+struct freebsd32_semsys_args {
+ char which_l_[PADL_(int)]; int which; char which_r_[PADR_(int)];
+ char a2_l_[PADL_(int)]; int a2; char a2_r_[PADR_(int)];
+ char a3_l_[PADL_(int)]; int a3; char a3_r_[PADR_(int)];
+ char a4_l_[PADL_(int)]; int a4; char a4_r_[PADR_(int)];
+ char a5_l_[PADL_(int)]; int a5; char a5_r_[PADR_(int)];
+};
+struct freebsd32_msgsys_args {
+ char which_l_[PADL_(int)]; int which; char which_r_[PADR_(int)];
+ char a2_l_[PADL_(int)]; int a2; char a2_r_[PADR_(int)];
+ char a3_l_[PADL_(int)]; int a3; char a3_r_[PADR_(int)];
+ char a4_l_[PADL_(int)]; int a4; char a4_r_[PADR_(int)];
+ char a5_l_[PADL_(int)]; int a5; char a5_r_[PADR_(int)];
+ char a6_l_[PADL_(int)]; int a6; char a6_r_[PADR_(int)];
+};
+struct freebsd32_shmsys_args {
+ char which_l_[PADL_(uint32_t)]; uint32_t which; char which_r_[PADR_(uint32_t)];
+ char a2_l_[PADL_(uint32_t)]; uint32_t a2; char a2_r_[PADR_(uint32_t)];
+ char a3_l_[PADL_(uint32_t)]; uint32_t a3; char a3_r_[PADR_(uint32_t)];
+ char a4_l_[PADL_(uint32_t)]; uint32_t a4; char a4_r_[PADR_(uint32_t)];
+};
+struct freebsd32_ntp_adjtime_args {
+ char tp_l_[PADL_(struct timex32 *)]; struct timex32 * tp; char tp_r_[PADR_(struct timex32 *)];
+};
+struct freebsd32___sysctl_args {
+ char name_l_[PADL_(int *)]; int * name; char name_r_[PADR_(int *)];
+ char namelen_l_[PADL_(u_int)]; u_int namelen; char namelen_r_[PADR_(u_int)];
+ char old_l_[PADL_(void *)]; void * old; char old_r_[PADR_(void *)];
+ char oldlenp_l_[PADL_(uint32_t *)]; uint32_t * oldlenp; char oldlenp_r_[PADR_(uint32_t *)];
+ char new_l_[PADL_(const void *)]; const void * new; char new_r_[PADR_(const void *)];
+ char newlen_l_[PADL_(uint32_t)]; uint32_t newlen; char newlen_r_[PADR_(uint32_t)];
+};
+struct freebsd32_futimes_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char tptr_l_[PADL_(struct timeval32 *)]; struct timeval32 * tptr; char tptr_r_[PADR_(struct timeval32 *)];
+};
+struct freebsd32_msgsnd_args {
+ char msqid_l_[PADL_(int)]; int msqid; char msqid_r_[PADR_(int)];
+ char msgp_l_[PADL_(void *)]; void * msgp; char msgp_r_[PADR_(void *)];
+ char msgsz_l_[PADL_(size_t)]; size_t msgsz; char msgsz_r_[PADR_(size_t)];
+ char msgflg_l_[PADL_(int)]; int msgflg; char msgflg_r_[PADR_(int)];
+};
+struct freebsd32_msgrcv_args {
+ char msqid_l_[PADL_(int)]; int msqid; char msqid_r_[PADR_(int)];
+ char msgp_l_[PADL_(void *)]; void * msgp; char msgp_r_[PADR_(void *)];
+ char msgsz_l_[PADL_(size_t)]; size_t msgsz; char msgsz_r_[PADR_(size_t)];
+ char msgtyp_l_[PADL_(long)]; long msgtyp; char msgtyp_r_[PADR_(long)];
+ char msgflg_l_[PADL_(int)]; int msgflg; char msgflg_r_[PADR_(int)];
+};
+struct freebsd32_clock_gettime_args {
+ char clock_id_l_[PADL_(clockid_t)]; clockid_t clock_id; char clock_id_r_[PADR_(clockid_t)];
+ char tp_l_[PADL_(struct timespec32 *)]; struct timespec32 * tp; char tp_r_[PADR_(struct timespec32 *)];
+};
+struct freebsd32_clock_settime_args {
+ char clock_id_l_[PADL_(clockid_t)]; clockid_t clock_id; char clock_id_r_[PADR_(clockid_t)];
+ char tp_l_[PADL_(const struct timespec32 *)]; const struct timespec32 * tp; char tp_r_[PADR_(const struct timespec32 *)];
+};
+struct freebsd32_clock_getres_args {
+ char clock_id_l_[PADL_(clockid_t)]; clockid_t clock_id; char clock_id_r_[PADR_(clockid_t)];
+ char tp_l_[PADL_(struct timespec32 *)]; struct timespec32 * tp; char tp_r_[PADR_(struct timespec32 *)];
+};
+struct freebsd32_ktimer_create_args {
+ char clock_id_l_[PADL_(clockid_t)]; clockid_t clock_id; char clock_id_r_[PADR_(clockid_t)];
+ char evp_l_[PADL_(struct sigevent32 *)]; struct sigevent32 * evp; char evp_r_[PADR_(struct sigevent32 *)];
+ char timerid_l_[PADL_(int *)]; int * timerid; char timerid_r_[PADR_(int *)];
+};
+struct freebsd32_ktimer_settime_args {
+ char timerid_l_[PADL_(int)]; int timerid; char timerid_r_[PADR_(int)];
+ char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
+ char value_l_[PADL_(const struct itimerspec32 *)]; const struct itimerspec32 * value; char value_r_[PADR_(const struct itimerspec32 *)];
+ char ovalue_l_[PADL_(struct itimerspec32 *)]; struct itimerspec32 * ovalue; char ovalue_r_[PADR_(struct itimerspec32 *)];
+};
+struct freebsd32_ktimer_gettime_args {
+ char timerid_l_[PADL_(int)]; int timerid; char timerid_r_[PADR_(int)];
+ char value_l_[PADL_(struct itimerspec32 *)]; struct itimerspec32 * value; char value_r_[PADR_(struct itimerspec32 *)];
+};
+struct freebsd32_nanosleep_args {
+ char rqtp_l_[PADL_(const struct timespec32 *)]; const struct timespec32 * rqtp; char rqtp_r_[PADR_(const struct timespec32 *)];
+ char rmtp_l_[PADL_(struct timespec32 *)]; struct timespec32 * rmtp; char rmtp_r_[PADR_(struct timespec32 *)];
+};
+struct freebsd32_clock_nanosleep_args {
+ char clock_id_l_[PADL_(clockid_t)]; clockid_t clock_id; char clock_id_r_[PADR_(clockid_t)];
+ char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
+ char rqtp_l_[PADL_(const struct timespec32 *)]; const struct timespec32 * rqtp; char rqtp_r_[PADR_(const struct timespec32 *)];
+ char rmtp_l_[PADL_(struct timespec32 *)]; struct timespec32 * rmtp; char rmtp_r_[PADR_(struct timespec32 *)];
+};
+struct freebsd32_clock_getcpuclockid2_args {
+ char id1_l_[PADL_(uint32_t)]; uint32_t id1; char id1_r_[PADR_(uint32_t)];
+ char id2_l_[PADL_(uint32_t)]; uint32_t id2; char id2_r_[PADR_(uint32_t)];
+ char which_l_[PADL_(int)]; int which; char which_r_[PADR_(int)];
+ char clock_id_l_[PADL_(clockid_t *)]; clockid_t * clock_id; char clock_id_r_[PADR_(clockid_t *)];
+};
+struct freebsd32_aio_read_args {
+ char aiocbp_l_[PADL_(struct aiocb32 *)]; struct aiocb32 * aiocbp; char aiocbp_r_[PADR_(struct aiocb32 *)];
+};
+struct freebsd32_aio_write_args {
+ char aiocbp_l_[PADL_(struct aiocb32 *)]; struct aiocb32 * aiocbp; char aiocbp_r_[PADR_(struct aiocb32 *)];
+};
+struct freebsd32_lio_listio_args {
+ char mode_l_[PADL_(int)]; int mode; char mode_r_[PADR_(int)];
+ char acb_list_l_[PADL_(struct aiocb32 * const *)]; struct aiocb32 * const * acb_list; char acb_list_r_[PADR_(struct aiocb32 * const *)];
+ char nent_l_[PADL_(int)]; int nent; char nent_r_[PADR_(int)];
+ char sig_l_[PADL_(struct sigevent32 *)]; struct sigevent32 * sig; char sig_r_[PADR_(struct sigevent32 *)];
+};
+struct freebsd32_lutimes_args {
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char tptr_l_[PADL_(struct timeval32 *)]; struct timeval32 * tptr; char tptr_r_[PADR_(struct timeval32 *)];
+};
+struct freebsd32_preadv_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char iovp_l_[PADL_(struct iovec32 *)]; struct iovec32 * iovp; char iovp_r_[PADR_(struct iovec32 *)];
+ char iovcnt_l_[PADL_(u_int)]; u_int iovcnt; char iovcnt_r_[PADR_(u_int)];
+ char offset1_l_[PADL_(uint32_t)]; uint32_t offset1; char offset1_r_[PADR_(uint32_t)];
+ char offset2_l_[PADL_(uint32_t)]; uint32_t offset2; char offset2_r_[PADR_(uint32_t)];
+};
+struct freebsd32_pwritev_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char iovp_l_[PADL_(struct iovec32 *)]; struct iovec32 * iovp; char iovp_r_[PADR_(struct iovec32 *)];
+ char iovcnt_l_[PADL_(u_int)]; u_int iovcnt; char iovcnt_r_[PADR_(u_int)];
+ char offset1_l_[PADL_(uint32_t)]; uint32_t offset1; char offset1_r_[PADR_(uint32_t)];
+ char offset2_l_[PADL_(uint32_t)]; uint32_t offset2; char offset2_r_[PADR_(uint32_t)];
+};
+struct freebsd32_modstat_args {
+ char modid_l_[PADL_(int)]; int modid; char modid_r_[PADR_(int)];
+ char stat_l_[PADL_(struct module_stat32 *)]; struct module_stat32 * stat; char stat_r_[PADR_(struct module_stat32 *)];
+};
+struct freebsd32_kldstat_args {
+ char fileid_l_[PADL_(int)]; int fileid; char fileid_r_[PADR_(int)];
+ char stat_l_[PADL_(struct kld32_file_stat *)]; struct kld32_file_stat * stat; char stat_r_[PADR_(struct kld32_file_stat *)];
+};
+struct freebsd32_aio_return_args {
+ char aiocbp_l_[PADL_(struct aiocb32 *)]; struct aiocb32 * aiocbp; char aiocbp_r_[PADR_(struct aiocb32 *)];
+};
+struct freebsd32_aio_suspend_args {
+ char aiocbp_l_[PADL_(struct aiocb32 * const *)]; struct aiocb32 * const * aiocbp; char aiocbp_r_[PADR_(struct aiocb32 * const *)];
+ char nent_l_[PADL_(int)]; int nent; char nent_r_[PADR_(int)];
+ char timeout_l_[PADL_(const struct timespec32 *)]; const struct timespec32 * timeout; char timeout_r_[PADR_(const struct timespec32 *)];
+};
+struct freebsd32_aio_error_args {
+ char aiocbp_l_[PADL_(struct aiocb32 *)]; struct aiocb32 * aiocbp; char aiocbp_r_[PADR_(struct aiocb32 *)];
+};
+struct freebsd32_sched_rr_get_interval_args {
+ char pid_l_[PADL_(pid_t)]; pid_t pid; char pid_r_[PADR_(pid_t)];
+ char interval_l_[PADL_(struct timespec32 *)]; struct timespec32 * interval; char interval_r_[PADR_(struct timespec32 *)];
+};
+struct freebsd32_jail_args {
+ char jail_l_[PADL_(struct jail32 *)]; struct jail32 * jail; char jail_r_[PADR_(struct jail32 *)];
+};
+struct freebsd32_sigtimedwait_args {
+ char set_l_[PADL_(const sigset_t *)]; const sigset_t * set; char set_r_[PADR_(const sigset_t *)];
+ char info_l_[PADL_(siginfo_t *)]; siginfo_t * info; char info_r_[PADR_(siginfo_t *)];
+ char timeout_l_[PADL_(const struct timespec *)]; const struct timespec * timeout; char timeout_r_[PADR_(const struct timespec *)];
+};
+struct freebsd32_sigwaitinfo_args {
+ char set_l_[PADL_(const sigset_t *)]; const sigset_t * set; char set_r_[PADR_(const sigset_t *)];
+ char info_l_[PADL_(siginfo_t *)]; siginfo_t * info; char info_r_[PADR_(siginfo_t *)];
+};
+struct freebsd32_aio_waitcomplete_args {
+ char aiocbp_l_[PADL_(struct aiocb32 **)]; struct aiocb32 ** aiocbp; char aiocbp_r_[PADR_(struct aiocb32 **)];
+ char timeout_l_[PADL_(struct timespec32 *)]; struct timespec32 * timeout; char timeout_r_[PADR_(struct timespec32 *)];
+};
+struct freebsd32_nmount_args {
+ char iovp_l_[PADL_(struct iovec32 *)]; struct iovec32 * iovp; char iovp_r_[PADR_(struct iovec32 *)];
+ char iovcnt_l_[PADL_(unsigned int)]; unsigned int iovcnt; char iovcnt_r_[PADR_(unsigned int)];
+ char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
+};
+struct freebsd32_sendfile_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char s_l_[PADL_(int)]; int s; char s_r_[PADR_(int)];
+ char offset1_l_[PADL_(uint32_t)]; uint32_t offset1; char offset1_r_[PADR_(uint32_t)];
+ char offset2_l_[PADL_(uint32_t)]; uint32_t offset2; char offset2_r_[PADR_(uint32_t)];
+ char nbytes_l_[PADL_(size_t)]; size_t nbytes; char nbytes_r_[PADR_(size_t)];
+ char hdtr_l_[PADL_(struct sf_hdtr32 *)]; struct sf_hdtr32 * hdtr; char hdtr_r_[PADR_(struct sf_hdtr32 *)];
+ char sbytes_l_[PADL_(off_t *)]; off_t * sbytes; char sbytes_r_[PADR_(off_t *)];
+ char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
+};
+struct freebsd32_ksem_init_args {
+ char idp_l_[PADL_(semid_t *)]; semid_t * idp; char idp_r_[PADR_(semid_t *)];
+ char value_l_[PADL_(unsigned int)]; unsigned int value; char value_r_[PADR_(unsigned int)];
+};
+struct freebsd32_ksem_open_args {
+ char idp_l_[PADL_(semid_t *)]; semid_t * idp; char idp_r_[PADR_(semid_t *)];
+ char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)];
+ char oflag_l_[PADL_(int)]; int oflag; char oflag_r_[PADR_(int)];
+ char mode_l_[PADL_(mode_t)]; mode_t mode; char mode_r_[PADR_(mode_t)];
+ char value_l_[PADL_(unsigned int)]; unsigned int value; char value_r_[PADR_(unsigned int)];
+};
+struct freebsd32_sigaction_args {
+ char sig_l_[PADL_(int)]; int sig; char sig_r_[PADR_(int)];
+ char act_l_[PADL_(struct sigaction32 *)]; struct sigaction32 * act; char act_r_[PADR_(struct sigaction32 *)];
+ char oact_l_[PADL_(struct sigaction32 *)]; struct sigaction32 * oact; char oact_r_[PADR_(struct sigaction32 *)];
+};
+struct freebsd32_sigreturn_args {
+ char sigcntxp_l_[PADL_(const struct freebsd32_ucontext *)]; const struct freebsd32_ucontext * sigcntxp; char sigcntxp_r_[PADR_(const struct freebsd32_ucontext *)];
+};
+struct freebsd32_getcontext_args {
+ char ucp_l_[PADL_(struct freebsd32_ucontext *)]; struct freebsd32_ucontext * ucp; char ucp_r_[PADR_(struct freebsd32_ucontext *)];
+};
+struct freebsd32_setcontext_args {
+ char ucp_l_[PADL_(const struct freebsd32_ucontext *)]; const struct freebsd32_ucontext * ucp; char ucp_r_[PADR_(const struct freebsd32_ucontext *)];
+};
+struct freebsd32_swapcontext_args {
+ char oucp_l_[PADL_(struct freebsd32_ucontext *)]; struct freebsd32_ucontext * oucp; char oucp_r_[PADR_(struct freebsd32_ucontext *)];
+ char ucp_l_[PADL_(const struct freebsd32_ucontext *)]; const struct freebsd32_ucontext * ucp; char ucp_r_[PADR_(const struct freebsd32_ucontext *)];
+};
+struct freebsd32_ksem_timedwait_args {
+ char id_l_[PADL_(semid_t)]; semid_t id; char id_r_[PADR_(semid_t)];
+ char abstime_l_[PADL_(const struct timespec32 *)]; const struct timespec32 * abstime; char abstime_r_[PADR_(const struct timespec32 *)];
+};
+struct freebsd32_thr_suspend_args {
+ char timeout_l_[PADL_(const struct timespec32 *)]; const struct timespec32 * timeout; char timeout_r_[PADR_(const struct timespec32 *)];
+};
+struct freebsd32__umtx_op_args {
+ char obj_l_[PADL_(void *)]; void * obj; char obj_r_[PADR_(void *)];
+ char op_l_[PADL_(int)]; int op; char op_r_[PADR_(int)];
+ char val_l_[PADL_(u_long)]; u_long val; char val_r_[PADR_(u_long)];
+ char uaddr_l_[PADL_(void *)]; void * uaddr; char uaddr_r_[PADR_(void *)];
+ char uaddr2_l_[PADL_(void *)]; void * uaddr2; char uaddr2_r_[PADR_(void *)];
+};
+struct freebsd32_thr_new_args {
+ char param_l_[PADL_(struct thr_param32 *)]; struct thr_param32 * param; char param_r_[PADR_(struct thr_param32 *)];
+ char param_size_l_[PADL_(int)]; int param_size; char param_size_r_[PADR_(int)];
+};
+struct freebsd32_sigqueue_args {
+ char pid_l_[PADL_(pid_t)]; pid_t pid; char pid_r_[PADR_(pid_t)];
+ char signum_l_[PADL_(int)]; int signum; char signum_r_[PADR_(int)];
+ char value_l_[PADL_(int)]; int value; char value_r_[PADR_(int)];
+};
+struct freebsd32_kmq_open_args {
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
+ char mode_l_[PADL_(mode_t)]; mode_t mode; char mode_r_[PADR_(mode_t)];
+ char attr_l_[PADL_(const struct mq_attr32 *)]; const struct mq_attr32 * attr; char attr_r_[PADR_(const struct mq_attr32 *)];
+};
+struct freebsd32_kmq_setattr_args {
+ char mqd_l_[PADL_(int)]; int mqd; char mqd_r_[PADR_(int)];
+ char attr_l_[PADL_(const struct mq_attr32 *)]; const struct mq_attr32 * attr; char attr_r_[PADR_(const struct mq_attr32 *)];
+ char oattr_l_[PADL_(struct mq_attr32 *)]; struct mq_attr32 * oattr; char oattr_r_[PADR_(struct mq_attr32 *)];
+};
+struct freebsd32_kmq_timedreceive_args {
+ char mqd_l_[PADL_(int)]; int mqd; char mqd_r_[PADR_(int)];
+ char msg_ptr_l_[PADL_(char *)]; char * msg_ptr; char msg_ptr_r_[PADR_(char *)];
+ char msg_len_l_[PADL_(size_t)]; size_t msg_len; char msg_len_r_[PADR_(size_t)];
+ char msg_prio_l_[PADL_(unsigned *)]; unsigned * msg_prio; char msg_prio_r_[PADR_(unsigned *)];
+ char abs_timeout_l_[PADL_(const struct timespec32 *)]; const struct timespec32 * abs_timeout; char abs_timeout_r_[PADR_(const struct timespec32 *)];
+};
+struct freebsd32_kmq_timedsend_args {
+ char mqd_l_[PADL_(int)]; int mqd; char mqd_r_[PADR_(int)];
+ char msg_ptr_l_[PADL_(const char *)]; const char * msg_ptr; char msg_ptr_r_[PADR_(const char *)];
+ char msg_len_l_[PADL_(size_t)]; size_t msg_len; char msg_len_r_[PADR_(size_t)];
+ char msg_prio_l_[PADL_(unsigned)]; unsigned msg_prio; char msg_prio_r_[PADR_(unsigned)];
+ char abs_timeout_l_[PADL_(const struct timespec32 *)]; const struct timespec32 * abs_timeout; char abs_timeout_r_[PADR_(const struct timespec32 *)];
+};
+struct freebsd32_kmq_notify_args {
+ char mqd_l_[PADL_(int)]; int mqd; char mqd_r_[PADR_(int)];
+ char sigev_l_[PADL_(const struct sigevent32 *)]; const struct sigevent32 * sigev; char sigev_r_[PADR_(const struct sigevent32 *)];
+};
+struct freebsd32_aio_fsync_args {
+ char op_l_[PADL_(int)]; int op; char op_r_[PADR_(int)];
+ char aiocbp_l_[PADL_(struct aiocb32 *)]; struct aiocb32 * aiocbp; char aiocbp_r_[PADR_(struct aiocb32 *)];
+};
+#ifdef PAD64_REQUIRED
+struct freebsd32_pread_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char buf_l_[PADL_(void *)]; void * buf; char buf_r_[PADR_(void *)];
+ char nbyte_l_[PADL_(size_t)]; size_t nbyte; char nbyte_r_[PADR_(size_t)];
+ char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
+ char offset1_l_[PADL_(uint32_t)]; uint32_t offset1; char offset1_r_[PADR_(uint32_t)];
+ char offset2_l_[PADL_(uint32_t)]; uint32_t offset2; char offset2_r_[PADR_(uint32_t)];
+};
+struct freebsd32_pwrite_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char buf_l_[PADL_(const void *)]; const void * buf; char buf_r_[PADR_(const void *)];
+ char nbyte_l_[PADL_(size_t)]; size_t nbyte; char nbyte_r_[PADR_(size_t)];
+ char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
+ char offset1_l_[PADL_(uint32_t)]; uint32_t offset1; char offset1_r_[PADR_(uint32_t)];
+ char offset2_l_[PADL_(uint32_t)]; uint32_t offset2; char offset2_r_[PADR_(uint32_t)];
+};
+struct freebsd32_mmap_args {
+ char addr_l_[PADL_(void *)]; void * addr; char addr_r_[PADR_(void *)];
+ char len_l_[PADL_(size_t)]; size_t len; char len_r_[PADR_(size_t)];
+ char prot_l_[PADL_(int)]; int prot; char prot_r_[PADR_(int)];
+ char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
+ char pos1_l_[PADL_(uint32_t)]; uint32_t pos1; char pos1_r_[PADR_(uint32_t)];
+ char pos2_l_[PADL_(uint32_t)]; uint32_t pos2; char pos2_r_[PADR_(uint32_t)];
+};
+struct freebsd32_lseek_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
+ char offset1_l_[PADL_(uint32_t)]; uint32_t offset1; char offset1_r_[PADR_(uint32_t)];
+ char offset2_l_[PADL_(uint32_t)]; uint32_t offset2; char offset2_r_[PADR_(uint32_t)];
+ char whence_l_[PADL_(int)]; int whence; char whence_r_[PADR_(int)];
+};
+struct freebsd32_truncate_args {
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
+ char length1_l_[PADL_(uint32_t)]; uint32_t length1; char length1_r_[PADR_(uint32_t)];
+ char length2_l_[PADL_(uint32_t)]; uint32_t length2; char length2_r_[PADR_(uint32_t)];
+};
+struct freebsd32_ftruncate_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
+ char length1_l_[PADL_(uint32_t)]; uint32_t length1; char length1_r_[PADR_(uint32_t)];
+ char length2_l_[PADL_(uint32_t)]; uint32_t length2; char length2_r_[PADR_(uint32_t)];
+};
+#else
+struct freebsd32_pread_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char buf_l_[PADL_(void *)]; void * buf; char buf_r_[PADR_(void *)];
+ char nbyte_l_[PADL_(size_t)]; size_t nbyte; char nbyte_r_[PADR_(size_t)];
+ char offset1_l_[PADL_(uint32_t)]; uint32_t offset1; char offset1_r_[PADR_(uint32_t)];
+ char offset2_l_[PADL_(uint32_t)]; uint32_t offset2; char offset2_r_[PADR_(uint32_t)];
+};
+struct freebsd32_pwrite_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char buf_l_[PADL_(const void *)]; const void * buf; char buf_r_[PADR_(const void *)];
+ char nbyte_l_[PADL_(size_t)]; size_t nbyte; char nbyte_r_[PADR_(size_t)];
+ char offset1_l_[PADL_(uint32_t)]; uint32_t offset1; char offset1_r_[PADR_(uint32_t)];
+ char offset2_l_[PADL_(uint32_t)]; uint32_t offset2; char offset2_r_[PADR_(uint32_t)];
+};
+struct freebsd32_mmap_args {
+ char addr_l_[PADL_(void *)]; void * addr; char addr_r_[PADR_(void *)];
+ char len_l_[PADL_(size_t)]; size_t len; char len_r_[PADR_(size_t)];
+ char prot_l_[PADL_(int)]; int prot; char prot_r_[PADR_(int)];
+ char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char pos1_l_[PADL_(uint32_t)]; uint32_t pos1; char pos1_r_[PADR_(uint32_t)];
+ char pos2_l_[PADL_(uint32_t)]; uint32_t pos2; char pos2_r_[PADR_(uint32_t)];
+};
+struct freebsd32_lseek_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char offset1_l_[PADL_(uint32_t)]; uint32_t offset1; char offset1_r_[PADR_(uint32_t)];
+ char offset2_l_[PADL_(uint32_t)]; uint32_t offset2; char offset2_r_[PADR_(uint32_t)];
+ char whence_l_[PADL_(int)]; int whence; char whence_r_[PADR_(int)];
+};
+struct freebsd32_truncate_args {
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char length1_l_[PADL_(uint32_t)]; uint32_t length1; char length1_r_[PADR_(uint32_t)];
+ char length2_l_[PADL_(uint32_t)]; uint32_t length2; char length2_r_[PADR_(uint32_t)];
+};
+struct freebsd32_ftruncate_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char length1_l_[PADL_(uint32_t)]; uint32_t length1; char length1_r_[PADR_(uint32_t)];
+ char length2_l_[PADL_(uint32_t)]; uint32_t length2; char length2_r_[PADR_(uint32_t)];
+};
+#endif
+#ifdef PAD64_REQUIRED
+struct freebsd32_cpuset_setid_args {
+ char which_l_[PADL_(cpuwhich_t)]; cpuwhich_t which; char which_r_[PADR_(cpuwhich_t)];
+ char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
+ char id1_l_[PADL_(uint32_t)]; uint32_t id1; char id1_r_[PADR_(uint32_t)];
+ char id2_l_[PADL_(uint32_t)]; uint32_t id2; char id2_r_[PADR_(uint32_t)];
+ char setid_l_[PADL_(cpusetid_t)]; cpusetid_t setid; char setid_r_[PADR_(cpusetid_t)];
+};
+#else
+struct freebsd32_cpuset_setid_args {
+ char which_l_[PADL_(cpuwhich_t)]; cpuwhich_t which; char which_r_[PADR_(cpuwhich_t)];
+ char id1_l_[PADL_(uint32_t)]; uint32_t id1; char id1_r_[PADR_(uint32_t)];
+ char id2_l_[PADL_(uint32_t)]; uint32_t id2; char id2_r_[PADR_(uint32_t)];
+ char setid_l_[PADL_(cpusetid_t)]; cpusetid_t setid; char setid_r_[PADR_(cpusetid_t)];
+};
+#endif
+struct freebsd32_cpuset_getid_args {
+ char level_l_[PADL_(cpulevel_t)]; cpulevel_t level; char level_r_[PADR_(cpulevel_t)];
+ char which_l_[PADL_(cpuwhich_t)]; cpuwhich_t which; char which_r_[PADR_(cpuwhich_t)];
+ char id1_l_[PADL_(uint32_t)]; uint32_t id1; char id1_r_[PADR_(uint32_t)];
+ char id2_l_[PADL_(uint32_t)]; uint32_t id2; char id2_r_[PADR_(uint32_t)];
+ char setid_l_[PADL_(cpusetid_t *)]; cpusetid_t * setid; char setid_r_[PADR_(cpusetid_t *)];
+};
+struct freebsd32_cpuset_getaffinity_args {
+ char level_l_[PADL_(cpulevel_t)]; cpulevel_t level; char level_r_[PADR_(cpulevel_t)];
+ char which_l_[PADL_(cpuwhich_t)]; cpuwhich_t which; char which_r_[PADR_(cpuwhich_t)];
+ char id1_l_[PADL_(uint32_t)]; uint32_t id1; char id1_r_[PADR_(uint32_t)];
+ char id2_l_[PADL_(uint32_t)]; uint32_t id2; char id2_r_[PADR_(uint32_t)];
+ char cpusetsize_l_[PADL_(size_t)]; size_t cpusetsize; char cpusetsize_r_[PADR_(size_t)];
+ char mask_l_[PADL_(cpuset_t *)]; cpuset_t * mask; char mask_r_[PADR_(cpuset_t *)];
+};
+struct freebsd32_cpuset_setaffinity_args {
+ char level_l_[PADL_(cpulevel_t)]; cpulevel_t level; char level_r_[PADR_(cpulevel_t)];
+ char which_l_[PADL_(cpuwhich_t)]; cpuwhich_t which; char which_r_[PADR_(cpuwhich_t)];
+ char id1_l_[PADL_(uint32_t)]; uint32_t id1; char id1_r_[PADR_(uint32_t)];
+ char id2_l_[PADL_(uint32_t)]; uint32_t id2; char id2_r_[PADR_(uint32_t)];
+ char cpusetsize_l_[PADL_(size_t)]; size_t cpusetsize; char cpusetsize_r_[PADR_(size_t)];
+ char mask_l_[PADL_(const cpuset_t *)]; const cpuset_t * mask; char mask_r_[PADR_(const cpuset_t *)];
+};
+struct freebsd32_fexecve_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char argv_l_[PADL_(uint32_t *)]; uint32_t * argv; char argv_r_[PADR_(uint32_t *)];
+ char envv_l_[PADL_(uint32_t *)]; uint32_t * envv; char envv_r_[PADR_(uint32_t *)];
+};
+struct freebsd32_futimesat_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char times_l_[PADL_(struct timeval *)]; struct timeval * times; char times_r_[PADR_(struct timeval *)];
+};
+struct freebsd32_jail_get_args {
+ char iovp_l_[PADL_(struct iovec32 *)]; struct iovec32 * iovp; char iovp_r_[PADR_(struct iovec32 *)];
+ char iovcnt_l_[PADL_(unsigned int)]; unsigned int iovcnt; char iovcnt_r_[PADR_(unsigned int)];
+ char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
+};
+struct freebsd32_jail_set_args {
+ char iovp_l_[PADL_(struct iovec32 *)]; struct iovec32 * iovp; char iovp_r_[PADR_(struct iovec32 *)];
+ char iovcnt_l_[PADL_(unsigned int)]; unsigned int iovcnt; char iovcnt_r_[PADR_(unsigned int)];
+ char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
+};
+struct freebsd32_semctl_args {
+ char semid_l_[PADL_(int)]; int semid; char semid_r_[PADR_(int)];
+ char semnum_l_[PADL_(int)]; int semnum; char semnum_r_[PADR_(int)];
+ char cmd_l_[PADL_(int)]; int cmd; char cmd_r_[PADR_(int)];
+ char arg_l_[PADL_(union semun32 *)]; union semun32 * arg; char arg_r_[PADR_(union semun32 *)];
+};
+struct freebsd32_msgctl_args {
+ char msqid_l_[PADL_(int)]; int msqid; char msqid_r_[PADR_(int)];
+ char cmd_l_[PADL_(int)]; int cmd; char cmd_r_[PADR_(int)];
+ char buf_l_[PADL_(struct msqid_ds32 *)]; struct msqid_ds32 * buf; char buf_r_[PADR_(struct msqid_ds32 *)];
+};
+struct freebsd32_shmctl_args {
+ char shmid_l_[PADL_(int)]; int shmid; char shmid_r_[PADR_(int)];
+ char cmd_l_[PADL_(int)]; int cmd; char cmd_r_[PADR_(int)];
+ char buf_l_[PADL_(struct shmid_ds32 *)]; struct shmid_ds32 * buf; char buf_r_[PADR_(struct shmid_ds32 *)];
+};
+struct freebsd32_pselect_args {
+ char nd_l_[PADL_(int)]; int nd; char nd_r_[PADR_(int)];
+ char in_l_[PADL_(fd_set *)]; fd_set * in; char in_r_[PADR_(fd_set *)];
+ char ou_l_[PADL_(fd_set *)]; fd_set * ou; char ou_r_[PADR_(fd_set *)];
+ char ex_l_[PADL_(fd_set *)]; fd_set * ex; char ex_r_[PADR_(fd_set *)];
+ char ts_l_[PADL_(const struct timespec32 *)]; const struct timespec32 * ts; char ts_r_[PADR_(const struct timespec32 *)];
+ char sm_l_[PADL_(const sigset_t *)]; const sigset_t * sm; char sm_r_[PADR_(const sigset_t *)];
+};
+#ifdef PAD64_REQUIRED
+struct freebsd32_posix_fallocate_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
+ char offset1_l_[PADL_(uint32_t)]; uint32_t offset1; char offset1_r_[PADR_(uint32_t)];
+ char offset2_l_[PADL_(uint32_t)]; uint32_t offset2; char offset2_r_[PADR_(uint32_t)];
+ char len1_l_[PADL_(uint32_t)]; uint32_t len1; char len1_r_[PADR_(uint32_t)];
+ char len2_l_[PADL_(uint32_t)]; uint32_t len2; char len2_r_[PADR_(uint32_t)];
+};
+struct freebsd32_posix_fadvise_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
+ char offset1_l_[PADL_(uint32_t)]; uint32_t offset1; char offset1_r_[PADR_(uint32_t)];
+ char offset2_l_[PADL_(uint32_t)]; uint32_t offset2; char offset2_r_[PADR_(uint32_t)];
+ char len1_l_[PADL_(uint32_t)]; uint32_t len1; char len1_r_[PADR_(uint32_t)];
+ char len2_l_[PADL_(uint32_t)]; uint32_t len2; char len2_r_[PADR_(uint32_t)];
+ char advice_l_[PADL_(int)]; int advice; char advice_r_[PADR_(int)];
+};
+struct freebsd32_wait6_args {
+ char idtype_l_[PADL_(int)]; int idtype; char idtype_r_[PADR_(int)];
+ char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
+ char id1_l_[PADL_(uint32_t)]; uint32_t id1; char id1_r_[PADR_(uint32_t)];
+ char id2_l_[PADL_(uint32_t)]; uint32_t id2; char id2_r_[PADR_(uint32_t)];
+ char status_l_[PADL_(int *)]; int * status; char status_r_[PADR_(int *)];
+ char options_l_[PADL_(int)]; int options; char options_r_[PADR_(int)];
+ char wrusage_l_[PADL_(struct wrusage32 *)]; struct wrusage32 * wrusage; char wrusage_r_[PADR_(struct wrusage32 *)];
+ char info_l_[PADL_(siginfo_t *)]; siginfo_t * info; char info_r_[PADR_(siginfo_t *)];
+};
+#else
+struct freebsd32_posix_fallocate_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char offset1_l_[PADL_(uint32_t)]; uint32_t offset1; char offset1_r_[PADR_(uint32_t)];
+ char offset2_l_[PADL_(uint32_t)]; uint32_t offset2; char offset2_r_[PADR_(uint32_t)];
+ char len1_l_[PADL_(uint32_t)]; uint32_t len1; char len1_r_[PADR_(uint32_t)];
+ char len2_l_[PADL_(uint32_t)]; uint32_t len2; char len2_r_[PADR_(uint32_t)];
+};
+struct freebsd32_posix_fadvise_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char offset1_l_[PADL_(uint32_t)]; uint32_t offset1; char offset1_r_[PADR_(uint32_t)];
+ char offset2_l_[PADL_(uint32_t)]; uint32_t offset2; char offset2_r_[PADR_(uint32_t)];
+ char len1_l_[PADL_(uint32_t)]; uint32_t len1; char len1_r_[PADR_(uint32_t)];
+ char len2_l_[PADL_(uint32_t)]; uint32_t len2; char len2_r_[PADR_(uint32_t)];
+ char advice_l_[PADL_(int)]; int advice; char advice_r_[PADR_(int)];
+};
+struct freebsd32_wait6_args {
+ char idtype_l_[PADL_(int)]; int idtype; char idtype_r_[PADR_(int)];
+ char id1_l_[PADL_(uint32_t)]; uint32_t id1; char id1_r_[PADR_(uint32_t)];
+ char id2_l_[PADL_(uint32_t)]; uint32_t id2; char id2_r_[PADR_(uint32_t)];
+ char status_l_[PADL_(int *)]; int * status; char status_r_[PADR_(int *)];
+ char options_l_[PADL_(int)]; int options; char options_r_[PADR_(int)];
+ char wrusage_l_[PADL_(struct wrusage32 *)]; struct wrusage32 * wrusage; char wrusage_r_[PADR_(struct wrusage32 *)];
+ char info_l_[PADL_(siginfo_t *)]; siginfo_t * info; char info_r_[PADR_(siginfo_t *)];
+};
+#endif
+struct freebsd32_cap_ioctls_limit_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char cmds_l_[PADL_(const uint32_t *)]; const uint32_t * cmds; char cmds_r_[PADR_(const uint32_t *)];
+ char ncmds_l_[PADL_(size_t)]; size_t ncmds; char ncmds_r_[PADR_(size_t)];
+};
+struct freebsd32_cap_ioctls_get_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char cmds_l_[PADL_(uint32_t *)]; uint32_t * cmds; char cmds_r_[PADR_(uint32_t *)];
+ char maxcmds_l_[PADL_(size_t)]; size_t maxcmds; char maxcmds_r_[PADR_(size_t)];
+};
+struct freebsd32_aio_mlock_args {
+ char aiocbp_l_[PADL_(struct aiocb32 *)]; struct aiocb32 * aiocbp; char aiocbp_r_[PADR_(struct aiocb32 *)];
+};
+#ifdef PAD64_REQUIRED
+struct freebsd32_procctl_args {
+ char idtype_l_[PADL_(int)]; int idtype; char idtype_r_[PADR_(int)];
+ char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
+ char id1_l_[PADL_(uint32_t)]; uint32_t id1; char id1_r_[PADR_(uint32_t)];
+ char id2_l_[PADL_(uint32_t)]; uint32_t id2; char id2_r_[PADR_(uint32_t)];
+ char com_l_[PADL_(int)]; int com; char com_r_[PADR_(int)];
+ char data_l_[PADL_(void *)]; void * data; char data_r_[PADR_(void *)];
+};
+#else
+struct freebsd32_procctl_args {
+ char idtype_l_[PADL_(int)]; int idtype; char idtype_r_[PADR_(int)];
+ char id1_l_[PADL_(uint32_t)]; uint32_t id1; char id1_r_[PADR_(uint32_t)];
+ char id2_l_[PADL_(uint32_t)]; uint32_t id2; char id2_r_[PADR_(uint32_t)];
+ char com_l_[PADL_(int)]; int com; char com_r_[PADR_(int)];
+ char data_l_[PADL_(void *)]; void * data; char data_r_[PADR_(void *)];
+};
+#endif
+struct freebsd32_ppoll_args {
+ char fds_l_[PADL_(struct pollfd *)]; struct pollfd * fds; char fds_r_[PADR_(struct pollfd *)];
+ char nfds_l_[PADL_(u_int)]; u_int nfds; char nfds_r_[PADR_(u_int)];
+ char ts_l_[PADL_(const struct timespec32 *)]; const struct timespec32 * ts; char ts_r_[PADR_(const struct timespec32 *)];
+ char set_l_[PADL_(const sigset_t *)]; const sigset_t * set; char set_r_[PADR_(const sigset_t *)];
+};
+struct freebsd32_futimens_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char times_l_[PADL_(struct timespec *)]; struct timespec * times; char times_r_[PADR_(struct timespec *)];
+};
+struct freebsd32_utimensat_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char times_l_[PADL_(struct timespec *)]; struct timespec * times; char times_r_[PADR_(struct timespec *)];
+ char flag_l_[PADL_(int)]; int flag; char flag_r_[PADR_(int)];
+};
+struct freebsd32_fstat_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char ub_l_[PADL_(struct stat32 *)]; struct stat32 * ub; char ub_r_[PADR_(struct stat32 *)];
+};
+struct freebsd32_fstatat_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char buf_l_[PADL_(struct stat32 *)]; struct stat32 * buf; char buf_r_[PADR_(struct stat32 *)];
+ char flag_l_[PADL_(int)]; int flag; char flag_r_[PADR_(int)];
+};
+struct freebsd32_fhstat_args {
+ char u_fhp_l_[PADL_(const struct fhandle *)]; const struct fhandle * u_fhp; char u_fhp_r_[PADR_(const struct fhandle *)];
+ char sb_l_[PADL_(struct stat32 *)]; struct stat32 * sb; char sb_r_[PADR_(struct stat32 *)];
+};
+#ifdef PAD64_REQUIRED
+struct freebsd32_mknodat_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char mode_l_[PADL_(mode_t)]; mode_t mode; char mode_r_[PADR_(mode_t)];
+ char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
+ char dev1_l_[PADL_(uint32_t)]; uint32_t dev1; char dev1_r_[PADR_(uint32_t)];
+ char dev2_l_[PADL_(uint32_t)]; uint32_t dev2; char dev2_r_[PADR_(uint32_t)];
+};
+#else
+struct freebsd32_mknodat_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char mode_l_[PADL_(mode_t)]; mode_t mode; char mode_r_[PADR_(mode_t)];
+ char dev1_l_[PADL_(uint32_t)]; uint32_t dev1; char dev1_r_[PADR_(uint32_t)];
+ char dev2_l_[PADL_(uint32_t)]; uint32_t dev2; char dev2_r_[PADR_(uint32_t)];
+};
+#endif
+struct freebsd32_kevent_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char changelist_l_[PADL_(const struct kevent32 *)]; const struct kevent32 * changelist; char changelist_r_[PADR_(const struct kevent32 *)];
+ char nchanges_l_[PADL_(int)]; int nchanges; char nchanges_r_[PADR_(int)];
+ char eventlist_l_[PADL_(struct kevent32 *)]; struct kevent32 * eventlist; char eventlist_r_[PADR_(struct kevent32 *)];
+ char nevents_l_[PADL_(int)]; int nevents; char nevents_r_[PADR_(int)];
+ char timeout_l_[PADL_(const struct timespec32 *)]; const struct timespec32 * timeout; char timeout_r_[PADR_(const struct timespec32 *)];
+};
+struct freebsd32_cpuset_getdomain_args {
+ char level_l_[PADL_(cpulevel_t)]; cpulevel_t level; char level_r_[PADR_(cpulevel_t)];
+ char which_l_[PADL_(cpuwhich_t)]; cpuwhich_t which; char which_r_[PADR_(cpuwhich_t)];
+ char id1_l_[PADL_(uint32_t)]; uint32_t id1; char id1_r_[PADR_(uint32_t)];
+ char id2_l_[PADL_(uint32_t)]; uint32_t id2; char id2_r_[PADR_(uint32_t)];
+ char domainsetsize_l_[PADL_(size_t)]; size_t domainsetsize; char domainsetsize_r_[PADR_(size_t)];
+ char mask_l_[PADL_(domainset_t *)]; domainset_t * mask; char mask_r_[PADR_(domainset_t *)];
+ char policy_l_[PADL_(int *)]; int * policy; char policy_r_[PADR_(int *)];
+};
+struct freebsd32_cpuset_setdomain_args {
+ char level_l_[PADL_(cpulevel_t)]; cpulevel_t level; char level_r_[PADR_(cpulevel_t)];
+ char which_l_[PADL_(cpuwhich_t)]; cpuwhich_t which; char which_r_[PADR_(cpuwhich_t)];
+ char id1_l_[PADL_(uint32_t)]; uint32_t id1; char id1_r_[PADR_(uint32_t)];
+ char id2_l_[PADL_(uint32_t)]; uint32_t id2; char id2_r_[PADR_(uint32_t)];
+ char domainsetsize_l_[PADL_(size_t)]; size_t domainsetsize; char domainsetsize_r_[PADR_(size_t)];
+ char mask_l_[PADL_(domainset_t *)]; domainset_t * mask; char mask_r_[PADR_(domainset_t *)];
+ char policy_l_[PADL_(int)]; int policy; char policy_r_[PADR_(int)];
+};
+struct freebsd32___sysctlbyname_args {
+ char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)];
+ char namelen_l_[PADL_(size_t)]; size_t namelen; char namelen_r_[PADR_(size_t)];
+ char old_l_[PADL_(void *)]; void * old; char old_r_[PADR_(void *)];
+ char oldlenp_l_[PADL_(uint32_t *)]; uint32_t * oldlenp; char oldlenp_r_[PADR_(uint32_t *)];
+ char new_l_[PADL_(void *)]; void * new; char new_r_[PADR_(void *)];
+ char newlen_l_[PADL_(size_t)]; size_t newlen; char newlen_r_[PADR_(size_t)];
+};
+struct freebsd32_aio_writev_args {
+ char aiocbp_l_[PADL_(struct aiocb32 *)]; struct aiocb32 * aiocbp; char aiocbp_r_[PADR_(struct aiocb32 *)];
+};
+struct freebsd32_aio_readv_args {
+ char aiocbp_l_[PADL_(struct aiocb32 *)]; struct aiocb32 * aiocbp; char aiocbp_r_[PADR_(struct aiocb32 *)];
+};
+#if !defined(PAD64_REQUIRED) && !defined(__amd64__)
+#define PAD64_REQUIRED
+#endif
+int freebsd32_wait4(struct thread *, struct freebsd32_wait4_args *);
+int freebsd32_ptrace(struct thread *, struct freebsd32_ptrace_args *);
+int freebsd32_recvmsg(struct thread *, struct freebsd32_recvmsg_args *);
+int freebsd32_sendmsg(struct thread *, struct freebsd32_sendmsg_args *);
+int freebsd32_recvfrom(struct thread *, struct freebsd32_recvfrom_args *);
+int freebsd32_sigaltstack(struct thread *, struct freebsd32_sigaltstack_args *);
+int freebsd32_ioctl(struct thread *, struct freebsd32_ioctl_args *);
+int freebsd32_execve(struct thread *, struct freebsd32_execve_args *);
+int freebsd32_mprotect(struct thread *, struct freebsd32_mprotect_args *);
+int freebsd32_setitimer(struct thread *, struct freebsd32_setitimer_args *);
+int freebsd32_getitimer(struct thread *, struct freebsd32_getitimer_args *);
+int freebsd32_fcntl(struct thread *, struct freebsd32_fcntl_args *);
+int freebsd32_select(struct thread *, struct freebsd32_select_args *);
+int freebsd32_gettimeofday(struct thread *, struct freebsd32_gettimeofday_args *);
+int freebsd32_getrusage(struct thread *, struct freebsd32_getrusage_args *);
+int freebsd32_readv(struct thread *, struct freebsd32_readv_args *);
+int freebsd32_writev(struct thread *, struct freebsd32_writev_args *);
+int freebsd32_settimeofday(struct thread *, struct freebsd32_settimeofday_args *);
+int freebsd32_utimes(struct thread *, struct freebsd32_utimes_args *);
+int freebsd32_adjtime(struct thread *, struct freebsd32_adjtime_args *);
+int freebsd32_sysarch(struct thread *, struct freebsd32_sysarch_args *);
+int freebsd32_semsys(struct thread *, struct freebsd32_semsys_args *);
+int freebsd32_msgsys(struct thread *, struct freebsd32_msgsys_args *);
+int freebsd32_shmsys(struct thread *, struct freebsd32_shmsys_args *);
+int freebsd32_ntp_adjtime(struct thread *, struct freebsd32_ntp_adjtime_args *);
+int freebsd32___sysctl(struct thread *, struct freebsd32___sysctl_args *);
+int freebsd32_futimes(struct thread *, struct freebsd32_futimes_args *);
+int freebsd32_msgsnd(struct thread *, struct freebsd32_msgsnd_args *);
+int freebsd32_msgrcv(struct thread *, struct freebsd32_msgrcv_args *);
+int freebsd32_clock_gettime(struct thread *, struct freebsd32_clock_gettime_args *);
+int freebsd32_clock_settime(struct thread *, struct freebsd32_clock_settime_args *);
+int freebsd32_clock_getres(struct thread *, struct freebsd32_clock_getres_args *);
+int freebsd32_ktimer_create(struct thread *, struct freebsd32_ktimer_create_args *);
+int freebsd32_ktimer_settime(struct thread *, struct freebsd32_ktimer_settime_args *);
+int freebsd32_ktimer_gettime(struct thread *, struct freebsd32_ktimer_gettime_args *);
+int freebsd32_nanosleep(struct thread *, struct freebsd32_nanosleep_args *);
+int freebsd32_clock_nanosleep(struct thread *, struct freebsd32_clock_nanosleep_args *);
+int freebsd32_clock_getcpuclockid2(struct thread *, struct freebsd32_clock_getcpuclockid2_args *);
+int freebsd32_aio_read(struct thread *, struct freebsd32_aio_read_args *);
+int freebsd32_aio_write(struct thread *, struct freebsd32_aio_write_args *);
+int freebsd32_lio_listio(struct thread *, struct freebsd32_lio_listio_args *);
+int freebsd32_lutimes(struct thread *, struct freebsd32_lutimes_args *);
+int freebsd32_preadv(struct thread *, struct freebsd32_preadv_args *);
+int freebsd32_pwritev(struct thread *, struct freebsd32_pwritev_args *);
+int freebsd32_modstat(struct thread *, struct freebsd32_modstat_args *);
+int freebsd32_kldstat(struct thread *, struct freebsd32_kldstat_args *);
+int freebsd32_aio_return(struct thread *, struct freebsd32_aio_return_args *);
+int freebsd32_aio_suspend(struct thread *, struct freebsd32_aio_suspend_args *);
+int freebsd32_aio_error(struct thread *, struct freebsd32_aio_error_args *);
+int freebsd32_sched_rr_get_interval(struct thread *, struct freebsd32_sched_rr_get_interval_args *);
+int freebsd32_jail(struct thread *, struct freebsd32_jail_args *);
+int freebsd32_sigtimedwait(struct thread *, struct freebsd32_sigtimedwait_args *);
+int freebsd32_sigwaitinfo(struct thread *, struct freebsd32_sigwaitinfo_args *);
+int freebsd32_aio_waitcomplete(struct thread *, struct freebsd32_aio_waitcomplete_args *);
+int freebsd32_nmount(struct thread *, struct freebsd32_nmount_args *);
+int freebsd32_sendfile(struct thread *, struct freebsd32_sendfile_args *);
+int freebsd32_ksem_init(struct thread *, struct freebsd32_ksem_init_args *);
+int freebsd32_ksem_open(struct thread *, struct freebsd32_ksem_open_args *);
+int freebsd32_sigaction(struct thread *, struct freebsd32_sigaction_args *);
+int freebsd32_sigreturn(struct thread *, struct freebsd32_sigreturn_args *);
+int freebsd32_getcontext(struct thread *, struct freebsd32_getcontext_args *);
+int freebsd32_setcontext(struct thread *, struct freebsd32_setcontext_args *);
+int freebsd32_swapcontext(struct thread *, struct freebsd32_swapcontext_args *);
+int freebsd32_ksem_timedwait(struct thread *, struct freebsd32_ksem_timedwait_args *);
+int freebsd32_thr_suspend(struct thread *, struct freebsd32_thr_suspend_args *);
+int freebsd32__umtx_op(struct thread *, struct freebsd32__umtx_op_args *);
+int freebsd32_thr_new(struct thread *, struct freebsd32_thr_new_args *);
+int freebsd32_sigqueue(struct thread *, struct freebsd32_sigqueue_args *);
+int freebsd32_kmq_open(struct thread *, struct freebsd32_kmq_open_args *);
+int freebsd32_kmq_setattr(struct thread *, struct freebsd32_kmq_setattr_args *);
+int freebsd32_kmq_timedreceive(struct thread *, struct freebsd32_kmq_timedreceive_args *);
+int freebsd32_kmq_timedsend(struct thread *, struct freebsd32_kmq_timedsend_args *);
+int freebsd32_kmq_notify(struct thread *, struct freebsd32_kmq_notify_args *);
+int freebsd32_aio_fsync(struct thread *, struct freebsd32_aio_fsync_args *);
+#ifdef PAD64_REQUIRED
+int freebsd32_pread(struct thread *, struct freebsd32_pread_args *);
+int freebsd32_pwrite(struct thread *, struct freebsd32_pwrite_args *);
+int freebsd32_mmap(struct thread *, struct freebsd32_mmap_args *);
+int freebsd32_lseek(struct thread *, struct freebsd32_lseek_args *);
+int freebsd32_truncate(struct thread *, struct freebsd32_truncate_args *);
+int freebsd32_ftruncate(struct thread *, struct freebsd32_ftruncate_args *);
+#else
+int freebsd32_pread(struct thread *, struct freebsd32_pread_args *);
+int freebsd32_pwrite(struct thread *, struct freebsd32_pwrite_args *);
+int freebsd32_mmap(struct thread *, struct freebsd32_mmap_args *);
+int freebsd32_lseek(struct thread *, struct freebsd32_lseek_args *);
+int freebsd32_truncate(struct thread *, struct freebsd32_truncate_args *);
+int freebsd32_ftruncate(struct thread *, struct freebsd32_ftruncate_args *);
+#endif
+#ifdef PAD64_REQUIRED
+int freebsd32_cpuset_setid(struct thread *, struct freebsd32_cpuset_setid_args *);
+#else
+int freebsd32_cpuset_setid(struct thread *, struct freebsd32_cpuset_setid_args *);
+#endif
+int freebsd32_cpuset_getid(struct thread *, struct freebsd32_cpuset_getid_args *);
+int freebsd32_cpuset_getaffinity(struct thread *, struct freebsd32_cpuset_getaffinity_args *);
+int freebsd32_cpuset_setaffinity(struct thread *, struct freebsd32_cpuset_setaffinity_args *);
+int freebsd32_fexecve(struct thread *, struct freebsd32_fexecve_args *);
+int freebsd32_futimesat(struct thread *, struct freebsd32_futimesat_args *);
+int freebsd32_jail_get(struct thread *, struct freebsd32_jail_get_args *);
+int freebsd32_jail_set(struct thread *, struct freebsd32_jail_set_args *);
+int freebsd32_semctl(struct thread *, struct freebsd32_semctl_args *);
+int freebsd32_msgctl(struct thread *, struct freebsd32_msgctl_args *);
+int freebsd32_shmctl(struct thread *, struct freebsd32_shmctl_args *);
+int freebsd32_pselect(struct thread *, struct freebsd32_pselect_args *);
+#ifdef PAD64_REQUIRED
+int freebsd32_posix_fallocate(struct thread *, struct freebsd32_posix_fallocate_args *);
+int freebsd32_posix_fadvise(struct thread *, struct freebsd32_posix_fadvise_args *);
+int freebsd32_wait6(struct thread *, struct freebsd32_wait6_args *);
+#else
+int freebsd32_posix_fallocate(struct thread *, struct freebsd32_posix_fallocate_args *);
+int freebsd32_posix_fadvise(struct thread *, struct freebsd32_posix_fadvise_args *);
+int freebsd32_wait6(struct thread *, struct freebsd32_wait6_args *);
+#endif
+int freebsd32_cap_ioctls_limit(struct thread *, struct freebsd32_cap_ioctls_limit_args *);
+int freebsd32_cap_ioctls_get(struct thread *, struct freebsd32_cap_ioctls_get_args *);
+int freebsd32_aio_mlock(struct thread *, struct freebsd32_aio_mlock_args *);
+#ifdef PAD64_REQUIRED
+int freebsd32_procctl(struct thread *, struct freebsd32_procctl_args *);
+#else
+int freebsd32_procctl(struct thread *, struct freebsd32_procctl_args *);
+#endif
+int freebsd32_ppoll(struct thread *, struct freebsd32_ppoll_args *);
+int freebsd32_futimens(struct thread *, struct freebsd32_futimens_args *);
+int freebsd32_utimensat(struct thread *, struct freebsd32_utimensat_args *);
+int freebsd32_fstat(struct thread *, struct freebsd32_fstat_args *);
+int freebsd32_fstatat(struct thread *, struct freebsd32_fstatat_args *);
+int freebsd32_fhstat(struct thread *, struct freebsd32_fhstat_args *);
+#ifdef PAD64_REQUIRED
+int freebsd32_mknodat(struct thread *, struct freebsd32_mknodat_args *);
+#else
+int freebsd32_mknodat(struct thread *, struct freebsd32_mknodat_args *);
+#endif
+int freebsd32_kevent(struct thread *, struct freebsd32_kevent_args *);
+int freebsd32_cpuset_getdomain(struct thread *, struct freebsd32_cpuset_getdomain_args *);
+int freebsd32_cpuset_setdomain(struct thread *, struct freebsd32_cpuset_setdomain_args *);
+int freebsd32___sysctlbyname(struct thread *, struct freebsd32___sysctlbyname_args *);
+int freebsd32_aio_writev(struct thread *, struct freebsd32_aio_writev_args *);
+int freebsd32_aio_readv(struct thread *, struct freebsd32_aio_readv_args *);
+
+#ifdef COMPAT_43
+
+#if !defined(PAD64_REQUIRED) && !defined(__amd64__)
+#define PAD64_REQUIRED
+#endif
+struct ofreebsd32_lseek_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char offset_l_[PADL_(int)]; int offset; char offset_r_[PADR_(int)];
+ char whence_l_[PADL_(int)]; int whence; char whence_r_[PADR_(int)];
+};
+struct ofreebsd32_stat_args {
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char ub_l_[PADL_(struct ostat32 *)]; struct ostat32 * ub; char ub_r_[PADR_(struct ostat32 *)];
+};
+struct ofreebsd32_lstat_args {
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char ub_l_[PADL_(struct ostat *)]; struct ostat * ub; char ub_r_[PADR_(struct ostat *)];
+};
+struct ofreebsd32_sigaction_args {
+ char signum_l_[PADL_(int)]; int signum; char signum_r_[PADR_(int)];
+ char nsa_l_[PADL_(struct osigaction32 *)]; struct osigaction32 * nsa; char nsa_r_[PADR_(struct osigaction32 *)];
+ char osa_l_[PADL_(struct osigaction32 *)]; struct osigaction32 * osa; char osa_r_[PADR_(struct osigaction32 *)];
+};
+struct ofreebsd32_sigprocmask_args {
+ char how_l_[PADL_(int)]; int how; char how_r_[PADR_(int)];
+ char mask_l_[PADL_(osigset_t)]; osigset_t mask; char mask_r_[PADR_(osigset_t)];
+};
+struct ofreebsd32_fstat_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char ub_l_[PADL_(struct ostat32 *)]; struct ostat32 * ub; char ub_r_[PADR_(struct ostat32 *)];
+};
+struct ofreebsd32_getpagesize_args {
+ char dummy_l_[PADL_(int32_t)]; int32_t dummy; char dummy_r_[PADR_(int32_t)];
+};
+struct ofreebsd32_sigreturn_args {
+ char sigcntxp_l_[PADL_(struct ia32_sigcontext3 *)]; struct ia32_sigcontext3 * sigcntxp; char sigcntxp_r_[PADR_(struct ia32_sigcontext3 *)];
+};
+struct ofreebsd32_sigvec_args {
+ char signum_l_[PADL_(int)]; int signum; char signum_r_[PADR_(int)];
+ char nsv_l_[PADL_(struct sigvec32 *)]; struct sigvec32 * nsv; char nsv_r_[PADR_(struct sigvec32 *)];
+ char osv_l_[PADL_(struct sigvec32 *)]; struct sigvec32 * osv; char osv_r_[PADR_(struct sigvec32 *)];
+};
+struct ofreebsd32_sigblock_args {
+ char mask_l_[PADL_(int)]; int mask; char mask_r_[PADR_(int)];
+};
+struct ofreebsd32_sigsetmask_args {
+ char mask_l_[PADL_(int)]; int mask; char mask_r_[PADR_(int)];
+};
+struct ofreebsd32_sigsuspend_args {
+ char mask_l_[PADL_(int)]; int mask; char mask_r_[PADR_(int)];
+};
+struct ofreebsd32_sigstack_args {
+ char nss_l_[PADL_(struct sigstack32 *)]; struct sigstack32 * nss; char nss_r_[PADR_(struct sigstack32 *)];
+ char oss_l_[PADL_(struct sigstack32 *)]; struct sigstack32 * oss; char oss_r_[PADR_(struct sigstack32 *)];
+};
+struct ofreebsd32_getdirentries_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)];
+ char count_l_[PADL_(u_int)]; u_int count; char count_r_[PADR_(u_int)];
+ char basep_l_[PADL_(uint32_t *)]; uint32_t * basep; char basep_r_[PADR_(uint32_t *)];
+};
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+int ofreebsd32_lseek(struct thread *, struct ofreebsd32_lseek_args *);
+int ofreebsd32_stat(struct thread *, struct ofreebsd32_stat_args *);
+int ofreebsd32_lstat(struct thread *, struct ofreebsd32_lstat_args *);
+int ofreebsd32_sigaction(struct thread *, struct ofreebsd32_sigaction_args *);
+int ofreebsd32_sigprocmask(struct thread *, struct ofreebsd32_sigprocmask_args *);
+int ofreebsd32_sigpending(struct thread *, struct ofreebsd32_sigpending_args *);
+int ofreebsd32_fstat(struct thread *, struct ofreebsd32_fstat_args *);
+int ofreebsd32_getpagesize(struct thread *, struct ofreebsd32_getpagesize_args *);
+int ofreebsd32_sigreturn(struct thread *, struct ofreebsd32_sigreturn_args *);
+int ofreebsd32_sigvec(struct thread *, struct ofreebsd32_sigvec_args *);
+int ofreebsd32_sigblock(struct thread *, struct ofreebsd32_sigblock_args *);
+int ofreebsd32_sigsetmask(struct thread *, struct ofreebsd32_sigsetmask_args *);
+int ofreebsd32_sigsuspend(struct thread *, struct ofreebsd32_sigsuspend_args *);
+int ofreebsd32_sigstack(struct thread *, struct ofreebsd32_sigstack_args *);
+int ofreebsd32_getdirentries(struct thread *, struct ofreebsd32_getdirentries_args *);
+
+#endif /* COMPAT_43 */
+
+
+#ifdef COMPAT_FREEBSD4
+
+#if !defined(PAD64_REQUIRED) && !defined(__amd64__)
+#define PAD64_REQUIRED
+#endif
+struct freebsd4_freebsd32_getfsstat_args {
+ char buf_l_[PADL_(struct statfs32 *)]; struct statfs32 * buf; char buf_r_[PADR_(struct statfs32 *)];
+ char bufsize_l_[PADL_(long)]; long bufsize; char bufsize_r_[PADR_(long)];
+ char mode_l_[PADL_(int)]; int mode; char mode_r_[PADR_(int)];
+};
+struct freebsd4_freebsd32_statfs_args {
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char buf_l_[PADL_(struct statfs32 *)]; struct statfs32 * buf; char buf_r_[PADR_(struct statfs32 *)];
+};
+struct freebsd4_freebsd32_fstatfs_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char buf_l_[PADL_(struct statfs32 *)]; struct statfs32 * buf; char buf_r_[PADR_(struct statfs32 *)];
+};
+struct freebsd4_freebsd32_fhstatfs_args {
+ char u_fhp_l_[PADL_(const struct fhandle *)]; const struct fhandle * u_fhp; char u_fhp_r_[PADR_(const struct fhandle *)];
+ char buf_l_[PADL_(struct statfs32 *)]; struct statfs32 * buf; char buf_r_[PADR_(struct statfs32 *)];
+};
+struct freebsd4_freebsd32_sendfile_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char s_l_[PADL_(int)]; int s; char s_r_[PADR_(int)];
+ char offset1_l_[PADL_(uint32_t)]; uint32_t offset1; char offset1_r_[PADR_(uint32_t)];
+ char offset2_l_[PADL_(uint32_t)]; uint32_t offset2; char offset2_r_[PADR_(uint32_t)];
+ char nbytes_l_[PADL_(size_t)]; size_t nbytes; char nbytes_r_[PADR_(size_t)];
+ char hdtr_l_[PADL_(struct sf_hdtr32 *)]; struct sf_hdtr32 * hdtr; char hdtr_r_[PADR_(struct sf_hdtr32 *)];
+ char sbytes_l_[PADL_(off_t *)]; off_t * sbytes; char sbytes_r_[PADR_(off_t *)];
+ char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
+};
+struct freebsd4_freebsd32_sigaction_args {
+ char sig_l_[PADL_(int)]; int sig; char sig_r_[PADR_(int)];
+ char act_l_[PADL_(struct sigaction32 *)]; struct sigaction32 * act; char act_r_[PADR_(struct sigaction32 *)];
+ char oact_l_[PADL_(struct sigaction32 *)]; struct sigaction32 * oact; char oact_r_[PADR_(struct sigaction32 *)];
+};
+struct freebsd4_freebsd32_sigreturn_args {
+ char sigcntxp_l_[PADL_(const struct freebsd4_freebsd32_ucontext *)]; const struct freebsd4_freebsd32_ucontext * sigcntxp; char sigcntxp_r_[PADR_(const struct freebsd4_freebsd32_ucontext *)];
+};
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+int freebsd4_freebsd32_getfsstat(struct thread *, struct freebsd4_freebsd32_getfsstat_args *);
+int freebsd4_freebsd32_statfs(struct thread *, struct freebsd4_freebsd32_statfs_args *);
+int freebsd4_freebsd32_fstatfs(struct thread *, struct freebsd4_freebsd32_fstatfs_args *);
+int freebsd4_freebsd32_fhstatfs(struct thread *, struct freebsd4_freebsd32_fhstatfs_args *);
+int freebsd4_freebsd32_sendfile(struct thread *, struct freebsd4_freebsd32_sendfile_args *);
+int freebsd4_freebsd32_sigaction(struct thread *, struct freebsd4_freebsd32_sigaction_args *);
+int freebsd4_freebsd32_sigreturn(struct thread *, struct freebsd4_freebsd32_sigreturn_args *);
+
+#endif /* COMPAT_FREEBSD4 */
+
+
+#ifdef COMPAT_FREEBSD6
+
+#if !defined(PAD64_REQUIRED) && !defined(__amd64__)
+#define PAD64_REQUIRED
+#endif
+struct freebsd6_freebsd32_pread_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char buf_l_[PADL_(void *)]; void * buf; char buf_r_[PADR_(void *)];
+ char nbyte_l_[PADL_(size_t)]; size_t nbyte; char nbyte_r_[PADR_(size_t)];
+ char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
+ char offset1_l_[PADL_(uint32_t)]; uint32_t offset1; char offset1_r_[PADR_(uint32_t)];
+ char offset2_l_[PADL_(uint32_t)]; uint32_t offset2; char offset2_r_[PADR_(uint32_t)];
+};
+struct freebsd6_freebsd32_pwrite_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char buf_l_[PADL_(const void *)]; const void * buf; char buf_r_[PADR_(const void *)];
+ char nbyte_l_[PADL_(size_t)]; size_t nbyte; char nbyte_r_[PADR_(size_t)];
+ char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
+ char offset1_l_[PADL_(uint32_t)]; uint32_t offset1; char offset1_r_[PADR_(uint32_t)];
+ char offset2_l_[PADL_(uint32_t)]; uint32_t offset2; char offset2_r_[PADR_(uint32_t)];
+};
+struct freebsd6_freebsd32_mmap_args {
+ char addr_l_[PADL_(void *)]; void * addr; char addr_r_[PADR_(void *)];
+ char len_l_[PADL_(size_t)]; size_t len; char len_r_[PADR_(size_t)];
+ char prot_l_[PADL_(int)]; int prot; char prot_r_[PADR_(int)];
+ char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
+ char pos1_l_[PADL_(uint32_t)]; uint32_t pos1; char pos1_r_[PADR_(uint32_t)];
+ char pos2_l_[PADL_(uint32_t)]; uint32_t pos2; char pos2_r_[PADR_(uint32_t)];
+};
+struct freebsd6_freebsd32_lseek_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
+ char offset1_l_[PADL_(uint32_t)]; uint32_t offset1; char offset1_r_[PADR_(uint32_t)];
+ char offset2_l_[PADL_(uint32_t)]; uint32_t offset2; char offset2_r_[PADR_(uint32_t)];
+ char whence_l_[PADL_(int)]; int whence; char whence_r_[PADR_(int)];
+};
+struct freebsd6_freebsd32_truncate_args {
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
+ char length1_l_[PADL_(uint32_t)]; uint32_t length1; char length1_r_[PADR_(uint32_t)];
+ char length2_l_[PADL_(uint32_t)]; uint32_t length2; char length2_r_[PADR_(uint32_t)];
+};
+struct freebsd6_freebsd32_ftruncate_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
+ char length1_l_[PADL_(uint32_t)]; uint32_t length1; char length1_r_[PADR_(uint32_t)];
+ char length2_l_[PADL_(uint32_t)]; uint32_t length2; char length2_r_[PADR_(uint32_t)];
+};
+struct freebsd6_freebsd32_aio_read_args {
+ char aiocbp_l_[PADL_(struct oaiocb32 *)]; struct oaiocb32 * aiocbp; char aiocbp_r_[PADR_(struct oaiocb32 *)];
+};
+struct freebsd6_freebsd32_aio_write_args {
+ char aiocbp_l_[PADL_(struct oaiocb32 *)]; struct oaiocb32 * aiocbp; char aiocbp_r_[PADR_(struct oaiocb32 *)];
+};
+struct freebsd6_freebsd32_lio_listio_args {
+ char mode_l_[PADL_(int)]; int mode; char mode_r_[PADR_(int)];
+ char acb_list_l_[PADL_(struct oaiocb32 * const *)]; struct oaiocb32 * const * acb_list; char acb_list_r_[PADR_(struct oaiocb32 * const *)];
+ char nent_l_[PADL_(int)]; int nent; char nent_r_[PADR_(int)];
+ char sig_l_[PADL_(struct osigevent32 *)]; struct osigevent32 * sig; char sig_r_[PADR_(struct osigevent32 *)];
+};
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+int freebsd6_freebsd32_pread(struct thread *, struct freebsd6_freebsd32_pread_args *);
+int freebsd6_freebsd32_pwrite(struct thread *, struct freebsd6_freebsd32_pwrite_args *);
+int freebsd6_freebsd32_mmap(struct thread *, struct freebsd6_freebsd32_mmap_args *);
+int freebsd6_freebsd32_lseek(struct thread *, struct freebsd6_freebsd32_lseek_args *);
+int freebsd6_freebsd32_truncate(struct thread *, struct freebsd6_freebsd32_truncate_args *);
+int freebsd6_freebsd32_ftruncate(struct thread *, struct freebsd6_freebsd32_ftruncate_args *);
+int freebsd6_freebsd32_aio_read(struct thread *, struct freebsd6_freebsd32_aio_read_args *);
+int freebsd6_freebsd32_aio_write(struct thread *, struct freebsd6_freebsd32_aio_write_args *);
+int freebsd6_freebsd32_lio_listio(struct thread *, struct freebsd6_freebsd32_lio_listio_args *);
+
+#endif /* COMPAT_FREEBSD6 */
+
+
+#ifdef COMPAT_FREEBSD7
+
+#if !defined(PAD64_REQUIRED) && !defined(__amd64__)
+#define PAD64_REQUIRED
+#endif
+struct freebsd7_freebsd32_semctl_args {
+ char semid_l_[PADL_(int)]; int semid; char semid_r_[PADR_(int)];
+ char semnum_l_[PADL_(int)]; int semnum; char semnum_r_[PADR_(int)];
+ char cmd_l_[PADL_(int)]; int cmd; char cmd_r_[PADR_(int)];
+ char arg_l_[PADL_(union semun32 *)]; union semun32 * arg; char arg_r_[PADR_(union semun32 *)];
+};
+struct freebsd7_freebsd32_msgctl_args {
+ char msqid_l_[PADL_(int)]; int msqid; char msqid_r_[PADR_(int)];
+ char cmd_l_[PADL_(int)]; int cmd; char cmd_r_[PADR_(int)];
+ char buf_l_[PADL_(struct msqid_ds32_old *)]; struct msqid_ds32_old * buf; char buf_r_[PADR_(struct msqid_ds32_old *)];
+};
+struct freebsd7_freebsd32_shmctl_args {
+ char shmid_l_[PADL_(int)]; int shmid; char shmid_r_[PADR_(int)];
+ char cmd_l_[PADL_(int)]; int cmd; char cmd_r_[PADR_(int)];
+ char buf_l_[PADL_(struct shmid_ds32_old *)]; struct shmid_ds32_old * buf; char buf_r_[PADR_(struct shmid_ds32_old *)];
+};
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+int freebsd7_freebsd32_semctl(struct thread *, struct freebsd7_freebsd32_semctl_args *);
+int freebsd7_freebsd32_msgctl(struct thread *, struct freebsd7_freebsd32_msgctl_args *);
+int freebsd7_freebsd32_shmctl(struct thread *, struct freebsd7_freebsd32_shmctl_args *);
+
+#endif /* COMPAT_FREEBSD7 */
+
+
+#ifdef COMPAT_FREEBSD10
+
+#if !defined(PAD64_REQUIRED) && !defined(__amd64__)
+#define PAD64_REQUIRED
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+int freebsd10_freebsd32_pipe(struct thread *, struct freebsd10_freebsd32_pipe_args *);
+
+#endif /* COMPAT_FREEBSD10 */
+
+
+#ifdef COMPAT_FREEBSD11
+
+#if !defined(PAD64_REQUIRED) && !defined(__amd64__)
+#define PAD64_REQUIRED
+#endif
+struct freebsd11_freebsd32_stat_args {
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char ub_l_[PADL_(struct freebsd11_stat32 *)]; struct freebsd11_stat32 * ub; char ub_r_[PADR_(struct freebsd11_stat32 *)];
+};
+struct freebsd11_freebsd32_fstat_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char ub_l_[PADL_(struct freebsd11_stat32 *)]; struct freebsd11_stat32 * ub; char ub_r_[PADR_(struct freebsd11_stat32 *)];
+};
+struct freebsd11_freebsd32_lstat_args {
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char ub_l_[PADL_(struct freebsd11_stat32 *)]; struct freebsd11_stat32 * ub; char ub_r_[PADR_(struct freebsd11_stat32 *)];
+};
+struct freebsd11_freebsd32_getdirentries_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)];
+ char count_l_[PADL_(u_int)]; u_int count; char count_r_[PADR_(u_int)];
+ char basep_l_[PADL_(int32_t *)]; int32_t * basep; char basep_r_[PADR_(int32_t *)];
+};
+struct freebsd11_freebsd32_getdents_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)];
+ char count_l_[PADL_(int)]; int count; char count_r_[PADR_(int)];
+};
+struct freebsd11_freebsd32_fhstat_args {
+ char u_fhp_l_[PADL_(const struct fhandle *)]; const struct fhandle * u_fhp; char u_fhp_r_[PADR_(const struct fhandle *)];
+ char sb_l_[PADL_(struct freebsd11_stat32 *)]; struct freebsd11_stat32 * sb; char sb_r_[PADR_(struct freebsd11_stat32 *)];
+};
+struct freebsd11_freebsd32_kevent_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char changelist_l_[PADL_(const struct kevent32_freebsd11 *)]; const struct kevent32_freebsd11 * changelist; char changelist_r_[PADR_(const struct kevent32_freebsd11 *)];
+ char nchanges_l_[PADL_(int)]; int nchanges; char nchanges_r_[PADR_(int)];
+ char eventlist_l_[PADL_(struct kevent32_freebsd11 *)]; struct kevent32_freebsd11 * eventlist; char eventlist_r_[PADR_(struct kevent32_freebsd11 *)];
+ char nevents_l_[PADL_(int)]; int nevents; char nevents_r_[PADR_(int)];
+ char timeout_l_[PADL_(const struct timespec32 *)]; const struct timespec32 * timeout; char timeout_r_[PADR_(const struct timespec32 *)];
+};
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+struct freebsd11_freebsd32_fstatat_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char buf_l_[PADL_(struct freebsd11_stat32 *)]; struct freebsd11_stat32 * buf; char buf_r_[PADR_(struct freebsd11_stat32 *)];
+ char flag_l_[PADL_(int)]; int flag; char flag_r_[PADR_(int)];
+};
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+int freebsd11_freebsd32_stat(struct thread *, struct freebsd11_freebsd32_stat_args *);
+int freebsd11_freebsd32_fstat(struct thread *, struct freebsd11_freebsd32_fstat_args *);
+int freebsd11_freebsd32_lstat(struct thread *, struct freebsd11_freebsd32_lstat_args *);
+int freebsd11_freebsd32_getdirentries(struct thread *, struct freebsd11_freebsd32_getdirentries_args *);
+int freebsd11_freebsd32_getdents(struct thread *, struct freebsd11_freebsd32_getdents_args *);
+int freebsd11_freebsd32_fhstat(struct thread *, struct freebsd11_freebsd32_fhstat_args *);
+int freebsd11_freebsd32_kevent(struct thread *, struct freebsd11_freebsd32_kevent_args *);
+int freebsd11_freebsd32_fstatat(struct thread *, struct freebsd11_freebsd32_fstatat_args *);
+
+#endif /* COMPAT_FREEBSD11 */
+
+
+#ifdef COMPAT_FREEBSD12
+
+#if !defined(PAD64_REQUIRED) && !defined(__amd64__)
+#define PAD64_REQUIRED
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+#ifdef PAD64_REQUIRED
+#else
+#endif
+
+#endif /* COMPAT_FREEBSD12 */
+
+#define FREEBSD32_SYS_AUE_freebsd32_wait4 AUE_WAIT4
+#define FREEBSD32_SYS_AUE_freebsd4_freebsd32_getfsstat AUE_GETFSSTAT
+#define FREEBSD32_SYS_AUE_ofreebsd32_lseek AUE_LSEEK
+#define FREEBSD32_SYS_AUE_freebsd32_ptrace AUE_PTRACE
+#define FREEBSD32_SYS_AUE_freebsd32_recvmsg AUE_RECVMSG
+#define FREEBSD32_SYS_AUE_freebsd32_sendmsg AUE_SENDMSG
+#define FREEBSD32_SYS_AUE_freebsd32_recvfrom AUE_RECVFROM
+#define FREEBSD32_SYS_AUE_ofreebsd32_stat AUE_STAT
+#define FREEBSD32_SYS_AUE_ofreebsd32_lstat AUE_LSTAT
+#define FREEBSD32_SYS_AUE_freebsd10_freebsd32_pipe AUE_PIPE
+#define FREEBSD32_SYS_AUE_ofreebsd32_sigaction AUE_SIGACTION
+#define FREEBSD32_SYS_AUE_ofreebsd32_sigprocmask AUE_SIGPROCMASK
+#define FREEBSD32_SYS_AUE_ofreebsd32_sigpending AUE_SIGPENDING
+#define FREEBSD32_SYS_AUE_freebsd32_sigaltstack AUE_SIGALTSTACK
+#define FREEBSD32_SYS_AUE_freebsd32_ioctl AUE_IOCTL
+#define FREEBSD32_SYS_AUE_freebsd32_execve AUE_EXECVE
+#define FREEBSD32_SYS_AUE_ofreebsd32_fstat AUE_FSTAT
+#define FREEBSD32_SYS_AUE_ofreebsd32_getpagesize AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32_mprotect AUE_MPROTECT
+#define FREEBSD32_SYS_AUE_freebsd32_setitimer AUE_SETITIMER
+#define FREEBSD32_SYS_AUE_freebsd32_getitimer AUE_GETITIMER
+#define FREEBSD32_SYS_AUE_freebsd32_fcntl AUE_FCNTL
+#define FREEBSD32_SYS_AUE_freebsd32_select AUE_SELECT
+#define FREEBSD32_SYS_AUE_ofreebsd32_sigreturn AUE_SIGRETURN
+#define FREEBSD32_SYS_AUE_ofreebsd32_sigvec AUE_O_SIGVEC
+#define FREEBSD32_SYS_AUE_ofreebsd32_sigblock AUE_O_SIGBLOCK
+#define FREEBSD32_SYS_AUE_ofreebsd32_sigsetmask AUE_O_SIGSETMASK
+#define FREEBSD32_SYS_AUE_ofreebsd32_sigsuspend AUE_SIGSUSPEND
+#define FREEBSD32_SYS_AUE_ofreebsd32_sigstack AUE_O_SIGSTACK
+#define FREEBSD32_SYS_AUE_freebsd32_gettimeofday AUE_GETTIMEOFDAY
+#define FREEBSD32_SYS_AUE_freebsd32_getrusage AUE_GETRUSAGE
+#define FREEBSD32_SYS_AUE_freebsd32_readv AUE_READV
+#define FREEBSD32_SYS_AUE_freebsd32_writev AUE_WRITEV
+#define FREEBSD32_SYS_AUE_freebsd32_settimeofday AUE_SETTIMEOFDAY
+#define FREEBSD32_SYS_AUE_freebsd32_utimes AUE_UTIMES
+#define FREEBSD32_SYS_AUE_freebsd32_adjtime AUE_ADJTIME
+#define FREEBSD32_SYS_AUE_ofreebsd32_getdirentries AUE_GETDIRENTRIES
+#define FREEBSD32_SYS_AUE_freebsd4_freebsd32_statfs AUE_STATFS
+#define FREEBSD32_SYS_AUE_freebsd4_freebsd32_fstatfs AUE_FSTATFS
+#define FREEBSD32_SYS_AUE_freebsd32_sysarch AUE_SYSARCH
+#define FREEBSD32_SYS_AUE_freebsd32_semsys AUE_SEMSYS
+#define FREEBSD32_SYS_AUE_freebsd32_msgsys AUE_MSGSYS
+#define FREEBSD32_SYS_AUE_freebsd32_shmsys AUE_SHMSYS
+#define FREEBSD32_SYS_AUE_freebsd6_freebsd32_pread AUE_PREAD
+#define FREEBSD32_SYS_AUE_freebsd6_freebsd32_pwrite AUE_PWRITE
+#define FREEBSD32_SYS_AUE_freebsd32_ntp_adjtime AUE_NTP_ADJTIME
+#define FREEBSD32_SYS_AUE_freebsd11_freebsd32_stat AUE_STAT
+#define FREEBSD32_SYS_AUE_freebsd11_freebsd32_fstat AUE_FSTAT
+#define FREEBSD32_SYS_AUE_freebsd11_freebsd32_lstat AUE_LSTAT
+#define FREEBSD32_SYS_AUE_freebsd11_freebsd32_getdirentries AUE_GETDIRENTRIES
+#define FREEBSD32_SYS_AUE_freebsd6_freebsd32_mmap AUE_MMAP
+#define FREEBSD32_SYS_AUE_freebsd6_freebsd32_lseek AUE_LSEEK
+#define FREEBSD32_SYS_AUE_freebsd6_freebsd32_truncate AUE_TRUNCATE
+#define FREEBSD32_SYS_AUE_freebsd6_freebsd32_ftruncate AUE_FTRUNCATE
+#define FREEBSD32_SYS_AUE_freebsd32___sysctl AUE_SYSCTL
+#define FREEBSD32_SYS_AUE_freebsd32_futimes AUE_FUTIMES
+#define FREEBSD32_SYS_AUE_freebsd7_freebsd32_semctl AUE_SEMCTL
+#define FREEBSD32_SYS_AUE_freebsd7_freebsd32_msgctl AUE_MSGCTL
+#define FREEBSD32_SYS_AUE_freebsd32_msgsnd AUE_MSGSND
+#define FREEBSD32_SYS_AUE_freebsd32_msgrcv AUE_MSGRCV
+#define FREEBSD32_SYS_AUE_freebsd7_freebsd32_shmctl AUE_SHMCTL
+#define FREEBSD32_SYS_AUE_freebsd32_clock_gettime AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32_clock_settime AUE_CLOCK_SETTIME
+#define FREEBSD32_SYS_AUE_freebsd32_clock_getres AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32_ktimer_create AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32_ktimer_settime AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32_ktimer_gettime AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32_nanosleep AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32_clock_nanosleep AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32_clock_getcpuclockid2 AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32_aio_read AUE_AIO_READ
+#define FREEBSD32_SYS_AUE_freebsd32_aio_write AUE_AIO_WRITE
+#define FREEBSD32_SYS_AUE_freebsd32_lio_listio AUE_LIO_LISTIO
+#define FREEBSD32_SYS_AUE_freebsd11_freebsd32_getdents AUE_O_GETDENTS
+#define FREEBSD32_SYS_AUE_freebsd32_lutimes AUE_LUTIMES
+#define FREEBSD32_SYS_AUE_freebsd32_preadv AUE_PREADV
+#define FREEBSD32_SYS_AUE_freebsd32_pwritev AUE_PWRITEV
+#define FREEBSD32_SYS_AUE_freebsd4_freebsd32_fhstatfs AUE_FHSTATFS
+#define FREEBSD32_SYS_AUE_freebsd11_freebsd32_fhstat AUE_FHSTAT
+#define FREEBSD32_SYS_AUE_freebsd32_modstat AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32_kldstat AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32_aio_return AUE_AIO_RETURN
+#define FREEBSD32_SYS_AUE_freebsd32_aio_suspend AUE_AIO_SUSPEND
+#define FREEBSD32_SYS_AUE_freebsd32_aio_error AUE_AIO_ERROR
+#define FREEBSD32_SYS_AUE_freebsd6_freebsd32_aio_read AUE_AIO_READ
+#define FREEBSD32_SYS_AUE_freebsd6_freebsd32_aio_write AUE_AIO_WRITE
+#define FREEBSD32_SYS_AUE_freebsd6_freebsd32_lio_listio AUE_LIO_LISTIO
+#define FREEBSD32_SYS_AUE_freebsd32_sched_rr_get_interval AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd4_freebsd32_sendfile AUE_SENDFILE
+#define FREEBSD32_SYS_AUE_freebsd32_jail AUE_JAIL
+#define FREEBSD32_SYS_AUE_freebsd4_freebsd32_sigaction AUE_SIGACTION
+#define FREEBSD32_SYS_AUE_freebsd4_freebsd32_sigreturn AUE_SIGRETURN
+#define FREEBSD32_SYS_AUE_freebsd32_sigtimedwait AUE_SIGWAIT
+#define FREEBSD32_SYS_AUE_freebsd32_sigwaitinfo AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32_aio_waitcomplete AUE_AIO_WAITCOMPLETE
+#define FREEBSD32_SYS_AUE_freebsd11_freebsd32_kevent AUE_KEVENT
+#define FREEBSD32_SYS_AUE_freebsd32_nmount AUE_NMOUNT
+#define FREEBSD32_SYS_AUE_freebsd32_sendfile AUE_SENDFILE
+#define FREEBSD32_SYS_AUE_freebsd32_ksem_init AUE_SEMINIT
+#define FREEBSD32_SYS_AUE_freebsd32_ksem_open AUE_SEMOPEN
+#define FREEBSD32_SYS_AUE_freebsd32_sigaction AUE_SIGACTION
+#define FREEBSD32_SYS_AUE_freebsd32_sigreturn AUE_SIGRETURN
+#define FREEBSD32_SYS_AUE_freebsd32_getcontext AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32_setcontext AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32_swapcontext AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32_ksem_timedwait AUE_SEMWAIT
+#define FREEBSD32_SYS_AUE_freebsd32_thr_suspend AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32__umtx_op AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32_thr_new AUE_THR_NEW
+#define FREEBSD32_SYS_AUE_freebsd32_sigqueue AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32_kmq_open AUE_MQ_OPEN
+#define FREEBSD32_SYS_AUE_freebsd32_kmq_setattr AUE_MQ_SETATTR
+#define FREEBSD32_SYS_AUE_freebsd32_kmq_timedreceive AUE_MQ_TIMEDRECEIVE
+#define FREEBSD32_SYS_AUE_freebsd32_kmq_timedsend AUE_MQ_TIMEDSEND
+#define FREEBSD32_SYS_AUE_freebsd32_kmq_notify AUE_MQ_NOTIFY
+#define FREEBSD32_SYS_AUE_freebsd32_aio_fsync AUE_AIO_FSYNC
+#define FREEBSD32_SYS_AUE_freebsd32_pread AUE_PREAD
+#define FREEBSD32_SYS_AUE_freebsd32_pwrite AUE_PWRITE
+#define FREEBSD32_SYS_AUE_freebsd32_mmap AUE_MMAP
+#define FREEBSD32_SYS_AUE_freebsd32_lseek AUE_LSEEK
+#define FREEBSD32_SYS_AUE_freebsd32_truncate AUE_TRUNCATE
+#define FREEBSD32_SYS_AUE_freebsd32_ftruncate AUE_FTRUNCATE
+#define FREEBSD32_SYS_AUE_freebsd32_pread AUE_PREAD
+#define FREEBSD32_SYS_AUE_freebsd32_pwrite AUE_PWRITE
+#define FREEBSD32_SYS_AUE_freebsd32_mmap AUE_MMAP
+#define FREEBSD32_SYS_AUE_freebsd32_lseek AUE_LSEEK
+#define FREEBSD32_SYS_AUE_freebsd32_truncate AUE_TRUNCATE
+#define FREEBSD32_SYS_AUE_freebsd32_ftruncate AUE_FTRUNCATE
+#define FREEBSD32_SYS_AUE_freebsd32_cpuset_setid AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32_cpuset_setid AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32_cpuset_getid AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32_cpuset_getaffinity AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32_cpuset_setaffinity AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32_fexecve AUE_FEXECVE
+#define FREEBSD32_SYS_AUE_freebsd11_freebsd32_fstatat AUE_FSTATAT
+#define FREEBSD32_SYS_AUE_freebsd32_futimesat AUE_FUTIMESAT
+#define FREEBSD32_SYS_AUE_freebsd32_jail_get AUE_JAIL_GET
+#define FREEBSD32_SYS_AUE_freebsd32_jail_set AUE_JAIL_SET
+#define FREEBSD32_SYS_AUE_freebsd32_semctl AUE_SEMCTL
+#define FREEBSD32_SYS_AUE_freebsd32_msgctl AUE_MSGCTL
+#define FREEBSD32_SYS_AUE_freebsd32_shmctl AUE_SHMCTL
+#define FREEBSD32_SYS_AUE_freebsd32_pselect AUE_SELECT
+#define FREEBSD32_SYS_AUE_freebsd32_posix_fallocate AUE_POSIX_FALLOCATE
+#define FREEBSD32_SYS_AUE_freebsd32_posix_fadvise AUE_POSIX_FADVISE
+#define FREEBSD32_SYS_AUE_freebsd32_wait6 AUE_WAIT6
+#define FREEBSD32_SYS_AUE_freebsd32_posix_fallocate AUE_POSIX_FALLOCATE
+#define FREEBSD32_SYS_AUE_freebsd32_posix_fadvise AUE_POSIX_FADVISE
+#define FREEBSD32_SYS_AUE_freebsd32_wait6 AUE_WAIT6
+#define FREEBSD32_SYS_AUE_freebsd32_cap_ioctls_limit AUE_CAP_IOCTLS_LIMIT
+#define FREEBSD32_SYS_AUE_freebsd32_cap_ioctls_get AUE_CAP_IOCTLS_GET
+#define FREEBSD32_SYS_AUE_freebsd32_aio_mlock AUE_AIO_MLOCK
+#define FREEBSD32_SYS_AUE_freebsd32_procctl AUE_PROCCTL
+#define FREEBSD32_SYS_AUE_freebsd32_procctl AUE_PROCCTL
+#define FREEBSD32_SYS_AUE_freebsd32_ppoll AUE_POLL
+#define FREEBSD32_SYS_AUE_freebsd32_futimens AUE_FUTIMES
+#define FREEBSD32_SYS_AUE_freebsd32_utimensat AUE_FUTIMESAT
+#define FREEBSD32_SYS_AUE_freebsd32_fstat AUE_FSTAT
+#define FREEBSD32_SYS_AUE_freebsd32_fstatat AUE_FSTATAT
+#define FREEBSD32_SYS_AUE_freebsd32_fhstat AUE_FHSTAT
+#define FREEBSD32_SYS_AUE_freebsd32_mknodat AUE_MKNODAT
+#define FREEBSD32_SYS_AUE_freebsd32_mknodat AUE_MKNODAT
+#define FREEBSD32_SYS_AUE_freebsd32_kevent AUE_KEVENT
+#define FREEBSD32_SYS_AUE_freebsd32_cpuset_getdomain AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32_cpuset_setdomain AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32___sysctlbyname AUE_SYSCTL
+#define FREEBSD32_SYS_AUE_freebsd32_aio_writev AUE_AIO_WRITEV
+#define FREEBSD32_SYS_AUE_freebsd32_aio_readv AUE_AIO_READV
+
+#undef PAD_
+#undef PADL_
+#undef PADR_
+
+#endif /* !_FREEBSD32_SYSPROTO_H_ */
diff --git a/sys/compat/freebsd32/freebsd32_signal.h b/sys/compat/freebsd32/freebsd32_signal.h
new file mode 100644
index 000000000000..cc7aeb858fb1
--- /dev/null
+++ b/sys/compat/freebsd32/freebsd32_signal.h
@@ -0,0 +1,68 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2006 David Xu <davidxu@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _COMPAT_FREEBSD32_SIGNAL_H_
+#define _COMPAT_FREEBSD32_SIGNAL_H_
+
+struct sigaltstack32 {
+ u_int32_t ss_sp; /* signal stack base */
+ u_int32_t ss_size; /* signal stack length */
+ int ss_flags; /* SS_DISABLE and/or SS_ONSTACK */
+};
+
+struct osigevent32 {
+ int sigev_notify; /* Notification type */
+ union {
+ int __sigev_signo; /* Signal number */
+ int __sigev_notify_kqueue;
+ } __sigev_u;
+ union sigval32 sigev_value; /* Signal value */
+};
+
+struct sigevent32 {
+ int sigev_notify; /* Notification type */
+ int sigev_signo; /* Signal number */
+ union sigval32 sigev_value; /* Signal value */
+ union {
+ __lwpid_t _threadid;
+ struct {
+ uint32_t _function;
+ uint32_t _attribute;
+ } _sigev_thread;
+ unsigned short _kevent_flags;
+ uint32_t __spare__[8];
+ } _sigev_un;
+};
+
+struct sigevent;
+int convert_sigevent32(struct sigevent32 *sig32, struct sigevent *sig);
+void siginfo_to_siginfo32(const siginfo_t *src, struct siginfo32 *dst);
+
+#endif /* !_COMPAT_FREEBSD32_SIGNAL_H_ */
diff --git a/sys/compat/freebsd32/freebsd32_syscall.h b/sys/compat/freebsd32/freebsd32_syscall.h
new file mode 100644
index 000000000000..eea7e2f56968
--- /dev/null
+++ b/sys/compat/freebsd32/freebsd32_syscall.h
@@ -0,0 +1,509 @@
+/*
+ * System call numbers.
+ *
+ * DO NOT EDIT-- this file is automatically @generated.
+ * $FreeBSD$
+ */
+
+#define FREEBSD32_SYS_syscall 0
+#define FREEBSD32_SYS_exit 1
+#define FREEBSD32_SYS_fork 2
+#define FREEBSD32_SYS_read 3
+#define FREEBSD32_SYS_write 4
+#define FREEBSD32_SYS_open 5
+#define FREEBSD32_SYS_close 6
+#define FREEBSD32_SYS_freebsd32_wait4 7
+ /* 8 is obsolete old creat */
+#define FREEBSD32_SYS_link 9
+#define FREEBSD32_SYS_unlink 10
+ /* 11 is obsolete execv */
+#define FREEBSD32_SYS_chdir 12
+#define FREEBSD32_SYS_fchdir 13
+#define FREEBSD32_SYS_freebsd11_mknod 14
+#define FREEBSD32_SYS_chmod 15
+#define FREEBSD32_SYS_chown 16
+#define FREEBSD32_SYS_break 17
+ /* 18 is freebsd4 freebsd32_getfsstat */
+ /* 19 is old freebsd32_lseek */
+#define FREEBSD32_SYS_getpid 20
+#define FREEBSD32_SYS_mount 21
+#define FREEBSD32_SYS_unmount 22
+#define FREEBSD32_SYS_setuid 23
+#define FREEBSD32_SYS_getuid 24
+#define FREEBSD32_SYS_geteuid 25
+#define FREEBSD32_SYS_freebsd32_ptrace 26
+#define FREEBSD32_SYS_freebsd32_recvmsg 27
+#define FREEBSD32_SYS_freebsd32_sendmsg 28
+#define FREEBSD32_SYS_freebsd32_recvfrom 29
+#define FREEBSD32_SYS_accept 30
+#define FREEBSD32_SYS_getpeername 31
+#define FREEBSD32_SYS_getsockname 32
+#define FREEBSD32_SYS_access 33
+#define FREEBSD32_SYS_chflags 34
+#define FREEBSD32_SYS_fchflags 35
+#define FREEBSD32_SYS_sync 36
+#define FREEBSD32_SYS_kill 37
+ /* 38 is old freebsd32_stat */
+#define FREEBSD32_SYS_getppid 39
+ /* 40 is old freebsd32_lstat */
+#define FREEBSD32_SYS_dup 41
+#define FREEBSD32_SYS_freebsd10_freebsd32_pipe 42
+#define FREEBSD32_SYS_getegid 43
+#define FREEBSD32_SYS_profil 44
+#define FREEBSD32_SYS_ktrace 45
+ /* 46 is old freebsd32_sigaction */
+#define FREEBSD32_SYS_getgid 47
+ /* 48 is old freebsd32_sigprocmask */
+#define FREEBSD32_SYS_getlogin 49
+#define FREEBSD32_SYS_setlogin 50
+#define FREEBSD32_SYS_acct 51
+ /* 52 is old freebsd32_sigpending */
+#define FREEBSD32_SYS_freebsd32_sigaltstack 53
+#define FREEBSD32_SYS_freebsd32_ioctl 54
+#define FREEBSD32_SYS_reboot 55
+#define FREEBSD32_SYS_revoke 56
+#define FREEBSD32_SYS_symlink 57
+#define FREEBSD32_SYS_readlink 58
+#define FREEBSD32_SYS_freebsd32_execve 59
+#define FREEBSD32_SYS_umask 60
+#define FREEBSD32_SYS_chroot 61
+ /* 62 is old freebsd32_fstat */
+ /* 63 is obsolete ogetkerninfo */
+ /* 64 is old freebsd32_getpagesize */
+#define FREEBSD32_SYS_msync 65
+#define FREEBSD32_SYS_vfork 66
+ /* 67 is obsolete vread */
+ /* 68 is obsolete vwrite */
+#define FREEBSD32_SYS_sbrk 69
+#define FREEBSD32_SYS_sstk 70
+ /* 71 is old mmap */
+#define FREEBSD32_SYS_freebsd11_vadvise 72
+#define FREEBSD32_SYS_munmap 73
+#define FREEBSD32_SYS_freebsd32_mprotect 74
+#define FREEBSD32_SYS_madvise 75
+ /* 76 is obsolete vhangup */
+ /* 77 is obsolete vlimit */
+#define FREEBSD32_SYS_mincore 78
+#define FREEBSD32_SYS_getgroups 79
+#define FREEBSD32_SYS_setgroups 80
+#define FREEBSD32_SYS_getpgrp 81
+#define FREEBSD32_SYS_setpgid 82
+#define FREEBSD32_SYS_freebsd32_setitimer 83
+ /* 84 is obsolete owait */
+#define FREEBSD32_SYS_swapon 85
+#define FREEBSD32_SYS_freebsd32_getitimer 86
+ /* 87 is obsolete ogethostname */
+ /* 88 is obsolete osethostname */
+#define FREEBSD32_SYS_getdtablesize 89
+#define FREEBSD32_SYS_dup2 90
+#define FREEBSD32_SYS_freebsd32_fcntl 92
+#define FREEBSD32_SYS_freebsd32_select 93
+#define FREEBSD32_SYS_fsync 95
+#define FREEBSD32_SYS_setpriority 96
+#define FREEBSD32_SYS_socket 97
+#define FREEBSD32_SYS_connect 98
+ /* 99 is obsolete oaccept */
+#define FREEBSD32_SYS_getpriority 100
+ /* 101 is obsolete osend */
+ /* 102 is obsolete orecv */
+ /* 103 is old freebsd32_sigreturn */
+#define FREEBSD32_SYS_bind 104
+#define FREEBSD32_SYS_setsockopt 105
+#define FREEBSD32_SYS_listen 106
+ /* 107 is obsolete vtimes */
+ /* 108 is old freebsd32_sigvec */
+ /* 109 is old freebsd32_sigblock */
+ /* 110 is old freebsd32_sigsetmask */
+ /* 111 is old freebsd32_sigsuspend */
+ /* 112 is old freebsd32_sigstack */
+ /* 113 is obsolete orecvmsg */
+ /* 114 is obsolete osendmsg */
+ /* 115 is obsolete vtrace */
+#define FREEBSD32_SYS_freebsd32_gettimeofday 116
+#define FREEBSD32_SYS_freebsd32_getrusage 117
+#define FREEBSD32_SYS_getsockopt 118
+#define FREEBSD32_SYS_freebsd32_readv 120
+#define FREEBSD32_SYS_freebsd32_writev 121
+#define FREEBSD32_SYS_freebsd32_settimeofday 122
+#define FREEBSD32_SYS_fchown 123
+#define FREEBSD32_SYS_fchmod 124
+ /* 125 is obsolete orecvfrom */
+#define FREEBSD32_SYS_setreuid 126
+#define FREEBSD32_SYS_setregid 127
+#define FREEBSD32_SYS_rename 128
+ /* 129 is old truncate */
+ /* 130 is old ftruncate */
+#define FREEBSD32_SYS_flock 131
+#define FREEBSD32_SYS_mkfifo 132
+#define FREEBSD32_SYS_sendto 133
+#define FREEBSD32_SYS_shutdown 134
+#define FREEBSD32_SYS_socketpair 135
+#define FREEBSD32_SYS_mkdir 136
+#define FREEBSD32_SYS_rmdir 137
+#define FREEBSD32_SYS_freebsd32_utimes 138
+ /* 139 is obsolete 4.2 sigreturn */
+#define FREEBSD32_SYS_freebsd32_adjtime 140
+ /* 141 is obsolete ogetpeername */
+ /* 142 is obsolete ogethostid */
+ /* 143 is obsolete sethostid */
+ /* 144 is obsolete getrlimit */
+ /* 145 is obsolete setrlimit */
+ /* 146 is obsolete killpg */
+#define FREEBSD32_SYS_setsid 147
+#define FREEBSD32_SYS_quotactl 148
+ /* 149 is obsolete oquota */
+ /* 150 is obsolete ogetsockname */
+ /* 156 is old freebsd32_getdirentries */
+ /* 157 is freebsd4 freebsd32_statfs */
+ /* 158 is freebsd4 freebsd32_fstatfs */
+#define FREEBSD32_SYS_getfh 161
+ /* 162 is obsolete getdomainname */
+ /* 163 is obsolete setdomainname */
+ /* 164 is obsolete uname */
+#define FREEBSD32_SYS_freebsd32_sysarch 165
+#define FREEBSD32_SYS_rtprio 166
+#define FREEBSD32_SYS_freebsd32_semsys 169
+#define FREEBSD32_SYS_freebsd32_msgsys 170
+#define FREEBSD32_SYS_freebsd32_shmsys 171
+ /* 173 is freebsd6 freebsd32_pread */
+ /* 174 is freebsd6 freebsd32_pwrite */
+#define FREEBSD32_SYS_freebsd32_ntp_adjtime 176
+#define FREEBSD32_SYS_setgid 181
+#define FREEBSD32_SYS_setegid 182
+#define FREEBSD32_SYS_seteuid 183
+ /* 184 is obsolete lfs_bmapv */
+ /* 185 is obsolete lfs_markv */
+ /* 186 is obsolete lfs_segclean */
+ /* 187 is obsolete lfs_segwait */
+#define FREEBSD32_SYS_freebsd11_freebsd32_stat 188
+#define FREEBSD32_SYS_freebsd11_freebsd32_fstat 189
+#define FREEBSD32_SYS_freebsd11_freebsd32_lstat 190
+#define FREEBSD32_SYS_pathconf 191
+#define FREEBSD32_SYS_fpathconf 192
+#define FREEBSD32_SYS_getrlimit 194
+#define FREEBSD32_SYS_setrlimit 195
+#define FREEBSD32_SYS_freebsd11_freebsd32_getdirentries 196
+ /* 197 is freebsd6 freebsd32_mmap */
+#define FREEBSD32_SYS___syscall 198
+ /* 199 is freebsd6 freebsd32_lseek */
+ /* 200 is freebsd6 freebsd32_truncate */
+ /* 201 is freebsd6 freebsd32_ftruncate */
+#define FREEBSD32_SYS_freebsd32___sysctl 202
+#define FREEBSD32_SYS_mlock 203
+#define FREEBSD32_SYS_munlock 204
+#define FREEBSD32_SYS_undelete 205
+#define FREEBSD32_SYS_freebsd32_futimes 206
+#define FREEBSD32_SYS_getpgid 207
+#define FREEBSD32_SYS_poll 209
+#define FREEBSD32_SYS_freebsd7_freebsd32_semctl 220
+#define FREEBSD32_SYS_semget 221
+#define FREEBSD32_SYS_semop 222
+ /* 223 is obsolete semconfig */
+#define FREEBSD32_SYS_freebsd7_freebsd32_msgctl 224
+#define FREEBSD32_SYS_msgget 225
+#define FREEBSD32_SYS_freebsd32_msgsnd 226
+#define FREEBSD32_SYS_freebsd32_msgrcv 227
+#define FREEBSD32_SYS_shmat 228
+#define FREEBSD32_SYS_freebsd7_freebsd32_shmctl 229
+#define FREEBSD32_SYS_shmdt 230
+#define FREEBSD32_SYS_shmget 231
+#define FREEBSD32_SYS_freebsd32_clock_gettime 232
+#define FREEBSD32_SYS_freebsd32_clock_settime 233
+#define FREEBSD32_SYS_freebsd32_clock_getres 234
+#define FREEBSD32_SYS_freebsd32_ktimer_create 235
+#define FREEBSD32_SYS_ktimer_delete 236
+#define FREEBSD32_SYS_freebsd32_ktimer_settime 237
+#define FREEBSD32_SYS_freebsd32_ktimer_gettime 238
+#define FREEBSD32_SYS_ktimer_getoverrun 239
+#define FREEBSD32_SYS_freebsd32_nanosleep 240
+#define FREEBSD32_SYS_ffclock_getcounter 241
+#define FREEBSD32_SYS_ffclock_setestimate 242
+#define FREEBSD32_SYS_ffclock_getestimate 243
+#define FREEBSD32_SYS_freebsd32_clock_nanosleep 244
+#define FREEBSD32_SYS_freebsd32_clock_getcpuclockid2 247
+#define FREEBSD32_SYS_minherit 250
+#define FREEBSD32_SYS_rfork 251
+ /* 252 is obsolete openbsd_poll */
+#define FREEBSD32_SYS_issetugid 253
+#define FREEBSD32_SYS_lchown 254
+#define FREEBSD32_SYS_freebsd32_aio_read 255
+#define FREEBSD32_SYS_freebsd32_aio_write 256
+#define FREEBSD32_SYS_freebsd32_lio_listio 257
+#define FREEBSD32_SYS_freebsd11_freebsd32_getdents 272
+#define FREEBSD32_SYS_lchmod 274
+ /* 275 is obsolete netbsd_lchown */
+#define FREEBSD32_SYS_freebsd32_lutimes 276
+ /* 277 is obsolete netbsd_msync */
+#define FREEBSD32_SYS_freebsd11_nstat 278
+#define FREEBSD32_SYS_freebsd11_nfstat 279
+#define FREEBSD32_SYS_freebsd11_nlstat 280
+#define FREEBSD32_SYS_freebsd32_preadv 289
+#define FREEBSD32_SYS_freebsd32_pwritev 290
+ /* 297 is freebsd4 freebsd32_fhstatfs */
+#define FREEBSD32_SYS_fhopen 298
+#define FREEBSD32_SYS_freebsd11_freebsd32_fhstat 299
+#define FREEBSD32_SYS_modnext 300
+#define FREEBSD32_SYS_freebsd32_modstat 301
+#define FREEBSD32_SYS_modfnext 302
+#define FREEBSD32_SYS_modfind 303
+#define FREEBSD32_SYS_kldload 304
+#define FREEBSD32_SYS_kldunload 305
+#define FREEBSD32_SYS_kldfind 306
+#define FREEBSD32_SYS_kldnext 307
+#define FREEBSD32_SYS_freebsd32_kldstat 308
+#define FREEBSD32_SYS_kldfirstmod 309
+#define FREEBSD32_SYS_getsid 310
+#define FREEBSD32_SYS_setresuid 311
+#define FREEBSD32_SYS_setresgid 312
+ /* 313 is obsolete signanosleep */
+#define FREEBSD32_SYS_freebsd32_aio_return 314
+#define FREEBSD32_SYS_freebsd32_aio_suspend 315
+#define FREEBSD32_SYS_aio_cancel 316
+#define FREEBSD32_SYS_freebsd32_aio_error 317
+ /* 318 is freebsd6 freebsd32_aio_read */
+ /* 319 is freebsd6 freebsd32_aio_write */
+ /* 320 is freebsd6 freebsd32_lio_listio */
+#define FREEBSD32_SYS_yield 321
+ /* 322 is obsolete thr_sleep */
+ /* 323 is obsolete thr_wakeup */
+#define FREEBSD32_SYS_mlockall 324
+#define FREEBSD32_SYS_munlockall 325
+#define FREEBSD32_SYS___getcwd 326
+#define FREEBSD32_SYS_sched_setparam 327
+#define FREEBSD32_SYS_sched_getparam 328
+#define FREEBSD32_SYS_sched_setscheduler 329
+#define FREEBSD32_SYS_sched_getscheduler 330
+#define FREEBSD32_SYS_sched_yield 331
+#define FREEBSD32_SYS_sched_get_priority_max 332
+#define FREEBSD32_SYS_sched_get_priority_min 333
+#define FREEBSD32_SYS_freebsd32_sched_rr_get_interval 334
+#define FREEBSD32_SYS_utrace 335
+ /* 336 is freebsd4 freebsd32_sendfile */
+#define FREEBSD32_SYS_kldsym 337
+#define FREEBSD32_SYS_freebsd32_jail 338
+#define FREEBSD32_SYS_sigprocmask 340
+#define FREEBSD32_SYS_sigsuspend 341
+ /* 342 is freebsd4 freebsd32_sigaction */
+#define FREEBSD32_SYS_sigpending 343
+ /* 344 is freebsd4 freebsd32_sigreturn */
+#define FREEBSD32_SYS_freebsd32_sigtimedwait 345
+#define FREEBSD32_SYS_freebsd32_sigwaitinfo 346
+#define FREEBSD32_SYS___acl_get_file 347
+#define FREEBSD32_SYS___acl_set_file 348
+#define FREEBSD32_SYS___acl_get_fd 349
+#define FREEBSD32_SYS___acl_set_fd 350
+#define FREEBSD32_SYS___acl_delete_file 351
+#define FREEBSD32_SYS___acl_delete_fd 352
+#define FREEBSD32_SYS___acl_aclcheck_file 353
+#define FREEBSD32_SYS___acl_aclcheck_fd 354
+#define FREEBSD32_SYS_extattrctl 355
+#define FREEBSD32_SYS_extattr_set_file 356
+#define FREEBSD32_SYS_extattr_get_file 357
+#define FREEBSD32_SYS_extattr_delete_file 358
+#define FREEBSD32_SYS_freebsd32_aio_waitcomplete 359
+#define FREEBSD32_SYS_getresuid 360
+#define FREEBSD32_SYS_getresgid 361
+#define FREEBSD32_SYS_kqueue 362
+#define FREEBSD32_SYS_freebsd11_freebsd32_kevent 363
+ /* 364 is obsolete __cap_get_proc */
+ /* 365 is obsolete __cap_set_proc */
+ /* 366 is obsolete __cap_get_fd */
+ /* 367 is obsolete __cap_get_file */
+ /* 368 is obsolete __cap_set_fd */
+ /* 369 is obsolete __cap_set_file */
+#define FREEBSD32_SYS_extattr_set_fd 371
+#define FREEBSD32_SYS_extattr_get_fd 372
+#define FREEBSD32_SYS_extattr_delete_fd 373
+#define FREEBSD32_SYS___setugid 374
+ /* 375 is obsolete nfsclnt */
+#define FREEBSD32_SYS_eaccess 376
+#define FREEBSD32_SYS_freebsd32_nmount 378
+ /* 379 is obsolete kse_exit */
+ /* 380 is obsolete kse_wakeup */
+ /* 381 is obsolete kse_create */
+ /* 382 is obsolete kse_thr_interrupt */
+ /* 383 is obsolete kse_release */
+#define FREEBSD32_SYS_kenv 390
+#define FREEBSD32_SYS_lchflags 391
+#define FREEBSD32_SYS_uuidgen 392
+#define FREEBSD32_SYS_freebsd32_sendfile 393
+#define FREEBSD32_SYS_freebsd11_getfsstat 395
+#define FREEBSD32_SYS_freebsd11_statfs 396
+#define FREEBSD32_SYS_freebsd11_fstatfs 397
+#define FREEBSD32_SYS_freebsd11_fhstatfs 398
+#define FREEBSD32_SYS_ksem_close 400
+#define FREEBSD32_SYS_ksem_post 401
+#define FREEBSD32_SYS_ksem_wait 402
+#define FREEBSD32_SYS_ksem_trywait 403
+#define FREEBSD32_SYS_freebsd32_ksem_init 404
+#define FREEBSD32_SYS_freebsd32_ksem_open 405
+#define FREEBSD32_SYS_ksem_unlink 406
+#define FREEBSD32_SYS_ksem_getvalue 407
+#define FREEBSD32_SYS_ksem_destroy 408
+#define FREEBSD32_SYS_extattr_set_link 412
+#define FREEBSD32_SYS_extattr_get_link 413
+#define FREEBSD32_SYS_extattr_delete_link 414
+#define FREEBSD32_SYS_freebsd32_sigaction 416
+#define FREEBSD32_SYS_freebsd32_sigreturn 417
+#define FREEBSD32_SYS_freebsd32_getcontext 421
+#define FREEBSD32_SYS_freebsd32_setcontext 422
+#define FREEBSD32_SYS_freebsd32_swapcontext 423
+#define FREEBSD32_SYS___acl_get_link 425
+#define FREEBSD32_SYS___acl_set_link 426
+#define FREEBSD32_SYS___acl_delete_link 427
+#define FREEBSD32_SYS___acl_aclcheck_link 428
+#define FREEBSD32_SYS_sigwait 429
+#define FREEBSD32_SYS_thr_exit 431
+#define FREEBSD32_SYS_thr_self 432
+#define FREEBSD32_SYS_thr_kill 433
+#define FREEBSD32_SYS_jail_attach 436
+#define FREEBSD32_SYS_extattr_list_fd 437
+#define FREEBSD32_SYS_extattr_list_file 438
+#define FREEBSD32_SYS_extattr_list_link 439
+ /* 440 is obsolete kse_switchin */
+#define FREEBSD32_SYS_freebsd32_ksem_timedwait 441
+#define FREEBSD32_SYS_freebsd32_thr_suspend 442
+#define FREEBSD32_SYS_thr_wake 443
+#define FREEBSD32_SYS_kldunloadf 444
+#define FREEBSD32_SYS_audit 445
+#define FREEBSD32_SYS_auditon 446
+#define FREEBSD32_SYS_getauid 447
+#define FREEBSD32_SYS_setauid 448
+#define FREEBSD32_SYS_getaudit 449
+#define FREEBSD32_SYS_setaudit 450
+#define FREEBSD32_SYS_getaudit_addr 451
+#define FREEBSD32_SYS_setaudit_addr 452
+#define FREEBSD32_SYS_auditctl 453
+#define FREEBSD32_SYS_freebsd32__umtx_op 454
+#define FREEBSD32_SYS_freebsd32_thr_new 455
+#define FREEBSD32_SYS_freebsd32_sigqueue 456
+#define FREEBSD32_SYS_freebsd32_kmq_open 457
+#define FREEBSD32_SYS_freebsd32_kmq_setattr 458
+#define FREEBSD32_SYS_freebsd32_kmq_timedreceive 459
+#define FREEBSD32_SYS_freebsd32_kmq_timedsend 460
+#define FREEBSD32_SYS_freebsd32_kmq_notify 461
+#define FREEBSD32_SYS_kmq_unlink 462
+#define FREEBSD32_SYS_abort2 463
+#define FREEBSD32_SYS_thr_set_name 464
+#define FREEBSD32_SYS_freebsd32_aio_fsync 465
+#define FREEBSD32_SYS_rtprio_thread 466
+#define FREEBSD32_SYS_sctp_peeloff 471
+#define FREEBSD32_SYS_sctp_generic_sendmsg 472
+#define FREEBSD32_SYS_sctp_generic_sendmsg_iov 473
+#define FREEBSD32_SYS_sctp_generic_recvmsg 474
+#define FREEBSD32_SYS_freebsd32_pread 475
+#define FREEBSD32_SYS_freebsd32_pwrite 476
+#define FREEBSD32_SYS_freebsd32_mmap 477
+#define FREEBSD32_SYS_freebsd32_lseek 478
+#define FREEBSD32_SYS_freebsd32_truncate 479
+#define FREEBSD32_SYS_freebsd32_ftruncate 480
+#define FREEBSD32_SYS_freebsd32_pread 475
+#define FREEBSD32_SYS_freebsd32_pwrite 476
+#define FREEBSD32_SYS_freebsd32_mmap 477
+#define FREEBSD32_SYS_freebsd32_lseek 478
+#define FREEBSD32_SYS_freebsd32_truncate 479
+#define FREEBSD32_SYS_freebsd32_ftruncate 480
+#define FREEBSD32_SYS_thr_kill2 481
+#define FREEBSD32_SYS_freebsd12_shm_open 482
+#define FREEBSD32_SYS_shm_unlink 483
+#define FREEBSD32_SYS_cpuset 484
+#define FREEBSD32_SYS_freebsd32_cpuset_setid 485
+#define FREEBSD32_SYS_freebsd32_cpuset_setid 485
+#define FREEBSD32_SYS_freebsd32_cpuset_getid 486
+#define FREEBSD32_SYS_freebsd32_cpuset_getaffinity 487
+#define FREEBSD32_SYS_freebsd32_cpuset_setaffinity 488
+#define FREEBSD32_SYS_faccessat 489
+#define FREEBSD32_SYS_fchmodat 490
+#define FREEBSD32_SYS_fchownat 491
+#define FREEBSD32_SYS_freebsd32_fexecve 492
+#define FREEBSD32_SYS_freebsd11_freebsd32_fstatat 493
+#define FREEBSD32_SYS_freebsd32_futimesat 494
+#define FREEBSD32_SYS_linkat 495
+#define FREEBSD32_SYS_mkdirat 496
+#define FREEBSD32_SYS_mkfifoat 497
+#define FREEBSD32_SYS_freebsd11_mknodat 498
+#define FREEBSD32_SYS_openat 499
+#define FREEBSD32_SYS_readlinkat 500
+#define FREEBSD32_SYS_renameat 501
+#define FREEBSD32_SYS_symlinkat 502
+#define FREEBSD32_SYS_unlinkat 503
+#define FREEBSD32_SYS_posix_openpt 504
+#define FREEBSD32_SYS_freebsd32_jail_get 506
+#define FREEBSD32_SYS_freebsd32_jail_set 507
+#define FREEBSD32_SYS_jail_remove 508
+#define FREEBSD32_SYS_freebsd12_closefrom 509
+#define FREEBSD32_SYS_freebsd32_semctl 510
+#define FREEBSD32_SYS_freebsd32_msgctl 511
+#define FREEBSD32_SYS_freebsd32_shmctl 512
+#define FREEBSD32_SYS_lpathconf 513
+ /* 514 is obsolete cap_new */
+#define FREEBSD32_SYS___cap_rights_get 515
+#define FREEBSD32_SYS_cap_enter 516
+#define FREEBSD32_SYS_cap_getmode 517
+#define FREEBSD32_SYS_pdfork 518
+#define FREEBSD32_SYS_pdkill 519
+#define FREEBSD32_SYS_pdgetpid 520
+#define FREEBSD32_SYS_freebsd32_pselect 522
+#define FREEBSD32_SYS_getloginclass 523
+#define FREEBSD32_SYS_setloginclass 524
+#define FREEBSD32_SYS_rctl_get_racct 525
+#define FREEBSD32_SYS_rctl_get_rules 526
+#define FREEBSD32_SYS_rctl_get_limits 527
+#define FREEBSD32_SYS_rctl_add_rule 528
+#define FREEBSD32_SYS_rctl_remove_rule 529
+#define FREEBSD32_SYS_freebsd32_posix_fallocate 530
+#define FREEBSD32_SYS_freebsd32_posix_fadvise 531
+#define FREEBSD32_SYS_freebsd32_wait6 532
+#define FREEBSD32_SYS_freebsd32_posix_fallocate 530
+#define FREEBSD32_SYS_freebsd32_posix_fadvise 531
+#define FREEBSD32_SYS_freebsd32_wait6 532
+#define FREEBSD32_SYS_cap_rights_limit 533
+#define FREEBSD32_SYS_freebsd32_cap_ioctls_limit 534
+#define FREEBSD32_SYS_freebsd32_cap_ioctls_get 535
+#define FREEBSD32_SYS_cap_fcntls_limit 536
+#define FREEBSD32_SYS_cap_fcntls_get 537
+#define FREEBSD32_SYS_bindat 538
+#define FREEBSD32_SYS_connectat 539
+#define FREEBSD32_SYS_chflagsat 540
+#define FREEBSD32_SYS_accept4 541
+#define FREEBSD32_SYS_pipe2 542
+#define FREEBSD32_SYS_freebsd32_aio_mlock 543
+#define FREEBSD32_SYS_freebsd32_procctl 544
+#define FREEBSD32_SYS_freebsd32_procctl 544
+#define FREEBSD32_SYS_freebsd32_ppoll 545
+#define FREEBSD32_SYS_freebsd32_futimens 546
+#define FREEBSD32_SYS_freebsd32_utimensat 547
+ /* 548 is obsolete numa_getaffinity */
+ /* 549 is obsolete numa_setaffinity */
+#define FREEBSD32_SYS_fdatasync 550
+#define FREEBSD32_SYS_freebsd32_fstat 551
+#define FREEBSD32_SYS_freebsd32_fstatat 552
+#define FREEBSD32_SYS_freebsd32_fhstat 553
+#define FREEBSD32_SYS_getdirentries 554
+#define FREEBSD32_SYS_statfs 555
+#define FREEBSD32_SYS_fstatfs 556
+#define FREEBSD32_SYS_getfsstat 557
+#define FREEBSD32_SYS_fhstatfs 558
+#define FREEBSD32_SYS_freebsd32_mknodat 559
+#define FREEBSD32_SYS_freebsd32_mknodat 559
+#define FREEBSD32_SYS_freebsd32_kevent 560
+#define FREEBSD32_SYS_freebsd32_cpuset_getdomain 561
+#define FREEBSD32_SYS_freebsd32_cpuset_setdomain 562
+#define FREEBSD32_SYS_getrandom 563
+#define FREEBSD32_SYS_getfhat 564
+#define FREEBSD32_SYS_fhlink 565
+#define FREEBSD32_SYS_fhlinkat 566
+#define FREEBSD32_SYS_fhreadlink 567
+#define FREEBSD32_SYS_funlinkat 568
+#define FREEBSD32_SYS_copy_file_range 569
+#define FREEBSD32_SYS_freebsd32___sysctlbyname 570
+#define FREEBSD32_SYS_shm_open2 571
+#define FREEBSD32_SYS_shm_rename 572
+#define FREEBSD32_SYS_sigfastblock 573
+#define FREEBSD32_SYS___realpathat 574
+#define FREEBSD32_SYS_close_range 575
+#define FREEBSD32_SYS_rpctls_syscall 576
+#define FREEBSD32_SYS___specialfd 577
+#define FREEBSD32_SYS_freebsd32_aio_writev 578
+#define FREEBSD32_SYS_freebsd32_aio_readv 579
+#define FREEBSD32_SYS_MAXSYSCALL 580
diff --git a/sys/compat/freebsd32/freebsd32_syscalls.c b/sys/compat/freebsd32/freebsd32_syscalls.c
new file mode 100644
index 000000000000..0311882f02d0
--- /dev/null
+++ b/sys/compat/freebsd32/freebsd32_syscalls.c
@@ -0,0 +1,619 @@
+/*
+ * System call names.
+ *
+ * DO NOT EDIT-- this file is automatically @generated.
+ * $FreeBSD$
+ */
+
+const char *freebsd32_syscallnames[] = {
+#if !defined(PAD64_REQUIRED) && !defined(__amd64__)
+#define PAD64_REQUIRED
+#endif
+ "syscall", /* 0 = syscall */
+ "exit", /* 1 = exit */
+ "fork", /* 2 = fork */
+ "read", /* 3 = read */
+ "write", /* 4 = write */
+ "open", /* 5 = open */
+ "close", /* 6 = close */
+ "freebsd32_wait4", /* 7 = freebsd32_wait4 */
+ "obs_old", /* 8 = obsolete old creat */
+ "link", /* 9 = link */
+ "unlink", /* 10 = unlink */
+ "obs_execv", /* 11 = obsolete execv */
+ "chdir", /* 12 = chdir */
+ "fchdir", /* 13 = fchdir */
+ "compat11.mknod", /* 14 = freebsd11 mknod */
+ "chmod", /* 15 = chmod */
+ "chown", /* 16 = chown */
+ "break", /* 17 = break */
+ "compat4.freebsd32_getfsstat", /* 18 = freebsd4 freebsd32_getfsstat */
+ "compat.freebsd32_lseek", /* 19 = old freebsd32_lseek */
+ "getpid", /* 20 = getpid */
+ "mount", /* 21 = mount */
+ "unmount", /* 22 = unmount */
+ "setuid", /* 23 = setuid */
+ "getuid", /* 24 = getuid */
+ "geteuid", /* 25 = geteuid */
+ "freebsd32_ptrace", /* 26 = freebsd32_ptrace */
+ "freebsd32_recvmsg", /* 27 = freebsd32_recvmsg */
+ "freebsd32_sendmsg", /* 28 = freebsd32_sendmsg */
+ "freebsd32_recvfrom", /* 29 = freebsd32_recvfrom */
+ "accept", /* 30 = accept */
+ "getpeername", /* 31 = getpeername */
+ "getsockname", /* 32 = getsockname */
+ "access", /* 33 = access */
+ "chflags", /* 34 = chflags */
+ "fchflags", /* 35 = fchflags */
+ "sync", /* 36 = sync */
+ "kill", /* 37 = kill */
+ "compat.freebsd32_stat", /* 38 = old freebsd32_stat */
+ "getppid", /* 39 = getppid */
+ "compat.freebsd32_lstat", /* 40 = old freebsd32_lstat */
+ "dup", /* 41 = dup */
+ "compat10.freebsd32_pipe", /* 42 = freebsd10 freebsd32_pipe */
+ "getegid", /* 43 = getegid */
+ "profil", /* 44 = profil */
+ "ktrace", /* 45 = ktrace */
+ "compat.freebsd32_sigaction", /* 46 = old freebsd32_sigaction */
+ "getgid", /* 47 = getgid */
+ "compat.freebsd32_sigprocmask", /* 48 = old freebsd32_sigprocmask */
+ "getlogin", /* 49 = getlogin */
+ "setlogin", /* 50 = setlogin */
+ "acct", /* 51 = acct */
+ "compat.freebsd32_sigpending", /* 52 = old freebsd32_sigpending */
+ "freebsd32_sigaltstack", /* 53 = freebsd32_sigaltstack */
+ "freebsd32_ioctl", /* 54 = freebsd32_ioctl */
+ "reboot", /* 55 = reboot */
+ "revoke", /* 56 = revoke */
+ "symlink", /* 57 = symlink */
+ "readlink", /* 58 = readlink */
+ "freebsd32_execve", /* 59 = freebsd32_execve */
+ "umask", /* 60 = umask */
+ "chroot", /* 61 = chroot */
+ "compat.freebsd32_fstat", /* 62 = old freebsd32_fstat */
+ "obs_ogetkerninfo", /* 63 = obsolete ogetkerninfo */
+ "compat.freebsd32_getpagesize", /* 64 = old freebsd32_getpagesize */
+ "msync", /* 65 = msync */
+ "vfork", /* 66 = vfork */
+ "obs_vread", /* 67 = obsolete vread */
+ "obs_vwrite", /* 68 = obsolete vwrite */
+ "sbrk", /* 69 = sbrk */
+ "sstk", /* 70 = sstk */
+ "compat.mmap", /* 71 = old mmap */
+ "compat11.vadvise", /* 72 = freebsd11 vadvise */
+ "munmap", /* 73 = munmap */
+ "freebsd32_mprotect", /* 74 = freebsd32_mprotect */
+ "madvise", /* 75 = madvise */
+ "obs_vhangup", /* 76 = obsolete vhangup */
+ "obs_vlimit", /* 77 = obsolete vlimit */
+ "mincore", /* 78 = mincore */
+ "getgroups", /* 79 = getgroups */
+ "setgroups", /* 80 = setgroups */
+ "getpgrp", /* 81 = getpgrp */
+ "setpgid", /* 82 = setpgid */
+ "freebsd32_setitimer", /* 83 = freebsd32_setitimer */
+ "obs_owait", /* 84 = obsolete owait */
+ "swapon", /* 85 = swapon */
+ "freebsd32_getitimer", /* 86 = freebsd32_getitimer */
+ "obs_ogethostname", /* 87 = obsolete ogethostname */
+ "obs_osethostname", /* 88 = obsolete osethostname */
+ "getdtablesize", /* 89 = getdtablesize */
+ "dup2", /* 90 = dup2 */
+ "#91", /* 91 = getdopt */
+ "freebsd32_fcntl", /* 92 = freebsd32_fcntl */
+ "freebsd32_select", /* 93 = freebsd32_select */
+ "#94", /* 94 = setdopt */
+ "fsync", /* 95 = fsync */
+ "setpriority", /* 96 = setpriority */
+ "socket", /* 97 = socket */
+ "connect", /* 98 = connect */
+ "obs_oaccept", /* 99 = obsolete oaccept */
+ "getpriority", /* 100 = getpriority */
+ "obs_osend", /* 101 = obsolete osend */
+ "obs_orecv", /* 102 = obsolete orecv */
+ "compat.freebsd32_sigreturn", /* 103 = old freebsd32_sigreturn */
+ "bind", /* 104 = bind */
+ "setsockopt", /* 105 = setsockopt */
+ "listen", /* 106 = listen */
+ "obs_vtimes", /* 107 = obsolete vtimes */
+ "compat.freebsd32_sigvec", /* 108 = old freebsd32_sigvec */
+ "compat.freebsd32_sigblock", /* 109 = old freebsd32_sigblock */
+ "compat.freebsd32_sigsetmask", /* 110 = old freebsd32_sigsetmask */
+ "compat.freebsd32_sigsuspend", /* 111 = old freebsd32_sigsuspend */
+ "compat.freebsd32_sigstack", /* 112 = old freebsd32_sigstack */
+ "obs_orecvmsg", /* 113 = obsolete orecvmsg */
+ "obs_osendmsg", /* 114 = obsolete osendmsg */
+ "obs_vtrace", /* 115 = obsolete vtrace */
+ "freebsd32_gettimeofday", /* 116 = freebsd32_gettimeofday */
+ "freebsd32_getrusage", /* 117 = freebsd32_getrusage */
+ "getsockopt", /* 118 = getsockopt */
+ "#119", /* 119 = resuba */
+ "freebsd32_readv", /* 120 = freebsd32_readv */
+ "freebsd32_writev", /* 121 = freebsd32_writev */
+ "freebsd32_settimeofday", /* 122 = freebsd32_settimeofday */
+ "fchown", /* 123 = fchown */
+ "fchmod", /* 124 = fchmod */
+ "obs_orecvfrom", /* 125 = obsolete orecvfrom */
+ "setreuid", /* 126 = setreuid */
+ "setregid", /* 127 = setregid */
+ "rename", /* 128 = rename */
+ "compat.truncate", /* 129 = old truncate */
+ "compat.ftruncate", /* 130 = old ftruncate */
+ "flock", /* 131 = flock */
+ "mkfifo", /* 132 = mkfifo */
+ "sendto", /* 133 = sendto */
+ "shutdown", /* 134 = shutdown */
+ "socketpair", /* 135 = socketpair */
+ "mkdir", /* 136 = mkdir */
+ "rmdir", /* 137 = rmdir */
+ "freebsd32_utimes", /* 138 = freebsd32_utimes */
+ "obs_4.2", /* 139 = obsolete 4.2 sigreturn */
+ "freebsd32_adjtime", /* 140 = freebsd32_adjtime */
+ "obs_ogetpeername", /* 141 = obsolete ogetpeername */
+ "obs_ogethostid", /* 142 = obsolete ogethostid */
+ "obs_sethostid", /* 143 = obsolete sethostid */
+ "obs_getrlimit", /* 144 = obsolete getrlimit */
+ "obs_setrlimit", /* 145 = obsolete setrlimit */
+ "obs_killpg", /* 146 = obsolete killpg */
+ "setsid", /* 147 = setsid */
+ "quotactl", /* 148 = quotactl */
+ "obs_oquota", /* 149 = obsolete oquota */
+ "obs_ogetsockname", /* 150 = obsolete ogetsockname */
+ "#151", /* 151 = sem_lock */
+ "#152", /* 152 = sem_wakeup */
+ "#153", /* 153 = asyncdaemon */
+ "#154", /* 154 = nlm_syscall */
+ "#155", /* 155 = nfssvc */
+ "compat.freebsd32_getdirentries", /* 156 = old freebsd32_getdirentries */
+ "compat4.freebsd32_statfs", /* 157 = freebsd4 freebsd32_statfs */
+ "compat4.freebsd32_fstatfs", /* 158 = freebsd4 freebsd32_fstatfs */
+ "#159", /* 159 = nosys */
+ "#160", /* 160 = lgetfh */
+ "getfh", /* 161 = getfh */
+ "obs_getdomainname", /* 162 = obsolete getdomainname */
+ "obs_setdomainname", /* 163 = obsolete setdomainname */
+ "obs_uname", /* 164 = obsolete uname */
+ "freebsd32_sysarch", /* 165 = freebsd32_sysarch */
+ "rtprio", /* 166 = rtprio */
+ "#167", /* 167 = nosys */
+ "#168", /* 168 = nosys */
+ "freebsd32_semsys", /* 169 = freebsd32_semsys */
+ "freebsd32_msgsys", /* 170 = freebsd32_msgsys */
+ "freebsd32_shmsys", /* 171 = freebsd32_shmsys */
+ "#172", /* 172 = nosys */
+ "compat6.freebsd32_pread", /* 173 = freebsd6 freebsd32_pread */
+ "compat6.freebsd32_pwrite", /* 174 = freebsd6 freebsd32_pwrite */
+ "#175", /* 175 = nosys */
+ "freebsd32_ntp_adjtime", /* 176 = freebsd32_ntp_adjtime */
+ "#177", /* 177 = sfork */
+ "#178", /* 178 = getdescriptor */
+ "#179", /* 179 = setdescriptor */
+ "#180", /* 180 = nosys */
+ "setgid", /* 181 = setgid */
+ "setegid", /* 182 = setegid */
+ "seteuid", /* 183 = seteuid */
+ "obs_lfs_bmapv", /* 184 = obsolete lfs_bmapv */
+ "obs_lfs_markv", /* 185 = obsolete lfs_markv */
+ "obs_lfs_segclean", /* 186 = obsolete lfs_segclean */
+ "obs_lfs_segwait", /* 187 = obsolete lfs_segwait */
+ "compat11.freebsd32_stat", /* 188 = freebsd11 freebsd32_stat */
+ "compat11.freebsd32_fstat", /* 189 = freebsd11 freebsd32_fstat */
+ "compat11.freebsd32_lstat", /* 190 = freebsd11 freebsd32_lstat */
+ "pathconf", /* 191 = pathconf */
+ "fpathconf", /* 192 = fpathconf */
+ "#193", /* 193 = nosys */
+ "getrlimit", /* 194 = getrlimit */
+ "setrlimit", /* 195 = setrlimit */
+ "compat11.freebsd32_getdirentries", /* 196 = freebsd11 freebsd32_getdirentries */
+ "compat6.freebsd32_mmap", /* 197 = freebsd6 freebsd32_mmap */
+ "__syscall", /* 198 = __syscall */
+ "compat6.freebsd32_lseek", /* 199 = freebsd6 freebsd32_lseek */
+ "compat6.freebsd32_truncate", /* 200 = freebsd6 freebsd32_truncate */
+ "compat6.freebsd32_ftruncate", /* 201 = freebsd6 freebsd32_ftruncate */
+ "freebsd32___sysctl", /* 202 = freebsd32___sysctl */
+ "mlock", /* 203 = mlock */
+ "munlock", /* 204 = munlock */
+ "undelete", /* 205 = undelete */
+ "freebsd32_futimes", /* 206 = freebsd32_futimes */
+ "getpgid", /* 207 = getpgid */
+ "#208", /* 208 = nosys */
+ "poll", /* 209 = poll */
+ "lkmnosys", /* 210 = lkmnosys */
+ "lkmnosys", /* 211 = lkmnosys */
+ "lkmnosys", /* 212 = lkmnosys */
+ "lkmnosys", /* 213 = lkmnosys */
+ "lkmnosys", /* 214 = lkmnosys */
+ "lkmnosys", /* 215 = lkmnosys */
+ "lkmnosys", /* 216 = lkmnosys */
+ "lkmnosys", /* 217 = lkmnosys */
+ "lkmnosys", /* 218 = lkmnosys */
+ "lkmnosys", /* 219 = lkmnosys */
+ "compat7.freebsd32_semctl", /* 220 = freebsd7 freebsd32_semctl */
+ "semget", /* 221 = semget */
+ "semop", /* 222 = semop */
+ "obs_semconfig", /* 223 = obsolete semconfig */
+ "compat7.freebsd32_msgctl", /* 224 = freebsd7 freebsd32_msgctl */
+ "msgget", /* 225 = msgget */
+ "freebsd32_msgsnd", /* 226 = freebsd32_msgsnd */
+ "freebsd32_msgrcv", /* 227 = freebsd32_msgrcv */
+ "shmat", /* 228 = shmat */
+ "compat7.freebsd32_shmctl", /* 229 = freebsd7 freebsd32_shmctl */
+ "shmdt", /* 230 = shmdt */
+ "shmget", /* 231 = shmget */
+ "freebsd32_clock_gettime", /* 232 = freebsd32_clock_gettime */
+ "freebsd32_clock_settime", /* 233 = freebsd32_clock_settime */
+ "freebsd32_clock_getres", /* 234 = freebsd32_clock_getres */
+ "freebsd32_ktimer_create", /* 235 = freebsd32_ktimer_create */
+ "ktimer_delete", /* 236 = ktimer_delete */
+ "freebsd32_ktimer_settime", /* 237 = freebsd32_ktimer_settime */
+ "freebsd32_ktimer_gettime", /* 238 = freebsd32_ktimer_gettime */
+ "ktimer_getoverrun", /* 239 = ktimer_getoverrun */
+ "freebsd32_nanosleep", /* 240 = freebsd32_nanosleep */
+ "ffclock_getcounter", /* 241 = ffclock_getcounter */
+ "ffclock_setestimate", /* 242 = ffclock_setestimate */
+ "ffclock_getestimate", /* 243 = ffclock_getestimate */
+ "freebsd32_clock_nanosleep", /* 244 = freebsd32_clock_nanosleep */
+ "#245", /* 245 = nosys */
+ "#246", /* 246 = nosys */
+ "freebsd32_clock_getcpuclockid2", /* 247 = freebsd32_clock_getcpuclockid2 */
+ "#248", /* 248 = ntp_gettime */
+ "#249", /* 249 = nosys */
+ "minherit", /* 250 = minherit */
+ "rfork", /* 251 = rfork */
+ "obs_openbsd_poll", /* 252 = obsolete openbsd_poll */
+ "issetugid", /* 253 = issetugid */
+ "lchown", /* 254 = lchown */
+ "freebsd32_aio_read", /* 255 = freebsd32_aio_read */
+ "freebsd32_aio_write", /* 256 = freebsd32_aio_write */
+ "freebsd32_lio_listio", /* 257 = freebsd32_lio_listio */
+ "#258", /* 258 = nosys */
+ "#259", /* 259 = nosys */
+ "#260", /* 260 = nosys */
+ "#261", /* 261 = nosys */
+ "#262", /* 262 = nosys */
+ "#263", /* 263 = nosys */
+ "#264", /* 264 = nosys */
+ "#265", /* 265 = nosys */
+ "#266", /* 266 = nosys */
+ "#267", /* 267 = nosys */
+ "#268", /* 268 = nosys */
+ "#269", /* 269 = nosys */
+ "#270", /* 270 = nosys */
+ "#271", /* 271 = nosys */
+ "compat11.freebsd32_getdents", /* 272 = freebsd11 freebsd32_getdents */
+ "#273", /* 273 = nosys */
+ "lchmod", /* 274 = lchmod */
+ "obs_netbsd_lchown", /* 275 = obsolete netbsd_lchown */
+ "freebsd32_lutimes", /* 276 = freebsd32_lutimes */
+ "obs_netbsd_msync", /* 277 = obsolete netbsd_msync */
+ "compat11.nstat", /* 278 = freebsd11 nstat */
+ "compat11.nfstat", /* 279 = freebsd11 nfstat */
+ "compat11.nlstat", /* 280 = freebsd11 nlstat */
+ "#281", /* 281 = nosys */
+ "#282", /* 282 = nosys */
+ "#283", /* 283 = nosys */
+ "#284", /* 284 = nosys */
+ "#285", /* 285 = nosys */
+ "#286", /* 286 = nosys */
+ "#287", /* 287 = nosys */
+ "#288", /* 288 = nosys */
+ "freebsd32_preadv", /* 289 = freebsd32_preadv */
+ "freebsd32_pwritev", /* 290 = freebsd32_pwritev */
+ "#291", /* 291 = nosys */
+ "#292", /* 292 = nosys */
+ "#293", /* 293 = nosys */
+ "#294", /* 294 = nosys */
+ "#295", /* 295 = nosys */
+ "#296", /* 296 = nosys */
+ "compat4.freebsd32_fhstatfs", /* 297 = freebsd4 freebsd32_fhstatfs */
+ "fhopen", /* 298 = fhopen */
+ "compat11.freebsd32_fhstat", /* 299 = freebsd11 freebsd32_fhstat */
+ "modnext", /* 300 = modnext */
+ "freebsd32_modstat", /* 301 = freebsd32_modstat */
+ "modfnext", /* 302 = modfnext */
+ "modfind", /* 303 = modfind */
+ "kldload", /* 304 = kldload */
+ "kldunload", /* 305 = kldunload */
+ "kldfind", /* 306 = kldfind */
+ "kldnext", /* 307 = kldnext */
+ "freebsd32_kldstat", /* 308 = freebsd32_kldstat */
+ "kldfirstmod", /* 309 = kldfirstmod */
+ "getsid", /* 310 = getsid */
+ "setresuid", /* 311 = setresuid */
+ "setresgid", /* 312 = setresgid */
+ "obs_signanosleep", /* 313 = obsolete signanosleep */
+ "freebsd32_aio_return", /* 314 = freebsd32_aio_return */
+ "freebsd32_aio_suspend", /* 315 = freebsd32_aio_suspend */
+ "aio_cancel", /* 316 = aio_cancel */
+ "freebsd32_aio_error", /* 317 = freebsd32_aio_error */
+ "compat6.freebsd32_aio_read", /* 318 = freebsd6 freebsd32_aio_read */
+ "compat6.freebsd32_aio_write", /* 319 = freebsd6 freebsd32_aio_write */
+ "compat6.freebsd32_lio_listio", /* 320 = freebsd6 freebsd32_lio_listio */
+ "yield", /* 321 = yield */
+ "obs_thr_sleep", /* 322 = obsolete thr_sleep */
+ "obs_thr_wakeup", /* 323 = obsolete thr_wakeup */
+ "mlockall", /* 324 = mlockall */
+ "munlockall", /* 325 = munlockall */
+ "__getcwd", /* 326 = __getcwd */
+ "sched_setparam", /* 327 = sched_setparam */
+ "sched_getparam", /* 328 = sched_getparam */
+ "sched_setscheduler", /* 329 = sched_setscheduler */
+ "sched_getscheduler", /* 330 = sched_getscheduler */
+ "sched_yield", /* 331 = sched_yield */
+ "sched_get_priority_max", /* 332 = sched_get_priority_max */
+ "sched_get_priority_min", /* 333 = sched_get_priority_min */
+ "freebsd32_sched_rr_get_interval", /* 334 = freebsd32_sched_rr_get_interval */
+ "utrace", /* 335 = utrace */
+ "compat4.freebsd32_sendfile", /* 336 = freebsd4 freebsd32_sendfile */
+ "kldsym", /* 337 = kldsym */
+ "freebsd32_jail", /* 338 = freebsd32_jail */
+ "#339", /* 339 = pioctl */
+ "sigprocmask", /* 340 = sigprocmask */
+ "sigsuspend", /* 341 = sigsuspend */
+ "compat4.freebsd32_sigaction", /* 342 = freebsd4 freebsd32_sigaction */
+ "sigpending", /* 343 = sigpending */
+ "compat4.freebsd32_sigreturn", /* 344 = freebsd4 freebsd32_sigreturn */
+ "freebsd32_sigtimedwait", /* 345 = freebsd32_sigtimedwait */
+ "freebsd32_sigwaitinfo", /* 346 = freebsd32_sigwaitinfo */
+ "__acl_get_file", /* 347 = __acl_get_file */
+ "__acl_set_file", /* 348 = __acl_set_file */
+ "__acl_get_fd", /* 349 = __acl_get_fd */
+ "__acl_set_fd", /* 350 = __acl_set_fd */
+ "__acl_delete_file", /* 351 = __acl_delete_file */
+ "__acl_delete_fd", /* 352 = __acl_delete_fd */
+ "__acl_aclcheck_file", /* 353 = __acl_aclcheck_file */
+ "__acl_aclcheck_fd", /* 354 = __acl_aclcheck_fd */
+ "extattrctl", /* 355 = extattrctl */
+ "extattr_set_file", /* 356 = extattr_set_file */
+ "extattr_get_file", /* 357 = extattr_get_file */
+ "extattr_delete_file", /* 358 = extattr_delete_file */
+ "freebsd32_aio_waitcomplete", /* 359 = freebsd32_aio_waitcomplete */
+ "getresuid", /* 360 = getresuid */
+ "getresgid", /* 361 = getresgid */
+ "kqueue", /* 362 = kqueue */
+ "compat11.freebsd32_kevent", /* 363 = freebsd11 freebsd32_kevent */
+ "obs___cap_get_proc", /* 364 = obsolete __cap_get_proc */
+ "obs___cap_set_proc", /* 365 = obsolete __cap_set_proc */
+ "obs___cap_get_fd", /* 366 = obsolete __cap_get_fd */
+ "obs___cap_get_file", /* 367 = obsolete __cap_get_file */
+ "obs___cap_set_fd", /* 368 = obsolete __cap_set_fd */
+ "obs___cap_set_file", /* 369 = obsolete __cap_set_file */
+ "#370", /* 370 = nosys */
+ "extattr_set_fd", /* 371 = extattr_set_fd */
+ "extattr_get_fd", /* 372 = extattr_get_fd */
+ "extattr_delete_fd", /* 373 = extattr_delete_fd */
+ "__setugid", /* 374 = __setugid */
+ "obs_nfsclnt", /* 375 = obsolete nfsclnt */
+ "eaccess", /* 376 = eaccess */
+ "#377", /* 377 = afs_syscall */
+ "freebsd32_nmount", /* 378 = freebsd32_nmount */
+ "obs_kse_exit", /* 379 = obsolete kse_exit */
+ "obs_kse_wakeup", /* 380 = obsolete kse_wakeup */
+ "obs_kse_create", /* 381 = obsolete kse_create */
+ "obs_kse_thr_interrupt", /* 382 = obsolete kse_thr_interrupt */
+ "obs_kse_release", /* 383 = obsolete kse_release */
+ "#384", /* 384 = __mac_get_proc */
+ "#385", /* 385 = __mac_set_proc */
+ "#386", /* 386 = __mac_get_fd */
+ "#387", /* 387 = __mac_get_file */
+ "#388", /* 388 = __mac_set_fd */
+ "#389", /* 389 = __mac_set_file */
+ "kenv", /* 390 = kenv */
+ "lchflags", /* 391 = lchflags */
+ "uuidgen", /* 392 = uuidgen */
+ "freebsd32_sendfile", /* 393 = freebsd32_sendfile */
+ "#394", /* 394 = mac_syscall */
+ "compat11.getfsstat", /* 395 = freebsd11 getfsstat */
+ "compat11.statfs", /* 396 = freebsd11 statfs */
+ "compat11.fstatfs", /* 397 = freebsd11 fstatfs */
+ "compat11.fhstatfs", /* 398 = freebsd11 fhstatfs */
+ "#399", /* 399 = nosys */
+ "ksem_close", /* 400 = ksem_close */
+ "ksem_post", /* 401 = ksem_post */
+ "ksem_wait", /* 402 = ksem_wait */
+ "ksem_trywait", /* 403 = ksem_trywait */
+ "freebsd32_ksem_init", /* 404 = freebsd32_ksem_init */
+ "freebsd32_ksem_open", /* 405 = freebsd32_ksem_open */
+ "ksem_unlink", /* 406 = ksem_unlink */
+ "ksem_getvalue", /* 407 = ksem_getvalue */
+ "ksem_destroy", /* 408 = ksem_destroy */
+ "#409", /* 409 = __mac_get_pid */
+ "#410", /* 410 = __mac_get_link */
+ "#411", /* 411 = __mac_set_link */
+ "extattr_set_link", /* 412 = extattr_set_link */
+ "extattr_get_link", /* 413 = extattr_get_link */
+ "extattr_delete_link", /* 414 = extattr_delete_link */
+ "#415", /* 415 = __mac_execve */
+ "freebsd32_sigaction", /* 416 = freebsd32_sigaction */
+ "freebsd32_sigreturn", /* 417 = freebsd32_sigreturn */
+ "#418", /* 418 = __xstat */
+ "#419", /* 419 = __xfstat */
+ "#420", /* 420 = __xlstat */
+ "freebsd32_getcontext", /* 421 = freebsd32_getcontext */
+ "freebsd32_setcontext", /* 422 = freebsd32_setcontext */
+ "freebsd32_swapcontext", /* 423 = freebsd32_swapcontext */
+ "#424", /* 424 = swapoff */
+ "__acl_get_link", /* 425 = __acl_get_link */
+ "__acl_set_link", /* 426 = __acl_set_link */
+ "__acl_delete_link", /* 427 = __acl_delete_link */
+ "__acl_aclcheck_link", /* 428 = __acl_aclcheck_link */
+ "sigwait", /* 429 = sigwait */
+ "#430", /* 430 = thr_create; */
+ "thr_exit", /* 431 = thr_exit */
+ "thr_self", /* 432 = thr_self */
+ "thr_kill", /* 433 = thr_kill */
+ "#434", /* 434 = nosys */
+ "#435", /* 435 = nosys */
+ "jail_attach", /* 436 = jail_attach */
+ "extattr_list_fd", /* 437 = extattr_list_fd */
+ "extattr_list_file", /* 438 = extattr_list_file */
+ "extattr_list_link", /* 439 = extattr_list_link */
+ "obs_kse_switchin", /* 440 = obsolete kse_switchin */
+ "freebsd32_ksem_timedwait", /* 441 = freebsd32_ksem_timedwait */
+ "freebsd32_thr_suspend", /* 442 = freebsd32_thr_suspend */
+ "thr_wake", /* 443 = thr_wake */
+ "kldunloadf", /* 444 = kldunloadf */
+ "audit", /* 445 = audit */
+ "auditon", /* 446 = auditon */
+ "getauid", /* 447 = getauid */
+ "setauid", /* 448 = setauid */
+ "getaudit", /* 449 = getaudit */
+ "setaudit", /* 450 = setaudit */
+ "getaudit_addr", /* 451 = getaudit_addr */
+ "setaudit_addr", /* 452 = setaudit_addr */
+ "auditctl", /* 453 = auditctl */
+ "freebsd32__umtx_op", /* 454 = freebsd32__umtx_op */
+ "freebsd32_thr_new", /* 455 = freebsd32_thr_new */
+ "freebsd32_sigqueue", /* 456 = freebsd32_sigqueue */
+ "freebsd32_kmq_open", /* 457 = freebsd32_kmq_open */
+ "freebsd32_kmq_setattr", /* 458 = freebsd32_kmq_setattr */
+ "freebsd32_kmq_timedreceive", /* 459 = freebsd32_kmq_timedreceive */
+ "freebsd32_kmq_timedsend", /* 460 = freebsd32_kmq_timedsend */
+ "freebsd32_kmq_notify", /* 461 = freebsd32_kmq_notify */
+ "kmq_unlink", /* 462 = kmq_unlink */
+ "abort2", /* 463 = abort2 */
+ "thr_set_name", /* 464 = thr_set_name */
+ "freebsd32_aio_fsync", /* 465 = freebsd32_aio_fsync */
+ "rtprio_thread", /* 466 = rtprio_thread */
+ "#467", /* 467 = nosys */
+ "#468", /* 468 = nosys */
+ "#469", /* 469 = __getpath_fromfd */
+ "#470", /* 470 = __getpath_fromaddr */
+ "sctp_peeloff", /* 471 = sctp_peeloff */
+ "sctp_generic_sendmsg", /* 472 = sctp_generic_sendmsg */
+ "sctp_generic_sendmsg_iov", /* 473 = sctp_generic_sendmsg_iov */
+ "sctp_generic_recvmsg", /* 474 = sctp_generic_recvmsg */
+#ifdef PAD64_REQUIRED
+ "freebsd32_pread", /* 475 = freebsd32_pread */
+ "freebsd32_pwrite", /* 476 = freebsd32_pwrite */
+ "freebsd32_mmap", /* 477 = freebsd32_mmap */
+ "freebsd32_lseek", /* 478 = freebsd32_lseek */
+ "freebsd32_truncate", /* 479 = freebsd32_truncate */
+ "freebsd32_ftruncate", /* 480 = freebsd32_ftruncate */
+#else
+ "freebsd32_pread", /* 475 = freebsd32_pread */
+ "freebsd32_pwrite", /* 476 = freebsd32_pwrite */
+ "freebsd32_mmap", /* 477 = freebsd32_mmap */
+ "freebsd32_lseek", /* 478 = freebsd32_lseek */
+ "freebsd32_truncate", /* 479 = freebsd32_truncate */
+ "freebsd32_ftruncate", /* 480 = freebsd32_ftruncate */
+#endif
+ "thr_kill2", /* 481 = thr_kill2 */
+ "compat12.shm_open", /* 482 = freebsd12 shm_open */
+ "shm_unlink", /* 483 = shm_unlink */
+ "cpuset", /* 484 = cpuset */
+#ifdef PAD64_REQUIRED
+ "freebsd32_cpuset_setid", /* 485 = freebsd32_cpuset_setid */
+#else
+ "freebsd32_cpuset_setid", /* 485 = freebsd32_cpuset_setid */
+#endif
+ "freebsd32_cpuset_getid", /* 486 = freebsd32_cpuset_getid */
+ "freebsd32_cpuset_getaffinity", /* 487 = freebsd32_cpuset_getaffinity */
+ "freebsd32_cpuset_setaffinity", /* 488 = freebsd32_cpuset_setaffinity */
+ "faccessat", /* 489 = faccessat */
+ "fchmodat", /* 490 = fchmodat */
+ "fchownat", /* 491 = fchownat */
+ "freebsd32_fexecve", /* 492 = freebsd32_fexecve */
+ "compat11.freebsd32_fstatat", /* 493 = freebsd11 freebsd32_fstatat */
+ "freebsd32_futimesat", /* 494 = freebsd32_futimesat */
+ "linkat", /* 495 = linkat */
+ "mkdirat", /* 496 = mkdirat */
+ "mkfifoat", /* 497 = mkfifoat */
+ "compat11.mknodat", /* 498 = freebsd11 mknodat */
+ "openat", /* 499 = openat */
+ "readlinkat", /* 500 = readlinkat */
+ "renameat", /* 501 = renameat */
+ "symlinkat", /* 502 = symlinkat */
+ "unlinkat", /* 503 = unlinkat */
+ "posix_openpt", /* 504 = posix_openpt */
+ "#505", /* 505 = gssd_syscall */
+ "freebsd32_jail_get", /* 506 = freebsd32_jail_get */
+ "freebsd32_jail_set", /* 507 = freebsd32_jail_set */
+ "jail_remove", /* 508 = jail_remove */
+ "compat12.closefrom", /* 509 = freebsd12 closefrom */
+ "freebsd32_semctl", /* 510 = freebsd32_semctl */
+ "freebsd32_msgctl", /* 511 = freebsd32_msgctl */
+ "freebsd32_shmctl", /* 512 = freebsd32_shmctl */
+ "lpathconf", /* 513 = lpathconf */
+ "obs_cap_new", /* 514 = obsolete cap_new */
+ "__cap_rights_get", /* 515 = __cap_rights_get */
+ "cap_enter", /* 516 = cap_enter */
+ "cap_getmode", /* 517 = cap_getmode */
+ "pdfork", /* 518 = pdfork */
+ "pdkill", /* 519 = pdkill */
+ "pdgetpid", /* 520 = pdgetpid */
+ "#521", /* 521 = pdwait4 */
+ "freebsd32_pselect", /* 522 = freebsd32_pselect */
+ "getloginclass", /* 523 = getloginclass */
+ "setloginclass", /* 524 = setloginclass */
+ "rctl_get_racct", /* 525 = rctl_get_racct */
+ "rctl_get_rules", /* 526 = rctl_get_rules */
+ "rctl_get_limits", /* 527 = rctl_get_limits */
+ "rctl_add_rule", /* 528 = rctl_add_rule */
+ "rctl_remove_rule", /* 529 = rctl_remove_rule */
+#ifdef PAD64_REQUIRED
+ "freebsd32_posix_fallocate", /* 530 = freebsd32_posix_fallocate */
+ "freebsd32_posix_fadvise", /* 531 = freebsd32_posix_fadvise */
+ "freebsd32_wait6", /* 532 = freebsd32_wait6 */
+#else
+ "freebsd32_posix_fallocate", /* 530 = freebsd32_posix_fallocate */
+ "freebsd32_posix_fadvise", /* 531 = freebsd32_posix_fadvise */
+ "freebsd32_wait6", /* 532 = freebsd32_wait6 */
+#endif
+ "cap_rights_limit", /* 533 = cap_rights_limit */
+ "freebsd32_cap_ioctls_limit", /* 534 = freebsd32_cap_ioctls_limit */
+ "freebsd32_cap_ioctls_get", /* 535 = freebsd32_cap_ioctls_get */
+ "cap_fcntls_limit", /* 536 = cap_fcntls_limit */
+ "cap_fcntls_get", /* 537 = cap_fcntls_get */
+ "bindat", /* 538 = bindat */
+ "connectat", /* 539 = connectat */
+ "chflagsat", /* 540 = chflagsat */
+ "accept4", /* 541 = accept4 */
+ "pipe2", /* 542 = pipe2 */
+ "freebsd32_aio_mlock", /* 543 = freebsd32_aio_mlock */
+#ifdef PAD64_REQUIRED
+ "freebsd32_procctl", /* 544 = freebsd32_procctl */
+#else
+ "freebsd32_procctl", /* 544 = freebsd32_procctl */
+#endif
+ "freebsd32_ppoll", /* 545 = freebsd32_ppoll */
+ "freebsd32_futimens", /* 546 = freebsd32_futimens */
+ "freebsd32_utimensat", /* 547 = freebsd32_utimensat */
+ "obs_numa_getaffinity", /* 548 = obsolete numa_getaffinity */
+ "obs_numa_setaffinity", /* 549 = obsolete numa_setaffinity */
+ "fdatasync", /* 550 = fdatasync */
+ "freebsd32_fstat", /* 551 = freebsd32_fstat */
+ "freebsd32_fstatat", /* 552 = freebsd32_fstatat */
+ "freebsd32_fhstat", /* 553 = freebsd32_fhstat */
+ "getdirentries", /* 554 = getdirentries */
+ "statfs", /* 555 = statfs */
+ "fstatfs", /* 556 = fstatfs */
+ "getfsstat", /* 557 = getfsstat */
+ "fhstatfs", /* 558 = fhstatfs */
+#ifdef PAD64_REQUIRED
+ "freebsd32_mknodat", /* 559 = freebsd32_mknodat */
+#else
+ "freebsd32_mknodat", /* 559 = freebsd32_mknodat */
+#endif
+ "freebsd32_kevent", /* 560 = freebsd32_kevent */
+ "freebsd32_cpuset_getdomain", /* 561 = freebsd32_cpuset_getdomain */
+ "freebsd32_cpuset_setdomain", /* 562 = freebsd32_cpuset_setdomain */
+ "getrandom", /* 563 = getrandom */
+ "getfhat", /* 564 = getfhat */
+ "fhlink", /* 565 = fhlink */
+ "fhlinkat", /* 566 = fhlinkat */
+ "fhreadlink", /* 567 = fhreadlink */
+ "funlinkat", /* 568 = funlinkat */
+ "copy_file_range", /* 569 = copy_file_range */
+ "freebsd32___sysctlbyname", /* 570 = freebsd32___sysctlbyname */
+ "shm_open2", /* 571 = shm_open2 */
+ "shm_rename", /* 572 = shm_rename */
+ "sigfastblock", /* 573 = sigfastblock */
+ "__realpathat", /* 574 = __realpathat */
+ "close_range", /* 575 = close_range */
+ "rpctls_syscall", /* 576 = rpctls_syscall */
+ "__specialfd", /* 577 = __specialfd */
+ "freebsd32_aio_writev", /* 578 = freebsd32_aio_writev */
+ "freebsd32_aio_readv", /* 579 = freebsd32_aio_readv */
+};
diff --git a/sys/compat/freebsd32/freebsd32_sysent.c b/sys/compat/freebsd32/freebsd32_sysent.c
new file mode 100644
index 000000000000..bec3a87c820a
--- /dev/null
+++ b/sys/compat/freebsd32/freebsd32_sysent.c
@@ -0,0 +1,672 @@
+/*
+ * System call switch table.
+ *
+ * DO NOT EDIT-- this file is automatically @generated.
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <compat/freebsd32/freebsd32.h>
+#include <compat/freebsd32/freebsd32_proto.h>
+
+#define AS(name) (sizeof(struct name) / sizeof(register_t))
+
+#ifdef COMPAT_43
+#define compat(n, name) .sy_narg = n, .sy_call = (sy_call_t *)__CONCAT(o,name)
+#else
+#define compat(n, name) .sy_narg = 0, .sy_call = (sy_call_t *)nosys
+#endif
+
+#ifdef COMPAT_FREEBSD4
+#define compat4(n, name) .sy_narg = n, .sy_call = (sy_call_t *)__CONCAT(freebsd4_,name)
+#else
+#define compat4(n, name) .sy_narg = 0, .sy_call = (sy_call_t *)nosys
+#endif
+
+#ifdef COMPAT_FREEBSD6
+#define compat6(n, name) .sy_narg = n, .sy_call = (sy_call_t *)__CONCAT(freebsd6_,name)
+#else
+#define compat6(n, name) .sy_narg = 0, .sy_call = (sy_call_t *)nosys
+#endif
+
+#ifdef COMPAT_FREEBSD7
+#define compat7(n, name) .sy_narg = n, .sy_call = (sy_call_t *)__CONCAT(freebsd7_,name)
+#else
+#define compat7(n, name) .sy_narg = 0, .sy_call = (sy_call_t *)nosys
+#endif
+
+#ifdef COMPAT_FREEBSD10
+#define compat10(n, name) .sy_narg = n, .sy_call = (sy_call_t *)__CONCAT(freebsd10_,name)
+#else
+#define compat10(n, name) .sy_narg = 0, .sy_call = (sy_call_t *)nosys
+#endif
+
+#ifdef COMPAT_FREEBSD11
+#define compat11(n, name) .sy_narg = n, .sy_call = (sy_call_t *)__CONCAT(freebsd11_,name)
+#else
+#define compat11(n, name) .sy_narg = 0, .sy_call = (sy_call_t *)nosys
+#endif
+
+#ifdef COMPAT_FREEBSD12
+#define compat12(n, name) .sy_narg = n, .sy_call = (sy_call_t *)__CONCAT(freebsd12_,name)
+#else
+#define compat12(n, name) .sy_narg = 0, .sy_call = (sy_call_t *)nosys
+#endif
+
+/* The casts are bogus but will do for now. */
+struct sysent freebsd32_sysent[] = {
+#if !defined(PAD64_REQUIRED) && !defined(__amd64__)
+#define PAD64_REQUIRED
+#endif
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 0 = syscall */
+ { .sy_narg = AS(sys_exit_args), .sy_call = (sy_call_t *)sys_sys_exit, .sy_auevent = AUE_EXIT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 1 = exit */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)sys_fork, .sy_auevent = AUE_FORK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 2 = fork */
+ { .sy_narg = AS(read_args), .sy_call = (sy_call_t *)sys_read, .sy_auevent = AUE_READ, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 3 = read */
+ { .sy_narg = AS(write_args), .sy_call = (sy_call_t *)sys_write, .sy_auevent = AUE_WRITE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 4 = write */
+ { .sy_narg = AS(open_args), .sy_call = (sy_call_t *)sys_open, .sy_auevent = AUE_OPEN_RWTC, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 5 = open */
+ { .sy_narg = AS(close_args), .sy_call = (sy_call_t *)sys_close, .sy_auevent = AUE_CLOSE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 6 = close */
+ { .sy_narg = AS(freebsd32_wait4_args), .sy_call = (sy_call_t *)freebsd32_wait4, .sy_auevent = AUE_WAIT4, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 7 = freebsd32_wait4 */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 8 = obsolete old creat */
+ { .sy_narg = AS(link_args), .sy_call = (sy_call_t *)sys_link, .sy_auevent = AUE_LINK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 9 = link */
+ { .sy_narg = AS(unlink_args), .sy_call = (sy_call_t *)sys_unlink, .sy_auevent = AUE_UNLINK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 10 = unlink */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 11 = obsolete execv */
+ { .sy_narg = AS(chdir_args), .sy_call = (sy_call_t *)sys_chdir, .sy_auevent = AUE_CHDIR, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 12 = chdir */
+ { .sy_narg = AS(fchdir_args), .sy_call = (sy_call_t *)sys_fchdir, .sy_auevent = AUE_FCHDIR, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 13 = fchdir */
+ { compat11(AS(freebsd11_mknod_args),mknod), .sy_auevent = AUE_MKNOD, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 14 = freebsd11 mknod */
+ { .sy_narg = AS(chmod_args), .sy_call = (sy_call_t *)sys_chmod, .sy_auevent = AUE_CHMOD, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 15 = chmod */
+ { .sy_narg = AS(chown_args), .sy_call = (sy_call_t *)sys_chown, .sy_auevent = AUE_CHOWN, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 16 = chown */
+ { .sy_narg = AS(break_args), .sy_call = (sy_call_t *)sys_break, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 17 = break */
+ { compat4(AS(freebsd4_freebsd32_getfsstat_args),freebsd32_getfsstat), .sy_auevent = AUE_GETFSSTAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 18 = freebsd4 freebsd32_getfsstat */
+ { compat(AS(ofreebsd32_lseek_args),freebsd32_lseek), .sy_auevent = AUE_LSEEK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 19 = old freebsd32_lseek */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)sys_getpid, .sy_auevent = AUE_GETPID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 20 = getpid */
+ { .sy_narg = AS(mount_args), .sy_call = (sy_call_t *)sys_mount, .sy_auevent = AUE_MOUNT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 21 = mount */
+ { .sy_narg = AS(unmount_args), .sy_call = (sy_call_t *)sys_unmount, .sy_auevent = AUE_UMOUNT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 22 = unmount */
+ { .sy_narg = AS(setuid_args), .sy_call = (sy_call_t *)sys_setuid, .sy_auevent = AUE_SETUID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 23 = setuid */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)sys_getuid, .sy_auevent = AUE_GETUID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 24 = getuid */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)sys_geteuid, .sy_auevent = AUE_GETEUID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 25 = geteuid */
+ { .sy_narg = AS(freebsd32_ptrace_args), .sy_call = (sy_call_t *)freebsd32_ptrace, .sy_auevent = AUE_PTRACE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 26 = freebsd32_ptrace */
+ { .sy_narg = AS(freebsd32_recvmsg_args), .sy_call = (sy_call_t *)freebsd32_recvmsg, .sy_auevent = AUE_RECVMSG, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 27 = freebsd32_recvmsg */
+ { .sy_narg = AS(freebsd32_sendmsg_args), .sy_call = (sy_call_t *)freebsd32_sendmsg, .sy_auevent = AUE_SENDMSG, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 28 = freebsd32_sendmsg */
+ { .sy_narg = AS(freebsd32_recvfrom_args), .sy_call = (sy_call_t *)freebsd32_recvfrom, .sy_auevent = AUE_RECVFROM, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 29 = freebsd32_recvfrom */
+ { .sy_narg = AS(accept_args), .sy_call = (sy_call_t *)sys_accept, .sy_auevent = AUE_ACCEPT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 30 = accept */
+ { .sy_narg = AS(getpeername_args), .sy_call = (sy_call_t *)sys_getpeername, .sy_auevent = AUE_GETPEERNAME, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 31 = getpeername */
+ { .sy_narg = AS(getsockname_args), .sy_call = (sy_call_t *)sys_getsockname, .sy_auevent = AUE_GETSOCKNAME, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 32 = getsockname */
+ { .sy_narg = AS(access_args), .sy_call = (sy_call_t *)sys_access, .sy_auevent = AUE_ACCESS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 33 = access */
+ { .sy_narg = AS(chflags_args), .sy_call = (sy_call_t *)sys_chflags, .sy_auevent = AUE_CHFLAGS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 34 = chflags */
+ { .sy_narg = AS(fchflags_args), .sy_call = (sy_call_t *)sys_fchflags, .sy_auevent = AUE_FCHFLAGS, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 35 = fchflags */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)sys_sync, .sy_auevent = AUE_SYNC, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 36 = sync */
+ { .sy_narg = AS(kill_args), .sy_call = (sy_call_t *)sys_kill, .sy_auevent = AUE_KILL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 37 = kill */
+ { compat(AS(ofreebsd32_stat_args),freebsd32_stat), .sy_auevent = AUE_STAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 38 = old freebsd32_stat */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)sys_getppid, .sy_auevent = AUE_GETPPID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 39 = getppid */
+ { compat(AS(ofreebsd32_lstat_args),freebsd32_lstat), .sy_auevent = AUE_LSTAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 40 = old freebsd32_lstat */
+ { .sy_narg = AS(dup_args), .sy_call = (sy_call_t *)sys_dup, .sy_auevent = AUE_DUP, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 41 = dup */
+ { compat10(0,freebsd32_pipe), .sy_auevent = AUE_PIPE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 42 = freebsd10 freebsd32_pipe */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)sys_getegid, .sy_auevent = AUE_GETEGID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 43 = getegid */
+ { .sy_narg = AS(profil_args), .sy_call = (sy_call_t *)sys_profil, .sy_auevent = AUE_PROFILE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 44 = profil */
+ { .sy_narg = AS(ktrace_args), .sy_call = (sy_call_t *)sys_ktrace, .sy_auevent = AUE_KTRACE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 45 = ktrace */
+ { compat(AS(ofreebsd32_sigaction_args),freebsd32_sigaction), .sy_auevent = AUE_SIGACTION, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 46 = old freebsd32_sigaction */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)sys_getgid, .sy_auevent = AUE_GETGID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 47 = getgid */
+ { compat(AS(ofreebsd32_sigprocmask_args),freebsd32_sigprocmask), .sy_auevent = AUE_SIGPROCMASK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 48 = old freebsd32_sigprocmask */
+ { .sy_narg = AS(getlogin_args), .sy_call = (sy_call_t *)sys_getlogin, .sy_auevent = AUE_GETLOGIN, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 49 = getlogin */
+ { .sy_narg = AS(setlogin_args), .sy_call = (sy_call_t *)sys_setlogin, .sy_auevent = AUE_SETLOGIN, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 50 = setlogin */
+ { .sy_narg = AS(acct_args), .sy_call = (sy_call_t *)sys_acct, .sy_auevent = AUE_ACCT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 51 = acct */
+ { compat(0,freebsd32_sigpending), .sy_auevent = AUE_SIGPENDING, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 52 = old freebsd32_sigpending */
+ { .sy_narg = AS(freebsd32_sigaltstack_args), .sy_call = (sy_call_t *)freebsd32_sigaltstack, .sy_auevent = AUE_SIGALTSTACK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 53 = freebsd32_sigaltstack */
+ { .sy_narg = AS(freebsd32_ioctl_args), .sy_call = (sy_call_t *)freebsd32_ioctl, .sy_auevent = AUE_IOCTL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 54 = freebsd32_ioctl */
+ { .sy_narg = AS(reboot_args), .sy_call = (sy_call_t *)sys_reboot, .sy_auevent = AUE_REBOOT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 55 = reboot */
+ { .sy_narg = AS(revoke_args), .sy_call = (sy_call_t *)sys_revoke, .sy_auevent = AUE_REVOKE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 56 = revoke */
+ { .sy_narg = AS(symlink_args), .sy_call = (sy_call_t *)sys_symlink, .sy_auevent = AUE_SYMLINK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 57 = symlink */
+ { .sy_narg = AS(readlink_args), .sy_call = (sy_call_t *)sys_readlink, .sy_auevent = AUE_READLINK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 58 = readlink */
+ { .sy_narg = AS(freebsd32_execve_args), .sy_call = (sy_call_t *)freebsd32_execve, .sy_auevent = AUE_EXECVE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 59 = freebsd32_execve */
+ { .sy_narg = AS(umask_args), .sy_call = (sy_call_t *)sys_umask, .sy_auevent = AUE_UMASK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 60 = umask */
+ { .sy_narg = AS(chroot_args), .sy_call = (sy_call_t *)sys_chroot, .sy_auevent = AUE_CHROOT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 61 = chroot */
+ { compat(AS(ofreebsd32_fstat_args),freebsd32_fstat), .sy_auevent = AUE_FSTAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 62 = old freebsd32_fstat */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 63 = obsolete ogetkerninfo */
+ { compat(AS(ofreebsd32_getpagesize_args),freebsd32_getpagesize), .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 64 = old freebsd32_getpagesize */
+ { .sy_narg = AS(msync_args), .sy_call = (sy_call_t *)sys_msync, .sy_auevent = AUE_MSYNC, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 65 = msync */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)sys_vfork, .sy_auevent = AUE_VFORK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 66 = vfork */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 67 = obsolete vread */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 68 = obsolete vwrite */
+ { .sy_narg = AS(sbrk_args), .sy_call = (sy_call_t *)sys_sbrk, .sy_auevent = AUE_SBRK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 69 = sbrk */
+ { .sy_narg = AS(sstk_args), .sy_call = (sy_call_t *)sys_sstk, .sy_auevent = AUE_SSTK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 70 = sstk */
+ { compat(AS(ommap_args),mmap), .sy_auevent = AUE_MMAP, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 71 = old mmap */
+ { compat11(AS(freebsd11_vadvise_args),vadvise), .sy_auevent = AUE_O_VADVISE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 72 = freebsd11 vadvise */
+ { .sy_narg = AS(munmap_args), .sy_call = (sy_call_t *)sys_munmap, .sy_auevent = AUE_MUNMAP, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 73 = munmap */
+ { .sy_narg = AS(freebsd32_mprotect_args), .sy_call = (sy_call_t *)freebsd32_mprotect, .sy_auevent = AUE_MPROTECT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 74 = freebsd32_mprotect */
+ { .sy_narg = AS(madvise_args), .sy_call = (sy_call_t *)sys_madvise, .sy_auevent = AUE_MADVISE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 75 = madvise */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 76 = obsolete vhangup */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 77 = obsolete vlimit */
+ { .sy_narg = AS(mincore_args), .sy_call = (sy_call_t *)sys_mincore, .sy_auevent = AUE_MINCORE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 78 = mincore */
+ { .sy_narg = AS(getgroups_args), .sy_call = (sy_call_t *)sys_getgroups, .sy_auevent = AUE_GETGROUPS, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 79 = getgroups */
+ { .sy_narg = AS(setgroups_args), .sy_call = (sy_call_t *)sys_setgroups, .sy_auevent = AUE_SETGROUPS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 80 = setgroups */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)sys_getpgrp, .sy_auevent = AUE_GETPGRP, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 81 = getpgrp */
+ { .sy_narg = AS(setpgid_args), .sy_call = (sy_call_t *)sys_setpgid, .sy_auevent = AUE_SETPGRP, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 82 = setpgid */
+ { .sy_narg = AS(freebsd32_setitimer_args), .sy_call = (sy_call_t *)freebsd32_setitimer, .sy_auevent = AUE_SETITIMER, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 83 = freebsd32_setitimer */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 84 = obsolete owait */
+ { .sy_narg = AS(swapon_args), .sy_call = (sy_call_t *)sys_swapon, .sy_auevent = AUE_SWAPON, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 85 = swapon */
+ { .sy_narg = AS(freebsd32_getitimer_args), .sy_call = (sy_call_t *)freebsd32_getitimer, .sy_auevent = AUE_GETITIMER, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 86 = freebsd32_getitimer */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 87 = obsolete ogethostname */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 88 = obsolete osethostname */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)sys_getdtablesize, .sy_auevent = AUE_GETDTABLESIZE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 89 = getdtablesize */
+ { .sy_narg = AS(dup2_args), .sy_call = (sy_call_t *)sys_dup2, .sy_auevent = AUE_DUP2, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 90 = dup2 */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 91 = getdopt */
+ { .sy_narg = AS(freebsd32_fcntl_args), .sy_call = (sy_call_t *)freebsd32_fcntl, .sy_auevent = AUE_FCNTL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 92 = freebsd32_fcntl */
+ { .sy_narg = AS(freebsd32_select_args), .sy_call = (sy_call_t *)freebsd32_select, .sy_auevent = AUE_SELECT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 93 = freebsd32_select */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 94 = setdopt */
+ { .sy_narg = AS(fsync_args), .sy_call = (sy_call_t *)sys_fsync, .sy_auevent = AUE_FSYNC, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 95 = fsync */
+ { .sy_narg = AS(setpriority_args), .sy_call = (sy_call_t *)sys_setpriority, .sy_auevent = AUE_SETPRIORITY, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 96 = setpriority */
+ { .sy_narg = AS(socket_args), .sy_call = (sy_call_t *)sys_socket, .sy_auevent = AUE_SOCKET, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 97 = socket */
+ { .sy_narg = AS(connect_args), .sy_call = (sy_call_t *)sys_connect, .sy_auevent = AUE_CONNECT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 98 = connect */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 99 = obsolete oaccept */
+ { .sy_narg = AS(getpriority_args), .sy_call = (sy_call_t *)sys_getpriority, .sy_auevent = AUE_GETPRIORITY, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 100 = getpriority */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 101 = obsolete osend */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 102 = obsolete orecv */
+ { compat(AS(ofreebsd32_sigreturn_args),freebsd32_sigreturn), .sy_auevent = AUE_SIGRETURN, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 103 = old freebsd32_sigreturn */
+ { .sy_narg = AS(bind_args), .sy_call = (sy_call_t *)sys_bind, .sy_auevent = AUE_BIND, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 104 = bind */
+ { .sy_narg = AS(setsockopt_args), .sy_call = (sy_call_t *)sys_setsockopt, .sy_auevent = AUE_SETSOCKOPT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 105 = setsockopt */
+ { .sy_narg = AS(listen_args), .sy_call = (sy_call_t *)sys_listen, .sy_auevent = AUE_LISTEN, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 106 = listen */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 107 = obsolete vtimes */
+ { compat(AS(ofreebsd32_sigvec_args),freebsd32_sigvec), .sy_auevent = AUE_O_SIGVEC, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 108 = old freebsd32_sigvec */
+ { compat(AS(ofreebsd32_sigblock_args),freebsd32_sigblock), .sy_auevent = AUE_O_SIGBLOCK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 109 = old freebsd32_sigblock */
+ { compat(AS(ofreebsd32_sigsetmask_args),freebsd32_sigsetmask), .sy_auevent = AUE_O_SIGSETMASK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 110 = old freebsd32_sigsetmask */
+ { compat(AS(ofreebsd32_sigsuspend_args),freebsd32_sigsuspend), .sy_auevent = AUE_SIGSUSPEND, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 111 = old freebsd32_sigsuspend */
+ { compat(AS(ofreebsd32_sigstack_args),freebsd32_sigstack), .sy_auevent = AUE_O_SIGSTACK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 112 = old freebsd32_sigstack */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 113 = obsolete orecvmsg */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 114 = obsolete osendmsg */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 115 = obsolete vtrace */
+ { .sy_narg = AS(freebsd32_gettimeofday_args), .sy_call = (sy_call_t *)freebsd32_gettimeofday, .sy_auevent = AUE_GETTIMEOFDAY, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 116 = freebsd32_gettimeofday */
+ { .sy_narg = AS(freebsd32_getrusage_args), .sy_call = (sy_call_t *)freebsd32_getrusage, .sy_auevent = AUE_GETRUSAGE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 117 = freebsd32_getrusage */
+ { .sy_narg = AS(getsockopt_args), .sy_call = (sy_call_t *)sys_getsockopt, .sy_auevent = AUE_GETSOCKOPT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 118 = getsockopt */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 119 = resuba */
+ { .sy_narg = AS(freebsd32_readv_args), .sy_call = (sy_call_t *)freebsd32_readv, .sy_auevent = AUE_READV, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 120 = freebsd32_readv */
+ { .sy_narg = AS(freebsd32_writev_args), .sy_call = (sy_call_t *)freebsd32_writev, .sy_auevent = AUE_WRITEV, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 121 = freebsd32_writev */
+ { .sy_narg = AS(freebsd32_settimeofday_args), .sy_call = (sy_call_t *)freebsd32_settimeofday, .sy_auevent = AUE_SETTIMEOFDAY, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 122 = freebsd32_settimeofday */
+ { .sy_narg = AS(fchown_args), .sy_call = (sy_call_t *)sys_fchown, .sy_auevent = AUE_FCHOWN, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 123 = fchown */
+ { .sy_narg = AS(fchmod_args), .sy_call = (sy_call_t *)sys_fchmod, .sy_auevent = AUE_FCHMOD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 124 = fchmod */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 125 = obsolete orecvfrom */
+ { .sy_narg = AS(setreuid_args), .sy_call = (sy_call_t *)sys_setreuid, .sy_auevent = AUE_SETREUID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 126 = setreuid */
+ { .sy_narg = AS(setregid_args), .sy_call = (sy_call_t *)sys_setregid, .sy_auevent = AUE_SETREGID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 127 = setregid */
+ { .sy_narg = AS(rename_args), .sy_call = (sy_call_t *)sys_rename, .sy_auevent = AUE_RENAME, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 128 = rename */
+ { compat(AS(otruncate_args),truncate), .sy_auevent = AUE_TRUNCATE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 129 = old truncate */
+ { compat(AS(oftruncate_args),ftruncate), .sy_auevent = AUE_FTRUNCATE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 130 = old ftruncate */
+ { .sy_narg = AS(flock_args), .sy_call = (sy_call_t *)sys_flock, .sy_auevent = AUE_FLOCK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 131 = flock */
+ { .sy_narg = AS(mkfifo_args), .sy_call = (sy_call_t *)sys_mkfifo, .sy_auevent = AUE_MKFIFO, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 132 = mkfifo */
+ { .sy_narg = AS(sendto_args), .sy_call = (sy_call_t *)sys_sendto, .sy_auevent = AUE_SENDTO, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 133 = sendto */
+ { .sy_narg = AS(shutdown_args), .sy_call = (sy_call_t *)sys_shutdown, .sy_auevent = AUE_SHUTDOWN, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 134 = shutdown */
+ { .sy_narg = AS(socketpair_args), .sy_call = (sy_call_t *)sys_socketpair, .sy_auevent = AUE_SOCKETPAIR, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 135 = socketpair */
+ { .sy_narg = AS(mkdir_args), .sy_call = (sy_call_t *)sys_mkdir, .sy_auevent = AUE_MKDIR, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 136 = mkdir */
+ { .sy_narg = AS(rmdir_args), .sy_call = (sy_call_t *)sys_rmdir, .sy_auevent = AUE_RMDIR, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 137 = rmdir */
+ { .sy_narg = AS(freebsd32_utimes_args), .sy_call = (sy_call_t *)freebsd32_utimes, .sy_auevent = AUE_UTIMES, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 138 = freebsd32_utimes */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 139 = obsolete 4.2 sigreturn */
+ { .sy_narg = AS(freebsd32_adjtime_args), .sy_call = (sy_call_t *)freebsd32_adjtime, .sy_auevent = AUE_ADJTIME, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 140 = freebsd32_adjtime */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 141 = obsolete ogetpeername */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 142 = obsolete ogethostid */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 143 = obsolete sethostid */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 144 = obsolete getrlimit */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 145 = obsolete setrlimit */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 146 = obsolete killpg */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)sys_setsid, .sy_auevent = AUE_SETSID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 147 = setsid */
+ { .sy_narg = AS(quotactl_args), .sy_call = (sy_call_t *)sys_quotactl, .sy_auevent = AUE_QUOTACTL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 148 = quotactl */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 149 = obsolete oquota */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 150 = obsolete ogetsockname */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 151 = sem_lock */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 152 = sem_wakeup */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 153 = asyncdaemon */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 154 = nlm_syscall */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 155 = nfssvc */
+ { compat(AS(ofreebsd32_getdirentries_args),freebsd32_getdirentries), .sy_auevent = AUE_GETDIRENTRIES, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 156 = old freebsd32_getdirentries */
+ { compat4(AS(freebsd4_freebsd32_statfs_args),freebsd32_statfs), .sy_auevent = AUE_STATFS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 157 = freebsd4 freebsd32_statfs */
+ { compat4(AS(freebsd4_freebsd32_fstatfs_args),freebsd32_fstatfs), .sy_auevent = AUE_FSTATFS, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 158 = freebsd4 freebsd32_fstatfs */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 159 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 160 = lgetfh */
+ { .sy_narg = AS(getfh_args), .sy_call = (sy_call_t *)sys_getfh, .sy_auevent = AUE_NFS_GETFH, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 161 = getfh */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 162 = obsolete getdomainname */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 163 = obsolete setdomainname */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 164 = obsolete uname */
+ { .sy_narg = AS(freebsd32_sysarch_args), .sy_call = (sy_call_t *)freebsd32_sysarch, .sy_auevent = AUE_SYSARCH, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 165 = freebsd32_sysarch */
+ { .sy_narg = AS(rtprio_args), .sy_call = (sy_call_t *)sys_rtprio, .sy_auevent = AUE_RTPRIO, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 166 = rtprio */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 167 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 168 = nosys */
+ { .sy_narg = AS(freebsd32_semsys_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 169 = freebsd32_semsys */
+ { .sy_narg = AS(freebsd32_msgsys_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 170 = freebsd32_msgsys */
+ { .sy_narg = AS(freebsd32_shmsys_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 171 = freebsd32_shmsys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 172 = nosys */
+ { compat6(AS(freebsd6_freebsd32_pread_args),freebsd32_pread), .sy_auevent = AUE_PREAD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 173 = freebsd6 freebsd32_pread */
+ { compat6(AS(freebsd6_freebsd32_pwrite_args),freebsd32_pwrite), .sy_auevent = AUE_PWRITE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 174 = freebsd6 freebsd32_pwrite */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 175 = nosys */
+ { .sy_narg = AS(freebsd32_ntp_adjtime_args), .sy_call = (sy_call_t *)freebsd32_ntp_adjtime, .sy_auevent = AUE_NTP_ADJTIME, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 176 = freebsd32_ntp_adjtime */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 177 = sfork */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 178 = getdescriptor */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 179 = setdescriptor */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 180 = nosys */
+ { .sy_narg = AS(setgid_args), .sy_call = (sy_call_t *)sys_setgid, .sy_auevent = AUE_SETGID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 181 = setgid */
+ { .sy_narg = AS(setegid_args), .sy_call = (sy_call_t *)sys_setegid, .sy_auevent = AUE_SETEGID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 182 = setegid */
+ { .sy_narg = AS(seteuid_args), .sy_call = (sy_call_t *)sys_seteuid, .sy_auevent = AUE_SETEUID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 183 = seteuid */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 184 = obsolete lfs_bmapv */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 185 = obsolete lfs_markv */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 186 = obsolete lfs_segclean */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 187 = obsolete lfs_segwait */
+ { compat11(AS(freebsd11_freebsd32_stat_args),freebsd32_stat), .sy_auevent = AUE_STAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 188 = freebsd11 freebsd32_stat */
+ { compat11(AS(freebsd11_freebsd32_fstat_args),freebsd32_fstat), .sy_auevent = AUE_FSTAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 189 = freebsd11 freebsd32_fstat */
+ { compat11(AS(freebsd11_freebsd32_lstat_args),freebsd32_lstat), .sy_auevent = AUE_LSTAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 190 = freebsd11 freebsd32_lstat */
+ { .sy_narg = AS(pathconf_args), .sy_call = (sy_call_t *)sys_pathconf, .sy_auevent = AUE_PATHCONF, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 191 = pathconf */
+ { .sy_narg = AS(fpathconf_args), .sy_call = (sy_call_t *)sys_fpathconf, .sy_auevent = AUE_FPATHCONF, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 192 = fpathconf */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 193 = nosys */
+ { .sy_narg = AS(__getrlimit_args), .sy_call = (sy_call_t *)sys_getrlimit, .sy_auevent = AUE_GETRLIMIT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 194 = getrlimit */
+ { .sy_narg = AS(__setrlimit_args), .sy_call = (sy_call_t *)sys_setrlimit, .sy_auevent = AUE_SETRLIMIT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 195 = setrlimit */
+ { compat11(AS(freebsd11_freebsd32_getdirentries_args),freebsd32_getdirentries), .sy_auevent = AUE_GETDIRENTRIES, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 196 = freebsd11 freebsd32_getdirentries */
+ { compat6(AS(freebsd6_freebsd32_mmap_args),freebsd32_mmap), .sy_auevent = AUE_MMAP, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 197 = freebsd6 freebsd32_mmap */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 198 = __syscall */
+ { compat6(AS(freebsd6_freebsd32_lseek_args),freebsd32_lseek), .sy_auevent = AUE_LSEEK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 199 = freebsd6 freebsd32_lseek */
+ { compat6(AS(freebsd6_freebsd32_truncate_args),freebsd32_truncate), .sy_auevent = AUE_TRUNCATE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 200 = freebsd6 freebsd32_truncate */
+ { compat6(AS(freebsd6_freebsd32_ftruncate_args),freebsd32_ftruncate), .sy_auevent = AUE_FTRUNCATE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 201 = freebsd6 freebsd32_ftruncate */
+ { .sy_narg = AS(freebsd32___sysctl_args), .sy_call = (sy_call_t *)freebsd32___sysctl, .sy_auevent = AUE_SYSCTL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 202 = freebsd32___sysctl */
+ { .sy_narg = AS(mlock_args), .sy_call = (sy_call_t *)sys_mlock, .sy_auevent = AUE_MLOCK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 203 = mlock */
+ { .sy_narg = AS(munlock_args), .sy_call = (sy_call_t *)sys_munlock, .sy_auevent = AUE_MUNLOCK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 204 = munlock */
+ { .sy_narg = AS(undelete_args), .sy_call = (sy_call_t *)sys_undelete, .sy_auevent = AUE_UNDELETE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 205 = undelete */
+ { .sy_narg = AS(freebsd32_futimes_args), .sy_call = (sy_call_t *)freebsd32_futimes, .sy_auevent = AUE_FUTIMES, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 206 = freebsd32_futimes */
+ { .sy_narg = AS(getpgid_args), .sy_call = (sy_call_t *)sys_getpgid, .sy_auevent = AUE_GETPGID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 207 = getpgid */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 208 = nosys */
+ { .sy_narg = AS(poll_args), .sy_call = (sy_call_t *)sys_poll, .sy_auevent = AUE_POLL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 209 = poll */
+ { .sy_narg = AS(nosys_args), .sy_call = (sy_call_t *)lkmnosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 210 = lkmnosys */
+ { .sy_narg = AS(nosys_args), .sy_call = (sy_call_t *)lkmnosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 211 = lkmnosys */
+ { .sy_narg = AS(nosys_args), .sy_call = (sy_call_t *)lkmnosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 212 = lkmnosys */
+ { .sy_narg = AS(nosys_args), .sy_call = (sy_call_t *)lkmnosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 213 = lkmnosys */
+ { .sy_narg = AS(nosys_args), .sy_call = (sy_call_t *)lkmnosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 214 = lkmnosys */
+ { .sy_narg = AS(nosys_args), .sy_call = (sy_call_t *)lkmnosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 215 = lkmnosys */
+ { .sy_narg = AS(nosys_args), .sy_call = (sy_call_t *)lkmnosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 216 = lkmnosys */
+ { .sy_narg = AS(nosys_args), .sy_call = (sy_call_t *)lkmnosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 217 = lkmnosys */
+ { .sy_narg = AS(nosys_args), .sy_call = (sy_call_t *)lkmnosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 218 = lkmnosys */
+ { .sy_narg = AS(nosys_args), .sy_call = (sy_call_t *)lkmnosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 219 = lkmnosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 220 = freebsd7 freebsd32_semctl */
+ { .sy_narg = AS(semget_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 221 = semget */
+ { .sy_narg = AS(semop_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 222 = semop */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 223 = obsolete semconfig */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 224 = freebsd7 freebsd32_msgctl */
+ { .sy_narg = AS(msgget_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 225 = msgget */
+ { .sy_narg = AS(freebsd32_msgsnd_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 226 = freebsd32_msgsnd */
+ { .sy_narg = AS(freebsd32_msgrcv_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 227 = freebsd32_msgrcv */
+ { .sy_narg = AS(shmat_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 228 = shmat */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 229 = freebsd7 freebsd32_shmctl */
+ { .sy_narg = AS(shmdt_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 230 = shmdt */
+ { .sy_narg = AS(shmget_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 231 = shmget */
+ { .sy_narg = AS(freebsd32_clock_gettime_args), .sy_call = (sy_call_t *)freebsd32_clock_gettime, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 232 = freebsd32_clock_gettime */
+ { .sy_narg = AS(freebsd32_clock_settime_args), .sy_call = (sy_call_t *)freebsd32_clock_settime, .sy_auevent = AUE_CLOCK_SETTIME, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 233 = freebsd32_clock_settime */
+ { .sy_narg = AS(freebsd32_clock_getres_args), .sy_call = (sy_call_t *)freebsd32_clock_getres, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 234 = freebsd32_clock_getres */
+ { .sy_narg = AS(freebsd32_ktimer_create_args), .sy_call = (sy_call_t *)freebsd32_ktimer_create, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 235 = freebsd32_ktimer_create */
+ { .sy_narg = AS(ktimer_delete_args), .sy_call = (sy_call_t *)sys_ktimer_delete, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 236 = ktimer_delete */
+ { .sy_narg = AS(freebsd32_ktimer_settime_args), .sy_call = (sy_call_t *)freebsd32_ktimer_settime, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 237 = freebsd32_ktimer_settime */
+ { .sy_narg = AS(freebsd32_ktimer_gettime_args), .sy_call = (sy_call_t *)freebsd32_ktimer_gettime, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 238 = freebsd32_ktimer_gettime */
+ { .sy_narg = AS(ktimer_getoverrun_args), .sy_call = (sy_call_t *)sys_ktimer_getoverrun, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 239 = ktimer_getoverrun */
+ { .sy_narg = AS(freebsd32_nanosleep_args), .sy_call = (sy_call_t *)freebsd32_nanosleep, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 240 = freebsd32_nanosleep */
+ { .sy_narg = AS(ffclock_getcounter_args), .sy_call = (sy_call_t *)sys_ffclock_getcounter, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 241 = ffclock_getcounter */
+ { .sy_narg = AS(ffclock_setestimate_args), .sy_call = (sy_call_t *)sys_ffclock_setestimate, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 242 = ffclock_setestimate */
+ { .sy_narg = AS(ffclock_getestimate_args), .sy_call = (sy_call_t *)sys_ffclock_getestimate, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 243 = ffclock_getestimate */
+ { .sy_narg = AS(freebsd32_clock_nanosleep_args), .sy_call = (sy_call_t *)freebsd32_clock_nanosleep, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 244 = freebsd32_clock_nanosleep */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 245 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 246 = nosys */
+ { .sy_narg = AS(freebsd32_clock_getcpuclockid2_args), .sy_call = (sy_call_t *)freebsd32_clock_getcpuclockid2, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 247 = freebsd32_clock_getcpuclockid2 */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 248 = ntp_gettime */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 249 = nosys */
+ { .sy_narg = AS(minherit_args), .sy_call = (sy_call_t *)sys_minherit, .sy_auevent = AUE_MINHERIT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 250 = minherit */
+ { .sy_narg = AS(rfork_args), .sy_call = (sy_call_t *)sys_rfork, .sy_auevent = AUE_RFORK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 251 = rfork */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 252 = obsolete openbsd_poll */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)sys_issetugid, .sy_auevent = AUE_ISSETUGID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 253 = issetugid */
+ { .sy_narg = AS(lchown_args), .sy_call = (sy_call_t *)sys_lchown, .sy_auevent = AUE_LCHOWN, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 254 = lchown */
+ { .sy_narg = AS(freebsd32_aio_read_args), .sy_call = (sy_call_t *)freebsd32_aio_read, .sy_auevent = AUE_AIO_READ, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 255 = freebsd32_aio_read */
+ { .sy_narg = AS(freebsd32_aio_write_args), .sy_call = (sy_call_t *)freebsd32_aio_write, .sy_auevent = AUE_AIO_WRITE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 256 = freebsd32_aio_write */
+ { .sy_narg = AS(freebsd32_lio_listio_args), .sy_call = (sy_call_t *)freebsd32_lio_listio, .sy_auevent = AUE_LIO_LISTIO, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 257 = freebsd32_lio_listio */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 258 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 259 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 260 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 261 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 262 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 263 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 264 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 265 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 266 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 267 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 268 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 269 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 270 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 271 = nosys */
+ { compat11(AS(freebsd11_freebsd32_getdents_args),freebsd32_getdents), .sy_auevent = AUE_O_GETDENTS, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 272 = freebsd11 freebsd32_getdents */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 273 = nosys */
+ { .sy_narg = AS(lchmod_args), .sy_call = (sy_call_t *)sys_lchmod, .sy_auevent = AUE_LCHMOD, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 274 = lchmod */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 275 = obsolete netbsd_lchown */
+ { .sy_narg = AS(freebsd32_lutimes_args), .sy_call = (sy_call_t *)freebsd32_lutimes, .sy_auevent = AUE_LUTIMES, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 276 = freebsd32_lutimes */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 277 = obsolete netbsd_msync */
+ { compat11(AS(freebsd11_nstat_args),nstat), .sy_auevent = AUE_STAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 278 = freebsd11 nstat */
+ { compat11(AS(freebsd11_nfstat_args),nfstat), .sy_auevent = AUE_FSTAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 279 = freebsd11 nfstat */
+ { compat11(AS(freebsd11_nlstat_args),nlstat), .sy_auevent = AUE_LSTAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 280 = freebsd11 nlstat */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 281 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 282 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 283 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 284 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 285 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 286 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 287 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 288 = nosys */
+ { .sy_narg = AS(freebsd32_preadv_args), .sy_call = (sy_call_t *)freebsd32_preadv, .sy_auevent = AUE_PREADV, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 289 = freebsd32_preadv */
+ { .sy_narg = AS(freebsd32_pwritev_args), .sy_call = (sy_call_t *)freebsd32_pwritev, .sy_auevent = AUE_PWRITEV, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 290 = freebsd32_pwritev */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 291 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 292 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 293 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 294 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 295 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 296 = nosys */
+ { compat4(AS(freebsd4_freebsd32_fhstatfs_args),freebsd32_fhstatfs), .sy_auevent = AUE_FHSTATFS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 297 = freebsd4 freebsd32_fhstatfs */
+ { .sy_narg = AS(fhopen_args), .sy_call = (sy_call_t *)sys_fhopen, .sy_auevent = AUE_FHOPEN, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 298 = fhopen */
+ { compat11(AS(freebsd11_freebsd32_fhstat_args),freebsd32_fhstat), .sy_auevent = AUE_FHSTAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 299 = freebsd11 freebsd32_fhstat */
+ { .sy_narg = AS(modnext_args), .sy_call = (sy_call_t *)sys_modnext, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 300 = modnext */
+ { .sy_narg = AS(freebsd32_modstat_args), .sy_call = (sy_call_t *)freebsd32_modstat, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 301 = freebsd32_modstat */
+ { .sy_narg = AS(modfnext_args), .sy_call = (sy_call_t *)sys_modfnext, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 302 = modfnext */
+ { .sy_narg = AS(modfind_args), .sy_call = (sy_call_t *)sys_modfind, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 303 = modfind */
+ { .sy_narg = AS(kldload_args), .sy_call = (sy_call_t *)sys_kldload, .sy_auevent = AUE_MODLOAD, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 304 = kldload */
+ { .sy_narg = AS(kldunload_args), .sy_call = (sy_call_t *)sys_kldunload, .sy_auevent = AUE_MODUNLOAD, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 305 = kldunload */
+ { .sy_narg = AS(kldfind_args), .sy_call = (sy_call_t *)sys_kldfind, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 306 = kldfind */
+ { .sy_narg = AS(kldnext_args), .sy_call = (sy_call_t *)sys_kldnext, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 307 = kldnext */
+ { .sy_narg = AS(freebsd32_kldstat_args), .sy_call = (sy_call_t *)freebsd32_kldstat, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 308 = freebsd32_kldstat */
+ { .sy_narg = AS(kldfirstmod_args), .sy_call = (sy_call_t *)sys_kldfirstmod, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 309 = kldfirstmod */
+ { .sy_narg = AS(getsid_args), .sy_call = (sy_call_t *)sys_getsid, .sy_auevent = AUE_GETSID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 310 = getsid */
+ { .sy_narg = AS(setresuid_args), .sy_call = (sy_call_t *)sys_setresuid, .sy_auevent = AUE_SETRESUID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 311 = setresuid */
+ { .sy_narg = AS(setresgid_args), .sy_call = (sy_call_t *)sys_setresgid, .sy_auevent = AUE_SETRESGID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 312 = setresgid */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 313 = obsolete signanosleep */
+ { .sy_narg = AS(freebsd32_aio_return_args), .sy_call = (sy_call_t *)freebsd32_aio_return, .sy_auevent = AUE_AIO_RETURN, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 314 = freebsd32_aio_return */
+ { .sy_narg = AS(freebsd32_aio_suspend_args), .sy_call = (sy_call_t *)freebsd32_aio_suspend, .sy_auevent = AUE_AIO_SUSPEND, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 315 = freebsd32_aio_suspend */
+ { .sy_narg = AS(aio_cancel_args), .sy_call = (sy_call_t *)sys_aio_cancel, .sy_auevent = AUE_AIO_CANCEL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 316 = aio_cancel */
+ { .sy_narg = AS(freebsd32_aio_error_args), .sy_call = (sy_call_t *)freebsd32_aio_error, .sy_auevent = AUE_AIO_ERROR, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 317 = freebsd32_aio_error */
+ { compat6(AS(freebsd6_freebsd32_aio_read_args),freebsd32_aio_read), .sy_auevent = AUE_AIO_READ, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 318 = freebsd6 freebsd32_aio_read */
+ { compat6(AS(freebsd6_freebsd32_aio_write_args),freebsd32_aio_write), .sy_auevent = AUE_AIO_WRITE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 319 = freebsd6 freebsd32_aio_write */
+ { compat6(AS(freebsd6_freebsd32_lio_listio_args),freebsd32_lio_listio), .sy_auevent = AUE_LIO_LISTIO, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 320 = freebsd6 freebsd32_lio_listio */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)sys_yield, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 321 = yield */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 322 = obsolete thr_sleep */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 323 = obsolete thr_wakeup */
+ { .sy_narg = AS(mlockall_args), .sy_call = (sy_call_t *)sys_mlockall, .sy_auevent = AUE_MLOCKALL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 324 = mlockall */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)sys_munlockall, .sy_auevent = AUE_MUNLOCKALL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 325 = munlockall */
+ { .sy_narg = AS(__getcwd_args), .sy_call = (sy_call_t *)sys___getcwd, .sy_auevent = AUE_GETCWD, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 326 = __getcwd */
+ { .sy_narg = AS(sched_setparam_args), .sy_call = (sy_call_t *)sys_sched_setparam, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 327 = sched_setparam */
+ { .sy_narg = AS(sched_getparam_args), .sy_call = (sy_call_t *)sys_sched_getparam, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 328 = sched_getparam */
+ { .sy_narg = AS(sched_setscheduler_args), .sy_call = (sy_call_t *)sys_sched_setscheduler, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 329 = sched_setscheduler */
+ { .sy_narg = AS(sched_getscheduler_args), .sy_call = (sy_call_t *)sys_sched_getscheduler, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 330 = sched_getscheduler */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)sys_sched_yield, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 331 = sched_yield */
+ { .sy_narg = AS(sched_get_priority_max_args), .sy_call = (sy_call_t *)sys_sched_get_priority_max, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 332 = sched_get_priority_max */
+ { .sy_narg = AS(sched_get_priority_min_args), .sy_call = (sy_call_t *)sys_sched_get_priority_min, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 333 = sched_get_priority_min */
+ { .sy_narg = AS(freebsd32_sched_rr_get_interval_args), .sy_call = (sy_call_t *)freebsd32_sched_rr_get_interval, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 334 = freebsd32_sched_rr_get_interval */
+ { .sy_narg = AS(utrace_args), .sy_call = (sy_call_t *)sys_utrace, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 335 = utrace */
+ { compat4(AS(freebsd4_freebsd32_sendfile_args),freebsd32_sendfile), .sy_auevent = AUE_SENDFILE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 336 = freebsd4 freebsd32_sendfile */
+ { .sy_narg = AS(kldsym_args), .sy_call = (sy_call_t *)sys_kldsym, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 337 = kldsym */
+ { .sy_narg = AS(freebsd32_jail_args), .sy_call = (sy_call_t *)freebsd32_jail, .sy_auevent = AUE_JAIL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 338 = freebsd32_jail */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 339 = pioctl */
+ { .sy_narg = AS(sigprocmask_args), .sy_call = (sy_call_t *)sys_sigprocmask, .sy_auevent = AUE_SIGPROCMASK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 340 = sigprocmask */
+ { .sy_narg = AS(sigsuspend_args), .sy_call = (sy_call_t *)sys_sigsuspend, .sy_auevent = AUE_SIGSUSPEND, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 341 = sigsuspend */
+ { compat4(AS(freebsd4_freebsd32_sigaction_args),freebsd32_sigaction), .sy_auevent = AUE_SIGACTION, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 342 = freebsd4 freebsd32_sigaction */
+ { .sy_narg = AS(sigpending_args), .sy_call = (sy_call_t *)sys_sigpending, .sy_auevent = AUE_SIGPENDING, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 343 = sigpending */
+ { compat4(AS(freebsd4_freebsd32_sigreturn_args),freebsd32_sigreturn), .sy_auevent = AUE_SIGRETURN, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 344 = freebsd4 freebsd32_sigreturn */
+ { .sy_narg = AS(freebsd32_sigtimedwait_args), .sy_call = (sy_call_t *)freebsd32_sigtimedwait, .sy_auevent = AUE_SIGWAIT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 345 = freebsd32_sigtimedwait */
+ { .sy_narg = AS(freebsd32_sigwaitinfo_args), .sy_call = (sy_call_t *)freebsd32_sigwaitinfo, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 346 = freebsd32_sigwaitinfo */
+ { .sy_narg = AS(__acl_get_file_args), .sy_call = (sy_call_t *)sys___acl_get_file, .sy_auevent = AUE_ACL_GET_FILE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 347 = __acl_get_file */
+ { .sy_narg = AS(__acl_set_file_args), .sy_call = (sy_call_t *)sys___acl_set_file, .sy_auevent = AUE_ACL_SET_FILE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 348 = __acl_set_file */
+ { .sy_narg = AS(__acl_get_fd_args), .sy_call = (sy_call_t *)sys___acl_get_fd, .sy_auevent = AUE_ACL_GET_FD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 349 = __acl_get_fd */
+ { .sy_narg = AS(__acl_set_fd_args), .sy_call = (sy_call_t *)sys___acl_set_fd, .sy_auevent = AUE_ACL_SET_FD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 350 = __acl_set_fd */
+ { .sy_narg = AS(__acl_delete_file_args), .sy_call = (sy_call_t *)sys___acl_delete_file, .sy_auevent = AUE_ACL_DELETE_FILE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 351 = __acl_delete_file */
+ { .sy_narg = AS(__acl_delete_fd_args), .sy_call = (sy_call_t *)sys___acl_delete_fd, .sy_auevent = AUE_ACL_DELETE_FD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 352 = __acl_delete_fd */
+ { .sy_narg = AS(__acl_aclcheck_file_args), .sy_call = (sy_call_t *)sys___acl_aclcheck_file, .sy_auevent = AUE_ACL_CHECK_FILE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 353 = __acl_aclcheck_file */
+ { .sy_narg = AS(__acl_aclcheck_fd_args), .sy_call = (sy_call_t *)sys___acl_aclcheck_fd, .sy_auevent = AUE_ACL_CHECK_FD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 354 = __acl_aclcheck_fd */
+ { .sy_narg = AS(extattrctl_args), .sy_call = (sy_call_t *)sys_extattrctl, .sy_auevent = AUE_EXTATTRCTL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 355 = extattrctl */
+ { .sy_narg = AS(extattr_set_file_args), .sy_call = (sy_call_t *)sys_extattr_set_file, .sy_auevent = AUE_EXTATTR_SET_FILE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 356 = extattr_set_file */
+ { .sy_narg = AS(extattr_get_file_args), .sy_call = (sy_call_t *)sys_extattr_get_file, .sy_auevent = AUE_EXTATTR_GET_FILE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 357 = extattr_get_file */
+ { .sy_narg = AS(extattr_delete_file_args), .sy_call = (sy_call_t *)sys_extattr_delete_file, .sy_auevent = AUE_EXTATTR_DELETE_FILE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 358 = extattr_delete_file */
+ { .sy_narg = AS(freebsd32_aio_waitcomplete_args), .sy_call = (sy_call_t *)freebsd32_aio_waitcomplete, .sy_auevent = AUE_AIO_WAITCOMPLETE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 359 = freebsd32_aio_waitcomplete */
+ { .sy_narg = AS(getresuid_args), .sy_call = (sy_call_t *)sys_getresuid, .sy_auevent = AUE_GETRESUID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 360 = getresuid */
+ { .sy_narg = AS(getresgid_args), .sy_call = (sy_call_t *)sys_getresgid, .sy_auevent = AUE_GETRESGID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 361 = getresgid */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)sys_kqueue, .sy_auevent = AUE_KQUEUE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 362 = kqueue */
+ { compat11(AS(freebsd11_freebsd32_kevent_args),freebsd32_kevent), .sy_auevent = AUE_KEVENT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 363 = freebsd11 freebsd32_kevent */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 364 = obsolete __cap_get_proc */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 365 = obsolete __cap_set_proc */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 366 = obsolete __cap_get_fd */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 367 = obsolete __cap_get_file */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 368 = obsolete __cap_set_fd */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 369 = obsolete __cap_set_file */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 370 = nosys */
+ { .sy_narg = AS(extattr_set_fd_args), .sy_call = (sy_call_t *)sys_extattr_set_fd, .sy_auevent = AUE_EXTATTR_SET_FD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 371 = extattr_set_fd */
+ { .sy_narg = AS(extattr_get_fd_args), .sy_call = (sy_call_t *)sys_extattr_get_fd, .sy_auevent = AUE_EXTATTR_GET_FD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 372 = extattr_get_fd */
+ { .sy_narg = AS(extattr_delete_fd_args), .sy_call = (sy_call_t *)sys_extattr_delete_fd, .sy_auevent = AUE_EXTATTR_DELETE_FD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 373 = extattr_delete_fd */
+ { .sy_narg = AS(__setugid_args), .sy_call = (sy_call_t *)sys___setugid, .sy_auevent = AUE_SETUGID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 374 = __setugid */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 375 = obsolete nfsclnt */
+ { .sy_narg = AS(eaccess_args), .sy_call = (sy_call_t *)sys_eaccess, .sy_auevent = AUE_EACCESS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 376 = eaccess */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 377 = afs_syscall */
+ { .sy_narg = AS(freebsd32_nmount_args), .sy_call = (sy_call_t *)freebsd32_nmount, .sy_auevent = AUE_NMOUNT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 378 = freebsd32_nmount */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 379 = obsolete kse_exit */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 380 = obsolete kse_wakeup */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 381 = obsolete kse_create */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 382 = obsolete kse_thr_interrupt */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 383 = obsolete kse_release */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 384 = __mac_get_proc */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 385 = __mac_set_proc */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 386 = __mac_get_fd */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 387 = __mac_get_file */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 388 = __mac_set_fd */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 389 = __mac_set_file */
+ { .sy_narg = AS(kenv_args), .sy_call = (sy_call_t *)sys_kenv, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 390 = kenv */
+ { .sy_narg = AS(lchflags_args), .sy_call = (sy_call_t *)sys_lchflags, .sy_auevent = AUE_LCHFLAGS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 391 = lchflags */
+ { .sy_narg = AS(uuidgen_args), .sy_call = (sy_call_t *)sys_uuidgen, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 392 = uuidgen */
+ { .sy_narg = AS(freebsd32_sendfile_args), .sy_call = (sy_call_t *)freebsd32_sendfile, .sy_auevent = AUE_SENDFILE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 393 = freebsd32_sendfile */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 394 = mac_syscall */
+ { compat11(AS(freebsd11_getfsstat_args),getfsstat), .sy_auevent = AUE_GETFSSTAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 395 = freebsd11 getfsstat */
+ { compat11(AS(freebsd11_statfs_args),statfs), .sy_auevent = AUE_STATFS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 396 = freebsd11 statfs */
+ { compat11(AS(freebsd11_fstatfs_args),fstatfs), .sy_auevent = AUE_FSTATFS, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 397 = freebsd11 fstatfs */
+ { compat11(AS(freebsd11_fhstatfs_args),fhstatfs), .sy_auevent = AUE_FHSTATFS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 398 = freebsd11 fhstatfs */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 399 = nosys */
+ { .sy_narg = AS(ksem_close_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 400 = ksem_close */
+ { .sy_narg = AS(ksem_post_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 401 = ksem_post */
+ { .sy_narg = AS(ksem_wait_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 402 = ksem_wait */
+ { .sy_narg = AS(ksem_trywait_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 403 = ksem_trywait */
+ { .sy_narg = AS(freebsd32_ksem_init_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 404 = freebsd32_ksem_init */
+ { .sy_narg = AS(freebsd32_ksem_open_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 405 = freebsd32_ksem_open */
+ { .sy_narg = AS(ksem_unlink_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 406 = ksem_unlink */
+ { .sy_narg = AS(ksem_getvalue_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 407 = ksem_getvalue */
+ { .sy_narg = AS(ksem_destroy_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 408 = ksem_destroy */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 409 = __mac_get_pid */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 410 = __mac_get_link */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 411 = __mac_set_link */
+ { .sy_narg = AS(extattr_set_link_args), .sy_call = (sy_call_t *)sys_extattr_set_link, .sy_auevent = AUE_EXTATTR_SET_LINK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 412 = extattr_set_link */
+ { .sy_narg = AS(extattr_get_link_args), .sy_call = (sy_call_t *)sys_extattr_get_link, .sy_auevent = AUE_EXTATTR_GET_LINK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 413 = extattr_get_link */
+ { .sy_narg = AS(extattr_delete_link_args), .sy_call = (sy_call_t *)sys_extattr_delete_link, .sy_auevent = AUE_EXTATTR_DELETE_LINK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 414 = extattr_delete_link */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 415 = __mac_execve */
+ { .sy_narg = AS(freebsd32_sigaction_args), .sy_call = (sy_call_t *)freebsd32_sigaction, .sy_auevent = AUE_SIGACTION, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 416 = freebsd32_sigaction */
+ { .sy_narg = AS(freebsd32_sigreturn_args), .sy_call = (sy_call_t *)freebsd32_sigreturn, .sy_auevent = AUE_SIGRETURN, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 417 = freebsd32_sigreturn */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 418 = __xstat */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 419 = __xfstat */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 420 = __xlstat */
+ { .sy_narg = AS(freebsd32_getcontext_args), .sy_call = (sy_call_t *)freebsd32_getcontext, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 421 = freebsd32_getcontext */
+ { .sy_narg = AS(freebsd32_setcontext_args), .sy_call = (sy_call_t *)freebsd32_setcontext, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 422 = freebsd32_setcontext */
+ { .sy_narg = AS(freebsd32_swapcontext_args), .sy_call = (sy_call_t *)freebsd32_swapcontext, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 423 = freebsd32_swapcontext */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 424 = swapoff */
+ { .sy_narg = AS(__acl_get_link_args), .sy_call = (sy_call_t *)sys___acl_get_link, .sy_auevent = AUE_ACL_GET_LINK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 425 = __acl_get_link */
+ { .sy_narg = AS(__acl_set_link_args), .sy_call = (sy_call_t *)sys___acl_set_link, .sy_auevent = AUE_ACL_SET_LINK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 426 = __acl_set_link */
+ { .sy_narg = AS(__acl_delete_link_args), .sy_call = (sy_call_t *)sys___acl_delete_link, .sy_auevent = AUE_ACL_DELETE_LINK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 427 = __acl_delete_link */
+ { .sy_narg = AS(__acl_aclcheck_link_args), .sy_call = (sy_call_t *)sys___acl_aclcheck_link, .sy_auevent = AUE_ACL_CHECK_LINK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 428 = __acl_aclcheck_link */
+ { .sy_narg = AS(sigwait_args), .sy_call = (sy_call_t *)sys_sigwait, .sy_auevent = AUE_SIGWAIT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 429 = sigwait */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 430 = thr_create; */
+ { .sy_narg = AS(thr_exit_args), .sy_call = (sy_call_t *)sys_thr_exit, .sy_auevent = AUE_THR_EXIT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 431 = thr_exit */
+ { .sy_narg = AS(thr_self_args), .sy_call = (sy_call_t *)sys_thr_self, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 432 = thr_self */
+ { .sy_narg = AS(thr_kill_args), .sy_call = (sy_call_t *)sys_thr_kill, .sy_auevent = AUE_THR_KILL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 433 = thr_kill */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 434 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 435 = nosys */
+ { .sy_narg = AS(jail_attach_args), .sy_call = (sy_call_t *)sys_jail_attach, .sy_auevent = AUE_JAIL_ATTACH, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 436 = jail_attach */
+ { .sy_narg = AS(extattr_list_fd_args), .sy_call = (sy_call_t *)sys_extattr_list_fd, .sy_auevent = AUE_EXTATTR_LIST_FD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 437 = extattr_list_fd */
+ { .sy_narg = AS(extattr_list_file_args), .sy_call = (sy_call_t *)sys_extattr_list_file, .sy_auevent = AUE_EXTATTR_LIST_FILE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 438 = extattr_list_file */
+ { .sy_narg = AS(extattr_list_link_args), .sy_call = (sy_call_t *)sys_extattr_list_link, .sy_auevent = AUE_EXTATTR_LIST_LINK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 439 = extattr_list_link */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 440 = obsolete kse_switchin */
+ { .sy_narg = AS(freebsd32_ksem_timedwait_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 441 = freebsd32_ksem_timedwait */
+ { .sy_narg = AS(freebsd32_thr_suspend_args), .sy_call = (sy_call_t *)freebsd32_thr_suspend, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 442 = freebsd32_thr_suspend */
+ { .sy_narg = AS(thr_wake_args), .sy_call = (sy_call_t *)sys_thr_wake, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 443 = thr_wake */
+ { .sy_narg = AS(kldunloadf_args), .sy_call = (sy_call_t *)sys_kldunloadf, .sy_auevent = AUE_MODUNLOAD, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 444 = kldunloadf */
+ { .sy_narg = AS(audit_args), .sy_call = (sy_call_t *)sys_audit, .sy_auevent = AUE_AUDIT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 445 = audit */
+ { .sy_narg = AS(auditon_args), .sy_call = (sy_call_t *)sys_auditon, .sy_auevent = AUE_AUDITON, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 446 = auditon */
+ { .sy_narg = AS(getauid_args), .sy_call = (sy_call_t *)sys_getauid, .sy_auevent = AUE_GETAUID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 447 = getauid */
+ { .sy_narg = AS(setauid_args), .sy_call = (sy_call_t *)sys_setauid, .sy_auevent = AUE_SETAUID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 448 = setauid */
+ { .sy_narg = AS(getaudit_args), .sy_call = (sy_call_t *)sys_getaudit, .sy_auevent = AUE_GETAUDIT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 449 = getaudit */
+ { .sy_narg = AS(setaudit_args), .sy_call = (sy_call_t *)sys_setaudit, .sy_auevent = AUE_SETAUDIT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 450 = setaudit */
+ { .sy_narg = AS(getaudit_addr_args), .sy_call = (sy_call_t *)sys_getaudit_addr, .sy_auevent = AUE_GETAUDIT_ADDR, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 451 = getaudit_addr */
+ { .sy_narg = AS(setaudit_addr_args), .sy_call = (sy_call_t *)sys_setaudit_addr, .sy_auevent = AUE_SETAUDIT_ADDR, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 452 = setaudit_addr */
+ { .sy_narg = AS(auditctl_args), .sy_call = (sy_call_t *)sys_auditctl, .sy_auevent = AUE_AUDITCTL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 453 = auditctl */
+ { .sy_narg = AS(freebsd32__umtx_op_args), .sy_call = (sy_call_t *)freebsd32__umtx_op, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 454 = freebsd32__umtx_op */
+ { .sy_narg = AS(freebsd32_thr_new_args), .sy_call = (sy_call_t *)freebsd32_thr_new, .sy_auevent = AUE_THR_NEW, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 455 = freebsd32_thr_new */
+ { .sy_narg = AS(freebsd32_sigqueue_args), .sy_call = (sy_call_t *)freebsd32_sigqueue, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 456 = freebsd32_sigqueue */
+ { .sy_narg = AS(freebsd32_kmq_open_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 457 = freebsd32_kmq_open */
+ { .sy_narg = AS(freebsd32_kmq_setattr_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_ABSENT }, /* 458 = freebsd32_kmq_setattr */
+ { .sy_narg = AS(freebsd32_kmq_timedreceive_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_ABSENT }, /* 459 = freebsd32_kmq_timedreceive */
+ { .sy_narg = AS(freebsd32_kmq_timedsend_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_ABSENT }, /* 460 = freebsd32_kmq_timedsend */
+ { .sy_narg = AS(freebsd32_kmq_notify_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_ABSENT }, /* 461 = freebsd32_kmq_notify */
+ { .sy_narg = AS(kmq_unlink_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 462 = kmq_unlink */
+ { .sy_narg = AS(abort2_args), .sy_call = (sy_call_t *)sys_abort2, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 463 = abort2 */
+ { .sy_narg = AS(thr_set_name_args), .sy_call = (sy_call_t *)sys_thr_set_name, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 464 = thr_set_name */
+ { .sy_narg = AS(freebsd32_aio_fsync_args), .sy_call = (sy_call_t *)freebsd32_aio_fsync, .sy_auevent = AUE_AIO_FSYNC, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 465 = freebsd32_aio_fsync */
+ { .sy_narg = AS(rtprio_thread_args), .sy_call = (sy_call_t *)sys_rtprio_thread, .sy_auevent = AUE_RTPRIO, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 466 = rtprio_thread */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 467 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 468 = nosys */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 469 = __getpath_fromfd */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 470 = __getpath_fromaddr */
+ { .sy_narg = AS(sctp_peeloff_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_ABSENT }, /* 471 = sctp_peeloff */
+ { .sy_narg = AS(sctp_generic_sendmsg_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_ABSENT }, /* 472 = sctp_generic_sendmsg */
+ { .sy_narg = AS(sctp_generic_sendmsg_iov_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_ABSENT }, /* 473 = sctp_generic_sendmsg_iov */
+ { .sy_narg = AS(sctp_generic_recvmsg_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_ABSENT }, /* 474 = sctp_generic_recvmsg */
+#ifdef PAD64_REQUIRED
+ { .sy_narg = AS(freebsd32_pread_args), .sy_call = (sy_call_t *)freebsd32_pread, .sy_auevent = AUE_PREAD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 475 = freebsd32_pread */
+ { .sy_narg = AS(freebsd32_pwrite_args), .sy_call = (sy_call_t *)freebsd32_pwrite, .sy_auevent = AUE_PWRITE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 476 = freebsd32_pwrite */
+ { .sy_narg = AS(freebsd32_mmap_args), .sy_call = (sy_call_t *)freebsd32_mmap, .sy_auevent = AUE_MMAP, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 477 = freebsd32_mmap */
+ { .sy_narg = AS(freebsd32_lseek_args), .sy_call = (sy_call_t *)freebsd32_lseek, .sy_auevent = AUE_LSEEK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 478 = freebsd32_lseek */
+ { .sy_narg = AS(freebsd32_truncate_args), .sy_call = (sy_call_t *)freebsd32_truncate, .sy_auevent = AUE_TRUNCATE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 479 = freebsd32_truncate */
+ { .sy_narg = AS(freebsd32_ftruncate_args), .sy_call = (sy_call_t *)freebsd32_ftruncate, .sy_auevent = AUE_FTRUNCATE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 480 = freebsd32_ftruncate */
+#else
+ { .sy_narg = AS(freebsd32_pread_args), .sy_call = (sy_call_t *)freebsd32_pread, .sy_auevent = AUE_PREAD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 475 = freebsd32_pread */
+ { .sy_narg = AS(freebsd32_pwrite_args), .sy_call = (sy_call_t *)freebsd32_pwrite, .sy_auevent = AUE_PWRITE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 476 = freebsd32_pwrite */
+ { .sy_narg = AS(freebsd32_mmap_args), .sy_call = (sy_call_t *)freebsd32_mmap, .sy_auevent = AUE_MMAP, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 477 = freebsd32_mmap */
+ { .sy_narg = AS(freebsd32_lseek_args), .sy_call = (sy_call_t *)freebsd32_lseek, .sy_auevent = AUE_LSEEK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 478 = freebsd32_lseek */
+ { .sy_narg = AS(freebsd32_truncate_args), .sy_call = (sy_call_t *)freebsd32_truncate, .sy_auevent = AUE_TRUNCATE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 479 = freebsd32_truncate */
+ { .sy_narg = AS(freebsd32_ftruncate_args), .sy_call = (sy_call_t *)freebsd32_ftruncate, .sy_auevent = AUE_FTRUNCATE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 480 = freebsd32_ftruncate */
+#endif
+ { .sy_narg = AS(thr_kill2_args), .sy_call = (sy_call_t *)sys_thr_kill2, .sy_auevent = AUE_THR_KILL2, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 481 = thr_kill2 */
+ { compat12(AS(freebsd12_shm_open_args),shm_open), .sy_auevent = AUE_SHMOPEN, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 482 = freebsd12 shm_open */
+ { .sy_narg = AS(shm_unlink_args), .sy_call = (sy_call_t *)sys_shm_unlink, .sy_auevent = AUE_SHMUNLINK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 483 = shm_unlink */
+ { .sy_narg = AS(cpuset_args), .sy_call = (sy_call_t *)sys_cpuset, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 484 = cpuset */
+#ifdef PAD64_REQUIRED
+ { .sy_narg = AS(freebsd32_cpuset_setid_args), .sy_call = (sy_call_t *)freebsd32_cpuset_setid, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 485 = freebsd32_cpuset_setid */
+#else
+ { .sy_narg = AS(freebsd32_cpuset_setid_args), .sy_call = (sy_call_t *)freebsd32_cpuset_setid, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 485 = freebsd32_cpuset_setid */
+#endif
+ { .sy_narg = AS(freebsd32_cpuset_getid_args), .sy_call = (sy_call_t *)freebsd32_cpuset_getid, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 486 = freebsd32_cpuset_getid */
+ { .sy_narg = AS(freebsd32_cpuset_getaffinity_args), .sy_call = (sy_call_t *)freebsd32_cpuset_getaffinity, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 487 = freebsd32_cpuset_getaffinity */
+ { .sy_narg = AS(freebsd32_cpuset_setaffinity_args), .sy_call = (sy_call_t *)freebsd32_cpuset_setaffinity, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 488 = freebsd32_cpuset_setaffinity */
+ { .sy_narg = AS(faccessat_args), .sy_call = (sy_call_t *)sys_faccessat, .sy_auevent = AUE_FACCESSAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 489 = faccessat */
+ { .sy_narg = AS(fchmodat_args), .sy_call = (sy_call_t *)sys_fchmodat, .sy_auevent = AUE_FCHMODAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 490 = fchmodat */
+ { .sy_narg = AS(fchownat_args), .sy_call = (sy_call_t *)sys_fchownat, .sy_auevent = AUE_FCHOWNAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 491 = fchownat */
+ { .sy_narg = AS(freebsd32_fexecve_args), .sy_call = (sy_call_t *)freebsd32_fexecve, .sy_auevent = AUE_FEXECVE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 492 = freebsd32_fexecve */
+ { compat11(AS(freebsd11_freebsd32_fstatat_args),freebsd32_fstatat), .sy_auevent = AUE_FSTATAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 493 = freebsd11 freebsd32_fstatat */
+ { .sy_narg = AS(freebsd32_futimesat_args), .sy_call = (sy_call_t *)freebsd32_futimesat, .sy_auevent = AUE_FUTIMESAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 494 = freebsd32_futimesat */
+ { .sy_narg = AS(linkat_args), .sy_call = (sy_call_t *)sys_linkat, .sy_auevent = AUE_LINKAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 495 = linkat */
+ { .sy_narg = AS(mkdirat_args), .sy_call = (sy_call_t *)sys_mkdirat, .sy_auevent = AUE_MKDIRAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 496 = mkdirat */
+ { .sy_narg = AS(mkfifoat_args), .sy_call = (sy_call_t *)sys_mkfifoat, .sy_auevent = AUE_MKFIFOAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 497 = mkfifoat */
+ { compat11(AS(freebsd11_mknodat_args),mknodat), .sy_auevent = AUE_MKNODAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 498 = freebsd11 mknodat */
+ { .sy_narg = AS(openat_args), .sy_call = (sy_call_t *)sys_openat, .sy_auevent = AUE_OPENAT_RWTC, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 499 = openat */
+ { .sy_narg = AS(readlinkat_args), .sy_call = (sy_call_t *)sys_readlinkat, .sy_auevent = AUE_READLINKAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 500 = readlinkat */
+ { .sy_narg = AS(renameat_args), .sy_call = (sy_call_t *)sys_renameat, .sy_auevent = AUE_RENAMEAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 501 = renameat */
+ { .sy_narg = AS(symlinkat_args), .sy_call = (sy_call_t *)sys_symlinkat, .sy_auevent = AUE_SYMLINKAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 502 = symlinkat */
+ { .sy_narg = AS(unlinkat_args), .sy_call = (sy_call_t *)sys_unlinkat, .sy_auevent = AUE_UNLINKAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 503 = unlinkat */
+ { .sy_narg = AS(posix_openpt_args), .sy_call = (sy_call_t *)sys_posix_openpt, .sy_auevent = AUE_POSIX_OPENPT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 504 = posix_openpt */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 505 = gssd_syscall */
+ { .sy_narg = AS(freebsd32_jail_get_args), .sy_call = (sy_call_t *)freebsd32_jail_get, .sy_auevent = AUE_JAIL_GET, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 506 = freebsd32_jail_get */
+ { .sy_narg = AS(freebsd32_jail_set_args), .sy_call = (sy_call_t *)freebsd32_jail_set, .sy_auevent = AUE_JAIL_SET, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 507 = freebsd32_jail_set */
+ { .sy_narg = AS(jail_remove_args), .sy_call = (sy_call_t *)sys_jail_remove, .sy_auevent = AUE_JAIL_REMOVE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 508 = jail_remove */
+ { compat12(AS(freebsd12_closefrom_args),closefrom), .sy_auevent = AUE_CLOSEFROM, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 509 = freebsd12 closefrom */
+ { .sy_narg = AS(freebsd32_semctl_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 510 = freebsd32_semctl */
+ { .sy_narg = AS(freebsd32_msgctl_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 511 = freebsd32_msgctl */
+ { .sy_narg = AS(freebsd32_shmctl_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 512 = freebsd32_shmctl */
+ { .sy_narg = AS(lpathconf_args), .sy_call = (sy_call_t *)sys_lpathconf, .sy_auevent = AUE_LPATHCONF, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 513 = lpathconf */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 514 = obsolete cap_new */
+ { .sy_narg = AS(__cap_rights_get_args), .sy_call = (sy_call_t *)sys___cap_rights_get, .sy_auevent = AUE_CAP_RIGHTS_GET, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 515 = __cap_rights_get */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)sys_cap_enter, .sy_auevent = AUE_CAP_ENTER, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 516 = cap_enter */
+ { .sy_narg = AS(cap_getmode_args), .sy_call = (sy_call_t *)sys_cap_getmode, .sy_auevent = AUE_CAP_GETMODE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 517 = cap_getmode */
+ { .sy_narg = AS(pdfork_args), .sy_call = (sy_call_t *)sys_pdfork, .sy_auevent = AUE_PDFORK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 518 = pdfork */
+ { .sy_narg = AS(pdkill_args), .sy_call = (sy_call_t *)sys_pdkill, .sy_auevent = AUE_PDKILL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 519 = pdkill */
+ { .sy_narg = AS(pdgetpid_args), .sy_call = (sy_call_t *)sys_pdgetpid, .sy_auevent = AUE_PDGETPID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 520 = pdgetpid */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 521 = pdwait4 */
+ { .sy_narg = AS(freebsd32_pselect_args), .sy_call = (sy_call_t *)freebsd32_pselect, .sy_auevent = AUE_SELECT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 522 = freebsd32_pselect */
+ { .sy_narg = AS(getloginclass_args), .sy_call = (sy_call_t *)sys_getloginclass, .sy_auevent = AUE_GETLOGINCLASS, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 523 = getloginclass */
+ { .sy_narg = AS(setloginclass_args), .sy_call = (sy_call_t *)sys_setloginclass, .sy_auevent = AUE_SETLOGINCLASS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 524 = setloginclass */
+ { .sy_narg = AS(rctl_get_racct_args), .sy_call = (sy_call_t *)sys_rctl_get_racct, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 525 = rctl_get_racct */
+ { .sy_narg = AS(rctl_get_rules_args), .sy_call = (sy_call_t *)sys_rctl_get_rules, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 526 = rctl_get_rules */
+ { .sy_narg = AS(rctl_get_limits_args), .sy_call = (sy_call_t *)sys_rctl_get_limits, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 527 = rctl_get_limits */
+ { .sy_narg = AS(rctl_add_rule_args), .sy_call = (sy_call_t *)sys_rctl_add_rule, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 528 = rctl_add_rule */
+ { .sy_narg = AS(rctl_remove_rule_args), .sy_call = (sy_call_t *)sys_rctl_remove_rule, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 529 = rctl_remove_rule */
+#ifdef PAD64_REQUIRED
+ { .sy_narg = AS(freebsd32_posix_fallocate_args), .sy_call = (sy_call_t *)freebsd32_posix_fallocate, .sy_auevent = AUE_POSIX_FALLOCATE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 530 = freebsd32_posix_fallocate */
+ { .sy_narg = AS(freebsd32_posix_fadvise_args), .sy_call = (sy_call_t *)freebsd32_posix_fadvise, .sy_auevent = AUE_POSIX_FADVISE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 531 = freebsd32_posix_fadvise */
+ { .sy_narg = AS(freebsd32_wait6_args), .sy_call = (sy_call_t *)freebsd32_wait6, .sy_auevent = AUE_WAIT6, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 532 = freebsd32_wait6 */
+#else
+ { .sy_narg = AS(freebsd32_posix_fallocate_args), .sy_call = (sy_call_t *)freebsd32_posix_fallocate, .sy_auevent = AUE_POSIX_FALLOCATE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 530 = freebsd32_posix_fallocate */
+ { .sy_narg = AS(freebsd32_posix_fadvise_args), .sy_call = (sy_call_t *)freebsd32_posix_fadvise, .sy_auevent = AUE_POSIX_FADVISE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 531 = freebsd32_posix_fadvise */
+ { .sy_narg = AS(freebsd32_wait6_args), .sy_call = (sy_call_t *)freebsd32_wait6, .sy_auevent = AUE_WAIT6, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 532 = freebsd32_wait6 */
+#endif
+ { .sy_narg = AS(cap_rights_limit_args), .sy_call = (sy_call_t *)sys_cap_rights_limit, .sy_auevent = AUE_CAP_RIGHTS_LIMIT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 533 = cap_rights_limit */
+ { .sy_narg = AS(freebsd32_cap_ioctls_limit_args), .sy_call = (sy_call_t *)freebsd32_cap_ioctls_limit, .sy_auevent = AUE_CAP_IOCTLS_LIMIT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 534 = freebsd32_cap_ioctls_limit */
+ { .sy_narg = AS(freebsd32_cap_ioctls_get_args), .sy_call = (sy_call_t *)freebsd32_cap_ioctls_get, .sy_auevent = AUE_CAP_IOCTLS_GET, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 535 = freebsd32_cap_ioctls_get */
+ { .sy_narg = AS(cap_fcntls_limit_args), .sy_call = (sy_call_t *)sys_cap_fcntls_limit, .sy_auevent = AUE_CAP_FCNTLS_LIMIT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 536 = cap_fcntls_limit */
+ { .sy_narg = AS(cap_fcntls_get_args), .sy_call = (sy_call_t *)sys_cap_fcntls_get, .sy_auevent = AUE_CAP_FCNTLS_GET, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 537 = cap_fcntls_get */
+ { .sy_narg = AS(bindat_args), .sy_call = (sy_call_t *)sys_bindat, .sy_auevent = AUE_BINDAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 538 = bindat */
+ { .sy_narg = AS(connectat_args), .sy_call = (sy_call_t *)sys_connectat, .sy_auevent = AUE_CONNECTAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 539 = connectat */
+ { .sy_narg = AS(chflagsat_args), .sy_call = (sy_call_t *)sys_chflagsat, .sy_auevent = AUE_CHFLAGSAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 540 = chflagsat */
+ { .sy_narg = AS(accept4_args), .sy_call = (sy_call_t *)sys_accept4, .sy_auevent = AUE_ACCEPT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 541 = accept4 */
+ { .sy_narg = AS(pipe2_args), .sy_call = (sy_call_t *)sys_pipe2, .sy_auevent = AUE_PIPE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 542 = pipe2 */
+ { .sy_narg = AS(freebsd32_aio_mlock_args), .sy_call = (sy_call_t *)freebsd32_aio_mlock, .sy_auevent = AUE_AIO_MLOCK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 543 = freebsd32_aio_mlock */
+#ifdef PAD64_REQUIRED
+ { .sy_narg = AS(freebsd32_procctl_args), .sy_call = (sy_call_t *)freebsd32_procctl, .sy_auevent = AUE_PROCCTL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 544 = freebsd32_procctl */
+#else
+ { .sy_narg = AS(freebsd32_procctl_args), .sy_call = (sy_call_t *)freebsd32_procctl, .sy_auevent = AUE_PROCCTL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 544 = freebsd32_procctl */
+#endif
+ { .sy_narg = AS(freebsd32_ppoll_args), .sy_call = (sy_call_t *)freebsd32_ppoll, .sy_auevent = AUE_POLL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 545 = freebsd32_ppoll */
+ { .sy_narg = AS(freebsd32_futimens_args), .sy_call = (sy_call_t *)freebsd32_futimens, .sy_auevent = AUE_FUTIMES, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 546 = freebsd32_futimens */
+ { .sy_narg = AS(freebsd32_utimensat_args), .sy_call = (sy_call_t *)freebsd32_utimensat, .sy_auevent = AUE_FUTIMESAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 547 = freebsd32_utimensat */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 548 = obsolete numa_getaffinity */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 549 = obsolete numa_setaffinity */
+ { .sy_narg = AS(fdatasync_args), .sy_call = (sy_call_t *)sys_fdatasync, .sy_auevent = AUE_FSYNC, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 550 = fdatasync */
+ { .sy_narg = AS(freebsd32_fstat_args), .sy_call = (sy_call_t *)freebsd32_fstat, .sy_auevent = AUE_FSTAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 551 = freebsd32_fstat */
+ { .sy_narg = AS(freebsd32_fstatat_args), .sy_call = (sy_call_t *)freebsd32_fstatat, .sy_auevent = AUE_FSTATAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 552 = freebsd32_fstatat */
+ { .sy_narg = AS(freebsd32_fhstat_args), .sy_call = (sy_call_t *)freebsd32_fhstat, .sy_auevent = AUE_FHSTAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 553 = freebsd32_fhstat */
+ { .sy_narg = AS(getdirentries_args), .sy_call = (sy_call_t *)sys_getdirentries, .sy_auevent = AUE_GETDIRENTRIES, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 554 = getdirentries */
+ { .sy_narg = AS(statfs_args), .sy_call = (sy_call_t *)sys_statfs, .sy_auevent = AUE_STATFS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 555 = statfs */
+ { .sy_narg = AS(fstatfs_args), .sy_call = (sy_call_t *)sys_fstatfs, .sy_auevent = AUE_FSTATFS, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 556 = fstatfs */
+ { .sy_narg = AS(getfsstat_args), .sy_call = (sy_call_t *)sys_getfsstat, .sy_auevent = AUE_GETFSSTAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 557 = getfsstat */
+ { .sy_narg = AS(fhstatfs_args), .sy_call = (sy_call_t *)sys_fhstatfs, .sy_auevent = AUE_FHSTATFS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 558 = fhstatfs */
+#ifdef PAD64_REQUIRED
+ { .sy_narg = AS(freebsd32_mknodat_args), .sy_call = (sy_call_t *)freebsd32_mknodat, .sy_auevent = AUE_MKNODAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 559 = freebsd32_mknodat */
+#else
+ { .sy_narg = AS(freebsd32_mknodat_args), .sy_call = (sy_call_t *)freebsd32_mknodat, .sy_auevent = AUE_MKNODAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 559 = freebsd32_mknodat */
+#endif
+ { .sy_narg = AS(freebsd32_kevent_args), .sy_call = (sy_call_t *)freebsd32_kevent, .sy_auevent = AUE_KEVENT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 560 = freebsd32_kevent */
+ { .sy_narg = AS(freebsd32_cpuset_getdomain_args), .sy_call = (sy_call_t *)freebsd32_cpuset_getdomain, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 561 = freebsd32_cpuset_getdomain */
+ { .sy_narg = AS(freebsd32_cpuset_setdomain_args), .sy_call = (sy_call_t *)freebsd32_cpuset_setdomain, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 562 = freebsd32_cpuset_setdomain */
+ { .sy_narg = AS(getrandom_args), .sy_call = (sy_call_t *)sys_getrandom, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 563 = getrandom */
+ { .sy_narg = AS(getfhat_args), .sy_call = (sy_call_t *)sys_getfhat, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 564 = getfhat */
+ { .sy_narg = AS(fhlink_args), .sy_call = (sy_call_t *)sys_fhlink, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 565 = fhlink */
+ { .sy_narg = AS(fhlinkat_args), .sy_call = (sy_call_t *)sys_fhlinkat, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 566 = fhlinkat */
+ { .sy_narg = AS(fhreadlink_args), .sy_call = (sy_call_t *)sys_fhreadlink, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 567 = fhreadlink */
+ { .sy_narg = AS(funlinkat_args), .sy_call = (sy_call_t *)sys_funlinkat, .sy_auevent = AUE_UNLINKAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 568 = funlinkat */
+ { .sy_narg = AS(copy_file_range_args), .sy_call = (sy_call_t *)sys_copy_file_range, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 569 = copy_file_range */
+ { .sy_narg = AS(freebsd32___sysctlbyname_args), .sy_call = (sy_call_t *)freebsd32___sysctlbyname, .sy_auevent = AUE_SYSCTL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 570 = freebsd32___sysctlbyname */
+ { .sy_narg = AS(shm_open2_args), .sy_call = (sy_call_t *)sys_shm_open2, .sy_auevent = AUE_SHMOPEN, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 571 = shm_open2 */
+ { .sy_narg = AS(shm_rename_args), .sy_call = (sy_call_t *)sys_shm_rename, .sy_auevent = AUE_SHMRENAME, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 572 = shm_rename */
+ { .sy_narg = AS(sigfastblock_args), .sy_call = (sy_call_t *)sys_sigfastblock, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 573 = sigfastblock */
+ { .sy_narg = AS(__realpathat_args), .sy_call = (sy_call_t *)sys___realpathat, .sy_auevent = AUE_REALPATHAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 574 = __realpathat */
+ { .sy_narg = AS(close_range_args), .sy_call = (sy_call_t *)sys_close_range, .sy_auevent = AUE_CLOSERANGE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 575 = close_range */
+ { .sy_narg = AS(rpctls_syscall_args), .sy_call = (sy_call_t *)lkmressys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 576 = rpctls_syscall */
+ { .sy_narg = AS(__specialfd_args), .sy_call = (sy_call_t *)sys___specialfd, .sy_auevent = AUE_SPECIALFD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 577 = __specialfd */
+ { .sy_narg = AS(freebsd32_aio_writev_args), .sy_call = (sy_call_t *)freebsd32_aio_writev, .sy_auevent = AUE_AIO_WRITEV, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 578 = freebsd32_aio_writev */
+ { .sy_narg = AS(freebsd32_aio_readv_args), .sy_call = (sy_call_t *)freebsd32_aio_readv, .sy_auevent = AUE_AIO_READV, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 579 = freebsd32_aio_readv */
+};
diff --git a/sys/compat/freebsd32/freebsd32_systrace_args.c b/sys/compat/freebsd32/freebsd32_systrace_args.c
new file mode 100644
index 000000000000..c4f1602f885c
--- /dev/null
+++ b/sys/compat/freebsd32/freebsd32_systrace_args.c
@@ -0,0 +1,11110 @@
+/*
+ * System call argument to DTrace register array converstion.
+ *
+ * DO NOT EDIT-- this file is automatically @generated.
+ * $FreeBSD$
+ * This file is part of the DTrace syscall provider.
+ */
+
+static void
+systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
+{
+ int64_t *iarg = (int64_t *) uarg;
+ switch (sysnum) {
+#if !defined(PAD64_REQUIRED) && !defined(__amd64__)
+#define PAD64_REQUIRED
+#endif
+ /* nosys */
+ case 0: {
+ *n_args = 0;
+ break;
+ }
+ /* sys_exit */
+ case 1: {
+ struct sys_exit_args *p = params;
+ iarg[0] = p->rval; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* fork */
+ case 2: {
+ *n_args = 0;
+ break;
+ }
+ /* read */
+ case 3: {
+ struct read_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->buf; /* void * */
+ uarg[2] = p->nbyte; /* size_t */
+ *n_args = 3;
+ break;
+ }
+ /* write */
+ case 4: {
+ struct write_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->buf; /* const void * */
+ uarg[2] = p->nbyte; /* size_t */
+ *n_args = 3;
+ break;
+ }
+ /* open */
+ case 5: {
+ struct open_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->flags; /* int */
+ iarg[2] = p->mode; /* mode_t */
+ *n_args = 3;
+ break;
+ }
+ /* close */
+ case 6: {
+ struct close_args *p = params;
+ iarg[0] = p->fd; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* freebsd32_wait4 */
+ case 7: {
+ struct freebsd32_wait4_args *p = params;
+ iarg[0] = p->pid; /* int */
+ uarg[1] = (intptr_t) p->status; /* int * */
+ iarg[2] = p->options; /* int */
+ uarg[3] = (intptr_t) p->rusage; /* struct rusage32 * */
+ *n_args = 4;
+ break;
+ }
+ /* link */
+ case 9: {
+ struct link_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ uarg[1] = (intptr_t) p->link; /* const char * */
+ *n_args = 2;
+ break;
+ }
+ /* unlink */
+ case 10: {
+ struct unlink_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ *n_args = 1;
+ break;
+ }
+ /* chdir */
+ case 12: {
+ struct chdir_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ *n_args = 1;
+ break;
+ }
+ /* fchdir */
+ case 13: {
+ struct fchdir_args *p = params;
+ iarg[0] = p->fd; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* chmod */
+ case 15: {
+ struct chmod_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->mode; /* mode_t */
+ *n_args = 2;
+ break;
+ }
+ /* chown */
+ case 16: {
+ struct chown_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->uid; /* int */
+ iarg[2] = p->gid; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* break */
+ case 17: {
+ struct break_args *p = params;
+ uarg[0] = (intptr_t) p->nsize; /* char * */
+ *n_args = 1;
+ break;
+ }
+ /* getpid */
+ case 20: {
+ *n_args = 0;
+ break;
+ }
+ /* mount */
+ case 21: {
+ struct mount_args *p = params;
+ uarg[0] = (intptr_t) p->type; /* const char * */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ iarg[2] = p->flags; /* int */
+ uarg[3] = (intptr_t) p->data; /* void * */
+ *n_args = 4;
+ break;
+ }
+ /* unmount */
+ case 22: {
+ struct unmount_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->flags; /* int */
+ *n_args = 2;
+ break;
+ }
+ /* setuid */
+ case 23: {
+ struct setuid_args *p = params;
+ uarg[0] = p->uid; /* uid_t */
+ *n_args = 1;
+ break;
+ }
+ /* getuid */
+ case 24: {
+ *n_args = 0;
+ break;
+ }
+ /* geteuid */
+ case 25: {
+ *n_args = 0;
+ break;
+ }
+ /* freebsd32_ptrace */
+ case 26: {
+ struct freebsd32_ptrace_args *p = params;
+ iarg[0] = p->req; /* int */
+ iarg[1] = p->pid; /* pid_t */
+ uarg[2] = (intptr_t) p->addr; /* caddr_t */
+ iarg[3] = p->data; /* int */
+ *n_args = 4;
+ break;
+ }
+ /* freebsd32_recvmsg */
+ case 27: {
+ struct freebsd32_recvmsg_args *p = params;
+ iarg[0] = p->s; /* int */
+ uarg[1] = (intptr_t) p->msg; /* struct msghdr32 * */
+ iarg[2] = p->flags; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* freebsd32_sendmsg */
+ case 28: {
+ struct freebsd32_sendmsg_args *p = params;
+ iarg[0] = p->s; /* int */
+ uarg[1] = (intptr_t) p->msg; /* struct msghdr32 * */
+ iarg[2] = p->flags; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* freebsd32_recvfrom */
+ case 29: {
+ struct freebsd32_recvfrom_args *p = params;
+ iarg[0] = p->s; /* int */
+ uarg[1] = (intptr_t) p->buf; /* void * */
+ uarg[2] = p->len; /* uint32_t */
+ iarg[3] = p->flags; /* int */
+ uarg[4] = (intptr_t) p->from; /* struct sockaddr * */
+ uarg[5] = p->fromlenaddr; /* uint32_t */
+ *n_args = 6;
+ break;
+ }
+ /* accept */
+ case 30: {
+ struct accept_args *p = params;
+ iarg[0] = p->s; /* int */
+ uarg[1] = (intptr_t) p->name; /* struct sockaddr * */
+ uarg[2] = (intptr_t) p->anamelen; /* int * */
+ *n_args = 3;
+ break;
+ }
+ /* getpeername */
+ case 31: {
+ struct getpeername_args *p = params;
+ iarg[0] = p->fdes; /* int */
+ uarg[1] = (intptr_t) p->asa; /* struct sockaddr * */
+ uarg[2] = (intptr_t) p->alen; /* int * */
+ *n_args = 3;
+ break;
+ }
+ /* getsockname */
+ case 32: {
+ struct getsockname_args *p = params;
+ iarg[0] = p->fdes; /* int */
+ uarg[1] = (intptr_t) p->asa; /* struct sockaddr * */
+ uarg[2] = (intptr_t) p->alen; /* int * */
+ *n_args = 3;
+ break;
+ }
+ /* access */
+ case 33: {
+ struct access_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->amode; /* int */
+ *n_args = 2;
+ break;
+ }
+ /* chflags */
+ case 34: {
+ struct chflags_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ uarg[1] = p->flags; /* u_long */
+ *n_args = 2;
+ break;
+ }
+ /* fchflags */
+ case 35: {
+ struct fchflags_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = p->flags; /* u_long */
+ *n_args = 2;
+ break;
+ }
+ /* sync */
+ case 36: {
+ *n_args = 0;
+ break;
+ }
+ /* kill */
+ case 37: {
+ struct kill_args *p = params;
+ iarg[0] = p->pid; /* int */
+ iarg[1] = p->signum; /* int */
+ *n_args = 2;
+ break;
+ }
+ /* getppid */
+ case 39: {
+ *n_args = 0;
+ break;
+ }
+ /* dup */
+ case 41: {
+ struct dup_args *p = params;
+ uarg[0] = p->fd; /* u_int */
+ *n_args = 1;
+ break;
+ }
+ /* getegid */
+ case 43: {
+ *n_args = 0;
+ break;
+ }
+ /* profil */
+ case 44: {
+ struct profil_args *p = params;
+ uarg[0] = (intptr_t) p->samples; /* char * */
+ uarg[1] = p->size; /* size_t */
+ uarg[2] = p->offset; /* size_t */
+ uarg[3] = p->scale; /* u_int */
+ *n_args = 4;
+ break;
+ }
+ /* ktrace */
+ case 45: {
+ struct ktrace_args *p = params;
+ uarg[0] = (intptr_t) p->fname; /* const char * */
+ iarg[1] = p->ops; /* int */
+ iarg[2] = p->facs; /* int */
+ iarg[3] = p->pid; /* int */
+ *n_args = 4;
+ break;
+ }
+ /* getgid */
+ case 47: {
+ *n_args = 0;
+ break;
+ }
+ /* getlogin */
+ case 49: {
+ struct getlogin_args *p = params;
+ uarg[0] = (intptr_t) p->namebuf; /* char * */
+ uarg[1] = p->namelen; /* u_int */
+ *n_args = 2;
+ break;
+ }
+ /* setlogin */
+ case 50: {
+ struct setlogin_args *p = params;
+ uarg[0] = (intptr_t) p->namebuf; /* const char * */
+ *n_args = 1;
+ break;
+ }
+ /* acct */
+ case 51: {
+ struct acct_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ *n_args = 1;
+ break;
+ }
+ /* freebsd32_sigaltstack */
+ case 53: {
+ struct freebsd32_sigaltstack_args *p = params;
+ uarg[0] = (intptr_t) p->ss; /* struct sigaltstack32 * */
+ uarg[1] = (intptr_t) p->oss; /* struct sigaltstack32 * */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_ioctl */
+ case 54: {
+ struct freebsd32_ioctl_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = p->com; /* uint32_t */
+ uarg[2] = (intptr_t) p->data; /* struct md_ioctl32 * */
+ *n_args = 3;
+ break;
+ }
+ /* reboot */
+ case 55: {
+ struct reboot_args *p = params;
+ iarg[0] = p->opt; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* revoke */
+ case 56: {
+ struct revoke_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ *n_args = 1;
+ break;
+ }
+ /* symlink */
+ case 57: {
+ struct symlink_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ uarg[1] = (intptr_t) p->link; /* const char * */
+ *n_args = 2;
+ break;
+ }
+ /* readlink */
+ case 58: {
+ struct readlink_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ uarg[1] = (intptr_t) p->buf; /* char * */
+ uarg[2] = p->count; /* size_t */
+ *n_args = 3;
+ break;
+ }
+ /* freebsd32_execve */
+ case 59: {
+ struct freebsd32_execve_args *p = params;
+ uarg[0] = (intptr_t) p->fname; /* const char * */
+ uarg[1] = (intptr_t) p->argv; /* uint32_t * */
+ uarg[2] = (intptr_t) p->envv; /* uint32_t * */
+ *n_args = 3;
+ break;
+ }
+ /* umask */
+ case 60: {
+ struct umask_args *p = params;
+ iarg[0] = p->newmask; /* mode_t */
+ *n_args = 1;
+ break;
+ }
+ /* chroot */
+ case 61: {
+ struct chroot_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ *n_args = 1;
+ break;
+ }
+ /* msync */
+ case 65: {
+ struct msync_args *p = params;
+ uarg[0] = (intptr_t) p->addr; /* void * */
+ uarg[1] = p->len; /* size_t */
+ iarg[2] = p->flags; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* vfork */
+ case 66: {
+ *n_args = 0;
+ break;
+ }
+ /* sbrk */
+ case 69: {
+ struct sbrk_args *p = params;
+ iarg[0] = p->incr; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* sstk */
+ case 70: {
+ struct sstk_args *p = params;
+ iarg[0] = p->incr; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* munmap */
+ case 73: {
+ struct munmap_args *p = params;
+ uarg[0] = (intptr_t) p->addr; /* void * */
+ uarg[1] = p->len; /* size_t */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_mprotect */
+ case 74: {
+ struct freebsd32_mprotect_args *p = params;
+ uarg[0] = (intptr_t) p->addr; /* void * */
+ uarg[1] = p->len; /* size_t */
+ iarg[2] = p->prot; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* madvise */
+ case 75: {
+ struct madvise_args *p = params;
+ uarg[0] = (intptr_t) p->addr; /* void * */
+ uarg[1] = p->len; /* size_t */
+ iarg[2] = p->behav; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* mincore */
+ case 78: {
+ struct mincore_args *p = params;
+ uarg[0] = (intptr_t) p->addr; /* const void * */
+ uarg[1] = p->len; /* size_t */
+ uarg[2] = (intptr_t) p->vec; /* char * */
+ *n_args = 3;
+ break;
+ }
+ /* getgroups */
+ case 79: {
+ struct getgroups_args *p = params;
+ uarg[0] = p->gidsetsize; /* u_int */
+ uarg[1] = (intptr_t) p->gidset; /* gid_t * */
+ *n_args = 2;
+ break;
+ }
+ /* setgroups */
+ case 80: {
+ struct setgroups_args *p = params;
+ uarg[0] = p->gidsetsize; /* u_int */
+ uarg[1] = (intptr_t) p->gidset; /* gid_t * */
+ *n_args = 2;
+ break;
+ }
+ /* getpgrp */
+ case 81: {
+ *n_args = 0;
+ break;
+ }
+ /* setpgid */
+ case 82: {
+ struct setpgid_args *p = params;
+ iarg[0] = p->pid; /* int */
+ iarg[1] = p->pgid; /* int */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_setitimer */
+ case 83: {
+ struct freebsd32_setitimer_args *p = params;
+ uarg[0] = p->which; /* u_int */
+ uarg[1] = (intptr_t) p->itv; /* struct itimerval32 * */
+ uarg[2] = (intptr_t) p->oitv; /* struct itimerval32 * */
+ *n_args = 3;
+ break;
+ }
+ /* swapon */
+ case 85: {
+ struct swapon_args *p = params;
+ uarg[0] = (intptr_t) p->name; /* const char * */
+ *n_args = 1;
+ break;
+ }
+ /* freebsd32_getitimer */
+ case 86: {
+ struct freebsd32_getitimer_args *p = params;
+ uarg[0] = p->which; /* u_int */
+ uarg[1] = (intptr_t) p->itv; /* struct itimerval32 * */
+ *n_args = 2;
+ break;
+ }
+ /* getdtablesize */
+ case 89: {
+ *n_args = 0;
+ break;
+ }
+ /* dup2 */
+ case 90: {
+ struct dup2_args *p = params;
+ uarg[0] = p->from; /* u_int */
+ uarg[1] = p->to; /* u_int */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_fcntl */
+ case 92: {
+ struct freebsd32_fcntl_args *p = params;
+ iarg[0] = p->fd; /* int */
+ iarg[1] = p->cmd; /* int */
+ iarg[2] = p->arg; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* freebsd32_select */
+ case 93: {
+ struct freebsd32_select_args *p = params;
+ iarg[0] = p->nd; /* int */
+ uarg[1] = (intptr_t) p->in; /* fd_set * */
+ uarg[2] = (intptr_t) p->ou; /* fd_set * */
+ uarg[3] = (intptr_t) p->ex; /* fd_set * */
+ uarg[4] = (intptr_t) p->tv; /* struct timeval32 * */
+ *n_args = 5;
+ break;
+ }
+ /* fsync */
+ case 95: {
+ struct fsync_args *p = params;
+ iarg[0] = p->fd; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* setpriority */
+ case 96: {
+ struct setpriority_args *p = params;
+ iarg[0] = p->which; /* int */
+ iarg[1] = p->who; /* int */
+ iarg[2] = p->prio; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* socket */
+ case 97: {
+ struct socket_args *p = params;
+ iarg[0] = p->domain; /* int */
+ iarg[1] = p->type; /* int */
+ iarg[2] = p->protocol; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* connect */
+ case 98: {
+ struct connect_args *p = params;
+ iarg[0] = p->s; /* int */
+ uarg[1] = (intptr_t) p->name; /* const struct sockaddr * */
+ iarg[2] = p->namelen; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* getpriority */
+ case 100: {
+ struct getpriority_args *p = params;
+ iarg[0] = p->which; /* int */
+ iarg[1] = p->who; /* int */
+ *n_args = 2;
+ break;
+ }
+ /* bind */
+ case 104: {
+ struct bind_args *p = params;
+ iarg[0] = p->s; /* int */
+ uarg[1] = (intptr_t) p->name; /* const struct sockaddr * */
+ iarg[2] = p->namelen; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* setsockopt */
+ case 105: {
+ struct setsockopt_args *p = params;
+ iarg[0] = p->s; /* int */
+ iarg[1] = p->level; /* int */
+ iarg[2] = p->name; /* int */
+ uarg[3] = (intptr_t) p->val; /* const void * */
+ iarg[4] = p->valsize; /* int */
+ *n_args = 5;
+ break;
+ }
+ /* listen */
+ case 106: {
+ struct listen_args *p = params;
+ iarg[0] = p->s; /* int */
+ iarg[1] = p->backlog; /* int */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_gettimeofday */
+ case 116: {
+ struct freebsd32_gettimeofday_args *p = params;
+ uarg[0] = (intptr_t) p->tp; /* struct timeval32 * */
+ uarg[1] = (intptr_t) p->tzp; /* struct timezone * */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_getrusage */
+ case 117: {
+ struct freebsd32_getrusage_args *p = params;
+ iarg[0] = p->who; /* int */
+ uarg[1] = (intptr_t) p->rusage; /* struct rusage32 * */
+ *n_args = 2;
+ break;
+ }
+ /* getsockopt */
+ case 118: {
+ struct getsockopt_args *p = params;
+ iarg[0] = p->s; /* int */
+ iarg[1] = p->level; /* int */
+ iarg[2] = p->name; /* int */
+ uarg[3] = (intptr_t) p->val; /* void * */
+ uarg[4] = (intptr_t) p->avalsize; /* int * */
+ *n_args = 5;
+ break;
+ }
+ /* freebsd32_readv */
+ case 120: {
+ struct freebsd32_readv_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->iovp; /* struct iovec32 * */
+ uarg[2] = p->iovcnt; /* u_int */
+ *n_args = 3;
+ break;
+ }
+ /* freebsd32_writev */
+ case 121: {
+ struct freebsd32_writev_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->iovp; /* struct iovec32 * */
+ uarg[2] = p->iovcnt; /* u_int */
+ *n_args = 3;
+ break;
+ }
+ /* freebsd32_settimeofday */
+ case 122: {
+ struct freebsd32_settimeofday_args *p = params;
+ uarg[0] = (intptr_t) p->tv; /* struct timeval32 * */
+ uarg[1] = (intptr_t) p->tzp; /* struct timezone * */
+ *n_args = 2;
+ break;
+ }
+ /* fchown */
+ case 123: {
+ struct fchown_args *p = params;
+ iarg[0] = p->fd; /* int */
+ iarg[1] = p->uid; /* int */
+ iarg[2] = p->gid; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* fchmod */
+ case 124: {
+ struct fchmod_args *p = params;
+ iarg[0] = p->fd; /* int */
+ iarg[1] = p->mode; /* mode_t */
+ *n_args = 2;
+ break;
+ }
+ /* setreuid */
+ case 126: {
+ struct setreuid_args *p = params;
+ iarg[0] = p->ruid; /* int */
+ iarg[1] = p->euid; /* int */
+ *n_args = 2;
+ break;
+ }
+ /* setregid */
+ case 127: {
+ struct setregid_args *p = params;
+ iarg[0] = p->rgid; /* int */
+ iarg[1] = p->egid; /* int */
+ *n_args = 2;
+ break;
+ }
+ /* rename */
+ case 128: {
+ struct rename_args *p = params;
+ uarg[0] = (intptr_t) p->from; /* const char * */
+ uarg[1] = (intptr_t) p->to; /* const char * */
+ *n_args = 2;
+ break;
+ }
+ /* flock */
+ case 131: {
+ struct flock_args *p = params;
+ iarg[0] = p->fd; /* int */
+ iarg[1] = p->how; /* int */
+ *n_args = 2;
+ break;
+ }
+ /* mkfifo */
+ case 132: {
+ struct mkfifo_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->mode; /* mode_t */
+ *n_args = 2;
+ break;
+ }
+ /* sendto */
+ case 133: {
+ struct sendto_args *p = params;
+ iarg[0] = p->s; /* int */
+ uarg[1] = (intptr_t) p->buf; /* const void * */
+ uarg[2] = p->len; /* size_t */
+ iarg[3] = p->flags; /* int */
+ uarg[4] = (intptr_t) p->to; /* const struct sockaddr * */
+ iarg[5] = p->tolen; /* int */
+ *n_args = 6;
+ break;
+ }
+ /* shutdown */
+ case 134: {
+ struct shutdown_args *p = params;
+ iarg[0] = p->s; /* int */
+ iarg[1] = p->how; /* int */
+ *n_args = 2;
+ break;
+ }
+ /* socketpair */
+ case 135: {
+ struct socketpair_args *p = params;
+ iarg[0] = p->domain; /* int */
+ iarg[1] = p->type; /* int */
+ iarg[2] = p->protocol; /* int */
+ uarg[3] = (intptr_t) p->rsv; /* int * */
+ *n_args = 4;
+ break;
+ }
+ /* mkdir */
+ case 136: {
+ struct mkdir_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->mode; /* mode_t */
+ *n_args = 2;
+ break;
+ }
+ /* rmdir */
+ case 137: {
+ struct rmdir_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ *n_args = 1;
+ break;
+ }
+ /* freebsd32_utimes */
+ case 138: {
+ struct freebsd32_utimes_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ uarg[1] = (intptr_t) p->tptr; /* struct timeval32 * */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_adjtime */
+ case 140: {
+ struct freebsd32_adjtime_args *p = params;
+ uarg[0] = (intptr_t) p->delta; /* struct timeval32 * */
+ uarg[1] = (intptr_t) p->olddelta; /* struct timeval32 * */
+ *n_args = 2;
+ break;
+ }
+ /* setsid */
+ case 147: {
+ *n_args = 0;
+ break;
+ }
+ /* quotactl */
+ case 148: {
+ struct quotactl_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->cmd; /* int */
+ iarg[2] = p->uid; /* int */
+ uarg[3] = (intptr_t) p->arg; /* void * */
+ *n_args = 4;
+ break;
+ }
+ /* getfh */
+ case 161: {
+ struct getfh_args *p = params;
+ uarg[0] = (intptr_t) p->fname; /* const char * */
+ uarg[1] = (intptr_t) p->fhp; /* struct fhandle * */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_sysarch */
+ case 165: {
+ struct freebsd32_sysarch_args *p = params;
+ iarg[0] = p->op; /* int */
+ uarg[1] = (intptr_t) p->parms; /* char * */
+ *n_args = 2;
+ break;
+ }
+ /* rtprio */
+ case 166: {
+ struct rtprio_args *p = params;
+ iarg[0] = p->function; /* int */
+ iarg[1] = p->pid; /* pid_t */
+ uarg[2] = (intptr_t) p->rtp; /* struct rtprio * */
+ *n_args = 3;
+ break;
+ }
+ /* freebsd32_semsys */
+ case 169: {
+ struct freebsd32_semsys_args *p = params;
+ iarg[0] = p->which; /* int */
+ iarg[1] = p->a2; /* int */
+ iarg[2] = p->a3; /* int */
+ iarg[3] = p->a4; /* int */
+ iarg[4] = p->a5; /* int */
+ *n_args = 5;
+ break;
+ }
+ /* freebsd32_msgsys */
+ case 170: {
+ struct freebsd32_msgsys_args *p = params;
+ iarg[0] = p->which; /* int */
+ iarg[1] = p->a2; /* int */
+ iarg[2] = p->a3; /* int */
+ iarg[3] = p->a4; /* int */
+ iarg[4] = p->a5; /* int */
+ iarg[5] = p->a6; /* int */
+ *n_args = 6;
+ break;
+ }
+ /* freebsd32_shmsys */
+ case 171: {
+ struct freebsd32_shmsys_args *p = params;
+ uarg[0] = p->which; /* uint32_t */
+ uarg[1] = p->a2; /* uint32_t */
+ uarg[2] = p->a3; /* uint32_t */
+ uarg[3] = p->a4; /* uint32_t */
+ *n_args = 4;
+ break;
+ }
+ /* freebsd32_ntp_adjtime */
+ case 176: {
+ struct freebsd32_ntp_adjtime_args *p = params;
+ uarg[0] = (intptr_t) p->tp; /* struct timex32 * */
+ *n_args = 1;
+ break;
+ }
+ /* setgid */
+ case 181: {
+ struct setgid_args *p = params;
+ iarg[0] = p->gid; /* gid_t */
+ *n_args = 1;
+ break;
+ }
+ /* setegid */
+ case 182: {
+ struct setegid_args *p = params;
+ iarg[0] = p->egid; /* gid_t */
+ *n_args = 1;
+ break;
+ }
+ /* seteuid */
+ case 183: {
+ struct seteuid_args *p = params;
+ uarg[0] = p->euid; /* uid_t */
+ *n_args = 1;
+ break;
+ }
+ /* pathconf */
+ case 191: {
+ struct pathconf_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->name; /* int */
+ *n_args = 2;
+ break;
+ }
+ /* fpathconf */
+ case 192: {
+ struct fpathconf_args *p = params;
+ iarg[0] = p->fd; /* int */
+ iarg[1] = p->name; /* int */
+ *n_args = 2;
+ break;
+ }
+ /* getrlimit */
+ case 194: {
+ struct __getrlimit_args *p = params;
+ uarg[0] = p->which; /* u_int */
+ uarg[1] = (intptr_t) p->rlp; /* struct rlimit * */
+ *n_args = 2;
+ break;
+ }
+ /* setrlimit */
+ case 195: {
+ struct __setrlimit_args *p = params;
+ uarg[0] = p->which; /* u_int */
+ uarg[1] = (intptr_t) p->rlp; /* struct rlimit * */
+ *n_args = 2;
+ break;
+ }
+ /* nosys */
+ case 198: {
+ *n_args = 0;
+ break;
+ }
+ /* freebsd32___sysctl */
+ case 202: {
+ struct freebsd32___sysctl_args *p = params;
+ uarg[0] = (intptr_t) p->name; /* int * */
+ uarg[1] = p->namelen; /* u_int */
+ uarg[2] = (intptr_t) p->old; /* void * */
+ uarg[3] = (intptr_t) p->oldlenp; /* uint32_t * */
+ uarg[4] = (intptr_t) p->new; /* const void * */
+ uarg[5] = p->newlen; /* uint32_t */
+ *n_args = 6;
+ break;
+ }
+ /* mlock */
+ case 203: {
+ struct mlock_args *p = params;
+ uarg[0] = (intptr_t) p->addr; /* const void * */
+ uarg[1] = p->len; /* size_t */
+ *n_args = 2;
+ break;
+ }
+ /* munlock */
+ case 204: {
+ struct munlock_args *p = params;
+ uarg[0] = (intptr_t) p->addr; /* const void * */
+ uarg[1] = p->len; /* size_t */
+ *n_args = 2;
+ break;
+ }
+ /* undelete */
+ case 205: {
+ struct undelete_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ *n_args = 1;
+ break;
+ }
+ /* freebsd32_futimes */
+ case 206: {
+ struct freebsd32_futimes_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->tptr; /* struct timeval32 * */
+ *n_args = 2;
+ break;
+ }
+ /* getpgid */
+ case 207: {
+ struct getpgid_args *p = params;
+ iarg[0] = p->pid; /* pid_t */
+ *n_args = 1;
+ break;
+ }
+ /* poll */
+ case 209: {
+ struct poll_args *p = params;
+ uarg[0] = (intptr_t) p->fds; /* struct pollfd * */
+ uarg[1] = p->nfds; /* u_int */
+ iarg[2] = p->timeout; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* lkmnosys */
+ case 210: {
+ *n_args = 0;
+ break;
+ }
+ /* lkmnosys */
+ case 211: {
+ *n_args = 0;
+ break;
+ }
+ /* lkmnosys */
+ case 212: {
+ *n_args = 0;
+ break;
+ }
+ /* lkmnosys */
+ case 213: {
+ *n_args = 0;
+ break;
+ }
+ /* lkmnosys */
+ case 214: {
+ *n_args = 0;
+ break;
+ }
+ /* lkmnosys */
+ case 215: {
+ *n_args = 0;
+ break;
+ }
+ /* lkmnosys */
+ case 216: {
+ *n_args = 0;
+ break;
+ }
+ /* lkmnosys */
+ case 217: {
+ *n_args = 0;
+ break;
+ }
+ /* lkmnosys */
+ case 218: {
+ *n_args = 0;
+ break;
+ }
+ /* lkmnosys */
+ case 219: {
+ *n_args = 0;
+ break;
+ }
+ /* semget */
+ case 221: {
+ struct semget_args *p = params;
+ iarg[0] = p->key; /* key_t */
+ iarg[1] = p->nsems; /* int */
+ iarg[2] = p->semflg; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* semop */
+ case 222: {
+ struct semop_args *p = params;
+ iarg[0] = p->semid; /* int */
+ uarg[1] = (intptr_t) p->sops; /* struct sembuf * */
+ uarg[2] = p->nsops; /* u_int */
+ *n_args = 3;
+ break;
+ }
+ /* msgget */
+ case 225: {
+ struct msgget_args *p = params;
+ iarg[0] = p->key; /* key_t */
+ iarg[1] = p->msgflg; /* int */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_msgsnd */
+ case 226: {
+ struct freebsd32_msgsnd_args *p = params;
+ iarg[0] = p->msqid; /* int */
+ uarg[1] = (intptr_t) p->msgp; /* void * */
+ uarg[2] = p->msgsz; /* size_t */
+ iarg[3] = p->msgflg; /* int */
+ *n_args = 4;
+ break;
+ }
+ /* freebsd32_msgrcv */
+ case 227: {
+ struct freebsd32_msgrcv_args *p = params;
+ iarg[0] = p->msqid; /* int */
+ uarg[1] = (intptr_t) p->msgp; /* void * */
+ uarg[2] = p->msgsz; /* size_t */
+ iarg[3] = p->msgtyp; /* long */
+ iarg[4] = p->msgflg; /* int */
+ *n_args = 5;
+ break;
+ }
+ /* shmat */
+ case 228: {
+ struct shmat_args *p = params;
+ iarg[0] = p->shmid; /* int */
+ uarg[1] = (intptr_t) p->shmaddr; /* void * */
+ iarg[2] = p->shmflg; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* shmdt */
+ case 230: {
+ struct shmdt_args *p = params;
+ uarg[0] = (intptr_t) p->shmaddr; /* void * */
+ *n_args = 1;
+ break;
+ }
+ /* shmget */
+ case 231: {
+ struct shmget_args *p = params;
+ iarg[0] = p->key; /* key_t */
+ iarg[1] = p->size; /* int */
+ iarg[2] = p->shmflg; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* freebsd32_clock_gettime */
+ case 232: {
+ struct freebsd32_clock_gettime_args *p = params;
+ iarg[0] = p->clock_id; /* clockid_t */
+ uarg[1] = (intptr_t) p->tp; /* struct timespec32 * */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_clock_settime */
+ case 233: {
+ struct freebsd32_clock_settime_args *p = params;
+ iarg[0] = p->clock_id; /* clockid_t */
+ uarg[1] = (intptr_t) p->tp; /* const struct timespec32 * */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_clock_getres */
+ case 234: {
+ struct freebsd32_clock_getres_args *p = params;
+ iarg[0] = p->clock_id; /* clockid_t */
+ uarg[1] = (intptr_t) p->tp; /* struct timespec32 * */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_ktimer_create */
+ case 235: {
+ struct freebsd32_ktimer_create_args *p = params;
+ iarg[0] = p->clock_id; /* clockid_t */
+ uarg[1] = (intptr_t) p->evp; /* struct sigevent32 * */
+ uarg[2] = (intptr_t) p->timerid; /* int * */
+ *n_args = 3;
+ break;
+ }
+ /* ktimer_delete */
+ case 236: {
+ struct ktimer_delete_args *p = params;
+ iarg[0] = p->timerid; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* freebsd32_ktimer_settime */
+ case 237: {
+ struct freebsd32_ktimer_settime_args *p = params;
+ iarg[0] = p->timerid; /* int */
+ iarg[1] = p->flags; /* int */
+ uarg[2] = (intptr_t) p->value; /* const struct itimerspec32 * */
+ uarg[3] = (intptr_t) p->ovalue; /* struct itimerspec32 * */
+ *n_args = 4;
+ break;
+ }
+ /* freebsd32_ktimer_gettime */
+ case 238: {
+ struct freebsd32_ktimer_gettime_args *p = params;
+ iarg[0] = p->timerid; /* int */
+ uarg[1] = (intptr_t) p->value; /* struct itimerspec32 * */
+ *n_args = 2;
+ break;
+ }
+ /* ktimer_getoverrun */
+ case 239: {
+ struct ktimer_getoverrun_args *p = params;
+ iarg[0] = p->timerid; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* freebsd32_nanosleep */
+ case 240: {
+ struct freebsd32_nanosleep_args *p = params;
+ uarg[0] = (intptr_t) p->rqtp; /* const struct timespec32 * */
+ uarg[1] = (intptr_t) p->rmtp; /* struct timespec32 * */
+ *n_args = 2;
+ break;
+ }
+ /* ffclock_getcounter */
+ case 241: {
+ struct ffclock_getcounter_args *p = params;
+ uarg[0] = (intptr_t) p->ffcount; /* ffcounter * */
+ *n_args = 1;
+ break;
+ }
+ /* ffclock_setestimate */
+ case 242: {
+ struct ffclock_setestimate_args *p = params;
+ uarg[0] = (intptr_t) p->cest; /* struct ffclock_estimate * */
+ *n_args = 1;
+ break;
+ }
+ /* ffclock_getestimate */
+ case 243: {
+ struct ffclock_getestimate_args *p = params;
+ uarg[0] = (intptr_t) p->cest; /* struct ffclock_estimate * */
+ *n_args = 1;
+ break;
+ }
+ /* freebsd32_clock_nanosleep */
+ case 244: {
+ struct freebsd32_clock_nanosleep_args *p = params;
+ iarg[0] = p->clock_id; /* clockid_t */
+ iarg[1] = p->flags; /* int */
+ uarg[2] = (intptr_t) p->rqtp; /* const struct timespec32 * */
+ uarg[3] = (intptr_t) p->rmtp; /* struct timespec32 * */
+ *n_args = 4;
+ break;
+ }
+ /* freebsd32_clock_getcpuclockid2 */
+ case 247: {
+ struct freebsd32_clock_getcpuclockid2_args *p = params;
+ uarg[0] = p->id1; /* uint32_t */
+ uarg[1] = p->id2; /* uint32_t */
+ iarg[2] = p->which; /* int */
+ uarg[3] = (intptr_t) p->clock_id; /* clockid_t * */
+ *n_args = 4;
+ break;
+ }
+ /* minherit */
+ case 250: {
+ struct minherit_args *p = params;
+ uarg[0] = (intptr_t) p->addr; /* void * */
+ uarg[1] = p->len; /* size_t */
+ iarg[2] = p->inherit; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* rfork */
+ case 251: {
+ struct rfork_args *p = params;
+ iarg[0] = p->flags; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* issetugid */
+ case 253: {
+ *n_args = 0;
+ break;
+ }
+ /* lchown */
+ case 254: {
+ struct lchown_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->uid; /* int */
+ iarg[2] = p->gid; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* freebsd32_aio_read */
+ case 255: {
+ struct freebsd32_aio_read_args *p = params;
+ uarg[0] = (intptr_t) p->aiocbp; /* struct aiocb32 * */
+ *n_args = 1;
+ break;
+ }
+ /* freebsd32_aio_write */
+ case 256: {
+ struct freebsd32_aio_write_args *p = params;
+ uarg[0] = (intptr_t) p->aiocbp; /* struct aiocb32 * */
+ *n_args = 1;
+ break;
+ }
+ /* freebsd32_lio_listio */
+ case 257: {
+ struct freebsd32_lio_listio_args *p = params;
+ iarg[0] = p->mode; /* int */
+ uarg[1] = (intptr_t) p->acb_list; /* struct aiocb32 * const * */
+ iarg[2] = p->nent; /* int */
+ uarg[3] = (intptr_t) p->sig; /* struct sigevent32 * */
+ *n_args = 4;
+ break;
+ }
+ /* lchmod */
+ case 274: {
+ struct lchmod_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->mode; /* mode_t */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_lutimes */
+ case 276: {
+ struct freebsd32_lutimes_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ uarg[1] = (intptr_t) p->tptr; /* struct timeval32 * */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_preadv */
+ case 289: {
+ struct freebsd32_preadv_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->iovp; /* struct iovec32 * */
+ uarg[2] = p->iovcnt; /* u_int */
+ uarg[3] = p->offset1; /* uint32_t */
+ uarg[4] = p->offset2; /* uint32_t */
+ *n_args = 5;
+ break;
+ }
+ /* freebsd32_pwritev */
+ case 290: {
+ struct freebsd32_pwritev_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->iovp; /* struct iovec32 * */
+ uarg[2] = p->iovcnt; /* u_int */
+ uarg[3] = p->offset1; /* uint32_t */
+ uarg[4] = p->offset2; /* uint32_t */
+ *n_args = 5;
+ break;
+ }
+ /* fhopen */
+ case 298: {
+ struct fhopen_args *p = params;
+ uarg[0] = (intptr_t) p->u_fhp; /* const struct fhandle * */
+ iarg[1] = p->flags; /* int */
+ *n_args = 2;
+ break;
+ }
+ /* modnext */
+ case 300: {
+ struct modnext_args *p = params;
+ iarg[0] = p->modid; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* freebsd32_modstat */
+ case 301: {
+ struct freebsd32_modstat_args *p = params;
+ iarg[0] = p->modid; /* int */
+ uarg[1] = (intptr_t) p->stat; /* struct module_stat32 * */
+ *n_args = 2;
+ break;
+ }
+ /* modfnext */
+ case 302: {
+ struct modfnext_args *p = params;
+ iarg[0] = p->modid; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* modfind */
+ case 303: {
+ struct modfind_args *p = params;
+ uarg[0] = (intptr_t) p->name; /* const char * */
+ *n_args = 1;
+ break;
+ }
+ /* kldload */
+ case 304: {
+ struct kldload_args *p = params;
+ uarg[0] = (intptr_t) p->file; /* const char * */
+ *n_args = 1;
+ break;
+ }
+ /* kldunload */
+ case 305: {
+ struct kldunload_args *p = params;
+ iarg[0] = p->fileid; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* kldfind */
+ case 306: {
+ struct kldfind_args *p = params;
+ uarg[0] = (intptr_t) p->file; /* const char * */
+ *n_args = 1;
+ break;
+ }
+ /* kldnext */
+ case 307: {
+ struct kldnext_args *p = params;
+ iarg[0] = p->fileid; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* freebsd32_kldstat */
+ case 308: {
+ struct freebsd32_kldstat_args *p = params;
+ iarg[0] = p->fileid; /* int */
+ uarg[1] = (intptr_t) p->stat; /* struct kld32_file_stat * */
+ *n_args = 2;
+ break;
+ }
+ /* kldfirstmod */
+ case 309: {
+ struct kldfirstmod_args *p = params;
+ iarg[0] = p->fileid; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* getsid */
+ case 310: {
+ struct getsid_args *p = params;
+ iarg[0] = p->pid; /* pid_t */
+ *n_args = 1;
+ break;
+ }
+ /* setresuid */
+ case 311: {
+ struct setresuid_args *p = params;
+ uarg[0] = p->ruid; /* uid_t */
+ uarg[1] = p->euid; /* uid_t */
+ uarg[2] = p->suid; /* uid_t */
+ *n_args = 3;
+ break;
+ }
+ /* setresgid */
+ case 312: {
+ struct setresgid_args *p = params;
+ iarg[0] = p->rgid; /* gid_t */
+ iarg[1] = p->egid; /* gid_t */
+ iarg[2] = p->sgid; /* gid_t */
+ *n_args = 3;
+ break;
+ }
+ /* freebsd32_aio_return */
+ case 314: {
+ struct freebsd32_aio_return_args *p = params;
+ uarg[0] = (intptr_t) p->aiocbp; /* struct aiocb32 * */
+ *n_args = 1;
+ break;
+ }
+ /* freebsd32_aio_suspend */
+ case 315: {
+ struct freebsd32_aio_suspend_args *p = params;
+ uarg[0] = (intptr_t) p->aiocbp; /* struct aiocb32 * const * */
+ iarg[1] = p->nent; /* int */
+ uarg[2] = (intptr_t) p->timeout; /* const struct timespec32 * */
+ *n_args = 3;
+ break;
+ }
+ /* aio_cancel */
+ case 316: {
+ struct aio_cancel_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->aiocbp; /* struct aiocb * */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_aio_error */
+ case 317: {
+ struct freebsd32_aio_error_args *p = params;
+ uarg[0] = (intptr_t) p->aiocbp; /* struct aiocb32 * */
+ *n_args = 1;
+ break;
+ }
+ /* yield */
+ case 321: {
+ *n_args = 0;
+ break;
+ }
+ /* mlockall */
+ case 324: {
+ struct mlockall_args *p = params;
+ iarg[0] = p->how; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* munlockall */
+ case 325: {
+ *n_args = 0;
+ break;
+ }
+ /* __getcwd */
+ case 326: {
+ struct __getcwd_args *p = params;
+ uarg[0] = (intptr_t) p->buf; /* char * */
+ uarg[1] = p->buflen; /* size_t */
+ *n_args = 2;
+ break;
+ }
+ /* sched_setparam */
+ case 327: {
+ struct sched_setparam_args *p = params;
+ iarg[0] = p->pid; /* pid_t */
+ uarg[1] = (intptr_t) p->param; /* const struct sched_param * */
+ *n_args = 2;
+ break;
+ }
+ /* sched_getparam */
+ case 328: {
+ struct sched_getparam_args *p = params;
+ iarg[0] = p->pid; /* pid_t */
+ uarg[1] = (intptr_t) p->param; /* struct sched_param * */
+ *n_args = 2;
+ break;
+ }
+ /* sched_setscheduler */
+ case 329: {
+ struct sched_setscheduler_args *p = params;
+ iarg[0] = p->pid; /* pid_t */
+ iarg[1] = p->policy; /* int */
+ uarg[2] = (intptr_t) p->param; /* const struct sched_param * */
+ *n_args = 3;
+ break;
+ }
+ /* sched_getscheduler */
+ case 330: {
+ struct sched_getscheduler_args *p = params;
+ iarg[0] = p->pid; /* pid_t */
+ *n_args = 1;
+ break;
+ }
+ /* sched_yield */
+ case 331: {
+ *n_args = 0;
+ break;
+ }
+ /* sched_get_priority_max */
+ case 332: {
+ struct sched_get_priority_max_args *p = params;
+ iarg[0] = p->policy; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* sched_get_priority_min */
+ case 333: {
+ struct sched_get_priority_min_args *p = params;
+ iarg[0] = p->policy; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* freebsd32_sched_rr_get_interval */
+ case 334: {
+ struct freebsd32_sched_rr_get_interval_args *p = params;
+ iarg[0] = p->pid; /* pid_t */
+ uarg[1] = (intptr_t) p->interval; /* struct timespec32 * */
+ *n_args = 2;
+ break;
+ }
+ /* utrace */
+ case 335: {
+ struct utrace_args *p = params;
+ uarg[0] = (intptr_t) p->addr; /* const void * */
+ uarg[1] = p->len; /* size_t */
+ *n_args = 2;
+ break;
+ }
+ /* kldsym */
+ case 337: {
+ struct kldsym_args *p = params;
+ iarg[0] = p->fileid; /* int */
+ iarg[1] = p->cmd; /* int */
+ uarg[2] = (intptr_t) p->data; /* void * */
+ *n_args = 3;
+ break;
+ }
+ /* freebsd32_jail */
+ case 338: {
+ struct freebsd32_jail_args *p = params;
+ uarg[0] = (intptr_t) p->jail; /* struct jail32 * */
+ *n_args = 1;
+ break;
+ }
+ /* sigprocmask */
+ case 340: {
+ struct sigprocmask_args *p = params;
+ iarg[0] = p->how; /* int */
+ uarg[1] = (intptr_t) p->set; /* const sigset_t * */
+ uarg[2] = (intptr_t) p->oset; /* sigset_t * */
+ *n_args = 3;
+ break;
+ }
+ /* sigsuspend */
+ case 341: {
+ struct sigsuspend_args *p = params;
+ uarg[0] = (intptr_t) p->sigmask; /* const sigset_t * */
+ *n_args = 1;
+ break;
+ }
+ /* sigpending */
+ case 343: {
+ struct sigpending_args *p = params;
+ uarg[0] = (intptr_t) p->set; /* sigset_t * */
+ *n_args = 1;
+ break;
+ }
+ /* freebsd32_sigtimedwait */
+ case 345: {
+ struct freebsd32_sigtimedwait_args *p = params;
+ uarg[0] = (intptr_t) p->set; /* const sigset_t * */
+ uarg[1] = (intptr_t) p->info; /* siginfo_t * */
+ uarg[2] = (intptr_t) p->timeout; /* const struct timespec * */
+ *n_args = 3;
+ break;
+ }
+ /* freebsd32_sigwaitinfo */
+ case 346: {
+ struct freebsd32_sigwaitinfo_args *p = params;
+ uarg[0] = (intptr_t) p->set; /* const sigset_t * */
+ uarg[1] = (intptr_t) p->info; /* siginfo_t * */
+ *n_args = 2;
+ break;
+ }
+ /* __acl_get_file */
+ case 347: {
+ struct __acl_get_file_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->type; /* acl_type_t */
+ uarg[2] = (intptr_t) p->aclp; /* struct acl * */
+ *n_args = 3;
+ break;
+ }
+ /* __acl_set_file */
+ case 348: {
+ struct __acl_set_file_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->type; /* acl_type_t */
+ uarg[2] = (intptr_t) p->aclp; /* struct acl * */
+ *n_args = 3;
+ break;
+ }
+ /* __acl_get_fd */
+ case 349: {
+ struct __acl_get_fd_args *p = params;
+ iarg[0] = p->filedes; /* int */
+ iarg[1] = p->type; /* acl_type_t */
+ uarg[2] = (intptr_t) p->aclp; /* struct acl * */
+ *n_args = 3;
+ break;
+ }
+ /* __acl_set_fd */
+ case 350: {
+ struct __acl_set_fd_args *p = params;
+ iarg[0] = p->filedes; /* int */
+ iarg[1] = p->type; /* acl_type_t */
+ uarg[2] = (intptr_t) p->aclp; /* struct acl * */
+ *n_args = 3;
+ break;
+ }
+ /* __acl_delete_file */
+ case 351: {
+ struct __acl_delete_file_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->type; /* acl_type_t */
+ *n_args = 2;
+ break;
+ }
+ /* __acl_delete_fd */
+ case 352: {
+ struct __acl_delete_fd_args *p = params;
+ iarg[0] = p->filedes; /* int */
+ iarg[1] = p->type; /* acl_type_t */
+ *n_args = 2;
+ break;
+ }
+ /* __acl_aclcheck_file */
+ case 353: {
+ struct __acl_aclcheck_file_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->type; /* acl_type_t */
+ uarg[2] = (intptr_t) p->aclp; /* struct acl * */
+ *n_args = 3;
+ break;
+ }
+ /* __acl_aclcheck_fd */
+ case 354: {
+ struct __acl_aclcheck_fd_args *p = params;
+ iarg[0] = p->filedes; /* int */
+ iarg[1] = p->type; /* acl_type_t */
+ uarg[2] = (intptr_t) p->aclp; /* struct acl * */
+ *n_args = 3;
+ break;
+ }
+ /* extattrctl */
+ case 355: {
+ struct extattrctl_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->cmd; /* int */
+ uarg[2] = (intptr_t) p->filename; /* const char * */
+ iarg[3] = p->attrnamespace; /* int */
+ uarg[4] = (intptr_t) p->attrname; /* const char * */
+ *n_args = 5;
+ break;
+ }
+ /* extattr_set_file */
+ case 356: {
+ struct extattr_set_file_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->attrnamespace; /* int */
+ uarg[2] = (intptr_t) p->attrname; /* const char * */
+ uarg[3] = (intptr_t) p->data; /* void * */
+ uarg[4] = p->nbytes; /* size_t */
+ *n_args = 5;
+ break;
+ }
+ /* extattr_get_file */
+ case 357: {
+ struct extattr_get_file_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->attrnamespace; /* int */
+ uarg[2] = (intptr_t) p->attrname; /* const char * */
+ uarg[3] = (intptr_t) p->data; /* void * */
+ uarg[4] = p->nbytes; /* size_t */
+ *n_args = 5;
+ break;
+ }
+ /* extattr_delete_file */
+ case 358: {
+ struct extattr_delete_file_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->attrnamespace; /* int */
+ uarg[2] = (intptr_t) p->attrname; /* const char * */
+ *n_args = 3;
+ break;
+ }
+ /* freebsd32_aio_waitcomplete */
+ case 359: {
+ struct freebsd32_aio_waitcomplete_args *p = params;
+ uarg[0] = (intptr_t) p->aiocbp; /* struct aiocb32 ** */
+ uarg[1] = (intptr_t) p->timeout; /* struct timespec32 * */
+ *n_args = 2;
+ break;
+ }
+ /* getresuid */
+ case 360: {
+ struct getresuid_args *p = params;
+ uarg[0] = (intptr_t) p->ruid; /* uid_t * */
+ uarg[1] = (intptr_t) p->euid; /* uid_t * */
+ uarg[2] = (intptr_t) p->suid; /* uid_t * */
+ *n_args = 3;
+ break;
+ }
+ /* getresgid */
+ case 361: {
+ struct getresgid_args *p = params;
+ uarg[0] = (intptr_t) p->rgid; /* gid_t * */
+ uarg[1] = (intptr_t) p->egid; /* gid_t * */
+ uarg[2] = (intptr_t) p->sgid; /* gid_t * */
+ *n_args = 3;
+ break;
+ }
+ /* kqueue */
+ case 362: {
+ *n_args = 0;
+ break;
+ }
+ /* extattr_set_fd */
+ case 371: {
+ struct extattr_set_fd_args *p = params;
+ iarg[0] = p->fd; /* int */
+ iarg[1] = p->attrnamespace; /* int */
+ uarg[2] = (intptr_t) p->attrname; /* const char * */
+ uarg[3] = (intptr_t) p->data; /* void * */
+ uarg[4] = p->nbytes; /* size_t */
+ *n_args = 5;
+ break;
+ }
+ /* extattr_get_fd */
+ case 372: {
+ struct extattr_get_fd_args *p = params;
+ iarg[0] = p->fd; /* int */
+ iarg[1] = p->attrnamespace; /* int */
+ uarg[2] = (intptr_t) p->attrname; /* const char * */
+ uarg[3] = (intptr_t) p->data; /* void * */
+ uarg[4] = p->nbytes; /* size_t */
+ *n_args = 5;
+ break;
+ }
+ /* extattr_delete_fd */
+ case 373: {
+ struct extattr_delete_fd_args *p = params;
+ iarg[0] = p->fd; /* int */
+ iarg[1] = p->attrnamespace; /* int */
+ uarg[2] = (intptr_t) p->attrname; /* const char * */
+ *n_args = 3;
+ break;
+ }
+ /* __setugid */
+ case 374: {
+ struct __setugid_args *p = params;
+ iarg[0] = p->flag; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* eaccess */
+ case 376: {
+ struct eaccess_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->amode; /* int */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_nmount */
+ case 378: {
+ struct freebsd32_nmount_args *p = params;
+ uarg[0] = (intptr_t) p->iovp; /* struct iovec32 * */
+ uarg[1] = p->iovcnt; /* unsigned int */
+ iarg[2] = p->flags; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* kenv */
+ case 390: {
+ struct kenv_args *p = params;
+ iarg[0] = p->what; /* int */
+ uarg[1] = (intptr_t) p->name; /* const char * */
+ uarg[2] = (intptr_t) p->value; /* char * */
+ iarg[3] = p->len; /* int */
+ *n_args = 4;
+ break;
+ }
+ /* lchflags */
+ case 391: {
+ struct lchflags_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ uarg[1] = p->flags; /* u_long */
+ *n_args = 2;
+ break;
+ }
+ /* uuidgen */
+ case 392: {
+ struct uuidgen_args *p = params;
+ uarg[0] = (intptr_t) p->store; /* struct uuid * */
+ iarg[1] = p->count; /* int */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_sendfile */
+ case 393: {
+ struct freebsd32_sendfile_args *p = params;
+ iarg[0] = p->fd; /* int */
+ iarg[1] = p->s; /* int */
+ uarg[2] = p->offset1; /* uint32_t */
+ uarg[3] = p->offset2; /* uint32_t */
+ uarg[4] = p->nbytes; /* size_t */
+ uarg[5] = (intptr_t) p->hdtr; /* struct sf_hdtr32 * */
+ uarg[6] = (intptr_t) p->sbytes; /* off_t * */
+ iarg[7] = p->flags; /* int */
+ *n_args = 8;
+ break;
+ }
+ /* ksem_close */
+ case 400: {
+ struct ksem_close_args *p = params;
+ iarg[0] = p->id; /* semid_t */
+ *n_args = 1;
+ break;
+ }
+ /* ksem_post */
+ case 401: {
+ struct ksem_post_args *p = params;
+ iarg[0] = p->id; /* semid_t */
+ *n_args = 1;
+ break;
+ }
+ /* ksem_wait */
+ case 402: {
+ struct ksem_wait_args *p = params;
+ iarg[0] = p->id; /* semid_t */
+ *n_args = 1;
+ break;
+ }
+ /* ksem_trywait */
+ case 403: {
+ struct ksem_trywait_args *p = params;
+ iarg[0] = p->id; /* semid_t */
+ *n_args = 1;
+ break;
+ }
+ /* freebsd32_ksem_init */
+ case 404: {
+ struct freebsd32_ksem_init_args *p = params;
+ uarg[0] = (intptr_t) p->idp; /* semid_t * */
+ uarg[1] = p->value; /* unsigned int */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_ksem_open */
+ case 405: {
+ struct freebsd32_ksem_open_args *p = params;
+ uarg[0] = (intptr_t) p->idp; /* semid_t * */
+ uarg[1] = (intptr_t) p->name; /* const char * */
+ iarg[2] = p->oflag; /* int */
+ iarg[3] = p->mode; /* mode_t */
+ uarg[4] = p->value; /* unsigned int */
+ *n_args = 5;
+ break;
+ }
+ /* ksem_unlink */
+ case 406: {
+ struct ksem_unlink_args *p = params;
+ uarg[0] = (intptr_t) p->name; /* const char * */
+ *n_args = 1;
+ break;
+ }
+ /* ksem_getvalue */
+ case 407: {
+ struct ksem_getvalue_args *p = params;
+ iarg[0] = p->id; /* semid_t */
+ uarg[1] = (intptr_t) p->val; /* int * */
+ *n_args = 2;
+ break;
+ }
+ /* ksem_destroy */
+ case 408: {
+ struct ksem_destroy_args *p = params;
+ iarg[0] = p->id; /* semid_t */
+ *n_args = 1;
+ break;
+ }
+ /* extattr_set_link */
+ case 412: {
+ struct extattr_set_link_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->attrnamespace; /* int */
+ uarg[2] = (intptr_t) p->attrname; /* const char * */
+ uarg[3] = (intptr_t) p->data; /* void * */
+ uarg[4] = p->nbytes; /* size_t */
+ *n_args = 5;
+ break;
+ }
+ /* extattr_get_link */
+ case 413: {
+ struct extattr_get_link_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->attrnamespace; /* int */
+ uarg[2] = (intptr_t) p->attrname; /* const char * */
+ uarg[3] = (intptr_t) p->data; /* void * */
+ uarg[4] = p->nbytes; /* size_t */
+ *n_args = 5;
+ break;
+ }
+ /* extattr_delete_link */
+ case 414: {
+ struct extattr_delete_link_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->attrnamespace; /* int */
+ uarg[2] = (intptr_t) p->attrname; /* const char * */
+ *n_args = 3;
+ break;
+ }
+ /* freebsd32_sigaction */
+ case 416: {
+ struct freebsd32_sigaction_args *p = params;
+ iarg[0] = p->sig; /* int */
+ uarg[1] = (intptr_t) p->act; /* struct sigaction32 * */
+ uarg[2] = (intptr_t) p->oact; /* struct sigaction32 * */
+ *n_args = 3;
+ break;
+ }
+ /* freebsd32_sigreturn */
+ case 417: {
+ struct freebsd32_sigreturn_args *p = params;
+ uarg[0] = (intptr_t) p->sigcntxp; /* const struct freebsd32_ucontext * */
+ *n_args = 1;
+ break;
+ }
+ /* freebsd32_getcontext */
+ case 421: {
+ struct freebsd32_getcontext_args *p = params;
+ uarg[0] = (intptr_t) p->ucp; /* struct freebsd32_ucontext * */
+ *n_args = 1;
+ break;
+ }
+ /* freebsd32_setcontext */
+ case 422: {
+ struct freebsd32_setcontext_args *p = params;
+ uarg[0] = (intptr_t) p->ucp; /* const struct freebsd32_ucontext * */
+ *n_args = 1;
+ break;
+ }
+ /* freebsd32_swapcontext */
+ case 423: {
+ struct freebsd32_swapcontext_args *p = params;
+ uarg[0] = (intptr_t) p->oucp; /* struct freebsd32_ucontext * */
+ uarg[1] = (intptr_t) p->ucp; /* const struct freebsd32_ucontext * */
+ *n_args = 2;
+ break;
+ }
+ /* __acl_get_link */
+ case 425: {
+ struct __acl_get_link_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->type; /* acl_type_t */
+ uarg[2] = (intptr_t) p->aclp; /* struct acl * */
+ *n_args = 3;
+ break;
+ }
+ /* __acl_set_link */
+ case 426: {
+ struct __acl_set_link_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->type; /* acl_type_t */
+ uarg[2] = (intptr_t) p->aclp; /* struct acl * */
+ *n_args = 3;
+ break;
+ }
+ /* __acl_delete_link */
+ case 427: {
+ struct __acl_delete_link_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->type; /* acl_type_t */
+ *n_args = 2;
+ break;
+ }
+ /* __acl_aclcheck_link */
+ case 428: {
+ struct __acl_aclcheck_link_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->type; /* acl_type_t */
+ uarg[2] = (intptr_t) p->aclp; /* struct acl * */
+ *n_args = 3;
+ break;
+ }
+ /* sigwait */
+ case 429: {
+ struct sigwait_args *p = params;
+ uarg[0] = (intptr_t) p->set; /* const sigset_t * */
+ uarg[1] = (intptr_t) p->sig; /* int * */
+ *n_args = 2;
+ break;
+ }
+ /* thr_exit */
+ case 431: {
+ struct thr_exit_args *p = params;
+ uarg[0] = (intptr_t) p->state; /* long * */
+ *n_args = 1;
+ break;
+ }
+ /* thr_self */
+ case 432: {
+ struct thr_self_args *p = params;
+ uarg[0] = (intptr_t) p->id; /* long * */
+ *n_args = 1;
+ break;
+ }
+ /* thr_kill */
+ case 433: {
+ struct thr_kill_args *p = params;
+ iarg[0] = p->id; /* long */
+ iarg[1] = p->sig; /* int */
+ *n_args = 2;
+ break;
+ }
+ /* jail_attach */
+ case 436: {
+ struct jail_attach_args *p = params;
+ iarg[0] = p->jid; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* extattr_list_fd */
+ case 437: {
+ struct extattr_list_fd_args *p = params;
+ iarg[0] = p->fd; /* int */
+ iarg[1] = p->attrnamespace; /* int */
+ uarg[2] = (intptr_t) p->data; /* void * */
+ uarg[3] = p->nbytes; /* size_t */
+ *n_args = 4;
+ break;
+ }
+ /* extattr_list_file */
+ case 438: {
+ struct extattr_list_file_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->attrnamespace; /* int */
+ uarg[2] = (intptr_t) p->data; /* void * */
+ uarg[3] = p->nbytes; /* size_t */
+ *n_args = 4;
+ break;
+ }
+ /* extattr_list_link */
+ case 439: {
+ struct extattr_list_link_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->attrnamespace; /* int */
+ uarg[2] = (intptr_t) p->data; /* void * */
+ uarg[3] = p->nbytes; /* size_t */
+ *n_args = 4;
+ break;
+ }
+ /* freebsd32_ksem_timedwait */
+ case 441: {
+ struct freebsd32_ksem_timedwait_args *p = params;
+ iarg[0] = p->id; /* semid_t */
+ uarg[1] = (intptr_t) p->abstime; /* const struct timespec32 * */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_thr_suspend */
+ case 442: {
+ struct freebsd32_thr_suspend_args *p = params;
+ uarg[0] = (intptr_t) p->timeout; /* const struct timespec32 * */
+ *n_args = 1;
+ break;
+ }
+ /* thr_wake */
+ case 443: {
+ struct thr_wake_args *p = params;
+ iarg[0] = p->id; /* long */
+ *n_args = 1;
+ break;
+ }
+ /* kldunloadf */
+ case 444: {
+ struct kldunloadf_args *p = params;
+ iarg[0] = p->fileid; /* int */
+ iarg[1] = p->flags; /* int */
+ *n_args = 2;
+ break;
+ }
+ /* audit */
+ case 445: {
+ struct audit_args *p = params;
+ uarg[0] = (intptr_t) p->record; /* const void * */
+ uarg[1] = p->length; /* u_int */
+ *n_args = 2;
+ break;
+ }
+ /* auditon */
+ case 446: {
+ struct auditon_args *p = params;
+ iarg[0] = p->cmd; /* int */
+ uarg[1] = (intptr_t) p->data; /* void * */
+ uarg[2] = p->length; /* u_int */
+ *n_args = 3;
+ break;
+ }
+ /* getauid */
+ case 447: {
+ struct getauid_args *p = params;
+ uarg[0] = (intptr_t) p->auid; /* uid_t * */
+ *n_args = 1;
+ break;
+ }
+ /* setauid */
+ case 448: {
+ struct setauid_args *p = params;
+ uarg[0] = (intptr_t) p->auid; /* uid_t * */
+ *n_args = 1;
+ break;
+ }
+ /* getaudit */
+ case 449: {
+ struct getaudit_args *p = params;
+ uarg[0] = (intptr_t) p->auditinfo; /* struct auditinfo * */
+ *n_args = 1;
+ break;
+ }
+ /* setaudit */
+ case 450: {
+ struct setaudit_args *p = params;
+ uarg[0] = (intptr_t) p->auditinfo; /* struct auditinfo * */
+ *n_args = 1;
+ break;
+ }
+ /* getaudit_addr */
+ case 451: {
+ struct getaudit_addr_args *p = params;
+ uarg[0] = (intptr_t) p->auditinfo_addr; /* struct auditinfo_addr * */
+ uarg[1] = p->length; /* u_int */
+ *n_args = 2;
+ break;
+ }
+ /* setaudit_addr */
+ case 452: {
+ struct setaudit_addr_args *p = params;
+ uarg[0] = (intptr_t) p->auditinfo_addr; /* struct auditinfo_addr * */
+ uarg[1] = p->length; /* u_int */
+ *n_args = 2;
+ break;
+ }
+ /* auditctl */
+ case 453: {
+ struct auditctl_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ *n_args = 1;
+ break;
+ }
+ /* freebsd32__umtx_op */
+ case 454: {
+ struct freebsd32__umtx_op_args *p = params;
+ uarg[0] = (intptr_t) p->obj; /* void * */
+ iarg[1] = p->op; /* int */
+ uarg[2] = p->val; /* u_long */
+ uarg[3] = (intptr_t) p->uaddr; /* void * */
+ uarg[4] = (intptr_t) p->uaddr2; /* void * */
+ *n_args = 5;
+ break;
+ }
+ /* freebsd32_thr_new */
+ case 455: {
+ struct freebsd32_thr_new_args *p = params;
+ uarg[0] = (intptr_t) p->param; /* struct thr_param32 * */
+ iarg[1] = p->param_size; /* int */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_sigqueue */
+ case 456: {
+ struct freebsd32_sigqueue_args *p = params;
+ iarg[0] = p->pid; /* pid_t */
+ iarg[1] = p->signum; /* int */
+ iarg[2] = p->value; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* freebsd32_kmq_open */
+ case 457: {
+ struct freebsd32_kmq_open_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->flags; /* int */
+ iarg[2] = p->mode; /* mode_t */
+ uarg[3] = (intptr_t) p->attr; /* const struct mq_attr32 * */
+ *n_args = 4;
+ break;
+ }
+ /* freebsd32_kmq_setattr */
+ case 458: {
+ struct freebsd32_kmq_setattr_args *p = params;
+ iarg[0] = p->mqd; /* int */
+ uarg[1] = (intptr_t) p->attr; /* const struct mq_attr32 * */
+ uarg[2] = (intptr_t) p->oattr; /* struct mq_attr32 * */
+ *n_args = 3;
+ break;
+ }
+ /* freebsd32_kmq_timedreceive */
+ case 459: {
+ struct freebsd32_kmq_timedreceive_args *p = params;
+ iarg[0] = p->mqd; /* int */
+ uarg[1] = (intptr_t) p->msg_ptr; /* char * */
+ uarg[2] = p->msg_len; /* size_t */
+ uarg[3] = (intptr_t) p->msg_prio; /* unsigned * */
+ uarg[4] = (intptr_t) p->abs_timeout; /* const struct timespec32 * */
+ *n_args = 5;
+ break;
+ }
+ /* freebsd32_kmq_timedsend */
+ case 460: {
+ struct freebsd32_kmq_timedsend_args *p = params;
+ iarg[0] = p->mqd; /* int */
+ uarg[1] = (intptr_t) p->msg_ptr; /* const char * */
+ uarg[2] = p->msg_len; /* size_t */
+ uarg[3] = p->msg_prio; /* unsigned */
+ uarg[4] = (intptr_t) p->abs_timeout; /* const struct timespec32 * */
+ *n_args = 5;
+ break;
+ }
+ /* freebsd32_kmq_notify */
+ case 461: {
+ struct freebsd32_kmq_notify_args *p = params;
+ iarg[0] = p->mqd; /* int */
+ uarg[1] = (intptr_t) p->sigev; /* const struct sigevent32 * */
+ *n_args = 2;
+ break;
+ }
+ /* kmq_unlink */
+ case 462: {
+ struct kmq_unlink_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ *n_args = 1;
+ break;
+ }
+ /* abort2 */
+ case 463: {
+ struct abort2_args *p = params;
+ uarg[0] = (intptr_t) p->why; /* const char * */
+ iarg[1] = p->nargs; /* int */
+ uarg[2] = (intptr_t) p->args; /* void ** */
+ *n_args = 3;
+ break;
+ }
+ /* thr_set_name */
+ case 464: {
+ struct thr_set_name_args *p = params;
+ iarg[0] = p->id; /* long */
+ uarg[1] = (intptr_t) p->name; /* const char * */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_aio_fsync */
+ case 465: {
+ struct freebsd32_aio_fsync_args *p = params;
+ iarg[0] = p->op; /* int */
+ uarg[1] = (intptr_t) p->aiocbp; /* struct aiocb32 * */
+ *n_args = 2;
+ break;
+ }
+ /* rtprio_thread */
+ case 466: {
+ struct rtprio_thread_args *p = params;
+ iarg[0] = p->function; /* int */
+ iarg[1] = p->lwpid; /* lwpid_t */
+ uarg[2] = (intptr_t) p->rtp; /* struct rtprio * */
+ *n_args = 3;
+ break;
+ }
+ /* sctp_peeloff */
+ case 471: {
+ struct sctp_peeloff_args *p = params;
+ iarg[0] = p->sd; /* int */
+ uarg[1] = p->name; /* uint32_t */
+ *n_args = 2;
+ break;
+ }
+ /* sctp_generic_sendmsg */
+ case 472: {
+ struct sctp_generic_sendmsg_args *p = params;
+ iarg[0] = p->sd; /* int */
+ uarg[1] = (intptr_t) p->msg; /* void * */
+ iarg[2] = p->mlen; /* int */
+ uarg[3] = (intptr_t) p->to; /* struct sockaddr * */
+ iarg[4] = p->tolen; /* __socklen_t */
+ uarg[5] = (intptr_t) p->sinfo; /* struct sctp_sndrcvinfo * */
+ iarg[6] = p->flags; /* int */
+ *n_args = 7;
+ break;
+ }
+ /* sctp_generic_sendmsg_iov */
+ case 473: {
+ struct sctp_generic_sendmsg_iov_args *p = params;
+ iarg[0] = p->sd; /* int */
+ uarg[1] = (intptr_t) p->iov; /* struct iovec * */
+ iarg[2] = p->iovlen; /* int */
+ uarg[3] = (intptr_t) p->to; /* struct sockaddr * */
+ iarg[4] = p->tolen; /* __socklen_t */
+ uarg[5] = (intptr_t) p->sinfo; /* struct sctp_sndrcvinfo * */
+ iarg[6] = p->flags; /* int */
+ *n_args = 7;
+ break;
+ }
+ /* sctp_generic_recvmsg */
+ case 474: {
+ struct sctp_generic_recvmsg_args *p = params;
+ iarg[0] = p->sd; /* int */
+ uarg[1] = (intptr_t) p->iov; /* struct iovec * */
+ iarg[2] = p->iovlen; /* int */
+ uarg[3] = (intptr_t) p->from; /* struct sockaddr * */
+ uarg[4] = (intptr_t) p->fromlenaddr; /* __socklen_t * */
+ uarg[5] = (intptr_t) p->sinfo; /* struct sctp_sndrcvinfo * */
+ uarg[6] = (intptr_t) p->msg_flags; /* int * */
+ *n_args = 7;
+ break;
+ }
+#ifdef PAD64_REQUIRED
+ /* freebsd32_pread */
+ case 475: {
+ struct freebsd32_pread_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->buf; /* void * */
+ uarg[2] = p->nbyte; /* size_t */
+ iarg[3] = p->pad; /* int */
+ uarg[4] = p->offset1; /* uint32_t */
+ uarg[5] = p->offset2; /* uint32_t */
+ *n_args = 6;
+ break;
+ }
+ /* freebsd32_pwrite */
+ case 476: {
+ struct freebsd32_pwrite_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->buf; /* const void * */
+ uarg[2] = p->nbyte; /* size_t */
+ iarg[3] = p->pad; /* int */
+ uarg[4] = p->offset1; /* uint32_t */
+ uarg[5] = p->offset2; /* uint32_t */
+ *n_args = 6;
+ break;
+ }
+ /* freebsd32_mmap */
+ case 477: {
+ struct freebsd32_mmap_args *p = params;
+ uarg[0] = (intptr_t) p->addr; /* void * */
+ uarg[1] = p->len; /* size_t */
+ iarg[2] = p->prot; /* int */
+ iarg[3] = p->flags; /* int */
+ iarg[4] = p->fd; /* int */
+ iarg[5] = p->pad; /* int */
+ uarg[6] = p->pos1; /* uint32_t */
+ uarg[7] = p->pos2; /* uint32_t */
+ *n_args = 8;
+ break;
+ }
+ /* freebsd32_lseek */
+ case 478: {
+ struct freebsd32_lseek_args *p = params;
+ iarg[0] = p->fd; /* int */
+ iarg[1] = p->pad; /* int */
+ uarg[2] = p->offset1; /* uint32_t */
+ uarg[3] = p->offset2; /* uint32_t */
+ iarg[4] = p->whence; /* int */
+ *n_args = 5;
+ break;
+ }
+ /* freebsd32_truncate */
+ case 479: {
+ struct freebsd32_truncate_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->pad; /* int */
+ uarg[2] = p->length1; /* uint32_t */
+ uarg[3] = p->length2; /* uint32_t */
+ *n_args = 4;
+ break;
+ }
+ /* freebsd32_ftruncate */
+ case 480: {
+ struct freebsd32_ftruncate_args *p = params;
+ iarg[0] = p->fd; /* int */
+ iarg[1] = p->pad; /* int */
+ uarg[2] = p->length1; /* uint32_t */
+ uarg[3] = p->length2; /* uint32_t */
+ *n_args = 4;
+ break;
+ }
+#else
+ /* freebsd32_pread */
+ case 475: {
+ struct freebsd32_pread_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->buf; /* void * */
+ uarg[2] = p->nbyte; /* size_t */
+ uarg[3] = p->offset1; /* uint32_t */
+ uarg[4] = p->offset2; /* uint32_t */
+ *n_args = 5;
+ break;
+ }
+ /* freebsd32_pwrite */
+ case 476: {
+ struct freebsd32_pwrite_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->buf; /* const void * */
+ uarg[2] = p->nbyte; /* size_t */
+ uarg[3] = p->offset1; /* uint32_t */
+ uarg[4] = p->offset2; /* uint32_t */
+ *n_args = 5;
+ break;
+ }
+ /* freebsd32_mmap */
+ case 477: {
+ struct freebsd32_mmap_args *p = params;
+ uarg[0] = (intptr_t) p->addr; /* void * */
+ uarg[1] = p->len; /* size_t */
+ iarg[2] = p->prot; /* int */
+ iarg[3] = p->flags; /* int */
+ iarg[4] = p->fd; /* int */
+ uarg[5] = p->pos1; /* uint32_t */
+ uarg[6] = p->pos2; /* uint32_t */
+ *n_args = 7;
+ break;
+ }
+ /* freebsd32_lseek */
+ case 478: {
+ struct freebsd32_lseek_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = p->offset1; /* uint32_t */
+ uarg[2] = p->offset2; /* uint32_t */
+ iarg[3] = p->whence; /* int */
+ *n_args = 4;
+ break;
+ }
+ /* freebsd32_truncate */
+ case 479: {
+ struct freebsd32_truncate_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ uarg[1] = p->length1; /* uint32_t */
+ uarg[2] = p->length2; /* uint32_t */
+ *n_args = 3;
+ break;
+ }
+ /* freebsd32_ftruncate */
+ case 480: {
+ struct freebsd32_ftruncate_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = p->length1; /* uint32_t */
+ uarg[2] = p->length2; /* uint32_t */
+ *n_args = 3;
+ break;
+ }
+#endif
+ /* thr_kill2 */
+ case 481: {
+ struct thr_kill2_args *p = params;
+ iarg[0] = p->pid; /* pid_t */
+ iarg[1] = p->id; /* long */
+ iarg[2] = p->sig; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* shm_unlink */
+ case 483: {
+ struct shm_unlink_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ *n_args = 1;
+ break;
+ }
+ /* cpuset */
+ case 484: {
+ struct cpuset_args *p = params;
+ uarg[0] = (intptr_t) p->setid; /* cpusetid_t * */
+ *n_args = 1;
+ break;
+ }
+#ifdef PAD64_REQUIRED
+ /* freebsd32_cpuset_setid */
+ case 485: {
+ struct freebsd32_cpuset_setid_args *p = params;
+ iarg[0] = p->which; /* cpuwhich_t */
+ iarg[1] = p->pad; /* int */
+ uarg[2] = p->id1; /* uint32_t */
+ uarg[3] = p->id2; /* uint32_t */
+ iarg[4] = p->setid; /* cpusetid_t */
+ *n_args = 5;
+ break;
+ }
+#else
+ /* freebsd32_cpuset_setid */
+ case 485: {
+ struct freebsd32_cpuset_setid_args *p = params;
+ iarg[0] = p->which; /* cpuwhich_t */
+ uarg[1] = p->id1; /* uint32_t */
+ uarg[2] = p->id2; /* uint32_t */
+ iarg[3] = p->setid; /* cpusetid_t */
+ *n_args = 4;
+ break;
+ }
+#endif
+ /* freebsd32_cpuset_getid */
+ case 486: {
+ struct freebsd32_cpuset_getid_args *p = params;
+ iarg[0] = p->level; /* cpulevel_t */
+ iarg[1] = p->which; /* cpuwhich_t */
+ uarg[2] = p->id1; /* uint32_t */
+ uarg[3] = p->id2; /* uint32_t */
+ uarg[4] = (intptr_t) p->setid; /* cpusetid_t * */
+ *n_args = 5;
+ break;
+ }
+ /* freebsd32_cpuset_getaffinity */
+ case 487: {
+ struct freebsd32_cpuset_getaffinity_args *p = params;
+ iarg[0] = p->level; /* cpulevel_t */
+ iarg[1] = p->which; /* cpuwhich_t */
+ uarg[2] = p->id1; /* uint32_t */
+ uarg[3] = p->id2; /* uint32_t */
+ uarg[4] = p->cpusetsize; /* size_t */
+ uarg[5] = (intptr_t) p->mask; /* cpuset_t * */
+ *n_args = 6;
+ break;
+ }
+ /* freebsd32_cpuset_setaffinity */
+ case 488: {
+ struct freebsd32_cpuset_setaffinity_args *p = params;
+ iarg[0] = p->level; /* cpulevel_t */
+ iarg[1] = p->which; /* cpuwhich_t */
+ uarg[2] = p->id1; /* uint32_t */
+ uarg[3] = p->id2; /* uint32_t */
+ uarg[4] = p->cpusetsize; /* size_t */
+ uarg[5] = (intptr_t) p->mask; /* const cpuset_t * */
+ *n_args = 6;
+ break;
+ }
+ /* faccessat */
+ case 489: {
+ struct faccessat_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ iarg[2] = p->amode; /* int */
+ iarg[3] = p->flag; /* int */
+ *n_args = 4;
+ break;
+ }
+ /* fchmodat */
+ case 490: {
+ struct fchmodat_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ iarg[2] = p->mode; /* mode_t */
+ iarg[3] = p->flag; /* int */
+ *n_args = 4;
+ break;
+ }
+ /* fchownat */
+ case 491: {
+ struct fchownat_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ uarg[2] = p->uid; /* uid_t */
+ iarg[3] = p->gid; /* gid_t */
+ iarg[4] = p->flag; /* int */
+ *n_args = 5;
+ break;
+ }
+ /* freebsd32_fexecve */
+ case 492: {
+ struct freebsd32_fexecve_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->argv; /* uint32_t * */
+ uarg[2] = (intptr_t) p->envv; /* uint32_t * */
+ *n_args = 3;
+ break;
+ }
+ /* freebsd32_futimesat */
+ case 494: {
+ struct freebsd32_futimesat_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ uarg[2] = (intptr_t) p->times; /* struct timeval * */
+ *n_args = 3;
+ break;
+ }
+ /* linkat */
+ case 495: {
+ struct linkat_args *p = params;
+ iarg[0] = p->fd1; /* int */
+ uarg[1] = (intptr_t) p->path1; /* const char * */
+ iarg[2] = p->fd2; /* int */
+ uarg[3] = (intptr_t) p->path2; /* const char * */
+ iarg[4] = p->flag; /* int */
+ *n_args = 5;
+ break;
+ }
+ /* mkdirat */
+ case 496: {
+ struct mkdirat_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ iarg[2] = p->mode; /* mode_t */
+ *n_args = 3;
+ break;
+ }
+ /* mkfifoat */
+ case 497: {
+ struct mkfifoat_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ iarg[2] = p->mode; /* mode_t */
+ *n_args = 3;
+ break;
+ }
+ /* openat */
+ case 499: {
+ struct openat_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ iarg[2] = p->flag; /* int */
+ iarg[3] = p->mode; /* mode_t */
+ *n_args = 4;
+ break;
+ }
+ /* readlinkat */
+ case 500: {
+ struct readlinkat_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ uarg[2] = (intptr_t) p->buf; /* char * */
+ uarg[3] = p->bufsize; /* size_t */
+ *n_args = 4;
+ break;
+ }
+ /* renameat */
+ case 501: {
+ struct renameat_args *p = params;
+ iarg[0] = p->oldfd; /* int */
+ uarg[1] = (intptr_t) p->old; /* const char * */
+ iarg[2] = p->newfd; /* int */
+ uarg[3] = (intptr_t) p->new; /* const char * */
+ *n_args = 4;
+ break;
+ }
+ /* symlinkat */
+ case 502: {
+ struct symlinkat_args *p = params;
+ uarg[0] = (intptr_t) p->path1; /* const char * */
+ iarg[1] = p->fd; /* int */
+ uarg[2] = (intptr_t) p->path2; /* const char * */
+ *n_args = 3;
+ break;
+ }
+ /* unlinkat */
+ case 503: {
+ struct unlinkat_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ iarg[2] = p->flag; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* posix_openpt */
+ case 504: {
+ struct posix_openpt_args *p = params;
+ iarg[0] = p->flags; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* freebsd32_jail_get */
+ case 506: {
+ struct freebsd32_jail_get_args *p = params;
+ uarg[0] = (intptr_t) p->iovp; /* struct iovec32 * */
+ uarg[1] = p->iovcnt; /* unsigned int */
+ iarg[2] = p->flags; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* freebsd32_jail_set */
+ case 507: {
+ struct freebsd32_jail_set_args *p = params;
+ uarg[0] = (intptr_t) p->iovp; /* struct iovec32 * */
+ uarg[1] = p->iovcnt; /* unsigned int */
+ iarg[2] = p->flags; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* jail_remove */
+ case 508: {
+ struct jail_remove_args *p = params;
+ iarg[0] = p->jid; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* freebsd32_semctl */
+ case 510: {
+ struct freebsd32_semctl_args *p = params;
+ iarg[0] = p->semid; /* int */
+ iarg[1] = p->semnum; /* int */
+ iarg[2] = p->cmd; /* int */
+ uarg[3] = (intptr_t) p->arg; /* union semun32 * */
+ *n_args = 4;
+ break;
+ }
+ /* freebsd32_msgctl */
+ case 511: {
+ struct freebsd32_msgctl_args *p = params;
+ iarg[0] = p->msqid; /* int */
+ iarg[1] = p->cmd; /* int */
+ uarg[2] = (intptr_t) p->buf; /* struct msqid_ds32 * */
+ *n_args = 3;
+ break;
+ }
+ /* freebsd32_shmctl */
+ case 512: {
+ struct freebsd32_shmctl_args *p = params;
+ iarg[0] = p->shmid; /* int */
+ iarg[1] = p->cmd; /* int */
+ uarg[2] = (intptr_t) p->buf; /* struct shmid_ds32 * */
+ *n_args = 3;
+ break;
+ }
+ /* lpathconf */
+ case 513: {
+ struct lpathconf_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->name; /* int */
+ *n_args = 2;
+ break;
+ }
+ /* __cap_rights_get */
+ case 515: {
+ struct __cap_rights_get_args *p = params;
+ iarg[0] = p->version; /* int */
+ iarg[1] = p->fd; /* int */
+ uarg[2] = (intptr_t) p->rightsp; /* cap_rights_t * */
+ *n_args = 3;
+ break;
+ }
+ /* cap_enter */
+ case 516: {
+ *n_args = 0;
+ break;
+ }
+ /* cap_getmode */
+ case 517: {
+ struct cap_getmode_args *p = params;
+ uarg[0] = (intptr_t) p->modep; /* u_int * */
+ *n_args = 1;
+ break;
+ }
+ /* pdfork */
+ case 518: {
+ struct pdfork_args *p = params;
+ uarg[0] = (intptr_t) p->fdp; /* int * */
+ iarg[1] = p->flags; /* int */
+ *n_args = 2;
+ break;
+ }
+ /* pdkill */
+ case 519: {
+ struct pdkill_args *p = params;
+ iarg[0] = p->fd; /* int */
+ iarg[1] = p->signum; /* int */
+ *n_args = 2;
+ break;
+ }
+ /* pdgetpid */
+ case 520: {
+ struct pdgetpid_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->pidp; /* pid_t * */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_pselect */
+ case 522: {
+ struct freebsd32_pselect_args *p = params;
+ iarg[0] = p->nd; /* int */
+ uarg[1] = (intptr_t) p->in; /* fd_set * */
+ uarg[2] = (intptr_t) p->ou; /* fd_set * */
+ uarg[3] = (intptr_t) p->ex; /* fd_set * */
+ uarg[4] = (intptr_t) p->ts; /* const struct timespec32 * */
+ uarg[5] = (intptr_t) p->sm; /* const sigset_t * */
+ *n_args = 6;
+ break;
+ }
+ /* getloginclass */
+ case 523: {
+ struct getloginclass_args *p = params;
+ uarg[0] = (intptr_t) p->namebuf; /* char * */
+ uarg[1] = p->namelen; /* size_t */
+ *n_args = 2;
+ break;
+ }
+ /* setloginclass */
+ case 524: {
+ struct setloginclass_args *p = params;
+ uarg[0] = (intptr_t) p->namebuf; /* const char * */
+ *n_args = 1;
+ break;
+ }
+ /* rctl_get_racct */
+ case 525: {
+ struct rctl_get_racct_args *p = params;
+ uarg[0] = (intptr_t) p->inbufp; /* const void * */
+ uarg[1] = p->inbuflen; /* size_t */
+ uarg[2] = (intptr_t) p->outbufp; /* void * */
+ uarg[3] = p->outbuflen; /* size_t */
+ *n_args = 4;
+ break;
+ }
+ /* rctl_get_rules */
+ case 526: {
+ struct rctl_get_rules_args *p = params;
+ uarg[0] = (intptr_t) p->inbufp; /* const void * */
+ uarg[1] = p->inbuflen; /* size_t */
+ uarg[2] = (intptr_t) p->outbufp; /* void * */
+ uarg[3] = p->outbuflen; /* size_t */
+ *n_args = 4;
+ break;
+ }
+ /* rctl_get_limits */
+ case 527: {
+ struct rctl_get_limits_args *p = params;
+ uarg[0] = (intptr_t) p->inbufp; /* const void * */
+ uarg[1] = p->inbuflen; /* size_t */
+ uarg[2] = (intptr_t) p->outbufp; /* void * */
+ uarg[3] = p->outbuflen; /* size_t */
+ *n_args = 4;
+ break;
+ }
+ /* rctl_add_rule */
+ case 528: {
+ struct rctl_add_rule_args *p = params;
+ uarg[0] = (intptr_t) p->inbufp; /* const void * */
+ uarg[1] = p->inbuflen; /* size_t */
+ uarg[2] = (intptr_t) p->outbufp; /* void * */
+ uarg[3] = p->outbuflen; /* size_t */
+ *n_args = 4;
+ break;
+ }
+ /* rctl_remove_rule */
+ case 529: {
+ struct rctl_remove_rule_args *p = params;
+ uarg[0] = (intptr_t) p->inbufp; /* const void * */
+ uarg[1] = p->inbuflen; /* size_t */
+ uarg[2] = (intptr_t) p->outbufp; /* void * */
+ uarg[3] = p->outbuflen; /* size_t */
+ *n_args = 4;
+ break;
+ }
+#ifdef PAD64_REQUIRED
+ /* freebsd32_posix_fallocate */
+ case 530: {
+ struct freebsd32_posix_fallocate_args *p = params;
+ iarg[0] = p->fd; /* int */
+ iarg[1] = p->pad; /* int */
+ uarg[2] = p->offset1; /* uint32_t */
+ uarg[3] = p->offset2; /* uint32_t */
+ uarg[4] = p->len1; /* uint32_t */
+ uarg[5] = p->len2; /* uint32_t */
+ *n_args = 6;
+ break;
+ }
+ /* freebsd32_posix_fadvise */
+ case 531: {
+ struct freebsd32_posix_fadvise_args *p = params;
+ iarg[0] = p->fd; /* int */
+ iarg[1] = p->pad; /* int */
+ uarg[2] = p->offset1; /* uint32_t */
+ uarg[3] = p->offset2; /* uint32_t */
+ uarg[4] = p->len1; /* uint32_t */
+ uarg[5] = p->len2; /* uint32_t */
+ iarg[6] = p->advice; /* int */
+ *n_args = 7;
+ break;
+ }
+ /* freebsd32_wait6 */
+ case 532: {
+ struct freebsd32_wait6_args *p = params;
+ iarg[0] = p->idtype; /* int */
+ iarg[1] = p->pad; /* int */
+ uarg[2] = p->id1; /* uint32_t */
+ uarg[3] = p->id2; /* uint32_t */
+ uarg[4] = (intptr_t) p->status; /* int * */
+ iarg[5] = p->options; /* int */
+ uarg[6] = (intptr_t) p->wrusage; /* struct wrusage32 * */
+ uarg[7] = (intptr_t) p->info; /* siginfo_t * */
+ *n_args = 8;
+ break;
+ }
+#else
+ /* freebsd32_posix_fallocate */
+ case 530: {
+ struct freebsd32_posix_fallocate_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = p->offset1; /* uint32_t */
+ uarg[2] = p->offset2; /* uint32_t */
+ uarg[3] = p->len1; /* uint32_t */
+ uarg[4] = p->len2; /* uint32_t */
+ *n_args = 5;
+ break;
+ }
+ /* freebsd32_posix_fadvise */
+ case 531: {
+ struct freebsd32_posix_fadvise_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = p->offset1; /* uint32_t */
+ uarg[2] = p->offset2; /* uint32_t */
+ uarg[3] = p->len1; /* uint32_t */
+ uarg[4] = p->len2; /* uint32_t */
+ iarg[5] = p->advice; /* int */
+ *n_args = 6;
+ break;
+ }
+ /* freebsd32_wait6 */
+ case 532: {
+ struct freebsd32_wait6_args *p = params;
+ iarg[0] = p->idtype; /* int */
+ uarg[1] = p->id1; /* uint32_t */
+ uarg[2] = p->id2; /* uint32_t */
+ uarg[3] = (intptr_t) p->status; /* int * */
+ iarg[4] = p->options; /* int */
+ uarg[5] = (intptr_t) p->wrusage; /* struct wrusage32 * */
+ uarg[6] = (intptr_t) p->info; /* siginfo_t * */
+ *n_args = 7;
+ break;
+ }
+#endif
+ /* cap_rights_limit */
+ case 533: {
+ struct cap_rights_limit_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->rightsp; /* cap_rights_t * */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_cap_ioctls_limit */
+ case 534: {
+ struct freebsd32_cap_ioctls_limit_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->cmds; /* const uint32_t * */
+ uarg[2] = p->ncmds; /* size_t */
+ *n_args = 3;
+ break;
+ }
+ /* freebsd32_cap_ioctls_get */
+ case 535: {
+ struct freebsd32_cap_ioctls_get_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->cmds; /* uint32_t * */
+ uarg[2] = p->maxcmds; /* size_t */
+ *n_args = 3;
+ break;
+ }
+ /* cap_fcntls_limit */
+ case 536: {
+ struct cap_fcntls_limit_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = p->fcntlrights; /* uint32_t */
+ *n_args = 2;
+ break;
+ }
+ /* cap_fcntls_get */
+ case 537: {
+ struct cap_fcntls_get_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->fcntlrightsp; /* uint32_t * */
+ *n_args = 2;
+ break;
+ }
+ /* bindat */
+ case 538: {
+ struct bindat_args *p = params;
+ iarg[0] = p->fd; /* int */
+ iarg[1] = p->s; /* int */
+ uarg[2] = (intptr_t) p->name; /* const struct sockaddr * */
+ iarg[3] = p->namelen; /* int */
+ *n_args = 4;
+ break;
+ }
+ /* connectat */
+ case 539: {
+ struct connectat_args *p = params;
+ iarg[0] = p->fd; /* int */
+ iarg[1] = p->s; /* int */
+ uarg[2] = (intptr_t) p->name; /* const struct sockaddr * */
+ iarg[3] = p->namelen; /* int */
+ *n_args = 4;
+ break;
+ }
+ /* chflagsat */
+ case 540: {
+ struct chflagsat_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ uarg[2] = p->flags; /* u_long */
+ iarg[3] = p->atflag; /* int */
+ *n_args = 4;
+ break;
+ }
+ /* accept4 */
+ case 541: {
+ struct accept4_args *p = params;
+ iarg[0] = p->s; /* int */
+ uarg[1] = (intptr_t) p->name; /* struct sockaddr * */
+ uarg[2] = (intptr_t) p->anamelen; /* __socklen_t * */
+ iarg[3] = p->flags; /* int */
+ *n_args = 4;
+ break;
+ }
+ /* pipe2 */
+ case 542: {
+ struct pipe2_args *p = params;
+ uarg[0] = (intptr_t) p->fildes; /* int * */
+ iarg[1] = p->flags; /* int */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_aio_mlock */
+ case 543: {
+ struct freebsd32_aio_mlock_args *p = params;
+ uarg[0] = (intptr_t) p->aiocbp; /* struct aiocb32 * */
+ *n_args = 1;
+ break;
+ }
+#ifdef PAD64_REQUIRED
+ /* freebsd32_procctl */
+ case 544: {
+ struct freebsd32_procctl_args *p = params;
+ iarg[0] = p->idtype; /* int */
+ iarg[1] = p->pad; /* int */
+ uarg[2] = p->id1; /* uint32_t */
+ uarg[3] = p->id2; /* uint32_t */
+ iarg[4] = p->com; /* int */
+ uarg[5] = (intptr_t) p->data; /* void * */
+ *n_args = 6;
+ break;
+ }
+#else
+ /* freebsd32_procctl */
+ case 544: {
+ struct freebsd32_procctl_args *p = params;
+ iarg[0] = p->idtype; /* int */
+ uarg[1] = p->id1; /* uint32_t */
+ uarg[2] = p->id2; /* uint32_t */
+ iarg[3] = p->com; /* int */
+ uarg[4] = (intptr_t) p->data; /* void * */
+ *n_args = 5;
+ break;
+ }
+#endif
+ /* freebsd32_ppoll */
+ case 545: {
+ struct freebsd32_ppoll_args *p = params;
+ uarg[0] = (intptr_t) p->fds; /* struct pollfd * */
+ uarg[1] = p->nfds; /* u_int */
+ uarg[2] = (intptr_t) p->ts; /* const struct timespec32 * */
+ uarg[3] = (intptr_t) p->set; /* const sigset_t * */
+ *n_args = 4;
+ break;
+ }
+ /* freebsd32_futimens */
+ case 546: {
+ struct freebsd32_futimens_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->times; /* struct timespec * */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_utimensat */
+ case 547: {
+ struct freebsd32_utimensat_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ uarg[2] = (intptr_t) p->times; /* struct timespec * */
+ iarg[3] = p->flag; /* int */
+ *n_args = 4;
+ break;
+ }
+ /* fdatasync */
+ case 550: {
+ struct fdatasync_args *p = params;
+ iarg[0] = p->fd; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* freebsd32_fstat */
+ case 551: {
+ struct freebsd32_fstat_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->ub; /* struct stat32 * */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_fstatat */
+ case 552: {
+ struct freebsd32_fstatat_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ uarg[2] = (intptr_t) p->buf; /* struct stat32 * */
+ iarg[3] = p->flag; /* int */
+ *n_args = 4;
+ break;
+ }
+ /* freebsd32_fhstat */
+ case 553: {
+ struct freebsd32_fhstat_args *p = params;
+ uarg[0] = (intptr_t) p->u_fhp; /* const struct fhandle * */
+ uarg[1] = (intptr_t) p->sb; /* struct stat32 * */
+ *n_args = 2;
+ break;
+ }
+ /* getdirentries */
+ case 554: {
+ struct getdirentries_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->buf; /* char * */
+ uarg[2] = p->count; /* size_t */
+ uarg[3] = (intptr_t) p->basep; /* off_t * */
+ *n_args = 4;
+ break;
+ }
+ /* statfs */
+ case 555: {
+ struct statfs_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ uarg[1] = (intptr_t) p->buf; /* struct statfs32 * */
+ *n_args = 2;
+ break;
+ }
+ /* fstatfs */
+ case 556: {
+ struct fstatfs_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->buf; /* struct statfs32 * */
+ *n_args = 2;
+ break;
+ }
+ /* getfsstat */
+ case 557: {
+ struct getfsstat_args *p = params;
+ uarg[0] = (intptr_t) p->buf; /* struct statfs32 * */
+ iarg[1] = p->bufsize; /* long */
+ iarg[2] = p->mode; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* fhstatfs */
+ case 558: {
+ struct fhstatfs_args *p = params;
+ uarg[0] = (intptr_t) p->u_fhp; /* const struct fhandle * */
+ uarg[1] = (intptr_t) p->buf; /* struct statfs32 * */
+ *n_args = 2;
+ break;
+ }
+#ifdef PAD64_REQUIRED
+ /* freebsd32_mknodat */
+ case 559: {
+ struct freebsd32_mknodat_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ iarg[2] = p->mode; /* mode_t */
+ iarg[3] = p->pad; /* int */
+ uarg[4] = p->dev1; /* uint32_t */
+ uarg[5] = p->dev2; /* uint32_t */
+ *n_args = 6;
+ break;
+ }
+#else
+ /* freebsd32_mknodat */
+ case 559: {
+ struct freebsd32_mknodat_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ iarg[2] = p->mode; /* mode_t */
+ uarg[3] = p->dev1; /* uint32_t */
+ uarg[4] = p->dev2; /* uint32_t */
+ *n_args = 5;
+ break;
+ }
+#endif
+ /* freebsd32_kevent */
+ case 560: {
+ struct freebsd32_kevent_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->changelist; /* const struct kevent32 * */
+ iarg[2] = p->nchanges; /* int */
+ uarg[3] = (intptr_t) p->eventlist; /* struct kevent32 * */
+ iarg[4] = p->nevents; /* int */
+ uarg[5] = (intptr_t) p->timeout; /* const struct timespec32 * */
+ *n_args = 6;
+ break;
+ }
+ /* freebsd32_cpuset_getdomain */
+ case 561: {
+ struct freebsd32_cpuset_getdomain_args *p = params;
+ iarg[0] = p->level; /* cpulevel_t */
+ iarg[1] = p->which; /* cpuwhich_t */
+ uarg[2] = p->id1; /* uint32_t */
+ uarg[3] = p->id2; /* uint32_t */
+ uarg[4] = p->domainsetsize; /* size_t */
+ uarg[5] = (intptr_t) p->mask; /* domainset_t * */
+ uarg[6] = (intptr_t) p->policy; /* int * */
+ *n_args = 7;
+ break;
+ }
+ /* freebsd32_cpuset_setdomain */
+ case 562: {
+ struct freebsd32_cpuset_setdomain_args *p = params;
+ iarg[0] = p->level; /* cpulevel_t */
+ iarg[1] = p->which; /* cpuwhich_t */
+ uarg[2] = p->id1; /* uint32_t */
+ uarg[3] = p->id2; /* uint32_t */
+ uarg[4] = p->domainsetsize; /* size_t */
+ uarg[5] = (intptr_t) p->mask; /* domainset_t * */
+ iarg[6] = p->policy; /* int */
+ *n_args = 7;
+ break;
+ }
+ /* getrandom */
+ case 563: {
+ struct getrandom_args *p = params;
+ uarg[0] = (intptr_t) p->buf; /* void * */
+ uarg[1] = p->buflen; /* size_t */
+ uarg[2] = p->flags; /* unsigned int */
+ *n_args = 3;
+ break;
+ }
+ /* getfhat */
+ case 564: {
+ struct getfhat_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->path; /* char * */
+ uarg[2] = (intptr_t) p->fhp; /* struct fhandle * */
+ iarg[3] = p->flags; /* int */
+ *n_args = 4;
+ break;
+ }
+ /* fhlink */
+ case 565: {
+ struct fhlink_args *p = params;
+ uarg[0] = (intptr_t) p->fhp; /* struct fhandle * */
+ uarg[1] = (intptr_t) p->to; /* const char * */
+ *n_args = 2;
+ break;
+ }
+ /* fhlinkat */
+ case 566: {
+ struct fhlinkat_args *p = params;
+ uarg[0] = (intptr_t) p->fhp; /* struct fhandle * */
+ iarg[1] = p->tofd; /* int */
+ uarg[2] = (intptr_t) p->to; /* const char * */
+ *n_args = 3;
+ break;
+ }
+ /* fhreadlink */
+ case 567: {
+ struct fhreadlink_args *p = params;
+ uarg[0] = (intptr_t) p->fhp; /* struct fhandle * */
+ uarg[1] = (intptr_t) p->buf; /* char * */
+ uarg[2] = p->bufsize; /* size_t */
+ *n_args = 3;
+ break;
+ }
+ /* funlinkat */
+ case 568: {
+ struct funlinkat_args *p = params;
+ iarg[0] = p->dfd; /* int */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ iarg[2] = p->fd; /* int */
+ iarg[3] = p->flag; /* int */
+ *n_args = 4;
+ break;
+ }
+ /* copy_file_range */
+ case 569: {
+ struct copy_file_range_args *p = params;
+ iarg[0] = p->infd; /* int */
+ uarg[1] = (intptr_t) p->inoffp; /* off_t * */
+ iarg[2] = p->outfd; /* int */
+ uarg[3] = (intptr_t) p->outoffp; /* off_t * */
+ uarg[4] = p->len; /* size_t */
+ uarg[5] = p->flags; /* unsigned int */
+ *n_args = 6;
+ break;
+ }
+ /* freebsd32___sysctlbyname */
+ case 570: {
+ struct freebsd32___sysctlbyname_args *p = params;
+ uarg[0] = (intptr_t) p->name; /* const char * */
+ uarg[1] = p->namelen; /* size_t */
+ uarg[2] = (intptr_t) p->old; /* void * */
+ uarg[3] = (intptr_t) p->oldlenp; /* uint32_t * */
+ uarg[4] = (intptr_t) p->new; /* void * */
+ uarg[5] = p->newlen; /* size_t */
+ *n_args = 6;
+ break;
+ }
+ /* shm_open2 */
+ case 571: {
+ struct shm_open2_args *p = params;
+ uarg[0] = (intptr_t) p->path; /* const char * */
+ iarg[1] = p->flags; /* int */
+ iarg[2] = p->mode; /* mode_t */
+ iarg[3] = p->shmflags; /* int */
+ uarg[4] = (intptr_t) p->name; /* const char * */
+ *n_args = 5;
+ break;
+ }
+ /* shm_rename */
+ case 572: {
+ struct shm_rename_args *p = params;
+ uarg[0] = (intptr_t) p->path_from; /* const char * */
+ uarg[1] = (intptr_t) p->path_to; /* const char * */
+ iarg[2] = p->flags; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* sigfastblock */
+ case 573: {
+ struct sigfastblock_args *p = params;
+ iarg[0] = p->cmd; /* int */
+ uarg[1] = (intptr_t) p->ptr; /* uint32_t * */
+ *n_args = 2;
+ break;
+ }
+ /* __realpathat */
+ case 574: {
+ struct __realpathat_args *p = params;
+ iarg[0] = p->fd; /* int */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ uarg[2] = (intptr_t) p->buf; /* char * */
+ uarg[3] = p->size; /* size_t */
+ iarg[4] = p->flags; /* int */
+ *n_args = 5;
+ break;
+ }
+ /* close_range */
+ case 575: {
+ struct close_range_args *p = params;
+ uarg[0] = p->lowfd; /* u_int */
+ uarg[1] = p->highfd; /* u_int */
+ iarg[2] = p->flags; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* rpctls_syscall */
+ case 576: {
+ struct rpctls_syscall_args *p = params;
+ iarg[0] = p->op; /* int */
+ uarg[1] = (intptr_t) p->path; /* const char * */
+ *n_args = 2;
+ break;
+ }
+ /* __specialfd */
+ case 577: {
+ struct __specialfd_args *p = params;
+ iarg[0] = p->type; /* int */
+ uarg[1] = (intptr_t) p->req; /* const void * */
+ uarg[2] = p->len; /* size_t */
+ *n_args = 3;
+ break;
+ }
+ /* freebsd32_aio_writev */
+ case 578: {
+ struct freebsd32_aio_writev_args *p = params;
+ uarg[0] = (intptr_t) p->aiocbp; /* struct aiocb32 * */
+ *n_args = 1;
+ break;
+ }
+ /* freebsd32_aio_readv */
+ case 579: {
+ struct freebsd32_aio_readv_args *p = params;
+ uarg[0] = (intptr_t) p->aiocbp; /* struct aiocb32 * */
+ *n_args = 1;
+ break;
+ }
+ default:
+ *n_args = 0;
+ break;
+ };
+}
+static void
+systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
+{
+ const char *p = NULL;
+ switch (sysnum) {
+#if !defined(PAD64_REQUIRED) && !defined(__amd64__)
+#define PAD64_REQUIRED
+#endif
+ /* nosys */
+ case 0:
+ break;
+ /* sys_exit */
+ case 1:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* fork */
+ case 2:
+ break;
+ /* read */
+ case 3:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland void *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* write */
+ case 4:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const void *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* open */
+ case 5:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "mode_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* close */
+ case 6:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_wait4 */
+ case 7:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland int *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "userland struct rusage32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* link */
+ case 9:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* unlink */
+ case 10:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* chdir */
+ case 12:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* fchdir */
+ case 13:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* chmod */
+ case 15:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "mode_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* chown */
+ case 16:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* break */
+ case 17:
+ switch(ndx) {
+ case 0:
+ p = "userland char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getpid */
+ case 20:
+ break;
+ /* mount */
+ case 21:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "userland void *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* unmount */
+ case 22:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* setuid */
+ case 23:
+ switch(ndx) {
+ case 0:
+ p = "uid_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getuid */
+ case 24:
+ break;
+ /* geteuid */
+ case 25:
+ break;
+ /* freebsd32_ptrace */
+ case 26:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "pid_t";
+ break;
+ case 2:
+ p = "caddr_t";
+ break;
+ case 3:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_recvmsg */
+ case 27:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct msghdr32 *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_sendmsg */
+ case 28:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct msghdr32 *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_recvfrom */
+ case 29:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland void *";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ case 3:
+ p = "int";
+ break;
+ case 4:
+ p = "userland struct sockaddr *";
+ break;
+ case 5:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* accept */
+ case 30:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct sockaddr *";
+ break;
+ case 2:
+ p = "userland int *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getpeername */
+ case 31:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct sockaddr *";
+ break;
+ case 2:
+ p = "userland int *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getsockname */
+ case 32:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct sockaddr *";
+ break;
+ case 2:
+ p = "userland int *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* access */
+ case 33:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* chflags */
+ case 34:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "u_long";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* fchflags */
+ case 35:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "u_long";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* sync */
+ case 36:
+ break;
+ /* kill */
+ case 37:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getppid */
+ case 39:
+ break;
+ /* dup */
+ case 41:
+ switch(ndx) {
+ case 0:
+ p = "u_int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getegid */
+ case 43:
+ break;
+ /* profil */
+ case 44:
+ switch(ndx) {
+ case 0:
+ p = "userland char *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "u_int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* ktrace */
+ case 45:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getgid */
+ case 47:
+ break;
+ /* getlogin */
+ case 49:
+ switch(ndx) {
+ case 0:
+ p = "userland char *";
+ break;
+ case 1:
+ p = "u_int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* setlogin */
+ case 50:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* acct */
+ case 51:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_sigaltstack */
+ case 53:
+ switch(ndx) {
+ case 0:
+ p = "userland struct sigaltstack32 *";
+ break;
+ case 1:
+ p = "userland struct sigaltstack32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_ioctl */
+ case 54:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "uint32_t";
+ break;
+ case 2:
+ p = "userland struct md_ioctl32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* reboot */
+ case 55:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* revoke */
+ case 56:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* symlink */
+ case 57:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* readlink */
+ case 58:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "userland char *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_execve */
+ case 59:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "userland uint32_t *";
+ break;
+ case 2:
+ p = "userland uint32_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* umask */
+ case 60:
+ switch(ndx) {
+ case 0:
+ p = "mode_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* chroot */
+ case 61:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* msync */
+ case 65:
+ switch(ndx) {
+ case 0:
+ p = "userland void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* vfork */
+ case 66:
+ break;
+ /* sbrk */
+ case 69:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* sstk */
+ case 70:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* munmap */
+ case 73:
+ switch(ndx) {
+ case 0:
+ p = "userland void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_mprotect */
+ case 74:
+ switch(ndx) {
+ case 0:
+ p = "userland void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* madvise */
+ case 75:
+ switch(ndx) {
+ case 0:
+ p = "userland void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* mincore */
+ case 78:
+ switch(ndx) {
+ case 0:
+ p = "userland const void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "userland char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getgroups */
+ case 79:
+ switch(ndx) {
+ case 0:
+ p = "u_int";
+ break;
+ case 1:
+ p = "userland gid_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* setgroups */
+ case 80:
+ switch(ndx) {
+ case 0:
+ p = "u_int";
+ break;
+ case 1:
+ p = "userland gid_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getpgrp */
+ case 81:
+ break;
+ /* setpgid */
+ case 82:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_setitimer */
+ case 83:
+ switch(ndx) {
+ case 0:
+ p = "u_int";
+ break;
+ case 1:
+ p = "userland struct itimerval32 *";
+ break;
+ case 2:
+ p = "userland struct itimerval32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* swapon */
+ case 85:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_getitimer */
+ case 86:
+ switch(ndx) {
+ case 0:
+ p = "u_int";
+ break;
+ case 1:
+ p = "userland struct itimerval32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getdtablesize */
+ case 89:
+ break;
+ /* dup2 */
+ case 90:
+ switch(ndx) {
+ case 0:
+ p = "u_int";
+ break;
+ case 1:
+ p = "u_int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_fcntl */
+ case 92:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_select */
+ case 93:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland fd_set *";
+ break;
+ case 2:
+ p = "userland fd_set *";
+ break;
+ case 3:
+ p = "userland fd_set *";
+ break;
+ case 4:
+ p = "userland struct timeval32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* fsync */
+ case 95:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* setpriority */
+ case 96:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* socket */
+ case 97:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* connect */
+ case 98:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const struct sockaddr *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getpriority */
+ case 100:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* bind */
+ case 104:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const struct sockaddr *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* setsockopt */
+ case 105:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "userland const void *";
+ break;
+ case 4:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* listen */
+ case 106:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_gettimeofday */
+ case 116:
+ switch(ndx) {
+ case 0:
+ p = "userland struct timeval32 *";
+ break;
+ case 1:
+ p = "userland struct timezone *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_getrusage */
+ case 117:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct rusage32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getsockopt */
+ case 118:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "userland void *";
+ break;
+ case 4:
+ p = "userland int *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_readv */
+ case 120:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct iovec32 *";
+ break;
+ case 2:
+ p = "u_int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_writev */
+ case 121:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct iovec32 *";
+ break;
+ case 2:
+ p = "u_int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_settimeofday */
+ case 122:
+ switch(ndx) {
+ case 0:
+ p = "userland struct timeval32 *";
+ break;
+ case 1:
+ p = "userland struct timezone *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* fchown */
+ case 123:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* fchmod */
+ case 124:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "mode_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* setreuid */
+ case 126:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* setregid */
+ case 127:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* rename */
+ case 128:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* flock */
+ case 131:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* mkfifo */
+ case 132:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "mode_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* sendto */
+ case 133:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const void *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "int";
+ break;
+ case 4:
+ p = "userland const struct sockaddr *";
+ break;
+ case 5:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* shutdown */
+ case 134:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* socketpair */
+ case 135:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "userland int *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* mkdir */
+ case 136:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "mode_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* rmdir */
+ case 137:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_utimes */
+ case 138:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "userland struct timeval32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_adjtime */
+ case 140:
+ switch(ndx) {
+ case 0:
+ p = "userland struct timeval32 *";
+ break;
+ case 1:
+ p = "userland struct timeval32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* setsid */
+ case 147:
+ break;
+ /* quotactl */
+ case 148:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "userland void *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getfh */
+ case 161:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "userland struct fhandle *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_sysarch */
+ case 165:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* rtprio */
+ case 166:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "pid_t";
+ break;
+ case 2:
+ p = "userland struct rtprio *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_semsys */
+ case 169:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "int";
+ break;
+ case 4:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_msgsys */
+ case 170:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "int";
+ break;
+ case 4:
+ p = "int";
+ break;
+ case 5:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_shmsys */
+ case 171:
+ switch(ndx) {
+ case 0:
+ p = "uint32_t";
+ break;
+ case 1:
+ p = "uint32_t";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ case 3:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_ntp_adjtime */
+ case 176:
+ switch(ndx) {
+ case 0:
+ p = "userland struct timex32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* setgid */
+ case 181:
+ switch(ndx) {
+ case 0:
+ p = "gid_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* setegid */
+ case 182:
+ switch(ndx) {
+ case 0:
+ p = "gid_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* seteuid */
+ case 183:
+ switch(ndx) {
+ case 0:
+ p = "uid_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* pathconf */
+ case 191:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* fpathconf */
+ case 192:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getrlimit */
+ case 194:
+ switch(ndx) {
+ case 0:
+ p = "u_int";
+ break;
+ case 1:
+ p = "userland struct rlimit *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* setrlimit */
+ case 195:
+ switch(ndx) {
+ case 0:
+ p = "u_int";
+ break;
+ case 1:
+ p = "userland struct rlimit *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* nosys */
+ case 198:
+ break;
+ /* freebsd32___sysctl */
+ case 202:
+ switch(ndx) {
+ case 0:
+ p = "userland int *";
+ break;
+ case 1:
+ p = "u_int";
+ break;
+ case 2:
+ p = "userland void *";
+ break;
+ case 3:
+ p = "userland uint32_t *";
+ break;
+ case 4:
+ p = "userland const void *";
+ break;
+ case 5:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* mlock */
+ case 203:
+ switch(ndx) {
+ case 0:
+ p = "userland const void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* munlock */
+ case 204:
+ switch(ndx) {
+ case 0:
+ p = "userland const void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* undelete */
+ case 205:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_futimes */
+ case 206:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct timeval32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getpgid */
+ case 207:
+ switch(ndx) {
+ case 0:
+ p = "pid_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* poll */
+ case 209:
+ switch(ndx) {
+ case 0:
+ p = "userland struct pollfd *";
+ break;
+ case 1:
+ p = "u_int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* lkmnosys */
+ case 210:
+ break;
+ /* lkmnosys */
+ case 211:
+ break;
+ /* lkmnosys */
+ case 212:
+ break;
+ /* lkmnosys */
+ case 213:
+ break;
+ /* lkmnosys */
+ case 214:
+ break;
+ /* lkmnosys */
+ case 215:
+ break;
+ /* lkmnosys */
+ case 216:
+ break;
+ /* lkmnosys */
+ case 217:
+ break;
+ /* lkmnosys */
+ case 218:
+ break;
+ /* lkmnosys */
+ case 219:
+ break;
+ /* semget */
+ case 221:
+ switch(ndx) {
+ case 0:
+ p = "key_t";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* semop */
+ case 222:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct sembuf *";
+ break;
+ case 2:
+ p = "u_int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* msgget */
+ case 225:
+ switch(ndx) {
+ case 0:
+ p = "key_t";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_msgsnd */
+ case 226:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland void *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_msgrcv */
+ case 227:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland void *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "long";
+ break;
+ case 4:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* shmat */
+ case 228:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland void *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* shmdt */
+ case 230:
+ switch(ndx) {
+ case 0:
+ p = "userland void *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* shmget */
+ case 231:
+ switch(ndx) {
+ case 0:
+ p = "key_t";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_clock_gettime */
+ case 232:
+ switch(ndx) {
+ case 0:
+ p = "clockid_t";
+ break;
+ case 1:
+ p = "userland struct timespec32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_clock_settime */
+ case 233:
+ switch(ndx) {
+ case 0:
+ p = "clockid_t";
+ break;
+ case 1:
+ p = "userland const struct timespec32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_clock_getres */
+ case 234:
+ switch(ndx) {
+ case 0:
+ p = "clockid_t";
+ break;
+ case 1:
+ p = "userland struct timespec32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_ktimer_create */
+ case 235:
+ switch(ndx) {
+ case 0:
+ p = "clockid_t";
+ break;
+ case 1:
+ p = "userland struct sigevent32 *";
+ break;
+ case 2:
+ p = "userland int *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* ktimer_delete */
+ case 236:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_ktimer_settime */
+ case 237:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland const struct itimerspec32 *";
+ break;
+ case 3:
+ p = "userland struct itimerspec32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_ktimer_gettime */
+ case 238:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct itimerspec32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* ktimer_getoverrun */
+ case 239:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_nanosleep */
+ case 240:
+ switch(ndx) {
+ case 0:
+ p = "userland const struct timespec32 *";
+ break;
+ case 1:
+ p = "userland struct timespec32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* ffclock_getcounter */
+ case 241:
+ switch(ndx) {
+ case 0:
+ p = "userland ffcounter *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* ffclock_setestimate */
+ case 242:
+ switch(ndx) {
+ case 0:
+ p = "userland struct ffclock_estimate *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* ffclock_getestimate */
+ case 243:
+ switch(ndx) {
+ case 0:
+ p = "userland struct ffclock_estimate *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_clock_nanosleep */
+ case 244:
+ switch(ndx) {
+ case 0:
+ p = "clockid_t";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland const struct timespec32 *";
+ break;
+ case 3:
+ p = "userland struct timespec32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_clock_getcpuclockid2 */
+ case 247:
+ switch(ndx) {
+ case 0:
+ p = "uint32_t";
+ break;
+ case 1:
+ p = "uint32_t";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "userland clockid_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* minherit */
+ case 250:
+ switch(ndx) {
+ case 0:
+ p = "userland void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* rfork */
+ case 251:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* issetugid */
+ case 253:
+ break;
+ /* lchown */
+ case 254:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_aio_read */
+ case 255:
+ switch(ndx) {
+ case 0:
+ p = "userland struct aiocb32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_aio_write */
+ case 256:
+ switch(ndx) {
+ case 0:
+ p = "userland struct aiocb32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_lio_listio */
+ case 257:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct aiocb32 * const *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "userland struct sigevent32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* lchmod */
+ case 274:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "mode_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_lutimes */
+ case 276:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "userland struct timeval32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_preadv */
+ case 289:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct iovec32 *";
+ break;
+ case 2:
+ p = "u_int";
+ break;
+ case 3:
+ p = "uint32_t";
+ break;
+ case 4:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_pwritev */
+ case 290:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct iovec32 *";
+ break;
+ case 2:
+ p = "u_int";
+ break;
+ case 3:
+ p = "uint32_t";
+ break;
+ case 4:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* fhopen */
+ case 298:
+ switch(ndx) {
+ case 0:
+ p = "userland const struct fhandle *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* modnext */
+ case 300:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_modstat */
+ case 301:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct module_stat32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* modfnext */
+ case 302:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* modfind */
+ case 303:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* kldload */
+ case 304:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* kldunload */
+ case 305:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* kldfind */
+ case 306:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* kldnext */
+ case 307:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_kldstat */
+ case 308:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct kld32_file_stat *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* kldfirstmod */
+ case 309:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getsid */
+ case 310:
+ switch(ndx) {
+ case 0:
+ p = "pid_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* setresuid */
+ case 311:
+ switch(ndx) {
+ case 0:
+ p = "uid_t";
+ break;
+ case 1:
+ p = "uid_t";
+ break;
+ case 2:
+ p = "uid_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* setresgid */
+ case 312:
+ switch(ndx) {
+ case 0:
+ p = "gid_t";
+ break;
+ case 1:
+ p = "gid_t";
+ break;
+ case 2:
+ p = "gid_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_aio_return */
+ case 314:
+ switch(ndx) {
+ case 0:
+ p = "userland struct aiocb32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_aio_suspend */
+ case 315:
+ switch(ndx) {
+ case 0:
+ p = "userland struct aiocb32 * const *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland const struct timespec32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* aio_cancel */
+ case 316:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct aiocb *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_aio_error */
+ case 317:
+ switch(ndx) {
+ case 0:
+ p = "userland struct aiocb32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* yield */
+ case 321:
+ break;
+ /* mlockall */
+ case 324:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* munlockall */
+ case 325:
+ break;
+ /* __getcwd */
+ case 326:
+ switch(ndx) {
+ case 0:
+ p = "userland char *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* sched_setparam */
+ case 327:
+ switch(ndx) {
+ case 0:
+ p = "pid_t";
+ break;
+ case 1:
+ p = "userland const struct sched_param *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* sched_getparam */
+ case 328:
+ switch(ndx) {
+ case 0:
+ p = "pid_t";
+ break;
+ case 1:
+ p = "userland struct sched_param *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* sched_setscheduler */
+ case 329:
+ switch(ndx) {
+ case 0:
+ p = "pid_t";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland const struct sched_param *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* sched_getscheduler */
+ case 330:
+ switch(ndx) {
+ case 0:
+ p = "pid_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* sched_yield */
+ case 331:
+ break;
+ /* sched_get_priority_max */
+ case 332:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* sched_get_priority_min */
+ case 333:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_sched_rr_get_interval */
+ case 334:
+ switch(ndx) {
+ case 0:
+ p = "pid_t";
+ break;
+ case 1:
+ p = "userland struct timespec32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* utrace */
+ case 335:
+ switch(ndx) {
+ case 0:
+ p = "userland const void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* kldsym */
+ case 337:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland void *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_jail */
+ case 338:
+ switch(ndx) {
+ case 0:
+ p = "userland struct jail32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* sigprocmask */
+ case 340:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const sigset_t *";
+ break;
+ case 2:
+ p = "userland sigset_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* sigsuspend */
+ case 341:
+ switch(ndx) {
+ case 0:
+ p = "userland const sigset_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* sigpending */
+ case 343:
+ switch(ndx) {
+ case 0:
+ p = "userland sigset_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_sigtimedwait */
+ case 345:
+ switch(ndx) {
+ case 0:
+ p = "userland const sigset_t *";
+ break;
+ case 1:
+ p = "userland siginfo_t *";
+ break;
+ case 2:
+ p = "userland const struct timespec *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_sigwaitinfo */
+ case 346:
+ switch(ndx) {
+ case 0:
+ p = "userland const sigset_t *";
+ break;
+ case 1:
+ p = "userland siginfo_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* __acl_get_file */
+ case 347:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "acl_type_t";
+ break;
+ case 2:
+ p = "userland struct acl *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* __acl_set_file */
+ case 348:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "acl_type_t";
+ break;
+ case 2:
+ p = "userland struct acl *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* __acl_get_fd */
+ case 349:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "acl_type_t";
+ break;
+ case 2:
+ p = "userland struct acl *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* __acl_set_fd */
+ case 350:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "acl_type_t";
+ break;
+ case 2:
+ p = "userland struct acl *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* __acl_delete_file */
+ case 351:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "acl_type_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* __acl_delete_fd */
+ case 352:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "acl_type_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* __acl_aclcheck_file */
+ case 353:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "acl_type_t";
+ break;
+ case 2:
+ p = "userland struct acl *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* __acl_aclcheck_fd */
+ case 354:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "acl_type_t";
+ break;
+ case 2:
+ p = "userland struct acl *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* extattrctl */
+ case 355:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland const char *";
+ break;
+ case 3:
+ p = "int";
+ break;
+ case 4:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* extattr_set_file */
+ case 356:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland const char *";
+ break;
+ case 3:
+ p = "userland void *";
+ break;
+ case 4:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* extattr_get_file */
+ case 357:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland const char *";
+ break;
+ case 3:
+ p = "userland void *";
+ break;
+ case 4:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* extattr_delete_file */
+ case 358:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_aio_waitcomplete */
+ case 359:
+ switch(ndx) {
+ case 0:
+ p = "userland struct aiocb32 **";
+ break;
+ case 1:
+ p = "userland struct timespec32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getresuid */
+ case 360:
+ switch(ndx) {
+ case 0:
+ p = "userland uid_t *";
+ break;
+ case 1:
+ p = "userland uid_t *";
+ break;
+ case 2:
+ p = "userland uid_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getresgid */
+ case 361:
+ switch(ndx) {
+ case 0:
+ p = "userland gid_t *";
+ break;
+ case 1:
+ p = "userland gid_t *";
+ break;
+ case 2:
+ p = "userland gid_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* kqueue */
+ case 362:
+ break;
+ /* extattr_set_fd */
+ case 371:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland const char *";
+ break;
+ case 3:
+ p = "userland void *";
+ break;
+ case 4:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* extattr_get_fd */
+ case 372:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland const char *";
+ break;
+ case 3:
+ p = "userland void *";
+ break;
+ case 4:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* extattr_delete_fd */
+ case 373:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* __setugid */
+ case 374:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* eaccess */
+ case 376:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_nmount */
+ case 378:
+ switch(ndx) {
+ case 0:
+ p = "userland struct iovec32 *";
+ break;
+ case 1:
+ p = "unsigned int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* kenv */
+ case 390:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "userland char *";
+ break;
+ case 3:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* lchflags */
+ case 391:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "u_long";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* uuidgen */
+ case 392:
+ switch(ndx) {
+ case 0:
+ p = "userland struct uuid *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_sendfile */
+ case 393:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ case 3:
+ p = "uint32_t";
+ break;
+ case 4:
+ p = "size_t";
+ break;
+ case 5:
+ p = "userland struct sf_hdtr32 *";
+ break;
+ case 6:
+ p = "userland off_t *";
+ break;
+ case 7:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* ksem_close */
+ case 400:
+ switch(ndx) {
+ case 0:
+ p = "semid_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* ksem_post */
+ case 401:
+ switch(ndx) {
+ case 0:
+ p = "semid_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* ksem_wait */
+ case 402:
+ switch(ndx) {
+ case 0:
+ p = "semid_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* ksem_trywait */
+ case 403:
+ switch(ndx) {
+ case 0:
+ p = "semid_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_ksem_init */
+ case 404:
+ switch(ndx) {
+ case 0:
+ p = "userland semid_t *";
+ break;
+ case 1:
+ p = "unsigned int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_ksem_open */
+ case 405:
+ switch(ndx) {
+ case 0:
+ p = "userland semid_t *";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "mode_t";
+ break;
+ case 4:
+ p = "unsigned int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* ksem_unlink */
+ case 406:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* ksem_getvalue */
+ case 407:
+ switch(ndx) {
+ case 0:
+ p = "semid_t";
+ break;
+ case 1:
+ p = "userland int *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* ksem_destroy */
+ case 408:
+ switch(ndx) {
+ case 0:
+ p = "semid_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* extattr_set_link */
+ case 412:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland const char *";
+ break;
+ case 3:
+ p = "userland void *";
+ break;
+ case 4:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* extattr_get_link */
+ case 413:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland const char *";
+ break;
+ case 3:
+ p = "userland void *";
+ break;
+ case 4:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* extattr_delete_link */
+ case 414:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_sigaction */
+ case 416:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct sigaction32 *";
+ break;
+ case 2:
+ p = "userland struct sigaction32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_sigreturn */
+ case 417:
+ switch(ndx) {
+ case 0:
+ p = "userland const struct freebsd32_ucontext *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_getcontext */
+ case 421:
+ switch(ndx) {
+ case 0:
+ p = "userland struct freebsd32_ucontext *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_setcontext */
+ case 422:
+ switch(ndx) {
+ case 0:
+ p = "userland const struct freebsd32_ucontext *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_swapcontext */
+ case 423:
+ switch(ndx) {
+ case 0:
+ p = "userland struct freebsd32_ucontext *";
+ break;
+ case 1:
+ p = "userland const struct freebsd32_ucontext *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* __acl_get_link */
+ case 425:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "acl_type_t";
+ break;
+ case 2:
+ p = "userland struct acl *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* __acl_set_link */
+ case 426:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "acl_type_t";
+ break;
+ case 2:
+ p = "userland struct acl *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* __acl_delete_link */
+ case 427:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "acl_type_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* __acl_aclcheck_link */
+ case 428:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "acl_type_t";
+ break;
+ case 2:
+ p = "userland struct acl *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* sigwait */
+ case 429:
+ switch(ndx) {
+ case 0:
+ p = "userland const sigset_t *";
+ break;
+ case 1:
+ p = "userland int *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* thr_exit */
+ case 431:
+ switch(ndx) {
+ case 0:
+ p = "userland long *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* thr_self */
+ case 432:
+ switch(ndx) {
+ case 0:
+ p = "userland long *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* thr_kill */
+ case 433:
+ switch(ndx) {
+ case 0:
+ p = "long";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* jail_attach */
+ case 436:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* extattr_list_fd */
+ case 437:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland void *";
+ break;
+ case 3:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* extattr_list_file */
+ case 438:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland void *";
+ break;
+ case 3:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* extattr_list_link */
+ case 439:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland void *";
+ break;
+ case 3:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_ksem_timedwait */
+ case 441:
+ switch(ndx) {
+ case 0:
+ p = "semid_t";
+ break;
+ case 1:
+ p = "userland const struct timespec32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_thr_suspend */
+ case 442:
+ switch(ndx) {
+ case 0:
+ p = "userland const struct timespec32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* thr_wake */
+ case 443:
+ switch(ndx) {
+ case 0:
+ p = "long";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* kldunloadf */
+ case 444:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* audit */
+ case 445:
+ switch(ndx) {
+ case 0:
+ p = "userland const void *";
+ break;
+ case 1:
+ p = "u_int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* auditon */
+ case 446:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland void *";
+ break;
+ case 2:
+ p = "u_int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getauid */
+ case 447:
+ switch(ndx) {
+ case 0:
+ p = "userland uid_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* setauid */
+ case 448:
+ switch(ndx) {
+ case 0:
+ p = "userland uid_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getaudit */
+ case 449:
+ switch(ndx) {
+ case 0:
+ p = "userland struct auditinfo *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* setaudit */
+ case 450:
+ switch(ndx) {
+ case 0:
+ p = "userland struct auditinfo *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getaudit_addr */
+ case 451:
+ switch(ndx) {
+ case 0:
+ p = "userland struct auditinfo_addr *";
+ break;
+ case 1:
+ p = "u_int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* setaudit_addr */
+ case 452:
+ switch(ndx) {
+ case 0:
+ p = "userland struct auditinfo_addr *";
+ break;
+ case 1:
+ p = "u_int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* auditctl */
+ case 453:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32__umtx_op */
+ case 454:
+ switch(ndx) {
+ case 0:
+ p = "userland void *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "u_long";
+ break;
+ case 3:
+ p = "userland void *";
+ break;
+ case 4:
+ p = "userland void *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_thr_new */
+ case 455:
+ switch(ndx) {
+ case 0:
+ p = "userland struct thr_param32 *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_sigqueue */
+ case 456:
+ switch(ndx) {
+ case 0:
+ p = "pid_t";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_kmq_open */
+ case 457:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "mode_t";
+ break;
+ case 3:
+ p = "userland const struct mq_attr32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_kmq_setattr */
+ case 458:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const struct mq_attr32 *";
+ break;
+ case 2:
+ p = "userland struct mq_attr32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_kmq_timedreceive */
+ case 459:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland char *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "userland unsigned *";
+ break;
+ case 4:
+ p = "userland const struct timespec32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_kmq_timedsend */
+ case 460:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "unsigned";
+ break;
+ case 4:
+ p = "userland const struct timespec32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_kmq_notify */
+ case 461:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const struct sigevent32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* kmq_unlink */
+ case 462:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* abort2 */
+ case 463:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland void **";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* thr_set_name */
+ case 464:
+ switch(ndx) {
+ case 0:
+ p = "long";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_aio_fsync */
+ case 465:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct aiocb32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* rtprio_thread */
+ case 466:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "lwpid_t";
+ break;
+ case 2:
+ p = "userland struct rtprio *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* sctp_peeloff */
+ case 471:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* sctp_generic_sendmsg */
+ case 472:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland void *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "userland struct sockaddr *";
+ break;
+ case 4:
+ p = "__socklen_t";
+ break;
+ case 5:
+ p = "userland struct sctp_sndrcvinfo *";
+ break;
+ case 6:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* sctp_generic_sendmsg_iov */
+ case 473:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct iovec *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "userland struct sockaddr *";
+ break;
+ case 4:
+ p = "__socklen_t";
+ break;
+ case 5:
+ p = "userland struct sctp_sndrcvinfo *";
+ break;
+ case 6:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* sctp_generic_recvmsg */
+ case 474:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct iovec *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "userland struct sockaddr *";
+ break;
+ case 4:
+ p = "userland __socklen_t *";
+ break;
+ case 5:
+ p = "userland struct sctp_sndrcvinfo *";
+ break;
+ case 6:
+ p = "userland int *";
+ break;
+ default:
+ break;
+ };
+ break;
+#ifdef PAD64_REQUIRED
+ /* freebsd32_pread */
+ case 475:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland void *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "int";
+ break;
+ case 4:
+ p = "uint32_t";
+ break;
+ case 5:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_pwrite */
+ case 476:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const void *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "int";
+ break;
+ case 4:
+ p = "uint32_t";
+ break;
+ case 5:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_mmap */
+ case 477:
+ switch(ndx) {
+ case 0:
+ p = "userland void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "int";
+ break;
+ case 4:
+ p = "int";
+ break;
+ case 5:
+ p = "int";
+ break;
+ case 6:
+ p = "uint32_t";
+ break;
+ case 7:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_lseek */
+ case 478:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ case 3:
+ p = "uint32_t";
+ break;
+ case 4:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_truncate */
+ case 479:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ case 3:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_ftruncate */
+ case 480:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ case 3:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
+ break;
+#else
+ /* freebsd32_pread */
+ case 475:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland void *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "uint32_t";
+ break;
+ case 4:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_pwrite */
+ case 476:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const void *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "uint32_t";
+ break;
+ case 4:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_mmap */
+ case 477:
+ switch(ndx) {
+ case 0:
+ p = "userland void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "int";
+ break;
+ case 4:
+ p = "int";
+ break;
+ case 5:
+ p = "uint32_t";
+ break;
+ case 6:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_lseek */
+ case 478:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "uint32_t";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ case 3:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_truncate */
+ case 479:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "uint32_t";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_ftruncate */
+ case 480:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "uint32_t";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
+ break;
+#endif
+ /* thr_kill2 */
+ case 481:
+ switch(ndx) {
+ case 0:
+ p = "pid_t";
+ break;
+ case 1:
+ p = "long";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* shm_unlink */
+ case 483:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cpuset */
+ case 484:
+ switch(ndx) {
+ case 0:
+ p = "userland cpusetid_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+#ifdef PAD64_REQUIRED
+ /* freebsd32_cpuset_setid */
+ case 485:
+ switch(ndx) {
+ case 0:
+ p = "cpuwhich_t";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ case 3:
+ p = "uint32_t";
+ break;
+ case 4:
+ p = "cpusetid_t";
+ break;
+ default:
+ break;
+ };
+ break;
+#else
+ /* freebsd32_cpuset_setid */
+ case 485:
+ switch(ndx) {
+ case 0:
+ p = "cpuwhich_t";
+ break;
+ case 1:
+ p = "uint32_t";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ case 3:
+ p = "cpusetid_t";
+ break;
+ default:
+ break;
+ };
+ break;
+#endif
+ /* freebsd32_cpuset_getid */
+ case 486:
+ switch(ndx) {
+ case 0:
+ p = "cpulevel_t";
+ break;
+ case 1:
+ p = "cpuwhich_t";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ case 3:
+ p = "uint32_t";
+ break;
+ case 4:
+ p = "userland cpusetid_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_cpuset_getaffinity */
+ case 487:
+ switch(ndx) {
+ case 0:
+ p = "cpulevel_t";
+ break;
+ case 1:
+ p = "cpuwhich_t";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ case 3:
+ p = "uint32_t";
+ break;
+ case 4:
+ p = "size_t";
+ break;
+ case 5:
+ p = "userland cpuset_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_cpuset_setaffinity */
+ case 488:
+ switch(ndx) {
+ case 0:
+ p = "cpulevel_t";
+ break;
+ case 1:
+ p = "cpuwhich_t";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ case 3:
+ p = "uint32_t";
+ break;
+ case 4:
+ p = "size_t";
+ break;
+ case 5:
+ p = "userland const cpuset_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* faccessat */
+ case 489:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* fchmodat */
+ case 490:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "mode_t";
+ break;
+ case 3:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* fchownat */
+ case 491:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "uid_t";
+ break;
+ case 3:
+ p = "gid_t";
+ break;
+ case 4:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_fexecve */
+ case 492:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland uint32_t *";
+ break;
+ case 2:
+ p = "userland uint32_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_futimesat */
+ case 494:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "userland struct timeval *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* linkat */
+ case 495:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "userland const char *";
+ break;
+ case 4:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* mkdirat */
+ case 496:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "mode_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* mkfifoat */
+ case 497:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "mode_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* openat */
+ case 499:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "mode_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* readlinkat */
+ case 500:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "userland char *";
+ break;
+ case 3:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* renameat */
+ case 501:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* symlinkat */
+ case 502:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* unlinkat */
+ case 503:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* posix_openpt */
+ case 504:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_jail_get */
+ case 506:
+ switch(ndx) {
+ case 0:
+ p = "userland struct iovec32 *";
+ break;
+ case 1:
+ p = "unsigned int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_jail_set */
+ case 507:
+ switch(ndx) {
+ case 0:
+ p = "userland struct iovec32 *";
+ break;
+ case 1:
+ p = "unsigned int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* jail_remove */
+ case 508:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_semctl */
+ case 510:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "userland union semun32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_msgctl */
+ case 511:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland struct msqid_ds32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_shmctl */
+ case 512:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland struct shmid_ds32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* lpathconf */
+ case 513:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* __cap_rights_get */
+ case 515:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland cap_rights_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cap_enter */
+ case 516:
+ break;
+ /* cap_getmode */
+ case 517:
+ switch(ndx) {
+ case 0:
+ p = "userland u_int *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* pdfork */
+ case 518:
+ switch(ndx) {
+ case 0:
+ p = "userland int *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* pdkill */
+ case 519:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* pdgetpid */
+ case 520:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland pid_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_pselect */
+ case 522:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland fd_set *";
+ break;
+ case 2:
+ p = "userland fd_set *";
+ break;
+ case 3:
+ p = "userland fd_set *";
+ break;
+ case 4:
+ p = "userland const struct timespec32 *";
+ break;
+ case 5:
+ p = "userland const sigset_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getloginclass */
+ case 523:
+ switch(ndx) {
+ case 0:
+ p = "userland char *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* setloginclass */
+ case 524:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* rctl_get_racct */
+ case 525:
+ switch(ndx) {
+ case 0:
+ p = "userland const void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "userland void *";
+ break;
+ case 3:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* rctl_get_rules */
+ case 526:
+ switch(ndx) {
+ case 0:
+ p = "userland const void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "userland void *";
+ break;
+ case 3:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* rctl_get_limits */
+ case 527:
+ switch(ndx) {
+ case 0:
+ p = "userland const void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "userland void *";
+ break;
+ case 3:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* rctl_add_rule */
+ case 528:
+ switch(ndx) {
+ case 0:
+ p = "userland const void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "userland void *";
+ break;
+ case 3:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* rctl_remove_rule */
+ case 529:
+ switch(ndx) {
+ case 0:
+ p = "userland const void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "userland void *";
+ break;
+ case 3:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+#ifdef PAD64_REQUIRED
+ /* freebsd32_posix_fallocate */
+ case 530:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ case 3:
+ p = "uint32_t";
+ break;
+ case 4:
+ p = "uint32_t";
+ break;
+ case 5:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_posix_fadvise */
+ case 531:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ case 3:
+ p = "uint32_t";
+ break;
+ case 4:
+ p = "uint32_t";
+ break;
+ case 5:
+ p = "uint32_t";
+ break;
+ case 6:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_wait6 */
+ case 532:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ case 3:
+ p = "uint32_t";
+ break;
+ case 4:
+ p = "userland int *";
+ break;
+ case 5:
+ p = "int";
+ break;
+ case 6:
+ p = "userland struct wrusage32 *";
+ break;
+ case 7:
+ p = "userland siginfo_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+#else
+ /* freebsd32_posix_fallocate */
+ case 530:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "uint32_t";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ case 3:
+ p = "uint32_t";
+ break;
+ case 4:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_posix_fadvise */
+ case 531:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "uint32_t";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ case 3:
+ p = "uint32_t";
+ break;
+ case 4:
+ p = "uint32_t";
+ break;
+ case 5:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_wait6 */
+ case 532:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "uint32_t";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ case 3:
+ p = "userland int *";
+ break;
+ case 4:
+ p = "int";
+ break;
+ case 5:
+ p = "userland struct wrusage32 *";
+ break;
+ case 6:
+ p = "userland siginfo_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+#endif
+ /* cap_rights_limit */
+ case 533:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland cap_rights_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_cap_ioctls_limit */
+ case 534:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const uint32_t *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_cap_ioctls_get */
+ case 535:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland uint32_t *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cap_fcntls_limit */
+ case 536:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* cap_fcntls_get */
+ case 537:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland uint32_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* bindat */
+ case 538:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland const struct sockaddr *";
+ break;
+ case 3:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* connectat */
+ case 539:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland const struct sockaddr *";
+ break;
+ case 3:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* chflagsat */
+ case 540:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "u_long";
+ break;
+ case 3:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* accept4 */
+ case 541:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct sockaddr *";
+ break;
+ case 2:
+ p = "userland __socklen_t *";
+ break;
+ case 3:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* pipe2 */
+ case 542:
+ switch(ndx) {
+ case 0:
+ p = "userland int *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_aio_mlock */
+ case 543:
+ switch(ndx) {
+ case 0:
+ p = "userland struct aiocb32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+#ifdef PAD64_REQUIRED
+ /* freebsd32_procctl */
+ case 544:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ case 3:
+ p = "uint32_t";
+ break;
+ case 4:
+ p = "int";
+ break;
+ case 5:
+ p = "userland void *";
+ break;
+ default:
+ break;
+ };
+ break;
+#else
+ /* freebsd32_procctl */
+ case 544:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "uint32_t";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ case 3:
+ p = "int";
+ break;
+ case 4:
+ p = "userland void *";
+ break;
+ default:
+ break;
+ };
+ break;
+#endif
+ /* freebsd32_ppoll */
+ case 545:
+ switch(ndx) {
+ case 0:
+ p = "userland struct pollfd *";
+ break;
+ case 1:
+ p = "u_int";
+ break;
+ case 2:
+ p = "userland const struct timespec32 *";
+ break;
+ case 3:
+ p = "userland const sigset_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_futimens */
+ case 546:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct timespec *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_utimensat */
+ case 547:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "userland struct timespec *";
+ break;
+ case 3:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* fdatasync */
+ case 550:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_fstat */
+ case 551:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct stat32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_fstatat */
+ case 552:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "userland struct stat32 *";
+ break;
+ case 3:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_fhstat */
+ case 553:
+ switch(ndx) {
+ case 0:
+ p = "userland const struct fhandle *";
+ break;
+ case 1:
+ p = "userland struct stat32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getdirentries */
+ case 554:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland char *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ case 3:
+ p = "userland off_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* statfs */
+ case 555:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "userland struct statfs32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* fstatfs */
+ case 556:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct statfs32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getfsstat */
+ case 557:
+ switch(ndx) {
+ case 0:
+ p = "userland struct statfs32 *";
+ break;
+ case 1:
+ p = "long";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* fhstatfs */
+ case 558:
+ switch(ndx) {
+ case 0:
+ p = "userland const struct fhandle *";
+ break;
+ case 1:
+ p = "userland struct statfs32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+#ifdef PAD64_REQUIRED
+ /* freebsd32_mknodat */
+ case 559:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "mode_t";
+ break;
+ case 3:
+ p = "int";
+ break;
+ case 4:
+ p = "uint32_t";
+ break;
+ case 5:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
+ break;
+#else
+ /* freebsd32_mknodat */
+ case 559:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "mode_t";
+ break;
+ case 3:
+ p = "uint32_t";
+ break;
+ case 4:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
+ break;
+#endif
+ /* freebsd32_kevent */
+ case 560:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const struct kevent32 *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "userland struct kevent32 *";
+ break;
+ case 4:
+ p = "int";
+ break;
+ case 5:
+ p = "userland const struct timespec32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_cpuset_getdomain */
+ case 561:
+ switch(ndx) {
+ case 0:
+ p = "cpulevel_t";
+ break;
+ case 1:
+ p = "cpuwhich_t";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ case 3:
+ p = "uint32_t";
+ break;
+ case 4:
+ p = "size_t";
+ break;
+ case 5:
+ p = "userland domainset_t *";
+ break;
+ case 6:
+ p = "userland int *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_cpuset_setdomain */
+ case 562:
+ switch(ndx) {
+ case 0:
+ p = "cpulevel_t";
+ break;
+ case 1:
+ p = "cpuwhich_t";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ case 3:
+ p = "uint32_t";
+ break;
+ case 4:
+ p = "size_t";
+ break;
+ case 5:
+ p = "userland domainset_t *";
+ break;
+ case 6:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getrandom */
+ case 563:
+ switch(ndx) {
+ case 0:
+ p = "userland void *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "unsigned int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* getfhat */
+ case 564:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland char *";
+ break;
+ case 2:
+ p = "userland struct fhandle *";
+ break;
+ case 3:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* fhlink */
+ case 565:
+ switch(ndx) {
+ case 0:
+ p = "userland struct fhandle *";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* fhlinkat */
+ case 566:
+ switch(ndx) {
+ case 0:
+ p = "userland struct fhandle *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* fhreadlink */
+ case 567:
+ switch(ndx) {
+ case 0:
+ p = "userland struct fhandle *";
+ break;
+ case 1:
+ p = "userland char *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* funlinkat */
+ case 568:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* copy_file_range */
+ case 569:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland off_t *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "userland off_t *";
+ break;
+ case 4:
+ p = "size_t";
+ break;
+ case 5:
+ p = "unsigned int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32___sysctlbyname */
+ case 570:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "userland void *";
+ break;
+ case 3:
+ p = "userland uint32_t *";
+ break;
+ case 4:
+ p = "userland void *";
+ break;
+ case 5:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* shm_open2 */
+ case 571:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "mode_t";
+ break;
+ case 3:
+ p = "int";
+ break;
+ case 4:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* shm_rename */
+ case 572:
+ switch(ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* sigfastblock */
+ case 573:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland uint32_t *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* __realpathat */
+ case 574:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "userland char *";
+ break;
+ case 3:
+ p = "size_t";
+ break;
+ case 4:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* close_range */
+ case 575:
+ switch(ndx) {
+ case 0:
+ p = "u_int";
+ break;
+ case 1:
+ p = "u_int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* rpctls_syscall */
+ case 576:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* __specialfd */
+ case 577:
+ switch(ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const void *";
+ break;
+ case 2:
+ p = "size_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_aio_writev */
+ case 578:
+ switch(ndx) {
+ case 0:
+ p = "userland struct aiocb32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_aio_readv */
+ case 579:
+ switch(ndx) {
+ case 0:
+ p = "userland struct aiocb32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ default:
+ break;
+ };
+ if (p != NULL)
+ strlcpy(desc, p, descsz);
+}
+static void
+systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
+{
+ const char *p = NULL;
+ switch (sysnum) {
+#if !defined(PAD64_REQUIRED) && !defined(__amd64__)
+#define PAD64_REQUIRED
+#endif
+ /* nosys */
+ case 0:
+ /* sys_exit */
+ case 1:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* fork */
+ case 2:
+ /* read */
+ case 3:
+ if (ndx == 0 || ndx == 1)
+ p = "ssize_t";
+ break;
+ /* write */
+ case 4:
+ if (ndx == 0 || ndx == 1)
+ p = "ssize_t";
+ break;
+ /* open */
+ case 5:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* close */
+ case 6:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_wait4 */
+ case 7:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* link */
+ case 9:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* unlink */
+ case 10:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* chdir */
+ case 12:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* fchdir */
+ case 13:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* chmod */
+ case 15:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* chown */
+ case 16:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* break */
+ case 17:
+ if (ndx == 0 || ndx == 1)
+ p = "void *";
+ break;
+ /* getpid */
+ case 20:
+ /* mount */
+ case 21:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* unmount */
+ case 22:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* setuid */
+ case 23:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* getuid */
+ case 24:
+ /* geteuid */
+ case 25:
+ /* freebsd32_ptrace */
+ case 26:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_recvmsg */
+ case 27:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_sendmsg */
+ case 28:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_recvfrom */
+ case 29:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* accept */
+ case 30:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* getpeername */
+ case 31:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* getsockname */
+ case 32:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* access */
+ case 33:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* chflags */
+ case 34:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* fchflags */
+ case 35:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* sync */
+ case 36:
+ /* kill */
+ case 37:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* getppid */
+ case 39:
+ /* dup */
+ case 41:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* getegid */
+ case 43:
+ /* profil */
+ case 44:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* ktrace */
+ case 45:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* getgid */
+ case 47:
+ /* getlogin */
+ case 49:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* setlogin */
+ case 50:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* acct */
+ case 51:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_sigaltstack */
+ case 53:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_ioctl */
+ case 54:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* reboot */
+ case 55:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* revoke */
+ case 56:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* symlink */
+ case 57:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* readlink */
+ case 58:
+ if (ndx == 0 || ndx == 1)
+ p = "ssize_t";
+ break;
+ /* freebsd32_execve */
+ case 59:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* umask */
+ case 60:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* chroot */
+ case 61:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* msync */
+ case 65:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* vfork */
+ case 66:
+ /* sbrk */
+ case 69:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* sstk */
+ case 70:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* munmap */
+ case 73:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_mprotect */
+ case 74:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* madvise */
+ case 75:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* mincore */
+ case 78:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* getgroups */
+ case 79:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* setgroups */
+ case 80:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* getpgrp */
+ case 81:
+ /* setpgid */
+ case 82:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_setitimer */
+ case 83:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* swapon */
+ case 85:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_getitimer */
+ case 86:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* getdtablesize */
+ case 89:
+ /* dup2 */
+ case 90:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_fcntl */
+ case 92:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_select */
+ case 93:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* fsync */
+ case 95:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* setpriority */
+ case 96:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* socket */
+ case 97:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* connect */
+ case 98:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* getpriority */
+ case 100:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* bind */
+ case 104:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* setsockopt */
+ case 105:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* listen */
+ case 106:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_gettimeofday */
+ case 116:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_getrusage */
+ case 117:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* getsockopt */
+ case 118:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_readv */
+ case 120:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_writev */
+ case 121:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_settimeofday */
+ case 122:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* fchown */
+ case 123:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* fchmod */
+ case 124:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* setreuid */
+ case 126:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* setregid */
+ case 127:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* rename */
+ case 128:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* flock */
+ case 131:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* mkfifo */
+ case 132:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* sendto */
+ case 133:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* shutdown */
+ case 134:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* socketpair */
+ case 135:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* mkdir */
+ case 136:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* rmdir */
+ case 137:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_utimes */
+ case 138:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_adjtime */
+ case 140:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* setsid */
+ case 147:
+ /* quotactl */
+ case 148:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* getfh */
+ case 161:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_sysarch */
+ case 165:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* rtprio */
+ case 166:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_semsys */
+ case 169:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_msgsys */
+ case 170:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_shmsys */
+ case 171:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_ntp_adjtime */
+ case 176:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* setgid */
+ case 181:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* setegid */
+ case 182:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* seteuid */
+ case 183:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* pathconf */
+ case 191:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* fpathconf */
+ case 192:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* getrlimit */
+ case 194:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* setrlimit */
+ case 195:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* nosys */
+ case 198:
+ /* freebsd32___sysctl */
+ case 202:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* mlock */
+ case 203:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* munlock */
+ case 204:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* undelete */
+ case 205:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_futimes */
+ case 206:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* getpgid */
+ case 207:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* poll */
+ case 209:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* lkmnosys */
+ case 210:
+ /* lkmnosys */
+ case 211:
+ /* lkmnosys */
+ case 212:
+ /* lkmnosys */
+ case 213:
+ /* lkmnosys */
+ case 214:
+ /* lkmnosys */
+ case 215:
+ /* lkmnosys */
+ case 216:
+ /* lkmnosys */
+ case 217:
+ /* lkmnosys */
+ case 218:
+ /* lkmnosys */
+ case 219:
+ /* semget */
+ case 221:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* semop */
+ case 222:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* msgget */
+ case 225:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_msgsnd */
+ case 226:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_msgrcv */
+ case 227:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* shmat */
+ case 228:
+ if (ndx == 0 || ndx == 1)
+ p = "void *";
+ break;
+ /* shmdt */
+ case 230:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* shmget */
+ case 231:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_clock_gettime */
+ case 232:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_clock_settime */
+ case 233:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_clock_getres */
+ case 234:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_ktimer_create */
+ case 235:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* ktimer_delete */
+ case 236:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_ktimer_settime */
+ case 237:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_ktimer_gettime */
+ case 238:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* ktimer_getoverrun */
+ case 239:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_nanosleep */
+ case 240:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* ffclock_getcounter */
+ case 241:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* ffclock_setestimate */
+ case 242:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* ffclock_getestimate */
+ case 243:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_clock_nanosleep */
+ case 244:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_clock_getcpuclockid2 */
+ case 247:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* minherit */
+ case 250:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* rfork */
+ case 251:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* issetugid */
+ case 253:
+ /* lchown */
+ case 254:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_aio_read */
+ case 255:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_aio_write */
+ case 256:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_lio_listio */
+ case 257:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* lchmod */
+ case 274:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_lutimes */
+ case 276:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_preadv */
+ case 289:
+ if (ndx == 0 || ndx == 1)
+ p = "ssize_t";
+ break;
+ /* freebsd32_pwritev */
+ case 290:
+ if (ndx == 0 || ndx == 1)
+ p = "ssize_t";
+ break;
+ /* fhopen */
+ case 298:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* modnext */
+ case 300:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_modstat */
+ case 301:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* modfnext */
+ case 302:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* modfind */
+ case 303:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* kldload */
+ case 304:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* kldunload */
+ case 305:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* kldfind */
+ case 306:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* kldnext */
+ case 307:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_kldstat */
+ case 308:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* kldfirstmod */
+ case 309:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* getsid */
+ case 310:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* setresuid */
+ case 311:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* setresgid */
+ case 312:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_aio_return */
+ case 314:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_aio_suspend */
+ case 315:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* aio_cancel */
+ case 316:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_aio_error */
+ case 317:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* yield */
+ case 321:
+ /* mlockall */
+ case 324:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* munlockall */
+ case 325:
+ /* __getcwd */
+ case 326:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* sched_setparam */
+ case 327:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* sched_getparam */
+ case 328:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* sched_setscheduler */
+ case 329:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* sched_getscheduler */
+ case 330:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* sched_yield */
+ case 331:
+ /* sched_get_priority_max */
+ case 332:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* sched_get_priority_min */
+ case 333:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_sched_rr_get_interval */
+ case 334:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* utrace */
+ case 335:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* kldsym */
+ case 337:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_jail */
+ case 338:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* sigprocmask */
+ case 340:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* sigsuspend */
+ case 341:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* sigpending */
+ case 343:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_sigtimedwait */
+ case 345:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_sigwaitinfo */
+ case 346:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* __acl_get_file */
+ case 347:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* __acl_set_file */
+ case 348:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* __acl_get_fd */
+ case 349:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* __acl_set_fd */
+ case 350:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* __acl_delete_file */
+ case 351:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* __acl_delete_fd */
+ case 352:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* __acl_aclcheck_file */
+ case 353:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* __acl_aclcheck_fd */
+ case 354:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* extattrctl */
+ case 355:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* extattr_set_file */
+ case 356:
+ if (ndx == 0 || ndx == 1)
+ p = "ssize_t";
+ break;
+ /* extattr_get_file */
+ case 357:
+ if (ndx == 0 || ndx == 1)
+ p = "ssize_t";
+ break;
+ /* extattr_delete_file */
+ case 358:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_aio_waitcomplete */
+ case 359:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* getresuid */
+ case 360:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* getresgid */
+ case 361:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* kqueue */
+ case 362:
+ /* extattr_set_fd */
+ case 371:
+ if (ndx == 0 || ndx == 1)
+ p = "ssize_t";
+ break;
+ /* extattr_get_fd */
+ case 372:
+ if (ndx == 0 || ndx == 1)
+ p = "ssize_t";
+ break;
+ /* extattr_delete_fd */
+ case 373:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* __setugid */
+ case 374:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* eaccess */
+ case 376:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_nmount */
+ case 378:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* kenv */
+ case 390:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* lchflags */
+ case 391:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* uuidgen */
+ case 392:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_sendfile */
+ case 393:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* ksem_close */
+ case 400:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* ksem_post */
+ case 401:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* ksem_wait */
+ case 402:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* ksem_trywait */
+ case 403:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_ksem_init */
+ case 404:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_ksem_open */
+ case 405:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* ksem_unlink */
+ case 406:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* ksem_getvalue */
+ case 407:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* ksem_destroy */
+ case 408:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* extattr_set_link */
+ case 412:
+ if (ndx == 0 || ndx == 1)
+ p = "ssize_t";
+ break;
+ /* extattr_get_link */
+ case 413:
+ if (ndx == 0 || ndx == 1)
+ p = "ssize_t";
+ break;
+ /* extattr_delete_link */
+ case 414:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_sigaction */
+ case 416:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_sigreturn */
+ case 417:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_getcontext */
+ case 421:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_setcontext */
+ case 422:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_swapcontext */
+ case 423:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* __acl_get_link */
+ case 425:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* __acl_set_link */
+ case 426:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* __acl_delete_link */
+ case 427:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* __acl_aclcheck_link */
+ case 428:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* sigwait */
+ case 429:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* thr_exit */
+ case 431:
+ if (ndx == 0 || ndx == 1)
+ p = "void";
+ break;
+ /* thr_self */
+ case 432:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* thr_kill */
+ case 433:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* jail_attach */
+ case 436:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* extattr_list_fd */
+ case 437:
+ if (ndx == 0 || ndx == 1)
+ p = "ssize_t";
+ break;
+ /* extattr_list_file */
+ case 438:
+ if (ndx == 0 || ndx == 1)
+ p = "ssize_t";
+ break;
+ /* extattr_list_link */
+ case 439:
+ if (ndx == 0 || ndx == 1)
+ p = "ssize_t";
+ break;
+ /* freebsd32_ksem_timedwait */
+ case 441:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_thr_suspend */
+ case 442:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* thr_wake */
+ case 443:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* kldunloadf */
+ case 444:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* audit */
+ case 445:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* auditon */
+ case 446:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* getauid */
+ case 447:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* setauid */
+ case 448:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* getaudit */
+ case 449:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* setaudit */
+ case 450:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* getaudit_addr */
+ case 451:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* setaudit_addr */
+ case 452:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* auditctl */
+ case 453:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32__umtx_op */
+ case 454:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_thr_new */
+ case 455:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_sigqueue */
+ case 456:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_kmq_open */
+ case 457:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_kmq_setattr */
+ case 458:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_kmq_timedreceive */
+ case 459:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_kmq_timedsend */
+ case 460:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_kmq_notify */
+ case 461:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* kmq_unlink */
+ case 462:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* abort2 */
+ case 463:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* thr_set_name */
+ case 464:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_aio_fsync */
+ case 465:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* rtprio_thread */
+ case 466:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* sctp_peeloff */
+ case 471:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* sctp_generic_sendmsg */
+ case 472:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* sctp_generic_sendmsg_iov */
+ case 473:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* sctp_generic_recvmsg */
+ case 474:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+#ifdef PAD64_REQUIRED
+ /* freebsd32_pread */
+ case 475:
+ if (ndx == 0 || ndx == 1)
+ p = "ssize_t";
+ break;
+ /* freebsd32_pwrite */
+ case 476:
+ if (ndx == 0 || ndx == 1)
+ p = "ssize_t";
+ break;
+ /* freebsd32_mmap */
+ case 477:
+ if (ndx == 0 || ndx == 1)
+ p = "void *";
+ break;
+ /* freebsd32_lseek */
+ case 478:
+ if (ndx == 0 || ndx == 1)
+ p = "off_t";
+ break;
+ /* freebsd32_truncate */
+ case 479:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_ftruncate */
+ case 480:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+#else
+ /* freebsd32_pread */
+ case 475:
+ if (ndx == 0 || ndx == 1)
+ p = "ssize_t";
+ break;
+ /* freebsd32_pwrite */
+ case 476:
+ if (ndx == 0 || ndx == 1)
+ p = "ssize_t";
+ break;
+ /* freebsd32_mmap */
+ case 477:
+ if (ndx == 0 || ndx == 1)
+ p = "void *";
+ break;
+ /* freebsd32_lseek */
+ case 478:
+ if (ndx == 0 || ndx == 1)
+ p = "off_t";
+ break;
+ /* freebsd32_truncate */
+ case 479:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_ftruncate */
+ case 480:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+#endif
+ /* thr_kill2 */
+ case 481:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* shm_unlink */
+ case 483:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* cpuset */
+ case 484:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+#ifdef PAD64_REQUIRED
+ /* freebsd32_cpuset_setid */
+ case 485:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+#else
+ /* freebsd32_cpuset_setid */
+ case 485:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+#endif
+ /* freebsd32_cpuset_getid */
+ case 486:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_cpuset_getaffinity */
+ case 487:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_cpuset_setaffinity */
+ case 488:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* faccessat */
+ case 489:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* fchmodat */
+ case 490:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* fchownat */
+ case 491:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_fexecve */
+ case 492:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_futimesat */
+ case 494:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* linkat */
+ case 495:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* mkdirat */
+ case 496:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* mkfifoat */
+ case 497:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* openat */
+ case 499:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* readlinkat */
+ case 500:
+ if (ndx == 0 || ndx == 1)
+ p = "ssize_t";
+ break;
+ /* renameat */
+ case 501:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* symlinkat */
+ case 502:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* unlinkat */
+ case 503:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* posix_openpt */
+ case 504:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_jail_get */
+ case 506:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_jail_set */
+ case 507:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* jail_remove */
+ case 508:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_semctl */
+ case 510:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_msgctl */
+ case 511:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_shmctl */
+ case 512:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* lpathconf */
+ case 513:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* __cap_rights_get */
+ case 515:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* cap_enter */
+ case 516:
+ /* cap_getmode */
+ case 517:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* pdfork */
+ case 518:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* pdkill */
+ case 519:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* pdgetpid */
+ case 520:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_pselect */
+ case 522:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* getloginclass */
+ case 523:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* setloginclass */
+ case 524:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* rctl_get_racct */
+ case 525:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* rctl_get_rules */
+ case 526:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* rctl_get_limits */
+ case 527:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* rctl_add_rule */
+ case 528:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* rctl_remove_rule */
+ case 529:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+#ifdef PAD64_REQUIRED
+ /* freebsd32_posix_fallocate */
+ case 530:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_posix_fadvise */
+ case 531:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_wait6 */
+ case 532:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+#else
+ /* freebsd32_posix_fallocate */
+ case 530:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_posix_fadvise */
+ case 531:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_wait6 */
+ case 532:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+#endif
+ /* cap_rights_limit */
+ case 533:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_cap_ioctls_limit */
+ case 534:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_cap_ioctls_get */
+ case 535:
+ if (ndx == 0 || ndx == 1)
+ p = "ssize_t";
+ break;
+ /* cap_fcntls_limit */
+ case 536:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* cap_fcntls_get */
+ case 537:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* bindat */
+ case 538:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* connectat */
+ case 539:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* chflagsat */
+ case 540:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* accept4 */
+ case 541:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* pipe2 */
+ case 542:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_aio_mlock */
+ case 543:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+#ifdef PAD64_REQUIRED
+ /* freebsd32_procctl */
+ case 544:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+#else
+ /* freebsd32_procctl */
+ case 544:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+#endif
+ /* freebsd32_ppoll */
+ case 545:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_futimens */
+ case 546:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_utimensat */
+ case 547:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* fdatasync */
+ case 550:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_fstat */
+ case 551:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_fstatat */
+ case 552:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_fhstat */
+ case 553:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* getdirentries */
+ case 554:
+ if (ndx == 0 || ndx == 1)
+ p = "ssize_t";
+ break;
+ /* statfs */
+ case 555:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* fstatfs */
+ case 556:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* getfsstat */
+ case 557:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* fhstatfs */
+ case 558:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+#ifdef PAD64_REQUIRED
+ /* freebsd32_mknodat */
+ case 559:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+#else
+ /* freebsd32_mknodat */
+ case 559:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+#endif
+ /* freebsd32_kevent */
+ case 560:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_cpuset_getdomain */
+ case 561:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_cpuset_setdomain */
+ case 562:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* getrandom */
+ case 563:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* getfhat */
+ case 564:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* fhlink */
+ case 565:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* fhlinkat */
+ case 566:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* fhreadlink */
+ case 567:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* funlinkat */
+ case 568:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* copy_file_range */
+ case 569:
+ if (ndx == 0 || ndx == 1)
+ p = "ssize_t";
+ break;
+ /* freebsd32___sysctlbyname */
+ case 570:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* shm_open2 */
+ case 571:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* shm_rename */
+ case 572:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* sigfastblock */
+ case 573:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* __realpathat */
+ case 574:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* close_range */
+ case 575:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* rpctls_syscall */
+ case 576:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* __specialfd */
+ case 577:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_aio_writev */
+ case 578:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_aio_readv */
+ case 579:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ if (p != NULL)
+ strlcpy(desc, p, descsz);
+}
diff --git a/sys/compat/freebsd32/freebsd32_util.h b/sys/compat/freebsd32/freebsd32_util.h
new file mode 100644
index 000000000000..b126fbde0857
--- /dev/null
+++ b/sys/compat/freebsd32/freebsd32_util.h
@@ -0,0 +1,127 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1998-1999 Andrew Gallatin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _COMPAT_FREEBSD32_FREEBSD32_UTIL_H_
+#define _COMPAT_FREEBSD32_FREEBSD32_UTIL_H_
+
+#include <sys/cdefs.h>
+#include <sys/exec.h>
+#include <sys/sysent.h>
+#include <sys/uio.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+
+struct freebsd32_ps_strings {
+ u_int32_t ps_argvstr; /* first of 0 or more argument strings */
+ int ps_nargvstr; /* the number of argument strings */
+ u_int32_t ps_envstr; /* first of 0 or more environment strings */
+ int ps_nenvstr; /* the number of environment strings */
+};
+
+#if defined(__amd64__)
+#include <compat/ia32/ia32_util.h>
+#endif
+
+#define FREEBSD32_PS_STRINGS \
+ (FREEBSD32_USRSTACK - sizeof(struct freebsd32_ps_strings))
+
+extern struct sysent freebsd32_sysent[];
+
+#define SYSCALL32_MODULE(name, offset, new_sysent, evh, arg) \
+static struct syscall_module_data name##_syscall32_mod = { \
+ evh, arg, offset, new_sysent, { 0, NULL } \
+}; \
+ \
+static moduledata_t name##32_mod = { \
+ "sys32/" #name, \
+ syscall32_module_handler, \
+ &name##_syscall32_mod \
+}; \
+DECLARE_MODULE(name##32, name##32_mod, SI_SUB_SYSCALLS, SI_ORDER_MIDDLE)
+
+#define SYSCALL32_MODULE_HELPER(syscallname) \
+static int syscallname##_syscall32 = FREEBSD32_SYS_##syscallname; \
+static struct sysent syscallname##_sysent32 = { \
+ (sizeof(struct syscallname ## _args ) \
+ / sizeof(register_t)), \
+ (sy_call_t *)& syscallname \
+}; \
+SYSCALL32_MODULE(syscallname, \
+ & syscallname##_syscall32, & syscallname##_sysent32,\
+ NULL, NULL);
+
+#define SYSCALL32_INIT_HELPER_F(syscallname, flags) { \
+ .new_sysent = { \
+ .sy_narg = (sizeof(struct syscallname ## _args ) \
+ / sizeof(register_t)), \
+ .sy_call = (sy_call_t *)& syscallname, \
+ .sy_flags = (flags) \
+ }, \
+ .syscall_no = FREEBSD32_SYS_##syscallname \
+}
+
+#define SYSCALL32_INIT_HELPER_COMPAT_F(syscallname, flags) { \
+ .new_sysent = { \
+ .sy_narg = (sizeof(struct syscallname ## _args ) \
+ / sizeof(register_t)), \
+ .sy_call = (sy_call_t *)& sys_ ## syscallname, \
+ .sy_flags = (flags) \
+ }, \
+ .syscall_no = FREEBSD32_SYS_##syscallname \
+}
+
+#define SYSCALL32_INIT_HELPER(syscallname) \
+ SYSCALL32_INIT_HELPER_F(syscallname, 0)
+#define SYSCALL32_INIT_HELPER_COMPAT(syscallname) \
+ SYSCALL32_INIT_HELPER_COMPAT_F(syscallname, 0)
+
+int syscall32_module_handler(struct module *mod, int what, void *arg);
+int syscall32_helper_register(struct syscall_helper_data *sd, int flags);
+int syscall32_helper_unregister(struct syscall_helper_data *sd);
+
+struct iovec32;
+struct rusage32;
+int freebsd32_copyout_strings(struct image_params *imgp,
+ uintptr_t *stack_base);
+int freebsd32_copyiniov(struct iovec32 *iovp, u_int iovcnt,
+ struct iovec **iov, int error);
+int freebsd32_copyinuio(struct iovec32 *iovp, u_int iovcnt,
+ struct uio **uiop);
+void freebsd32_rusage_out(const struct rusage *s, struct rusage32 *s32);
+
+struct image_args;
+int freebsd32_exec_copyin_args(struct image_args *args, const char *fname,
+ enum uio_seg segflg, u_int32_t *argv, u_int32_t *envv);
+
+#endif /* !_COMPAT_FREEBSD32_FREEBSD32_UTIL_H_ */
diff --git a/sys/compat/freebsd32/syscalls.conf b/sys/compat/freebsd32/syscalls.conf
new file mode 100644
index 000000000000..0b3d59f2fcf3
--- /dev/null
+++ b/sys/compat/freebsd32/syscalls.conf
@@ -0,0 +1,13 @@
+# $FreeBSD$
+sysnames="freebsd32_syscalls.c"
+sysproto="freebsd32_proto.h"
+sysproto_h=_FREEBSD32_SYSPROTO_H_
+syshdr="freebsd32_syscall.h"
+syssw="freebsd32_sysent.c"
+sysmk="/dev/null"
+syscallprefix="FREEBSD32_SYS_"
+switchname="freebsd32_sysent"
+namesname="freebsd32_syscallnames"
+systrace="freebsd32_systrace_args.c"
+abi_func_prefix="freebsd32_"
+capabilities_conf="../../kern/capabilities.conf"
diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master
new file mode 100644
index 000000000000..93d5a251d8ab
--- /dev/null
+++ b/sys/compat/freebsd32/syscalls.master
@@ -0,0 +1,1178 @@
+ $FreeBSD$
+; from: @(#)syscalls.master 8.2 (Berkeley) 1/13/94
+; from: src/sys/kern/syscalls.master 1.107
+;
+; System call name/number master file.
+; Processed to created init_sysent.c, syscalls.c and syscall.h.
+
+; Columns: number audit type name alt{name,tag,rtyp}/comments
+; number system call number, must be in order
+; audit the audit event associated with the system call
+; A value of AUE_NULL means no auditing, but it also means that
+; there is no audit event for the call at this time. For the
+; case where the event exists, but we don't want auditing, the
+; event should be #defined to AUE_NULL in audit_kevents.h.
+; type one of STD, OBSOL, UNIMPL, COMPAT, COMPAT4, COMPAT6,
+; COMPAT7, COMPAT11, COMPAT12, NODEF, NOARGS, NOPROTO, NOSTD
+; The COMPAT* options may be combined with one or more NO*
+; options separated by '|' with no spaces (e.g. COMPAT|NOARGS)
+; name pseudo-prototype of syscall routine
+; If one of the following alts is different, then all appear:
+; altname name of system call if different
+; alttag name of args struct tag if different from [o]`name'"_args"
+; altrtyp return type if not int (bogus - syscalls always return int)
+; for UNIMPL/OBSOL, name continues with comments
+
+; types:
+; STD always included
+; COMPAT included on COMPAT #ifdef
+; COMPAT4 included on COMPAT_FREEBSD4 #ifdef (FreeBSD 4 compat)
+; COMPAT6 included on COMPAT_FREEBSD6 #ifdef (FreeBSD 6 compat)
+; COMPAT7 included on COMPAT_FREEBSD7 #ifdef (FreeBSD 7 compat)
+; COMPAT10 included on COMPAT_FREEBSD10 #ifdef (FreeBSD 10 compat)
+; COMPAT11 included on COMPAT_FREEBSD11 #ifdef (FreeBSD 11 compat)
+; COMPAT12 included on COMPAT_FREEBSD12 #ifdef (FreeBSD 12 compat)
+; OBSOL obsolete, not included in system, only specifies name
+; UNIMPL not implemented, placeholder only
+; NOSTD implemented but as a lkm that can be statically
+; compiled in; sysent entry will be filled with lkmressys
+; so the SYSCALL_MODULE macro works
+; NOARGS same as STD except do not create structure in sys/sysproto.h
+; NODEF same as STD except only have the entry in the syscall table
+; added. Meaning - do not create structure or function
+; prototype in sys/sysproto.h
+; NOPROTO same as STD except do not create structure or
+; function prototype in sys/sysproto.h. Does add a
+; definition to syscall.h besides adding a sysent.
+
+; #ifdef's, etc. may be included, and are copied to the output files.
+
+#include <sys/param.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <compat/freebsd32/freebsd32.h>
+#include <compat/freebsd32/freebsd32_proto.h>
+
+#if !defined(PAD64_REQUIRED) && !defined(__amd64__)
+#define PAD64_REQUIRED
+#endif
+
+; Reserved/unimplemented system calls in the range 0-150 inclusive
+; are reserved for use in future Berkeley releases.
+; Additional system calls implemented in vendor and other
+; redistributions should be placed in the reserved range at the end
+; of the current calls.
+
+0 AUE_NULL NOPROTO { int nosys(void); } syscall nosys_args int
+1 AUE_EXIT NOPROTO { void sys_exit(int rval); } exit \
+ sys_exit_args void
+2 AUE_FORK NOPROTO { int fork(void); }
+3 AUE_READ NOPROTO { ssize_t read(int fd, void *buf, \
+ size_t nbyte); }
+4 AUE_WRITE NOPROTO { ssize_t write(int fd, const void *buf, \
+ size_t nbyte); }
+5 AUE_OPEN_RWTC NOPROTO { int open(const char *path, int flags, \
+ mode_t mode); }
+6 AUE_CLOSE NOPROTO { int close(int fd); }
+7 AUE_WAIT4 STD { int freebsd32_wait4(int pid, int *status, \
+ int options, struct rusage32 *rusage); }
+8 AUE_CREAT OBSOL old creat
+9 AUE_LINK NOPROTO { int link(const char *path, \
+ const char *link); }
+10 AUE_UNLINK NOPROTO { int unlink(const char *path); }
+11 AUE_NULL OBSOL execv
+12 AUE_CHDIR NOPROTO { int chdir(const char *path); }
+13 AUE_FCHDIR NOPROTO { int fchdir(int fd); }
+14 AUE_MKNOD COMPAT11|NOPROTO { int mknod(const char *path, \
+ int mode, uint32_t dev); }
+15 AUE_CHMOD NOPROTO { int chmod(const char *path, mode_t mode); }
+16 AUE_CHOWN NOPROTO { int chown(const char *path, int uid, int gid); }
+17 AUE_NULL NOPROTO { void *break(char *nsize); }
+18 AUE_GETFSSTAT COMPAT4 { int freebsd32_getfsstat( \
+ struct statfs32 *buf, long bufsize, \
+ int mode); }
+19 AUE_LSEEK COMPAT { int freebsd32_lseek(int fd, int offset, \
+ int whence); }
+20 AUE_GETPID NOPROTO { pid_t getpid(void); }
+21 AUE_MOUNT NOPROTO { int mount(const char *type, \
+ const char *path, \
+ int flags, void *data); }
+22 AUE_UMOUNT NOPROTO { int unmount(const char *path, int flags); }
+23 AUE_SETUID NOPROTO { int setuid(uid_t uid); }
+24 AUE_GETUID NOPROTO { uid_t getuid(void); }
+25 AUE_GETEUID NOPROTO { uid_t geteuid(void); }
+26 AUE_PTRACE STD { int freebsd32_ptrace(int req, pid_t pid, \
+ caddr_t addr, int data); }
+27 AUE_RECVMSG STD { int freebsd32_recvmsg(int s, struct msghdr32 *msg, \
+ int flags); }
+28 AUE_SENDMSG STD { int freebsd32_sendmsg(int s, struct msghdr32 *msg, \
+ int flags); }
+29 AUE_RECVFROM STD { int freebsd32_recvfrom(int s, void *buf, \
+ uint32_t len, int flags, \
+ struct sockaddr *from, \
+ uint32_t fromlenaddr); }
+30 AUE_ACCEPT NOPROTO { int accept(int s, struct sockaddr *name, \
+ int *anamelen); }
+31 AUE_GETPEERNAME NOPROTO { int getpeername(int fdes, \
+ struct sockaddr *asa, \
+ int *alen); }
+32 AUE_GETSOCKNAME NOPROTO { int getsockname(int fdes, \
+ struct sockaddr *asa, \
+ int *alen); }
+33 AUE_ACCESS NOPROTO { int access(const char *path, int amode); }
+34 AUE_CHFLAGS NOPROTO { int chflags(const char *path, u_long flags); }
+35 AUE_FCHFLAGS NOPROTO { int fchflags(int fd, u_long flags); }
+36 AUE_SYNC NOPROTO { int sync(void); }
+37 AUE_KILL NOPROTO { int kill(int pid, int signum); }
+38 AUE_STAT COMPAT { int freebsd32_stat(const char *path, \
+ struct ostat32 *ub); }
+39 AUE_GETPPID NOPROTO { pid_t getppid(void); }
+40 AUE_LSTAT COMPAT { int freebsd32_lstat(const char *path, \
+ struct ostat *ub); }
+41 AUE_DUP NOPROTO { int dup(u_int fd); }
+42 AUE_PIPE COMPAT10 { int freebsd32_pipe(void); }
+43 AUE_GETEGID NOPROTO { gid_t getegid(void); }
+44 AUE_PROFILE NOPROTO { int profil(char *samples, size_t size, \
+ size_t offset, u_int scale); }
+45 AUE_KTRACE NOPROTO { int ktrace(const char *fname, int ops, \
+ int facs, int pid); }
+46 AUE_SIGACTION COMPAT { int freebsd32_sigaction( int signum, \
+ struct osigaction32 *nsa, \
+ struct osigaction32 *osa); }
+47 AUE_GETGID NOPROTO { gid_t getgid(void); }
+48 AUE_SIGPROCMASK COMPAT { int freebsd32_sigprocmask(int how, \
+ osigset_t mask); }
+49 AUE_GETLOGIN NOPROTO { int getlogin(char *namebuf, \
+ u_int namelen); }
+50 AUE_SETLOGIN NOPROTO { int setlogin(const char *namebuf); }
+51 AUE_ACCT NOPROTO { int acct(const char *path); }
+52 AUE_SIGPENDING COMPAT { int freebsd32_sigpending(void); }
+53 AUE_SIGALTSTACK STD { int freebsd32_sigaltstack( \
+ struct sigaltstack32 *ss, \
+ struct sigaltstack32 *oss); }
+54 AUE_IOCTL STD { int freebsd32_ioctl(int fd, uint32_t com, \
+ struct md_ioctl32 *data); }
+55 AUE_REBOOT NOPROTO { int reboot(int opt); }
+56 AUE_REVOKE NOPROTO { int revoke(const char *path); }
+57 AUE_SYMLINK NOPROTO { int symlink(const char *path, \
+ const char *link); }
+58 AUE_READLINK NOPROTO { ssize_t readlink(const char *path, char *buf, \
+ size_t count); }
+59 AUE_EXECVE STD { int freebsd32_execve(const char *fname, \
+ uint32_t *argv, uint32_t *envv); }
+60 AUE_UMASK NOPROTO { int umask(mode_t newmask); }
+61 AUE_CHROOT NOPROTO { int chroot(const char *path); }
+62 AUE_FSTAT COMPAT { int freebsd32_fstat(int fd, \
+ struct ostat32 *ub); }
+63 AUE_NULL OBSOL ogetkerninfo
+64 AUE_NULL COMPAT { int freebsd32_getpagesize( \
+ int32_t dummy); }
+65 AUE_MSYNC NOPROTO { int msync(void *addr, size_t len, \
+ int flags); }
+66 AUE_VFORK NOPROTO { int vfork(void); }
+67 AUE_NULL OBSOL vread
+68 AUE_NULL OBSOL vwrite
+69 AUE_SBRK NOPROTO { int sbrk(int incr); }
+70 AUE_SSTK NOPROTO { int sstk(int incr); }
+71 AUE_MMAP COMPAT|NOPROTO { void *mmap(void *addr, int len, \
+ int prot, int flags, int fd, int pos); }
+72 AUE_O_VADVISE COMPAT11|NOPROTO { int vadvise(int anom); }
+73 AUE_MUNMAP NOPROTO { int munmap(void *addr, size_t len); }
+74 AUE_MPROTECT STD { int freebsd32_mprotect(void *addr, \
+ size_t len, int prot); }
+75 AUE_MADVISE NOPROTO { int madvise(void *addr, size_t len, \
+ int behav); }
+76 AUE_NULL OBSOL vhangup
+77 AUE_NULL OBSOL vlimit
+78 AUE_MINCORE NOPROTO { int mincore(const void *addr, size_t len, \
+ char *vec); }
+79 AUE_GETGROUPS NOPROTO { int getgroups(u_int gidsetsize, \
+ gid_t *gidset); }
+80 AUE_SETGROUPS NOPROTO { int setgroups(u_int gidsetsize, \
+ gid_t *gidset); }
+81 AUE_GETPGRP NOPROTO { int getpgrp(void); }
+82 AUE_SETPGRP NOPROTO { int setpgid(int pid, int pgid); }
+83 AUE_SETITIMER STD { int freebsd32_setitimer(u_int which, \
+ struct itimerval32 *itv, \
+ struct itimerval32 *oitv); }
+84 AUE_NULL OBSOL owait
+; XXX implement
+85 AUE_SWAPON NOPROTO { int swapon(const char *name); }
+86 AUE_GETITIMER STD { int freebsd32_getitimer(u_int which, \
+ struct itimerval32 *itv); }
+87 AUE_O_GETHOSTNAME OBSOL ogethostname
+88 AUE_O_SETHOSTNAME OBSOL osethostname
+89 AUE_GETDTABLESIZE NOPROTO { int getdtablesize(void); }
+90 AUE_DUP2 NOPROTO { int dup2(u_int from, u_int to); }
+91 AUE_NULL UNIMPL getdopt
+92 AUE_FCNTL STD { int freebsd32_fcntl(int fd, int cmd, \
+ int arg); }
+93 AUE_SELECT STD { int freebsd32_select(int nd, fd_set *in, \
+ fd_set *ou, fd_set *ex, \
+ struct timeval32 *tv); }
+94 AUE_NULL UNIMPL setdopt
+95 AUE_FSYNC NOPROTO { int fsync(int fd); }
+96 AUE_SETPRIORITY NOPROTO { int setpriority(int which, int who, \
+ int prio); }
+97 AUE_SOCKET NOPROTO { int socket(int domain, int type, \
+ int protocol); }
+98 AUE_CONNECT NOPROTO { int connect(int s, \
+ const struct sockaddr *name, \
+ int namelen); }
+99 AUE_NULL OBSOL oaccept
+100 AUE_GETPRIORITY NOPROTO { int getpriority(int which, int who); }
+101 AUE_NULL OBSOL osend
+102 AUE_NULL OBSOL orecv
+103 AUE_SIGRETURN COMPAT { int freebsd32_sigreturn( \
+ struct ia32_sigcontext3 *sigcntxp); }
+104 AUE_BIND NOPROTO { int bind(int s, const struct sockaddr *name, \
+ int namelen); }
+105 AUE_SETSOCKOPT NOPROTO { int setsockopt(int s, int level, \
+ int name, const void *val, int valsize); }
+106 AUE_LISTEN NOPROTO { int listen(int s, int backlog); }
+107 AUE_NULL OBSOL vtimes
+108 AUE_O_SIGVEC COMPAT { int freebsd32_sigvec(int signum, \
+ struct sigvec32 *nsv, \
+ struct sigvec32 *osv); }
+109 AUE_O_SIGBLOCK COMPAT { int freebsd32_sigblock(int mask); }
+110 AUE_O_SIGSETMASK COMPAT { int freebsd32_sigsetmask( int mask); }
+111 AUE_SIGSUSPEND COMPAT { int freebsd32_sigsuspend( int mask); }
+112 AUE_O_SIGSTACK COMPAT { int freebsd32_sigstack( \
+ struct sigstack32 *nss, \
+ struct sigstack32 *oss); }
+113 AUE_NULL OBSOL orecvmsg
+114 AUE_NULL OBSOL osendmsg
+115 AUE_NULL OBSOL vtrace
+116 AUE_GETTIMEOFDAY STD { int freebsd32_gettimeofday( \
+ struct timeval32 *tp, \
+ struct timezone *tzp); }
+117 AUE_GETRUSAGE STD { int freebsd32_getrusage(int who, \
+ struct rusage32 *rusage); }
+118 AUE_GETSOCKOPT NOPROTO { int getsockopt(int s, int level, \
+ int name, void *val, int *avalsize); }
+119 AUE_NULL UNIMPL resuba (BSD/OS 2.x)
+120 AUE_READV STD { int freebsd32_readv(int fd, \
+ struct iovec32 *iovp, u_int iovcnt); }
+121 AUE_WRITEV STD { int freebsd32_writev(int fd, \
+ struct iovec32 *iovp, u_int iovcnt); }
+122 AUE_SETTIMEOFDAY STD { int freebsd32_settimeofday( \
+ struct timeval32 *tv, \
+ struct timezone *tzp); }
+123 AUE_FCHOWN NOPROTO { int fchown(int fd, int uid, int gid); }
+124 AUE_FCHMOD NOPROTO { int fchmod(int fd, mode_t mode); }
+125 AUE_RECVFROM OBSOL orecvfrom
+126 AUE_SETREUID NOPROTO { int setreuid(int ruid, int euid); }
+127 AUE_SETREGID NOPROTO { int setregid(int rgid, int egid); }
+128 AUE_RENAME NOPROTO { int rename(const char *from, \
+ const char *to); }
+129 AUE_TRUNCATE COMPAT|NOPROTO { int truncate(const char *path, \
+ int length); }
+130 AUE_FTRUNCATE COMPAT|NOPROTO { int ftruncate(int fd, int length); }
+131 AUE_FLOCK NOPROTO { int flock(int fd, int how); }
+132 AUE_MKFIFO NOPROTO { int mkfifo(const char *path, mode_t mode); }
+133 AUE_SENDTO NOPROTO { int sendto(int s, const void *buf, \
+ size_t len, int flags, \
+ const struct sockaddr *to, \
+ int tolen); }
+134 AUE_SHUTDOWN NOPROTO { int shutdown(int s, int how); }
+135 AUE_SOCKETPAIR NOPROTO { int socketpair(int domain, int type, \
+ int protocol, int *rsv); }
+136 AUE_MKDIR NOPROTO { int mkdir(const char *path, mode_t mode); }
+137 AUE_RMDIR NOPROTO { int rmdir(const char *path); }
+138 AUE_UTIMES STD { int freebsd32_utimes(const char *path, \
+ struct timeval32 *tptr); }
+139 AUE_NULL OBSOL 4.2 sigreturn
+140 AUE_ADJTIME STD { int freebsd32_adjtime( \
+ struct timeval32 *delta, \
+ struct timeval32 *olddelta); }
+141 AUE_GETPEERNAME OBSOL ogetpeername
+142 AUE_SYSCTL OBSOL ogethostid
+143 AUE_SYSCTL OBSOL sethostid
+144 AUE_GETRLIMIT OBSOL getrlimit
+145 AUE_SETRLIMIT OBSOL setrlimit
+146 AUE_KILLPG OBSOL killpg
+147 AUE_SETSID NOPROTO { int setsid(void); }
+148 AUE_QUOTACTL NOPROTO { int quotactl(const char *path, int cmd, \
+ int uid, void *arg); }
+149 AUE_O_QUOTA OBSOL oquota
+150 AUE_GETSOCKNAME OBSOL ogetsockname
+
+; Syscalls 151-180 inclusive are reserved for vendor-specific
+; system calls. (This includes various calls added for compatibity
+; with other Unix variants.)
+; Some of these calls are now supported by BSD...
+151 AUE_NULL UNIMPL sem_lock (BSD/OS 2.x)
+152 AUE_NULL UNIMPL sem_wakeup (BSD/OS 2.x)
+153 AUE_NULL UNIMPL asyncdaemon (BSD/OS 2.x)
+; 154 is initialised by the NLM code, if present.
+154 AUE_NULL UNIMPL nlm_syscall
+; 155 is initialized by the NFS code, if present.
+; XXX this is a problem!!!
+155 AUE_NFS_SVC UNIMPL nfssvc
+156 AUE_GETDIRENTRIES COMPAT { int freebsd32_getdirentries(int fd, \
+ char *buf, u_int count, uint32_t *basep); }
+157 AUE_STATFS COMPAT4 { int freebsd32_statfs(const char *path, \
+ struct statfs32 *buf); }
+158 AUE_FSTATFS COMPAT4 { int freebsd32_fstatfs(int fd, \
+ struct statfs32 *buf); }
+159 AUE_NULL UNIMPL nosys
+160 AUE_LGETFH UNIMPL lgetfh
+161 AUE_NFS_GETFH NOPROTO { int getfh(const char *fname, \
+ struct fhandle *fhp); }
+162 AUE_SYSCTL OBSOL getdomainname
+163 AUE_SYSCTL OBSOL setdomainname
+164 AUE_NULL OBSOL uname
+165 AUE_SYSARCH STD { int freebsd32_sysarch(int op, char *parms); }
+166 AUE_RTPRIO NOPROTO { int rtprio(int function, pid_t pid, \
+ struct rtprio *rtp); }
+167 AUE_NULL UNIMPL nosys
+168 AUE_NULL UNIMPL nosys
+169 AUE_SEMSYS NOSTD { int freebsd32_semsys(int which, int a2, \
+ int a3, int a4, int a5); }
+170 AUE_MSGSYS NOSTD { int freebsd32_msgsys(int which, int a2, \
+ int a3, int a4, int a5, int a6); }
+171 AUE_SHMSYS NOSTD { int freebsd32_shmsys(uint32_t which, uint32_t a2, \
+ uint32_t a3, uint32_t a4); }
+172 AUE_NULL UNIMPL nosys
+173 AUE_PREAD COMPAT6 { ssize_t freebsd32_pread(int fd, void *buf, \
+ size_t nbyte, int pad, \
+ uint32_t offset1, uint32_t offset2); }
+174 AUE_PWRITE COMPAT6 { ssize_t freebsd32_pwrite(int fd, \
+ const void *buf, size_t nbyte, int pad, \
+ uint32_t offset1, uint32_t offset2); }
+175 AUE_NULL UNIMPL nosys
+176 AUE_NTP_ADJTIME STD { int freebsd32_ntp_adjtime( \
+ struct timex32 *tp); }
+177 AUE_NULL UNIMPL sfork (BSD/OS 2.x)
+178 AUE_NULL UNIMPL getdescriptor (BSD/OS 2.x)
+179 AUE_NULL UNIMPL setdescriptor (BSD/OS 2.x)
+180 AUE_NULL UNIMPL nosys
+
+; Syscalls 181-199 are used by/reserved for BSD
+181 AUE_SETGID NOPROTO { int setgid(gid_t gid); }
+182 AUE_SETEGID NOPROTO { int setegid(gid_t egid); }
+183 AUE_SETEUID NOPROTO { int seteuid(uid_t euid); }
+184 AUE_NULL OBSOL lfs_bmapv
+185 AUE_NULL OBSOL lfs_markv
+186 AUE_NULL OBSOL lfs_segclean
+187 AUE_NULL OBSOL lfs_segwait
+188 AUE_STAT COMPAT11 { int freebsd32_stat(const char *path, \
+ struct freebsd11_stat32 *ub); }
+189 AUE_FSTAT COMPAT11 { int freebsd32_fstat(int fd, \
+ struct freebsd11_stat32 *ub); }
+190 AUE_LSTAT COMPAT11 { int freebsd32_lstat(const char *path, \
+ struct freebsd11_stat32 *ub); }
+191 AUE_PATHCONF NOPROTO { int pathconf(const char *path, int name); }
+192 AUE_FPATHCONF NOPROTO { int fpathconf(int fd, int name); }
+193 AUE_NULL UNIMPL nosys
+194 AUE_GETRLIMIT NOPROTO { int getrlimit(u_int which, \
+ struct rlimit *rlp); } getrlimit \
+ __getrlimit_args int
+195 AUE_SETRLIMIT NOPROTO { int setrlimit(u_int which, \
+ struct rlimit *rlp); } setrlimit \
+ __setrlimit_args int
+196 AUE_GETDIRENTRIES COMPAT11 { int freebsd32_getdirentries(int fd, \
+ char *buf, u_int count, int32_t *basep); }
+197 AUE_MMAP COMPAT6 { void *freebsd32_mmap(void *addr, \
+ size_t len, int prot, int flags, int fd, \
+ int pad, uint32_t pos1, uint32_t pos2); }
+198 AUE_NULL NOPROTO { int nosys(void); } __syscall \
+ __syscall_args int
+199 AUE_LSEEK COMPAT6 { off_t freebsd32_lseek(int fd, int pad, \
+ uint32_t offset1, uint32_t offset2, \
+ int whence); }
+200 AUE_TRUNCATE COMPAT6 { int freebsd32_truncate(const char *path, \
+ int pad, uint32_t length1, \
+ uint32_t length2); }
+201 AUE_FTRUNCATE COMPAT6 { int freebsd32_ftruncate(int fd, int pad, \
+ uint32_t length1, uint32_t length2); }
+202 AUE_SYSCTL STD { int freebsd32___sysctl(int *name, \
+ u_int namelen, void *old, \
+ uint32_t *oldlenp, const void *new, \
+ uint32_t newlen); }
+203 AUE_MLOCK NOPROTO { int mlock(const void *addr, \
+ size_t len); }
+204 AUE_MUNLOCK NOPROTO { int munlock(const void *addr, \
+ size_t len); }
+205 AUE_UNDELETE NOPROTO { int undelete(const char *path); }
+206 AUE_FUTIMES STD { int freebsd32_futimes(int fd, \
+ struct timeval32 *tptr); }
+207 AUE_GETPGID NOPROTO { int getpgid(pid_t pid); }
+208 AUE_NULL UNIMPL nosys
+209 AUE_POLL NOPROTO { int poll(struct pollfd *fds, u_int nfds, \
+ int timeout); }
+
+;
+; The following are reserved for loadable syscalls
+;
+210 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
+211 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
+212 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
+213 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
+214 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
+215 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
+216 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
+217 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
+218 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
+219 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
+
+220 AUE_SEMCTL COMPAT7|NOSTD { int freebsd32_semctl( \
+ int semid, int semnum, \
+ int cmd, union semun32 *arg); }
+221 AUE_SEMGET NOSTD|NOPROTO { int semget(key_t key, int nsems, \
+ int semflg); }
+222 AUE_SEMOP NOSTD|NOPROTO { int semop(int semid, \
+ struct sembuf *sops, u_int nsops); }
+223 AUE_NULL OBSOL semconfig
+224 AUE_MSGCTL COMPAT7|NOSTD { int freebsd32_msgctl( \
+ int msqid, int cmd, \
+ struct msqid_ds32_old *buf); }
+225 AUE_MSGGET NOSTD|NOPROTO { int msgget(key_t key, int msgflg); }
+226 AUE_MSGSND NOSTD { int freebsd32_msgsnd(int msqid, void *msgp, \
+ size_t msgsz, int msgflg); }
+227 AUE_MSGRCV NOSTD { int freebsd32_msgrcv(int msqid, void *msgp, \
+ size_t msgsz, long msgtyp, int msgflg); }
+228 AUE_SHMAT NOSTD|NOPROTO { void *shmat(int shmid, void *shmaddr, \
+ int shmflg); }
+229 AUE_SHMCTL COMPAT7|NOSTD { int freebsd32_shmctl( \
+ int shmid, int cmd, \
+ struct shmid_ds32_old *buf); }
+230 AUE_SHMDT NOSTD|NOPROTO { int shmdt(void *shmaddr); }
+231 AUE_SHMGET NOSTD|NOPROTO { int shmget(key_t key, int size, \
+ int shmflg); }
+;
+232 AUE_NULL STD { int freebsd32_clock_gettime(clockid_t clock_id, \
+ struct timespec32 *tp); }
+233 AUE_CLOCK_SETTIME STD { int freebsd32_clock_settime(clockid_t clock_id, \
+ const struct timespec32 *tp); }
+234 AUE_NULL STD { int freebsd32_clock_getres(clockid_t clock_id, \
+ struct timespec32 *tp); }
+235 AUE_NULL STD { int freebsd32_ktimer_create(\
+ clockid_t clock_id, \
+ struct sigevent32 *evp, int *timerid); }
+236 AUE_NULL NOPROTO { int ktimer_delete(int timerid); }
+237 AUE_NULL STD { int freebsd32_ktimer_settime(int timerid,\
+ int flags, \
+ const struct itimerspec32 *value, \
+ struct itimerspec32 *ovalue); }
+238 AUE_NULL STD { int freebsd32_ktimer_gettime(int timerid,\
+ struct itimerspec32 *value); }
+239 AUE_NULL NOPROTO { int ktimer_getoverrun(int timerid); }
+240 AUE_NULL STD { int freebsd32_nanosleep( \
+ const struct timespec32 *rqtp, \
+ struct timespec32 *rmtp); }
+241 AUE_NULL NOPROTO { int ffclock_getcounter(ffcounter *ffcount); }
+242 AUE_NULL NOPROTO { int ffclock_setestimate( \
+ struct ffclock_estimate *cest); }
+243 AUE_NULL NOPROTO { int ffclock_getestimate( \
+ struct ffclock_estimate *cest); }
+244 AUE_NULL STD { int freebsd32_clock_nanosleep( \
+ clockid_t clock_id, int flags, \
+ const struct timespec32 *rqtp, \
+ struct timespec32 *rmtp); }
+245 AUE_NULL UNIMPL nosys
+246 AUE_NULL UNIMPL nosys
+247 AUE_NULL STD { int freebsd32_clock_getcpuclockid2(\
+ uint32_t id1, uint32_t id2,\
+ int which, clockid_t *clock_id); }
+248 AUE_NULL UNIMPL ntp_gettime
+249 AUE_NULL UNIMPL nosys
+250 AUE_MINHERIT NOPROTO { int minherit(void *addr, size_t len, \
+ int inherit); }
+251 AUE_RFORK NOPROTO { int rfork(int flags); }
+252 AUE_POLL OBSOL openbsd_poll
+253 AUE_ISSETUGID NOPROTO { int issetugid(void); }
+254 AUE_LCHOWN NOPROTO { int lchown(const char *path, int uid, \
+ int gid); }
+255 AUE_AIO_READ STD { int freebsd32_aio_read( \
+ struct aiocb32 *aiocbp); }
+256 AUE_AIO_WRITE STD { int freebsd32_aio_write( \
+ struct aiocb32 *aiocbp); }
+257 AUE_LIO_LISTIO STD { int freebsd32_lio_listio(int mode, \
+ struct aiocb32 * const *acb_list, \
+ int nent, struct sigevent32 *sig); }
+258 AUE_NULL UNIMPL nosys
+259 AUE_NULL UNIMPL nosys
+260 AUE_NULL UNIMPL nosys
+261 AUE_NULL UNIMPL nosys
+262 AUE_NULL UNIMPL nosys
+263 AUE_NULL UNIMPL nosys
+264 AUE_NULL UNIMPL nosys
+265 AUE_NULL UNIMPL nosys
+266 AUE_NULL UNIMPL nosys
+267 AUE_NULL UNIMPL nosys
+268 AUE_NULL UNIMPL nosys
+269 AUE_NULL UNIMPL nosys
+270 AUE_NULL UNIMPL nosys
+271 AUE_NULL UNIMPL nosys
+272 AUE_O_GETDENTS COMPAT11 { int freebsd32_getdents(int fd, char *buf, \
+ int count); }
+273 AUE_NULL UNIMPL nosys
+274 AUE_LCHMOD NOPROTO { int lchmod(const char *path, mode_t mode); }
+275 AUE_NULL OBSOL netbsd_lchown
+276 AUE_LUTIMES STD { int freebsd32_lutimes(const char *path, \
+ struct timeval32 *tptr); }
+277 AUE_NULL OBSOL netbsd_msync
+278 AUE_STAT COMPAT11|NOPROTO { int nstat(const char *path, \
+ struct nstat *ub); }
+279 AUE_FSTAT COMPAT11|NOPROTO { int nfstat(int fd, struct nstat *sb); }
+280 AUE_LSTAT COMPAT11|NOPROTO { int nlstat(const char *path, \
+ struct nstat *ub); }
+281 AUE_NULL UNIMPL nosys
+282 AUE_NULL UNIMPL nosys
+283 AUE_NULL UNIMPL nosys
+284 AUE_NULL UNIMPL nosys
+285 AUE_NULL UNIMPL nosys
+286 AUE_NULL UNIMPL nosys
+287 AUE_NULL UNIMPL nosys
+288 AUE_NULL UNIMPL nosys
+289 AUE_PREADV STD { ssize_t freebsd32_preadv(int fd, \
+ struct iovec32 *iovp, \
+ u_int iovcnt, \
+ uint32_t offset1, uint32_t offset2); }
+290 AUE_PWRITEV STD { ssize_t freebsd32_pwritev(int fd, \
+ struct iovec32 *iovp, \
+ u_int iovcnt, \
+ uint32_t offset1, uint32_t offset2); }
+291 AUE_NULL UNIMPL nosys
+292 AUE_NULL UNIMPL nosys
+293 AUE_NULL UNIMPL nosys
+294 AUE_NULL UNIMPL nosys
+295 AUE_NULL UNIMPL nosys
+296 AUE_NULL UNIMPL nosys
+297 AUE_FHSTATFS COMPAT4 { int freebsd32_fhstatfs( \
+ const struct fhandle *u_fhp, \
+ struct statfs32 *buf); }
+298 AUE_FHOPEN NOPROTO { int fhopen(const struct fhandle *u_fhp, \
+ int flags); }
+299 AUE_FHSTAT COMPAT11 { int freebsd32_fhstat( \
+ const struct fhandle *u_fhp, \
+ struct freebsd11_stat32 *sb); }
+; syscall numbers for FreeBSD
+300 AUE_NULL NOPROTO { int modnext(int modid); }
+301 AUE_NULL STD { int freebsd32_modstat(int modid, \
+ struct module_stat32 *stat); }
+302 AUE_NULL NOPROTO { int modfnext(int modid); }
+303 AUE_NULL NOPROTO { int modfind(const char *name); }
+304 AUE_MODLOAD NOPROTO { int kldload(const char *file); }
+305 AUE_MODUNLOAD NOPROTO { int kldunload(int fileid); }
+306 AUE_NULL NOPROTO { int kldfind(const char *file); }
+307 AUE_NULL NOPROTO { int kldnext(int fileid); }
+308 AUE_NULL STD { int freebsd32_kldstat(int fileid, \
+ struct kld32_file_stat *stat); }
+309 AUE_NULL NOPROTO { int kldfirstmod(int fileid); }
+310 AUE_GETSID NOPROTO { int getsid(pid_t pid); }
+311 AUE_SETRESUID NOPROTO { int setresuid(uid_t ruid, uid_t euid, \
+ uid_t suid); }
+312 AUE_SETRESGID NOPROTO { int setresgid(gid_t rgid, gid_t egid, \
+ gid_t sgid); }
+313 AUE_NULL OBSOL signanosleep
+314 AUE_AIO_RETURN STD { int freebsd32_aio_return( \
+ struct aiocb32 *aiocbp); }
+315 AUE_AIO_SUSPEND STD { int freebsd32_aio_suspend( \
+ struct aiocb32 * const * aiocbp, int nent, \
+ const struct timespec32 *timeout); }
+316 AUE_AIO_CANCEL NOPROTO { int aio_cancel(int fd, \
+ struct aiocb *aiocbp); }
+317 AUE_AIO_ERROR STD { int freebsd32_aio_error( \
+ struct aiocb32 *aiocbp); }
+318 AUE_AIO_READ COMPAT6 { int freebsd32_aio_read( \
+ struct oaiocb32 *aiocbp); }
+319 AUE_AIO_WRITE COMPAT6 { int freebsd32_aio_write( \
+ struct oaiocb32 *aiocbp); }
+320 AUE_LIO_LISTIO COMPAT6 { int freebsd32_lio_listio(int mode, \
+ struct oaiocb32 * const *acb_list, \
+ int nent, struct osigevent32 *sig); }
+321 AUE_NULL NOPROTO { int yield(void); }
+322 AUE_NULL OBSOL thr_sleep
+323 AUE_NULL OBSOL thr_wakeup
+324 AUE_MLOCKALL NOPROTO { int mlockall(int how); }
+325 AUE_MUNLOCKALL NOPROTO { int munlockall(void); }
+326 AUE_GETCWD NOPROTO { int __getcwd(char *buf, size_t buflen); }
+
+327 AUE_NULL NOPROTO { int sched_setparam (pid_t pid, \
+ const struct sched_param *param); }
+328 AUE_NULL NOPROTO { int sched_getparam (pid_t pid, \
+ struct sched_param *param); }
+
+329 AUE_NULL NOPROTO { int sched_setscheduler (pid_t pid, \
+ int policy, \
+ const struct sched_param *param); }
+330 AUE_NULL NOPROTO { int sched_getscheduler (pid_t pid); }
+
+331 AUE_NULL NOPROTO { int sched_yield (void); }
+332 AUE_NULL NOPROTO { int sched_get_priority_max (int policy); }
+333 AUE_NULL NOPROTO { int sched_get_priority_min (int policy); }
+334 AUE_NULL STD { int freebsd32_sched_rr_get_interval ( \
+ pid_t pid, \
+ struct timespec32 *interval); }
+335 AUE_NULL NOPROTO { int utrace(const void *addr, size_t len); }
+336 AUE_SENDFILE COMPAT4 { int freebsd32_sendfile(int fd, int s, \
+ uint32_t offset1, uint32_t offset2, \
+ size_t nbytes, struct sf_hdtr32 *hdtr, \
+ off_t *sbytes, int flags); }
+337 AUE_NULL NOPROTO { int kldsym(int fileid, int cmd, \
+ void *data); }
+338 AUE_JAIL STD { int freebsd32_jail(struct jail32 *jail); }
+339 AUE_NULL UNIMPL pioctl
+340 AUE_SIGPROCMASK NOPROTO { int sigprocmask(int how, \
+ const sigset_t *set, sigset_t *oset); }
+341 AUE_SIGSUSPEND NOPROTO { int sigsuspend(const sigset_t *sigmask); }
+342 AUE_SIGACTION COMPAT4 { int freebsd32_sigaction(int sig, \
+ struct sigaction32 *act, \
+ struct sigaction32 *oact); }
+343 AUE_SIGPENDING NOPROTO { int sigpending(sigset_t *set); }
+344 AUE_SIGRETURN COMPAT4 { int freebsd32_sigreturn( \
+ const struct freebsd4_freebsd32_ucontext *sigcntxp); }
+345 AUE_SIGWAIT STD { int freebsd32_sigtimedwait(const sigset_t *set, \
+ siginfo_t *info, \
+ const struct timespec *timeout); }
+346 AUE_NULL STD { int freebsd32_sigwaitinfo(const sigset_t *set, \
+ siginfo_t *info); }
+347 AUE_ACL_GET_FILE NOPROTO { int __acl_get_file(const char *path, \
+ acl_type_t type, struct acl *aclp); }
+348 AUE_ACL_SET_FILE NOPROTO { int __acl_set_file(const char *path, \
+ acl_type_t type, struct acl *aclp); }
+349 AUE_ACL_GET_FD NOPROTO { int __acl_get_fd(int filedes, \
+ acl_type_t type, struct acl *aclp); }
+350 AUE_ACL_SET_FD NOPROTO { int __acl_set_fd(int filedes, \
+ acl_type_t type, struct acl *aclp); }
+351 AUE_ACL_DELETE_FILE NOPROTO { int __acl_delete_file(const char *path, \
+ acl_type_t type); }
+352 AUE_ACL_DELETE_FD NOPROTO { int __acl_delete_fd(int filedes, \
+ acl_type_t type); }
+353 AUE_ACL_CHECK_FILE NOPROTO { int __acl_aclcheck_file(const char *path, \
+ acl_type_t type, struct acl *aclp); }
+354 AUE_ACL_CHECK_FD NOPROTO { int __acl_aclcheck_fd(int filedes, \
+ acl_type_t type, struct acl *aclp); }
+355 AUE_EXTATTRCTL NOPROTO { int extattrctl(const char *path, int cmd, \
+ const char *filename, int attrnamespace, \
+ const char *attrname); }
+356 AUE_EXTATTR_SET_FILE NOPROTO { ssize_t extattr_set_file( \
+ const char *path, int attrnamespace, \
+ const char *attrname, void *data, \
+ size_t nbytes); }
+357 AUE_EXTATTR_GET_FILE NOPROTO { ssize_t extattr_get_file( \
+ const char *path, int attrnamespace, \
+ const char *attrname, void *data, \
+ size_t nbytes); }
+358 AUE_EXTATTR_DELETE_FILE NOPROTO { int extattr_delete_file( \
+ const char *path, int attrnamespace, \
+ const char *attrname); }
+359 AUE_AIO_WAITCOMPLETE STD { int freebsd32_aio_waitcomplete( \
+ struct aiocb32 **aiocbp, \
+ struct timespec32 *timeout); }
+360 AUE_GETRESUID NOPROTO { int getresuid(uid_t *ruid, uid_t *euid, \
+ uid_t *suid); }
+361 AUE_GETRESGID NOPROTO { int getresgid(gid_t *rgid, gid_t *egid, \
+ gid_t *sgid); }
+362 AUE_KQUEUE NOPROTO { int kqueue(void); }
+363 AUE_KEVENT COMPAT11 { int freebsd32_kevent(int fd, \
+ const struct kevent32_freebsd11 * \
+ changelist, \
+ int nchanges, \
+ struct kevent32_freebsd11 *eventlist, \
+ int nevents, \
+ const struct timespec32 *timeout); }
+364 AUE_NULL OBSOL __cap_get_proc
+365 AUE_NULL OBSOL __cap_set_proc
+366 AUE_NULL OBSOL __cap_get_fd
+367 AUE_NULL OBSOL __cap_get_file
+368 AUE_NULL OBSOL __cap_set_fd
+369 AUE_NULL OBSOL __cap_set_file
+370 AUE_NULL UNIMPL nosys
+371 AUE_EXTATTR_SET_FD NOPROTO { ssize_t extattr_set_fd(int fd, \
+ int attrnamespace, const char *attrname, \
+ void *data, size_t nbytes); }
+372 AUE_EXTATTR_GET_FD NOPROTO { ssize_t extattr_get_fd(int fd, \
+ int attrnamespace, const char *attrname, \
+ void *data, size_t nbytes); }
+373 AUE_EXTATTR_DELETE_FD NOPROTO { int extattr_delete_fd(int fd, \
+ int attrnamespace, \
+ const char *attrname); }
+374 AUE_SETUGID NOPROTO { int __setugid(int flag); }
+375 AUE_NULL OBSOL nfsclnt
+376 AUE_EACCESS NOPROTO { int eaccess(const char *path, int amode); }
+377 AUE_NULL UNIMPL afs_syscall
+378 AUE_NMOUNT STD { int freebsd32_nmount(struct iovec32 *iovp, \
+ unsigned int iovcnt, int flags); }
+379 AUE_NULL OBSOL kse_exit
+380 AUE_NULL OBSOL kse_wakeup
+381 AUE_NULL OBSOL kse_create
+382 AUE_NULL OBSOL kse_thr_interrupt
+383 AUE_NULL OBSOL kse_release
+384 AUE_NULL UNIMPL __mac_get_proc
+385 AUE_NULL UNIMPL __mac_set_proc
+386 AUE_NULL UNIMPL __mac_get_fd
+387 AUE_NULL UNIMPL __mac_get_file
+388 AUE_NULL UNIMPL __mac_set_fd
+389 AUE_NULL UNIMPL __mac_set_file
+390 AUE_NULL NOPROTO { int kenv(int what, const char *name, \
+ char *value, int len); }
+391 AUE_LCHFLAGS NOPROTO { int lchflags(const char *path, \
+ u_long flags); }
+392 AUE_NULL NOPROTO { int uuidgen(struct uuid *store, \
+ int count); }
+393 AUE_SENDFILE STD { int freebsd32_sendfile(int fd, int s, \
+ uint32_t offset1, uint32_t offset2, \
+ size_t nbytes, struct sf_hdtr32 *hdtr, \
+ off_t *sbytes, int flags); }
+394 AUE_NULL UNIMPL mac_syscall
+395 AUE_GETFSSTAT COMPAT11|NOPROTO { int getfsstat( \
+ struct freebsd11_statfs *buf, \
+ long bufsize, int mode); }
+396 AUE_STATFS COMPAT11|NOPROTO { int statfs(const char *path, \
+ struct statfs *buf); }
+397 AUE_FSTATFS COMPAT11|NOPROTO { int fstatfs(int fd, \
+ struct freebsd11_statfs *buf); }
+398 AUE_FHSTATFS COMPAT11|NOPROTO { int fhstatfs( \
+ const struct fhandle *u_fhp, \
+ struct freebsd11_statfs *buf); }
+399 AUE_NULL UNIMPL nosys
+400 AUE_SEMCLOSE NOSTD|NOPROTO { int ksem_close(semid_t id); }
+401 AUE_SEMPOST NOSTD|NOPROTO { int ksem_post(semid_t id); }
+402 AUE_SEMWAIT NOSTD|NOPROTO { int ksem_wait(semid_t id); }
+403 AUE_SEMTRYWAIT NOSTD|NOPROTO { int ksem_trywait(semid_t id); }
+404 AUE_SEMINIT NOSTD { int freebsd32_ksem_init(semid_t *idp, \
+ unsigned int value); }
+405 AUE_SEMOPEN NOSTD { int freebsd32_ksem_open(semid_t *idp, \
+ const char *name, int oflag, \
+ mode_t mode, unsigned int value); }
+406 AUE_SEMUNLINK NOSTD|NOPROTO { int ksem_unlink(const char *name); }
+407 AUE_SEMGETVALUE NOSTD|NOPROTO { int ksem_getvalue(semid_t id, \
+ int *val); }
+408 AUE_SEMDESTROY NOSTD|NOPROTO { int ksem_destroy(semid_t id); }
+409 AUE_NULL UNIMPL __mac_get_pid
+410 AUE_NULL UNIMPL __mac_get_link
+411 AUE_NULL UNIMPL __mac_set_link
+412 AUE_EXTATTR_SET_LINK NOPROTO { ssize_t extattr_set_link( \
+ const char *path, int attrnamespace, \
+ const char *attrname, void *data, \
+ size_t nbytes); }
+413 AUE_EXTATTR_GET_LINK NOPROTO { ssize_t extattr_get_link( \
+ const char *path, int attrnamespace, \
+ const char *attrname, void *data, \
+ size_t nbytes); }
+414 AUE_EXTATTR_DELETE_LINK NOPROTO { int extattr_delete_link( \
+ const char *path, int attrnamespace, \
+ const char *attrname); }
+415 AUE_NULL UNIMPL __mac_execve
+416 AUE_SIGACTION STD { int freebsd32_sigaction(int sig, \
+ struct sigaction32 *act, \
+ struct sigaction32 *oact); }
+417 AUE_SIGRETURN STD { int freebsd32_sigreturn( \
+ const struct freebsd32_ucontext *sigcntxp); }
+418 AUE_NULL UNIMPL __xstat
+419 AUE_NULL UNIMPL __xfstat
+420 AUE_NULL UNIMPL __xlstat
+421 AUE_NULL STD { int freebsd32_getcontext( \
+ struct freebsd32_ucontext *ucp); }
+422 AUE_NULL STD { int freebsd32_setcontext( \
+ const struct freebsd32_ucontext *ucp); }
+423 AUE_NULL STD { int freebsd32_swapcontext( \
+ struct freebsd32_ucontext *oucp, \
+ const struct freebsd32_ucontext *ucp); }
+424 AUE_SWAPOFF UNIMPL swapoff
+425 AUE_ACL_GET_LINK NOPROTO { int __acl_get_link(const char *path, \
+ acl_type_t type, struct acl *aclp); }
+426 AUE_ACL_SET_LINK NOPROTO { int __acl_set_link(const char *path, \
+ acl_type_t type, struct acl *aclp); }
+427 AUE_ACL_DELETE_LINK NOPROTO { int __acl_delete_link(const char *path, \
+ acl_type_t type); }
+428 AUE_ACL_CHECK_LINK NOPROTO { int __acl_aclcheck_link(const char *path, \
+ acl_type_t type, struct acl *aclp); }
+429 AUE_SIGWAIT NOPROTO { int sigwait(const sigset_t *set, \
+ int *sig); }
+430 AUE_THR_CREATE UNIMPL thr_create;
+431 AUE_THR_EXIT NOPROTO { void thr_exit(long *state); }
+432 AUE_NULL NOPROTO { int thr_self(long *id); }
+433 AUE_THR_KILL NOPROTO { int thr_kill(long id, int sig); }
+434 AUE_NULL UNIMPL nosys
+435 AUE_NULL UNIMPL nosys
+436 AUE_JAIL_ATTACH NOPROTO { int jail_attach(int jid); }
+437 AUE_EXTATTR_LIST_FD NOPROTO { ssize_t extattr_list_fd(int fd, \
+ int attrnamespace, void *data, \
+ size_t nbytes); }
+438 AUE_EXTATTR_LIST_FILE NOPROTO { ssize_t extattr_list_file( \
+ const char *path, int attrnamespace, \
+ void *data, size_t nbytes); }
+439 AUE_EXTATTR_LIST_LINK NOPROTO { ssize_t extattr_list_link( \
+ const char *path, int attrnamespace, \
+ void *data, size_t nbytes); }
+440 AUE_NULL OBSOL kse_switchin
+441 AUE_SEMWAIT NOSTD { int freebsd32_ksem_timedwait(semid_t id, \
+ const struct timespec32 *abstime); }
+442 AUE_NULL STD { int freebsd32_thr_suspend( \
+ const struct timespec32 *timeout); }
+443 AUE_NULL NOPROTO { int thr_wake(long id); }
+444 AUE_MODUNLOAD NOPROTO { int kldunloadf(int fileid, int flags); }
+445 AUE_AUDIT NOPROTO { int audit(const void *record, \
+ u_int length); }
+446 AUE_AUDITON NOPROTO { int auditon(int cmd, void *data, \
+ u_int length); }
+447 AUE_GETAUID NOPROTO { int getauid(uid_t *auid); }
+448 AUE_SETAUID NOPROTO { int setauid(uid_t *auid); }
+449 AUE_GETAUDIT NOPROTO { int getaudit(struct auditinfo *auditinfo); }
+450 AUE_SETAUDIT NOPROTO { int setaudit(struct auditinfo *auditinfo); }
+451 AUE_GETAUDIT_ADDR NOPROTO { int getaudit_addr( \
+ struct auditinfo_addr *auditinfo_addr, \
+ u_int length); }
+452 AUE_SETAUDIT_ADDR NOPROTO { int setaudit_addr( \
+ struct auditinfo_addr *auditinfo_addr, \
+ u_int length); }
+453 AUE_AUDITCTL NOPROTO { int auditctl(const char *path); }
+454 AUE_NULL STD { int freebsd32__umtx_op(void *obj, int op,\
+ u_long val, void *uaddr, \
+ void *uaddr2); }
+455 AUE_THR_NEW STD { int freebsd32_thr_new( \
+ struct thr_param32 *param, \
+ int param_size); }
+456 AUE_NULL STD { int freebsd32_sigqueue(pid_t pid, \
+ int signum, int value); }
+457 AUE_MQ_OPEN NOSTD { int freebsd32_kmq_open( \
+ const char *path, int flags, mode_t mode, \
+ const struct mq_attr32 *attr); }
+458 AUE_MQ_SETATTR NOSTD { int freebsd32_kmq_setattr(int mqd, \
+ const struct mq_attr32 *attr, \
+ struct mq_attr32 *oattr); }
+459 AUE_MQ_TIMEDRECEIVE NOSTD { int freebsd32_kmq_timedreceive(int mqd, \
+ char *msg_ptr, size_t msg_len, \
+ unsigned *msg_prio, \
+ const struct timespec32 *abs_timeout); }
+460 AUE_MQ_TIMEDSEND NOSTD { int freebsd32_kmq_timedsend(int mqd, \
+ const char *msg_ptr, size_t msg_len,\
+ unsigned msg_prio, \
+ const struct timespec32 *abs_timeout);}
+461 AUE_MQ_NOTIFY NOSTD { int freebsd32_kmq_notify(int mqd, \
+ const struct sigevent32 *sigev); }
+462 AUE_MQ_UNLINK NOPROTO|NOSTD { int kmq_unlink(const char *path); }
+463 AUE_NULL NOPROTO { int abort2(const char *why, int nargs, void **args); }
+464 AUE_NULL NOPROTO { int thr_set_name(long id, const char *name); }
+465 AUE_AIO_FSYNC STD { int freebsd32_aio_fsync(int op, \
+ struct aiocb32 *aiocbp); }
+466 AUE_RTPRIO NOPROTO { int rtprio_thread(int function, \
+ lwpid_t lwpid, struct rtprio *rtp); }
+467 AUE_NULL UNIMPL nosys
+468 AUE_NULL UNIMPL nosys
+469 AUE_NULL UNIMPL __getpath_fromfd
+470 AUE_NULL UNIMPL __getpath_fromaddr
+471 AUE_SCTP_PEELOFF NOPROTO|NOSTD { int sctp_peeloff(int sd, uint32_t name); }
+472 AUE_SCTP_GENERIC_SENDMSG NOPROTO|NOSTD { int sctp_generic_sendmsg( \
+ int sd, void *msg, int mlen, \
+ struct sockaddr *to, __socklen_t tolen, \
+ struct sctp_sndrcvinfo *sinfo, int flags); }
+473 AUE_SCTP_GENERIC_SENDMSG_IOV NOPROTO|NOSTD { int sctp_generic_sendmsg_iov(int sd, struct iovec *iov, int iovlen, \
+ struct sockaddr *to, __socklen_t tolen, \
+ struct sctp_sndrcvinfo *sinfo, int flags); }
+474 AUE_SCTP_GENERIC_RECVMSG NOPROTO|NOSTD { int sctp_generic_recvmsg(int sd, struct iovec *iov, int iovlen, \
+ struct sockaddr * from, __socklen_t *fromlenaddr, \
+ struct sctp_sndrcvinfo *sinfo, int *msg_flags); }
+#ifdef PAD64_REQUIRED
+475 AUE_PREAD STD { ssize_t freebsd32_pread(int fd, \
+ void *buf,size_t nbyte, \
+ int pad, \
+ uint32_t offset1, uint32_t offset2); }
+476 AUE_PWRITE STD { ssize_t freebsd32_pwrite(int fd, \
+ const void *buf, size_t nbyte, \
+ int pad, \
+ uint32_t offset1, uint32_t offset2); }
+477 AUE_MMAP STD { void *freebsd32_mmap(void *addr, \
+ size_t len, int prot, int flags, int fd, \
+ int pad, \
+ uint32_t pos1, uint32_t pos2); }
+478 AUE_LSEEK STD { off_t freebsd32_lseek(int fd, \
+ int pad, \
+ uint32_t offset1, uint32_t offset2, \
+ int whence); }
+479 AUE_TRUNCATE STD { int freebsd32_truncate(const char *path, \
+ int pad, \
+ uint32_t length1, uint32_t length2); }
+480 AUE_FTRUNCATE STD { int freebsd32_ftruncate(int fd, \
+ int pad, \
+ uint32_t length1, uint32_t length2); }
+#else
+475 AUE_PREAD STD { ssize_t freebsd32_pread(int fd, \
+ void *buf,size_t nbyte, \
+ uint32_t offset1, uint32_t offset2); }
+476 AUE_PWRITE STD { ssize_t freebsd32_pwrite(int fd, \
+ const void *buf, size_t nbyte, \
+ uint32_t offset1, uint32_t offset2); }
+477 AUE_MMAP STD { void *freebsd32_mmap(void *addr, \
+ size_t len, int prot, int flags, int fd, \
+ uint32_t pos1, uint32_t pos2); }
+478 AUE_LSEEK STD { off_t freebsd32_lseek(int fd, \
+ uint32_t offset1, uint32_t offset2, \
+ int whence); }
+479 AUE_TRUNCATE STD { int freebsd32_truncate(const char *path, \
+ uint32_t length1, uint32_t length2); }
+480 AUE_FTRUNCATE STD { int freebsd32_ftruncate(int fd, \
+ uint32_t length1, uint32_t length2); }
+#endif
+481 AUE_THR_KILL2 NOPROTO { int thr_kill2(pid_t pid, long id, int sig); }
+482 AUE_SHMOPEN COMPAT12|NOPROTO { int shm_open( \
+ const char *path, int flags, mode_t mode); }
+483 AUE_SHMUNLINK NOPROTO { int shm_unlink(const char *path); }
+484 AUE_NULL NOPROTO { int cpuset(cpusetid_t *setid); }
+#ifdef PAD64_REQUIRED
+485 AUE_NULL STD { int freebsd32_cpuset_setid(cpuwhich_t which, \
+ int pad, \
+ uint32_t id1, uint32_t id2, \
+ cpusetid_t setid); }
+#else
+485 AUE_NULL STD { int freebsd32_cpuset_setid(cpuwhich_t which, \
+ uint32_t id1, uint32_t id2, \
+ cpusetid_t setid); }
+#endif
+486 AUE_NULL STD { int freebsd32_cpuset_getid(cpulevel_t level, \
+ cpuwhich_t which, \
+ uint32_t id1, uint32_t id2, \
+ cpusetid_t *setid); }
+487 AUE_NULL STD { int freebsd32_cpuset_getaffinity( \
+ cpulevel_t level, cpuwhich_t which, \
+ uint32_t id1, uint32_t id2, \
+ size_t cpusetsize, \
+ cpuset_t *mask); }
+488 AUE_NULL STD { int freebsd32_cpuset_setaffinity( \
+ cpulevel_t level, cpuwhich_t which, \
+ uint32_t id1, uint32_t id2, \
+ size_t cpusetsize, \
+ const cpuset_t *mask); }
+489 AUE_FACCESSAT NOPROTO { int faccessat(int fd, const char *path, \
+ int amode, int flag); }
+490 AUE_FCHMODAT NOPROTO { int fchmodat(int fd, const char *path, \
+ mode_t mode, int flag); }
+491 AUE_FCHOWNAT NOPROTO { int fchownat(int fd, const char *path, \
+ uid_t uid, gid_t gid, int flag); }
+492 AUE_FEXECVE STD { int freebsd32_fexecve(int fd, \
+ uint32_t *argv, uint32_t *envv); }
+493 AUE_FSTATAT COMPAT11 { int freebsd32_fstatat(int fd, \
+ const char *path, \
+ struct freebsd11_stat32 *buf, \
+ int flag); }
+494 AUE_FUTIMESAT STD { int freebsd32_futimesat(int fd, \
+ const char *path, \
+ struct timeval *times); }
+495 AUE_LINKAT NOPROTO { int linkat(int fd1, const char *path1, \
+ int fd2, const char *path2, int flag); }
+496 AUE_MKDIRAT NOPROTO { int mkdirat(int fd, const char *path, \
+ mode_t mode); }
+497 AUE_MKFIFOAT NOPROTO { int mkfifoat(int fd, const char *path, \
+ mode_t mode); }
+498 AUE_MKNODAT COMPAT11|NOPROTO { int mknodat(int fd, \
+ const char *path, mode_t mode, \
+ uint32_t dev); }
+499 AUE_OPENAT_RWTC NOPROTO { int openat(int fd, const char *path, \
+ int flag, mode_t mode); }
+500 AUE_READLINKAT NOPROTO { ssize_t readlinkat(int fd, const char *path, \
+ char *buf, size_t bufsize); }
+501 AUE_RENAMEAT NOPROTO { int renameat(int oldfd, const char *old, \
+ int newfd, const char *new); }
+502 AUE_SYMLINKAT NOPROTO { int symlinkat(const char *path1, int fd, \
+ const char *path2); }
+503 AUE_UNLINKAT NOPROTO { int unlinkat(int fd, const char *path, \
+ int flag); }
+504 AUE_POSIX_OPENPT NOPROTO { int posix_openpt(int flags); }
+; 505 is initialised by the kgssapi code, if present.
+505 AUE_NULL UNIMPL gssd_syscall
+506 AUE_JAIL_GET STD { int freebsd32_jail_get(struct iovec32 *iovp, \
+ unsigned int iovcnt, int flags); }
+507 AUE_JAIL_SET STD { int freebsd32_jail_set(struct iovec32 *iovp, \
+ unsigned int iovcnt, int flags); }
+508 AUE_JAIL_REMOVE NOPROTO { int jail_remove(int jid); }
+509 AUE_CLOSEFROM COMPAT12|NOPROTO { int closefrom(int lowfd); }
+510 AUE_SEMCTL NOSTD { int freebsd32_semctl(int semid, int semnum, \
+ int cmd, union semun32 *arg); }
+511 AUE_MSGCTL NOSTD { int freebsd32_msgctl(int msqid, int cmd, \
+ struct msqid_ds32 *buf); }
+512 AUE_SHMCTL NOSTD { int freebsd32_shmctl(int shmid, int cmd, \
+ struct shmid_ds32 *buf); }
+513 AUE_LPATHCONF NOPROTO { int lpathconf(const char *path, int name); }
+514 AUE_NULL OBSOL cap_new
+515 AUE_CAP_RIGHTS_GET NOPROTO { int __cap_rights_get(int version, \
+ int fd, cap_rights_t *rightsp); }
+516 AUE_CAP_ENTER NOPROTO { int cap_enter(void); }
+517 AUE_CAP_GETMODE NOPROTO { int cap_getmode(u_int *modep); }
+518 AUE_PDFORK NOPROTO { int pdfork(int *fdp, int flags); }
+519 AUE_PDKILL NOPROTO { int pdkill(int fd, int signum); }
+520 AUE_PDGETPID NOPROTO { int pdgetpid(int fd, pid_t *pidp); }
+521 AUE_PDWAIT UNIMPL pdwait4
+522 AUE_SELECT STD { int freebsd32_pselect(int nd, fd_set *in, \
+ fd_set *ou, fd_set *ex, \
+ const struct timespec32 *ts, \
+ const sigset_t *sm); }
+523 AUE_GETLOGINCLASS NOPROTO { int getloginclass(char *namebuf, \
+ size_t namelen); }
+524 AUE_SETLOGINCLASS NOPROTO { int setloginclass(const char *namebuf); }
+525 AUE_NULL NOPROTO { int rctl_get_racct(const void *inbufp, \
+ size_t inbuflen, void *outbufp, \
+ size_t outbuflen); }
+526 AUE_NULL NOPROTO { int rctl_get_rules(const void *inbufp, \
+ size_t inbuflen, void *outbufp, \
+ size_t outbuflen); }
+527 AUE_NULL NOPROTO { int rctl_get_limits(const void *inbufp, \
+ size_t inbuflen, void *outbufp, \
+ size_t outbuflen); }
+528 AUE_NULL NOPROTO { int rctl_add_rule(const void *inbufp, \
+ size_t inbuflen, void *outbufp, \
+ size_t outbuflen); }
+529 AUE_NULL NOPROTO { int rctl_remove_rule(const void *inbufp, \
+ size_t inbuflen, void *outbufp, \
+ size_t outbuflen); }
+#ifdef PAD64_REQUIRED
+530 AUE_POSIX_FALLOCATE STD { int freebsd32_posix_fallocate(int fd, \
+ int pad, \
+ uint32_t offset1, uint32_t offset2,\
+ uint32_t len1, uint32_t len2); }
+531 AUE_POSIX_FADVISE STD { int freebsd32_posix_fadvise(int fd, \
+ int pad, \
+ uint32_t offset1, uint32_t offset2,\
+ uint32_t len1, uint32_t len2, \
+ int advice); }
+532 AUE_WAIT6 STD { int freebsd32_wait6(int idtype, int pad, \
+ uint32_t id1, uint32_t id2, \
+ int *status, int options, \
+ struct wrusage32 *wrusage, \
+ siginfo_t *info); }
+#else
+530 AUE_POSIX_FALLOCATE STD { int freebsd32_posix_fallocate(int fd,\
+ uint32_t offset1, uint32_t offset2,\
+ uint32_t len1, uint32_t len2); }
+531 AUE_POSIX_FADVISE STD { int freebsd32_posix_fadvise(int fd, \
+ uint32_t offset1, uint32_t offset2,\
+ uint32_t len1, uint32_t len2, \
+ int advice); }
+532 AUE_WAIT6 STD { int freebsd32_wait6(int idtype, \
+ uint32_t id1, uint32_t id2, \
+ int *status, int options, \
+ struct wrusage32 *wrusage, \
+ siginfo_t *info); }
+#endif
+533 AUE_CAP_RIGHTS_LIMIT NOPROTO { \
+ int cap_rights_limit(int fd, \
+ cap_rights_t *rightsp); }
+534 AUE_CAP_IOCTLS_LIMIT STD { \
+ int freebsd32_cap_ioctls_limit(int fd, \
+ const uint32_t *cmds, size_t ncmds); }
+535 AUE_CAP_IOCTLS_GET STD { \
+ ssize_t freebsd32_cap_ioctls_get(int fd, \
+ uint32_t *cmds, size_t maxcmds); }
+536 AUE_CAP_FCNTLS_LIMIT NOPROTO { int cap_fcntls_limit(int fd, \
+ uint32_t fcntlrights); }
+537 AUE_CAP_FCNTLS_GET NOPROTO { int cap_fcntls_get(int fd, \
+ uint32_t *fcntlrightsp); }
+538 AUE_BINDAT NOPROTO { int bindat(int fd, int s, \
+ const struct sockaddr *name, \
+ int namelen); }
+539 AUE_CONNECTAT NOPROTO { int connectat(int fd, int s, \
+ const struct sockaddr *name, \
+ int namelen); }
+540 AUE_CHFLAGSAT NOPROTO { int chflagsat(int fd, const char *path, \
+ u_long flags, int atflag); }
+541 AUE_ACCEPT NOPROTO { int accept4(int s, \
+ struct sockaddr *name, \
+ __socklen_t *anamelen, \
+ int flags); }
+542 AUE_PIPE NOPROTO { int pipe2(int *fildes, int flags); }
+543 AUE_AIO_MLOCK STD { int freebsd32_aio_mlock( \
+ struct aiocb32 *aiocbp); }
+#ifdef PAD64_REQUIRED
+544 AUE_PROCCTL STD { int freebsd32_procctl(int idtype, int pad, \
+ uint32_t id1, uint32_t id2, int com, \
+ void *data); }
+#else
+544 AUE_PROCCTL STD { int freebsd32_procctl(int idtype, \
+ uint32_t id1, uint32_t id2, int com, \
+ void *data); }
+#endif
+545 AUE_POLL STD { int freebsd32_ppoll(struct pollfd *fds, \
+ u_int nfds, const struct timespec32 *ts, \
+ const sigset_t *set); }
+546 AUE_FUTIMES STD { int freebsd32_futimens(int fd, \
+ struct timespec *times); }
+547 AUE_FUTIMESAT STD { int freebsd32_utimensat(int fd, \
+ const char *path, \
+ struct timespec *times, int flag); }
+548 AUE_NULL OBSOL numa_getaffinity
+549 AUE_NULL OBSOL numa_setaffinity
+550 AUE_FSYNC NOPROTO { int fdatasync(int fd); }
+551 AUE_FSTAT STD { int freebsd32_fstat(int fd, \
+ struct stat32 *ub); }
+552 AUE_FSTATAT STD { int freebsd32_fstatat(int fd, \
+ const char *path, struct stat32 *buf, \
+ int flag); }
+553 AUE_FHSTAT STD { int freebsd32_fhstat( \
+ const struct fhandle *u_fhp, \
+ struct stat32 *sb); }
+554 AUE_GETDIRENTRIES NOPROTO { ssize_t getdirentries( \
+ int fd, char *buf, size_t count, \
+ off_t *basep); }
+555 AUE_STATFS NOPROTO { int statfs(const char *path, \
+ struct statfs32 *buf); }
+556 AUE_FSTATFS NOPROTO { int fstatfs(int fd, struct statfs32 *buf); }
+557 AUE_GETFSSTAT NOPROTO { int getfsstat(struct statfs32 *buf, \
+ long bufsize, int mode); }
+558 AUE_FHSTATFS NOPROTO { int fhstatfs(const struct fhandle *u_fhp, \
+ struct statfs32 *buf); }
+#ifdef PAD64_REQUIRED
+559 AUE_MKNODAT STD { int freebsd32_mknodat(int fd, \
+ const char *path, mode_t mode, \
+ int pad, uint32_t dev1, uint32_t dev2); }
+#else
+559 AUE_MKNODAT STD { int freebsd32_mknodat(int fd, \
+ const char *path, mode_t mode, \
+ uint32_t dev1, uint32_t dev2); }
+#endif
+560 AUE_KEVENT STD { int freebsd32_kevent(int fd, \
+ const struct kevent32 *changelist, \
+ int nchanges, \
+ struct kevent32 *eventlist, \
+ int nevents, \
+ const struct timespec32 *timeout); }
+561 AUE_NULL STD { int freebsd32_cpuset_getdomain(cpulevel_t level, \
+ cpuwhich_t which, uint32_t id1, uint32_t id2, \
+ size_t domainsetsize, domainset_t *mask, \
+ int *policy); }
+562 AUE_NULL STD { int freebsd32_cpuset_setdomain(cpulevel_t level, \
+ cpuwhich_t which, uint32_t id1, uint32_t id2, \
+ size_t domainsetsize, domainset_t *mask, \
+ int policy); }
+563 AUE_NULL NOPROTO { int getrandom(void *buf, size_t buflen, \
+ unsigned int flags); }
+564 AUE_NULL NOPROTO { int getfhat( int fd, char *path, \
+ struct fhandle *fhp, int flags); }
+565 AUE_NULL NOPROTO { int fhlink( struct fhandle *fhp, const char *to ); }
+566 AUE_NULL NOPROTO { int fhlinkat( struct fhandle *fhp, int tofd, \
+ const char *to); }
+567 AUE_NULL NOPROTO { int fhreadlink( struct fhandle *fhp, char *buf, \
+ size_t bufsize); }
+568 AUE_UNLINKAT NOPROTO { int funlinkat(int dfd, const char *path, int fd, \
+ int flag); }
+569 AUE_NULL NOPROTO { ssize_t copy_file_range(int infd, \
+ off_t *inoffp, int outfd, off_t *outoffp, \
+ size_t len, unsigned int flags); }
+570 AUE_SYSCTL STD { int freebsd32___sysctlbyname(const char *name, \
+ size_t namelen, void *old, uint32_t *oldlenp, \
+ void *new, size_t newlen); }
+571 AUE_SHMOPEN NOPROTO { int shm_open2( \
+ const char *path, int flags, mode_t mode, \
+ int shmflags, const char *name); }
+572 AUE_SHMRENAME NOPROTO { int shm_rename(const char *path_from, \
+ const char *path_to, int flags); }
+573 AUE_NULL NOPROTO { int sigfastblock(int cmd, uint32_t *ptr); }
+574 AUE_REALPATHAT NOPROTO { int __realpathat(int fd, const char *path, \
+ char *buf, size_t size, int flags); }
+575 AUE_CLOSERANGE NOPROTO { int close_range(u_int lowfd, u_int highfd, \
+ int flags); }
+; 576 is initialised by the krpc code, if present.
+576 AUE_NULL NOSTD|NOPROTO { int rpctls_syscall(int op, \
+ const char *path); }
+577 AUE_SPECIALFD NOPROTO { int __specialfd(int type, const void *req, \
+ size_t len); }
+578 AUE_AIO_WRITEV STD { int freebsd32_aio_writev( \
+ struct aiocb32 *aiocbp); }
+579 AUE_AIO_READV STD { int freebsd32_aio_readv( \
+ struct aiocb32 *aiocbp); }
+
+; vim: syntax=off
diff --git a/sys/compat/ia32/ia32_genassym.c b/sys/compat/ia32/ia32_genassym.c
new file mode 100644
index 000000000000..5a1faae892db
--- /dev/null
+++ b/sys/compat/ia32/ia32_genassym.c
@@ -0,0 +1,27 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/assym.h>
+#include <sys/systm.h>
+#include <sys/signal.h>
+
+#include <compat/freebsd32/freebsd32_signal.h>
+#include <compat/ia32/ia32_signal.h>
+
+ASSYM(IA32_SIGF_HANDLER, offsetof(struct ia32_sigframe, sf_ah));
+ASSYM(IA32_SIGF_UC, offsetof(struct ia32_sigframe, sf_uc));
+#ifdef COMPAT_43
+ASSYM(IA32_SIGF_SC, offsetof(struct ia32_sigframe3, sf_siginfo.si_sc));
+#endif
+ASSYM(IA32_UC_GS, offsetof(struct ia32_ucontext, uc_mcontext.mc_gs));
+ASSYM(IA32_UC_FS, offsetof(struct ia32_ucontext, uc_mcontext.mc_fs));
+ASSYM(IA32_UC_ES, offsetof(struct ia32_ucontext, uc_mcontext.mc_es));
+ASSYM(IA32_UC_DS, offsetof(struct ia32_ucontext, uc_mcontext.mc_ds));
+#ifdef COMPAT_FREEBSD4
+ASSYM(IA32_SIGF_UC4, offsetof(struct ia32_sigframe4, sf_uc));
+ASSYM(IA32_UC4_GS, offsetof(struct ia32_ucontext4, uc_mcontext.mc_gs));
+ASSYM(IA32_UC4_FS, offsetof(struct ia32_ucontext4, uc_mcontext.mc_fs));
+ASSYM(IA32_UC4_ES, offsetof(struct ia32_ucontext4, uc_mcontext.mc_es));
+ASSYM(IA32_UC4_DS, offsetof(struct ia32_ucontext4, uc_mcontext.mc_ds));
+#endif
diff --git a/sys/compat/ia32/ia32_signal.h b/sys/compat/ia32/ia32_signal.h
new file mode 100644
index 000000000000..e5fb8ec90fa2
--- /dev/null
+++ b/sys/compat/ia32/ia32_signal.h
@@ -0,0 +1,211 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1999 Marcel Moolenaar
+ * Copyright (c) 2003 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _COMPAT_IA32_IA32_SIGNAL_H
+#define _COMPAT_IA32_IA32_SIGNAL_H
+
+#include <compat/freebsd32/freebsd32_signal.h>
+
+#define _MC_IA32_HASSEGS 0x1
+#define _MC_IA32_HASBASES 0x2
+#define _MC_IA32_HASFPXSTATE 0x4
+#define _MC_IA32_FLAG_MASK \
+ (_MC_IA32_HASSEGS | _MC_IA32_HASBASES | _MC_IA32_HASFPXSTATE)
+
+struct ia32_mcontext {
+ u_int32_t mc_onstack; /* XXX - sigcontext compat. */
+ u_int32_t mc_gs; /* machine state (struct trapframe) */
+ u_int32_t mc_fs;
+ u_int32_t mc_es;
+ u_int32_t mc_ds;
+ u_int32_t mc_edi;
+ u_int32_t mc_esi;
+ u_int32_t mc_ebp;
+ u_int32_t mc_isp;
+ u_int32_t mc_ebx;
+ u_int32_t mc_edx;
+ u_int32_t mc_ecx;
+ u_int32_t mc_eax;
+ u_int32_t mc_trapno;
+ u_int32_t mc_err;
+ u_int32_t mc_eip;
+ u_int32_t mc_cs;
+ u_int32_t mc_eflags;
+ u_int32_t mc_esp;
+ u_int32_t mc_ss;
+ u_int32_t mc_len; /* sizeof(struct ia32_mcontext) */
+ /* We use the same values for fpformat and ownedfp */
+ u_int32_t mc_fpformat;
+ u_int32_t mc_ownedfp;
+ u_int32_t mc_flags;
+ /*
+ * See <i386/include/npx.h> for the internals of mc_fpstate[].
+ */
+ u_int32_t mc_fpstate[128] __aligned(16);
+ u_int32_t mc_fsbase;
+ u_int32_t mc_gsbase;
+ u_int32_t mc_xfpustate;
+ u_int32_t mc_xfpustate_len;
+ u_int32_t mc_spare2[4];
+};
+
+struct ia32_ucontext {
+ sigset_t uc_sigmask;
+ struct ia32_mcontext uc_mcontext;
+ u_int32_t uc_link;
+ struct sigaltstack32 uc_stack;
+ u_int32_t uc_flags;
+ u_int32_t __spare__[4];
+};
+
+#if defined(COMPAT_FREEBSD4)
+struct ia32_mcontext4 {
+ u_int32_t mc_onstack; /* XXX - sigcontext compat. */
+ u_int32_t mc_gs; /* machine state (struct trapframe) */
+ u_int32_t mc_fs;
+ u_int32_t mc_es;
+ u_int32_t mc_ds;
+ u_int32_t mc_edi;
+ u_int32_t mc_esi;
+ u_int32_t mc_ebp;
+ u_int32_t mc_isp;
+ u_int32_t mc_ebx;
+ u_int32_t mc_edx;
+ u_int32_t mc_ecx;
+ u_int32_t mc_eax;
+ u_int32_t mc_trapno;
+ u_int32_t mc_err;
+ u_int32_t mc_eip;
+ u_int32_t mc_cs;
+ u_int32_t mc_eflags;
+ u_int32_t mc_esp;
+ u_int32_t mc_ss;
+ u_int32_t mc_fpregs[28];
+ u_int32_t __spare__[17];
+};
+
+struct ia32_ucontext4 {
+ sigset_t uc_sigmask;
+ struct ia32_mcontext4 uc_mcontext;
+ u_int32_t uc_link;
+ struct sigaltstack32 uc_stack;
+ u_int32_t __spare__[8];
+};
+#endif
+
+#ifdef COMPAT_43
+struct ia32_sigcontext3 {
+ u_int32_t sc_onstack;
+ u_int32_t sc_mask;
+ u_int32_t sc_esp;
+ u_int32_t sc_ebp;
+ u_int32_t sc_isp;
+ u_int32_t sc_eip;
+ u_int32_t sc_eflags;
+ u_int32_t sc_es;
+ u_int32_t sc_ds;
+ u_int32_t sc_cs;
+ u_int32_t sc_ss;
+ u_int32_t sc_edi;
+ u_int32_t sc_esi;
+ u_int32_t sc_ebx;
+ u_int32_t sc_edx;
+ u_int32_t sc_ecx;
+ u_int32_t sc_eax;
+ u_int32_t sc_gs;
+ u_int32_t sc_fs;
+ u_int32_t sc_trapno;
+ u_int32_t sc_err;
+};
+#endif
+
+/*
+ * Signal frames, arguments passed to application signal handlers.
+ */
+
+#ifdef COMPAT_FREEBSD4
+struct ia32_sigframe4 {
+ u_int32_t sf_signum;
+ u_int32_t sf_siginfo; /* code or pointer to sf_si */
+ u_int32_t sf_ucontext; /* points to sf_uc */
+ u_int32_t sf_addr; /* undocumented 4th arg */
+ u_int32_t sf_ah; /* action/handler pointer */
+ struct ia32_ucontext4 sf_uc; /* = *sf_ucontext */
+ struct siginfo32 sf_si; /* = *sf_siginfo (SA_SIGINFO case) */
+};
+#endif
+
+struct ia32_sigframe {
+ u_int32_t sf_signum;
+ u_int32_t sf_siginfo; /* code or pointer to sf_si */
+ u_int32_t sf_ucontext; /* points to sf_uc */
+ u_int32_t sf_addr; /* undocumented 4th arg */
+ u_int32_t sf_ah; /* action/handler pointer */
+ /* Beware, hole due to ucontext being 16 byte aligned! */
+ struct ia32_ucontext sf_uc; /* = *sf_ucontext */
+ struct siginfo32 sf_si; /* = *sf_siginfo (SA_SIGINFO case) */
+};
+
+#ifdef COMPAT_43
+struct ia32_siginfo3 {
+ struct ia32_sigcontext3 si_sc;
+ int si_signo;
+ int si_code;
+ union sigval32 si_value;
+};
+struct ia32_sigframe3 {
+ int sf_signum;
+ u_int32_t sf_arg2; /* int or siginfo_t */
+ u_int32_t sf_scp;
+ u_int32_t sf_addr;
+ u_int32_t sf_ah; /* action/handler pointer */
+ struct ia32_siginfo3 sf_siginfo;
+};
+#endif
+
+struct ksiginfo;
+struct image_params;
+extern char ia32_sigcode[];
+extern char freebsd4_ia32_sigcode[];
+extern char ia32_osigcode[];
+extern char lcall_tramp;
+extern int sz_ia32_sigcode;
+extern int sz_freebsd4_ia32_sigcode;
+extern int sz_ia32_osigcode;
+extern int sz_lcall_tramp;
+void ia32_sendsig(sig_t, struct ksiginfo *, sigset_t *);
+void ia32_setregs(struct thread *td, struct image_params *imgp,
+ uintptr_t stack);
+int setup_lcall_gate(void);
+
+#endif
diff --git a/sys/compat/ia32/ia32_sysvec.c b/sys/compat/ia32/ia32_sysvec.c
new file mode 100644
index 000000000000..f5a2c1200fc6
--- /dev/null
+++ b/sys/compat/ia32/ia32_sysvec.c
@@ -0,0 +1,233 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2002 Doug Rabson
+ * Copyright (c) 2003 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define __ELF_WORD_SIZE 32
+
+#include <sys/param.h>
+#include <sys/exec.h>
+#include <sys/fcntl.h>
+#include <sys/imgact.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/mman.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/procfs.h>
+#include <sys/resourcevar.h>
+#include <sys/systm.h>
+#include <sys/signalvar.h>
+#include <sys/stat.h>
+#include <sys/sx.h>
+#include <sys/syscall.h>
+#include <sys/sysctl.h>
+#include <sys/sysent.h>
+#include <sys/vnode.h>
+#include <sys/imgact_elf.h>
+
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_extern.h>
+
+#include <compat/freebsd32/freebsd32_signal.h>
+#include <compat/freebsd32/freebsd32_util.h>
+#include <compat/freebsd32/freebsd32_proto.h>
+#include <compat/freebsd32/freebsd32_syscall.h>
+#include <compat/ia32/ia32_signal.h>
+#include <machine/frame.h>
+#include <machine/md_var.h>
+#include <machine/pcb.h>
+#include <machine/cpufunc.h>
+
+CTASSERT(sizeof(struct ia32_mcontext) == 640);
+CTASSERT(sizeof(struct ia32_ucontext) == 704);
+CTASSERT(sizeof(struct ia32_sigframe) == 800);
+CTASSERT(sizeof(struct siginfo32) == 64);
+#ifdef COMPAT_FREEBSD4
+CTASSERT(sizeof(struct ia32_mcontext4) == 260);
+CTASSERT(sizeof(struct ia32_ucontext4) == 324);
+CTASSERT(sizeof(struct ia32_sigframe4) == 408);
+#endif
+
+extern const char *freebsd32_syscallnames[];
+
+static SYSCTL_NODE(_compat, OID_AUTO, ia32, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
+ "ia32 mode");
+
+static u_long ia32_maxdsiz = IA32_MAXDSIZ;
+SYSCTL_ULONG(_compat_ia32, OID_AUTO, maxdsiz, CTLFLAG_RWTUN, &ia32_maxdsiz, 0, "");
+u_long ia32_maxssiz = IA32_MAXSSIZ;
+SYSCTL_ULONG(_compat_ia32, OID_AUTO, maxssiz, CTLFLAG_RWTUN, &ia32_maxssiz, 0, "");
+static u_long ia32_maxvmem = IA32_MAXVMEM;
+SYSCTL_ULONG(_compat_ia32, OID_AUTO, maxvmem, CTLFLAG_RWTUN, &ia32_maxvmem, 0, "");
+
+struct sysentvec ia32_freebsd_sysvec = {
+ .sv_size = FREEBSD32_SYS_MAXSYSCALL,
+ .sv_table = freebsd32_sysent,
+ .sv_transtrap = NULL,
+ .sv_fixup = elf32_freebsd_fixup,
+ .sv_sendsig = ia32_sendsig,
+ .sv_sigcode = ia32_sigcode,
+ .sv_szsigcode = &sz_ia32_sigcode,
+ .sv_name = "FreeBSD ELF32",
+ .sv_coredump = elf32_coredump,
+ .sv_imgact_try = NULL,
+ .sv_minsigstksz = MINSIGSTKSZ,
+ .sv_minuser = FREEBSD32_MINUSER,
+ .sv_maxuser = FREEBSD32_MAXUSER,
+ .sv_usrstack = FREEBSD32_USRSTACK,
+ .sv_psstrings = FREEBSD32_PS_STRINGS,
+ .sv_stackprot = VM_PROT_ALL,
+ .sv_copyout_auxargs = elf32_freebsd_copyout_auxargs,
+ .sv_copyout_strings = freebsd32_copyout_strings,
+ .sv_setregs = ia32_setregs,
+ .sv_fixlimit = ia32_fixlimit,
+ .sv_maxssiz = &ia32_maxssiz,
+ .sv_flags = SV_ABI_FREEBSD | SV_ASLR | SV_IA32 | SV_ILP32 |
+ SV_SHP | SV_TIMEKEEP | SV_RNG_SEED_VER,
+ .sv_set_syscall_retval = ia32_set_syscall_retval,
+ .sv_fetch_syscall_args = ia32_fetch_syscall_args,
+ .sv_syscallnames = freebsd32_syscallnames,
+ .sv_shared_page_base = FREEBSD32_SHAREDPAGE,
+ .sv_shared_page_len = PAGE_SIZE,
+ .sv_schedtail = NULL,
+ .sv_thread_detach = NULL,
+ .sv_trap = NULL,
+ .sv_stackgap = elf32_stackgap,
+};
+INIT_SYSENTVEC(elf_ia32_sysvec, &ia32_freebsd_sysvec);
+
+static Elf32_Brandinfo ia32_brand_info = {
+ .brand = ELFOSABI_FREEBSD,
+ .machine = EM_386,
+ .compat_3_brand = "FreeBSD",
+ .emul_path = NULL,
+ .interp_path = "/libexec/ld-elf.so.1",
+ .sysvec = &ia32_freebsd_sysvec,
+ .interp_newpath = "/libexec/ld-elf32.so.1",
+ .brand_note = &elf32_freebsd_brandnote,
+ .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE
+};
+
+SYSINIT(ia32, SI_SUB_EXEC, SI_ORDER_MIDDLE,
+ (sysinit_cfunc_t) elf32_insert_brand_entry,
+ &ia32_brand_info);
+
+static Elf32_Brandinfo ia32_brand_oinfo = {
+ .brand = ELFOSABI_FREEBSD,
+ .machine = EM_386,
+ .compat_3_brand = "FreeBSD",
+ .emul_path = NULL,
+ .interp_path = "/usr/libexec/ld-elf.so.1",
+ .sysvec = &ia32_freebsd_sysvec,
+ .interp_newpath = "/libexec/ld-elf32.so.1",
+ .brand_note = &elf32_freebsd_brandnote,
+ .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE
+};
+
+SYSINIT(oia32, SI_SUB_EXEC, SI_ORDER_ANY,
+ (sysinit_cfunc_t) elf32_insert_brand_entry,
+ &ia32_brand_oinfo);
+
+static Elf32_Brandinfo kia32_brand_info = {
+ .brand = ELFOSABI_FREEBSD,
+ .machine = EM_386,
+ .compat_3_brand = "FreeBSD",
+ .emul_path = NULL,
+ .interp_path = "/lib/ld.so.1",
+ .sysvec = &ia32_freebsd_sysvec,
+ .brand_note = &elf32_kfreebsd_brandnote,
+ .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE_MANDATORY
+};
+
+SYSINIT(kia32, SI_SUB_EXEC, SI_ORDER_ANY,
+ (sysinit_cfunc_t) elf32_insert_brand_entry,
+ &kia32_brand_info);
+
+void
+elf32_dump_thread(struct thread *td, void *dst, size_t *off)
+{
+ void *buf;
+ size_t len;
+
+ len = 0;
+ if (use_xsave) {
+ if (dst != NULL) {
+ fpugetregs(td);
+ len += elf32_populate_note(NT_X86_XSTATE,
+ get_pcb_user_save_td(td), dst,
+ cpu_max_ext_state_size, &buf);
+ *(uint64_t *)((char *)buf + X86_XSTATE_XCR0_OFFSET) =
+ xsave_mask;
+ } else
+ len += elf32_populate_note(NT_X86_XSTATE, NULL, NULL,
+ cpu_max_ext_state_size, NULL);
+ }
+ *off = len;
+}
+
+void
+ia32_fixlimit(struct rlimit *rl, int which)
+{
+
+ switch (which) {
+ case RLIMIT_DATA:
+ if (ia32_maxdsiz != 0) {
+ if (rl->rlim_cur > ia32_maxdsiz)
+ rl->rlim_cur = ia32_maxdsiz;
+ if (rl->rlim_max > ia32_maxdsiz)
+ rl->rlim_max = ia32_maxdsiz;
+ }
+ break;
+ case RLIMIT_STACK:
+ if (ia32_maxssiz != 0) {
+ if (rl->rlim_cur > ia32_maxssiz)
+ rl->rlim_cur = ia32_maxssiz;
+ if (rl->rlim_max > ia32_maxssiz)
+ rl->rlim_max = ia32_maxssiz;
+ }
+ break;
+ case RLIMIT_VMEM:
+ if (ia32_maxvmem != 0) {
+ if (rl->rlim_cur > ia32_maxvmem)
+ rl->rlim_cur = ia32_maxvmem;
+ if (rl->rlim_max > ia32_maxvmem)
+ rl->rlim_max = ia32_maxvmem;
+ }
+ break;
+ }
+}
diff --git a/sys/compat/ia32/ia32_util.h b/sys/compat/ia32/ia32_util.h
new file mode 100644
index 000000000000..8a41b90b2afa
--- /dev/null
+++ b/sys/compat/ia32/ia32_util.h
@@ -0,0 +1,59 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1998-1999 Andrew Gallatin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _COMPAT_IA32_IA32_UTIL_H
+#define _COMPAT_IA32_IA32_UTIL_H
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+
+#include <sys/exec.h>
+#include <sys/sysent.h>
+#include <sys/cdefs.h>
+
+#define FREEBSD32_MAXUSER ((1ul << 32) - IA32_PAGE_SIZE)
+#define FREEBSD32_MINUSER 0
+#define FREEBSD32_SHAREDPAGE (FREEBSD32_MAXUSER - IA32_PAGE_SIZE)
+#define FREEBSD32_USRSTACK FREEBSD32_SHAREDPAGE
+
+#define IA32_PAGE_SIZE 4096
+#define IA32_MAXDSIZ (512*1024*1024) /* 512MB */
+#define IA32_MAXSSIZ (64*1024*1024) /* 64MB */
+#define IA32_MAXVMEM 0 /* Unlimited */
+
+struct syscall_args;
+int ia32_fetch_syscall_args(struct thread *td);
+void ia32_set_syscall_retval(struct thread *, int);
+void ia32_fixlimit(struct rlimit *rl, int which);
+
+#endif /* _COMPAT_IA32_IA32_UTIL_H */
diff --git a/sys/compat/lindebugfs/lindebugfs.c b/sys/compat/lindebugfs/lindebugfs.c
new file mode 100644
index 000000000000..63161eedf14f
--- /dev/null
+++ b/sys/compat/lindebugfs/lindebugfs.c
@@ -0,0 +1,319 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2016-2018, Matthew Macy <mmacy@freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/queue.h>
+#include <sys/blist.h>
+#include <sys/conf.h>
+#include <sys/exec.h>
+#include <sys/filedesc.h>
+#include <sys/kernel.h>
+#include <sys/linker.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/resourcevar.h>
+#include <sys/sbuf.h>
+#include <sys/smp.h>
+#include <sys/socket.h>
+#include <sys/vnode.h>
+#include <sys/bus.h>
+#include <sys/pciio.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+
+#include <net/if.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <vm/vm_param.h>
+#include <vm/vm_object.h>
+#include <vm/swap_pager.h>
+
+#include <machine/bus.h>
+
+#include <compat/linux/linux_ioctl.h>
+#include <compat/linux/linux_mib.h>
+#include <compat/linux/linux_util.h>
+#include <fs/pseudofs/pseudofs.h>
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/compat.h>
+
+MALLOC_DEFINE(M_DFSINT, "debugfsint", "Linux debugfs internal");
+
+static struct pfs_node *debugfs_root;
+
+#define DM_SYMLINK 0x1
+#define DM_DIR 0x2
+#define DM_FILE 0x3
+
+struct dentry_meta {
+ struct dentry dm_dnode;
+ const struct file_operations *dm_fops;
+ void *dm_data;
+ umode_t dm_mode;
+ int dm_type;
+};
+
+static int
+debugfs_attr(PFS_ATTR_ARGS)
+{
+ struct dentry_meta *dm;
+
+ dm = pn->pn_data;
+
+ vap->va_mode = dm->dm_mode;
+ return (0);
+}
+
+static int
+debugfs_destroy(PFS_DESTROY_ARGS)
+{
+ struct dentry_meta *dm;
+
+ dm = pn->pn_data;
+ if (dm->dm_type == DM_SYMLINK)
+ free(dm->dm_data, M_DFSINT);
+
+ free(dm, M_DFSINT);
+ return (0);
+}
+
+static int
+debugfs_fill(PFS_FILL_ARGS)
+{
+ struct dentry_meta *d;
+ struct linux_file lf;
+ struct seq_file *sf;
+ struct vnode vn;
+ void *buf;
+ int rc;
+ size_t len;
+ off_t off;
+
+ d = pn->pn_data;
+
+ if ((rc = linux_set_current_flags(curthread, M_NOWAIT)))
+ return (rc);
+ vn.v_data = d->dm_data;
+ buf = uio->uio_iov[0].iov_base;
+ len = min(uio->uio_iov[0].iov_len, uio->uio_resid);
+ off = 0;
+ lf.private_data = NULL;
+ rc = d->dm_fops->open(&vn, &lf);
+ if (rc < 0) {
+#ifdef INVARIANTS
+ printf("%s:%d open failed with %d\n", __FUNCTION__, __LINE__, rc);
+#endif
+ return (-rc);
+ }
+ sf = lf.private_data;
+ sf->buf = sb;
+ if (uio->uio_rw == UIO_READ) {
+ if (d->dm_fops->read)
+ rc = d->dm_fops->read(&lf, NULL, len, &off);
+ else
+ rc = ENODEV;
+ } else {
+ if (d->dm_fops->write)
+ rc = d->dm_fops->write(&lf, buf, len, &off);
+ else
+ rc = ENODEV;
+ }
+ if (d->dm_fops->release)
+ d->dm_fops->release(&vn, &lf);
+ else
+ single_release(&vn, &lf);
+
+ if (rc < 0) {
+#ifdef INVARIANTS
+ printf("%s:%d read/write failed with %d\n", __FUNCTION__, __LINE__, rc);
+#endif
+ return (-rc);
+ }
+ return (0);
+}
+
+static int
+debugfs_fill_data(PFS_FILL_ARGS)
+{
+ struct dentry_meta *dm;
+
+ dm = pn->pn_data;
+ sbuf_printf(sb, "%s", (char *)dm->dm_data);
+ return (0);
+}
+
+struct dentry *
+debugfs_create_file(const char *name, umode_t mode,
+ struct dentry *parent, void *data,
+ const struct file_operations *fops)
+{
+ struct dentry_meta *dm;
+ struct dentry *dnode;
+ struct pfs_node *pnode;
+ int flags;
+
+ dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
+ if (dm == NULL)
+ return (NULL);
+ dnode = &dm->dm_dnode;
+ dm->dm_fops = fops;
+ dm->dm_data = data;
+ dm->dm_mode = mode;
+ dm->dm_type = DM_FILE;
+ if (parent != NULL)
+ pnode = parent->d_pfs_node;
+ else
+ pnode = debugfs_root;
+
+ flags = fops->write ? PFS_RDWR : PFS_RD;
+ dnode->d_pfs_node = pfs_create_file(pnode, name, debugfs_fill,
+ debugfs_attr, NULL, debugfs_destroy, flags | PFS_NOWAIT);
+ if (dnode->d_pfs_node == NULL) {
+ free(dm, M_DFSINT);
+ return (NULL);
+ }
+ dnode->d_pfs_node->pn_data = dm;
+
+ return (dnode);
+}
+
+struct dentry *
+debugfs_create_dir(const char *name, struct dentry *parent)
+{
+ struct dentry_meta *dm;
+ struct dentry *dnode;
+ struct pfs_node *pnode;
+
+ dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
+ if (dm == NULL)
+ return (NULL);
+ dnode = &dm->dm_dnode;
+ dm->dm_mode = 0700;
+ dm->dm_type = DM_DIR;
+ if (parent != NULL)
+ pnode = parent->d_pfs_node;
+ else
+ pnode = debugfs_root;
+
+ dnode->d_pfs_node = pfs_create_dir(pnode, name, debugfs_attr, NULL, debugfs_destroy, PFS_RD | PFS_NOWAIT);
+ if (dnode->d_pfs_node == NULL) {
+ free(dm, M_DFSINT);
+ return (NULL);
+ }
+ dnode->d_pfs_node->pn_data = dm;
+ return (dnode);
+}
+
+struct dentry *
+debugfs_create_symlink(const char *name, struct dentry *parent,
+ const char *dest)
+{
+ struct dentry_meta *dm;
+ struct dentry *dnode;
+ struct pfs_node *pnode;
+ void *data;
+
+ data = strdup_flags(dest, M_DFSINT, M_NOWAIT);
+ if (data == NULL)
+ return (NULL);
+ dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
+ if (dm == NULL)
+ goto fail1;
+ dnode = &dm->dm_dnode;
+ dm->dm_mode = 0700;
+ dm->dm_type = DM_SYMLINK;
+ dm->dm_data = data;
+ if (parent != NULL)
+ pnode = parent->d_pfs_node;
+ else
+ pnode = debugfs_root;
+
+ dnode->d_pfs_node = pfs_create_link(pnode, name, &debugfs_fill_data, NULL, NULL, NULL, PFS_NOWAIT);
+ if (dnode->d_pfs_node == NULL)
+ goto fail;
+ dnode->d_pfs_node->pn_data = dm;
+ return (dnode);
+ fail:
+ free(dm, M_DFSINT);
+ fail1:
+ free(data, M_DFSINT);
+ return (NULL);
+}
+
+void
+debugfs_remove(struct dentry *dnode)
+{
+ if (dnode == NULL)
+ return;
+
+ pfs_destroy(dnode->d_pfs_node);
+}
+
+void
+debugfs_remove_recursive(struct dentry *dnode)
+{
+ if (dnode == NULL)
+ return;
+
+ pfs_destroy(dnode->d_pfs_node);
+}
+
+static int
+debugfs_init(PFS_INIT_ARGS)
+{
+
+ debugfs_root = pi->pi_root;
+
+ (void)debugfs_create_symlink("kcov", NULL, "/dev/kcov");
+
+ return (0);
+}
+
+static int
+debugfs_uninit(PFS_INIT_ARGS)
+{
+ return (0);
+}
+
+#ifdef PR_ALLOW_MOUNT_LINSYSFS
+PSEUDOFS(debugfs, 1, PR_ALLOW_MOUNT_LINSYSFS);
+#else
+PSEUDOFS(debugfs, 1, VFCF_JAIL);
+#endif
+MODULE_DEPEND(lindebugfs, linuxkpi, 1, 1, 1);
diff --git a/sys/compat/linprocfs/linprocfs.c b/sys/compat/linprocfs/linprocfs.c
new file mode 100644
index 000000000000..79ffc4dfd5aa
--- /dev/null
+++ b/sys/compat/linprocfs/linprocfs.c
@@ -0,0 +1,2106 @@
+/*-
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
+ * Copyright (c) 2000 Dag-Erling Coïdan Smørgrav
+ * Copyright (c) 1999 Pierre Beyssac
+ * Copyright (c) 1993 Jan-Simon Pendry
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)procfs_status.c 8.4 (Berkeley) 6/15/94
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/blist.h>
+#include <sys/conf.h>
+#include <sys/exec.h>
+#include <sys/fcntl.h>
+#include <sys/filedesc.h>
+#include <sys/jail.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/msg.h>
+#include <sys/mutex.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/ptrace.h>
+#include <sys/resourcevar.h>
+#include <sys/resource.h>
+#include <sys/sbuf.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+#include <sys/smp.h>
+#include <sys/socket.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysctl.h>
+#include <sys/sysent.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/tty.h>
+#include <sys/user.h>
+#include <sys/uuid.h>
+#include <sys/vmmeter.h>
+#include <sys/vnode.h>
+#include <sys/bus.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_types.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <vm/vm_param.h>
+#include <vm/vm_object.h>
+#include <vm/swap_pager.h>
+
+#include <machine/clock.h>
+
+#include <geom/geom.h>
+#include <geom/geom_int.h>
+
+#if defined(__i386__) || defined(__amd64__)
+#include <machine/cputypes.h>
+#include <machine/md_var.h>
+#endif /* __i386__ || __amd64__ */
+
+#include <compat/linux/linux.h>
+#include <compat/linux/linux_mib.h>
+#include <compat/linux/linux_misc.h>
+#include <compat/linux/linux_util.h>
+#include <fs/pseudofs/pseudofs.h>
+#include <fs/procfs/procfs.h>
+
+/*
+ * Various conversion macros
+ */
+#define T2J(x) ((long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to jiffies */
+#define T2CS(x) ((unsigned long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to centiseconds */
+#define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */
+#define B2K(x) ((x) >> 10) /* bytes to kbytes */
+#define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */
+#define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */
+#define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */
+#define TV2J(x) ((x)->tv_sec * 100UL + (x)->tv_usec / 10000)
+
+/**
+ * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
+ *
+ * The linux procfs state field displays one of the characters RSDZTW to
+ * denote running, sleeping in an interruptible wait, waiting in an
+ * uninterruptible disk sleep, a zombie process, process is being traced
+ * or stopped, or process is paging respectively.
+ *
+ * Our struct kinfo_proc contains the variable ki_stat which contains a
+ * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
+ *
+ * This character array is used with ki_stati-1 as an index and tries to
+ * map our states to suitable linux states.
+ */
+static char linux_state[] = "RRSTZDD";
+
+/*
+ * Filler function for proc/meminfo
+ */
+static int
+linprocfs_domeminfo(PFS_FILL_ARGS)
+{
+ unsigned long memtotal; /* total memory in bytes */
+ unsigned long memfree; /* free memory in bytes */
+ unsigned long cached; /* page cache */
+ unsigned long buffers; /* buffer cache */
+ unsigned long long swaptotal; /* total swap space in bytes */
+ unsigned long long swapused; /* used swap space in bytes */
+ unsigned long long swapfree; /* free swap space in bytes */
+ size_t sz;
+ int error, i, j;
+
+ memtotal = physmem * PAGE_SIZE;
+ memfree = (unsigned long)vm_free_count() * PAGE_SIZE;
+ swap_pager_status(&i, &j);
+ swaptotal = (unsigned long long)i * PAGE_SIZE;
+ swapused = (unsigned long long)j * PAGE_SIZE;
+ swapfree = swaptotal - swapused;
+
+ /*
+ * This value may exclude wired pages, but we have no good way of
+ * accounting for that.
+ */
+ cached =
+ (vm_active_count() + vm_inactive_count() + vm_laundry_count()) *
+ PAGE_SIZE;
+
+ sz = sizeof(buffers);
+ error = kernel_sysctlbyname(curthread, "vfs.bufspace", &buffers, &sz,
+ NULL, 0, 0, 0);
+ if (error != 0)
+ buffers = 0;
+
+ sbuf_printf(sb,
+ "MemTotal: %9lu kB\n"
+ "MemFree: %9lu kB\n"
+ "Buffers: %9lu kB\n"
+ "Cached: %9lu kB\n"
+ "SwapTotal:%9llu kB\n"
+ "SwapFree: %9llu kB\n",
+ B2K(memtotal), B2K(memfree), B2K(buffers),
+ B2K(cached), B2K(swaptotal), B2K(swapfree));
+
+ return (0);
+}
+
+#if defined(__i386__) || defined(__amd64__)
+/*
+ * Filler function for proc/cpuinfo (i386 & amd64 version)
+ */
+static int
+linprocfs_docpuinfo(PFS_FILL_ARGS)
+{
+ int hw_model[2];
+ char model[128];
+ uint64_t freq;
+ size_t size;
+ u_int cache_size[4];
+ int fqmhz, fqkhz;
+ int i, j;
+
+ /*
+ * We default the flags to include all non-conflicting flags,
+ * and the Intel versions of conflicting flags.
+ */
+ static char *cpu_feature_names[] = {
+ /* 0 */ "fpu", "vme", "de", "pse",
+ /* 4 */ "tsc", "msr", "pae", "mce",
+ /* 8 */ "cx8", "apic", "", "sep",
+ /* 12 */ "mtrr", "pge", "mca", "cmov",
+ /* 16 */ "pat", "pse36", "pn", "clflush",
+ /* 20 */ "", "dts", "acpi", "mmx",
+ /* 24 */ "fxsr", "sse", "sse2", "ss",
+ /* 28 */ "ht", "tm", "ia64", "pbe"
+ };
+
+ static char *amd_feature_names[] = {
+ /* 0 */ "", "", "", "",
+ /* 4 */ "", "", "", "",
+ /* 8 */ "", "", "", "syscall",
+ /* 12 */ "", "", "", "",
+ /* 16 */ "", "", "", "mp",
+ /* 20 */ "nx", "", "mmxext", "",
+ /* 24 */ "", "fxsr_opt", "pdpe1gb", "rdtscp",
+ /* 28 */ "", "lm", "3dnowext", "3dnow"
+ };
+
+ static char *cpu_feature2_names[] = {
+ /* 0 */ "pni", "pclmulqdq", "dtes64", "monitor",
+ /* 4 */ "ds_cpl", "vmx", "smx", "est",
+ /* 8 */ "tm2", "ssse3", "cid", "sdbg",
+ /* 12 */ "fma", "cx16", "xtpr", "pdcm",
+ /* 16 */ "", "pcid", "dca", "sse4_1",
+ /* 20 */ "sse4_2", "x2apic", "movbe", "popcnt",
+ /* 24 */ "tsc_deadline_timer", "aes", "xsave", "",
+ /* 28 */ "avx", "f16c", "rdrand", "hypervisor"
+ };
+
+ static char *amd_feature2_names[] = {
+ /* 0 */ "lahf_lm", "cmp_legacy", "svm", "extapic",
+ /* 4 */ "cr8_legacy", "abm", "sse4a", "misalignsse",
+ /* 8 */ "3dnowprefetch", "osvw", "ibs", "xop",
+ /* 12 */ "skinit", "wdt", "", "lwp",
+ /* 16 */ "fma4", "tce", "", "nodeid_msr",
+ /* 20 */ "", "tbm", "topoext", "perfctr_core",
+ /* 24 */ "perfctr_nb", "", "bpext", "ptsc",
+ /* 28 */ "perfctr_llc", "mwaitx", "", ""
+ };
+
+ static char *cpu_stdext_feature_names[] = {
+ /* 0 */ "fsgsbase", "tsc_adjust", "", "bmi1",
+ /* 4 */ "hle", "avx2", "", "smep",
+ /* 8 */ "bmi2", "erms", "invpcid", "rtm",
+ /* 12 */ "cqm", "", "mpx", "rdt_a",
+ /* 16 */ "avx512f", "avx512dq", "rdseed", "adx",
+ /* 20 */ "smap", "avx512ifma", "", "clflushopt",
+ /* 24 */ "clwb", "intel_pt", "avx512pf", "avx512er",
+ /* 28 */ "avx512cd", "sha_ni", "avx512bw", "avx512vl"
+ };
+
+ static char *power_flags[] = {
+ "ts", "fid", "vid",
+ "ttp", "tm", "stc",
+ "100mhzsteps", "hwpstate", "",
+ "cpb", "eff_freq_ro", "proc_feedback",
+ "acc_power",
+ };
+
+ hw_model[0] = CTL_HW;
+ hw_model[1] = HW_MODEL;
+ model[0] = '\0';
+ size = sizeof(model);
+ if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
+ strcpy(model, "unknown");
+#ifdef __i386__
+ switch (cpu_vendor_id) {
+ case CPU_VENDOR_AMD:
+ if (cpu_class < CPUCLASS_686)
+ cpu_feature_names[16] = "fcmov";
+ break;
+ case CPU_VENDOR_CYRIX:
+ cpu_feature_names[24] = "cxmmx";
+ break;
+ }
+#endif
+ if (cpu_exthigh >= 0x80000006)
+ do_cpuid(0x80000006, cache_size);
+ else
+ memset(cache_size, 0, sizeof(cache_size));
+ for (i = 0; i < mp_ncpus; ++i) {
+ fqmhz = 0;
+ fqkhz = 0;
+ freq = atomic_load_acq_64(&tsc_freq);
+ if (freq != 0) {
+ fqmhz = (freq + 4999) / 1000000;
+ fqkhz = ((freq + 4999) / 10000) % 100;
+ }
+ sbuf_printf(sb,
+ "processor\t: %d\n"
+ "vendor_id\t: %.20s\n"
+ "cpu family\t: %u\n"
+ "model\t\t: %u\n"
+ "model name\t: %s\n"
+ "stepping\t: %u\n"
+ "cpu MHz\t\t: %d.%02d\n"
+ "cache size\t: %d KB\n"
+ "physical id\t: %d\n"
+ "siblings\t: %d\n"
+ "core id\t\t: %d\n"
+ "cpu cores\t: %d\n"
+ "apicid\t\t: %d\n"
+ "initial apicid\t: %d\n"
+ "fpu\t\t: %s\n"
+ "fpu_exception\t: %s\n"
+ "cpuid level\t: %d\n"
+ "wp\t\t: %s\n",
+ i, cpu_vendor, CPUID_TO_FAMILY(cpu_id),
+ CPUID_TO_MODEL(cpu_id), model, cpu_id & CPUID_STEPPING,
+ fqmhz, fqkhz,
+ (cache_size[2] >> 16), 0, mp_ncpus, i, mp_ncpus,
+ i, i, /*cpu_id & CPUID_LOCAL_APIC_ID ??*/
+ (cpu_feature & CPUID_FPU) ? "yes" : "no", "yes",
+ CPUID_TO_FAMILY(cpu_id), "yes");
+ sbuf_cat(sb, "flags\t\t:");
+ for (j = 0; j < nitems(cpu_feature_names); j++)
+ if (cpu_feature & (1 << j) &&
+ cpu_feature_names[j][0] != '\0')
+ sbuf_printf(sb, " %s", cpu_feature_names[j]);
+ for (j = 0; j < nitems(amd_feature_names); j++)
+ if (amd_feature & (1 << j) &&
+ amd_feature_names[j][0] != '\0')
+ sbuf_printf(sb, " %s", amd_feature_names[j]);
+ for (j = 0; j < nitems(cpu_feature2_names); j++)
+ if (cpu_feature2 & (1 << j) &&
+ cpu_feature2_names[j][0] != '\0')
+ sbuf_printf(sb, " %s", cpu_feature2_names[j]);
+ for (j = 0; j < nitems(amd_feature2_names); j++)
+ if (amd_feature2 & (1 << j) &&
+ amd_feature2_names[j][0] != '\0')
+ sbuf_printf(sb, " %s", amd_feature2_names[j]);
+ for (j = 0; j < nitems(cpu_stdext_feature_names); j++)
+ if (cpu_stdext_feature & (1 << j) &&
+ cpu_stdext_feature_names[j][0] != '\0')
+ sbuf_printf(sb, " %s",
+ cpu_stdext_feature_names[j]);
+ sbuf_cat(sb, "\n");
+ sbuf_printf(sb,
+ "bugs\t\t: %s\n"
+ "bogomips\t: %d.%02d\n"
+ "clflush size\t: %d\n"
+ "cache_alignment\t: %d\n"
+ "address sizes\t: %d bits physical, %d bits virtual\n",
+#if defined(I586_CPU) && !defined(NO_F00F_HACK)
+ (has_f00f_bug) ? "Intel F00F" : "",
+#else
+ "",
+#endif
+ fqmhz * 2, fqkhz,
+ cpu_clflush_line_size, cpu_clflush_line_size,
+ cpu_maxphyaddr,
+ (cpu_maxphyaddr > 32) ? 48 : 0);
+ sbuf_cat(sb, "power management: ");
+ for (j = 0; j < nitems(power_flags); j++)
+ if (amd_pminfo & (1 << j))
+ sbuf_printf(sb, " %s", power_flags[j]);
+ sbuf_cat(sb, "\n\n");
+
+ /* XXX per-cpu vendor / class / model / id? */
+ }
+ sbuf_cat(sb, "\n");
+
+ return (0);
+}
+#else
+/* ARM64TODO: implement non-stubbed linprocfs_docpuinfo */
+static int
+linprocfs_docpuinfo(PFS_FILL_ARGS)
+{
+ int i;
+
+ for (i = 0; i < mp_ncpus; ++i) {
+ sbuf_printf(sb,
+ "processor\t: %d\n"
+ "BogoMIPS\t: %d.%02d\n",
+ i, 0, 0);
+ sbuf_cat(sb, "Features\t: ");
+ sbuf_cat(sb, "\n");
+ sbuf_printf(sb,
+ "CPU implementer\t: \n"
+ "CPU architecture: \n"
+ "CPU variant\t: 0x%x\n"
+ "CPU part\t: 0x%x\n"
+ "CPU revision\t: %d\n",
+ 0, 0, 0);
+ sbuf_cat(sb, "\n");
+ }
+
+ return (0);
+}
+#endif /* __i386__ || __amd64__ */
+
+static const char *path_slash_sys = "/sys";
+static const char *fstype_sysfs = "sysfs";
+
+static int
+_mtab_helper(const struct pfs_node *pn, const struct statfs *sp,
+ const char **mntfrom, const char **mntto, const char **fstype)
+{
+ /* determine device name */
+ *mntfrom = sp->f_mntfromname;
+
+ /* determine mount point */
+ *mntto = sp->f_mntonname;
+
+ /* determine fs type */
+ *fstype = sp->f_fstypename;
+ if (strcmp(*fstype, pn->pn_info->pi_name) == 0)
+ *mntfrom = *fstype = "proc";
+ else if (strcmp(*fstype, "procfs") == 0)
+ return (ECANCELED);
+
+ if (strcmp(*fstype, "autofs") == 0) {
+ /*
+ * FreeBSD uses eg "map -hosts", whereas Linux
+ * expects just "-hosts".
+ */
+ if (strncmp(*mntfrom, "map ", 4) == 0)
+ *mntfrom += 4;
+ }
+
+ if (strcmp(*fstype, "linsysfs") == 0) {
+ *mntfrom = path_slash_sys;
+ *fstype = fstype_sysfs;
+ } else {
+ /* For Linux msdosfs is called vfat */
+ if (strcmp(*fstype, "msdosfs") == 0)
+ *fstype = "vfat";
+ }
+ return (0);
+}
+
+static void
+_sbuf_mntoptions_helper(struct sbuf *sb, uint64_t f_flags)
+{
+ sbuf_cat(sb, (f_flags & MNT_RDONLY) ? "ro" : "rw");
+#define ADD_OPTION(opt, name) \
+ if (f_flags & (opt)) sbuf_cat(sb, "," name);
+ ADD_OPTION(MNT_SYNCHRONOUS, "sync");
+ ADD_OPTION(MNT_NOEXEC, "noexec");
+ ADD_OPTION(MNT_NOSUID, "nosuid");
+ ADD_OPTION(MNT_UNION, "union");
+ ADD_OPTION(MNT_ASYNC, "async");
+ ADD_OPTION(MNT_SUIDDIR, "suiddir");
+ ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow");
+ ADD_OPTION(MNT_NOATIME, "noatime");
+#undef ADD_OPTION
+}
+
+/*
+ * Filler function for proc/mtab and proc/<pid>/mounts.
+ *
+ * /proc/mtab doesn't exist in Linux' procfs, but is included here so
+ * users can symlink /compat/linux/etc/mtab to /proc/mtab
+ */
+static int
+linprocfs_domtab(PFS_FILL_ARGS)
+{
+ struct nameidata nd;
+ const char *lep, *mntto, *mntfrom, *fstype;
+ char *dlep, *flep;
+ size_t lep_len;
+ int error;
+ struct statfs *buf, *sp;
+ size_t count;
+
+ /* resolve symlinks etc. in the emulation tree prefix */
+ /*
+ * Ideally, this would use the current chroot rather than some
+ * hardcoded path.
+ */
+ NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
+ flep = NULL;
+ error = namei(&nd);
+ lep = linux_emul_path;
+ if (error == 0) {
+ if (vn_fullpath(nd.ni_vp, &dlep, &flep) == 0)
+ lep = dlep;
+ vrele(nd.ni_vp);
+ }
+ lep_len = strlen(lep);
+
+ buf = NULL;
+ error = kern_getfsstat(td, &buf, SIZE_T_MAX, &count,
+ UIO_SYSSPACE, MNT_WAIT);
+ if (error != 0) {
+ free(buf, M_TEMP);
+ free(flep, M_TEMP);
+ return (error);
+ }
+
+ for (sp = buf; count > 0; sp++, count--) {
+ error = _mtab_helper(pn, sp, &mntfrom, &mntto, &fstype);
+ if (error != 0) {
+ MPASS(error == ECANCELED);
+ continue;
+ }
+
+ /* determine mount point */
+ if (strncmp(mntto, lep, lep_len) == 0 && mntto[lep_len] == '/')
+ mntto += lep_len;
+
+ sbuf_printf(sb, "%s %s %s ", mntfrom, mntto, fstype);
+ _sbuf_mntoptions_helper(sb, sp->f_flags);
+ /* a real Linux mtab will also show NFS options */
+ sbuf_printf(sb, " 0 0\n");
+ }
+
+ free(buf, M_TEMP);
+ free(flep, M_TEMP);
+ return (error);
+}
+
+static int
+linprocfs_doprocmountinfo(PFS_FILL_ARGS)
+{
+ struct nameidata nd;
+ const char *mntfrom, *mntto, *fstype;
+ const char *lep;
+ char *dlep, *flep;
+ struct statfs *buf, *sp;
+ size_t count, lep_len;
+ int error;
+
+ /*
+ * Ideally, this would use the current chroot rather than some
+ * hardcoded path.
+ */
+ NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
+ flep = NULL;
+ error = namei(&nd);
+ lep = linux_emul_path;
+ if (error == 0) {
+ if (vn_fullpath(nd.ni_vp, &dlep, &flep) == 0)
+ lep = dlep;
+ vrele(nd.ni_vp);
+ }
+ lep_len = strlen(lep);
+
+ buf = NULL;
+ error = kern_getfsstat(td, &buf, SIZE_T_MAX, &count,
+ UIO_SYSSPACE, MNT_WAIT);
+ if (error != 0)
+ goto out;
+
+ for (sp = buf; count > 0; sp++, count--) {
+ error = _mtab_helper(pn, sp, &mntfrom, &mntto, &fstype);
+ if (error != 0) {
+ MPASS(error == ECANCELED);
+ continue;
+ }
+
+ if (strncmp(mntto, lep, lep_len) == 0 && mntto[lep_len] == '/')
+ mntto += lep_len;
+#if 0
+ /*
+ * If the prefix is a chroot, and this mountpoint is not under
+ * the prefix, we should skip it. Leave it for now for
+ * consistency with procmtab above.
+ */
+ else
+ continue;
+#endif
+
+ /*
+ * (1) mount id
+ *
+ * (2) parent mount id -- we don't have this cheaply, so
+ * provide a dummy value
+ *
+ * (3) major:minor -- ditto
+ *
+ * (4) root filesystem mount -- probably a namespaces thing
+ *
+ * (5) mountto path
+ */
+ sbuf_printf(sb, "%u 0 0:0 / %s ",
+ sp->f_fsid.val[0] ^ sp->f_fsid.val[1], mntto);
+ /* (6) mount options */
+ _sbuf_mntoptions_helper(sb, sp->f_flags);
+ /*
+ * (7) zero or more optional fields -- again, namespace related
+ *
+ * (8) End of variable length fields separator ("-")
+ *
+ * (9) fstype
+ *
+ * (10) mount from
+ *
+ * (11) "superblock" options -- like (6), but different
+ * semantics in Linux
+ */
+ sbuf_printf(sb, " - %s %s %s\n", fstype, mntfrom,
+ (sp->f_flags & MNT_RDONLY) ? "ro" : "rw");
+ }
+
+ error = 0;
+out:
+ free(buf, M_TEMP);
+ free(flep, M_TEMP);
+ return (error);
+}
+
+/*
+ * Filler function for proc/partitions
+ */
+static int
+linprocfs_dopartitions(PFS_FILL_ARGS)
+{
+ struct g_class *cp;
+ struct g_geom *gp;
+ struct g_provider *pp;
+ int major, minor;
+
+ g_topology_lock();
+ sbuf_printf(sb, "major minor #blocks name rio rmerge rsect "
+ "ruse wio wmerge wsect wuse running use aveq\n");
+
+ LIST_FOREACH(cp, &g_classes, class) {
+ if (strcmp(cp->name, "DISK") == 0 ||
+ strcmp(cp->name, "PART") == 0)
+ LIST_FOREACH(gp, &cp->geom, geom) {
+ LIST_FOREACH(pp, &gp->provider, provider) {
+ if (linux_driver_get_major_minor(
+ pp->name, &major, &minor) != 0) {
+ major = 0;
+ minor = 0;
+ }
+ sbuf_printf(sb, "%d %d %lld %s "
+ "%d %d %d %d %d "
+ "%d %d %d %d %d %d\n",
+ major, minor,
+ (long long)pp->mediasize, pp->name,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0);
+ }
+ }
+ }
+ g_topology_unlock();
+
+ return (0);
+}
+
+/*
+ * Filler function for proc/stat
+ *
+ * Output depends on kernel version:
+ *
+ * v2.5.40 <=
+ * user nice system idle
+ * v2.5.41
+ * user nice system idle iowait
+ * v2.6.11
+ * user nice system idle iowait irq softirq steal
+ * v2.6.24
+ * user nice system idle iowait irq softirq steal guest
+ * v2.6.33 >=
+ * user nice system idle iowait irq softirq steal guest guest_nice
+ */
+static int
+linprocfs_dostat(PFS_FILL_ARGS)
+{
+ struct pcpu *pcpu;
+ long cp_time[CPUSTATES];
+ long *cp;
+ struct timeval boottime;
+ int i;
+ char *zero_pad;
+ bool has_intr = true;
+
+ if (linux_kernver(td) >= LINUX_KERNVER(2,6,33)) {
+ zero_pad = " 0 0 0 0\n";
+ } else if (linux_kernver(td) >= LINUX_KERNVER(2,6,24)) {
+ zero_pad = " 0 0 0\n";
+ } else if (linux_kernver(td) >= LINUX_KERNVER(2,6,11)) {
+ zero_pad = " 0 0\n";
+ } else if (linux_kernver(td) >= LINUX_KERNVER(2,5,41)) {
+ has_intr = false;
+ zero_pad = " 0\n";
+ } else {
+ has_intr = false;
+ zero_pad = "\n";
+ }
+
+ read_cpu_time(cp_time);
+ getboottime(&boottime);
+ /* Parameters common to all versions */
+ sbuf_printf(sb, "cpu %lu %lu %lu %lu",
+ T2J(cp_time[CP_USER]),
+ T2J(cp_time[CP_NICE]),
+ T2J(cp_time[CP_SYS]),
+ T2J(cp_time[CP_IDLE]));
+
+ /* Print interrupt stats if available */
+ if (has_intr) {
+ sbuf_printf(sb, " 0 %lu", T2J(cp_time[CP_INTR]));
+ }
+
+ /* Pad out remaining fields depending on version */
+ sbuf_printf(sb, "%s", zero_pad);
+
+ CPU_FOREACH(i) {
+ pcpu = pcpu_find(i);
+ cp = pcpu->pc_cp_time;
+ sbuf_printf(sb, "cpu%d %lu %lu %lu %lu", i,
+ T2J(cp[CP_USER]),
+ T2J(cp[CP_NICE]),
+ T2J(cp[CP_SYS]),
+ T2J(cp[CP_IDLE]));
+
+ if (has_intr) {
+ sbuf_printf(sb, " 0 %lu", T2J(cp[CP_INTR]));
+ }
+
+ sbuf_printf(sb, "%s", zero_pad);
+ }
+ sbuf_printf(sb,
+ "disk 0 0 0 0\n"
+ "page %ju %ju\n"
+ "swap %ju %ju\n"
+ "intr %ju\n"
+ "ctxt %ju\n"
+ "btime %lld\n",
+ (uintmax_t)VM_CNT_FETCH(v_vnodepgsin),
+ (uintmax_t)VM_CNT_FETCH(v_vnodepgsout),
+ (uintmax_t)VM_CNT_FETCH(v_swappgsin),
+ (uintmax_t)VM_CNT_FETCH(v_swappgsout),
+ (uintmax_t)VM_CNT_FETCH(v_intr),
+ (uintmax_t)VM_CNT_FETCH(v_swtch),
+ (long long)boottime.tv_sec);
+ return (0);
+}
+
+static int
+linprocfs_doswaps(PFS_FILL_ARGS)
+{
+ struct xswdev xsw;
+ uintmax_t total, used;
+ int n;
+ char devname[SPECNAMELEN + 1];
+
+ sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
+ for (n = 0; ; n++) {
+ if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0)
+ break;
+ total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024;
+ used = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024;
+
+ /*
+ * The space and not tab after the device name is on
+ * purpose. Linux does so.
+ */
+ sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n",
+ devname, total, used);
+ }
+ return (0);
+}
+
+/*
+ * Filler function for proc/uptime
+ */
+static int
+linprocfs_douptime(PFS_FILL_ARGS)
+{
+ long cp_time[CPUSTATES];
+ struct timeval tv;
+
+ getmicrouptime(&tv);
+ read_cpu_time(cp_time);
+ sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
+ (long long)tv.tv_sec, tv.tv_usec / 10000,
+ T2S(cp_time[CP_IDLE] / mp_ncpus),
+ T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
+ return (0);
+}
+
+/*
+ * Get OS build date
+ */
+static void
+linprocfs_osbuild(struct thread *td, struct sbuf *sb)
+{
+#if 0
+ char osbuild[256];
+ char *cp1, *cp2;
+
+ strncpy(osbuild, version, 256);
+ osbuild[255] = '\0';
+ cp1 = strstr(osbuild, "\n");
+ cp2 = strstr(osbuild, ":");
+ if (cp1 && cp2) {
+ *cp1 = *cp2 = '\0';
+ cp1 = strstr(osbuild, "#");
+ } else
+ cp1 = NULL;
+ if (cp1)
+ sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
+ else
+#endif
+ sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
+}
+
+/*
+ * Get OS builder
+ */
+static void
+linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
+{
+#if 0
+ char builder[256];
+ char *cp;
+
+ cp = strstr(version, "\n ");
+ if (cp) {
+ strncpy(builder, cp + 5, 256);
+ builder[255] = '\0';
+ cp = strstr(builder, ":");
+ if (cp)
+ *cp = '\0';
+ }
+ if (cp)
+ sbuf_cat(sb, builder);
+ else
+#endif
+ sbuf_cat(sb, "des@freebsd.org");
+}
+
+/*
+ * Filler function for proc/version
+ */
+static int
+linprocfs_doversion(PFS_FILL_ARGS)
+{
+ char osname[LINUX_MAX_UTSNAME];
+ char osrelease[LINUX_MAX_UTSNAME];
+
+ linux_get_osname(td, osname);
+ linux_get_osrelease(td, osrelease);
+ sbuf_printf(sb, "%s version %s (", osname, osrelease);
+ linprocfs_osbuilder(td, sb);
+ sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
+ linprocfs_osbuild(td, sb);
+ sbuf_cat(sb, "\n");
+
+ return (0);
+}
+
+/*
+ * Filler function for proc/loadavg
+ */
+static int
+linprocfs_doloadavg(PFS_FILL_ARGS)
+{
+
+ sbuf_printf(sb,
+ "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
+ (int)(averunnable.ldavg[0] / averunnable.fscale),
+ (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
+ (int)(averunnable.ldavg[1] / averunnable.fscale),
+ (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
+ (int)(averunnable.ldavg[2] / averunnable.fscale),
+ (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
+ 1, /* number of running tasks */
+ nprocs, /* number of tasks */
+ lastpid /* the last pid */
+ );
+ return (0);
+}
+
+static int
+linprocfs_get_tty_nr(struct proc *p)
+{
+ struct session *sp;
+ const char *ttyname;
+ int error, major, minor, nr;
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ sx_assert(&proctree_lock, SX_LOCKED);
+
+ if ((p->p_flag & P_CONTROLT) == 0)
+ return (-1);
+
+ sp = p->p_pgrp->pg_session;
+ if (sp == NULL)
+ return (-1);
+
+ ttyname = devtoname(sp->s_ttyp->t_dev);
+ error = linux_driver_get_major_minor(ttyname, &major, &minor);
+ if (error != 0)
+ return (-1);
+
+ nr = makedev(major, minor);
+ return (nr);
+}
+
+/*
+ * Filler function for proc/pid/stat
+ */
+static int
+linprocfs_doprocstat(PFS_FILL_ARGS)
+{
+ struct kinfo_proc kp;
+ struct timeval boottime;
+ char state;
+ static int ratelimit = 0;
+ int tty_nr;
+ vm_offset_t startcode, startdata;
+
+ getboottime(&boottime);
+ sx_slock(&proctree_lock);
+ PROC_LOCK(p);
+ fill_kinfo_proc(p, &kp);
+ tty_nr = linprocfs_get_tty_nr(p);
+ sx_sunlock(&proctree_lock);
+ if (p->p_vmspace) {
+ startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
+ startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
+ } else {
+ startcode = 0;
+ startdata = 0;
+ }
+ sbuf_printf(sb, "%d", p->p_pid);
+#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
+ PS_ADD("comm", "(%s)", p->p_comm);
+ if (kp.ki_stat > sizeof(linux_state)) {
+ state = 'R';
+
+ if (ratelimit == 0) {
+ printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
+ kp.ki_stat, sizeof(linux_state));
+ ++ratelimit;
+ }
+ } else
+ state = linux_state[kp.ki_stat - 1];
+ PS_ADD("state", "%c", state);
+ PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
+ PS_ADD("pgrp", "%d", p->p_pgid);
+ PS_ADD("session", "%d", p->p_session->s_sid);
+ PROC_UNLOCK(p);
+ PS_ADD("tty", "%d", tty_nr);
+ PS_ADD("tpgid", "%d", kp.ki_tpgid);
+ PS_ADD("flags", "%u", 0); /* XXX */
+ PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt);
+ PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt);
+ PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt);
+ PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt);
+ PS_ADD("utime", "%ld", TV2J(&kp.ki_rusage.ru_utime));
+ PS_ADD("stime", "%ld", TV2J(&kp.ki_rusage.ru_stime));
+ PS_ADD("cutime", "%ld", TV2J(&kp.ki_rusage_ch.ru_utime));
+ PS_ADD("cstime", "%ld", TV2J(&kp.ki_rusage_ch.ru_stime));
+ PS_ADD("priority", "%d", kp.ki_pri.pri_user);
+ PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */
+ PS_ADD("0", "%d", 0); /* removed field */
+ PS_ADD("itrealvalue", "%d", 0); /* XXX */
+ PS_ADD("starttime", "%lu", TV2J(&kp.ki_start) - TV2J(&boottime));
+ PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size));
+ PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize);
+ PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss);
+ PS_ADD("startcode", "%ju", (uintmax_t)startcode);
+ PS_ADD("endcode", "%ju", (uintmax_t)startdata);
+ PS_ADD("startstack", "%u", 0); /* XXX */
+ PS_ADD("kstkesp", "%u", 0); /* XXX */
+ PS_ADD("kstkeip", "%u", 0); /* XXX */
+ PS_ADD("signal", "%u", 0); /* XXX */
+ PS_ADD("blocked", "%u", 0); /* XXX */
+ PS_ADD("sigignore", "%u", 0); /* XXX */
+ PS_ADD("sigcatch", "%u", 0); /* XXX */
+ PS_ADD("wchan", "%u", 0); /* XXX */
+ PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap);
+ PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap);
+ PS_ADD("exitsignal", "%d", 0); /* XXX */
+ PS_ADD("processor", "%u", kp.ki_lastcpu);
+ PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */
+ PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */
+#undef PS_ADD
+ sbuf_putc(sb, '\n');
+
+ return (0);
+}
+
+/*
+ * Filler function for proc/pid/statm
+ */
+static int
+linprocfs_doprocstatm(PFS_FILL_ARGS)
+{
+ struct kinfo_proc kp;
+ segsz_t lsize;
+
+ sx_slock(&proctree_lock);
+ PROC_LOCK(p);
+ fill_kinfo_proc(p, &kp);
+ PROC_UNLOCK(p);
+ sx_sunlock(&proctree_lock);
+
+ /*
+ * See comments in linprocfs_doprocstatus() regarding the
+ * computation of lsize.
+ */
+ /* size resident share trs drs lrs dt */
+ sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
+ sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
+ sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
+ sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
+ sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
+ lsize = B2P(kp.ki_size) - kp.ki_dsize -
+ kp.ki_ssize - kp.ki_tsize - 1;
+ sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
+ sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
+
+ return (0);
+}
+
+/*
+ * Filler function for proc/pid/status
+ */
+static int
+linprocfs_doprocstatus(PFS_FILL_ARGS)
+{
+ struct kinfo_proc kp;
+ char *state;
+ segsz_t lsize;
+ struct thread *td2;
+ struct sigacts *ps;
+ l_sigset_t siglist, sigignore, sigcatch;
+ int i;
+
+ sx_slock(&proctree_lock);
+ PROC_LOCK(p);
+ td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
+
+ if (P_SHOULDSTOP(p)) {
+ state = "T (stopped)";
+ } else {
+ switch(p->p_state) {
+ case PRS_NEW:
+ state = "I (idle)";
+ break;
+ case PRS_NORMAL:
+ if (p->p_flag & P_WEXIT) {
+ state = "X (exiting)";
+ break;
+ }
+ switch(td2->td_state) {
+ case TDS_INHIBITED:
+ state = "S (sleeping)";
+ break;
+ case TDS_RUNQ:
+ case TDS_RUNNING:
+ state = "R (running)";
+ break;
+ default:
+ state = "? (unknown)";
+ break;
+ }
+ break;
+ case PRS_ZOMBIE:
+ state = "Z (zombie)";
+ break;
+ default:
+ state = "? (unknown)";
+ break;
+ }
+ }
+
+ fill_kinfo_proc(p, &kp);
+ sx_sunlock(&proctree_lock);
+
+ sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */
+ sbuf_printf(sb, "State:\t%s\n", state);
+
+ /*
+ * Credentials
+ */
+ sbuf_printf(sb, "Tgid:\t%d\n", p->p_pid);
+ sbuf_printf(sb, "Pid:\t%d\n", p->p_pid);
+ sbuf_printf(sb, "PPid:\t%d\n", kp.ki_ppid );
+ sbuf_printf(sb, "TracerPid:\t%d\n", kp.ki_tracer );
+ sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
+ p->p_ucred->cr_uid,
+ p->p_ucred->cr_svuid,
+ /* FreeBSD doesn't have fsuid */
+ p->p_ucred->cr_uid);
+ sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
+ p->p_ucred->cr_gid,
+ p->p_ucred->cr_svgid,
+ /* FreeBSD doesn't have fsgid */
+ p->p_ucred->cr_gid);
+ sbuf_cat(sb, "Groups:\t");
+ for (i = 0; i < p->p_ucred->cr_ngroups; i++)
+ sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]);
+ PROC_UNLOCK(p);
+ sbuf_putc(sb, '\n');
+
+ /*
+ * Memory
+ *
+ * While our approximation of VmLib may not be accurate (I
+ * don't know of a simple way to verify it, and I'm not sure
+ * it has much meaning anyway), I believe it's good enough.
+ *
+ * The same code that could (I think) accurately compute VmLib
+ * could also compute VmLck, but I don't really care enough to
+ * implement it. Submissions are welcome.
+ */
+ sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size));
+ sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
+ sbuf_printf(sb, "VmRSS:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize));
+ sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize));
+ sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize));
+ sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize));
+ lsize = B2P(kp.ki_size) - kp.ki_dsize -
+ kp.ki_ssize - kp.ki_tsize - 1;
+ sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize));
+
+ /*
+ * Signal masks
+ */
+ PROC_LOCK(p);
+ bsd_to_linux_sigset(&p->p_siglist, &siglist);
+ ps = p->p_sigacts;
+ mtx_lock(&ps->ps_mtx);
+ bsd_to_linux_sigset(&ps->ps_sigignore, &sigignore);
+ bsd_to_linux_sigset(&ps->ps_sigcatch, &sigcatch);
+ mtx_unlock(&ps->ps_mtx);
+ PROC_UNLOCK(p);
+
+ sbuf_printf(sb, "SigPnd:\t%016jx\n", siglist.__mask);
+ /*
+ * XXX. SigBlk - target thread's signal mask, td_sigmask.
+ * To implement SigBlk pseudofs should support proc/tid dir entries.
+ */
+ sbuf_printf(sb, "SigBlk:\t%016x\n", 0);
+ sbuf_printf(sb, "SigIgn:\t%016jx\n", sigignore.__mask);
+ sbuf_printf(sb, "SigCgt:\t%016jx\n", sigcatch.__mask);
+
+ /*
+ * Linux also prints the capability masks, but we don't have
+ * capabilities yet, and when we do get them they're likely to
+ * be meaningless to Linux programs, so we lie. XXX
+ */
+ sbuf_printf(sb, "CapInh:\t%016x\n", 0);
+ sbuf_printf(sb, "CapPrm:\t%016x\n", 0);
+ sbuf_printf(sb, "CapEff:\t%016x\n", 0);
+
+ return (0);
+}
+
+/*
+ * Filler function for proc/pid/cwd
+ */
+static int
+linprocfs_doproccwd(PFS_FILL_ARGS)
+{
+ struct pwd *pwd;
+ char *fullpath = "unknown";
+ char *freepath = NULL;
+
+ pwd = pwd_hold(td);
+ vn_fullpath(pwd->pwd_cdir, &fullpath, &freepath);
+ sbuf_printf(sb, "%s", fullpath);
+ if (freepath)
+ free(freepath, M_TEMP);
+ pwd_drop(pwd);
+ return (0);
+}
+
+/*
+ * Filler function for proc/pid/root
+ */
+static int
+linprocfs_doprocroot(PFS_FILL_ARGS)
+{
+ struct pwd *pwd;
+ struct vnode *vp;
+ char *fullpath = "unknown";
+ char *freepath = NULL;
+
+ pwd = pwd_hold(td);
+ vp = jailed(p->p_ucred) ? pwd->pwd_jdir : pwd->pwd_rdir;
+ vn_fullpath(vp, &fullpath, &freepath);
+ sbuf_printf(sb, "%s", fullpath);
+ if (freepath)
+ free(freepath, M_TEMP);
+ pwd_drop(pwd);
+ return (0);
+}
+
+/*
+ * Filler function for proc/pid/cmdline
+ */
+static int
+linprocfs_doproccmdline(PFS_FILL_ARGS)
+{
+ int ret;
+
+ PROC_LOCK(p);
+ if ((ret = p_cansee(td, p)) != 0) {
+ PROC_UNLOCK(p);
+ return (ret);
+ }
+
+ /*
+ * Mimic linux behavior and pass only processes with usermode
+ * address space as valid. Return zero silently otherwize.
+ */
+ if (p->p_vmspace == &vmspace0) {
+ PROC_UNLOCK(p);
+ return (0);
+ }
+ if (p->p_args != NULL) {
+ sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
+ PROC_UNLOCK(p);
+ return (0);
+ }
+
+ if ((p->p_flag & P_SYSTEM) != 0) {
+ PROC_UNLOCK(p);
+ return (0);
+ }
+
+ PROC_UNLOCK(p);
+
+ ret = proc_getargv(td, p, sb);
+ return (ret);
+}
+
+/*
+ * Filler function for proc/pid/environ
+ */
+static int
+linprocfs_doprocenviron(PFS_FILL_ARGS)
+{
+
+ /*
+ * Mimic linux behavior and pass only processes with usermode
+ * address space as valid. Return zero silently otherwize.
+ */
+ if (p->p_vmspace == &vmspace0)
+ return (0);
+
+ return (proc_getenvv(td, p, sb));
+}
+
+static char l32_map_str[] = "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
+static char l64_map_str[] = "%016lx-%016lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
+static char vdso_str[] = " [vdso]";
+static char stack_str[] = " [stack]";
+
+/*
+ * Filler function for proc/pid/maps
+ */
+static int
+linprocfs_doprocmaps(PFS_FILL_ARGS)
+{
+ struct vmspace *vm;
+ vm_map_t map;
+ vm_map_entry_t entry, tmp_entry;
+ vm_object_t obj, tobj, lobj;
+ vm_offset_t e_start, e_end;
+ vm_ooffset_t off;
+ vm_prot_t e_prot;
+ unsigned int last_timestamp;
+ char *name = "", *freename = NULL;
+ const char *l_map_str;
+ ino_t ino;
+ int ref_count, shadow_count, flags;
+ int error;
+ struct vnode *vp;
+ struct vattr vat;
+ bool private;
+
+ PROC_LOCK(p);
+ error = p_candebug(td, p);
+ PROC_UNLOCK(p);
+ if (error)
+ return (error);
+
+ if (uio->uio_rw != UIO_READ)
+ return (EOPNOTSUPP);
+
+ error = 0;
+ vm = vmspace_acquire_ref(p);
+ if (vm == NULL)
+ return (ESRCH);
+
+ if (SV_CURPROC_FLAG(SV_LP64))
+ l_map_str = l64_map_str;
+ else
+ l_map_str = l32_map_str;
+ map = &vm->vm_map;
+ vm_map_lock_read(map);
+ VM_MAP_ENTRY_FOREACH(entry, map) {
+ name = "";
+ freename = NULL;
+ if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
+ continue;
+ e_prot = entry->protection;
+ e_start = entry->start;
+ e_end = entry->end;
+ obj = entry->object.vm_object;
+ off = entry->offset;
+ for (lobj = tobj = obj; tobj != NULL;
+ lobj = tobj, tobj = tobj->backing_object) {
+ VM_OBJECT_RLOCK(tobj);
+ off += lobj->backing_object_offset;
+ if (lobj != obj)
+ VM_OBJECT_RUNLOCK(lobj);
+ }
+ private = (entry->eflags & MAP_ENTRY_COW) != 0 || obj == NULL ||
+ (obj->flags & OBJ_ANON) != 0;
+ last_timestamp = map->timestamp;
+ vm_map_unlock_read(map);
+ ino = 0;
+ if (lobj) {
+ vp = vm_object_vnode(lobj);
+ if (vp != NULL)
+ vref(vp);
+ if (lobj != obj)
+ VM_OBJECT_RUNLOCK(lobj);
+ flags = obj->flags;
+ ref_count = obj->ref_count;
+ shadow_count = obj->shadow_count;
+ VM_OBJECT_RUNLOCK(obj);
+ if (vp != NULL) {
+ vn_fullpath(vp, &name, &freename);
+ vn_lock(vp, LK_SHARED | LK_RETRY);
+ VOP_GETATTR(vp, &vat, td->td_ucred);
+ ino = vat.va_fileid;
+ vput(vp);
+ } else if (SV_PROC_ABI(p) == SV_ABI_LINUX) {
+ if (e_start == p->p_sysent->sv_shared_page_base)
+ name = vdso_str;
+ if (e_end == p->p_sysent->sv_usrstack)
+ name = stack_str;
+ }
+ } else {
+ flags = 0;
+ ref_count = 0;
+ shadow_count = 0;
+ }
+
+ /*
+ * format:
+ * start, end, access, offset, major, minor, inode, name.
+ */
+ error = sbuf_printf(sb, l_map_str,
+ (u_long)e_start, (u_long)e_end,
+ (e_prot & VM_PROT_READ)?"r":"-",
+ (e_prot & VM_PROT_WRITE)?"w":"-",
+ (e_prot & VM_PROT_EXECUTE)?"x":"-",
+ private ? "p" : "s",
+ (u_long)off,
+ 0,
+ 0,
+ (u_long)ino,
+ *name ? " " : " ",
+ name
+ );
+ if (freename)
+ free(freename, M_TEMP);
+ vm_map_lock_read(map);
+ if (error == -1) {
+ error = 0;
+ break;
+ }
+ if (last_timestamp != map->timestamp) {
+ /*
+ * Look again for the entry because the map was
+ * modified while it was unlocked. Specifically,
+ * the entry may have been clipped, merged, or deleted.
+ */
+ vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
+ entry = tmp_entry;
+ }
+ }
+ vm_map_unlock_read(map);
+ vmspace_free(vm);
+
+ return (error);
+}
+
+/*
+ * Filler function for proc/pid/mem
+ */
+static int
+linprocfs_doprocmem(PFS_FILL_ARGS)
+{
+ ssize_t resid;
+ int error;
+
+ resid = uio->uio_resid;
+ error = procfs_doprocmem(PFS_FILL_ARGNAMES);
+
+ if (uio->uio_rw == UIO_READ && resid != uio->uio_resid)
+ return (0);
+
+ if (error == EFAULT)
+ error = EIO;
+
+ return (error);
+}
+
+/*
+ * Criteria for interface name translation
+ */
+#define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER)
+
+static int
+linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
+{
+ struct ifnet *ifscan;
+ int ethno;
+
+ IFNET_RLOCK_ASSERT();
+
+ /* Short-circuit non ethernet interfaces */
+ if (!IFP_IS_ETH(ifp))
+ return (strlcpy(buffer, ifp->if_xname, buflen));
+
+ /* Determine the (relative) unit number for ethernet interfaces */
+ ethno = 0;
+ CK_STAILQ_FOREACH(ifscan, &V_ifnet, if_link) {
+ if (ifscan == ifp)
+ return (snprintf(buffer, buflen, "eth%d", ethno));
+ if (IFP_IS_ETH(ifscan))
+ ethno++;
+ }
+
+ return (0);
+}
+
+/*
+ * Filler function for proc/net/dev
+ */
+static int
+linprocfs_donetdev(PFS_FILL_ARGS)
+{
+ char ifname[16]; /* XXX LINUX_IFNAMSIZ */
+ struct ifnet *ifp;
+
+ sbuf_printf(sb, "%6s|%58s|%s\n"
+ "%6s|%58s|%58s\n",
+ "Inter-", " Receive", " Transmit",
+ " face",
+ "bytes packets errs drop fifo frame compressed multicast",
+ "bytes packets errs drop fifo colls carrier compressed");
+
+ CURVNET_SET(TD_TO_VNET(curthread));
+ IFNET_RLOCK();
+ CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+ linux_ifname(ifp, ifname, sizeof ifname);
+ sbuf_printf(sb, "%6.6s: ", ifname);
+ sbuf_printf(sb, "%7ju %7ju %4ju %4ju %4lu %5lu %10lu %9ju ",
+ (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IBYTES),
+ (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS),
+ (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IERRORS),
+ (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IQDROPS),
+ /* rx_missed_errors */
+ 0UL, /* rx_fifo_errors */
+ 0UL, /* rx_length_errors +
+ * rx_over_errors +
+ * rx_crc_errors +
+ * rx_frame_errors */
+ 0UL, /* rx_compressed */
+ (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IMCASTS));
+ /* XXX-BZ rx only? */
+ sbuf_printf(sb, "%8ju %7ju %4ju %4ju %4lu %5ju %7lu %10lu\n",
+ (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OBYTES),
+ (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS),
+ (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OERRORS),
+ (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OQDROPS),
+ 0UL, /* tx_fifo_errors */
+ (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_COLLISIONS),
+ 0UL, /* tx_carrier_errors +
+ * tx_aborted_errors +
+ * tx_window_errors +
+ * tx_heartbeat_errors*/
+ 0UL); /* tx_compressed */
+ }
+ IFNET_RUNLOCK();
+ CURVNET_RESTORE();
+
+ return (0);
+}
+
+/*
+ * Filler function for proc/sys/kernel/osrelease
+ */
+static int
+linprocfs_doosrelease(PFS_FILL_ARGS)
+{
+ char osrelease[LINUX_MAX_UTSNAME];
+
+ linux_get_osrelease(td, osrelease);
+ sbuf_printf(sb, "%s\n", osrelease);
+
+ return (0);
+}
+
+/*
+ * Filler function for proc/sys/kernel/ostype
+ */
+static int
+linprocfs_doostype(PFS_FILL_ARGS)
+{
+ char osname[LINUX_MAX_UTSNAME];
+
+ linux_get_osname(td, osname);
+ sbuf_printf(sb, "%s\n", osname);
+
+ return (0);
+}
+
+/*
+ * Filler function for proc/sys/kernel/version
+ */
+static int
+linprocfs_doosbuild(PFS_FILL_ARGS)
+{
+
+ linprocfs_osbuild(td, sb);
+ sbuf_cat(sb, "\n");
+ return (0);
+}
+
+/*
+ * Filler function for proc/sys/kernel/msgmax
+ */
+static int
+linprocfs_domsgmax(PFS_FILL_ARGS)
+{
+
+ sbuf_printf(sb, "%d\n", msginfo.msgmax);
+ return (0);
+}
+
+/*
+ * Filler function for proc/sys/kernel/msgmni
+ */
+static int
+linprocfs_domsgmni(PFS_FILL_ARGS)
+{
+
+ sbuf_printf(sb, "%d\n", msginfo.msgmni);
+ return (0);
+}
+
+/*
+ * Filler function for proc/sys/kernel/msgmnb
+ */
+static int
+linprocfs_domsgmnb(PFS_FILL_ARGS)
+{
+
+ sbuf_printf(sb, "%d\n", msginfo.msgmnb);
+ return (0);
+}
+
+/*
+ * Filler function for proc/sys/kernel/ngroups_max
+ *
+ * Note that in Linux it defaults to 65536, not 1023.
+ */
+static int
+linprocfs_dongroups_max(PFS_FILL_ARGS)
+{
+
+ sbuf_printf(sb, "%d\n", ngroups_max);
+ return (0);
+}
+
+/*
+ * Filler function for proc/sys/kernel/pid_max
+ */
+static int
+linprocfs_dopid_max(PFS_FILL_ARGS)
+{
+
+ sbuf_printf(sb, "%i\n", PID_MAX);
+ return (0);
+}
+
+/*
+ * Filler function for proc/sys/kernel/sem
+ */
+static int
+linprocfs_dosem(PFS_FILL_ARGS)
+{
+
+ sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
+ seminfo.semopm, seminfo.semmni);
+ return (0);
+}
+
+/*
+ * Filler function for proc/sys/kernel/shmall
+ */
+static int
+linprocfs_doshmall(PFS_FILL_ARGS)
+{
+
+ sbuf_printf(sb, "%lu\n", shminfo.shmall);
+ return (0);
+}
+
+/*
+ * Filler function for proc/sys/kernel/shmmax
+ */
+static int
+linprocfs_doshmmax(PFS_FILL_ARGS)
+{
+
+ sbuf_printf(sb, "%lu\n", shminfo.shmmax);
+ return (0);
+}
+
+/*
+ * Filler function for proc/sys/kernel/shmmni
+ */
+static int
+linprocfs_doshmmni(PFS_FILL_ARGS)
+{
+
+ sbuf_printf(sb, "%lu\n", shminfo.shmmni);
+ return (0);
+}
+
+/*
+ * Filler function for proc/sys/kernel/tainted
+ */
+static int
+linprocfs_dotainted(PFS_FILL_ARGS)
+{
+
+ sbuf_printf(sb, "0\n");
+ return (0);
+}
+
+/*
+ * Filler function for proc/sys/vm/min_free_kbytes
+ *
+ * This mirrors the approach in illumos to return zero for reads. Effectively,
+ * it says, no memory is kept in reserve for "atomic allocations". This class
+ * of allocation can be used at times when a thread cannot be suspended.
+ */
+static int
+linprocfs_dominfree(PFS_FILL_ARGS)
+{
+
+ sbuf_printf(sb, "%d\n", 0);
+ return (0);
+}
+
+/*
+ * Filler function for proc/scsi/device_info
+ */
+static int
+linprocfs_doscsidevinfo(PFS_FILL_ARGS)
+{
+
+ return (0);
+}
+
+/*
+ * Filler function for proc/scsi/scsi
+ */
+static int
+linprocfs_doscsiscsi(PFS_FILL_ARGS)
+{
+
+ return (0);
+}
+
+/*
+ * Filler function for proc/devices
+ */
+static int
+linprocfs_dodevices(PFS_FILL_ARGS)
+{
+ char *char_devices;
+ sbuf_printf(sb, "Character devices:\n");
+
+ char_devices = linux_get_char_devices();
+ sbuf_printf(sb, "%s", char_devices);
+ linux_free_get_char_devices(char_devices);
+
+ sbuf_printf(sb, "\nBlock devices:\n");
+
+ return (0);
+}
+
+/*
+ * Filler function for proc/cmdline
+ */
+static int
+linprocfs_docmdline(PFS_FILL_ARGS)
+{
+
+ sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
+ sbuf_printf(sb, " ro root=302\n");
+ return (0);
+}
+
+/*
+ * Filler function for proc/filesystems
+ */
+static int
+linprocfs_dofilesystems(PFS_FILL_ARGS)
+{
+ struct vfsconf *vfsp;
+
+ vfsconf_slock();
+ TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
+ if (vfsp->vfc_flags & VFCF_SYNTHETIC)
+ sbuf_printf(sb, "nodev");
+ sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
+ }
+ vfsconf_sunlock();
+ return(0);
+}
+
+/*
+ * Filler function for proc/modules
+ */
+static int
+linprocfs_domodules(PFS_FILL_ARGS)
+{
+#if 0
+ struct linker_file *lf;
+
+ TAILQ_FOREACH(lf, &linker_files, link) {
+ sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
+ (unsigned long)lf->size, lf->refs);
+ }
+#endif
+ return (0);
+}
+
+/*
+ * Filler function for proc/pid/fd
+ */
+static int
+linprocfs_dofdescfs(PFS_FILL_ARGS)
+{
+
+ if (p == curproc)
+ sbuf_printf(sb, "/dev/fd");
+ else
+ sbuf_printf(sb, "unknown");
+ return (0);
+}
+
+/*
+ * Filler function for proc/pid/limits
+ */
+static const struct linux_rlimit_ident {
+ const char *desc;
+ const char *unit;
+ unsigned int rlim_id;
+} linux_rlimits_ident[] = {
+ { "Max cpu time", "seconds", RLIMIT_CPU },
+ { "Max file size", "bytes", RLIMIT_FSIZE },
+ { "Max data size", "bytes", RLIMIT_DATA },
+ { "Max stack size", "bytes", RLIMIT_STACK },
+ { "Max core file size", "bytes", RLIMIT_CORE },
+ { "Max resident set", "bytes", RLIMIT_RSS },
+ { "Max processes", "processes", RLIMIT_NPROC },
+ { "Max open files", "files", RLIMIT_NOFILE },
+ { "Max locked memory", "bytes", RLIMIT_MEMLOCK },
+ { "Max address space", "bytes", RLIMIT_AS },
+ { "Max file locks", "locks", LINUX_RLIMIT_LOCKS },
+ { "Max pending signals", "signals", LINUX_RLIMIT_SIGPENDING },
+ { "Max msgqueue size", "bytes", LINUX_RLIMIT_MSGQUEUE },
+ { "Max nice priority", "", LINUX_RLIMIT_NICE },
+ { "Max realtime priority", "", LINUX_RLIMIT_RTPRIO },
+ { "Max realtime timeout", "us", LINUX_RLIMIT_RTTIME },
+ { 0, 0, 0 }
+};
+
+static int
+linprocfs_doproclimits(PFS_FILL_ARGS)
+{
+ const struct linux_rlimit_ident *li;
+ struct plimit *limp;
+ struct rlimit rl;
+ ssize_t size;
+ int res, error;
+
+ error = 0;
+
+ PROC_LOCK(p);
+ limp = lim_hold(p->p_limit);
+ PROC_UNLOCK(p);
+ size = sizeof(res);
+ sbuf_printf(sb, "%-26s%-21s%-21s%-21s\n", "Limit", "Soft Limit",
+ "Hard Limit", "Units");
+ for (li = linux_rlimits_ident; li->desc != NULL; ++li) {
+ switch (li->rlim_id)
+ {
+ case LINUX_RLIMIT_LOCKS:
+ /* FALLTHROUGH */
+ case LINUX_RLIMIT_RTTIME:
+ rl.rlim_cur = RLIM_INFINITY;
+ break;
+ case LINUX_RLIMIT_SIGPENDING:
+ error = kernel_sysctlbyname(td,
+ "kern.sigqueue.max_pending_per_proc",
+ &res, &size, 0, 0, 0, 0);
+ if (error != 0)
+ goto out;
+ rl.rlim_cur = res;
+ rl.rlim_max = res;
+ break;
+ case LINUX_RLIMIT_MSGQUEUE:
+ error = kernel_sysctlbyname(td,
+ "kern.ipc.msgmnb", &res, &size, 0, 0, 0, 0);
+ if (error != 0)
+ goto out;
+ rl.rlim_cur = res;
+ rl.rlim_max = res;
+ break;
+ case LINUX_RLIMIT_NICE:
+ /* FALLTHROUGH */
+ case LINUX_RLIMIT_RTPRIO:
+ rl.rlim_cur = 0;
+ rl.rlim_max = 0;
+ break;
+ default:
+ rl = limp->pl_rlimit[li->rlim_id];
+ break;
+ }
+ if (rl.rlim_cur == RLIM_INFINITY)
+ sbuf_printf(sb, "%-26s%-21s%-21s%-10s\n",
+ li->desc, "unlimited", "unlimited", li->unit);
+ else
+ sbuf_printf(sb, "%-26s%-21llu%-21llu%-10s\n",
+ li->desc, (unsigned long long)rl.rlim_cur,
+ (unsigned long long)rl.rlim_max, li->unit);
+ }
+out:
+ lim_free(limp);
+ return (error);
+}
+
+/*
+ * The point of the following two functions is to work around
+ * an assertion in Chromium; see kern/240991 for details.
+ */
+static int
+linprocfs_dotaskattr(PFS_ATTR_ARGS)
+{
+
+ vap->va_nlink = 3;
+ return (0);
+}
+
+/*
+ * Filler function for proc/<pid>/task/.dummy
+ */
+static int
+linprocfs_dotaskdummy(PFS_FILL_ARGS)
+{
+
+ return (0);
+}
+
+/*
+ * Filler function for proc/sys/kernel/random/uuid
+ */
+static int
+linprocfs_douuid(PFS_FILL_ARGS)
+{
+ struct uuid uuid;
+
+ kern_uuidgen(&uuid, 1);
+ sbuf_printf_uuid(sb, &uuid);
+ sbuf_printf(sb, "\n");
+ return(0);
+}
+
+/*
+ * Filler function for proc/pid/auxv
+ */
+static int
+linprocfs_doauxv(PFS_FILL_ARGS)
+{
+ struct sbuf *asb;
+ off_t buflen, resid;
+ int error;
+
+ /*
+ * Mimic linux behavior and pass only processes with usermode
+ * address space as valid. Return zero silently otherwise.
+ */
+ if (p->p_vmspace == &vmspace0)
+ return (0);
+
+ if (uio->uio_resid == 0)
+ return (0);
+ if (uio->uio_offset < 0 || uio->uio_resid < 0)
+ return (EINVAL);
+
+ asb = sbuf_new_auto();
+ if (asb == NULL)
+ return (ENOMEM);
+ error = proc_getauxv(td, p, asb);
+ if (error == 0)
+ error = sbuf_finish(asb);
+
+ resid = sbuf_len(asb) - uio->uio_offset;
+ if (resid > uio->uio_resid)
+ buflen = uio->uio_resid;
+ else
+ buflen = resid;
+ if (buflen > IOSIZE_MAX)
+ return (EINVAL);
+ if (buflen > maxphys)
+ buflen = maxphys;
+ if (resid <= 0)
+ return (0);
+
+ if (error == 0)
+ error = uiomove(sbuf_data(asb) + uio->uio_offset, buflen, uio);
+ sbuf_delete(asb);
+ return (error);
+}
+
+/*
+ * Constructor
+ */
+static int
+linprocfs_init(PFS_INIT_ARGS)
+{
+ struct pfs_node *root;
+ struct pfs_node *dir;
+ struct pfs_node *sys;
+
+ root = pi->pi_root;
+
+ /* /proc/... */
+ pfs_create_file(root, "cmdline", &linprocfs_docmdline,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(root, "devices", &linprocfs_dodevices,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(root, "modules", &linprocfs_domodules,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(root, "mounts", &linprocfs_domtab,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(root, "mtab", &linprocfs_domtab,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(root, "partitions", &linprocfs_dopartitions,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_link(root, "self", &procfs_docurproc,
+ NULL, NULL, NULL, 0);
+ pfs_create_file(root, "stat", &linprocfs_dostat,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(root, "swaps", &linprocfs_doswaps,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(root, "uptime", &linprocfs_douptime,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(root, "version", &linprocfs_doversion,
+ NULL, NULL, NULL, PFS_RD);
+
+ /* /proc/bus/... */
+ dir = pfs_create_dir(root, "bus", NULL, NULL, NULL, 0);
+ dir = pfs_create_dir(dir, "pci", NULL, NULL, NULL, 0);
+ dir = pfs_create_dir(dir, "devices", NULL, NULL, NULL, 0);
+
+ /* /proc/net/... */
+ dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
+ pfs_create_file(dir, "dev", &linprocfs_donetdev,
+ NULL, NULL, NULL, PFS_RD);
+
+ /* /proc/<pid>/... */
+ dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
+ pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
+ NULL, NULL, NULL, 0);
+ pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
+ NULL, &procfs_candebug, NULL, PFS_RD);
+ pfs_create_link(dir, "exe", &procfs_doprocfile,
+ NULL, &procfs_notsystem, NULL, 0);
+ pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
+ NULL, NULL, NULL, PFS_RD | PFS_AUTODRAIN);
+ pfs_create_file(dir, "mem", &linprocfs_doprocmem,
+ procfs_attr_rw, &procfs_candebug, NULL, PFS_RDWR | PFS_RAW);
+ pfs_create_file(dir, "mountinfo", &linprocfs_doprocmountinfo,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(dir, "mounts", &linprocfs_domtab,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_link(dir, "root", &linprocfs_doprocroot,
+ NULL, NULL, NULL, 0);
+ pfs_create_file(dir, "stat", &linprocfs_doprocstat,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(dir, "status", &linprocfs_doprocstatus,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
+ NULL, NULL, NULL, 0);
+ pfs_create_file(dir, "auxv", &linprocfs_doauxv,
+ NULL, &procfs_candebug, NULL, PFS_RD|PFS_RAWRD);
+ pfs_create_file(dir, "limits", &linprocfs_doproclimits,
+ NULL, NULL, NULL, PFS_RD);
+
+ /* /proc/<pid>/task/... */
+ dir = pfs_create_dir(dir, "task", linprocfs_dotaskattr, NULL, NULL, 0);
+ pfs_create_file(dir, ".dummy", &linprocfs_dotaskdummy,
+ NULL, NULL, NULL, PFS_RD);
+
+ /* /proc/scsi/... */
+ dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
+ pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
+ NULL, NULL, NULL, PFS_RD);
+
+ /* /proc/sys/... */
+ sys = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
+
+ /* /proc/sys/kernel/... */
+ dir = pfs_create_dir(sys, "kernel", NULL, NULL, NULL, 0);
+ pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(dir, "ostype", &linprocfs_doostype,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(dir, "version", &linprocfs_doosbuild,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(dir, "msgmax", &linprocfs_domsgmax,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(dir, "msgmnb", &linprocfs_domsgmnb,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(dir, "ngroups_max", &linprocfs_dongroups_max,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(dir, "sem", &linprocfs_dosem,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(dir, "shmall", &linprocfs_doshmall,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(dir, "shmmax", &linprocfs_doshmmax,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(dir, "shmmni", &linprocfs_doshmmni,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(dir, "tainted", &linprocfs_dotainted,
+ NULL, NULL, NULL, PFS_RD);
+
+ /* /proc/sys/kernel/random/... */
+ dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0);
+ pfs_create_file(dir, "uuid", &linprocfs_douuid,
+ NULL, NULL, NULL, PFS_RD);
+
+ /* /proc/sys/vm/.... */
+ dir = pfs_create_dir(sys, "vm", NULL, NULL, NULL, 0);
+ pfs_create_file(dir, "min_free_kbytes", &linprocfs_dominfree,
+ NULL, NULL, NULL, PFS_RD);
+
+ return (0);
+}
+
+/*
+ * Destructor
+ */
+static int
+linprocfs_uninit(PFS_INIT_ARGS)
+{
+
+ /* nothing to do, pseudofs will GC */
+ return (0);
+}
+
+PSEUDOFS(linprocfs, 1, VFCF_JAIL);
+#if defined(__aarch64__) || defined(__amd64__)
+MODULE_DEPEND(linprocfs, linux_common, 1, 1, 1);
+#else
+MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
+#endif
+MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
+MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
+MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);
+MODULE_DEPEND(linprocfs, sysvshm, 1, 1, 1);
diff --git a/sys/compat/linsysfs/linsysfs.c b/sys/compat/linsysfs/linsysfs.c
new file mode 100644
index 000000000000..66cb36db9868
--- /dev/null
+++ b/sys/compat/linsysfs/linsysfs.c
@@ -0,0 +1,708 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2006 IronPort Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/ctype.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/sbuf.h>
+#include <sys/smp.h>
+#include <sys/socket.h>
+#include <sys/bus.h>
+#include <sys/pciio.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+
+#include <compat/linux/linux.h>
+#include <compat/linux/linux_common.h>
+#include <compat/linux/linux_util.h>
+#include <fs/pseudofs/pseudofs.h>
+
+struct scsi_host_queue {
+ TAILQ_ENTRY(scsi_host_queue) scsi_host_next;
+ char *path;
+ char *name;
+};
+
+TAILQ_HEAD(,scsi_host_queue) scsi_host_q;
+
+static int host_number = 0;
+
+static int
+atoi(const char *str)
+{
+ return (int)strtol(str, (char **)NULL, 10);
+}
+
+static int
+linsysfs_ifnet_addr(PFS_FILL_ARGS)
+{
+ struct l_sockaddr lsa;
+ struct ifnet *ifp;
+
+ ifp = ifname_linux_to_bsd(td, pn->pn_parent->pn_name, NULL);
+ if (ifp == NULL)
+ return (ENOENT);
+ if (linux_ifhwaddr(ifp, &lsa) != 0)
+ return (ENOENT);
+ sbuf_printf(sb, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
+ lsa.sa_data[0], lsa.sa_data[1], lsa.sa_data[2],
+ lsa.sa_data[3], lsa.sa_data[4], lsa.sa_data[5]);
+ return (0);
+}
+
+static int
+linsysfs_ifnet_addrlen(PFS_FILL_ARGS)
+{
+
+ sbuf_printf(sb, "%d\n", LINUX_IFHWADDRLEN);
+ return (0);
+}
+
+static int
+linsysfs_ifnet_flags(PFS_FILL_ARGS)
+{
+ struct ifnet *ifp;
+ unsigned short flags;
+
+ ifp = ifname_linux_to_bsd(td, pn->pn_parent->pn_name, NULL);
+ if (ifp == NULL)
+ return (ENOENT);
+ linux_ifflags(ifp, &flags);
+ sbuf_printf(sb, "0x%x\n", flags);
+ return (0);
+}
+
+static int
+linsysfs_ifnet_ifindex(PFS_FILL_ARGS)
+{
+ struct ifnet *ifp;
+
+ ifp = ifname_linux_to_bsd(td, pn->pn_parent->pn_name, NULL);
+ if (ifp == NULL)
+ return (ENOENT);
+ sbuf_printf(sb, "%u\n", ifp->if_index);
+ return (0);
+}
+
+static int
+linsysfs_ifnet_mtu(PFS_FILL_ARGS)
+{
+ struct ifnet *ifp;
+
+ ifp = ifname_linux_to_bsd(td, pn->pn_parent->pn_name, NULL);
+ if (ifp == NULL)
+ return (ENOENT);
+ sbuf_printf(sb, "%u\n", ifp->if_mtu);
+ return (0);
+}
+
+static int
+linsysfs_ifnet_tx_queue_len(PFS_FILL_ARGS)
+{
+
+ /* XXX */
+ sbuf_printf(sb, "1000\n");
+ return (0);
+}
+
+static int
+linsysfs_ifnet_type(PFS_FILL_ARGS)
+{
+ struct l_sockaddr lsa;
+ struct ifnet *ifp;
+
+ ifp = ifname_linux_to_bsd(td, pn->pn_parent->pn_name, NULL);
+ if (ifp == NULL)
+ return (ENOENT);
+ if (linux_ifhwaddr(ifp, &lsa) != 0)
+ return (ENOENT);
+ sbuf_printf(sb, "%d\n", lsa.sa_family);
+ return (0);
+}
+
+static void
+linsysfs_listnics(struct pfs_node *dir)
+{
+ struct pfs_node *nic;
+ struct pfs_node *lo;
+
+ nic = pfs_create_dir(dir, "eth0", NULL, NULL, NULL, 0);
+
+ pfs_create_file(nic, "address", &linsysfs_ifnet_addr,
+ NULL, NULL, NULL, PFS_RD);
+
+ pfs_create_file(nic, "addr_len", &linsysfs_ifnet_addrlen,
+ NULL, NULL, NULL, PFS_RD);
+
+ pfs_create_file(nic, "flags", &linsysfs_ifnet_flags,
+ NULL, NULL, NULL, PFS_RD);
+
+ pfs_create_file(nic, "ifindex", &linsysfs_ifnet_ifindex,
+ NULL, NULL, NULL, PFS_RD);
+
+ pfs_create_file(nic, "mtu", &linsysfs_ifnet_mtu,
+ NULL, NULL, NULL, PFS_RD);
+
+ pfs_create_file(nic, "tx_queue_len", &linsysfs_ifnet_tx_queue_len,
+ NULL, NULL, NULL, PFS_RD);
+
+ pfs_create_file(nic, "type", &linsysfs_ifnet_type,
+ NULL, NULL, NULL, PFS_RD);
+
+ lo = pfs_create_dir(dir, "lo", NULL, NULL, NULL, 0);
+
+ pfs_create_file(lo, "address", &linsysfs_ifnet_addr,
+ NULL, NULL, NULL, PFS_RD);
+
+ pfs_create_file(lo, "addr_len", &linsysfs_ifnet_addrlen,
+ NULL, NULL, NULL, PFS_RD);
+
+ pfs_create_file(lo, "flags", &linsysfs_ifnet_flags,
+ NULL, NULL, NULL, PFS_RD);
+
+ pfs_create_file(lo, "ifindex", &linsysfs_ifnet_ifindex,
+ NULL, NULL, NULL, PFS_RD);
+
+ pfs_create_file(lo, "mtu", &linsysfs_ifnet_mtu,
+ NULL, NULL, NULL, PFS_RD);
+
+ pfs_create_file(lo, "tx_queue_len", &linsysfs_ifnet_tx_queue_len,
+ NULL, NULL, NULL, PFS_RD);
+
+ pfs_create_file(lo, "type", &linsysfs_ifnet_type,
+ NULL, NULL, NULL, PFS_RD);
+}
+
+/*
+ * Filler function for proc_name
+ */
+static int
+linsysfs_scsiname(PFS_FILL_ARGS)
+{
+ struct scsi_host_queue *scsi_host;
+ int index;
+
+ if (strncmp(pn->pn_parent->pn_name, "host", 4) == 0) {
+ index = atoi(&pn->pn_parent->pn_name[4]);
+ } else {
+ sbuf_printf(sb, "unknown\n");
+ return (0);
+ }
+ TAILQ_FOREACH(scsi_host, &scsi_host_q, scsi_host_next) {
+ if (index-- == 0) {
+ sbuf_printf(sb, "%s\n", scsi_host->name);
+ return (0);
+ }
+ }
+ sbuf_printf(sb, "unknown\n");
+ return (0);
+}
+
+/*
+ * Filler function for device sym-link
+ */
+static int
+linsysfs_link_scsi_host(PFS_FILL_ARGS)
+{
+ struct scsi_host_queue *scsi_host;
+ int index;
+
+ if (strncmp(pn->pn_parent->pn_name, "host", 4) == 0) {
+ index = atoi(&pn->pn_parent->pn_name[4]);
+ } else {
+ sbuf_printf(sb, "unknown\n");
+ return (0);
+ }
+ TAILQ_FOREACH(scsi_host, &scsi_host_q, scsi_host_next) {
+ if (index-- == 0) {
+ sbuf_printf(sb, "../../../devices%s", scsi_host->path);
+ return(0);
+ }
+ }
+ sbuf_printf(sb, "unknown\n");
+ return (0);
+}
+
+static int
+linsysfs_fill_data(PFS_FILL_ARGS)
+{
+ sbuf_printf(sb, "%s", (char *)pn->pn_data);
+ return (0);
+}
+
+static int
+linsysfs_fill_vendor(PFS_FILL_ARGS)
+{
+ sbuf_printf(sb, "0x%04x\n", pci_get_vendor((device_t)pn->pn_data));
+ return (0);
+}
+
+static int
+linsysfs_fill_device(PFS_FILL_ARGS)
+{
+ sbuf_printf(sb, "0x%04x\n", pci_get_device((device_t)pn->pn_data));
+ return (0);
+}
+
+static int
+linsysfs_fill_subvendor(PFS_FILL_ARGS)
+{
+ sbuf_printf(sb, "0x%04x\n", pci_get_subvendor((device_t)pn->pn_data));
+ return (0);
+}
+
+static int
+linsysfs_fill_subdevice(PFS_FILL_ARGS)
+{
+ sbuf_printf(sb, "0x%04x\n", pci_get_subdevice((device_t)pn->pn_data));
+ return (0);
+}
+
+static int
+linsysfs_fill_revid(PFS_FILL_ARGS)
+{
+ sbuf_printf(sb, "0x%x\n", pci_get_revid((device_t)pn->pn_data));
+ return (0);
+}
+
+static int
+linsysfs_fill_config(PFS_FILL_ARGS)
+{
+ uint8_t config[48];
+ device_t dev;
+ uint32_t reg;
+
+ dev = (device_t)pn->pn_data;
+ bzero(config, sizeof(config));
+ reg = pci_get_vendor(dev);
+ config[0] = reg;
+ config[1] = reg >> 8;
+ reg = pci_get_device(dev);
+ config[2] = reg;
+ config[3] = reg >> 8;
+ reg = pci_get_revid(dev);
+ config[8] = reg;
+ reg = pci_get_subvendor(dev);
+ config[44] = reg;
+ config[45] = reg >> 8;
+ reg = pci_get_subdevice(dev);
+ config[46] = reg;
+ config[47] = reg >> 8;
+ sbuf_bcat(sb, config, sizeof(config));
+ return (0);
+}
+
+/*
+ * Filler function for PCI uevent file
+ */
+static int
+linsysfs_fill_uevent_pci(PFS_FILL_ARGS)
+{
+ device_t dev;
+
+ dev = (device_t)pn->pn_data;
+ sbuf_printf(sb, "DRIVER=%s\nPCI_CLASS=%X\nPCI_ID=%04X:%04X\n"
+ "PCI_SUBSYS_ID=%04X:%04X\nPCI_SLOT_NAME=%04d:%02x:%02x.%x\n",
+ linux_driver_get_name_dev(dev), pci_get_class(dev),
+ pci_get_vendor(dev), pci_get_device(dev), pci_get_subvendor(dev),
+ pci_get_subdevice(dev), pci_get_domain(dev), pci_get_bus(dev),
+ pci_get_slot(dev), pci_get_function(dev));
+ return (0);
+}
+
+/*
+ * Filler function for drm uevent file
+ */
+static int
+linsysfs_fill_uevent_drm(PFS_FILL_ARGS)
+{
+ device_t dev;
+ int unit;
+
+ dev = (device_t)pn->pn_data;
+ unit = device_get_unit(dev);
+ sbuf_printf(sb,
+ "MAJOR=226\nMINOR=%d\nDEVNAME=dri/card%d\nDEVTYPE=dri_minor\n",
+ unit, unit);
+ return (0);
+}
+
+static char *
+get_full_pfs_path(struct pfs_node *cur)
+{
+ char *temp, *path;
+
+ temp = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
+ path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
+ path[0] = '\0';
+
+ do {
+ snprintf(temp, MAXPATHLEN, "%s/%s", cur->pn_name, path);
+ strlcpy(path, temp, MAXPATHLEN);
+ cur = cur->pn_parent;
+ } while (cur->pn_parent != NULL);
+
+ path[strlen(path) - 1] = '\0'; /* remove extra slash */
+ free(temp, M_TEMP);
+ return (path);
+}
+
+/*
+ * Filler function for symlink from drm char device to PCI device
+ */
+static int
+linsysfs_fill_vgapci(PFS_FILL_ARGS)
+{
+ char *path;
+
+ path = get_full_pfs_path((struct pfs_node*)pn->pn_data);
+ sbuf_printf(sb, "../../../%s", path);
+ free(path, M_TEMP);
+ return (0);
+}
+
+#undef PCI_DEV
+#define PCI_DEV "pci"
+#define DRMN_DEV "drmn"
+static int
+linsysfs_run_bus(device_t dev, struct pfs_node *dir, struct pfs_node *scsi,
+ struct pfs_node *chardev, struct pfs_node *drm, char *path, char *prefix)
+{
+ struct scsi_host_queue *scsi_host;
+ struct pfs_node *sub_dir, *cur_file;
+ int i, nchildren, error;
+ device_t *children, parent;
+ devclass_t devclass;
+ const char *name = NULL;
+ struct pci_devinfo *dinfo;
+ char *device, *host, *new_path, *devname;
+
+ new_path = path;
+ devname = malloc(16, M_TEMP, M_WAITOK);
+
+ parent = device_get_parent(dev);
+ if (parent) {
+ devclass = device_get_devclass(parent);
+ if (devclass != NULL)
+ name = devclass_get_name(devclass);
+ if (name && strcmp(name, PCI_DEV) == 0) {
+ dinfo = device_get_ivars(dev);
+ if (dinfo) {
+ device = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
+ new_path = malloc(MAXPATHLEN, M_TEMP,
+ M_WAITOK);
+ new_path[0] = '\000';
+ strcpy(new_path, path);
+ host = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
+ device[0] = '\000';
+ sprintf(device, "%s:%02x:%02x.%x",
+ prefix,
+ dinfo->cfg.bus,
+ dinfo->cfg.slot,
+ dinfo->cfg.func);
+ strcat(new_path, "/");
+ strcat(new_path, device);
+ dir = pfs_create_dir(dir, device,
+ NULL, NULL, NULL, 0);
+ cur_file = pfs_create_file(dir, "vendor",
+ &linsysfs_fill_vendor, NULL, NULL, NULL,
+ PFS_RD);
+ cur_file->pn_data = (void*)dev;
+ cur_file = pfs_create_file(dir, "device",
+ &linsysfs_fill_device, NULL, NULL, NULL,
+ PFS_RD);
+ cur_file->pn_data = (void*)dev;
+ cur_file = pfs_create_file(dir,
+ "subsystem_vendor",
+ &linsysfs_fill_subvendor, NULL, NULL, NULL,
+ PFS_RD);
+ cur_file->pn_data = (void*)dev;
+ cur_file = pfs_create_file(dir,
+ "subsystem_device",
+ &linsysfs_fill_subdevice, NULL, NULL, NULL,
+ PFS_RD);
+ cur_file->pn_data = (void*)dev;
+ cur_file = pfs_create_file(dir, "revision",
+ &linsysfs_fill_revid, NULL, NULL, NULL,
+ PFS_RD);
+ cur_file->pn_data = (void*)dev;
+ cur_file = pfs_create_file(dir, "config",
+ &linsysfs_fill_config, NULL, NULL, NULL,
+ PFS_RD);
+ cur_file->pn_data = (void*)dev;
+ cur_file = pfs_create_file(dir, "uevent",
+ &linsysfs_fill_uevent_pci, NULL, NULL,
+ NULL, PFS_RD);
+ cur_file->pn_data = (void*)dev;
+ cur_file = pfs_create_link(dir, "subsystem",
+ &linsysfs_fill_data, NULL, NULL, NULL, 0);
+ /* libdrm just checks that the link ends in "/pci" */
+ cur_file->pn_data = "/sys/bus/pci";
+
+ if (dinfo->cfg.baseclass == PCIC_STORAGE) {
+ /* DJA only make this if needed */
+ sprintf(host, "host%d", host_number++);
+ strcat(new_path, "/");
+ strcat(new_path, host);
+ pfs_create_dir(dir, host,
+ NULL, NULL, NULL, 0);
+ scsi_host = malloc(sizeof(
+ struct scsi_host_queue),
+ M_DEVBUF, M_NOWAIT);
+ scsi_host->path = malloc(
+ strlen(new_path) + 1,
+ M_DEVBUF, M_NOWAIT);
+ scsi_host->path[0] = '\000';
+ bcopy(new_path, scsi_host->path,
+ strlen(new_path) + 1);
+ scsi_host->name = "unknown";
+
+ sub_dir = pfs_create_dir(scsi, host,
+ NULL, NULL, NULL, 0);
+ pfs_create_link(sub_dir, "device",
+ &linsysfs_link_scsi_host,
+ NULL, NULL, NULL, 0);
+ pfs_create_file(sub_dir, "proc_name",
+ &linsysfs_scsiname,
+ NULL, NULL, NULL, PFS_RD);
+ scsi_host->name
+ = linux_driver_get_name_dev(dev);
+ TAILQ_INSERT_TAIL(&scsi_host_q,
+ scsi_host, scsi_host_next);
+ }
+ free(device, M_TEMP);
+ free(host, M_TEMP);
+ }
+ }
+
+ devclass = device_get_devclass(dev);
+ if (devclass != NULL)
+ name = devclass_get_name(devclass);
+ else
+ name = NULL;
+ if (name != NULL && strcmp(name, DRMN_DEV) == 0 &&
+ device_get_unit(dev) >= 0) {
+ dinfo = device_get_ivars(parent);
+ if (dinfo != NULL && dinfo->cfg.baseclass == PCIC_DISPLAY) {
+ pfs_create_dir(dir, "drm", NULL, NULL, NULL, 0);
+ sprintf(devname, "226:%d",
+ device_get_unit(dev));
+ sub_dir = pfs_create_dir(chardev,
+ devname, NULL, NULL, NULL, 0);
+ cur_file = pfs_create_link(sub_dir,
+ "device", &linsysfs_fill_vgapci, NULL,
+ NULL, NULL, PFS_RD);
+ cur_file->pn_data = (void*)dir;
+ cur_file = pfs_create_file(sub_dir,
+ "uevent", &linsysfs_fill_uevent_drm, NULL,
+ NULL, NULL, PFS_RD);
+ cur_file->pn_data = (void*)dev;
+ sprintf(devname, "card%d",
+ device_get_unit(dev));
+ sub_dir = pfs_create_dir(drm,
+ devname, NULL, NULL, NULL, 0);
+ cur_file = pfs_create_link(sub_dir,
+ "device", &linsysfs_fill_vgapci, NULL,
+ NULL, NULL, PFS_RD);
+ cur_file->pn_data = (void*)dir;
+ }
+ }
+ }
+
+ error = device_get_children(dev, &children, &nchildren);
+ if (error == 0) {
+ for (i = 0; i < nchildren; i++)
+ if (children[i])
+ linsysfs_run_bus(children[i], dir, scsi,
+ chardev, drm, new_path, prefix);
+ free(children, M_TEMP);
+ }
+ if (new_path != path)
+ free(new_path, M_TEMP);
+ free(devname, M_TEMP);
+
+ return (1);
+}
+
+/*
+ * Filler function for sys/devices/system/cpu/{online,possible,present}
+ */
+static int
+linsysfs_cpuonline(PFS_FILL_ARGS)
+{
+
+ sbuf_printf(sb, "%d-%d\n", CPU_FIRST(), mp_maxid);
+ return (0);
+}
+
+/*
+ * Filler function for sys/devices/system/cpu/cpuX/online
+ */
+static int
+linsysfs_cpuxonline(PFS_FILL_ARGS)
+{
+
+ sbuf_printf(sb, "1\n");
+ return (0);
+}
+
+static void
+linsysfs_listcpus(struct pfs_node *dir)
+{
+ struct pfs_node *cpu;
+ char *name;
+ int i, count, len;
+
+ len = 1;
+ count = mp_maxcpus;
+ while (count > 10) {
+ count /= 10;
+ len++;
+ }
+ len += sizeof("cpu");
+ name = malloc(len, M_TEMP, M_WAITOK);
+
+ for (i = 0; i < mp_ncpus; ++i) {
+ /* /sys/devices/system/cpu/cpuX */
+ sprintf(name, "cpu%d", i);
+ cpu = pfs_create_dir(dir, name, NULL, NULL, NULL, 0);
+
+ pfs_create_file(cpu, "online", &linsysfs_cpuxonline,
+ NULL, NULL, NULL, PFS_RD);
+ }
+ free(name, M_TEMP);
+}
+
+/*
+ * Constructor
+ */
+static int
+linsysfs_init(PFS_INIT_ARGS)
+{
+ struct pfs_node *root;
+ struct pfs_node *class;
+ struct pfs_node *dir, *sys, *cpu;
+ struct pfs_node *drm;
+ struct pfs_node *pci;
+ struct pfs_node *scsi;
+ struct pfs_node *net;
+ struct pfs_node *power_supply;
+ struct pfs_node *devdir, *chardev;
+ struct pfs_node *kernel;
+ struct pfs_node *debug;
+ devclass_t devclass;
+ device_t dev;
+
+ TAILQ_INIT(&scsi_host_q);
+
+ root = pi->pi_root;
+
+ /* /sys/class/... */
+ class = pfs_create_dir(root, "class", NULL, NULL, NULL, 0);
+ scsi = pfs_create_dir(class, "scsi_host", NULL, NULL, NULL, 0);
+ drm = pfs_create_dir(class, "drm", NULL, NULL, NULL, 0);
+ power_supply = pfs_create_dir(class, "power_supply", NULL, NULL, NULL, 0);
+
+ /* /sys/class/net/.. */
+ net = pfs_create_dir(class, "net", NULL, NULL, NULL, 0);
+
+ /* /sys/dev/... */
+ devdir = pfs_create_dir(root, "dev", NULL, NULL, NULL, 0);
+ chardev = pfs_create_dir(devdir, "char", NULL, NULL, NULL, 0);
+
+ /* /sys/devices/... */
+ dir = pfs_create_dir(root, "devices", NULL, NULL, NULL, 0);
+ pci = pfs_create_dir(dir, "pci0000:00", NULL, NULL, NULL, 0);
+
+ devclass = devclass_find("root");
+ if (devclass == NULL) {
+ return (0);
+ }
+
+ dev = devclass_get_device(devclass, 0);
+ linsysfs_run_bus(dev, pci, scsi, chardev, drm, "/pci0000:00", "0000");
+
+ /* /sys/devices/system */
+ sys = pfs_create_dir(dir, "system", NULL, NULL, NULL, 0);
+
+ /* /sys/devices/system/cpu */
+ cpu = pfs_create_dir(sys, "cpu", NULL, NULL, NULL, 0);
+
+ pfs_create_file(cpu, "online", &linsysfs_cpuonline,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(cpu, "possible", &linsysfs_cpuonline,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(cpu, "present", &linsysfs_cpuonline,
+ NULL, NULL, NULL, PFS_RD);
+
+ linsysfs_listcpus(cpu);
+ linsysfs_listnics(net);
+
+ /* /sys/kernel */
+ kernel = pfs_create_dir(root, "kernel", NULL, NULL, NULL, 0);
+ /* /sys/kernel/debug, mountpoint for lindebugfs. */
+ debug = pfs_create_dir(kernel, "debug", NULL, NULL, NULL, 0);
+
+ return (0);
+}
+
+/*
+ * Destructor
+ */
+static int
+linsysfs_uninit(PFS_INIT_ARGS)
+{
+ struct scsi_host_queue *scsi_host, *scsi_host_tmp;
+
+ TAILQ_FOREACH_SAFE(scsi_host, &scsi_host_q, scsi_host_next,
+ scsi_host_tmp) {
+ TAILQ_REMOVE(&scsi_host_q, scsi_host, scsi_host_next);
+ free(scsi_host->path, M_TEMP);
+ free(scsi_host, M_TEMP);
+ }
+
+ return (0);
+}
+
+PSEUDOFS(linsysfs, 1, VFCF_JAIL);
+#if defined(__aarch64__) || defined(__amd64__)
+MODULE_DEPEND(linsysfs, linux_common, 1, 1, 1);
+#else
+MODULE_DEPEND(linsysfs, linux, 1, 1, 1);
+#endif
diff --git a/sys/compat/linux/check_error.d b/sys/compat/linux/check_error.d
new file mode 100644
index 000000000000..389e768aa3f6
--- /dev/null
+++ b/sys/compat/linux/check_error.d
@@ -0,0 +1,144 @@
+#!/usr/sbin/dtrace -qs
+
+/*-
+ * Copyright (c) 2008-2012 Alexander Leidinger <netchild@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Report error conditions:
+ * - emulation errors (unsupportet stuff, unknown stuff, ...)
+ * - kernel errors (resource shortage, ...)
+ * - programming errors (errors which can happen, but should not happen)
+ */
+
+linuxulator*:dummy::not_implemented,
+linuxulator*:emul:linux_thread_detach:child_clear_tid_error,
+linuxulator*:emul:linux_thread_detach:futex_failed,
+linuxulator*:emul:linux_schedtail:copyout_error,
+linuxulator*:futex:futex_get:error,
+linuxulator*:futex:futex_sleep:requeue_error,
+linuxulator*:futex:futex_sleep:sleep_error,
+linuxulator*:futex:futex_wait:copyin_error,
+linuxulator*:futex:futex_wait:itimerfix_error,
+linuxulator*:futex:futex_wait:sleep_error,
+linuxulator*:futex:futex_atomic_op:missing_access_check,
+linuxulator*:futex:futex_atomic_op:unimplemented_op,
+linuxulator*:futex:futex_atomic_op:unimplemented_cmp,
+linuxulator*:futex:linux_sys_futex:unimplemented_clockswitch,
+linuxulator*:futex:linux_sys_futex:copyin_error,
+linuxulator*:futex:linux_sys_futex:unhandled_efault,
+linuxulator*:futex:linux_sys_futex:unimplemented_lock_pi,
+linuxulator*:futex:linux_sys_futex:unimplemented_unlock_pi,
+linuxulator*:futex:linux_sys_futex:unimplemented_trylock_pi,
+linuxulator*:futex:linux_sys_futex:unimplemented_wait_requeue_pi,
+linuxulator*:futex:linux_sys_futex:unimplemented_cmp_requeue_pi,
+linuxulator*:futex:linux_sys_futex:unknown_operation,
+linuxulator*:futex:linux_get_robust_list:copyout_error,
+linuxulator*:futex:handle_futex_death:copyin_error,
+linuxulator*:futex:fetch_robust_entry:copyin_error,
+linuxulator*:futex:release_futexes:copyin_error,
+linuxulator*:time:linux_clock_gettime:conversion_error,
+linuxulator*:time:linux_clock_gettime:gettime_error,
+linuxulator*:time:linux_clock_gettime:copyout_error,
+linuxulator*:time:linux_clock_settime:conversion_error,
+linuxulator*:time:linux_clock_settime:settime_error,
+linuxulator*:time:linux_clock_settime:copyin_error,
+linuxulator*:time:linux_clock_getres:conversion_error,
+linuxulator*:time:linux_clock_getres:getres_error,
+linuxulator*:time:linux_clock_getres:copyout_error,
+linuxulator*:time:linux_nanosleep:conversion_error,
+linuxulator*:time:linux_nanosleep:nanosleep_error,
+linuxulator*:time:linux_nanosleep:copyout_error,
+linuxulator*:time:linux_nanosleep:copyin_error,
+linuxulator*:time:linux_clock_nanosleep:copyin_error,
+linuxulator*:time:linux_clock_nanosleep:conversion_error,
+linuxulator*:time:linux_clock_nanosleep:copyout_error,
+linuxulator*:time:linux_clock_nanosleep:nanosleep_error,
+linuxulator*:sysctl:handle_string:copyout_error,
+linuxulator*:sysctl:linux_sysctl:copyin_error,
+linuxulator*:mib:linux_sysctl_osname:sysctl_string_error,
+linuxulator*:mib:linux_sysctl_osrelease:sysctl_string_error,
+linuxulator*:mib:linux_sysctl_oss_version:sysctl_string_error,
+linuxulator*:mib:linux_prison_create:vfs_copyopt_error,
+linuxulator*:mib:linux_prison_check:vfs_copyopt_error,
+linuxulator*:mib:linux_prison_check:vfs_getopt_error,
+linuxulator*:mib:linux_prison_set:vfs_copyopt_error,
+linuxulator*:mib:linux_prison_set:vfs_getopt_error,
+linuxulator*:mib:linux_prison_get:vfs_setopt_error,
+linuxulator*:mib:linux_prison_get:vfs_setopts_error
+{
+ printf("ERROR: %s in %s:%s:%s\n", probename, probeprov, probemod, probefunc);
+ stack();
+ ustack();
+}
+
+linuxulator*:util:linux_driver_get_name_dev:nullcall,
+linuxulator*:util:linux_driver_get_major_minor:nullcall,
+linuxulator*:futex:linux_sys_futex:invalid_cmp_requeue_use,
+linuxulator*:futex:linux_sys_futex:deprecated_requeue,
+linuxulator*:futex:linux_set_robust_list:size_error,
+linuxulator*:time:linux_clock_getres:nullcall
+{
+ printf("WARNING: %s:%s:%s:%s in application %s, maybe an application error?\n", probename, probeprov, probemod, probefunc, execname);
+ stack();
+ ustack();
+}
+
+linuxulator*:util:linux_driver_get_major_minor:notfound
+{
+ printf("WARNING: Application %s failed to find %s in %s:%s:%s, this may or may not be a problem.\n", execname, stringof(args[0]), probename, probeprov, probemod);
+ stack();
+ ustack();
+}
+
+linuxulator*:time:linux_to_native_clockid:unknown_clockid
+{
+ printf("INFO: Application %s tried to use unknown clockid %d. Please report this to freebsd-emulation@FreeBSD.org.\n", execname, arg0);
+}
+
+linuxulator*:time:linux_to_native_clockid:unsupported_clockid,
+linuxulator*:time:linux_clock_nanosleep:unsupported_clockid
+{
+ printf("WARNING: Application %s tried to use unsupported clockid (%d), this may or may not be a problem for the application.\nPatches to support this clockid are welcome on the freebsd-emulation@FreeBSD.org mailinglist.\n", execname, arg0);
+}
+
+linuxulator*:time:linux_clock_nanosleep:unsupported_flags
+{
+ printf("WARNING: Application %s tried to use unsupported flags (%d), this may or may not be a problem for the application.\nPatches to support those flags are welcome on the freebsd-emulation@FreeBSD.org mailinglist.\n", execname, arg0);
+}
+
+linuxulator*:sysctl:linux_sysctl:wrong_length
+{
+ printf("ERROR: Application %s issued a sysctl which failed the length restrictions.\nThe length passed is %d, the min length supported is 1 and the max length supported is %d.\n", execname, arg0, arg1);
+ stack();
+ ustack();
+}
+
+linuxulator*:sysctl:linux_sysctl:unsupported_sysctl
+{
+ printf("ERROR: Application %s issued an unsupported sysctl (%s).\nPatches to support this sysctl are welcome on the freebsd-emulation@FreeBSD.org mailinglist.\n", execname, stringof(args[0]));
+}
diff --git a/sys/compat/linux/check_internal_locks.d b/sys/compat/linux/check_internal_locks.d
new file mode 100644
index 000000000000..d3032c06c512
--- /dev/null
+++ b/sys/compat/linux/check_internal_locks.d
@@ -0,0 +1,97 @@
+#!/usr/sbin/dtrace -qs
+
+/*-
+ * Copyright (c) 2008-2012 Alexander Leidinger <netchild@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/**
+ * Check if the internal locks are correctly acquired/released:
+ * - no recursive locking (mtx locks, write locks)
+ * - no unlocking of already unlocked one
+ *
+ * Print stacktrace if a lock is longer locked than about 10sec or more.
+ */
+
+#pragma D option dynvarsize=32m
+#pragma D option specsize=32m
+
+BEGIN
+{
+ check["futex_mtx"] = 0;
+}
+
+linuxulator*:locks:futex_mtx:locked
+/check[probefunc] > 0/
+{
+ printf("ERROR: recursive lock of %s (%p),", probefunc, arg0);
+ printf(" or missing SDT probe in kernel. Stack trace follows:");
+ stack();
+}
+
+linuxulator*:locks:futex_mtx:locked
+{
+ ++check[probefunc];
+ @stats[probefunc] = count();
+
+ ts[probefunc] = timestamp;
+ spec[probefunc] = speculation();
+}
+
+linuxulator*:locks:futex_mtx:unlock
+/check[probefunc] == 0/
+{
+ printf("ERROR: unlock attempt of unlocked %s (%p),", probefunc, arg0);
+ printf(" missing SDT probe in kernel, or dtrace program started");
+ printf(" while the %s was already held (race condition).", probefunc);
+ printf(" Stack trace follows:");
+ stack();
+}
+
+linuxulator*:locks:futex_mtx:unlock
+{
+ discard(spec[probefunc]);
+ spec[probefunc] = 0;
+ --check[probefunc];
+}
+
+/* Timeout handling */
+
+tick-10s
+/spec["futex_mtx"] != 0 && timestamp - ts["futex_mtx"] >= 9999999000/
+{
+ commit(spec["futex_mtx"]);
+ spec["futex_mtx"] = 0;
+}
+
+
+/* Statistics */
+
+END
+{
+ printf("Number of locks per type:");
+ printa(@stats);
+}
diff --git a/sys/compat/linux/linux.c b/sys/compat/linux/linux.c
new file mode 100644
index 000000000000..a8c5e2baddc4
--- /dev/null
+++ b/sys/compat/linux/linux.c
@@ -0,0 +1,629 @@
+/*-
+ * Copyright (c) 2015 Dmitry Chagin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <opt_inet6.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/ctype.h>
+#include <sys/jail.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/signalvar.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+
+#include <sys/un.h>
+#include <netinet/in.h>
+
+#include <compat/linux/linux.h>
+#include <compat/linux/linux_common.h>
+#include <compat/linux/linux_util.h>
+
+struct futex_list futex_list;
+struct mtx futex_mtx; /* protects the futex list */
+
+CTASSERT(LINUX_IFNAMSIZ == IFNAMSIZ);
+
+static int bsd_to_linux_sigtbl[LINUX_SIGTBLSZ] = {
+ LINUX_SIGHUP, /* SIGHUP */
+ LINUX_SIGINT, /* SIGINT */
+ LINUX_SIGQUIT, /* SIGQUIT */
+ LINUX_SIGILL, /* SIGILL */
+ LINUX_SIGTRAP, /* SIGTRAP */
+ LINUX_SIGABRT, /* SIGABRT */
+ 0, /* SIGEMT */
+ LINUX_SIGFPE, /* SIGFPE */
+ LINUX_SIGKILL, /* SIGKILL */
+ LINUX_SIGBUS, /* SIGBUS */
+ LINUX_SIGSEGV, /* SIGSEGV */
+ LINUX_SIGSYS, /* SIGSYS */
+ LINUX_SIGPIPE, /* SIGPIPE */
+ LINUX_SIGALRM, /* SIGALRM */
+ LINUX_SIGTERM, /* SIGTERM */
+ LINUX_SIGURG, /* SIGURG */
+ LINUX_SIGSTOP, /* SIGSTOP */
+ LINUX_SIGTSTP, /* SIGTSTP */
+ LINUX_SIGCONT, /* SIGCONT */
+ LINUX_SIGCHLD, /* SIGCHLD */
+ LINUX_SIGTTIN, /* SIGTTIN */
+ LINUX_SIGTTOU, /* SIGTTOU */
+ LINUX_SIGIO, /* SIGIO */
+ LINUX_SIGXCPU, /* SIGXCPU */
+ LINUX_SIGXFSZ, /* SIGXFSZ */
+ LINUX_SIGVTALRM,/* SIGVTALRM */
+ LINUX_SIGPROF, /* SIGPROF */
+ LINUX_SIGWINCH, /* SIGWINCH */
+ 0, /* SIGINFO */
+ LINUX_SIGUSR1, /* SIGUSR1 */
+ LINUX_SIGUSR2 /* SIGUSR2 */
+};
+
+static int linux_to_bsd_sigtbl[LINUX_SIGTBLSZ] = {
+ SIGHUP, /* LINUX_SIGHUP */
+ SIGINT, /* LINUX_SIGINT */
+ SIGQUIT, /* LINUX_SIGQUIT */
+ SIGILL, /* LINUX_SIGILL */
+ SIGTRAP, /* LINUX_SIGTRAP */
+ SIGABRT, /* LINUX_SIGABRT */
+ SIGBUS, /* LINUX_SIGBUS */
+ SIGFPE, /* LINUX_SIGFPE */
+ SIGKILL, /* LINUX_SIGKILL */
+ SIGUSR1, /* LINUX_SIGUSR1 */
+ SIGSEGV, /* LINUX_SIGSEGV */
+ SIGUSR2, /* LINUX_SIGUSR2 */
+ SIGPIPE, /* LINUX_SIGPIPE */
+ SIGALRM, /* LINUX_SIGALRM */
+ SIGTERM, /* LINUX_SIGTERM */
+ SIGBUS, /* LINUX_SIGSTKFLT */
+ SIGCHLD, /* LINUX_SIGCHLD */
+ SIGCONT, /* LINUX_SIGCONT */
+ SIGSTOP, /* LINUX_SIGSTOP */
+ SIGTSTP, /* LINUX_SIGTSTP */
+ SIGTTIN, /* LINUX_SIGTTIN */
+ SIGTTOU, /* LINUX_SIGTTOU */
+ SIGURG, /* LINUX_SIGURG */
+ SIGXCPU, /* LINUX_SIGXCPU */
+ SIGXFSZ, /* LINUX_SIGXFSZ */
+ SIGVTALRM, /* LINUX_SIGVTALARM */
+ SIGPROF, /* LINUX_SIGPROF */
+ SIGWINCH, /* LINUX_SIGWINCH */
+ SIGIO, /* LINUX_SIGIO */
+ /*
+ * FreeBSD does not have SIGPWR signal, map Linux SIGPWR signal
+ * to the first unused FreeBSD signal number. Since Linux supports
+ * signals from 1 to 64 we are ok here as our SIGRTMIN = 65.
+ */
+ SIGRTMIN, /* LINUX_SIGPWR */
+ SIGSYS /* LINUX_SIGSYS */
+};
+
+static struct cdev *dev_shm_cdev;
+static struct cdevsw dev_shm_cdevsw = {
+ .d_version = D_VERSION,
+ .d_name = "dev_shm",
+};
+
+/*
+ * Map Linux RT signals to the FreeBSD RT signals.
+ */
+static inline int
+linux_to_bsd_rt_signal(int sig)
+{
+
+ return (SIGRTMIN + 1 + sig - LINUX_SIGRTMIN);
+}
+
+static inline int
+bsd_to_linux_rt_signal(int sig)
+{
+
+ return (sig - SIGRTMIN - 1 + LINUX_SIGRTMIN);
+}
+
+int
+linux_to_bsd_signal(int sig)
+{
+
+ KASSERT(sig > 0 && sig <= LINUX_SIGRTMAX, ("invalid Linux signal %d\n", sig));
+
+ if (sig < LINUX_SIGRTMIN)
+ return (linux_to_bsd_sigtbl[_SIG_IDX(sig)]);
+
+ return (linux_to_bsd_rt_signal(sig));
+}
+
+int
+bsd_to_linux_signal(int sig)
+{
+
+ if (sig <= LINUX_SIGTBLSZ)
+ return (bsd_to_linux_sigtbl[_SIG_IDX(sig)]);
+ if (sig == SIGRTMIN)
+ return (LINUX_SIGPWR);
+
+ return (bsd_to_linux_rt_signal(sig));
+}
+
+int
+linux_to_bsd_sigaltstack(int lsa)
+{
+ int bsa = 0;
+
+ if (lsa & LINUX_SS_DISABLE)
+ bsa |= SS_DISABLE;
+ /*
+ * Linux ignores SS_ONSTACK flag for ss
+ * parameter while FreeBSD prohibits it.
+ */
+ return (bsa);
+}
+
+int
+bsd_to_linux_sigaltstack(int bsa)
+{
+ int lsa = 0;
+
+ if (bsa & SS_DISABLE)
+ lsa |= LINUX_SS_DISABLE;
+ if (bsa & SS_ONSTACK)
+ lsa |= LINUX_SS_ONSTACK;
+ return (lsa);
+}
+
+void
+linux_to_bsd_sigset(l_sigset_t *lss, sigset_t *bss)
+{
+ int b, l;
+
+ SIGEMPTYSET(*bss);
+ for (l = 1; l <= LINUX_SIGRTMAX; l++) {
+ if (LINUX_SIGISMEMBER(*lss, l)) {
+ b = linux_to_bsd_signal(l);
+ if (b)
+ SIGADDSET(*bss, b);
+ }
+ }
+}
+
+void
+bsd_to_linux_sigset(sigset_t *bss, l_sigset_t *lss)
+{
+ int b, l;
+
+ LINUX_SIGEMPTYSET(*lss);
+ for (b = 1; b <= SIGRTMAX; b++) {
+ if (SIGISMEMBER(*bss, b)) {
+ l = bsd_to_linux_signal(b);
+ if (l)
+ LINUX_SIGADDSET(*lss, l);
+ }
+ }
+}
+
+/*
+ * Translate a Linux interface name to a FreeBSD interface name,
+ * and return the associated ifnet structure
+ * bsdname and lxname need to be least IFNAMSIZ bytes long, but
+ * can point to the same buffer.
+ */
+struct ifnet *
+ifname_linux_to_bsd(struct thread *td, const char *lxname, char *bsdname)
+{
+ struct ifnet *ifp;
+ int len, unit;
+ char *ep;
+ int index;
+ bool is_eth, is_lo;
+
+ for (len = 0; len < LINUX_IFNAMSIZ; ++len)
+ if (!isalpha(lxname[len]) || lxname[len] == '\0')
+ break;
+ if (len == 0 || len == LINUX_IFNAMSIZ)
+ return (NULL);
+ /* Linux loopback interface name is lo (not lo0) */
+ is_lo = (len == 2 && strncmp(lxname, "lo", len) == 0);
+ unit = (int)strtoul(lxname + len, &ep, 10);
+ if ((ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ) &&
+ is_lo == 0)
+ return (NULL);
+ index = 0;
+ is_eth = (len == 3 && strncmp(lxname, "eth", len) == 0);
+
+ CURVNET_SET(TD_TO_VNET(td));
+ IFNET_RLOCK();
+ CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+ /*
+ * Allow Linux programs to use FreeBSD names. Don't presume
+ * we never have an interface named "eth", so don't make
+ * the test optional based on is_eth.
+ */
+ if (strncmp(ifp->if_xname, lxname, LINUX_IFNAMSIZ) == 0)
+ break;
+ if (is_eth && IFP_IS_ETH(ifp) && unit == index++)
+ break;
+ if (is_lo && IFP_IS_LOOP(ifp))
+ break;
+ }
+ IFNET_RUNLOCK();
+ CURVNET_RESTORE();
+ if (ifp != NULL && bsdname != NULL)
+ strlcpy(bsdname, ifp->if_xname, IFNAMSIZ);
+ return (ifp);
+}
+
+void
+linux_ifflags(struct ifnet *ifp, short *flags)
+{
+ unsigned short fl;
+
+ fl = (ifp->if_flags | ifp->if_drv_flags) & 0xffff;
+ *flags = 0;
+ if (fl & IFF_UP)
+ *flags |= LINUX_IFF_UP;
+ if (fl & IFF_BROADCAST)
+ *flags |= LINUX_IFF_BROADCAST;
+ if (fl & IFF_DEBUG)
+ *flags |= LINUX_IFF_DEBUG;
+ if (fl & IFF_LOOPBACK)
+ *flags |= LINUX_IFF_LOOPBACK;
+ if (fl & IFF_POINTOPOINT)
+ *flags |= LINUX_IFF_POINTOPOINT;
+ if (fl & IFF_DRV_RUNNING)
+ *flags |= LINUX_IFF_RUNNING;
+ if (fl & IFF_NOARP)
+ *flags |= LINUX_IFF_NOARP;
+ if (fl & IFF_PROMISC)
+ *flags |= LINUX_IFF_PROMISC;
+ if (fl & IFF_ALLMULTI)
+ *flags |= LINUX_IFF_ALLMULTI;
+ if (fl & IFF_MULTICAST)
+ *flags |= LINUX_IFF_MULTICAST;
+}
+
+int
+linux_ifhwaddr(struct ifnet *ifp, struct l_sockaddr *lsa)
+{
+ struct ifaddr *ifa;
+ struct sockaddr_dl *sdl;
+
+ if (IFP_IS_LOOP(ifp)) {
+ bzero(lsa, sizeof(*lsa));
+ lsa->sa_family = LINUX_ARPHRD_LOOPBACK;
+ return (0);
+ }
+
+ if (!IFP_IS_ETH(ifp))
+ return (ENOENT);
+
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ sdl = (struct sockaddr_dl*)ifa->ifa_addr;
+ if (sdl != NULL && (sdl->sdl_family == AF_LINK) &&
+ (sdl->sdl_type == IFT_ETHER)) {
+ bzero(lsa, sizeof(*lsa));
+ lsa->sa_family = LINUX_ARPHRD_ETHER;
+ bcopy(LLADDR(sdl), lsa->sa_data, LINUX_IFHWADDRLEN);
+ return (0);
+ }
+ }
+
+ return (ENOENT);
+}
+
+int
+linux_to_bsd_domain(int domain)
+{
+
+ switch (domain) {
+ case LINUX_AF_UNSPEC:
+ return (AF_UNSPEC);
+ case LINUX_AF_UNIX:
+ return (AF_LOCAL);
+ case LINUX_AF_INET:
+ return (AF_INET);
+ case LINUX_AF_INET6:
+ return (AF_INET6);
+ case LINUX_AF_AX25:
+ return (AF_CCITT);
+ case LINUX_AF_IPX:
+ return (AF_IPX);
+ case LINUX_AF_APPLETALK:
+ return (AF_APPLETALK);
+ }
+ return (-1);
+}
+
+int
+bsd_to_linux_domain(int domain)
+{
+
+ switch (domain) {
+ case AF_UNSPEC:
+ return (LINUX_AF_UNSPEC);
+ case AF_LOCAL:
+ return (LINUX_AF_UNIX);
+ case AF_INET:
+ return (LINUX_AF_INET);
+ case AF_INET6:
+ return (LINUX_AF_INET6);
+ case AF_CCITT:
+ return (LINUX_AF_AX25);
+ case AF_IPX:
+ return (LINUX_AF_IPX);
+ case AF_APPLETALK:
+ return (LINUX_AF_APPLETALK);
+ }
+ return (-1);
+}
+
+/*
+ * Based on the fact that:
+ * 1. Native and Linux storage of struct sockaddr
+ * and struct sockaddr_in6 are equal.
+ * 2. On Linux sa_family is the first member of all struct sockaddr.
+ */
+int
+bsd_to_linux_sockaddr(const struct sockaddr *sa, struct l_sockaddr **lsa,
+ socklen_t len)
+{
+ struct l_sockaddr *kosa;
+ int error, bdom;
+
+ *lsa = NULL;
+ if (len < 2 || len > UCHAR_MAX)
+ return (EINVAL);
+
+ kosa = malloc(len, M_SONAME, M_WAITOK);
+ bcopy(sa, kosa, len);
+
+ bdom = bsd_to_linux_domain(sa->sa_family);
+ if (bdom == -1) {
+ error = EAFNOSUPPORT;
+ goto out;
+ }
+
+ kosa->sa_family = bdom;
+ *lsa = kosa;
+ return (0);
+
+out:
+ free(kosa, M_SONAME);
+ return (error);
+}
+
+int
+linux_to_bsd_sockaddr(const struct l_sockaddr *osa, struct sockaddr **sap,
+ socklen_t *len)
+{
+ struct sockaddr *sa;
+ struct l_sockaddr *kosa;
+#ifdef INET6
+ struct sockaddr_in6 *sin6;
+ bool oldv6size;
+#endif
+ char *name;
+ int salen, bdom, error, hdrlen, namelen;
+
+ if (*len < 2 || *len > UCHAR_MAX)
+ return (EINVAL);
+
+ salen = *len;
+
+#ifdef INET6
+ oldv6size = false;
+ /*
+ * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
+ * if it's a v4-mapped address, so reserve the proper space
+ * for it.
+ */
+ if (salen == sizeof(struct sockaddr_in6) - sizeof(uint32_t)) {
+ salen += sizeof(uint32_t);
+ oldv6size = true;
+ }
+#endif
+
+ kosa = malloc(salen, M_SONAME, M_WAITOK);
+
+ if ((error = copyin(osa, kosa, *len)))
+ goto out;
+
+ bdom = linux_to_bsd_domain(kosa->sa_family);
+ if (bdom == -1) {
+ error = EAFNOSUPPORT;
+ goto out;
+ }
+
+#ifdef INET6
+ /*
+ * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
+ * which lacks the scope id compared with RFC2553 one. If we detect
+ * the situation, reject the address and write a message to system log.
+ *
+ * Still accept addresses for which the scope id is not used.
+ */
+ if (oldv6size) {
+ if (bdom == AF_INET6) {
+ sin6 = (struct sockaddr_in6 *)kosa;
+ if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
+ (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
+ !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
+ !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
+ !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
+ !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
+ sin6->sin6_scope_id = 0;
+ } else {
+ linux_msg(curthread,
+ "obsolete pre-RFC2553 sockaddr_in6 rejected");
+ error = EINVAL;
+ goto out;
+ }
+ } else
+ salen -= sizeof(uint32_t);
+ }
+#endif
+ if (bdom == AF_INET) {
+ if (salen < sizeof(struct sockaddr_in)) {
+ error = EINVAL;
+ goto out;
+ }
+ salen = sizeof(struct sockaddr_in);
+ }
+
+ if (bdom == AF_LOCAL && salen > sizeof(struct sockaddr_un)) {
+ hdrlen = offsetof(struct sockaddr_un, sun_path);
+ name = ((struct sockaddr_un *)kosa)->sun_path;
+ if (*name == '\0') {
+ /*
+ * Linux abstract namespace starts with a NULL byte.
+ * XXX We do not support abstract namespace yet.
+ */
+ namelen = strnlen(name + 1, salen - hdrlen - 1) + 1;
+ } else
+ namelen = strnlen(name, salen - hdrlen);
+ salen = hdrlen + namelen;
+ if (salen > sizeof(struct sockaddr_un)) {
+ error = ENAMETOOLONG;
+ goto out;
+ }
+ }
+
+ sa = (struct sockaddr *)kosa;
+ sa->sa_family = bdom;
+ sa->sa_len = salen;
+
+ *sap = sa;
+ *len = salen;
+ return (0);
+
+out:
+ free(kosa, M_SONAME);
+ return (error);
+}
+
+void
+linux_dev_shm_create(void)
+{
+ int error;
+
+ error = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK, &dev_shm_cdev,
+ &dev_shm_cdevsw, NULL, UID_ROOT, GID_WHEEL, 0, "shm/.mountpoint");
+ if (error != 0) {
+ printf("%s: failed to create device node, error %d\n",
+ __func__, error);
+ }
+}
+
+void
+linux_dev_shm_destroy(void)
+{
+
+ destroy_dev(dev_shm_cdev);
+}
+
+int
+bsd_to_linux_bits_(int value, struct bsd_to_linux_bitmap *bitmap,
+ size_t mapcnt, int no_value)
+{
+ int bsd_mask, bsd_value, linux_mask, linux_value;
+ int linux_ret;
+ size_t i;
+ bool applied;
+
+ applied = false;
+ linux_ret = 0;
+ for (i = 0; i < mapcnt; ++i) {
+ bsd_mask = bitmap[i].bsd_mask;
+ bsd_value = bitmap[i].bsd_value;
+ if (bsd_mask == 0)
+ bsd_mask = bsd_value;
+
+ linux_mask = bitmap[i].linux_mask;
+ linux_value = bitmap[i].linux_value;
+ if (linux_mask == 0)
+ linux_mask = linux_value;
+
+ /*
+ * If a mask larger than just the value is set, we explicitly
+ * want to make sure that only this bit we mapped within that
+ * mask is set.
+ */
+ if ((value & bsd_mask) == bsd_value) {
+ linux_ret = (linux_ret & ~linux_mask) | linux_value;
+ applied = true;
+ }
+ }
+
+ if (!applied)
+ return (no_value);
+ return (linux_ret);
+}
+
+int
+linux_to_bsd_bits_(int value, struct bsd_to_linux_bitmap *bitmap,
+ size_t mapcnt, int no_value)
+{
+ int bsd_mask, bsd_value, linux_mask, linux_value;
+ int bsd_ret;
+ size_t i;
+ bool applied;
+
+ applied = false;
+ bsd_ret = 0;
+ for (i = 0; i < mapcnt; ++i) {
+ bsd_mask = bitmap[i].bsd_mask;
+ bsd_value = bitmap[i].bsd_value;
+ if (bsd_mask == 0)
+ bsd_mask = bsd_value;
+
+ linux_mask = bitmap[i].linux_mask;
+ linux_value = bitmap[i].linux_value;
+ if (linux_mask == 0)
+ linux_mask = linux_value;
+
+ /*
+ * If a mask larger than just the value is set, we explicitly
+ * want to make sure that only this bit we mapped within that
+ * mask is set.
+ */
+ if ((value & linux_mask) == linux_value) {
+ bsd_ret = (bsd_ret & ~bsd_mask) | bsd_value;
+ applied = true;
+ }
+ }
+
+ if (!applied)
+ return (no_value);
+ return (bsd_ret);
+}
diff --git a/sys/compat/linux/linux.h b/sys/compat/linux/linux.h
new file mode 100644
index 000000000000..48217959951c
--- /dev/null
+++ b/sys/compat/linux/linux.h
@@ -0,0 +1,208 @@
+/*-
+ * Copyright (c) 2015 Dmitry Chagin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_MI_H_
+#define _LINUX_MI_H_
+
+#include <sys/queue.h>
+
+#define LINUX_IFHWADDRLEN 6
+#define LINUX_IFNAMSIZ 16
+
+/*
+ * Criteria for interface name translation
+ */
+#define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER)
+#define IFP_IS_LOOP(ifp) (ifp->if_type == IFT_LOOP)
+
+struct l_sockaddr {
+ unsigned short sa_family;
+ char sa_data[14];
+};
+
+#define LINUX_ARPHRD_ETHER 1
+#define LINUX_ARPHRD_LOOPBACK 772
+
+/*
+ * Supported address families
+ */
+#define LINUX_AF_UNSPEC 0
+#define LINUX_AF_UNIX 1
+#define LINUX_AF_INET 2
+#define LINUX_AF_AX25 3
+#define LINUX_AF_IPX 4
+#define LINUX_AF_APPLETALK 5
+#define LINUX_AF_INET6 10
+#define LINUX_AF_NETLINK 16
+
+#define LINUX_NETLINK_ROUTE 0
+#define LINUX_NETLINK_SOCK_DIAG 4
+#define LINUX_NETLINK_NFLOG 5
+#define LINUX_NETLINK_SELINUX 7
+#define LINUX_NETLINK_AUDIT 9
+#define LINUX_NETLINK_FIB_LOOKUP 10
+#define LINUX_NETLINK_NETFILTER 12
+#define LINUX_NETLINK_KOBJECT_UEVENT 15
+
+/*
+ * net device flags
+ */
+#define LINUX_IFF_UP 0x0001
+#define LINUX_IFF_BROADCAST 0x0002
+#define LINUX_IFF_DEBUG 0x0004
+#define LINUX_IFF_LOOPBACK 0x0008
+#define LINUX_IFF_POINTOPOINT 0x0010
+#define LINUX_IFF_NOTRAILERS 0x0020
+#define LINUX_IFF_RUNNING 0x0040
+#define LINUX_IFF_NOARP 0x0080
+#define LINUX_IFF_PROMISC 0x0100
+#define LINUX_IFF_ALLMULTI 0x0200
+#define LINUX_IFF_MASTER 0x0400
+#define LINUX_IFF_SLAVE 0x0800
+#define LINUX_IFF_MULTICAST 0x1000
+#define LINUX_IFF_PORTSEL 0x2000
+#define LINUX_IFF_AUTOMEDIA 0x4000
+#define LINUX_IFF_DYNAMIC 0x8000
+
+/* sigaltstack */
+#define LINUX_SS_ONSTACK 1
+#define LINUX_SS_DISABLE 2
+
+int linux_to_bsd_sigaltstack(int lsa);
+int bsd_to_linux_sigaltstack(int bsa);
+
+/* sigset */
+typedef struct {
+ uint64_t __mask;
+} l_sigset_t;
+
+/* primitives to manipulate sigset_t */
+#define LINUX_SIGEMPTYSET(set) (set).__mask = 0
+#define LINUX_SIGISMEMBER(set, sig) (1UL & ((set).__mask >> _SIG_IDX(sig)))
+#define LINUX_SIGADDSET(set, sig) (set).__mask |= 1UL << _SIG_IDX(sig)
+
+void linux_to_bsd_sigset(l_sigset_t *, sigset_t *);
+void bsd_to_linux_sigset(sigset_t *, l_sigset_t *);
+
+/* signaling */
+#define LINUX_SIGHUP 1
+#define LINUX_SIGINT 2
+#define LINUX_SIGQUIT 3
+#define LINUX_SIGILL 4
+#define LINUX_SIGTRAP 5
+#define LINUX_SIGABRT 6
+#define LINUX_SIGIOT LINUX_SIGABRT
+#define LINUX_SIGBUS 7
+#define LINUX_SIGFPE 8
+#define LINUX_SIGKILL 9
+#define LINUX_SIGUSR1 10
+#define LINUX_SIGSEGV 11
+#define LINUX_SIGUSR2 12
+#define LINUX_SIGPIPE 13
+#define LINUX_SIGALRM 14
+#define LINUX_SIGTERM 15
+#define LINUX_SIGSTKFLT 16
+#define LINUX_SIGCHLD 17
+#define LINUX_SIGCONT 18
+#define LINUX_SIGSTOP 19
+#define LINUX_SIGTSTP 20
+#define LINUX_SIGTTIN 21
+#define LINUX_SIGTTOU 22
+#define LINUX_SIGURG 23
+#define LINUX_SIGXCPU 24
+#define LINUX_SIGXFSZ 25
+#define LINUX_SIGVTALRM 26
+#define LINUX_SIGPROF 27
+#define LINUX_SIGWINCH 28
+#define LINUX_SIGIO 29
+#define LINUX_SIGPOLL LINUX_SIGIO
+#define LINUX_SIGPWR 30
+#define LINUX_SIGSYS 31
+#define LINUX_SIGTBLSZ 31
+#define LINUX_SIGRTMIN 32
+#define LINUX_SIGRTMAX 64
+
+#define LINUX_SIG_VALID(sig) ((sig) <= LINUX_SIGRTMAX && (sig) > 0)
+
+int linux_to_bsd_signal(int sig);
+int bsd_to_linux_signal(int sig);
+
+extern LIST_HEAD(futex_list, futex) futex_list;
+extern struct mtx futex_mtx;
+
+void linux_dev_shm_create(void);
+void linux_dev_shm_destroy(void);
+
+/*
+ * mask=0 is not sensible for this application, so it will be taken to mean
+ * a mask equivalent to the value. Otherwise, (word & mask) == value maps to
+ * (word & ~mask) | value in a bitfield for the platform we're converting to.
+ */
+struct bsd_to_linux_bitmap {
+ int bsd_mask;
+ int bsd_value;
+ int linux_mask;
+ int linux_value;
+};
+
+int bsd_to_linux_bits_(int value, struct bsd_to_linux_bitmap *bitmap,
+ size_t mapcnt, int no_value);
+int linux_to_bsd_bits_(int value, struct bsd_to_linux_bitmap *bitmap,
+ size_t mapcnt, int no_value);
+
+/*
+ * These functions are used for simplification of BSD <-> Linux bit conversions.
+ * Given `value`, a bit field, these functions will walk the given bitmap table
+ * and set the appropriate bits for the target platform. If any bits were
+ * successfully converted, then the return value is the equivalent of value
+ * represented with the bit values appropriate for the target platform.
+ * Otherwise, the value supplied as `no_value` is returned.
+ */
+#define bsd_to_linux_bits(_val, _bmap, _noval) \
+ bsd_to_linux_bits_((_val), (_bmap), nitems((_bmap)), (_noval))
+#define linux_to_bsd_bits(_val, _bmap, _noval) \
+ linux_to_bsd_bits_((_val), (_bmap), nitems((_bmap)), (_noval))
+
+/*
+ * Easy mapping helpers. BITMAP_EASY_LINUX represents a single bit to be
+ * translated, and the FreeBSD and Linux values are supplied. BITMAP_1t1_LINUX
+ * is the extreme version of this, where not only is it a single bit, but the
+ * name of the macro used to represent the Linux version of a bit literally has
+ * LINUX_ prepended to the normal name.
+ */
+#define BITMAP_EASY_LINUX(_name, _linux_name) \
+ { \
+ .bsd_value = (_name), \
+ .linux_value = (_linux_name), \
+ }
+#define BITMAP_1t1_LINUX(_name) BITMAP_EASY_LINUX(_name, LINUX_##_name)
+
+int bsd_to_linux_errno(int error);
+void linux_check_errtbl(void);
+
+#endif /* _LINUX_MI_H_ */
diff --git a/sys/compat/linux/linux_common.c b/sys/compat/linux/linux_common.c
new file mode 100644
index 000000000000..5a0ac015ed0e
--- /dev/null
+++ b/sys/compat/linux/linux_common.c
@@ -0,0 +1,92 @@
+/*-
+ * Copyright (c) 2014 Vassilis Laganakos
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/exec.h>
+#include <sys/imgact.h>
+#include <sys/imgact_elf.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/sx.h>
+
+#include <compat/linux/linux.h>
+#include <compat/linux/linux_emul.h>
+#include <compat/linux/linux_ioctl.h>
+#include <compat/linux/linux_mib.h>
+#include <compat/linux/linux_util.h>
+
+MODULE_VERSION(linux_common, 1);
+
+SET_DECLARE(linux_device_handler_set, struct linux_device_handler);
+
+TAILQ_HEAD(, linux_ioctl_handler_element) linux_ioctl_handlers =
+ TAILQ_HEAD_INITIALIZER(linux_ioctl_handlers);
+struct sx linux_ioctl_sx;
+SX_SYSINIT(linux_ioctl, &linux_ioctl_sx, "Linux ioctl handlers");
+
+static int
+linux_common_modevent(module_t mod, int type, void *data)
+{
+ struct linux_device_handler **ldhp;
+
+ switch(type) {
+ case MOD_LOAD:
+#ifdef INVARIANTS
+ linux_check_errtbl();
+#endif
+ linux_dev_shm_create();
+ linux_osd_jail_register();
+ SET_FOREACH(ldhp, linux_device_handler_set)
+ linux_device_register_handler(*ldhp);
+ LIST_INIT(&futex_list);
+ mtx_init(&futex_mtx, "ftllk", NULL, MTX_DEF);
+ break;
+ case MOD_UNLOAD:
+ linux_dev_shm_destroy();
+ linux_osd_jail_deregister();
+ SET_FOREACH(ldhp, linux_device_handler_set)
+ linux_device_unregister_handler(*ldhp);
+ mtx_destroy(&futex_mtx);
+ break;
+ default:
+ return (EOPNOTSUPP);
+ }
+ return (0);
+}
+
+static moduledata_t linux_common_mod = {
+ "linuxcommon",
+ linux_common_modevent,
+ 0
+};
+
+DECLARE_MODULE(linuxcommon, linux_common_mod, SI_SUB_EXEC, SI_ORDER_ANY);
+MODULE_VERSION(linuxcommon, 1);
diff --git a/sys/compat/linux/linux_common.h b/sys/compat/linux/linux_common.h
new file mode 100644
index 000000000000..a306bb1eb859
--- /dev/null
+++ b/sys/compat/linux/linux_common.h
@@ -0,0 +1,45 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Dmitry Chagin
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_COMMON_H_
+#define _LINUX_COMMON_H_
+
+struct ifnet *ifname_linux_to_bsd(struct thread *td,
+ const char *lxname, char *bsdname);
+void linux_ifflags(struct ifnet *ifp, short *flags);
+int linux_ifhwaddr(struct ifnet *ifp, struct l_sockaddr *lsa);
+
+int linux_to_bsd_domain(int domain);
+int bsd_to_linux_domain(int domain);
+int bsd_to_linux_sockaddr(const struct sockaddr *sa,
+ struct l_sockaddr **lsa, socklen_t len);
+int linux_to_bsd_sockaddr(const struct l_sockaddr *lsa,
+ struct sockaddr **sap, socklen_t *len);
+
+#endif /* _LINUX_COMMON_H_ */
diff --git a/sys/compat/linux/linux_dtrace.h b/sys/compat/linux/linux_dtrace.h
new file mode 100644
index 000000000000..0bf42f43bac1
--- /dev/null
+++ b/sys/compat/linux/linux_dtrace.h
@@ -0,0 +1,92 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2008-2012 Alexander Leidinger <netchild@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_DTRACE_H_
+#define _LINUX_DTRACE_H_
+
+/**
+ * DTrace support macros for the linuxulator.
+ *
+ * Some wrapper macros to make it more easy to handle the linuxulator
+ * providers and to allow to make the name depend upon the bitsize.
+ *
+ * Basically this is the same as the normal SDT macros in sys/sdt.h. The
+ * difference is that the provider name is automatically inserted, and
+ * we do not use a different name for the probe-description.
+ */
+
+#define LIN_SDT_PROVIDER_DEFINE(x) SDT_PROVIDER_DEFINE(x)
+#define LIN_SDT_PROVIDER_DECLARE(x) SDT_PROVIDER_DECLARE(x)
+
+#define _LIN_SDT_PROBE_DECLARE(a, b, c, d) SDT_PROBE_DECLARE(a, b, c, d)
+#define LIN_SDT_PROBE_DECLARE(a, b, c) _LIN_SDT_PROBE_DECLARE( \
+ LINUX_DTRACE, a, b, c)
+
+#define _LIN_SDT_PROBE_DEFINE0(a, b, c, d) SDT_PROBE_DEFINE(a, \
+ b, c, d)
+#define LIN_SDT_PROBE_DEFINE0(a, b, c) _LIN_SDT_PROBE_DEFINE0(\
+ LINUX_DTRACE, a, b, c)
+#define _LIN_SDT_PROBE_DEFINE1(a, b, c, d, e) SDT_PROBE_DEFINE1(a, \
+ b, c, d, e)
+#define LIN_SDT_PROBE_DEFINE1(a, b, c, d) _LIN_SDT_PROBE_DEFINE1(\
+ LINUX_DTRACE, a, b, c, d)
+#define _LIN_SDT_PROBE_DEFINE2(a, b, c, d, e, f) SDT_PROBE_DEFINE2(a, \
+ b, c, d, e, f)
+#define LIN_SDT_PROBE_DEFINE2(a, b, c, d, e) _LIN_SDT_PROBE_DEFINE2(\
+ LINUX_DTRACE, a, b, c, d, e)
+#define _LIN_SDT_PROBE_DEFINE3(a, b, c, d, e, f, g) SDT_PROBE_DEFINE3(a, \
+ b, c, d, e, f, g)
+#define LIN_SDT_PROBE_DEFINE3(a, b, c, d, e, f) _LIN_SDT_PROBE_DEFINE3(\
+ LINUX_DTRACE, a, b, c, d, e, f)
+#define _LIN_SDT_PROBE_DEFINE4(a, b, c, d, e, f, g, h) SDT_PROBE_DEFINE4(a, \
+ b, c, d, e, f, g, h)
+#define LIN_SDT_PROBE_DEFINE4(a, b, c, d, e, f, g) _LIN_SDT_PROBE_DEFINE4(\
+ LINUX_DTRACE, a, b, c, d, e, f, g)
+#define _LIN_SDT_PROBE_DEFINE5(a, b, c, d, e, f, g, h, i) \
+ SDT_PROBE_DEFINE5(a, b, c, d, e, f, g, h, i)
+#define LIN_SDT_PROBE_DEFINE5(a, b, c, d, e, f, g, h) _LIN_SDT_PROBE_DEFINE5(\
+ LINUX_DTRACE, a, b, c, d, e, f, g, h)
+
+#define LIN_SDT_PROBE0(a, b, c) SDT_PROBE0(LINUX_DTRACE, a, b, \
+ c)
+#define LIN_SDT_PROBE1(a, b, c, d) SDT_PROBE1(LINUX_DTRACE, a, b, \
+ c, d)
+#define LIN_SDT_PROBE2(a, b, c, d, e) SDT_PROBE2(LINUX_DTRACE, a, b, \
+ c, d, e)
+#define LIN_SDT_PROBE3(a, b, c, d, e, f) SDT_PROBE3(LINUX_DTRACE, a, b, \
+ c, d, e, f)
+#define LIN_SDT_PROBE4(a, b, c, d, e, f, g) SDT_PROBE4(LINUX_DTRACE, a, b, \
+ c, d, e, f, g)
+#define _LIN_SDT_PROBE5(a, b, c, d, e, f, g, h, i) SDT_PROBE5(a, b, c, d, \
+ e, f, g, h, i)
+#define LIN_SDT_PROBE5(a, b, c, d, e, f, g, h) _LIN_SDT_PROBE5(LINUX_DTRACE, \
+ a, b, c, d, e, f, g, h)
+
+#endif /* _LINUX_DTRACE_H_ */
diff --git a/sys/compat/linux/linux_dummy.c b/sys/compat/linux/linux_dummy.c
new file mode 100644
index 000000000000..ae551da7fb43
--- /dev/null
+++ b/sys/compat/linux/linux_dummy.c
@@ -0,0 +1,155 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2013 Dmitry Chagin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/sdt.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+
+/*
+ * Including linux vs linux32 here is arbitrary -- the syscall args structures
+ * (proto.h) are not dereferenced by the DUMMY stub implementations, and
+ * suitable for use by both native and compat32 entrypoints.
+ */
+#include <machine/../linux/linux.h>
+#include <machine/../linux/linux_proto.h>
+
+#include <compat/linux/linux_dtrace.h>
+#include <compat/linux/linux_util.h>
+
+/* DTrace init */
+LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
+
+UNIMPLEMENTED(afs_syscall);
+UNIMPLEMENTED(create_module); /* Added in Linux 1.0 removed in 2.6. */
+UNIMPLEMENTED(epoll_ctl_old);
+UNIMPLEMENTED(epoll_wait_old);
+UNIMPLEMENTED(get_kernel_syms); /* Added in Linux 1.0 removed in 2.6. */
+UNIMPLEMENTED(getpmsg);
+UNIMPLEMENTED(nfsservctl); /* Added in Linux 2.2 removed in 3.1. */
+UNIMPLEMENTED(putpmsg);
+UNIMPLEMENTED(query_module); /* Added in Linux 2.2 removed in 2.6. */
+UNIMPLEMENTED(security);
+UNIMPLEMENTED(vserver);
+
+DUMMY(setfsuid);
+DUMMY(setfsgid);
+DUMMY(vhangup);
+DUMMY(pivot_root);
+DUMMY(adjtimex);
+DUMMY(swapoff);
+DUMMY(init_module);
+DUMMY(delete_module);
+DUMMY(lookup_dcookie);
+DUMMY(remap_file_pages);
+DUMMY(mbind);
+DUMMY(get_mempolicy);
+DUMMY(set_mempolicy);
+DUMMY(kexec_load);
+/* Linux 2.6.11: */
+DUMMY(add_key);
+DUMMY(request_key);
+DUMMY(keyctl);
+/* Linux 2.6.13: */
+DUMMY(ioprio_set);
+DUMMY(ioprio_get);
+DUMMY(inotify_add_watch);
+DUMMY(inotify_rm_watch);
+/* Linux 2.6.16: */
+DUMMY(migrate_pages);
+DUMMY(unshare);
+/* Linux 2.6.17: */
+DUMMY(tee);
+DUMMY(vmsplice);
+/* Linux 2.6.18: */
+DUMMY(move_pages);
+/* Linux 2.6.27: */
+DUMMY(signalfd4);
+DUMMY(inotify_init1);
+/* Linux 2.6.31: */
+DUMMY(perf_event_open);
+/* Linux 2.6.36: */
+DUMMY(fanotify_init);
+DUMMY(fanotify_mark);
+/* Linux 2.6.39: */
+DUMMY(clock_adjtime);
+/* Linux 3.0: */
+DUMMY(setns);
+/* Linux 3.2: */
+DUMMY(process_vm_readv);
+DUMMY(process_vm_writev);
+/* Linux 3.5: */
+DUMMY(kcmp);
+/* Linux 3.8: */
+DUMMY(finit_module);
+DUMMY(sched_setattr);
+DUMMY(sched_getattr);
+/* Linux 3.17: */
+DUMMY(seccomp);
+/* Linux 3.18: */
+DUMMY(bpf);
+/* Linux 3.19: */
+DUMMY(execveat);
+/* Linux 4.2: */
+DUMMY(userfaultfd);
+/* Linux 4.3: */
+DUMMY(membarrier);
+/* Linux 4.4: */
+DUMMY(mlock2);
+/* Linux 4.6: */
+DUMMY(preadv2);
+DUMMY(pwritev2);
+/* Linux 4.8: */
+DUMMY(pkey_mprotect);
+DUMMY(pkey_alloc);
+DUMMY(pkey_free);
+
+#define DUMMY_XATTR(s) \
+int \
+linux_ ## s ## xattr( \
+ struct thread *td, struct linux_ ## s ## xattr_args *arg) \
+{ \
+ \
+ return (EOPNOTSUPP); \
+}
+DUMMY_XATTR(set);
+DUMMY_XATTR(lset);
+DUMMY_XATTR(fset);
+DUMMY_XATTR(get);
+DUMMY_XATTR(lget);
+DUMMY_XATTR(fget);
+DUMMY_XATTR(list);
+DUMMY_XATTR(llist);
+DUMMY_XATTR(flist);
+DUMMY_XATTR(remove);
+DUMMY_XATTR(lremove);
+DUMMY_XATTR(fremove);
diff --git a/sys/compat/linux/linux_emul.c b/sys/compat/linux/linux_emul.c
new file mode 100644
index 000000000000..499bebe8926a
--- /dev/null
+++ b/sys/compat/linux/linux_emul.c
@@ -0,0 +1,383 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1994-1996 Søren Schmidt
+ * Copyright (c) 2006 Roman Divacky
+ * Copyright (c) 2013 Dmitry Chagin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/fcntl.h>
+#include <sys/imgact.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/sx.h>
+#include <sys/proc.h>
+#include <sys/resourcevar.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysent.h>
+
+#include <compat/linux/linux_emul.h>
+#include <compat/linux/linux_mib.h>
+#include <compat/linux/linux_misc.h>
+#include <compat/linux/linux_persona.h>
+#include <compat/linux/linux_util.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define SHELLMAGIC 0x2123 /* #! */
+#else
+#define SHELLMAGIC 0x2321
+#endif
+
+/*
+ * This returns reference to the thread emuldata entry (if found)
+ *
+ * Hold PROC_LOCK when referencing emuldata from other threads.
+ */
+struct linux_emuldata *
+em_find(struct thread *td)
+{
+ struct linux_emuldata *em;
+
+ em = td->td_emuldata;
+
+ return (em);
+}
+
+/*
+ * This returns reference to the proc pemuldata entry (if found)
+ *
+ * Hold PROC_LOCK when referencing proc pemuldata from other threads.
+ * Hold LINUX_PEM_LOCK wher referencing pemuldata members.
+ */
+struct linux_pemuldata *
+pem_find(struct proc *p)
+{
+ struct linux_pemuldata *pem;
+
+ pem = p->p_emuldata;
+
+ return (pem);
+}
+
+/*
+ * Linux apps generally expect the soft open file limit to be set
+ * to 1024, often iterating over all the file descriptors up to that
+ * limit instead of using closefrom(2). Give them what they want,
+ * unless there already is a resource limit in place.
+ */
+static void
+linux_set_default_openfiles(struct thread *td, struct proc *p)
+{
+ struct rlimit rlim;
+ int error;
+
+ if (linux_default_openfiles < 0)
+ return;
+
+ PROC_LOCK(p);
+ lim_rlimit_proc(p, RLIMIT_NOFILE, &rlim);
+ PROC_UNLOCK(p);
+ if (rlim.rlim_cur != rlim.rlim_max ||
+ rlim.rlim_cur <= linux_default_openfiles)
+ return;
+ rlim.rlim_cur = linux_default_openfiles;
+ error = kern_proc_setrlimit(td, p, RLIMIT_NOFILE, &rlim);
+ KASSERT(error == 0, ("kern_proc_setrlimit failed"));
+}
+
+/*
+ * The default stack size limit in Linux is 8MB.
+ */
+static void
+linux_set_default_stacksize(struct thread *td, struct proc *p)
+{
+ struct rlimit rlim;
+ int error;
+
+ if (linux_default_stacksize < 0)
+ return;
+
+ PROC_LOCK(p);
+ lim_rlimit_proc(p, RLIMIT_STACK, &rlim);
+ PROC_UNLOCK(p);
+ if (rlim.rlim_cur != rlim.rlim_max ||
+ rlim.rlim_cur <= linux_default_stacksize)
+ return;
+ rlim.rlim_cur = linux_default_stacksize;
+ error = kern_proc_setrlimit(td, p, RLIMIT_STACK, &rlim);
+ KASSERT(error == 0, ("kern_proc_setrlimit failed"));
+}
+
+void
+linux_proc_init(struct thread *td, struct thread *newtd, int flags)
+{
+ struct linux_emuldata *em;
+ struct linux_pemuldata *pem;
+ struct proc *p;
+
+ if (newtd != NULL) {
+ p = newtd->td_proc;
+
+ /* non-exec call */
+ em = malloc(sizeof(*em), M_TEMP, M_WAITOK | M_ZERO);
+ if (flags & LINUX_CLONE_THREAD) {
+ LINUX_CTR1(proc_init, "thread newtd(%d)",
+ newtd->td_tid);
+
+ em->em_tid = newtd->td_tid;
+ } else {
+ LINUX_CTR1(proc_init, "fork newtd(%d)", p->p_pid);
+
+ em->em_tid = p->p_pid;
+
+ pem = malloc(sizeof(*pem), M_LINUX, M_WAITOK | M_ZERO);
+ sx_init(&pem->pem_sx, "lpemlk");
+ p->p_emuldata = pem;
+ }
+ newtd->td_emuldata = em;
+
+ linux_set_default_openfiles(td, p);
+ linux_set_default_stacksize(td, p);
+ } else {
+ p = td->td_proc;
+
+ /* exec */
+ LINUX_CTR1(proc_init, "exec newtd(%d)", p->p_pid);
+
+ /* lookup the old one */
+ em = em_find(td);
+ KASSERT(em != NULL, ("proc_init: emuldata not found in exec case.\n"));
+
+ em->em_tid = p->p_pid;
+ em->flags = 0;
+ em->robust_futexes = NULL;
+ em->child_clear_tid = NULL;
+ em->child_set_tid = NULL;
+
+ pem = pem_find(p);
+ KASSERT(pem != NULL, ("proc_exit: proc emuldata not found.\n"));
+ pem->persona = 0;
+ }
+
+}
+
+void
+linux_on_exit(struct proc *p)
+{
+ struct linux_pemuldata *pem;
+ struct thread *td = curthread;
+
+ MPASS(SV_CURPROC_ABI() == SV_ABI_LINUX);
+
+ LINUX_CTR3(proc_exit, "thread(%d) proc(%d) p %p",
+ td->td_tid, p->p_pid, p);
+
+ pem = pem_find(p);
+ if (pem == NULL)
+ return;
+ (p->p_sysent->sv_thread_detach)(td);
+
+ p->p_emuldata = NULL;
+
+ sx_destroy(&pem->pem_sx);
+ free(pem, M_LINUX);
+}
+
+/*
+ * If a Linux binary is exec'ing something, try this image activator
+ * first. We override standard shell script execution in order to
+ * be able to modify the interpreter path. We only do this if a Linux
+ * binary is doing the exec, so we do not create an EXEC module for it.
+ */
+int
+linux_exec_imgact_try(struct image_params *imgp)
+{
+ const char *head = (const char *)imgp->image_header;
+ char *rpath;
+ int error = -1;
+
+ /*
+ * The interpreter for shell scripts run from a Linux binary needs
+ * to be located in /compat/linux if possible in order to recursively
+ * maintain Linux path emulation.
+ */
+ if (((const short *)head)[0] == SHELLMAGIC) {
+ /*
+ * Run our normal shell image activator. If it succeeds attempt
+ * to use the alternate path for the interpreter. If an
+ * alternate path is found, use our stringspace to store it.
+ */
+ if ((error = exec_shell_imgact(imgp)) == 0) {
+ linux_emul_convpath(FIRST_THREAD_IN_PROC(imgp->proc),
+ imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0,
+ AT_FDCWD);
+ if (rpath != NULL)
+ imgp->args->fname_buf =
+ imgp->interpreter_name = rpath;
+ }
+ }
+ return (error);
+}
+
+int
+linux_common_execve(struct thread *td, struct image_args *eargs)
+{
+ struct linux_pemuldata *pem;
+ struct vmspace *oldvmspace;
+ struct linux_emuldata *em;
+ struct proc *p;
+ int error;
+
+ p = td->td_proc;
+
+ error = pre_execve(td, &oldvmspace);
+ if (error != 0)
+ return (error);
+
+ error = kern_execve(td, eargs, NULL, oldvmspace);
+ post_execve(td, error, oldvmspace);
+ if (error != EJUSTRETURN)
+ return (error);
+
+ /*
+ * In a case of transition from Linux binary execing to
+ * FreeBSD binary we destroy Linux emuldata thread & proc entries.
+ */
+ if (SV_CURPROC_ABI() != SV_ABI_LINUX) {
+ PROC_LOCK(p);
+ em = em_find(td);
+ KASSERT(em != NULL, ("proc_exec: thread emuldata not found.\n"));
+ td->td_emuldata = NULL;
+
+ pem = pem_find(p);
+ KASSERT(pem != NULL, ("proc_exec: proc pemuldata not found.\n"));
+ p->p_emuldata = NULL;
+ PROC_UNLOCK(p);
+
+ free(em, M_TEMP);
+ free(pem, M_LINUX);
+ }
+ return (EJUSTRETURN);
+}
+
+void
+linux_on_exec(struct proc *p, struct image_params *imgp)
+{
+ struct thread *td;
+ struct thread *othertd;
+#if defined(__amd64__)
+ struct linux_pemuldata *pem;
+#endif
+
+ td = curthread;
+ MPASS((imgp->sysent->sv_flags & SV_ABI_MASK) == SV_ABI_LINUX);
+
+ /*
+ * When execing to Linux binary, we create Linux emuldata
+ * thread entry.
+ */
+ if (SV_PROC_ABI(p) == SV_ABI_LINUX) {
+ /*
+ * Process already was under Linuxolator
+ * before exec. Update emuldata to reflect
+ * single-threaded cleaned state after exec.
+ */
+ linux_proc_init(td, NULL, 0);
+ } else {
+ /*
+ * We are switching the process to Linux emulator.
+ */
+ linux_proc_init(td, td, 0);
+
+ /*
+ * Create a transient td_emuldata for all suspended
+ * threads, so that p->p_sysent->sv_thread_detach() ==
+ * linux_thread_detach() can find expected but unused
+ * emuldata.
+ */
+ FOREACH_THREAD_IN_PROC(td->td_proc, othertd) {
+ if (othertd == td)
+ continue;
+ linux_proc_init(td, othertd, LINUX_CLONE_THREAD);
+ }
+ }
+#if defined(__amd64__)
+ /*
+ * An IA32 executable which has executable stack will have the
+ * READ_IMPLIES_EXEC personality flag set automatically.
+ */
+ if (SV_PROC_FLAG(td->td_proc, SV_ILP32) &&
+ imgp->stack_prot & VM_PROT_EXECUTE) {
+ pem = pem_find(p);
+ pem->persona |= LINUX_READ_IMPLIES_EXEC;
+ }
+#endif
+}
+
+void
+linux_thread_dtor(struct thread *td)
+{
+ struct linux_emuldata *em;
+
+ em = em_find(td);
+ if (em == NULL)
+ return;
+ td->td_emuldata = NULL;
+
+ LINUX_CTR1(thread_dtor, "thread(%d)", em->em_tid);
+
+ free(em, M_TEMP);
+}
+
+void
+linux_schedtail(struct thread *td)
+{
+ struct linux_emuldata *em;
+ struct proc *p;
+ int error = 0;
+ int *child_set_tid;
+
+ p = td->td_proc;
+
+ em = em_find(td);
+ KASSERT(em != NULL, ("linux_schedtail: thread emuldata not found.\n"));
+ child_set_tid = em->child_set_tid;
+
+ if (child_set_tid != NULL) {
+ error = copyout(&em->em_tid, child_set_tid,
+ sizeof(em->em_tid));
+ LINUX_CTR4(schedtail, "thread(%d) %p stored %d error %d",
+ td->td_tid, child_set_tid, em->em_tid, error);
+ } else
+ LINUX_CTR1(schedtail, "thread(%d)", em->em_tid);
+}
diff --git a/sys/compat/linux/linux_emul.h b/sys/compat/linux/linux_emul.h
new file mode 100644
index 000000000000..de66a7a4c82a
--- /dev/null
+++ b/sys/compat/linux/linux_emul.h
@@ -0,0 +1,82 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2006 Roman Divacky
+ * Copyright (c) 2013 Dmitry Chagin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_EMUL_H_
+#define _LINUX_EMUL_H_
+
+struct image_params;
+
+/*
+ * modeled after similar structure in NetBSD
+ * this will be extended as we need more functionality
+ */
+struct linux_emuldata {
+ int *child_set_tid; /* in clone(): Child's TID to set on clone */
+ int *child_clear_tid;/* in clone(): Child's TID to clear on exit */
+
+ int flags; /* thread emuldata flags */
+ int em_tid; /* thread id */
+
+ struct linux_robust_list_head *robust_futexes;
+};
+
+struct linux_emuldata *em_find(struct thread *);
+
+int linux_exec_imgact_try(struct image_params *);
+void linux_proc_init(struct thread *, struct thread *, int);
+void linux_on_exit(struct proc *);
+void linux_schedtail(struct thread *);
+void linux_on_exec(struct proc *, struct image_params *);
+void linux_thread_dtor(struct thread *);
+void linux_thread_detach(struct thread *);
+int linux_common_execve(struct thread *, struct image_args *);
+
+/* process emuldata flags */
+#define LINUX_XDEPR_REQUEUEOP 0x00000001 /* uses deprecated
+ futex REQUEUE op*/
+#define LINUX_XUNSUP_EPOLL 0x00000002 /* unsupported epoll events */
+#define LINUX_XUNSUP_FUTEXPIOP 0x00000004 /* uses unsupported pi futex */
+
+struct linux_pemuldata {
+ uint32_t flags; /* process emuldata flags */
+ struct sx pem_sx; /* lock for this struct */
+ uint32_t persona; /* process execution domain */
+ uint32_t ptrace_flags; /* used by ptrace(2) */
+};
+
+#define LINUX_PEM_XLOCK(p) sx_xlock(&(p)->pem_sx)
+#define LINUX_PEM_XUNLOCK(p) sx_xunlock(&(p)->pem_sx)
+#define LINUX_PEM_SLOCK(p) sx_slock(&(p)->pem_sx)
+#define LINUX_PEM_SUNLOCK(p) sx_sunlock(&(p)->pem_sx)
+
+struct linux_pemuldata *pem_find(struct proc *);
+
+#endif /* !_LINUX_EMUL_H_ */
diff --git a/sys/compat/linux/linux_errno.c b/sys/compat/linux/linux_errno.c
new file mode 100644
index 000000000000..69880db86319
--- /dev/null
+++ b/sys/compat/linux/linux_errno.c
@@ -0,0 +1,41 @@
+/* $FreeBSD$ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/systm.h>
+
+#include <compat/linux/linux.h>
+#include <compat/linux/linux_errno.h>
+#include <compat/linux/linux_errno.inc>
+
+int
+bsd_to_linux_errno(int error)
+{
+
+ KASSERT(error >= 0 && error <= ELAST,
+ ("%s: bad error %d", __func__, error));
+
+ return (linux_errtbl[error]);
+}
+
+#ifdef INVARIANTS
+void
+linux_check_errtbl(void)
+{
+ int i;
+
+ for (i = 1; i < nitems(linux_errtbl); i++) {
+ KASSERT(linux_errtbl[i] != 0,
+ ("%s: linux_errtbl[%d] == 0", __func__, i));
+ }
+
+ for (i = 1; i < nitems(linux_to_bsd_errtbl); i++) {
+ KASSERT(linux_to_bsd_errtbl[i] != 0,
+ ("%s: linux_to_bsd_errtbl[%d] == 0", __func__, i));
+ }
+
+}
+#endif
diff --git a/sys/compat/linux/linux_errno.h b/sys/compat/linux/linux_errno.h
new file mode 100644
index 000000000000..46e6f46e202b
--- /dev/null
+++ b/sys/compat/linux/linux_errno.h
@@ -0,0 +1,185 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_ERRNO_H_
+#define _LINUX_ERRNO_H_
+
+#define LINUX_EPERM 1
+#define LINUX_ENOENT 2
+#define LINUX_ESRCH 3
+#define LINUX_EINTR 4
+#define LINUX_EIO 5
+#define LINUX_ENXIO 6
+#define LINUX_E2BIG 7
+#define LINUX_ENOEXEC 8
+#define LINUX_EBADF 9
+
+#define LINUX_ECHILD 10
+#define LINUX_EAGAIN 11
+#define LINUX_ENOMEM 12
+#define LINUX_EACCES 13
+#define LINUX_EFAULT 14
+#define LINUX_ENOTBLK 15
+#define LINUX_EBUSY 16
+#define LINUX_EEXIST 17
+#define LINUX_EXDEV 18
+#define LINUX_ENODEV 19
+
+#define LINUX_ENOTDIR 20
+#define LINUX_EISDIR 21
+#define LINUX_EINVAL 22
+#define LINUX_ENFILE 23
+#define LINUX_EMFILE 24
+#define LINUX_ENOTTY 25
+#define LINUX_ETXTBSY 26
+#define LINUX_EFBIG 27
+#define LINUX_ENOSPC 28
+#define LINUX_ESPIPE 29
+
+#define LINUX_EROFS 30
+#define LINUX_EMLINK 31
+#define LINUX_EPIPE 32
+#define LINUX_EDOM 33
+#define LINUX_ERANGE 34
+#define LINUX_EDEADLK 35
+#define LINUX_ENAMETOOLONG 36
+#define LINUX_ENOLCK 37
+#define LINUX_ENOSYS 38
+#define LINUX_ENOTEMPTY 39
+
+#define LINUX_ELOOP 40
+/* XXX: errno 41 is not defined in Linux. */
+#define LINUX_ENOMSG 42
+#define LINUX_EIDRM 43
+#define LINUX_ECHRNG 44
+#define LINUX_EL2NSYNC 45
+#define LINUX_EL3HLT 46
+#define LINUX_EL3RST 47
+#define LINUX_ELNRNG 48
+#define LINUX_EUNATCH 49
+
+#define LINUX_ENOCSI 50
+#define LINUX_EL2HLT 51
+#define LINUX_EBADE 52
+#define LINUX_EBADR 53
+#define LINUX_EXFULL 54
+#define LINUX_ENOANO 55
+#define LINUX_EBADRQC 56
+#define LINUX_EBADSLT 57
+/* XXX: errno 58 is not defined in Linux. */
+#define LINUX_EBFONT 59
+
+#define LINUX_ENOSTR 60
+#define LINUX_ENODATA 61
+#define LINUX_ENOTIME 62
+#define LINUX_ENOSR 63
+#define LINUX_ENONET 64
+#define LINUX_ENOPKG 65
+#define LINUX_EREMOTE 66
+#define LINUX_ENOLINK 67
+#define LINUX_EADV 68
+#define LINUX_ESRMNT 69
+
+#define LINUX_ECOMM 70
+#define LINUX_EPROTO 71
+#define LINUX_EMULTIHOP 72
+#define LINUX_EDOTDOT 73
+#define LINUX_EBADMSG 74
+#define LINUX_EOVERFLOW 75
+#define LINUX_ENOTUNIQ 76
+#define LINUX_EBADFD 77
+#define LINUX_EREMCHG 78
+#define LINUX_ELIBACC 79
+
+#define LINUX_ELIBBAD 80
+#define LINUX_ELIBSCN 81
+#define LINUX_ELIBMAX 82
+#define LINUX_ELIBEXEC 83
+#define LINUX_EILSEQ 84
+#define LINUX_ERESTART 85
+#define LINUX_ESTRPIPE 86
+#define LINUX_EUSERS 87
+#define LINUX_ENOTSOCK 88
+#define LINUX_EDESTADDRREQ 89
+
+#define LINUX_EMSGSIZE 90
+#define LINUX_EPROTOTYPE 91
+#define LINUX_ENOPROTOOPT 92
+#define LINUX_EPROTONOTSUPPORT 93
+#define LINUX_ESOCKNOTSUPPORT 94
+#define LINUX_EOPNOTSUPPORT 95
+#define LINUX_EPFNOTSUPPORT 96
+#define LINUX_EAFNOTSUPPORT 97
+#define LINUX_EADDRINUSE 98
+#define LINUX_EADDRNOTAVAIL 99
+
+#define LINUX_ENETDOWN 100
+#define LINUX_ENETUNREACH 101
+#define LINUX_ENETRESET 102
+#define LINUX_ECONNABORTED 103
+#define LINUX_ECONNRESET 104
+#define LINUX_ENOBUFS 105
+#define LINUX_EISCONN 106
+#define LINUX_ENOTCONN 107
+#define LINUX_ESHUTDOWN 108
+#define LINUX_ETOOMANYREFS 109
+
+#define LINUX_ETIMEDOUT 110
+#define LINUX_ECONNREFUSED 111
+#define LINUX_EHOSTDOWN 112
+#define LINUX_EHOSTUNREACH 113
+#define LINUX_EALREADY 114
+#define LINUX_EINPROGRESS 115
+#define LINUX_ESTALE 116
+#define LINUX_EUCLEAN 117
+#define LINUX_ENOTNAM 118
+#define LINUX_ENAVAIL 119
+
+#define LINUX_EISNAM 120
+#define LINUX_EREMOTEIO 121
+#define LINUX_EDQUOT 122
+#define LINUX_ENOMEDIUM 123
+#define LINUX_EMEDIUMTYPE 124
+#define LINUX_ECANCELED 125
+#define LINUX_ENOKEY 126
+#define LINUX_EKEYEXPIRED 127
+#define LINUX_EKEYREVOKED 128
+#define LINUX_EKEYREJECTED 129
+
+#define LINUX_EOWNERDEAD 130
+#define LINUX_ENOTRECOVERABLE 131
+#define LINUX_ERFKILL 132
+#define LINUX_EHWPOISON 133
+
+#define LINUX_ELAST LINUX_EHWPOISON
+
+#endif /* _LINUX_ERRNO_H_ */
diff --git a/sys/compat/linux/linux_errno.inc b/sys/compat/linux/linux_errno.inc
new file mode 100644
index 000000000000..37d83962fe44
--- /dev/null
+++ b/sys/compat/linux/linux_errno.inc
@@ -0,0 +1,329 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1994-1996 Søren Schmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Linux syscalls return negative errno's, we do positive and map them
+ * Reference:
+ * FreeBSD: src/sys/sys/errno.h
+ * Linux: include/uapi/asm-generic/errno-base.h
+ * include/uapi/asm-generic/errno.h
+ *
+ * XXX: The "XXX" comments below should be replaced with rationale
+ * for the errno value chosen.
+ */
+static const int linux_errtbl[ELAST + 1] = {
+ /* [0, 9] */
+ [0] = -0,
+ [EPERM] = -LINUX_EPERM,
+ [ENOENT] = -LINUX_ENOENT,
+ [ESRCH] = -LINUX_ESRCH,
+ [EINTR] = -LINUX_EINTR,
+ [EIO] = -LINUX_EIO,
+ [ENXIO] = -LINUX_ENXIO,
+ [E2BIG] = -LINUX_E2BIG,
+ [ENOEXEC] = -LINUX_ENOEXEC,
+ [EBADF] = -LINUX_EBADF,
+
+ /* [10, 19] */
+ [ECHILD] = -LINUX_ECHILD,
+ [EDEADLK] = -LINUX_EDEADLK,
+ [ENOMEM] = -LINUX_ENOMEM,
+ [EACCES] = -LINUX_EACCES,
+ [EFAULT] = -LINUX_EFAULT,
+ [ENOTBLK] = -LINUX_ENOTBLK,
+ [EBUSY] = -LINUX_EBUSY,
+ [EEXIST] = -LINUX_EEXIST,
+ [EXDEV] = -LINUX_EXDEV,
+ [ENODEV] = -LINUX_ENODEV,
+
+ /* [20, 29] */
+ [ENOTDIR] = -LINUX_ENOTDIR,
+ [EISDIR] = -LINUX_EISDIR,
+ [EINVAL] = -LINUX_EINVAL,
+ [ENFILE] = -LINUX_ENFILE,
+ [EMFILE] = -LINUX_EMFILE,
+ [ENOTTY] = -LINUX_ENOTTY,
+ [ETXTBSY] = -LINUX_ETXTBSY,
+ [EFBIG] = -LINUX_EFBIG,
+ [ENOSPC] = -LINUX_ENOSPC,
+ [ESPIPE] = -LINUX_ESPIPE,
+
+ /* [30, 39] */
+ [EROFS] = -LINUX_EROFS,
+ [EMLINK] = -LINUX_EMLINK,
+ [EPIPE] = -LINUX_EPIPE,
+ [EDOM] = -LINUX_EDOM,
+ [ERANGE] = -LINUX_ERANGE,
+ [EAGAIN] = -LINUX_EAGAIN,
+ [EINPROGRESS] = -LINUX_EINPROGRESS,
+ [EALREADY] = -LINUX_EALREADY,
+ [ENOTSOCK] = -LINUX_ENOTSOCK,
+ [EDESTADDRREQ] = -LINUX_EDESTADDRREQ,
+
+ /* [40, 49] */
+ [EMSGSIZE] = -LINUX_EMSGSIZE,
+ [EPROTOTYPE] = -LINUX_EPROTOTYPE,
+ [ENOPROTOOPT] = -LINUX_ENOPROTOOPT,
+ [EPROTONOSUPPORT] = -LINUX_EPROTONOTSUPPORT,
+ [ESOCKTNOSUPPORT] = -LINUX_ESOCKNOTSUPPORT,
+ [EOPNOTSUPP] = -LINUX_EOPNOTSUPPORT,
+ [EPFNOSUPPORT] = -LINUX_EPFNOTSUPPORT,
+ [EAFNOSUPPORT] = -LINUX_EAFNOTSUPPORT,
+ [EADDRINUSE] = -LINUX_EADDRINUSE,
+ [EADDRNOTAVAIL] = -LINUX_EADDRNOTAVAIL,
+
+ /* [50, 59] */
+ [ENETDOWN] = -LINUX_ENETDOWN,
+ [ENETUNREACH] = -LINUX_ENETUNREACH,
+ [ENETRESET] = -LINUX_ENETRESET,
+ [ECONNABORTED] = -LINUX_ECONNABORTED,
+ [ECONNRESET] = -LINUX_ECONNRESET,
+ [ENOBUFS] = -LINUX_ENOBUFS,
+ [EISCONN] = -LINUX_EISCONN,
+ [ENOTCONN] = -LINUX_ENOTCONN,
+ [ESHUTDOWN] = -LINUX_ESHUTDOWN,
+ [ETOOMANYREFS] = -LINUX_ETOOMANYREFS,
+
+ /* [60, 69] */
+ [ETIMEDOUT] = -LINUX_ETIMEDOUT,
+ [ECONNREFUSED] = -LINUX_ECONNREFUSED,
+ [ELOOP] = -LINUX_ELOOP,
+ [ENAMETOOLONG] = -LINUX_ENAMETOOLONG,
+ [EHOSTDOWN] = -LINUX_EHOSTDOWN,
+ [EHOSTUNREACH] = -LINUX_EHOSTUNREACH,
+ [ENOTEMPTY] = -LINUX_ENOTEMPTY,
+ [EPROCLIM] = -LINUX_EAGAIN, /* XXX */
+ [EUSERS] = -LINUX_EUSERS,
+ [EDQUOT] = -LINUX_EDQUOT,
+
+ /* [70, 79] */
+ [ESTALE] = -LINUX_ESTALE,
+ [EREMOTE] = -LINUX_EREMOTE,
+ [EBADRPC] = -LINUX_ENXIO, /* XXX */
+ [ERPCMISMATCH] = -LINUX_ENXIO, /* XXX */
+ [EPROGUNAVAIL] = -LINUX_ENXIO, /* XXX */
+ [EPROGMISMATCH] = -LINUX_ENXIO, /* XXX */
+ [EPROCUNAVAIL] = -LINUX_ENXIO, /* XXX */
+ [ENOLCK] = -LINUX_ENOLCK,
+ [ENOSYS] = -LINUX_ENOSYS,
+ [EFTYPE] = -LINUX_EBADF, /* XXX */
+
+ /* [80, 89] */
+ [EAUTH] = -LINUX_ENXIO, /* XXX */
+ [ENEEDAUTH] = -LINUX_ENXIO, /* XXX */
+ [EIDRM] = -LINUX_EIDRM,
+ [ENOMSG] = -LINUX_ENOMSG,
+ [EOVERFLOW] = -LINUX_EOVERFLOW,
+ [ECANCELED] = -LINUX_ECANCELED,
+ [EILSEQ] = -LINUX_EILSEQ,
+ [ENOATTR] = -LINUX_ENODATA, /* XXX */
+ [EDOOFUS] = -LINUX_EINVAL, /* XXX */
+ [EBADMSG] = -LINUX_EBADMSG,
+
+ /* [90, 99] */
+ [EMULTIHOP] = -LINUX_EMULTIHOP,
+ [ENOLINK] = -LINUX_ENOLINK,
+ [EPROTO] = -LINUX_EPROTO,
+ [ENOTCAPABLE] = -LINUX_EPERM, /* XXX */
+ [ECAPMODE] = -LINUX_EPERM, /* XXX */
+ [ENOTRECOVERABLE] = -LINUX_ENOTRECOVERABLE,
+ [EOWNERDEAD] = -LINUX_EOWNERDEAD,
+ [EINTEGRITY] = -LINUX_EINVAL, /* XXX */
+};
+
+_Static_assert(ELAST == 97,
+ "missing errno entries in linux_errtbl");
+
+static const int linux_to_bsd_errtbl[LINUX_ELAST + 1] = {
+ /* [0, 9] */
+ [0] = 0,
+ [LINUX_EPERM] = EPERM,
+ [LINUX_ENOENT] = ENOENT,
+ [LINUX_ESRCH] = ESRCH,
+ [LINUX_EINTR] = EINTR,
+ [LINUX_EIO] = EIO,
+ [LINUX_ENXIO] = ENXIO,
+ [LINUX_E2BIG] = E2BIG,
+ [LINUX_ENOEXEC] = ENOENT,
+ [LINUX_EBADF] = EBADF,
+
+ /* [10, 19] */
+ [LINUX_ECHILD] = ECHILD,
+ [LINUX_EAGAIN] = EAGAIN,
+ [LINUX_ENOMEM] = ENOMEM,
+ [LINUX_EACCES] = EACCES,
+ [LINUX_EFAULT] = EFAULT,
+ [LINUX_ENOTBLK] = ENOTBLK,
+ [LINUX_EBUSY] = EBUSY,
+ [LINUX_EEXIST] = EEXIST,
+ [LINUX_EXDEV] = EXDEV,
+ [LINUX_ENODEV] = ENODEV,
+
+ /* [20, 29] */
+ [LINUX_ENOTDIR] = ENOTDIR,
+ [LINUX_EISDIR] = EISDIR,
+ [LINUX_EINVAL] = EINVAL,
+ [LINUX_ENFILE] = ENFILE,
+ [LINUX_EMFILE] = EMFILE,
+ [LINUX_ENOTTY] = ENOTTY,
+ [LINUX_ETXTBSY] = ETXTBSY,
+ [LINUX_EFBIG] = EFBIG,
+ [LINUX_ENOSPC] = ENOSPC,
+ [LINUX_ESPIPE] = ESPIPE,
+
+ /* [30, 39] */
+ [LINUX_EROFS] = EROFS,
+ [LINUX_EMLINK] = EMLINK,
+ [LINUX_EPIPE] = EPIPE,
+ [LINUX_EDOM] = EDOM,
+ [LINUX_ERANGE] = ERANGE,
+ [LINUX_EDEADLK] = EDEADLK,
+ [LINUX_ENAMETOOLONG] = ENAMETOOLONG,
+ [LINUX_ENOLCK] = ENOLCK,
+ [LINUX_ENOSYS] = ENOSYS,
+ [LINUX_ENOTEMPTY] = ENOTEMPTY,
+
+ /* [40, 49] */
+ [LINUX_ELOOP] = ELOOP,
+ [41] = EINVAL,
+ [LINUX_ENOMSG] = ENOMSG,
+ [LINUX_EIDRM] = EIDRM,
+ [LINUX_ECHRNG] = EINVAL, /* XXX */
+ [LINUX_EL2NSYNC] = EINVAL, /* XXX */
+ [LINUX_EL3HLT] = EINVAL, /* XXX */
+ [LINUX_EL3RST] = EINVAL, /* XXX */
+ [LINUX_ELNRNG] = EINVAL, /* XXX */
+ [LINUX_EUNATCH] = EINVAL, /* XXX */
+
+ /* [50, 59] */
+ [LINUX_ENOCSI] = EINVAL, /* XXX */
+ [LINUX_EL2HLT] = EINVAL, /* XXX */
+ [LINUX_EBADE] = EINVAL, /* XXX */
+ [LINUX_EBADR] = EINVAL, /* XXX */
+ [LINUX_EXFULL] = EINVAL, /* XXX */
+ [LINUX_ENOANO] = EINVAL, /* XXX */
+ [LINUX_EBADRQC] = EINVAL, /* XXX */
+ [LINUX_EBADSLT] = EINVAL, /* XXX */
+ [58] = EINVAL,
+ [LINUX_EBFONT] = EINVAL, /* XXX */
+
+ /* [60, 69] */
+ [LINUX_ENOSTR] = EINVAL, /* XXX */
+ [LINUX_ENODATA] = ENOATTR, /* XXX */
+ [LINUX_ENOTIME] = EINVAL, /* XXX */
+ [LINUX_ENOSR] = EINVAL, /* XXX */
+ [LINUX_ENONET] = EINVAL, /* XXX */
+ [LINUX_ENOPKG] = EINVAL, /* XXX */
+ [LINUX_EREMOTE] = EREMOTE,
+ [LINUX_ENOLINK] = ENOLINK,
+ [LINUX_EADV] = EINVAL, /* XXX */
+ [LINUX_ESRMNT] = EINVAL, /* XXX */
+
+ /* [70, 79] */
+ [LINUX_ECOMM] = EINVAL, /* XXX */
+ [LINUX_EPROTO] = EPROTO,
+ [LINUX_EMULTIHOP] = EMULTIHOP,
+ [LINUX_EDOTDOT] = EINVAL, /* XXX */
+ [LINUX_EBADMSG] = EBADMSG,
+ [LINUX_EOVERFLOW] = EOVERFLOW,
+ [LINUX_ENOTUNIQ] = EINVAL, /* XXX */
+ [LINUX_EBADFD] = EBADF, /* XXX */
+ [LINUX_EREMCHG] = EINVAL, /* XXX */
+ [LINUX_ELIBACC] = EINVAL, /* XXX */
+
+ /* [80, 89] */
+ [LINUX_ELIBBAD] = EINVAL, /* XXX */
+ [LINUX_ELIBSCN] = EINVAL, /* XXX */
+ [LINUX_ELIBMAX] = EINVAL, /* XXX */
+ [LINUX_ELIBEXEC] = EINVAL, /* XXX */
+ [LINUX_EILSEQ] = EILSEQ,
+ [LINUX_ERESTART] = EAGAIN, /* XXX */
+ [LINUX_ESTRPIPE] = EINVAL, /* XXX */
+ [LINUX_EUSERS] = EUSERS,
+ [LINUX_ENOTSOCK] = ENOTSOCK,
+ [LINUX_EDESTADDRREQ] = EDESTADDRREQ,
+
+ /* [90, 99] */
+ [LINUX_EMSGSIZE] = EMSGSIZE,
+ [LINUX_EPROTOTYPE] = EPROTOTYPE,
+ [LINUX_ENOPROTOOPT] = ENOPROTOOPT,
+ [LINUX_EPROTONOTSUPPORT] = EPROTONOSUPPORT,
+ [LINUX_ESOCKNOTSUPPORT] = EPROTONOSUPPORT, /* XXX */
+ [LINUX_EOPNOTSUPPORT] = EOPNOTSUPP,
+ [LINUX_EPFNOTSUPPORT] = EPFNOSUPPORT,
+ [LINUX_EAFNOTSUPPORT] = EAFNOSUPPORT,
+ [LINUX_EADDRINUSE] = EADDRINUSE,
+ [LINUX_EADDRNOTAVAIL] = EADDRNOTAVAIL,
+
+ /* [100, 109] */
+ [LINUX_ENETDOWN] = ENETDOWN,
+ [LINUX_ENETUNREACH] = ENETUNREACH,
+ [LINUX_ENETRESET] = ENETRESET,
+ [LINUX_ECONNABORTED] = ECONNABORTED,
+ [LINUX_ECONNRESET] = ECONNRESET,
+ [LINUX_ENOBUFS] = ENOBUFS,
+ [LINUX_EISCONN] = EISCONN,
+ [LINUX_ENOTCONN] = ENOTCONN,
+ [LINUX_ESHUTDOWN] = ESHUTDOWN,
+ [LINUX_ETOOMANYREFS] = ETOOMANYREFS,
+
+ /* [110, 119] */
+ [LINUX_ETIMEDOUT] = ETIMEDOUT,
+ [LINUX_ECONNREFUSED] = ECONNREFUSED,
+ [LINUX_EHOSTDOWN] = EHOSTDOWN,
+ [LINUX_EHOSTUNREACH] = EHOSTUNREACH,
+ [LINUX_EALREADY] = EALREADY,
+ [LINUX_EINPROGRESS] = EINPROGRESS,
+ [LINUX_ESTALE] = ESTALE,
+ [LINUX_EUCLEAN] = EINVAL, /* XXX */
+ [LINUX_ENOTNAM] = EINVAL, /* XXX */
+ [LINUX_ENAVAIL] = EINVAL, /* XXX */
+
+ /* [120, 129] */
+ [LINUX_EISNAM] = EINVAL, /* XXX */
+ [LINUX_EREMOTEIO] = EINVAL, /* XXX */
+ [LINUX_EDQUOT] = EDQUOT,
+ [LINUX_ENOMEDIUM] = EIO, /* XXX */
+ [LINUX_EMEDIUMTYPE] = EIO, /* XXX */
+ [LINUX_ECANCELED] = ECANCELED,
+ [LINUX_ENOKEY] = EIO, /* XXX */
+ [LINUX_EKEYEXPIRED] = EIO, /* XXX */
+ [LINUX_EKEYREVOKED] = EIO, /* XXX */
+ [LINUX_EKEYREJECTED] = EIO, /* XXX */
+
+ /* [130, 139] */
+ [LINUX_EOWNERDEAD] = EOWNERDEAD,
+ [LINUX_ENOTRECOVERABLE] = ENOTRECOVERABLE,
+ [LINUX_ERFKILL] = ENETDOWN, /* XXX */
+ [LINUX_EHWPOISON] = EINVAL, /* XXX */
+};
+
+_Static_assert(LINUX_ELAST == 133,
+ "missing errno entries in linux_to_bsd_errtbl");
diff --git a/sys/compat/linux/linux_event.c b/sys/compat/linux/linux_event.c
new file mode 100644
index 000000000000..991af1b539e4
--- /dev/null
+++ b/sys/compat/linux/linux_event.c
@@ -0,0 +1,981 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2007 Roman Divacky
+ * Copyright (c) 2014 Dmitry Chagin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_compat.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/imgact.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/callout.h>
+#include <sys/capsicum.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/filio.h>
+#include <sys/errno.h>
+#include <sys/event.h>
+#include <sys/poll.h>
+#include <sys/proc.h>
+#include <sys/selinfo.h>
+#include <sys/specialfd.h>
+#include <sys/sx.h>
+#include <sys/syscallsubr.h>
+#include <sys/timespec.h>
+#include <sys/eventfd.h>
+
+#ifdef COMPAT_LINUX32
+#include <machine/../linux32/linux.h>
+#include <machine/../linux32/linux32_proto.h>
+#else
+#include <machine/../linux/linux.h>
+#include <machine/../linux/linux_proto.h>
+#endif
+
+#include <compat/linux/linux_emul.h>
+#include <compat/linux/linux_event.h>
+#include <compat/linux/linux_file.h>
+#include <compat/linux/linux_timer.h>
+#include <compat/linux/linux_util.h>
+
+typedef uint64_t epoll_udata_t;
+
+struct epoll_event {
+ uint32_t events;
+ epoll_udata_t data;
+}
+#if defined(__amd64__)
+__attribute__((packed))
+#endif
+;
+
+#define LINUX_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
+
+static int epoll_to_kevent(struct thread *td, int fd,
+ struct epoll_event *l_event, struct kevent *kevent,
+ int *nkevents);
+static void kevent_to_epoll(struct kevent *kevent, struct epoll_event *l_event);
+static int epoll_kev_copyout(void *arg, struct kevent *kevp, int count);
+static int epoll_kev_copyin(void *arg, struct kevent *kevp, int count);
+static int epoll_register_kevent(struct thread *td, struct file *epfp,
+ int fd, int filter, unsigned int flags);
+static int epoll_fd_registered(struct thread *td, struct file *epfp,
+ int fd);
+static int epoll_delete_all_events(struct thread *td, struct file *epfp,
+ int fd);
+
+struct epoll_copyin_args {
+ struct kevent *changelist;
+};
+
+struct epoll_copyout_args {
+ struct epoll_event *leventlist;
+ struct proc *p;
+ uint32_t count;
+ int error;
+};
+
+/* timerfd */
+typedef uint64_t timerfd_t;
+
+static fo_rdwr_t timerfd_read;
+static fo_ioctl_t timerfd_ioctl;
+static fo_poll_t timerfd_poll;
+static fo_kqfilter_t timerfd_kqfilter;
+static fo_stat_t timerfd_stat;
+static fo_close_t timerfd_close;
+static fo_fill_kinfo_t timerfd_fill_kinfo;
+
+static struct fileops timerfdops = {
+ .fo_read = timerfd_read,
+ .fo_write = invfo_rdwr,
+ .fo_truncate = invfo_truncate,
+ .fo_ioctl = timerfd_ioctl,
+ .fo_poll = timerfd_poll,
+ .fo_kqfilter = timerfd_kqfilter,
+ .fo_stat = timerfd_stat,
+ .fo_close = timerfd_close,
+ .fo_chmod = invfo_chmod,
+ .fo_chown = invfo_chown,
+ .fo_sendfile = invfo_sendfile,
+ .fo_fill_kinfo = timerfd_fill_kinfo,
+ .fo_flags = DFLAG_PASSABLE
+};
+
+static void filt_timerfddetach(struct knote *kn);
+static int filt_timerfdread(struct knote *kn, long hint);
+
+static struct filterops timerfd_rfiltops = {
+ .f_isfd = 1,
+ .f_detach = filt_timerfddetach,
+ .f_event = filt_timerfdread
+};
+
+struct timerfd {
+ clockid_t tfd_clockid;
+ struct itimerspec tfd_time;
+ struct callout tfd_callout;
+ timerfd_t tfd_count;
+ bool tfd_canceled;
+ struct selinfo tfd_sel;
+ struct mtx tfd_lock;
+};
+
+static void linux_timerfd_expire(void *);
+static void linux_timerfd_curval(struct timerfd *, struct itimerspec *);
+
+static int
+epoll_create_common(struct thread *td, int flags)
+{
+
+ return (kern_kqueue(td, flags, NULL));
+}
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_epoll_create(struct thread *td, struct linux_epoll_create_args *args)
+{
+
+ /*
+ * args->size is unused. Linux just tests it
+ * and then forgets it as well.
+ */
+ if (args->size <= 0)
+ return (EINVAL);
+
+ return (epoll_create_common(td, 0));
+}
+#endif
+
+int
+linux_epoll_create1(struct thread *td, struct linux_epoll_create1_args *args)
+{
+ int flags;
+
+ if ((args->flags & ~(LINUX_O_CLOEXEC)) != 0)
+ return (EINVAL);
+
+ flags = 0;
+ if ((args->flags & LINUX_O_CLOEXEC) != 0)
+ flags |= O_CLOEXEC;
+
+ return (epoll_create_common(td, flags));
+}
+
+/* Structure converting function from epoll to kevent. */
+static int
+epoll_to_kevent(struct thread *td, int fd, struct epoll_event *l_event,
+ struct kevent *kevent, int *nkevents)
+{
+ uint32_t levents = l_event->events;
+ struct linux_pemuldata *pem;
+ struct proc *p;
+ unsigned short kev_flags = EV_ADD | EV_ENABLE;
+
+ /* flags related to how event is registered */
+ if ((levents & LINUX_EPOLLONESHOT) != 0)
+ kev_flags |= EV_DISPATCH;
+ if ((levents & LINUX_EPOLLET) != 0)
+ kev_flags |= EV_CLEAR;
+ if ((levents & LINUX_EPOLLERR) != 0)
+ kev_flags |= EV_ERROR;
+ if ((levents & LINUX_EPOLLRDHUP) != 0)
+ kev_flags |= EV_EOF;
+
+ /* flags related to what event is registered */
+ if ((levents & LINUX_EPOLL_EVRD) != 0) {
+ EV_SET(kevent, fd, EVFILT_READ, kev_flags, 0, 0, 0);
+ kevent->ext[0] = l_event->data;
+ ++kevent;
+ ++(*nkevents);
+ }
+ if ((levents & LINUX_EPOLL_EVWR) != 0) {
+ EV_SET(kevent, fd, EVFILT_WRITE, kev_flags, 0, 0, 0);
+ kevent->ext[0] = l_event->data;
+ ++kevent;
+ ++(*nkevents);
+ }
+ /* zero event mask is legal */
+ if ((levents & (LINUX_EPOLL_EVRD | LINUX_EPOLL_EVWR)) == 0) {
+ EV_SET(kevent++, fd, EVFILT_READ, EV_ADD|EV_DISABLE, 0, 0, 0);
+ ++(*nkevents);
+ }
+
+ if ((levents & ~(LINUX_EPOLL_EVSUP)) != 0) {
+ p = td->td_proc;
+
+ pem = pem_find(p);
+ KASSERT(pem != NULL, ("epoll proc emuldata not found.\n"));
+
+ LINUX_PEM_XLOCK(pem);
+ if ((pem->flags & LINUX_XUNSUP_EPOLL) == 0) {
+ pem->flags |= LINUX_XUNSUP_EPOLL;
+ LINUX_PEM_XUNLOCK(pem);
+ linux_msg(td, "epoll_ctl unsupported flags: 0x%x",
+ levents);
+ } else
+ LINUX_PEM_XUNLOCK(pem);
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+/*
+ * Structure converting function from kevent to epoll. In a case
+ * this is called on error in registration we store the error in
+ * event->data and pick it up later in linux_epoll_ctl().
+ */
+static void
+kevent_to_epoll(struct kevent *kevent, struct epoll_event *l_event)
+{
+
+ l_event->data = kevent->ext[0];
+
+ if ((kevent->flags & EV_ERROR) != 0) {
+ l_event->events = LINUX_EPOLLERR;
+ return;
+ }
+
+ /* XXX EPOLLPRI, EPOLLHUP */
+ switch (kevent->filter) {
+ case EVFILT_READ:
+ l_event->events = LINUX_EPOLLIN;
+ if ((kevent->flags & EV_EOF) != 0)
+ l_event->events |= LINUX_EPOLLRDHUP;
+ break;
+ case EVFILT_WRITE:
+ l_event->events = LINUX_EPOLLOUT;
+ break;
+ }
+}
+
+/*
+ * Copyout callback used by kevent. This converts kevent
+ * events to epoll events and copies them back to the
+ * userspace. This is also called on error on registering
+ * of the filter.
+ */
+static int
+epoll_kev_copyout(void *arg, struct kevent *kevp, int count)
+{
+ struct epoll_copyout_args *args;
+ struct epoll_event *eep;
+ int error, i;
+
+ args = (struct epoll_copyout_args*) arg;
+ eep = malloc(sizeof(*eep) * count, M_EPOLL, M_WAITOK | M_ZERO);
+
+ for (i = 0; i < count; i++)
+ kevent_to_epoll(&kevp[i], &eep[i]);
+
+ error = copyout(eep, args->leventlist, count * sizeof(*eep));
+ if (error == 0) {
+ args->leventlist += count;
+ args->count += count;
+ } else if (args->error == 0)
+ args->error = error;
+
+ free(eep, M_EPOLL);
+ return (error);
+}
+
+/*
+ * Copyin callback used by kevent. This copies already
+ * converted filters from kernel memory to the kevent
+ * internal kernel memory. Hence the memcpy instead of
+ * copyin.
+ */
+static int
+epoll_kev_copyin(void *arg, struct kevent *kevp, int count)
+{
+ struct epoll_copyin_args *args;
+
+ args = (struct epoll_copyin_args*) arg;
+
+ memcpy(kevp, args->changelist, count * sizeof(*kevp));
+ args->changelist += count;
+
+ return (0);
+}
+
+/*
+ * Load epoll filter, convert it to kevent filter
+ * and load it into kevent subsystem.
+ */
+int
+linux_epoll_ctl(struct thread *td, struct linux_epoll_ctl_args *args)
+{
+ struct file *epfp, *fp;
+ struct epoll_copyin_args ciargs;
+ struct kevent kev[2];
+ struct kevent_copyops k_ops = { &ciargs,
+ NULL,
+ epoll_kev_copyin};
+ struct epoll_event le;
+ cap_rights_t rights;
+ int nchanges = 0;
+ int error;
+
+ if (args->op != LINUX_EPOLL_CTL_DEL) {
+ error = copyin(args->event, &le, sizeof(le));
+ if (error != 0)
+ return (error);
+ }
+
+ error = fget(td, args->epfd,
+ cap_rights_init_one(&rights, CAP_KQUEUE_CHANGE), &epfp);
+ if (error != 0)
+ return (error);
+ if (epfp->f_type != DTYPE_KQUEUE) {
+ error = EINVAL;
+ goto leave1;
+ }
+
+ /* Protect user data vector from incorrectly supplied fd. */
+ error = fget(td, args->fd,
+ cap_rights_init_one(&rights, CAP_POLL_EVENT), &fp);
+ if (error != 0)
+ goto leave1;
+
+ /* Linux disallows spying on himself */
+ if (epfp == fp) {
+ error = EINVAL;
+ goto leave0;
+ }
+
+ ciargs.changelist = kev;
+
+ if (args->op != LINUX_EPOLL_CTL_DEL) {
+ error = epoll_to_kevent(td, args->fd, &le, kev, &nchanges);
+ if (error != 0)
+ goto leave0;
+ }
+
+ switch (args->op) {
+ case LINUX_EPOLL_CTL_MOD:
+ error = epoll_delete_all_events(td, epfp, args->fd);
+ if (error != 0)
+ goto leave0;
+ break;
+
+ case LINUX_EPOLL_CTL_ADD:
+ if (epoll_fd_registered(td, epfp, args->fd)) {
+ error = EEXIST;
+ goto leave0;
+ }
+ break;
+
+ case LINUX_EPOLL_CTL_DEL:
+ /* CTL_DEL means unregister this fd with this epoll */
+ error = epoll_delete_all_events(td, epfp, args->fd);
+ goto leave0;
+
+ default:
+ error = EINVAL;
+ goto leave0;
+ }
+
+ error = kern_kevent_fp(td, epfp, nchanges, 0, &k_ops, NULL);
+
+leave0:
+ fdrop(fp, td);
+
+leave1:
+ fdrop(epfp, td);
+ return (error);
+}
+
+/*
+ * Wait for a filter to be triggered on the epoll file descriptor.
+ */
+static int
+linux_epoll_wait_common(struct thread *td, int epfd, struct epoll_event *events,
+ int maxevents, int timeout, sigset_t *uset)
+{
+ struct epoll_copyout_args coargs;
+ struct kevent_copyops k_ops = { &coargs,
+ epoll_kev_copyout,
+ NULL};
+ struct timespec ts, *tsp;
+ cap_rights_t rights;
+ struct file *epfp;
+ sigset_t omask;
+ int error;
+
+ if (maxevents <= 0 || maxevents > LINUX_MAX_EVENTS)
+ return (EINVAL);
+
+ error = fget(td, epfd,
+ cap_rights_init_one(&rights, CAP_KQUEUE_EVENT), &epfp);
+ if (error != 0)
+ return (error);
+ if (epfp->f_type != DTYPE_KQUEUE) {
+ error = EINVAL;
+ goto leave;
+ }
+ if (uset != NULL) {
+ error = kern_sigprocmask(td, SIG_SETMASK, uset,
+ &omask, 0);
+ if (error != 0)
+ goto leave;
+ td->td_pflags |= TDP_OLDMASK;
+ /*
+ * Make sure that ast() is called on return to
+ * usermode and TDP_OLDMASK is cleared, restoring old
+ * sigmask.
+ */
+ thread_lock(td);
+ td->td_flags |= TDF_ASTPENDING;
+ thread_unlock(td);
+ }
+
+ coargs.leventlist = events;
+ coargs.p = td->td_proc;
+ coargs.count = 0;
+ coargs.error = 0;
+
+ /*
+ * Linux epoll_wait(2) man page states that timeout of -1 causes caller
+ * to block indefinitely. Real implementation does it if any negative
+ * timeout value is passed.
+ */
+ if (timeout >= 0) {
+ /* Convert from milliseconds to timespec. */
+ ts.tv_sec = timeout / 1000;
+ ts.tv_nsec = (timeout % 1000) * 1000000;
+ tsp = &ts;
+ } else {
+ tsp = NULL;
+ }
+
+ error = kern_kevent_fp(td, epfp, 0, maxevents, &k_ops, tsp);
+ if (error == 0 && coargs.error != 0)
+ error = coargs.error;
+
+ /*
+ * kern_kevent might return ENOMEM which is not expected from epoll_wait.
+ * Maybe we should translate that but I don't think it matters at all.
+ */
+ if (error == 0)
+ td->td_retval[0] = coargs.count;
+
+ if (uset != NULL)
+ error = kern_sigprocmask(td, SIG_SETMASK, &omask,
+ NULL, 0);
+leave:
+ fdrop(epfp, td);
+ return (error);
+}
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_epoll_wait(struct thread *td, struct linux_epoll_wait_args *args)
+{
+
+ return (linux_epoll_wait_common(td, args->epfd, args->events,
+ args->maxevents, args->timeout, NULL));
+}
+#endif
+
+int
+linux_epoll_pwait(struct thread *td, struct linux_epoll_pwait_args *args)
+{
+ sigset_t mask, *pmask;
+ l_sigset_t lmask;
+ int error;
+
+ if (args->mask != NULL) {
+ if (args->sigsetsize != sizeof(l_sigset_t))
+ return (EINVAL);
+ error = copyin(args->mask, &lmask, sizeof(l_sigset_t));
+ if (error != 0)
+ return (error);
+ linux_to_bsd_sigset(&lmask, &mask);
+ pmask = &mask;
+ } else
+ pmask = NULL;
+ return (linux_epoll_wait_common(td, args->epfd, args->events,
+ args->maxevents, args->timeout, pmask));
+}
+
+static int
+epoll_register_kevent(struct thread *td, struct file *epfp, int fd, int filter,
+ unsigned int flags)
+{
+ struct epoll_copyin_args ciargs;
+ struct kevent kev;
+ struct kevent_copyops k_ops = { &ciargs,
+ NULL,
+ epoll_kev_copyin};
+
+ ciargs.changelist = &kev;
+ EV_SET(&kev, fd, filter, flags, 0, 0, 0);
+
+ return (kern_kevent_fp(td, epfp, 1, 0, &k_ops, NULL));
+}
+
+static int
+epoll_fd_registered(struct thread *td, struct file *epfp, int fd)
+{
+ /*
+ * Set empty filter flags to avoid accidental modification of already
+ * registered events. In the case of event re-registration:
+ * 1. If event does not exists kevent() does nothing and returns ENOENT
+ * 2. If event does exists, it's enabled/disabled state is preserved
+ * but fflags, data and udata fields are overwritten. So we can not
+ * set socket lowats and store user's context pointer in udata.
+ */
+ if (epoll_register_kevent(td, epfp, fd, EVFILT_READ, 0) != ENOENT ||
+ epoll_register_kevent(td, epfp, fd, EVFILT_WRITE, 0) != ENOENT)
+ return (1);
+
+ return (0);
+}
+
+static int
+epoll_delete_all_events(struct thread *td, struct file *epfp, int fd)
+{
+ int error1, error2;
+
+ error1 = epoll_register_kevent(td, epfp, fd, EVFILT_READ, EV_DELETE);
+ error2 = epoll_register_kevent(td, epfp, fd, EVFILT_WRITE, EV_DELETE);
+
+ /* return 0 if at least one result positive */
+ return (error1 == 0 ? 0 : error2);
+}
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_eventfd(struct thread *td, struct linux_eventfd_args *args)
+{
+ struct specialfd_eventfd ae;
+
+ bzero(&ae, sizeof(ae));
+ ae.initval = args->initval;
+ return (kern_specialfd(td, SPECIALFD_EVENTFD, &ae));
+}
+#endif
+
+int
+linux_eventfd2(struct thread *td, struct linux_eventfd2_args *args)
+{
+ struct specialfd_eventfd ae;
+ int flags;
+
+ if ((args->flags & ~(LINUX_O_CLOEXEC | LINUX_O_NONBLOCK |
+ LINUX_EFD_SEMAPHORE)) != 0)
+ return (EINVAL);
+ flags = 0;
+ if ((args->flags & LINUX_O_CLOEXEC) != 0)
+ flags |= EFD_CLOEXEC;
+ if ((args->flags & LINUX_O_NONBLOCK) != 0)
+ flags |= EFD_NONBLOCK;
+ if ((args->flags & LINUX_EFD_SEMAPHORE) != 0)
+ flags |= EFD_SEMAPHORE;
+
+ bzero(&ae, sizeof(ae));
+ ae.flags = flags;
+ ae.initval = args->initval;
+ return (kern_specialfd(td, SPECIALFD_EVENTFD, &ae));
+}
+
+int
+linux_timerfd_create(struct thread *td, struct linux_timerfd_create_args *args)
+{
+ struct filedesc *fdp;
+ struct timerfd *tfd;
+ struct file *fp;
+ clockid_t clockid;
+ int fflags, fd, error;
+
+ if ((args->flags & ~LINUX_TFD_CREATE_FLAGS) != 0)
+ return (EINVAL);
+
+ error = linux_to_native_clockid(&clockid, args->clockid);
+ if (error != 0)
+ return (error);
+ if (clockid != CLOCK_REALTIME && clockid != CLOCK_MONOTONIC)
+ return (EINVAL);
+
+ fflags = 0;
+ if ((args->flags & LINUX_TFD_CLOEXEC) != 0)
+ fflags |= O_CLOEXEC;
+
+ fdp = td->td_proc->p_fd;
+ error = falloc(td, &fp, &fd, fflags);
+ if (error != 0)
+ return (error);
+
+ tfd = malloc(sizeof(*tfd), M_EPOLL, M_WAITOK | M_ZERO);
+ tfd->tfd_clockid = clockid;
+ mtx_init(&tfd->tfd_lock, "timerfd", NULL, MTX_DEF);
+
+ callout_init_mtx(&tfd->tfd_callout, &tfd->tfd_lock, 0);
+ knlist_init_mtx(&tfd->tfd_sel.si_note, &tfd->tfd_lock);
+
+ fflags = FREAD;
+ if ((args->flags & LINUX_O_NONBLOCK) != 0)
+ fflags |= FNONBLOCK;
+
+ finit(fp, fflags, DTYPE_LINUXTFD, tfd, &timerfdops);
+ fdrop(fp, td);
+
+ td->td_retval[0] = fd;
+ return (error);
+}
+
+static int
+timerfd_close(struct file *fp, struct thread *td)
+{
+ struct timerfd *tfd;
+
+ tfd = fp->f_data;
+ if (fp->f_type != DTYPE_LINUXTFD || tfd == NULL)
+ return (EINVAL);
+
+ timespecclear(&tfd->tfd_time.it_value);
+ timespecclear(&tfd->tfd_time.it_interval);
+
+ callout_drain(&tfd->tfd_callout);
+
+ seldrain(&tfd->tfd_sel);
+ knlist_destroy(&tfd->tfd_sel.si_note);
+
+ fp->f_ops = &badfileops;
+ mtx_destroy(&tfd->tfd_lock);
+ free(tfd, M_EPOLL);
+
+ return (0);
+}
+
+static int
+timerfd_read(struct file *fp, struct uio *uio, struct ucred *active_cred,
+ int flags, struct thread *td)
+{
+ struct timerfd *tfd;
+ timerfd_t count;
+ int error;
+
+ tfd = fp->f_data;
+ if (fp->f_type != DTYPE_LINUXTFD || tfd == NULL)
+ return (EINVAL);
+
+ if (uio->uio_resid < sizeof(timerfd_t))
+ return (EINVAL);
+
+ error = 0;
+ mtx_lock(&tfd->tfd_lock);
+retry:
+ if (tfd->tfd_canceled) {
+ tfd->tfd_count = 0;
+ mtx_unlock(&tfd->tfd_lock);
+ return (ECANCELED);
+ }
+ if (tfd->tfd_count == 0) {
+ if ((fp->f_flag & FNONBLOCK) != 0) {
+ mtx_unlock(&tfd->tfd_lock);
+ return (EAGAIN);
+ }
+ error = mtx_sleep(&tfd->tfd_count, &tfd->tfd_lock, PCATCH, "ltfdrd", 0);
+ if (error == 0)
+ goto retry;
+ }
+ if (error == 0) {
+ count = tfd->tfd_count;
+ tfd->tfd_count = 0;
+ mtx_unlock(&tfd->tfd_lock);
+ error = uiomove(&count, sizeof(timerfd_t), uio);
+ } else
+ mtx_unlock(&tfd->tfd_lock);
+
+ return (error);
+}
+
+static int
+timerfd_poll(struct file *fp, int events, struct ucred *active_cred,
+ struct thread *td)
+{
+ struct timerfd *tfd;
+ int revents = 0;
+
+ tfd = fp->f_data;
+ if (fp->f_type != DTYPE_LINUXTFD || tfd == NULL)
+ return (POLLERR);
+
+ mtx_lock(&tfd->tfd_lock);
+ if ((events & (POLLIN|POLLRDNORM)) && tfd->tfd_count > 0)
+ revents |= events & (POLLIN|POLLRDNORM);
+ if (revents == 0)
+ selrecord(td, &tfd->tfd_sel);
+ mtx_unlock(&tfd->tfd_lock);
+
+ return (revents);
+}
+
+static int
+timerfd_kqfilter(struct file *fp, struct knote *kn)
+{
+ struct timerfd *tfd;
+
+ tfd = fp->f_data;
+ if (fp->f_type != DTYPE_LINUXTFD || tfd == NULL)
+ return (EINVAL);
+
+ if (kn->kn_filter == EVFILT_READ)
+ kn->kn_fop = &timerfd_rfiltops;
+ else
+ return (EINVAL);
+
+ kn->kn_hook = tfd;
+ knlist_add(&tfd->tfd_sel.si_note, kn, 0);
+
+ return (0);
+}
+
+static void
+filt_timerfddetach(struct knote *kn)
+{
+ struct timerfd *tfd = kn->kn_hook;
+
+ mtx_lock(&tfd->tfd_lock);
+ knlist_remove(&tfd->tfd_sel.si_note, kn, 1);
+ mtx_unlock(&tfd->tfd_lock);
+}
+
+static int
+filt_timerfdread(struct knote *kn, long hint)
+{
+ struct timerfd *tfd = kn->kn_hook;
+
+ return (tfd->tfd_count > 0);
+}
+
+static int
+timerfd_ioctl(struct file *fp, u_long cmd, void *data,
+ struct ucred *active_cred, struct thread *td)
+{
+
+ if (fp->f_data == NULL || fp->f_type != DTYPE_LINUXTFD)
+ return (EINVAL);
+
+ switch (cmd) {
+ case FIONBIO:
+ case FIOASYNC:
+ return (0);
+ }
+
+ return (ENOTTY);
+}
+
+static int
+timerfd_stat(struct file *fp, struct stat *st, struct ucred *active_cred,
+ struct thread *td)
+{
+
+ return (ENXIO);
+}
+
+static int
+timerfd_fill_kinfo(struct file *fp, struct kinfo_file *kif, struct filedesc *fdp)
+{
+
+ kif->kf_type = KF_TYPE_UNKNOWN;
+ return (0);
+}
+
+static void
+linux_timerfd_clocktime(struct timerfd *tfd, struct timespec *ts)
+{
+
+ if (tfd->tfd_clockid == CLOCK_REALTIME)
+ getnanotime(ts);
+ else /* CLOCK_MONOTONIC */
+ getnanouptime(ts);
+}
+
+static void
+linux_timerfd_curval(struct timerfd *tfd, struct itimerspec *ots)
+{
+ struct timespec cts;
+
+ linux_timerfd_clocktime(tfd, &cts);
+ *ots = tfd->tfd_time;
+ if (ots->it_value.tv_sec != 0 || ots->it_value.tv_nsec != 0) {
+ timespecsub(&ots->it_value, &cts, &ots->it_value);
+ if (ots->it_value.tv_sec < 0 ||
+ (ots->it_value.tv_sec == 0 &&
+ ots->it_value.tv_nsec == 0)) {
+ ots->it_value.tv_sec = 0;
+ ots->it_value.tv_nsec = 1;
+ }
+ }
+}
+
+int
+linux_timerfd_gettime(struct thread *td, struct linux_timerfd_gettime_args *args)
+{
+ struct l_itimerspec lots;
+ struct itimerspec ots;
+ struct timerfd *tfd;
+ struct file *fp;
+ int error;
+
+ error = fget(td, args->fd, &cap_read_rights, &fp);
+ if (error != 0)
+ return (error);
+ tfd = fp->f_data;
+ if (fp->f_type != DTYPE_LINUXTFD || tfd == NULL) {
+ error = EINVAL;
+ goto out;
+ }
+
+ mtx_lock(&tfd->tfd_lock);
+ linux_timerfd_curval(tfd, &ots);
+ mtx_unlock(&tfd->tfd_lock);
+
+ error = native_to_linux_itimerspec(&lots, &ots);
+ if (error == 0)
+ error = copyout(&lots, args->old_value, sizeof(lots));
+
+out:
+ fdrop(fp, td);
+ return (error);
+}
+
+int
+linux_timerfd_settime(struct thread *td, struct linux_timerfd_settime_args *args)
+{
+ struct l_itimerspec lots;
+ struct itimerspec nts, ots;
+ struct timespec cts, ts;
+ struct timerfd *tfd;
+ struct timeval tv;
+ struct file *fp;
+ int error;
+
+ if ((args->flags & ~LINUX_TFD_SETTIME_FLAGS) != 0)
+ return (EINVAL);
+
+ error = copyin(args->new_value, &lots, sizeof(lots));
+ if (error != 0)
+ return (error);
+ error = linux_to_native_itimerspec(&nts, &lots);
+ if (error != 0)
+ return (error);
+
+ error = fget(td, args->fd, &cap_write_rights, &fp);
+ if (error != 0)
+ return (error);
+ tfd = fp->f_data;
+ if (fp->f_type != DTYPE_LINUXTFD || tfd == NULL) {
+ error = EINVAL;
+ goto out;
+ }
+
+ mtx_lock(&tfd->tfd_lock);
+ if (!timespecisset(&nts.it_value))
+ timespecclear(&nts.it_interval);
+ if (args->old_value != NULL)
+ linux_timerfd_curval(tfd, &ots);
+
+ tfd->tfd_time = nts;
+ tfd->tfd_count = 0;
+ if (timespecisset(&nts.it_value)) {
+ linux_timerfd_clocktime(tfd, &cts);
+ ts = nts.it_value;
+ if ((args->flags & LINUX_TFD_TIMER_ABSTIME) == 0) {
+ timespecadd(&tfd->tfd_time.it_value, &cts,
+ &tfd->tfd_time.it_value);
+ } else {
+ timespecsub(&ts, &cts, &ts);
+ }
+ TIMESPEC_TO_TIMEVAL(&tv, &ts);
+ callout_reset(&tfd->tfd_callout, tvtohz(&tv),
+ linux_timerfd_expire, tfd);
+ tfd->tfd_canceled = false;
+ } else {
+ tfd->tfd_canceled = true;
+ callout_stop(&tfd->tfd_callout);
+ }
+ mtx_unlock(&tfd->tfd_lock);
+
+ if (args->old_value != NULL) {
+ error = native_to_linux_itimerspec(&lots, &ots);
+ if (error == 0)
+ error = copyout(&lots, args->old_value, sizeof(lots));
+ }
+
+out:
+ fdrop(fp, td);
+ return (error);
+}
+
+static void
+linux_timerfd_expire(void *arg)
+{
+ struct timespec cts, ts;
+ struct timeval tv;
+ struct timerfd *tfd;
+
+ tfd = (struct timerfd *)arg;
+
+ linux_timerfd_clocktime(tfd, &cts);
+ if (timespeccmp(&cts, &tfd->tfd_time.it_value, >=)) {
+ if (timespecisset(&tfd->tfd_time.it_interval))
+ timespecadd(&tfd->tfd_time.it_value,
+ &tfd->tfd_time.it_interval,
+ &tfd->tfd_time.it_value);
+ else
+ /* single shot timer */
+ timespecclear(&tfd->tfd_time.it_value);
+ if (timespecisset(&tfd->tfd_time.it_value)) {
+ timespecsub(&tfd->tfd_time.it_value, &cts, &ts);
+ TIMESPEC_TO_TIMEVAL(&tv, &ts);
+ callout_reset(&tfd->tfd_callout, tvtohz(&tv),
+ linux_timerfd_expire, tfd);
+ }
+ tfd->tfd_count++;
+ KNOTE_LOCKED(&tfd->tfd_sel.si_note, 0);
+ selwakeup(&tfd->tfd_sel);
+ wakeup(&tfd->tfd_count);
+ } else if (timespecisset(&tfd->tfd_time.it_value)) {
+ timespecsub(&tfd->tfd_time.it_value, &cts, &ts);
+ TIMESPEC_TO_TIMEVAL(&tv, &ts);
+ callout_reset(&tfd->tfd_callout, tvtohz(&tv),
+ linux_timerfd_expire, tfd);
+ }
+}
diff --git a/sys/compat/linux/linux_event.h b/sys/compat/linux/linux_event.h
new file mode 100644
index 000000000000..d6a0c2d42d0c
--- /dev/null
+++ b/sys/compat/linux/linux_event.h
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 2007 Roman Divacky
+ * Copyright (c) 2014 Dmitry Chagin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_EVENT_H_
+#define _LINUX_EVENT_H_
+
+#define LINUX_EPOLLIN 0x001
+#define LINUX_EPOLLPRI 0x002
+#define LINUX_EPOLLOUT 0x004
+#define LINUX_EPOLLRDNORM 0x040
+#define LINUX_EPOLLRDBAND 0x080
+#define LINUX_EPOLLWRNORM 0x100
+#define LINUX_EPOLLWRBAND 0x200
+#define LINUX_EPOLLMSG 0x400
+#define LINUX_EPOLLERR 0x008
+#define LINUX_EPOLLHUP 0x010
+#define LINUX_EPOLLRDHUP 0x2000
+#define LINUX_EPOLLWAKEUP 1u<<29
+#define LINUX_EPOLLONESHOT 1u<<30
+#define LINUX_EPOLLET 1u<<31
+
+#define LINUX_EPOLL_EVRD (LINUX_EPOLLIN|LINUX_EPOLLRDNORM)
+#define LINUX_EPOLL_EVWR (LINUX_EPOLLOUT|LINUX_EPOLLWRNORM)
+#define LINUX_EPOLL_EVSUP (LINUX_EPOLLET|LINUX_EPOLLONESHOT \
+ |LINUX_EPOLLHUP|LINUX_EPOLLERR|LINUX_EPOLLPRI \
+ |LINUX_EPOLL_EVRD|LINUX_EPOLL_EVWR|LINUX_EPOLLRDHUP)
+
+#define LINUX_EPOLL_CTL_ADD 1
+#define LINUX_EPOLL_CTL_DEL 2
+#define LINUX_EPOLL_CTL_MOD 3
+
+#define LINUX_EFD_SEMAPHORE (1 << 0)
+
+#define LINUX_TFD_TIMER_ABSTIME (1 << 0)
+#define LINUX_TFD_TIMER_CANCEL_ON_SET (1 << 1)
+#define LINUX_TFD_CLOEXEC LINUX_O_CLOEXEC
+#define LINUX_TFD_NONBLOCK LINUX_O_NONBLOCK
+
+#define LINUX_TFD_SHARED_FCNTL_FLAGS (LINUX_TFD_CLOEXEC \
+ |LINUX_TFD_NONBLOCK)
+#define LINUX_TFD_CREATE_FLAGS LINUX_TFD_SHARED_FCNTL_FLAGS
+#define LINUX_TFD_SETTIME_FLAGS (LINUX_TFD_TIMER_ABSTIME \
+ |LINUX_TFD_TIMER_CANCEL_ON_SET)
+
+#endif /* !_LINUX_EVENT_H_ */
diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c
new file mode 100644
index 000000000000..0c40a14d58f7
--- /dev/null
+++ b/sys/compat/linux/linux_file.c
@@ -0,0 +1,2024 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1994-1995 Søren Schmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_compat.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/capsicum.h>
+#include <sys/conf.h>
+#include <sys/dirent.h>
+#include <sys/fcntl.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/mutex.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/stat.h>
+#include <sys/sx.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysproto.h>
+#include <sys/tty.h>
+#include <sys/unistd.h>
+#include <sys/vnode.h>
+
+#ifdef COMPAT_LINUX32
+#include <compat/freebsd32/freebsd32_misc.h>
+#include <machine/../linux32/linux.h>
+#include <machine/../linux32/linux32_proto.h>
+#else
+#include <machine/../linux/linux.h>
+#include <machine/../linux/linux_proto.h>
+#endif
+#include <compat/linux/linux_misc.h>
+#include <compat/linux/linux_util.h>
+#include <compat/linux/linux_file.h>
+
+static int linux_common_open(struct thread *, int, const char *, int, int,
+ enum uio_seg);
+static int linux_getdents_error(struct thread *, int, int);
+
+static struct bsd_to_linux_bitmap seal_bitmap[] = {
+ BITMAP_1t1_LINUX(F_SEAL_SEAL),
+ BITMAP_1t1_LINUX(F_SEAL_SHRINK),
+ BITMAP_1t1_LINUX(F_SEAL_GROW),
+ BITMAP_1t1_LINUX(F_SEAL_WRITE),
+};
+
+#define MFD_HUGETLB_ENTRY(_size) \
+ { \
+ .bsd_value = MFD_HUGE_##_size, \
+ .linux_value = LINUX_HUGETLB_FLAG_ENCODE_##_size \
+ }
+static struct bsd_to_linux_bitmap mfd_bitmap[] = {
+ BITMAP_1t1_LINUX(MFD_CLOEXEC),
+ BITMAP_1t1_LINUX(MFD_ALLOW_SEALING),
+ BITMAP_1t1_LINUX(MFD_HUGETLB),
+ MFD_HUGETLB_ENTRY(64KB),
+ MFD_HUGETLB_ENTRY(512KB),
+ MFD_HUGETLB_ENTRY(1MB),
+ MFD_HUGETLB_ENTRY(2MB),
+ MFD_HUGETLB_ENTRY(8MB),
+ MFD_HUGETLB_ENTRY(16MB),
+ MFD_HUGETLB_ENTRY(32MB),
+ MFD_HUGETLB_ENTRY(256MB),
+ MFD_HUGETLB_ENTRY(512MB),
+ MFD_HUGETLB_ENTRY(1GB),
+ MFD_HUGETLB_ENTRY(2GB),
+ MFD_HUGETLB_ENTRY(16GB),
+};
+#undef MFD_HUGETLB_ENTRY
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_creat(struct thread *td, struct linux_creat_args *args)
+{
+ char *path;
+ int error;
+
+ if (!LUSECONVPATH(td)) {
+ return (kern_openat(td, AT_FDCWD, args->path, UIO_USERSPACE,
+ O_WRONLY | O_CREAT | O_TRUNC, args->mode));
+ }
+ LCONVPATHEXIST(td, args->path, &path);
+ error = kern_openat(td, AT_FDCWD, path, UIO_SYSSPACE,
+ O_WRONLY | O_CREAT | O_TRUNC, args->mode);
+ LFREEPATH(path);
+ return (error);
+}
+#endif
+
+static int
+linux_common_openflags(int l_flags)
+{
+ int bsd_flags;
+
+ bsd_flags = 0;
+ switch (l_flags & LINUX_O_ACCMODE) {
+ case LINUX_O_WRONLY:
+ bsd_flags |= O_WRONLY;
+ break;
+ case LINUX_O_RDWR:
+ bsd_flags |= O_RDWR;
+ break;
+ default:
+ bsd_flags |= O_RDONLY;
+ }
+ if (l_flags & LINUX_O_NDELAY)
+ bsd_flags |= O_NONBLOCK;
+ if (l_flags & LINUX_O_APPEND)
+ bsd_flags |= O_APPEND;
+ if (l_flags & LINUX_O_SYNC)
+ bsd_flags |= O_FSYNC;
+ if (l_flags & LINUX_O_CLOEXEC)
+ bsd_flags |= O_CLOEXEC;
+ if (l_flags & LINUX_O_NONBLOCK)
+ bsd_flags |= O_NONBLOCK;
+ if (l_flags & LINUX_O_ASYNC)
+ bsd_flags |= O_ASYNC;
+ if (l_flags & LINUX_O_CREAT)
+ bsd_flags |= O_CREAT;
+ if (l_flags & LINUX_O_TRUNC)
+ bsd_flags |= O_TRUNC;
+ if (l_flags & LINUX_O_EXCL)
+ bsd_flags |= O_EXCL;
+ if (l_flags & LINUX_O_NOCTTY)
+ bsd_flags |= O_NOCTTY;
+ if (l_flags & LINUX_O_DIRECT)
+ bsd_flags |= O_DIRECT;
+ if (l_flags & LINUX_O_NOFOLLOW)
+ bsd_flags |= O_NOFOLLOW;
+ if (l_flags & LINUX_O_DIRECTORY)
+ bsd_flags |= O_DIRECTORY;
+ /* XXX LINUX_O_NOATIME: unable to be easily implemented. */
+ return (bsd_flags);
+}
+
+static int
+linux_common_open(struct thread *td, int dirfd, const char *path, int l_flags,
+ int mode, enum uio_seg seg)
+{
+ struct proc *p = td->td_proc;
+ struct file *fp;
+ int fd;
+ int bsd_flags, error;
+
+ bsd_flags = linux_common_openflags(l_flags);
+ error = kern_openat(td, dirfd, path, seg, bsd_flags, mode);
+ if (error != 0) {
+ if (error == EMLINK)
+ error = ELOOP;
+ goto done;
+ }
+ if (p->p_flag & P_CONTROLT)
+ goto done;
+ if (bsd_flags & O_NOCTTY)
+ goto done;
+
+ /*
+ * XXX In between kern_openat() and fget(), another process
+ * having the same filedesc could use that fd without
+ * checking below.
+ */
+ fd = td->td_retval[0];
+ if (fget(td, fd, &cap_ioctl_rights, &fp) == 0) {
+ if (fp->f_type != DTYPE_VNODE) {
+ fdrop(fp, td);
+ goto done;
+ }
+ sx_slock(&proctree_lock);
+ PROC_LOCK(p);
+ if (SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
+ PROC_UNLOCK(p);
+ sx_sunlock(&proctree_lock);
+ /* XXXPJD: Verify if TIOCSCTTY is allowed. */
+ (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0,
+ td->td_ucred, td);
+ } else {
+ PROC_UNLOCK(p);
+ sx_sunlock(&proctree_lock);
+ }
+ fdrop(fp, td);
+ }
+
+done:
+ return (error);
+}
+
+int
+linux_openat(struct thread *td, struct linux_openat_args *args)
+{
+ char *path;
+ int dfd, error;
+
+ dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
+ if (!LUSECONVPATH(td)) {
+ return (linux_common_open(td, dfd, args->filename, args->flags,
+ args->mode, UIO_USERSPACE));
+ }
+ if (args->flags & LINUX_O_CREAT)
+ LCONVPATH_AT(td, args->filename, &path, 1, dfd);
+ else
+ LCONVPATH_AT(td, args->filename, &path, 0, dfd);
+
+ error = linux_common_open(td, dfd, path, args->flags, args->mode,
+ UIO_SYSSPACE);
+ LFREEPATH(path);
+ return (error);
+}
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_open(struct thread *td, struct linux_open_args *args)
+{
+ char *path;
+ int error;
+
+ if (!LUSECONVPATH(td)) {
+ return (linux_common_open(td, AT_FDCWD, args->path, args->flags,
+ args->mode, UIO_USERSPACE));
+ }
+ if (args->flags & LINUX_O_CREAT)
+ LCONVPATHCREAT(td, args->path, &path);
+ else
+ LCONVPATHEXIST(td, args->path, &path);
+
+ error = linux_common_open(td, AT_FDCWD, path, args->flags, args->mode,
+ UIO_SYSSPACE);
+ LFREEPATH(path);
+ return (error);
+}
+#endif
+
+int
+linux_name_to_handle_at(struct thread *td,
+ struct linux_name_to_handle_at_args *args)
+{
+ static const l_int valid_flags = (LINUX_AT_SYMLINK_FOLLOW |
+ LINUX_AT_EMPTY_PATH);
+ static const l_uint fh_size = sizeof(fhandle_t);
+
+ fhandle_t fh;
+ l_uint fh_bytes;
+ l_int mount_id;
+ int error, fd, bsd_flags;
+
+ if (args->flags & ~valid_flags)
+ return (EINVAL);
+ if (args->flags & LINUX_AT_EMPTY_PATH)
+ /* XXX: not supported yet */
+ return (EOPNOTSUPP);
+
+ fd = args->dirfd;
+ if (fd == LINUX_AT_FDCWD)
+ fd = AT_FDCWD;
+
+ bsd_flags = 0;
+ if (!(args->flags & LINUX_AT_SYMLINK_FOLLOW))
+ bsd_flags |= AT_SYMLINK_NOFOLLOW;
+
+ if (!LUSECONVPATH(td)) {
+ error = kern_getfhat(td, bsd_flags, fd, args->name,
+ UIO_USERSPACE, &fh, UIO_SYSSPACE);
+ } else {
+ char *path;
+
+ LCONVPATH_AT(td, args->name, &path, 0, fd);
+ error = kern_getfhat(td, bsd_flags, fd, path, UIO_SYSSPACE,
+ &fh, UIO_SYSSPACE);
+ LFREEPATH(path);
+ }
+ if (error != 0)
+ return (error);
+
+ /* Emit mount_id -- required before EOVERFLOW case. */
+ mount_id = (fh.fh_fsid.val[0] ^ fh.fh_fsid.val[1]);
+ error = copyout(&mount_id, args->mnt_id, sizeof(mount_id));
+ if (error != 0)
+ return (error);
+
+ /* Check if there is room for handle. */
+ error = copyin(&args->handle->handle_bytes, &fh_bytes,
+ sizeof(fh_bytes));
+ if (error != 0)
+ return (error);
+
+ if (fh_bytes < fh_size) {
+ error = copyout(&fh_size, &args->handle->handle_bytes,
+ sizeof(fh_size));
+ if (error == 0)
+ error = EOVERFLOW;
+ return (error);
+ }
+
+ /* Emit handle. */
+ mount_id = 0;
+ /*
+ * We don't use handle_type for anything yet, but initialize a known
+ * value.
+ */
+ error = copyout(&mount_id, &args->handle->handle_type,
+ sizeof(mount_id));
+ if (error != 0)
+ return (error);
+
+ error = copyout(&fh, &args->handle->f_handle,
+ sizeof(fh));
+ return (error);
+}
+
+int
+linux_open_by_handle_at(struct thread *td,
+ struct linux_open_by_handle_at_args *args)
+{
+ l_uint fh_bytes;
+ int bsd_flags, error;
+
+ error = copyin(&args->handle->handle_bytes, &fh_bytes,
+ sizeof(fh_bytes));
+ if (error != 0)
+ return (error);
+
+ if (fh_bytes < sizeof(fhandle_t))
+ return (EINVAL);
+
+ bsd_flags = linux_common_openflags(args->flags);
+ return (kern_fhopen(td, (void *)&args->handle->f_handle, bsd_flags));
+}
+
+int
+linux_lseek(struct thread *td, struct linux_lseek_args *args)
+{
+
+ return (kern_lseek(td, args->fdes, args->off, args->whence));
+}
+
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+int
+linux_llseek(struct thread *td, struct linux_llseek_args *args)
+{
+ int error;
+ off_t off;
+
+ off = (args->olow) | (((off_t) args->ohigh) << 32);
+
+ error = kern_lseek(td, args->fd, off, args->whence);
+ if (error != 0)
+ return (error);
+
+ error = copyout(td->td_retval, args->res, sizeof(off_t));
+ if (error != 0)
+ return (error);
+
+ td->td_retval[0] = 0;
+ return (0);
+}
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+
+/*
+ * Note that linux_getdents(2) and linux_getdents64(2) have the same
+ * arguments. They only differ in the definition of struct dirent they
+ * operate on.
+ * Note that linux_readdir(2) is a special case of linux_getdents(2)
+ * where count is always equals 1, meaning that the buffer is one
+ * dirent-structure in size and that the code can't handle more anyway.
+ * Note that linux_readdir(2) can't be implemented by means of linux_getdents(2)
+ * as in case when the *dent buffer size is equal to 1 linux_getdents(2) will
+ * trash user stack.
+ */
+
+static int
+linux_getdents_error(struct thread *td, int fd, int err)
+{
+ struct vnode *vp;
+ struct file *fp;
+ int error;
+
+ /* Linux return ENOTDIR in case when fd is not a directory. */
+ error = getvnode(td, fd, &cap_read_rights, &fp);
+ if (error != 0)
+ return (error);
+ vp = fp->f_vnode;
+ if (vp->v_type != VDIR) {
+ fdrop(fp, td);
+ return (ENOTDIR);
+ }
+ fdrop(fp, td);
+ return (err);
+}
+
+struct l_dirent {
+ l_ulong d_ino;
+ l_off_t d_off;
+ l_ushort d_reclen;
+ char d_name[LINUX_NAME_MAX + 1];
+};
+
+struct l_dirent64 {
+ uint64_t d_ino;
+ int64_t d_off;
+ l_ushort d_reclen;
+ u_char d_type;
+ char d_name[LINUX_NAME_MAX + 1];
+};
+
+/*
+ * Linux uses the last byte in the dirent buffer to store d_type,
+ * at least glibc-2.7 requires it. That is why l_dirent is padded with 2 bytes.
+ */
+#define LINUX_RECLEN(namlen) \
+ roundup(offsetof(struct l_dirent, d_name) + (namlen) + 2, sizeof(l_ulong))
+
+#define LINUX_RECLEN64(namlen) \
+ roundup(offsetof(struct l_dirent64, d_name) + (namlen) + 1, \
+ sizeof(uint64_t))
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_getdents(struct thread *td, struct linux_getdents_args *args)
+{
+ struct dirent *bdp;
+ caddr_t inp, buf; /* BSD-format */
+ int len, reclen; /* BSD-format */
+ caddr_t outp; /* Linux-format */
+ int resid, linuxreclen; /* Linux-format */
+ caddr_t lbuf; /* Linux-format */
+ off_t base;
+ struct l_dirent *linux_dirent;
+ int buflen, error;
+ size_t retval;
+
+ buflen = min(args->count, MAXBSIZE);
+ buf = malloc(buflen, M_TEMP, M_WAITOK);
+
+ error = kern_getdirentries(td, args->fd, buf, buflen,
+ &base, NULL, UIO_SYSSPACE);
+ if (error != 0) {
+ error = linux_getdents_error(td, args->fd, error);
+ goto out1;
+ }
+
+ lbuf = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO);
+
+ len = td->td_retval[0];
+ inp = buf;
+ outp = (caddr_t)args->dent;
+ resid = args->count;
+ retval = 0;
+
+ while (len > 0) {
+ bdp = (struct dirent *) inp;
+ reclen = bdp->d_reclen;
+ linuxreclen = LINUX_RECLEN(bdp->d_namlen);
+ /*
+ * No more space in the user supplied dirent buffer.
+ * Return EINVAL.
+ */
+ if (resid < linuxreclen) {
+ error = EINVAL;
+ goto out;
+ }
+
+ linux_dirent = (struct l_dirent*)lbuf;
+ linux_dirent->d_ino = bdp->d_fileno;
+ linux_dirent->d_off = base + reclen;
+ linux_dirent->d_reclen = linuxreclen;
+ /*
+ * Copy d_type to last byte of l_dirent buffer
+ */
+ lbuf[linuxreclen - 1] = bdp->d_type;
+ strlcpy(linux_dirent->d_name, bdp->d_name,
+ linuxreclen - offsetof(struct l_dirent, d_name)-1);
+ error = copyout(linux_dirent, outp, linuxreclen);
+ if (error != 0)
+ goto out;
+
+ inp += reclen;
+ base += reclen;
+ len -= reclen;
+
+ retval += linuxreclen;
+ outp += linuxreclen;
+ resid -= linuxreclen;
+ }
+ td->td_retval[0] = retval;
+
+out:
+ free(lbuf, M_TEMP);
+out1:
+ free(buf, M_TEMP);
+ return (error);
+}
+#endif
+
+int
+linux_getdents64(struct thread *td, struct linux_getdents64_args *args)
+{
+ struct dirent *bdp;
+ caddr_t inp, buf; /* BSD-format */
+ int len, reclen; /* BSD-format */
+ caddr_t outp; /* Linux-format */
+ int resid, linuxreclen; /* Linux-format */
+ caddr_t lbuf; /* Linux-format */
+ off_t base;
+ struct l_dirent64 *linux_dirent64;
+ int buflen, error;
+ size_t retval;
+
+ buflen = min(args->count, MAXBSIZE);
+ buf = malloc(buflen, M_TEMP, M_WAITOK);
+
+ error = kern_getdirentries(td, args->fd, buf, buflen,
+ &base, NULL, UIO_SYSSPACE);
+ if (error != 0) {
+ error = linux_getdents_error(td, args->fd, error);
+ goto out1;
+ }
+
+ lbuf = malloc(LINUX_RECLEN64(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO);
+
+ len = td->td_retval[0];
+ inp = buf;
+ outp = (caddr_t)args->dirent;
+ resid = args->count;
+ retval = 0;
+
+ while (len > 0) {
+ bdp = (struct dirent *) inp;
+ reclen = bdp->d_reclen;
+ linuxreclen = LINUX_RECLEN64(bdp->d_namlen);
+ /*
+ * No more space in the user supplied dirent buffer.
+ * Return EINVAL.
+ */
+ if (resid < linuxreclen) {
+ error = EINVAL;
+ goto out;
+ }
+
+ linux_dirent64 = (struct l_dirent64*)lbuf;
+ linux_dirent64->d_ino = bdp->d_fileno;
+ linux_dirent64->d_off = base + reclen;
+ linux_dirent64->d_reclen = linuxreclen;
+ linux_dirent64->d_type = bdp->d_type;
+ strlcpy(linux_dirent64->d_name, bdp->d_name,
+ linuxreclen - offsetof(struct l_dirent64, d_name));
+ error = copyout(linux_dirent64, outp, linuxreclen);
+ if (error != 0)
+ goto out;
+
+ inp += reclen;
+ base += reclen;
+ len -= reclen;
+
+ retval += linuxreclen;
+ outp += linuxreclen;
+ resid -= linuxreclen;
+ }
+ td->td_retval[0] = retval;
+
+out:
+ free(lbuf, M_TEMP);
+out1:
+ free(buf, M_TEMP);
+ return (error);
+}
+
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+int
+linux_readdir(struct thread *td, struct linux_readdir_args *args)
+{
+ struct dirent *bdp;
+ caddr_t buf; /* BSD-format */
+ int linuxreclen; /* Linux-format */
+ caddr_t lbuf; /* Linux-format */
+ off_t base;
+ struct l_dirent *linux_dirent;
+ int buflen, error;
+
+ buflen = LINUX_RECLEN(LINUX_NAME_MAX);
+ buf = malloc(buflen, M_TEMP, M_WAITOK);
+
+ error = kern_getdirentries(td, args->fd, buf, buflen,
+ &base, NULL, UIO_SYSSPACE);
+ if (error != 0) {
+ error = linux_getdents_error(td, args->fd, error);
+ goto out;
+ }
+ if (td->td_retval[0] == 0)
+ goto out;
+
+ lbuf = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO);
+
+ bdp = (struct dirent *) buf;
+ linuxreclen = LINUX_RECLEN(bdp->d_namlen);
+
+ linux_dirent = (struct l_dirent*)lbuf;
+ linux_dirent->d_ino = bdp->d_fileno;
+ linux_dirent->d_off = linuxreclen;
+ linux_dirent->d_reclen = bdp->d_namlen;
+ strlcpy(linux_dirent->d_name, bdp->d_name,
+ linuxreclen - offsetof(struct l_dirent, d_name));
+ error = copyout(linux_dirent, args->dent, linuxreclen);
+ if (error == 0)
+ td->td_retval[0] = linuxreclen;
+
+ free(lbuf, M_TEMP);
+out:
+ free(buf, M_TEMP);
+ return (error);
+}
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+
+/*
+ * These exist mainly for hooks for doing /compat/linux translation.
+ */
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_access(struct thread *td, struct linux_access_args *args)
+{
+ char *path;
+ int error;
+
+ /* Linux convention. */
+ if (args->amode & ~(F_OK | X_OK | W_OK | R_OK))
+ return (EINVAL);
+
+ if (!LUSECONVPATH(td)) {
+ error = kern_accessat(td, AT_FDCWD, args->path, UIO_USERSPACE, 0,
+ args->amode);
+ } else {
+ LCONVPATHEXIST(td, args->path, &path);
+ error = kern_accessat(td, AT_FDCWD, path, UIO_SYSSPACE, 0,
+ args->amode);
+ LFREEPATH(path);
+ }
+
+ return (error);
+}
+#endif
+
+int
+linux_faccessat(struct thread *td, struct linux_faccessat_args *args)
+{
+ char *path;
+ int error, dfd;
+
+ /* Linux convention. */
+ if (args->amode & ~(F_OK | X_OK | W_OK | R_OK))
+ return (EINVAL);
+
+ dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
+ if (!LUSECONVPATH(td)) {
+ error = kern_accessat(td, dfd, args->filename, UIO_USERSPACE, 0, args->amode);
+ } else {
+ LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
+ error = kern_accessat(td, dfd, path, UIO_SYSSPACE, 0, args->amode);
+ LFREEPATH(path);
+ }
+
+ return (error);
+}
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_unlink(struct thread *td, struct linux_unlink_args *args)
+{
+ char *path;
+ int error;
+ struct stat st;
+
+ if (!LUSECONVPATH(td)) {
+ error = kern_funlinkat(td, AT_FDCWD, args->path, FD_NONE,
+ UIO_USERSPACE, 0, 0);
+ if (error == EPERM) {
+ /* Introduce POSIX noncompliant behaviour of Linux */
+ if (kern_statat(td, 0, AT_FDCWD, args->path,
+ UIO_SYSSPACE, &st, NULL) == 0) {
+ if (S_ISDIR(st.st_mode))
+ error = EISDIR;
+ }
+ }
+ } else {
+ LCONVPATHEXIST(td, args->path, &path);
+ error = kern_funlinkat(td, AT_FDCWD, path, FD_NONE, UIO_SYSSPACE, 0, 0);
+ if (error == EPERM) {
+ /* Introduce POSIX noncompliant behaviour of Linux */
+ if (kern_statat(td, 0, AT_FDCWD, path, UIO_SYSSPACE, &st,
+ NULL) == 0) {
+ if (S_ISDIR(st.st_mode))
+ error = EISDIR;
+ }
+ }
+ LFREEPATH(path);
+ }
+
+ return (error);
+}
+#endif
+
+static int
+linux_unlinkat_impl(struct thread *td, enum uio_seg pathseg, const char *path,
+ int dfd, struct linux_unlinkat_args *args)
+{
+ struct stat st;
+ int error;
+
+ if (args->flag & LINUX_AT_REMOVEDIR)
+ error = kern_frmdirat(td, dfd, path, FD_NONE, pathseg, 0);
+ else
+ error = kern_funlinkat(td, dfd, path, FD_NONE, pathseg, 0, 0);
+ if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) {
+ /* Introduce POSIX noncompliant behaviour of Linux */
+ if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path,
+ UIO_SYSSPACE, &st, NULL) == 0 && S_ISDIR(st.st_mode))
+ error = EISDIR;
+ }
+ return (error);
+}
+
+int
+linux_unlinkat(struct thread *td, struct linux_unlinkat_args *args)
+{
+ char *path;
+ int error, dfd;
+
+ if (args->flag & ~LINUX_AT_REMOVEDIR)
+ return (EINVAL);
+ dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
+ if (!LUSECONVPATH(td)) {
+ return (linux_unlinkat_impl(td, UIO_USERSPACE, args->pathname,
+ dfd, args));
+ }
+ LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
+ error = linux_unlinkat_impl(td, UIO_SYSSPACE, path, dfd, args);
+ LFREEPATH(path);
+ return (error);
+}
+int
+linux_chdir(struct thread *td, struct linux_chdir_args *args)
+{
+ char *path;
+ int error;
+
+ if (!LUSECONVPATH(td)) {
+ return (kern_chdir(td, args->path, UIO_USERSPACE));
+ }
+ LCONVPATHEXIST(td, args->path, &path);
+ error = kern_chdir(td, path, UIO_SYSSPACE);
+ LFREEPATH(path);
+ return (error);
+}
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_chmod(struct thread *td, struct linux_chmod_args *args)
+{
+ char *path;
+ int error;
+
+ if (!LUSECONVPATH(td)) {
+ return (kern_fchmodat(td, AT_FDCWD, args->path, UIO_USERSPACE,
+ args->mode, 0));
+ }
+ LCONVPATHEXIST(td, args->path, &path);
+ error = kern_fchmodat(td, AT_FDCWD, path, UIO_SYSSPACE, args->mode, 0);
+ LFREEPATH(path);
+ return (error);
+}
+#endif
+
+int
+linux_fchmodat(struct thread *td, struct linux_fchmodat_args *args)
+{
+ char *path;
+ int error, dfd;
+
+ dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
+ if (!LUSECONVPATH(td)) {
+ return (kern_fchmodat(td, dfd, args->filename, UIO_USERSPACE,
+ args->mode, 0));
+ }
+ LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
+ error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0);
+ LFREEPATH(path);
+ return (error);
+}
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_mkdir(struct thread *td, struct linux_mkdir_args *args)
+{
+ char *path;
+ int error;
+
+ if (!LUSECONVPATH(td)) {
+ return (kern_mkdirat(td, AT_FDCWD, args->path, UIO_USERSPACE, args->mode));
+ }
+ LCONVPATHCREAT(td, args->path, &path);
+ error = kern_mkdirat(td, AT_FDCWD, path, UIO_SYSSPACE, args->mode);
+ LFREEPATH(path);
+ return (error);
+}
+#endif
+
+int
+linux_mkdirat(struct thread *td, struct linux_mkdirat_args *args)
+{
+ char *path;
+ int error, dfd;
+
+ dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
+ if (!LUSECONVPATH(td)) {
+ return (kern_mkdirat(td, dfd, args->pathname, UIO_USERSPACE, args->mode));
+ }
+ LCONVPATHCREAT_AT(td, args->pathname, &path, dfd);
+ error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode);
+ LFREEPATH(path);
+ return (error);
+}
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_rmdir(struct thread *td, struct linux_rmdir_args *args)
+{
+ char *path;
+ int error;
+
+ if (!LUSECONVPATH(td)) {
+ return (kern_frmdirat(td, AT_FDCWD, args->path, FD_NONE,
+ UIO_USERSPACE, 0));
+ }
+ LCONVPATHEXIST(td, args->path, &path);
+ error = kern_frmdirat(td, AT_FDCWD, path, FD_NONE, UIO_SYSSPACE, 0);
+ LFREEPATH(path);
+ return (error);
+}
+
+int
+linux_rename(struct thread *td, struct linux_rename_args *args)
+{
+ char *from, *to;
+ int error;
+
+ if (!LUSECONVPATH(td)) {
+ return (kern_renameat(td, AT_FDCWD, args->from, AT_FDCWD,
+ args->to, UIO_USERSPACE));
+ }
+ LCONVPATHEXIST(td, args->from, &from);
+ /* Expand LCONVPATHCREATE so that `from' can be freed on errors */
+ error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
+ if (to == NULL) {
+ LFREEPATH(from);
+ return (error);
+ }
+ error = kern_renameat(td, AT_FDCWD, from, AT_FDCWD, to, UIO_SYSSPACE);
+ LFREEPATH(from);
+ LFREEPATH(to);
+ return (error);
+}
+#endif
+
+int
+linux_renameat(struct thread *td, struct linux_renameat_args *args)
+{
+ struct linux_renameat2_args renameat2_args = {
+ .olddfd = args->olddfd,
+ .oldname = args->oldname,
+ .newdfd = args->newdfd,
+ .newname = args->newname,
+ .flags = 0
+ };
+
+ return (linux_renameat2(td, &renameat2_args));
+}
+
+int
+linux_renameat2(struct thread *td, struct linux_renameat2_args *args)
+{
+ char *from, *to;
+ int error, olddfd, newdfd;
+
+ if (args->flags != 0) {
+ if (args->flags & ~(LINUX_RENAME_EXCHANGE |
+ LINUX_RENAME_NOREPLACE | LINUX_RENAME_WHITEOUT))
+ return (EINVAL);
+ if (args->flags & LINUX_RENAME_EXCHANGE &&
+ args->flags & (LINUX_RENAME_NOREPLACE |
+ LINUX_RENAME_WHITEOUT))
+ return (EINVAL);
+#if 0
+ /*
+ * This spams the console on Ubuntu Focal.
+ *
+ * What's needed here is a general mechanism to let users know
+ * about missing features without hogging the system.
+ */
+ linux_msg(td, "renameat2 unsupported flags 0x%x",
+ args->flags);
+#endif
+ return (EINVAL);
+ }
+
+ olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
+ newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
+ if (!LUSECONVPATH(td)) {
+ return (kern_renameat(td, olddfd, args->oldname, newdfd,
+ args->newname, UIO_USERSPACE));
+ }
+ LCONVPATHEXIST_AT(td, args->oldname, &from, olddfd);
+ /* Expand LCONVPATHCREATE so that `from' can be freed on errors */
+ error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
+ if (to == NULL) {
+ LFREEPATH(from);
+ return (error);
+ }
+ error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE);
+ LFREEPATH(from);
+ LFREEPATH(to);
+ return (error);
+}
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_symlink(struct thread *td, struct linux_symlink_args *args)
+{
+ char *path, *to;
+ int error;
+
+ if (!LUSECONVPATH(td)) {
+ return (kern_symlinkat(td, args->path, AT_FDCWD, args->to,
+ UIO_USERSPACE));
+ }
+ LCONVPATHEXIST(td, args->path, &path);
+ /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
+ error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
+ if (to == NULL) {
+ LFREEPATH(path);
+ return (error);
+ }
+ error = kern_symlinkat(td, path, AT_FDCWD, to, UIO_SYSSPACE);
+ LFREEPATH(path);
+ LFREEPATH(to);
+ return (error);
+}
+#endif
+
+int
+linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args)
+{
+ char *path, *to;
+ int error, dfd;
+
+ dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
+ if (!LUSECONVPATH(td)) {
+ return (kern_symlinkat(td, args->oldname, dfd, args->newname,
+ UIO_USERSPACE));
+ }
+ LCONVPATHEXIST(td, args->oldname, &path);
+ /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
+ error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd);
+ if (to == NULL) {
+ LFREEPATH(path);
+ return (error);
+ }
+ error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE);
+ LFREEPATH(path);
+ LFREEPATH(to);
+ return (error);
+}
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_readlink(struct thread *td, struct linux_readlink_args *args)
+{
+ char *name;
+ int error;
+
+ if (!LUSECONVPATH(td)) {
+ return (kern_readlinkat(td, AT_FDCWD, args->name, UIO_USERSPACE,
+ args->buf, UIO_USERSPACE, args->count));
+ }
+ LCONVPATHEXIST(td, args->name, &name);
+ error = kern_readlinkat(td, AT_FDCWD, name, UIO_SYSSPACE,
+ args->buf, UIO_USERSPACE, args->count);
+ LFREEPATH(name);
+ return (error);
+}
+#endif
+
+int
+linux_readlinkat(struct thread *td, struct linux_readlinkat_args *args)
+{
+ char *name;
+ int error, dfd;
+
+ dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
+ if (!LUSECONVPATH(td)) {
+ return (kern_readlinkat(td, dfd, args->path, UIO_USERSPACE,
+ args->buf, UIO_USERSPACE, args->bufsiz));
+ }
+ LCONVPATHEXIST_AT(td, args->path, &name, dfd);
+ error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf,
+ UIO_USERSPACE, args->bufsiz);
+ LFREEPATH(name);
+ return (error);
+}
+
+int
+linux_truncate(struct thread *td, struct linux_truncate_args *args)
+{
+ char *path;
+ int error;
+
+ if (!LUSECONVPATH(td)) {
+ return (kern_truncate(td, args->path, UIO_USERSPACE, args->length));
+ }
+ LCONVPATHEXIST(td, args->path, &path);
+ error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
+ LFREEPATH(path);
+ return (error);
+}
+
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+int
+linux_truncate64(struct thread *td, struct linux_truncate64_args *args)
+{
+ char *path;
+ off_t length;
+ int error;
+
+#if defined(__amd64__) && defined(COMPAT_LINUX32)
+ length = PAIR32TO64(off_t, args->length);
+#else
+ length = args->length;
+#endif
+
+ if (!LUSECONVPATH(td)) {
+ return (kern_truncate(td, args->path, UIO_USERSPACE, length));
+ }
+ LCONVPATHEXIST(td, args->path, &path);
+ error = kern_truncate(td, path, UIO_SYSSPACE, length);
+ LFREEPATH(path);
+ return (error);
+}
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+
+int
+linux_ftruncate(struct thread *td, struct linux_ftruncate_args *args)
+{
+
+ return (kern_ftruncate(td, args->fd, args->length));
+}
+
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+int
+linux_ftruncate64(struct thread *td, struct linux_ftruncate64_args *args)
+{
+ off_t length;
+
+#if defined(__amd64__) && defined(COMPAT_LINUX32)
+ length = PAIR32TO64(off_t, args->length);
+#else
+ length = args->length;
+#endif
+
+ return (kern_ftruncate(td, args->fd, length));
+}
+#endif
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_link(struct thread *td, struct linux_link_args *args)
+{
+ char *path, *to;
+ int error;
+
+ if (!LUSECONVPATH(td)) {
+ return (kern_linkat(td, AT_FDCWD, AT_FDCWD, args->path, args->to,
+ UIO_USERSPACE, FOLLOW));
+ }
+ LCONVPATHEXIST(td, args->path, &path);
+ /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
+ error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
+ if (to == NULL) {
+ LFREEPATH(path);
+ return (error);
+ }
+ error = kern_linkat(td, AT_FDCWD, AT_FDCWD, path, to, UIO_SYSSPACE,
+ FOLLOW);
+ LFREEPATH(path);
+ LFREEPATH(to);
+ return (error);
+}
+#endif
+
+int
+linux_linkat(struct thread *td, struct linux_linkat_args *args)
+{
+ char *path, *to;
+ int error, olddfd, newdfd, follow;
+
+ if (args->flag & ~LINUX_AT_SYMLINK_FOLLOW)
+ return (EINVAL);
+
+ olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
+ newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
+ follow = (args->flag & LINUX_AT_SYMLINK_FOLLOW) == 0 ? NOFOLLOW :
+ FOLLOW;
+ if (!LUSECONVPATH(td)) {
+ return (kern_linkat(td, olddfd, newdfd, args->oldname,
+ args->newname, UIO_USERSPACE, follow));
+ }
+ LCONVPATHEXIST_AT(td, args->oldname, &path, olddfd);
+ /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
+ error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
+ if (to == NULL) {
+ LFREEPATH(path);
+ return (error);
+ }
+ error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, follow);
+ LFREEPATH(path);
+ LFREEPATH(to);
+ return (error);
+}
+
+int
+linux_fdatasync(struct thread *td, struct linux_fdatasync_args *uap)
+{
+
+ return (kern_fsync(td, uap->fd, false));
+}
+
+int
+linux_sync_file_range(struct thread *td, struct linux_sync_file_range_args *uap)
+{
+ off_t nbytes, offset;
+
+#if defined(__amd64__) && defined(COMPAT_LINUX32)
+ nbytes = PAIR32TO64(off_t, uap->nbytes);
+ offset = PAIR32TO64(off_t, uap->offset);
+#else
+ nbytes = uap->nbytes;
+ offset = uap->offset;
+#endif
+
+ if (offset < 0 || nbytes < 0 ||
+ (uap->flags & ~(LINUX_SYNC_FILE_RANGE_WAIT_BEFORE |
+ LINUX_SYNC_FILE_RANGE_WRITE |
+ LINUX_SYNC_FILE_RANGE_WAIT_AFTER)) != 0) {
+ return (EINVAL);
+ }
+
+ return (kern_fsync(td, uap->fd, false));
+}
+
+int
+linux_pread(struct thread *td, struct linux_pread_args *uap)
+{
+ struct vnode *vp;
+ off_t offset;
+ int error;
+
+#if defined(__amd64__) && defined(COMPAT_LINUX32)
+ offset = PAIR32TO64(off_t, uap->offset);
+#else
+ offset = uap->offset;
+#endif
+
+ error = kern_pread(td, uap->fd, uap->buf, uap->nbyte, offset);
+ if (error == 0) {
+ /* This seems to violate POSIX but Linux does it. */
+ error = fgetvp(td, uap->fd, &cap_pread_rights, &vp);
+ if (error != 0)
+ return (error);
+ if (vp->v_type == VDIR)
+ error = EISDIR;
+ vrele(vp);
+ }
+ return (error);
+}
+
+int
+linux_pwrite(struct thread *td, struct linux_pwrite_args *uap)
+{
+ off_t offset;
+
+#if defined(__amd64__) && defined(COMPAT_LINUX32)
+ offset = PAIR32TO64(off_t, uap->offset);
+#else
+ offset = uap->offset;
+#endif
+
+ return (kern_pwrite(td, uap->fd, uap->buf, uap->nbyte, offset));
+}
+
+int
+linux_preadv(struct thread *td, struct linux_preadv_args *uap)
+{
+ struct uio *auio;
+ int error;
+ off_t offset;
+
+ /*
+ * According http://man7.org/linux/man-pages/man2/preadv.2.html#NOTES
+ * pos_l and pos_h, respectively, contain the
+ * low order and high order 32 bits of offset.
+ */
+ offset = (((off_t)uap->pos_h << (sizeof(offset) * 4)) <<
+ (sizeof(offset) * 4)) | uap->pos_l;
+ if (offset < 0)
+ return (EINVAL);
+#ifdef COMPAT_LINUX32
+ error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio);
+#else
+ error = copyinuio(uap->vec, uap->vlen, &auio);
+#endif
+ if (error != 0)
+ return (error);
+ error = kern_preadv(td, uap->fd, auio, offset);
+ free(auio, M_IOV);
+ return (error);
+}
+
+int
+linux_pwritev(struct thread *td, struct linux_pwritev_args *uap)
+{
+ struct uio *auio;
+ int error;
+ off_t offset;
+
+ /*
+ * According http://man7.org/linux/man-pages/man2/pwritev.2.html#NOTES
+ * pos_l and pos_h, respectively, contain the
+ * low order and high order 32 bits of offset.
+ */
+ offset = (((off_t)uap->pos_h << (sizeof(offset) * 4)) <<
+ (sizeof(offset) * 4)) | uap->pos_l;
+ if (offset < 0)
+ return (EINVAL);
+#ifdef COMPAT_LINUX32
+ error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio);
+#else
+ error = copyinuio(uap->vec, uap->vlen, &auio);
+#endif
+ if (error != 0)
+ return (error);
+ error = kern_pwritev(td, uap->fd, auio, offset);
+ free(auio, M_IOV);
+ return (error);
+}
+
+int
+linux_mount(struct thread *td, struct linux_mount_args *args)
+{
+ struct mntarg *ma = NULL;
+ char *fstypename, *mntonname, *mntfromname, *data;
+ int error, fsflags;
+
+ fstypename = malloc(MNAMELEN, M_TEMP, M_WAITOK);
+ mntonname = malloc(MNAMELEN, M_TEMP, M_WAITOK);
+ mntfromname = malloc(MNAMELEN, M_TEMP, M_WAITOK);
+ data = NULL;
+ error = copyinstr(args->filesystemtype, fstypename, MNAMELEN - 1,
+ NULL);
+ if (error != 0)
+ goto out;
+ if (args->specialfile != NULL) {
+ error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL);
+ if (error != 0)
+ goto out;
+ } else {
+ mntfromname[0] = '\0';
+ }
+ error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL);
+ if (error != 0)
+ goto out;
+
+ if (strcmp(fstypename, "ext2") == 0) {
+ strcpy(fstypename, "ext2fs");
+ } else if (strcmp(fstypename, "proc") == 0) {
+ strcpy(fstypename, "linprocfs");
+ } else if (strcmp(fstypename, "vfat") == 0) {
+ strcpy(fstypename, "msdosfs");
+ } else if (strcmp(fstypename, "fuse") == 0) {
+ char *fuse_options, *fuse_option, *fuse_name;
+
+ if (strcmp(mntfromname, "fuse") == 0)
+ strcpy(mntfromname, "/dev/fuse");
+
+ strcpy(fstypename, "fusefs");
+ data = malloc(MNAMELEN, M_TEMP, M_WAITOK);
+ error = copyinstr(args->data, data, MNAMELEN - 1, NULL);
+ if (error != 0)
+ goto out;
+
+ fuse_options = data;
+ while ((fuse_option = strsep(&fuse_options, ",")) != NULL) {
+ fuse_name = strsep(&fuse_option, "=");
+ if (fuse_name == NULL || fuse_option == NULL)
+ goto out;
+ ma = mount_arg(ma, fuse_name, fuse_option, -1);
+ }
+
+ /*
+ * The FUSE server uses Linux errno values instead of FreeBSD
+ * ones; add a flag to tell fuse(4) to do errno translation.
+ */
+ ma = mount_arg(ma, "linux_errnos", "1", -1);
+ }
+
+ fsflags = 0;
+
+ /*
+ * Linux SYNC flag is not included; the closest equivalent
+ * FreeBSD has is !ASYNC, which is our default.
+ */
+ if (args->rwflag & LINUX_MS_RDONLY)
+ fsflags |= MNT_RDONLY;
+ if (args->rwflag & LINUX_MS_NOSUID)
+ fsflags |= MNT_NOSUID;
+ if (args->rwflag & LINUX_MS_NOEXEC)
+ fsflags |= MNT_NOEXEC;
+ if (args->rwflag & LINUX_MS_REMOUNT)
+ fsflags |= MNT_UPDATE;
+
+ ma = mount_arg(ma, "fstype", fstypename, -1);
+ ma = mount_arg(ma, "fspath", mntonname, -1);
+ ma = mount_arg(ma, "from", mntfromname, -1);
+ error = kernel_mount(ma, fsflags);
+out:
+ free(fstypename, M_TEMP);
+ free(mntonname, M_TEMP);
+ free(mntfromname, M_TEMP);
+ free(data, M_TEMP);
+ return (error);
+}
+
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+int
+linux_oldumount(struct thread *td, struct linux_oldumount_args *args)
+{
+
+ return (kern_unmount(td, args->path, 0));
+}
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_umount(struct thread *td, struct linux_umount_args *args)
+{
+ int flags;
+
+ flags = 0;
+ if ((args->flags & LINUX_MNT_FORCE) != 0) {
+ args->flags &= ~LINUX_MNT_FORCE;
+ flags |= MNT_FORCE;
+ }
+ if (args->flags != 0) {
+ linux_msg(td, "unsupported umount2 flags %#x", args->flags);
+ return (EINVAL);
+ }
+
+ return (kern_unmount(td, args->path, flags));
+}
+#endif
+
+/*
+ * fcntl family of syscalls
+ */
+
+struct l_flock {
+ l_short l_type;
+ l_short l_whence;
+ l_off_t l_start;
+ l_off_t l_len;
+ l_pid_t l_pid;
+}
+#if defined(__amd64__) && defined(COMPAT_LINUX32)
+__packed
+#endif
+;
+
+static void
+linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
+{
+ switch (linux_flock->l_type) {
+ case LINUX_F_RDLCK:
+ bsd_flock->l_type = F_RDLCK;
+ break;
+ case LINUX_F_WRLCK:
+ bsd_flock->l_type = F_WRLCK;
+ break;
+ case LINUX_F_UNLCK:
+ bsd_flock->l_type = F_UNLCK;
+ break;
+ default:
+ bsd_flock->l_type = -1;
+ break;
+ }
+ bsd_flock->l_whence = linux_flock->l_whence;
+ bsd_flock->l_start = (off_t)linux_flock->l_start;
+ bsd_flock->l_len = (off_t)linux_flock->l_len;
+ bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
+ bsd_flock->l_sysid = 0;
+}
+
+static void
+bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
+{
+ switch (bsd_flock->l_type) {
+ case F_RDLCK:
+ linux_flock->l_type = LINUX_F_RDLCK;
+ break;
+ case F_WRLCK:
+ linux_flock->l_type = LINUX_F_WRLCK;
+ break;
+ case F_UNLCK:
+ linux_flock->l_type = LINUX_F_UNLCK;
+ break;
+ }
+ linux_flock->l_whence = bsd_flock->l_whence;
+ linux_flock->l_start = (l_off_t)bsd_flock->l_start;
+ linux_flock->l_len = (l_off_t)bsd_flock->l_len;
+ linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
+}
+
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+struct l_flock64 {
+ l_short l_type;
+ l_short l_whence;
+ l_loff_t l_start;
+ l_loff_t l_len;
+ l_pid_t l_pid;
+}
+#if defined(__amd64__) && defined(COMPAT_LINUX32)
+__packed
+#endif
+;
+
+static void
+linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
+{
+ switch (linux_flock->l_type) {
+ case LINUX_F_RDLCK:
+ bsd_flock->l_type = F_RDLCK;
+ break;
+ case LINUX_F_WRLCK:
+ bsd_flock->l_type = F_WRLCK;
+ break;
+ case LINUX_F_UNLCK:
+ bsd_flock->l_type = F_UNLCK;
+ break;
+ default:
+ bsd_flock->l_type = -1;
+ break;
+ }
+ bsd_flock->l_whence = linux_flock->l_whence;
+ bsd_flock->l_start = (off_t)linux_flock->l_start;
+ bsd_flock->l_len = (off_t)linux_flock->l_len;
+ bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
+ bsd_flock->l_sysid = 0;
+}
+
+static void
+bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
+{
+ switch (bsd_flock->l_type) {
+ case F_RDLCK:
+ linux_flock->l_type = LINUX_F_RDLCK;
+ break;
+ case F_WRLCK:
+ linux_flock->l_type = LINUX_F_WRLCK;
+ break;
+ case F_UNLCK:
+ linux_flock->l_type = LINUX_F_UNLCK;
+ break;
+ }
+ linux_flock->l_whence = bsd_flock->l_whence;
+ linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
+ linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
+ linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
+}
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+
+static int
+fcntl_common(struct thread *td, struct linux_fcntl_args *args)
+{
+ struct l_flock linux_flock;
+ struct flock bsd_flock;
+ struct file *fp;
+ long arg;
+ int error, result;
+
+ switch (args->cmd) {
+ case LINUX_F_DUPFD:
+ return (kern_fcntl(td, args->fd, F_DUPFD, args->arg));
+
+ case LINUX_F_GETFD:
+ return (kern_fcntl(td, args->fd, F_GETFD, 0));
+
+ case LINUX_F_SETFD:
+ return (kern_fcntl(td, args->fd, F_SETFD, args->arg));
+
+ case LINUX_F_GETFL:
+ error = kern_fcntl(td, args->fd, F_GETFL, 0);
+ result = td->td_retval[0];
+ td->td_retval[0] = 0;
+ if (result & O_RDONLY)
+ td->td_retval[0] |= LINUX_O_RDONLY;
+ if (result & O_WRONLY)
+ td->td_retval[0] |= LINUX_O_WRONLY;
+ if (result & O_RDWR)
+ td->td_retval[0] |= LINUX_O_RDWR;
+ if (result & O_NDELAY)
+ td->td_retval[0] |= LINUX_O_NONBLOCK;
+ if (result & O_APPEND)
+ td->td_retval[0] |= LINUX_O_APPEND;
+ if (result & O_FSYNC)
+ td->td_retval[0] |= LINUX_O_SYNC;
+ if (result & O_ASYNC)
+ td->td_retval[0] |= LINUX_O_ASYNC;
+#ifdef LINUX_O_NOFOLLOW
+ if (result & O_NOFOLLOW)
+ td->td_retval[0] |= LINUX_O_NOFOLLOW;
+#endif
+#ifdef LINUX_O_DIRECT
+ if (result & O_DIRECT)
+ td->td_retval[0] |= LINUX_O_DIRECT;
+#endif
+ return (error);
+
+ case LINUX_F_SETFL:
+ arg = 0;
+ if (args->arg & LINUX_O_NDELAY)
+ arg |= O_NONBLOCK;
+ if (args->arg & LINUX_O_APPEND)
+ arg |= O_APPEND;
+ if (args->arg & LINUX_O_SYNC)
+ arg |= O_FSYNC;
+ if (args->arg & LINUX_O_ASYNC)
+ arg |= O_ASYNC;
+#ifdef LINUX_O_NOFOLLOW
+ if (args->arg & LINUX_O_NOFOLLOW)
+ arg |= O_NOFOLLOW;
+#endif
+#ifdef LINUX_O_DIRECT
+ if (args->arg & LINUX_O_DIRECT)
+ arg |= O_DIRECT;
+#endif
+ return (kern_fcntl(td, args->fd, F_SETFL, arg));
+
+ case LINUX_F_GETLK:
+ error = copyin((void *)args->arg, &linux_flock,
+ sizeof(linux_flock));
+ if (error)
+ return (error);
+ linux_to_bsd_flock(&linux_flock, &bsd_flock);
+ error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
+ if (error)
+ return (error);
+ bsd_to_linux_flock(&bsd_flock, &linux_flock);
+ return (copyout(&linux_flock, (void *)args->arg,
+ sizeof(linux_flock)));
+
+ case LINUX_F_SETLK:
+ error = copyin((void *)args->arg, &linux_flock,
+ sizeof(linux_flock));
+ if (error)
+ return (error);
+ linux_to_bsd_flock(&linux_flock, &bsd_flock);
+ return (kern_fcntl(td, args->fd, F_SETLK,
+ (intptr_t)&bsd_flock));
+
+ case LINUX_F_SETLKW:
+ error = copyin((void *)args->arg, &linux_flock,
+ sizeof(linux_flock));
+ if (error)
+ return (error);
+ linux_to_bsd_flock(&linux_flock, &bsd_flock);
+ return (kern_fcntl(td, args->fd, F_SETLKW,
+ (intptr_t)&bsd_flock));
+
+ case LINUX_F_GETOWN:
+ return (kern_fcntl(td, args->fd, F_GETOWN, 0));
+
+ case LINUX_F_SETOWN:
+ /*
+ * XXX some Linux applications depend on F_SETOWN having no
+ * significant effect for pipes (SIGIO is not delivered for
+ * pipes under Linux-2.2.35 at least).
+ */
+ error = fget(td, args->fd,
+ &cap_fcntl_rights, &fp);
+ if (error)
+ return (error);
+ if (fp->f_type == DTYPE_PIPE) {
+ fdrop(fp, td);
+ return (EINVAL);
+ }
+ fdrop(fp, td);
+
+ return (kern_fcntl(td, args->fd, F_SETOWN, args->arg));
+
+ case LINUX_F_DUPFD_CLOEXEC:
+ return (kern_fcntl(td, args->fd, F_DUPFD_CLOEXEC, args->arg));
+ /*
+ * Our F_SEAL_* values match Linux one for maximum compatibility. So we
+ * only needed to account for different values for fcntl(2) commands.
+ */
+ case LINUX_F_GET_SEALS:
+ error = kern_fcntl(td, args->fd, F_GET_SEALS, 0);
+ if (error != 0)
+ return (error);
+ td->td_retval[0] = bsd_to_linux_bits(td->td_retval[0],
+ seal_bitmap, 0);
+ return (0);
+
+ case LINUX_F_ADD_SEALS:
+ return (kern_fcntl(td, args->fd, F_ADD_SEALS,
+ linux_to_bsd_bits(args->arg, seal_bitmap, 0)));
+ default:
+ linux_msg(td, "unsupported fcntl cmd %d", args->cmd);
+ return (EINVAL);
+ }
+}
+
+int
+linux_fcntl(struct thread *td, struct linux_fcntl_args *args)
+{
+
+ return (fcntl_common(td, args));
+}
+
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+int
+linux_fcntl64(struct thread *td, struct linux_fcntl64_args *args)
+{
+ struct l_flock64 linux_flock;
+ struct flock bsd_flock;
+ struct linux_fcntl_args fcntl_args;
+ int error;
+
+ switch (args->cmd) {
+ case LINUX_F_GETLK64:
+ error = copyin((void *)args->arg, &linux_flock,
+ sizeof(linux_flock));
+ if (error)
+ return (error);
+ linux_to_bsd_flock64(&linux_flock, &bsd_flock);
+ error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
+ if (error)
+ return (error);
+ bsd_to_linux_flock64(&bsd_flock, &linux_flock);
+ return (copyout(&linux_flock, (void *)args->arg,
+ sizeof(linux_flock)));
+
+ case LINUX_F_SETLK64:
+ error = copyin((void *)args->arg, &linux_flock,
+ sizeof(linux_flock));
+ if (error)
+ return (error);
+ linux_to_bsd_flock64(&linux_flock, &bsd_flock);
+ return (kern_fcntl(td, args->fd, F_SETLK,
+ (intptr_t)&bsd_flock));
+
+ case LINUX_F_SETLKW64:
+ error = copyin((void *)args->arg, &linux_flock,
+ sizeof(linux_flock));
+ if (error)
+ return (error);
+ linux_to_bsd_flock64(&linux_flock, &bsd_flock);
+ return (kern_fcntl(td, args->fd, F_SETLKW,
+ (intptr_t)&bsd_flock));
+ }
+
+ fcntl_args.fd = args->fd;
+ fcntl_args.cmd = args->cmd;
+ fcntl_args.arg = args->arg;
+ return (fcntl_common(td, &fcntl_args));
+}
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_chown(struct thread *td, struct linux_chown_args *args)
+{
+ char *path;
+ int error;
+
+ if (!LUSECONVPATH(td)) {
+ return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE,
+ args->uid, args->gid, 0));
+ }
+ LCONVPATHEXIST(td, args->path, &path);
+ error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid,
+ args->gid, 0);
+ LFREEPATH(path);
+ return (error);
+}
+#endif
+
+int
+linux_fchownat(struct thread *td, struct linux_fchownat_args *args)
+{
+ char *path;
+ int error, dfd, flag;
+
+ if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
+ return (EINVAL);
+
+ dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
+ flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 :
+ AT_SYMLINK_NOFOLLOW;
+ if (!LUSECONVPATH(td)) {
+ return (kern_fchownat(td, dfd, args->filename, UIO_USERSPACE,
+ args->uid, args->gid, flag));
+ }
+ LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
+ error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid,
+ flag);
+ LFREEPATH(path);
+ return (error);
+}
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_lchown(struct thread *td, struct linux_lchown_args *args)
+{
+ char *path;
+ int error;
+
+ if (!LUSECONVPATH(td)) {
+ return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE, args->uid,
+ args->gid, AT_SYMLINK_NOFOLLOW));
+ }
+ LCONVPATHEXIST(td, args->path, &path);
+ error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid, args->gid,
+ AT_SYMLINK_NOFOLLOW);
+ LFREEPATH(path);
+ return (error);
+}
+#endif
+
+static int
+convert_fadvice(int advice)
+{
+ switch (advice) {
+ case LINUX_POSIX_FADV_NORMAL:
+ return (POSIX_FADV_NORMAL);
+ case LINUX_POSIX_FADV_RANDOM:
+ return (POSIX_FADV_RANDOM);
+ case LINUX_POSIX_FADV_SEQUENTIAL:
+ return (POSIX_FADV_SEQUENTIAL);
+ case LINUX_POSIX_FADV_WILLNEED:
+ return (POSIX_FADV_WILLNEED);
+ case LINUX_POSIX_FADV_DONTNEED:
+ return (POSIX_FADV_DONTNEED);
+ case LINUX_POSIX_FADV_NOREUSE:
+ return (POSIX_FADV_NOREUSE);
+ default:
+ return (-1);
+ }
+}
+
+int
+linux_fadvise64(struct thread *td, struct linux_fadvise64_args *args)
+{
+ off_t offset;
+ int advice;
+
+#if defined(__amd64__) && defined(COMPAT_LINUX32)
+ offset = PAIR32TO64(off_t, args->offset);
+#else
+ offset = args->offset;
+#endif
+
+ advice = convert_fadvice(args->advice);
+ if (advice == -1)
+ return (EINVAL);
+ return (kern_posix_fadvise(td, args->fd, offset, args->len, advice));
+}
+
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+int
+linux_fadvise64_64(struct thread *td, struct linux_fadvise64_64_args *args)
+{
+ off_t len, offset;
+ int advice;
+
+#if defined(__amd64__) && defined(COMPAT_LINUX32)
+ len = PAIR32TO64(off_t, args->len);
+ offset = PAIR32TO64(off_t, args->offset);
+#else
+ len = args->len;
+ offset = args->offset;
+#endif
+
+ advice = convert_fadvice(args->advice);
+ if (advice == -1)
+ return (EINVAL);
+ return (kern_posix_fadvise(td, args->fd, offset, len, advice));
+}
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_pipe(struct thread *td, struct linux_pipe_args *args)
+{
+ int fildes[2];
+ int error;
+
+ error = kern_pipe(td, fildes, 0, NULL, NULL);
+ if (error != 0)
+ return (error);
+
+ error = copyout(fildes, args->pipefds, sizeof(fildes));
+ if (error != 0) {
+ (void)kern_close(td, fildes[0]);
+ (void)kern_close(td, fildes[1]);
+ }
+
+ return (error);
+}
+#endif
+
+int
+linux_pipe2(struct thread *td, struct linux_pipe2_args *args)
+{
+ int fildes[2];
+ int error, flags;
+
+ if ((args->flags & ~(LINUX_O_NONBLOCK | LINUX_O_CLOEXEC)) != 0)
+ return (EINVAL);
+
+ flags = 0;
+ if ((args->flags & LINUX_O_NONBLOCK) != 0)
+ flags |= O_NONBLOCK;
+ if ((args->flags & LINUX_O_CLOEXEC) != 0)
+ flags |= O_CLOEXEC;
+ error = kern_pipe(td, fildes, flags, NULL, NULL);
+ if (error != 0)
+ return (error);
+
+ error = copyout(fildes, args->pipefds, sizeof(fildes));
+ if (error != 0) {
+ (void)kern_close(td, fildes[0]);
+ (void)kern_close(td, fildes[1]);
+ }
+
+ return (error);
+}
+
+int
+linux_dup3(struct thread *td, struct linux_dup3_args *args)
+{
+ int cmd;
+ intptr_t newfd;
+
+ if (args->oldfd == args->newfd)
+ return (EINVAL);
+ if ((args->flags & ~LINUX_O_CLOEXEC) != 0)
+ return (EINVAL);
+ if (args->flags & LINUX_O_CLOEXEC)
+ cmd = F_DUP2FD_CLOEXEC;
+ else
+ cmd = F_DUP2FD;
+
+ newfd = args->newfd;
+ return (kern_fcntl(td, args->oldfd, cmd, newfd));
+}
+
+int
+linux_fallocate(struct thread *td, struct linux_fallocate_args *args)
+{
+ off_t len, offset;
+
+ /*
+ * We emulate only posix_fallocate system call for which
+ * mode should be 0.
+ */
+ if (args->mode != 0)
+ return (EOPNOTSUPP);
+
+#if defined(__amd64__) && defined(COMPAT_LINUX32)
+ len = PAIR32TO64(off_t, args->len);
+ offset = PAIR32TO64(off_t, args->offset);
+#else
+ len = args->len;
+ offset = args->offset;
+#endif
+
+ return (kern_posix_fallocate(td, args->fd, offset, len));
+}
+
+int
+linux_copy_file_range(struct thread *td, struct linux_copy_file_range_args
+ *args)
+{
+ l_loff_t inoff, outoff, *inoffp, *outoffp;
+ int error, flags;
+
+ /*
+ * copy_file_range(2) on Linux doesn't define any flags (yet), so is
+ * the native implementation. Enforce it.
+ */
+ if (args->flags != 0) {
+ linux_msg(td, "copy_file_range unsupported flags 0x%x",
+ args->flags);
+ return (EINVAL);
+ }
+ flags = 0;
+ inoffp = outoffp = NULL;
+ if (args->off_in != NULL) {
+ error = copyin(args->off_in, &inoff, sizeof(l_loff_t));
+ if (error != 0)
+ return (error);
+ inoffp = &inoff;
+ }
+ if (args->off_out != NULL) {
+ error = copyin(args->off_out, &outoff, sizeof(l_loff_t));
+ if (error != 0)
+ return (error);
+ outoffp = &outoff;
+ }
+
+ error = kern_copy_file_range(td, args->fd_in, inoffp, args->fd_out,
+ outoffp, args->len, flags);
+ if (error == 0 && args->off_in != NULL)
+ error = copyout(inoffp, args->off_in, sizeof(l_loff_t));
+ if (error == 0 && args->off_out != NULL)
+ error = copyout(outoffp, args->off_out, sizeof(l_loff_t));
+ return (error);
+}
+
+#define LINUX_MEMFD_PREFIX "memfd:"
+
+int
+linux_memfd_create(struct thread *td, struct linux_memfd_create_args *args)
+{
+ char memfd_name[LINUX_NAME_MAX + 1];
+ int error, flags, shmflags, oflags;
+
+ /*
+ * This is our clever trick to avoid the heap allocation to copy in the
+ * uname. We don't really need to go this far out of our way, but it
+ * does keep the rest of this function fairly clean as they don't have
+ * to worry about cleanup on the way out.
+ */
+ error = copyinstr(args->uname_ptr,
+ memfd_name + sizeof(LINUX_MEMFD_PREFIX) - 1,
+ LINUX_NAME_MAX - sizeof(LINUX_MEMFD_PREFIX) - 1, NULL);
+ if (error != 0) {
+ if (error == ENAMETOOLONG)
+ error = EINVAL;
+ return (error);
+ }
+
+ memcpy(memfd_name, LINUX_MEMFD_PREFIX, sizeof(LINUX_MEMFD_PREFIX) - 1);
+ flags = linux_to_bsd_bits(args->flags, mfd_bitmap, 0);
+ if ((flags & ~(MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_HUGETLB |
+ MFD_HUGE_MASK)) != 0)
+ return (EINVAL);
+ /* Size specified but no HUGETLB. */
+ if ((flags & MFD_HUGE_MASK) != 0 && (flags & MFD_HUGETLB) == 0)
+ return (EINVAL);
+ /* We don't actually support HUGETLB. */
+ if ((flags & MFD_HUGETLB) != 0)
+ return (ENOSYS);
+ oflags = O_RDWR;
+ shmflags = SHM_GROW_ON_WRITE;
+ if ((flags & MFD_CLOEXEC) != 0)
+ oflags |= O_CLOEXEC;
+ if ((flags & MFD_ALLOW_SEALING) != 0)
+ shmflags |= SHM_ALLOW_SEALING;
+ return (kern_shm_open2(td, SHM_ANON, oflags, 0, shmflags, NULL,
+ memfd_name));
+}
+
+int
+linux_splice(struct thread *td, struct linux_splice_args *args)
+{
+
+ linux_msg(td, "syscall splice not really implemented");
+
+ /*
+ * splice(2) is documented to return EINVAL in various circumstances;
+ * returning it instead of ENOSYS should hint the caller to use fallback
+ * instead.
+ */
+ return (EINVAL);
+}
diff --git a/sys/compat/linux/linux_file.h b/sys/compat/linux/linux_file.h
new file mode 100644
index 000000000000..5a11e999ed59
--- /dev/null
+++ b/sys/compat/linux/linux_file.h
@@ -0,0 +1,184 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2007 Roman Divacky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_FILE_H_
+#define _LINUX_FILE_H_
+
+#define LINUX_AT_FDCWD -100
+#define LINUX_AT_SYMLINK_NOFOLLOW 0x100
+#define LINUX_AT_EACCESS 0x200
+#define LINUX_AT_REMOVEDIR 0x200
+#define LINUX_AT_SYMLINK_FOLLOW 0x400
+#define LINUX_AT_EMPTY_PATH 0x1000
+
+/*
+ * posix_fadvise advice
+ */
+#define LINUX_POSIX_FADV_NORMAL 0
+#define LINUX_POSIX_FADV_RANDOM 1
+#define LINUX_POSIX_FADV_SEQUENTIAL 2
+#define LINUX_POSIX_FADV_WILLNEED 3
+#define LINUX_POSIX_FADV_DONTNEED 4
+#define LINUX_POSIX_FADV_NOREUSE 5
+
+/*
+ * mount flags
+ */
+#define LINUX_MS_RDONLY 0x0001
+#define LINUX_MS_NOSUID 0x0002
+#define LINUX_MS_NODEV 0x0004
+#define LINUX_MS_NOEXEC 0x0008
+#define LINUX_MS_REMOUNT 0x0020
+
+/*
+ * umount2 flags
+ */
+#define LINUX_MNT_FORCE 0x0001
+
+/*
+ * common open/fcntl flags
+ */
+#define LINUX_O_RDONLY 00000000
+#define LINUX_O_WRONLY 00000001
+#define LINUX_O_RDWR 00000002
+#define LINUX_O_ACCMODE 00000003
+#define LINUX_O_CREAT 00000100
+#define LINUX_O_EXCL 00000200
+#define LINUX_O_NOCTTY 00000400
+#define LINUX_O_TRUNC 00001000
+#define LINUX_O_APPEND 00002000
+#define LINUX_O_NONBLOCK 00004000
+#define LINUX_O_NDELAY LINUX_O_NONBLOCK
+#define LINUX_O_SYNC 00010000
+#define LINUX_O_ASYNC 00020000
+#define LINUX_O_DIRECT 00040000 /* Direct disk access hint */
+#define LINUX_O_LARGEFILE 00100000
+#define LINUX_O_DIRECTORY 00200000 /* Must be a directory */
+#define LINUX_O_NOFOLLOW 00400000 /* Do not follow links */
+#define LINUX_O_NOATIME 01000000
+#define LINUX_O_CLOEXEC 02000000
+
+#define LINUX_F_DUPFD 0
+#define LINUX_F_GETFD 1
+#define LINUX_F_SETFD 2
+#define LINUX_F_GETFL 3
+#define LINUX_F_SETFL 4
+#ifndef LINUX_F_GETLK
+#define LINUX_F_GETLK 5
+#define LINUX_F_SETLK 6
+#define LINUX_F_SETLKW 7
+#endif
+#ifndef LINUX_F_SETOWN
+#define LINUX_F_SETOWN 8
+#define LINUX_F_GETOWN 9
+#endif
+#ifndef LINUX_F_SETSIG
+#define LINUX_F_SETSIG 10
+#define LINUX_F_GETSIG 11
+#endif
+#ifndef LINUX_F_SETOWN_EX
+#define LINUX_F_SETOWN_EX 15
+#define LINUX_F_GETOWN_EX 16
+#define LINUX_F_GETOWNER_UIDS 17
+#endif
+
+#define LINUX_F_SPECIFIC_BASE 1024
+
+#define LINUX_F_SETLEASE (LINUX_F_SPECIFIC_BASE + 0)
+#define LINUX_F_GETLEASE (LINUX_F_SPECIFIC_BASE + 1)
+#define LINUX_F_CANCELLK (LINUX_F_SPECIFIC_BASE + 5)
+#define LINUX_F_DUPFD_CLOEXEC (LINUX_F_SPECIFIC_BASE + 6)
+#define LINUX_F_NOTIFY (LINUX_F_SPECIFIC_BASE + 2)
+#define LINUX_F_SETPIPE_SZ (LINUX_F_SPECIFIC_BASE + 7)
+#define LINUX_F_GETPIPE_SZ (LINUX_F_SPECIFIC_BASE + 8)
+
+#define LINUX_F_ADD_SEALS (LINUX_F_SPECIFIC_BASE + 9)
+#define LINUX_F_GET_SEALS (LINUX_F_SPECIFIC_BASE + 10)
+
+#define LINUX_F_GETLKP 36
+#define LINUX_F_SETLKP 37
+#define LINUX_F_SETLKPW 38
+
+#define LINUX_F_OWNER_TID 0
+#define LINUX_F_OWNER_PID 1
+#define LINUX_F_OWNER_PGRP 2
+
+#ifndef LINUX_F_RDLCK
+#define LINUX_F_RDLCK 0
+#define LINUX_F_WRLCK 1
+#define LINUX_F_UNLCK 2
+#endif
+
+/*
+ * renameat2 flags
+ */
+#define LINUX_RENAME_NOREPLACE 0x00000001
+#define LINUX_RENAME_EXCHANGE 0x00000002
+#define LINUX_RENAME_WHITEOUT 0x00000004
+
+/*
+ * sync_file_range flags
+ */
+#define LINUX_SYNC_FILE_RANGE_WAIT_BEFORE 1
+#define LINUX_SYNC_FILE_RANGE_WRITE 2
+#define LINUX_SYNC_FILE_RANGE_WAIT_AFTER 4
+
+#define LINUX_F_SEAL_SEAL 0x0001
+#define LINUX_F_SEAL_SHRINK 0x0002
+#define LINUX_F_SEAL_GROW 0x0004
+#define LINUX_F_SEAL_WRITE 0x0008
+
+#define LINUX_MFD_CLOEXEC 0x0001
+#define LINUX_MFD_ALLOW_SEALING 0x0002
+#define LINUX_MFD_HUGETLB 0x0004
+
+#define LINUX_HUGETLB_FLAG_ENCODE_SHIFT 26
+#define LINUX_HUGETLB_FLAG_ENCODE_MASK 0x3f
+
+#define LINUX_HUGETLB_FLAG_ENCODE_64KB (16 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT)
+#define LINUX_HUGETLB_FLAG_ENCODE_512KB (19 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT)
+#define LINUX_HUGETLB_FLAG_ENCODE_1MB (20 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT)
+#define LINUX_HUGETLB_FLAG_ENCODE_2MB (21 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT)
+#define LINUX_HUGETLB_FLAG_ENCODE_8MB (23 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT)
+#define LINUX_HUGETLB_FLAG_ENCODE_16MB (24 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT)
+#define LINUX_HUGETLB_FLAG_ENCODE_32MB (25 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT)
+#define LINUX_HUGETLB_FLAG_ENCODE_256MB (28 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT)
+#define LINUX_HUGETLB_FLAG_ENCODE_512MB (29 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT)
+#define LINUX_HUGETLB_FLAG_ENCODE_1GB (30 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT)
+#define LINUX_HUGETLB_FLAG_ENCODE_2GB (31 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT)
+#define LINUX_HUGETLB_FLAG_ENCODE_16GB (34U << LINUX_HUGETLB_FLAG_ENCODE_SHIFT)
+
+struct l_file_handle {
+ l_uint handle_bytes;
+ l_int handle_type;
+ unsigned char f_handle[0];
+};
+
+#endif /* !_LINUX_FILE_H_ */
diff --git a/sys/compat/linux/linux_fork.c b/sys/compat/linux/linux_fork.c
new file mode 100644
index 000000000000..3ba40fc2705e
--- /dev/null
+++ b/sys/compat/linux/linux_fork.c
@@ -0,0 +1,449 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2004 Tim J. Robbins
+ * Copyright (c) 2002 Doug Rabson
+ * Copyright (c) 2000 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_compat.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/imgact.h>
+#include <sys/ktr.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/ptrace.h>
+#include <sys/racct.h>
+#include <sys/sched.h>
+#include <sys/syscallsubr.h>
+#include <sys/sx.h>
+#include <sys/umtx.h>
+#include <sys/unistd.h>
+#include <sys/wait.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+
+#ifdef COMPAT_LINUX32
+#include <machine/../linux32/linux.h>
+#include <machine/../linux32/linux32_proto.h>
+#else
+#include <machine/../linux/linux.h>
+#include <machine/../linux/linux_proto.h>
+#endif
+#include <compat/linux/linux_emul.h>
+#include <compat/linux/linux_futex.h>
+#include <compat/linux/linux_misc.h>
+#include <compat/linux/linux_util.h>
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_fork(struct thread *td, struct linux_fork_args *args)
+{
+ struct fork_req fr;
+ int error;
+ struct proc *p2;
+ struct thread *td2;
+
+ bzero(&fr, sizeof(fr));
+ fr.fr_flags = RFFDG | RFPROC | RFSTOPPED;
+ fr.fr_procp = &p2;
+ if ((error = fork1(td, &fr)) != 0)
+ return (error);
+
+ td2 = FIRST_THREAD_IN_PROC(p2);
+
+ linux_proc_init(td, td2, 0);
+
+ td->td_retval[0] = p2->p_pid;
+
+ /*
+ * Make this runnable after we are finished with it.
+ */
+ thread_lock(td2);
+ TD_SET_CAN_RUN(td2);
+ sched_add(td2, SRQ_BORING);
+
+ return (0);
+}
+
+int
+linux_vfork(struct thread *td, struct linux_vfork_args *args)
+{
+ struct fork_req fr;
+ int error;
+ struct proc *p2;
+ struct thread *td2;
+
+ bzero(&fr, sizeof(fr));
+ fr.fr_flags = RFFDG | RFPROC | RFMEM | RFPPWAIT | RFSTOPPED;
+ fr.fr_procp = &p2;
+ if ((error = fork1(td, &fr)) != 0)
+ return (error);
+
+ td2 = FIRST_THREAD_IN_PROC(p2);
+
+ linux_proc_init(td, td2, 0);
+
+ td->td_retval[0] = p2->p_pid;
+
+ /*
+ * Make this runnable after we are finished with it.
+ */
+ thread_lock(td2);
+ TD_SET_CAN_RUN(td2);
+ sched_add(td2, SRQ_BORING);
+
+ return (0);
+}
+#endif
+
+static int
+linux_clone_proc(struct thread *td, struct linux_clone_args *args)
+{
+ struct fork_req fr;
+ int error, ff = RFPROC | RFSTOPPED, f2;
+ struct proc *p2;
+ struct thread *td2;
+ int exit_signal;
+ struct linux_emuldata *em;
+
+ f2 = 0;
+ exit_signal = args->flags & 0x000000ff;
+ if (LINUX_SIG_VALID(exit_signal)) {
+ exit_signal = linux_to_bsd_signal(exit_signal);
+ } else if (exit_signal != 0)
+ return (EINVAL);
+
+ if (args->flags & LINUX_CLONE_VM)
+ ff |= RFMEM;
+ if (args->flags & LINUX_CLONE_SIGHAND)
+ ff |= RFSIGSHARE;
+ if (args->flags & LINUX_CLONE_FILES) {
+ if (!(args->flags & LINUX_CLONE_FS))
+ f2 |= FR2_SHARE_PATHS;
+ } else {
+ ff |= RFFDG;
+ if (args->flags & LINUX_CLONE_FS)
+ f2 |= FR2_SHARE_PATHS;
+ }
+
+ if (args->flags & LINUX_CLONE_PARENT_SETTID)
+ if (args->parent_tidptr == NULL)
+ return (EINVAL);
+
+ if (args->flags & LINUX_CLONE_VFORK)
+ ff |= RFPPWAIT;
+
+ bzero(&fr, sizeof(fr));
+ fr.fr_flags = ff;
+ fr.fr_flags2 = f2;
+ fr.fr_procp = &p2;
+ error = fork1(td, &fr);
+ if (error)
+ return (error);
+
+ td2 = FIRST_THREAD_IN_PROC(p2);
+
+ /* create the emuldata */
+ linux_proc_init(td, td2, args->flags);
+
+ em = em_find(td2);
+ KASSERT(em != NULL, ("clone_proc: emuldata not found.\n"));
+
+ if (args->flags & LINUX_CLONE_CHILD_SETTID)
+ em->child_set_tid = args->child_tidptr;
+ else
+ em->child_set_tid = NULL;
+
+ if (args->flags & LINUX_CLONE_CHILD_CLEARTID)
+ em->child_clear_tid = args->child_tidptr;
+ else
+ em->child_clear_tid = NULL;
+
+ if (args->flags & LINUX_CLONE_PARENT_SETTID) {
+ error = copyout(&p2->p_pid, args->parent_tidptr,
+ sizeof(p2->p_pid));
+ if (error)
+ linux_msg(td, "copyout p_pid failed!");
+ }
+
+ PROC_LOCK(p2);
+ p2->p_sigparent = exit_signal;
+ PROC_UNLOCK(p2);
+ /*
+ * In a case of stack = NULL, we are supposed to COW calling process
+ * stack. This is what normal fork() does, so we just keep tf_rsp arg
+ * intact.
+ */
+ linux_set_upcall_kse(td2, PTROUT(args->stack));
+
+ if (args->flags & LINUX_CLONE_SETTLS)
+ linux_set_cloned_tls(td2, args->tls);
+
+ /*
+ * If CLONE_PARENT is set, then the parent of the new process will be
+ * the same as that of the calling process.
+ */
+ if (args->flags & LINUX_CLONE_PARENT) {
+ sx_xlock(&proctree_lock);
+ PROC_LOCK(p2);
+ proc_reparent(p2, td->td_proc->p_pptr, true);
+ PROC_UNLOCK(p2);
+ sx_xunlock(&proctree_lock);
+ }
+
+ /*
+ * Make this runnable after we are finished with it.
+ */
+ thread_lock(td2);
+ TD_SET_CAN_RUN(td2);
+ sched_add(td2, SRQ_BORING);
+
+ td->td_retval[0] = p2->p_pid;
+
+ return (0);
+}
+
+static int
+linux_clone_thread(struct thread *td, struct linux_clone_args *args)
+{
+ struct linux_emuldata *em;
+ struct thread *newtd;
+ struct proc *p;
+ int error;
+
+ LINUX_CTR4(clone_thread, "thread(%d) flags %x ptid %p ctid %p",
+ td->td_tid, (unsigned)args->flags,
+ args->parent_tidptr, args->child_tidptr);
+
+ if ((args->flags & LINUX_CLONE_PARENT) != 0)
+ return (EINVAL);
+ if (args->flags & LINUX_CLONE_PARENT_SETTID)
+ if (args->parent_tidptr == NULL)
+ return (EINVAL);
+
+ /* Threads should be created with own stack */
+ if (args->stack == NULL)
+ return (EINVAL);
+
+ p = td->td_proc;
+
+#ifdef RACCT
+ if (racct_enable) {
+ PROC_LOCK(p);
+ error = racct_add(p, RACCT_NTHR, 1);
+ PROC_UNLOCK(p);
+ if (error != 0)
+ return (EPROCLIM);
+ }
+#endif
+
+ /* Initialize our td */
+ error = kern_thr_alloc(p, 0, &newtd);
+ if (error)
+ goto fail;
+
+ cpu_copy_thread(newtd, td);
+
+ bzero(&newtd->td_startzero,
+ __rangeof(struct thread, td_startzero, td_endzero));
+ bcopy(&td->td_startcopy, &newtd->td_startcopy,
+ __rangeof(struct thread, td_startcopy, td_endcopy));
+
+ newtd->td_proc = p;
+ thread_cow_get(newtd, td);
+
+ /* create the emuldata */
+ linux_proc_init(td, newtd, args->flags);
+
+ em = em_find(newtd);
+ KASSERT(em != NULL, ("clone_thread: emuldata not found.\n"));
+
+ if (args->flags & LINUX_CLONE_SETTLS)
+ linux_set_cloned_tls(newtd, args->tls);
+
+ if (args->flags & LINUX_CLONE_CHILD_SETTID)
+ em->child_set_tid = args->child_tidptr;
+ else
+ em->child_set_tid = NULL;
+
+ if (args->flags & LINUX_CLONE_CHILD_CLEARTID)
+ em->child_clear_tid = args->child_tidptr;
+ else
+ em->child_clear_tid = NULL;
+
+ cpu_thread_clean(newtd);
+
+ linux_set_upcall_kse(newtd, PTROUT(args->stack));
+
+ PROC_LOCK(p);
+ p->p_flag |= P_HADTHREADS;
+ thread_link(newtd, p);
+ bcopy(p->p_comm, newtd->td_name, sizeof(newtd->td_name));
+
+ thread_lock(td);
+ /* let the scheduler know about these things. */
+ sched_fork_thread(td, newtd);
+ thread_unlock(td);
+ if (P_SHOULDSTOP(p))
+ newtd->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK;
+
+ if (p->p_ptevents & PTRACE_LWP)
+ newtd->td_dbgflags |= TDB_BORN;
+ PROC_UNLOCK(p);
+
+ tidhash_add(newtd);
+
+ LINUX_CTR2(clone_thread, "thread(%d) successful clone to %d",
+ td->td_tid, newtd->td_tid);
+
+ if (args->flags & LINUX_CLONE_PARENT_SETTID) {
+ error = copyout(&newtd->td_tid, args->parent_tidptr,
+ sizeof(newtd->td_tid));
+ if (error)
+ linux_msg(td, "clone_thread: copyout td_tid failed!");
+ }
+
+ /*
+ * Make this runnable after we are finished with it.
+ */
+ thread_lock(newtd);
+ TD_SET_CAN_RUN(newtd);
+ sched_add(newtd, SRQ_BORING);
+
+ td->td_retval[0] = newtd->td_tid;
+
+ return (0);
+
+fail:
+#ifdef RACCT
+ if (racct_enable) {
+ PROC_LOCK(p);
+ racct_sub(p, RACCT_NTHR, 1);
+ PROC_UNLOCK(p);
+ }
+#endif
+ return (error);
+}
+
+int
+linux_clone(struct thread *td, struct linux_clone_args *args)
+{
+
+ if (args->flags & LINUX_CLONE_THREAD)
+ return (linux_clone_thread(td, args));
+ else
+ return (linux_clone_proc(td, args));
+}
+
+int
+linux_exit(struct thread *td, struct linux_exit_args *args)
+{
+ struct linux_emuldata *em;
+
+ em = em_find(td);
+ KASSERT(em != NULL, ("exit: emuldata not found.\n"));
+
+ LINUX_CTR2(exit, "thread(%d) (%d)", em->em_tid, args->rval);
+
+ umtx_thread_exit(td);
+
+ linux_thread_detach(td);
+
+ /*
+ * XXX. When the last two threads of a process
+ * exit via pthread_exit() try thr_exit() first.
+ */
+ kern_thr_exit(td);
+ exit1(td, args->rval, 0);
+ /* NOTREACHED */
+}
+
+int
+linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args)
+{
+ struct linux_emuldata *em;
+
+ em = em_find(td);
+ KASSERT(em != NULL, ("set_tid_address: emuldata not found.\n"));
+
+ em->child_clear_tid = args->tidptr;
+
+ td->td_retval[0] = em->em_tid;
+
+ LINUX_CTR3(set_tid_address, "tidptr(%d) %p, returns %d",
+ em->em_tid, args->tidptr, td->td_retval[0]);
+
+ return (0);
+}
+
+void
+linux_thread_detach(struct thread *td)
+{
+ struct linux_sys_futex_args cup;
+ struct linux_emuldata *em;
+ int *child_clear_tid;
+ int error;
+
+ em = em_find(td);
+ KASSERT(em != NULL, ("thread_detach: emuldata not found.\n"));
+
+ LINUX_CTR1(thread_detach, "thread(%d)", em->em_tid);
+
+ release_futexes(td, em);
+
+ child_clear_tid = em->child_clear_tid;
+
+ if (child_clear_tid != NULL) {
+ LINUX_CTR2(thread_detach, "thread(%d) %p",
+ em->em_tid, child_clear_tid);
+
+ error = suword32(child_clear_tid, 0);
+ if (error != 0)
+ return;
+
+ cup.uaddr = child_clear_tid;
+ cup.op = LINUX_FUTEX_WAKE;
+ cup.val = 1; /* wake one */
+ cup.timeout = NULL;
+ cup.uaddr2 = NULL;
+ cup.val3 = 0;
+ error = linux_sys_futex(td, &cup);
+ /*
+ * this cannot happen at the moment and if this happens it
+ * probably means there is a user space bug
+ */
+ if (error != 0)
+ linux_msg(td, "futex stuff in thread_detach failed.");
+ }
+}
diff --git a/sys/compat/linux/linux_futex.c b/sys/compat/linux/linux_futex.c
new file mode 100644
index 000000000000..43ac318d2b51
--- /dev/null
+++ b/sys/compat/linux/linux_futex.c
@@ -0,0 +1,1319 @@
+/* $NetBSD: linux_futex.c,v 1.7 2006/07/24 19:01:49 manu Exp $ */
+
+/*-
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
+ * Copyright (c) 2009-2016 Dmitry Chagin
+ * Copyright (c) 2005 Emmanuel Dreyfus
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Emmanuel Dreyfus
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#if 0
+__KERNEL_RCSID(1, "$NetBSD: linux_futex.c,v 1.7 2006/07/24 19:01:49 manu Exp $");
+#endif
+
+#include "opt_compat.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/imgact.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/priv.h>
+#include <sys/proc.h>
+#include <sys/queue.h>
+#include <sys/sched.h>
+#include <sys/sdt.h>
+#include <sys/umtx.h>
+
+#include <vm/vm_extern.h>
+
+#ifdef COMPAT_LINUX32
+#include <machine/../linux32/linux.h>
+#include <machine/../linux32/linux32_proto.h>
+#else
+#include <machine/../linux/linux.h>
+#include <machine/../linux/linux_proto.h>
+#endif
+#include <compat/linux/linux_dtrace.h>
+#include <compat/linux/linux_emul.h>
+#include <compat/linux/linux_futex.h>
+#include <compat/linux/linux_timer.h>
+#include <compat/linux/linux_util.h>
+
+/* DTrace init */
+LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
+
+/**
+ * Futex part for the special DTrace module "locks".
+ */
+LIN_SDT_PROBE_DEFINE1(locks, futex_mtx, locked, "struct mtx *");
+LIN_SDT_PROBE_DEFINE1(locks, futex_mtx, unlock, "struct mtx *");
+
+/**
+ * Per futex probes.
+ */
+LIN_SDT_PROBE_DEFINE1(futex, futex, create, "struct sx *");
+LIN_SDT_PROBE_DEFINE1(futex, futex, destroy, "struct sx *");
+
+/**
+ * DTrace probes in this module.
+ */
+LIN_SDT_PROBE_DEFINE2(futex, futex_put, entry, "struct futex *",
+ "struct waiting_proc *");
+LIN_SDT_PROBE_DEFINE3(futex, futex_put, destroy, "uint32_t *", "uint32_t",
+ "int");
+LIN_SDT_PROBE_DEFINE3(futex, futex_put, unlock, "uint32_t *", "uint32_t",
+ "int");
+LIN_SDT_PROBE_DEFINE0(futex, futex_put, return);
+LIN_SDT_PROBE_DEFINE3(futex, futex_get0, entry, "uint32_t *", "struct futex **",
+ "uint32_t");
+LIN_SDT_PROBE_DEFINE1(futex, futex_get0, umtx_key_get_error, "int");
+LIN_SDT_PROBE_DEFINE3(futex, futex_get0, shared, "uint32_t *", "uint32_t",
+ "int");
+LIN_SDT_PROBE_DEFINE1(futex, futex_get0, null, "uint32_t *");
+LIN_SDT_PROBE_DEFINE3(futex, futex_get0, new, "uint32_t *", "uint32_t", "int");
+LIN_SDT_PROBE_DEFINE1(futex, futex_get0, return, "int");
+LIN_SDT_PROBE_DEFINE3(futex, futex_get, entry, "uint32_t *",
+ "struct waiting_proc **", "struct futex **");
+LIN_SDT_PROBE_DEFINE0(futex, futex_get, error);
+LIN_SDT_PROBE_DEFINE1(futex, futex_get, return, "int");
+LIN_SDT_PROBE_DEFINE3(futex, futex_sleep, entry, "struct futex *",
+ "struct waiting_proc **", "struct timespec *");
+LIN_SDT_PROBE_DEFINE5(futex, futex_sleep, requeue_error, "int", "uint32_t *",
+ "struct waiting_proc *", "uint32_t *", "uint32_t");
+LIN_SDT_PROBE_DEFINE3(futex, futex_sleep, sleep_error, "int", "uint32_t *",
+ "struct waiting_proc *");
+LIN_SDT_PROBE_DEFINE1(futex, futex_sleep, return, "int");
+LIN_SDT_PROBE_DEFINE3(futex, futex_wake, entry, "struct futex *", "int",
+ "uint32_t");
+LIN_SDT_PROBE_DEFINE3(futex, futex_wake, iterate, "uint32_t",
+ "struct waiting_proc *", "uint32_t");
+LIN_SDT_PROBE_DEFINE1(futex, futex_wake, wakeup, "struct waiting_proc *");
+LIN_SDT_PROBE_DEFINE1(futex, futex_wake, return, "int");
+LIN_SDT_PROBE_DEFINE4(futex, futex_requeue, entry, "struct futex *", "int",
+ "struct futex *", "int");
+LIN_SDT_PROBE_DEFINE1(futex, futex_requeue, wakeup, "struct waiting_proc *");
+LIN_SDT_PROBE_DEFINE3(futex, futex_requeue, requeue, "uint32_t *",
+ "struct waiting_proc *", "uint32_t");
+LIN_SDT_PROBE_DEFINE1(futex, futex_requeue, return, "int");
+LIN_SDT_PROBE_DEFINE4(futex, futex_wait, entry, "struct futex *",
+ "struct waiting_proc **", "struct timespec *", "uint32_t");
+LIN_SDT_PROBE_DEFINE1(futex, futex_wait, sleep_error, "int");
+LIN_SDT_PROBE_DEFINE1(futex, futex_wait, return, "int");
+LIN_SDT_PROBE_DEFINE3(futex, futex_atomic_op, entry, "struct thread *",
+ "int", "uint32_t");
+LIN_SDT_PROBE_DEFINE4(futex, futex_atomic_op, decoded_op, "int", "int", "int",
+ "int");
+LIN_SDT_PROBE_DEFINE0(futex, futex_atomic_op, missing_access_check);
+LIN_SDT_PROBE_DEFINE1(futex, futex_atomic_op, unimplemented_op, "int");
+LIN_SDT_PROBE_DEFINE1(futex, futex_atomic_op, unimplemented_cmp, "int");
+LIN_SDT_PROBE_DEFINE1(futex, futex_atomic_op, return, "int");
+LIN_SDT_PROBE_DEFINE2(futex, linux_sys_futex, entry, "struct thread *",
+ "struct linux_sys_futex_args *");
+LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, unimplemented_clockswitch);
+LIN_SDT_PROBE_DEFINE1(futex, linux_sys_futex, copyin_error, "int");
+LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, invalid_cmp_requeue_use);
+LIN_SDT_PROBE_DEFINE3(futex, linux_sys_futex, debug_wait, "uint32_t *",
+ "uint32_t", "uint32_t");
+LIN_SDT_PROBE_DEFINE4(futex, linux_sys_futex, debug_wait_value_neq,
+ "uint32_t *", "uint32_t", "int", "uint32_t");
+LIN_SDT_PROBE_DEFINE3(futex, linux_sys_futex, debug_wake, "uint32_t *",
+ "uint32_t", "uint32_t");
+LIN_SDT_PROBE_DEFINE5(futex, linux_sys_futex, debug_cmp_requeue, "uint32_t *",
+ "uint32_t", "uint32_t", "uint32_t *", "struct l_timespec *");
+LIN_SDT_PROBE_DEFINE2(futex, linux_sys_futex, debug_cmp_requeue_value_neq,
+ "uint32_t", "int");
+LIN_SDT_PROBE_DEFINE5(futex, linux_sys_futex, debug_wake_op, "uint32_t *",
+ "int", "uint32_t", "uint32_t *", "uint32_t");
+LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, unhandled_efault);
+LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, unimplemented_lock_pi);
+LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, unimplemented_unlock_pi);
+LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, unimplemented_trylock_pi);
+LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, deprecated_requeue);
+LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, unimplemented_wait_requeue_pi);
+LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, unimplemented_cmp_requeue_pi);
+LIN_SDT_PROBE_DEFINE1(futex, linux_sys_futex, unknown_operation, "int");
+LIN_SDT_PROBE_DEFINE1(futex, linux_sys_futex, return, "int");
+LIN_SDT_PROBE_DEFINE2(futex, linux_set_robust_list, entry, "struct thread *",
+ "struct linux_set_robust_list_args *");
+LIN_SDT_PROBE_DEFINE0(futex, linux_set_robust_list, size_error);
+LIN_SDT_PROBE_DEFINE1(futex, linux_set_robust_list, return, "int");
+LIN_SDT_PROBE_DEFINE2(futex, linux_get_robust_list, entry, "struct thread *",
+ "struct linux_get_robust_list_args *");
+LIN_SDT_PROBE_DEFINE1(futex, linux_get_robust_list, copyout_error, "int");
+LIN_SDT_PROBE_DEFINE1(futex, linux_get_robust_list, return, "int");
+LIN_SDT_PROBE_DEFINE3(futex, handle_futex_death, entry,
+ "struct linux_emuldata *", "uint32_t *", "unsigned int");
+LIN_SDT_PROBE_DEFINE1(futex, handle_futex_death, copyin_error, "int");
+LIN_SDT_PROBE_DEFINE1(futex, handle_futex_death, return, "int");
+LIN_SDT_PROBE_DEFINE3(futex, fetch_robust_entry, entry,
+ "struct linux_robust_list **", "struct linux_robust_list **",
+ "unsigned int *");
+LIN_SDT_PROBE_DEFINE1(futex, fetch_robust_entry, copyin_error, "int");
+LIN_SDT_PROBE_DEFINE1(futex, fetch_robust_entry, return, "int");
+LIN_SDT_PROBE_DEFINE2(futex, release_futexes, entry, "struct thread *",
+ "struct linux_emuldata *");
+LIN_SDT_PROBE_DEFINE1(futex, release_futexes, copyin_error, "int");
+LIN_SDT_PROBE_DEFINE0(futex, release_futexes, return);
+
+struct futex;
+
+struct waiting_proc {
+ uint32_t wp_flags;
+ struct futex *wp_futex;
+ TAILQ_ENTRY(waiting_proc) wp_list;
+};
+
+struct futex {
+ struct mtx f_lck;
+ uint32_t *f_uaddr; /* user-supplied value, for debug */
+ struct umtx_key f_key;
+ uint32_t f_refcount;
+ uint32_t f_bitset;
+ LIST_ENTRY(futex) f_list;
+ TAILQ_HEAD(lf_waiting_proc, waiting_proc) f_waiting_proc;
+};
+
+#define FUTEX_LOCK(f) mtx_lock(&(f)->f_lck)
+#define FUTEX_LOCKED(f) mtx_owned(&(f)->f_lck)
+#define FUTEX_UNLOCK(f) mtx_unlock(&(f)->f_lck)
+#define FUTEX_INIT(f) do { \
+ mtx_init(&(f)->f_lck, "ftlk", NULL, \
+ MTX_DUPOK); \
+ LIN_SDT_PROBE1(futex, futex, create, \
+ &(f)->f_lck); \
+ } while (0)
+#define FUTEX_DESTROY(f) do { \
+ LIN_SDT_PROBE1(futex, futex, destroy, \
+ &(f)->f_lck); \
+ mtx_destroy(&(f)->f_lck); \
+ } while (0)
+#define FUTEX_ASSERT_LOCKED(f) mtx_assert(&(f)->f_lck, MA_OWNED)
+#define FUTEX_ASSERT_UNLOCKED(f) mtx_assert(&(f)->f_lck, MA_NOTOWNED)
+
+#define FUTEXES_LOCK do { \
+ mtx_lock(&futex_mtx); \
+ LIN_SDT_PROBE1(locks, futex_mtx, \
+ locked, &futex_mtx); \
+ } while (0)
+#define FUTEXES_UNLOCK do { \
+ LIN_SDT_PROBE1(locks, futex_mtx, \
+ unlock, &futex_mtx); \
+ mtx_unlock(&futex_mtx); \
+ } while (0)
+
+/* flags for futex_get() */
+#define FUTEX_CREATE_WP 0x1 /* create waiting_proc */
+#define FUTEX_DONTCREATE 0x2 /* don't create futex if not exists */
+#define FUTEX_DONTEXISTS 0x4 /* return EINVAL if futex exists */
+#define FUTEX_SHARED 0x8 /* shared futex */
+#define FUTEX_DONTLOCK 0x10 /* don't lock futex */
+
+/* wp_flags */
+#define FUTEX_WP_REQUEUED 0x1 /* wp requeued - wp moved from wp_list
+ * of futex where thread sleep to wp_list
+ * of another futex.
+ */
+#define FUTEX_WP_REMOVED 0x2 /* wp is woken up and removed from futex
+ * wp_list to prevent double wakeup.
+ */
+
+static void futex_put(struct futex *, struct waiting_proc *);
+static int futex_get0(uint32_t *, struct futex **f, uint32_t);
+static int futex_get(uint32_t *, struct waiting_proc **, struct futex **,
+ uint32_t);
+static int futex_sleep(struct futex *, struct waiting_proc *, struct timespec *);
+static int futex_wake(struct futex *, int, uint32_t);
+static int futex_requeue(struct futex *, int, struct futex *, int);
+static int futex_copyin_timeout(int, struct l_timespec *, int,
+ struct timespec *);
+static int futex_wait(struct futex *, struct waiting_proc *, struct timespec *,
+ uint32_t);
+static void futex_lock(struct futex *);
+static void futex_unlock(struct futex *);
+static int futex_atomic_op(struct thread *, int, uint32_t *);
+static int handle_futex_death(struct linux_emuldata *, uint32_t *,
+ unsigned int);
+static int fetch_robust_entry(struct linux_robust_list **,
+ struct linux_robust_list **, unsigned int *);
+
+static int
+futex_copyin_timeout(int op, struct l_timespec *luts, int clockrt,
+ struct timespec *ts)
+{
+ struct l_timespec lts;
+ struct timespec kts;
+ int error;
+
+ error = copyin(luts, &lts, sizeof(lts));
+ if (error)
+ return (error);
+
+ error = linux_to_native_timespec(ts, &lts);
+ if (error)
+ return (error);
+ if (clockrt) {
+ nanotime(&kts);
+ timespecsub(ts, &kts, ts);
+ } else if (op == LINUX_FUTEX_WAIT_BITSET) {
+ nanouptime(&kts);
+ timespecsub(ts, &kts, ts);
+ }
+ return (error);
+}
+
+static void
+futex_put(struct futex *f, struct waiting_proc *wp)
+{
+ LIN_SDT_PROBE2(futex, futex_put, entry, f, wp);
+
+ if (wp != NULL) {
+ if ((wp->wp_flags & FUTEX_WP_REMOVED) == 0)
+ TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list);
+ free(wp, M_FUTEX_WP);
+ }
+
+ FUTEXES_LOCK;
+ if (--f->f_refcount == 0) {
+ LIST_REMOVE(f, f_list);
+ FUTEXES_UNLOCK;
+ if (FUTEX_LOCKED(f))
+ futex_unlock(f);
+
+ LIN_SDT_PROBE3(futex, futex_put, destroy, f->f_uaddr,
+ f->f_refcount, f->f_key.shared);
+ LINUX_CTR3(sys_futex, "futex_put destroy uaddr %p ref %d "
+ "shared %d", f->f_uaddr, f->f_refcount, f->f_key.shared);
+ umtx_key_release(&f->f_key);
+ FUTEX_DESTROY(f);
+ free(f, M_FUTEX);
+
+ LIN_SDT_PROBE0(futex, futex_put, return);
+ return;
+ }
+
+ LIN_SDT_PROBE3(futex, futex_put, unlock, f->f_uaddr, f->f_refcount,
+ f->f_key.shared);
+ LINUX_CTR3(sys_futex, "futex_put uaddr %p ref %d shared %d",
+ f->f_uaddr, f->f_refcount, f->f_key.shared);
+ if (FUTEX_LOCKED(f))
+ futex_unlock(f);
+ FUTEXES_UNLOCK;
+
+ LIN_SDT_PROBE0(futex, futex_put, return);
+}
+
+static int
+futex_get0(uint32_t *uaddr, struct futex **newf, uint32_t flags)
+{
+ struct futex *f, *tmpf;
+ struct umtx_key key;
+ int error;
+
+ LIN_SDT_PROBE3(futex, futex_get0, entry, uaddr, newf, flags);
+
+ *newf = tmpf = NULL;
+
+ error = umtx_key_get(uaddr, TYPE_FUTEX, (flags & FUTEX_SHARED) ?
+ AUTO_SHARE : THREAD_SHARE, &key);
+ if (error) {
+ LIN_SDT_PROBE1(futex, futex_get0, umtx_key_get_error, error);
+ LIN_SDT_PROBE1(futex, futex_get0, return, error);
+ return (error);
+ }
+retry:
+ FUTEXES_LOCK;
+ LIST_FOREACH(f, &futex_list, f_list) {
+ if (umtx_key_match(&f->f_key, &key)) {
+ if (tmpf != NULL) {
+ if (FUTEX_LOCKED(tmpf))
+ futex_unlock(tmpf);
+ FUTEX_DESTROY(tmpf);
+ free(tmpf, M_FUTEX);
+ }
+ if (flags & FUTEX_DONTEXISTS) {
+ FUTEXES_UNLOCK;
+ umtx_key_release(&key);
+
+ LIN_SDT_PROBE1(futex, futex_get0, return,
+ EINVAL);
+ return (EINVAL);
+ }
+
+ /*
+ * Increment refcount of the found futex to
+ * prevent it from deallocation before FUTEX_LOCK()
+ */
+ ++f->f_refcount;
+ FUTEXES_UNLOCK;
+ umtx_key_release(&key);
+
+ if ((flags & FUTEX_DONTLOCK) == 0)
+ futex_lock(f);
+ *newf = f;
+ LIN_SDT_PROBE3(futex, futex_get0, shared, uaddr,
+ f->f_refcount, f->f_key.shared);
+ LINUX_CTR3(sys_futex, "futex_get uaddr %p ref %d shared %d",
+ uaddr, f->f_refcount, f->f_key.shared);
+
+ LIN_SDT_PROBE1(futex, futex_get0, return, 0);
+ return (0);
+ }
+ }
+
+ if (flags & FUTEX_DONTCREATE) {
+ FUTEXES_UNLOCK;
+ umtx_key_release(&key);
+ LIN_SDT_PROBE1(futex, futex_get0, null, uaddr);
+ LINUX_CTR1(sys_futex, "futex_get uaddr %p null", uaddr);
+
+ LIN_SDT_PROBE1(futex, futex_get0, return, 0);
+ return (0);
+ }
+
+ if (tmpf == NULL) {
+ FUTEXES_UNLOCK;
+ tmpf = malloc(sizeof(*tmpf), M_FUTEX, M_WAITOK | M_ZERO);
+ tmpf->f_uaddr = uaddr;
+ tmpf->f_key = key;
+ tmpf->f_refcount = 1;
+ tmpf->f_bitset = FUTEX_BITSET_MATCH_ANY;
+ FUTEX_INIT(tmpf);
+ TAILQ_INIT(&tmpf->f_waiting_proc);
+
+ /*
+ * Lock the new futex before an insert into the futex_list
+ * to prevent futex usage by other.
+ */
+ if ((flags & FUTEX_DONTLOCK) == 0)
+ futex_lock(tmpf);
+ goto retry;
+ }
+
+ LIST_INSERT_HEAD(&futex_list, tmpf, f_list);
+ FUTEXES_UNLOCK;
+
+ LIN_SDT_PROBE3(futex, futex_get0, new, uaddr, tmpf->f_refcount,
+ tmpf->f_key.shared);
+ LINUX_CTR3(sys_futex, "futex_get uaddr %p ref %d shared %d new",
+ uaddr, tmpf->f_refcount, tmpf->f_key.shared);
+ *newf = tmpf;
+
+ LIN_SDT_PROBE1(futex, futex_get0, return, 0);
+ return (0);
+}
+
+static int
+futex_get(uint32_t *uaddr, struct waiting_proc **wp, struct futex **f,
+ uint32_t flags)
+{
+ int error;
+
+ LIN_SDT_PROBE3(futex, futex_get, entry, uaddr, wp, f);
+
+ if (flags & FUTEX_CREATE_WP) {
+ *wp = malloc(sizeof(struct waiting_proc), M_FUTEX_WP, M_WAITOK);
+ (*wp)->wp_flags = 0;
+ }
+ error = futex_get0(uaddr, f, flags);
+ if (error) {
+ LIN_SDT_PROBE0(futex, futex_get, error);
+
+ if (flags & FUTEX_CREATE_WP)
+ free(*wp, M_FUTEX_WP);
+
+ LIN_SDT_PROBE1(futex, futex_get, return, error);
+ return (error);
+ }
+ if (flags & FUTEX_CREATE_WP) {
+ TAILQ_INSERT_HEAD(&(*f)->f_waiting_proc, *wp, wp_list);
+ (*wp)->wp_futex = *f;
+ }
+
+ LIN_SDT_PROBE1(futex, futex_get, return, error);
+ return (error);
+}
+
+static inline void
+futex_lock(struct futex *f)
+{
+
+ LINUX_CTR3(sys_futex, "futex_lock uaddr %p ref %d shared %d",
+ f->f_uaddr, f->f_refcount, f->f_key.shared);
+ FUTEX_ASSERT_UNLOCKED(f);
+ FUTEX_LOCK(f);
+}
+
+static inline void
+futex_unlock(struct futex *f)
+{
+
+ LINUX_CTR3(sys_futex, "futex_unlock uaddr %p ref %d shared %d",
+ f->f_uaddr, f->f_refcount, f->f_key.shared);
+ FUTEX_ASSERT_LOCKED(f);
+ FUTEX_UNLOCK(f);
+}
+
+static int
+futex_sleep(struct futex *f, struct waiting_proc *wp, struct timespec *ts)
+{
+ struct timespec uts;
+ sbintime_t sbt, prec, tmp;
+ time_t over;
+ int error;
+
+ FUTEX_ASSERT_LOCKED(f);
+ if (ts != NULL) {
+ uts = *ts;
+ if (uts.tv_sec > INT32_MAX / 2) {
+ over = uts.tv_sec - INT32_MAX / 2;
+ uts.tv_sec -= over;
+ }
+ tmp = tstosbt(uts);
+ if (TIMESEL(&sbt, tmp))
+ sbt += tc_tick_sbt;
+ sbt += tmp;
+ prec = tmp;
+ prec >>= tc_precexp;
+ } else {
+ sbt = 0;
+ prec = 0;
+ }
+ LIN_SDT_PROBE3(futex, futex_sleep, entry, f, wp, sbt);
+ LINUX_CTR4(sys_futex, "futex_sleep enter uaddr %p wp %p timo %ld ref %d",
+ f->f_uaddr, wp, sbt, f->f_refcount);
+
+ error = msleep_sbt(wp, &f->f_lck, PCATCH, "futex", sbt, prec, C_ABSOLUTE);
+ if (wp->wp_flags & FUTEX_WP_REQUEUED) {
+ KASSERT(f != wp->wp_futex, ("futex != wp_futex"));
+
+ if (error) {
+ LIN_SDT_PROBE5(futex, futex_sleep, requeue_error, error,
+ f->f_uaddr, wp, wp->wp_futex->f_uaddr,
+ wp->wp_futex->f_refcount);
+ }
+
+ LINUX_CTR5(sys_futex, "futex_sleep out error %d uaddr %p wp"
+ " %p requeued uaddr %p ref %d",
+ error, f->f_uaddr, wp, wp->wp_futex->f_uaddr,
+ wp->wp_futex->f_refcount);
+ futex_put(f, NULL);
+ f = wp->wp_futex;
+ futex_lock(f);
+ } else {
+ if (error) {
+ LIN_SDT_PROBE3(futex, futex_sleep, sleep_error, error,
+ f->f_uaddr, wp);
+ }
+ LINUX_CTR3(sys_futex, "futex_sleep out error %d uaddr %p wp %p",
+ error, f->f_uaddr, wp);
+ }
+
+ futex_put(f, wp);
+
+ LIN_SDT_PROBE1(futex, futex_sleep, return, error);
+ return (error);
+}
+
+static int
+futex_wake(struct futex *f, int n, uint32_t bitset)
+{
+ struct waiting_proc *wp, *wpt;
+ int count = 0;
+
+ LIN_SDT_PROBE3(futex, futex_wake, entry, f, n, bitset);
+
+ if (bitset == 0) {
+ LIN_SDT_PROBE1(futex, futex_wake, return, EINVAL);
+ return (EINVAL);
+ }
+
+ FUTEX_ASSERT_LOCKED(f);
+ TAILQ_FOREACH_SAFE(wp, &f->f_waiting_proc, wp_list, wpt) {
+ LIN_SDT_PROBE3(futex, futex_wake, iterate, f->f_uaddr, wp,
+ f->f_refcount);
+ LINUX_CTR3(sys_futex, "futex_wake uaddr %p wp %p ref %d",
+ f->f_uaddr, wp, f->f_refcount);
+ /*
+ * Unless we find a matching bit in
+ * the bitset, continue searching.
+ */
+ if (!(wp->wp_futex->f_bitset & bitset))
+ continue;
+
+ wp->wp_flags |= FUTEX_WP_REMOVED;
+ TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list);
+ LIN_SDT_PROBE1(futex, futex_wake, wakeup, wp);
+ wakeup_one(wp);
+ if (++count == n)
+ break;
+ }
+
+ LIN_SDT_PROBE1(futex, futex_wake, return, count);
+ return (count);
+}
+
+static int
+futex_requeue(struct futex *f, int n, struct futex *f2, int n2)
+{
+ struct waiting_proc *wp, *wpt;
+ int count = 0;
+
+ LIN_SDT_PROBE4(futex, futex_requeue, entry, f, n, f2, n2);
+
+ FUTEX_ASSERT_LOCKED(f);
+ FUTEX_ASSERT_LOCKED(f2);
+
+ TAILQ_FOREACH_SAFE(wp, &f->f_waiting_proc, wp_list, wpt) {
+ if (++count <= n) {
+ LINUX_CTR2(sys_futex, "futex_req_wake uaddr %p wp %p",
+ f->f_uaddr, wp);
+ wp->wp_flags |= FUTEX_WP_REMOVED;
+ TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list);
+ LIN_SDT_PROBE1(futex, futex_requeue, wakeup, wp);
+ wakeup_one(wp);
+ } else {
+ LIN_SDT_PROBE3(futex, futex_requeue, requeue,
+ f->f_uaddr, wp, f2->f_uaddr);
+ LINUX_CTR3(sys_futex, "futex_requeue uaddr %p wp %p to %p",
+ f->f_uaddr, wp, f2->f_uaddr);
+ wp->wp_flags |= FUTEX_WP_REQUEUED;
+ /* Move wp to wp_list of f2 futex */
+ TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list);
+ TAILQ_INSERT_HEAD(&f2->f_waiting_proc, wp, wp_list);
+
+ /*
+ * Thread which sleeps on wp after waking should
+ * acquire f2 lock, so increment refcount of f2 to
+ * prevent it from premature deallocation.
+ */
+ wp->wp_futex = f2;
+ FUTEXES_LOCK;
+ ++f2->f_refcount;
+ FUTEXES_UNLOCK;
+ if (count - n >= n2)
+ break;
+ }
+ }
+
+ LIN_SDT_PROBE1(futex, futex_requeue, return, count);
+ return (count);
+}
+
+static int
+futex_wait(struct futex *f, struct waiting_proc *wp, struct timespec *ts,
+ uint32_t bitset)
+{
+ int error;
+
+ LIN_SDT_PROBE4(futex, futex_wait, entry, f, wp, ts, bitset);
+
+ if (bitset == 0) {
+ LIN_SDT_PROBE1(futex, futex_wait, return, EINVAL);
+ futex_put(f, wp);
+ return (EINVAL);
+ }
+
+ f->f_bitset = bitset;
+ error = futex_sleep(f, wp, ts);
+ if (error)
+ LIN_SDT_PROBE1(futex, futex_wait, sleep_error, error);
+ if (error == EWOULDBLOCK)
+ error = ETIMEDOUT;
+
+ LIN_SDT_PROBE1(futex, futex_wait, return, error);
+ return (error);
+}
+
+static int
+futex_atomic_op(struct thread *td, int encoded_op, uint32_t *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret;
+
+ LIN_SDT_PROBE3(futex, futex_atomic_op, entry, td, encoded_op, uaddr);
+
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ LIN_SDT_PROBE4(futex, futex_atomic_op, decoded_op, op, cmp, oparg,
+ cmparg);
+
+ /* XXX: Linux verifies access here and returns EFAULT */
+ LIN_SDT_PROBE0(futex, futex_atomic_op, missing_access_check);
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ ret = futex_xchgl(oparg, uaddr, &oldval);
+ break;
+ case FUTEX_OP_ADD:
+ ret = futex_addl(oparg, uaddr, &oldval);
+ break;
+ case FUTEX_OP_OR:
+ ret = futex_orl(oparg, uaddr, &oldval);
+ break;
+ case FUTEX_OP_ANDN:
+ ret = futex_andl(~oparg, uaddr, &oldval);
+ break;
+ case FUTEX_OP_XOR:
+ ret = futex_xorl(oparg, uaddr, &oldval);
+ break;
+ default:
+ LIN_SDT_PROBE1(futex, futex_atomic_op, unimplemented_op, op);
+ ret = -ENOSYS;
+ break;
+ }
+
+ if (ret) {
+ LIN_SDT_PROBE1(futex, futex_atomic_op, return, ret);
+ return (ret);
+ }
+
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ:
+ ret = (oldval == cmparg);
+ break;
+ case FUTEX_OP_CMP_NE:
+ ret = (oldval != cmparg);
+ break;
+ case FUTEX_OP_CMP_LT:
+ ret = (oldval < cmparg);
+ break;
+ case FUTEX_OP_CMP_GE:
+ ret = (oldval >= cmparg);
+ break;
+ case FUTEX_OP_CMP_LE:
+ ret = (oldval <= cmparg);
+ break;
+ case FUTEX_OP_CMP_GT:
+ ret = (oldval > cmparg);
+ break;
+ default:
+ LIN_SDT_PROBE1(futex, futex_atomic_op, unimplemented_cmp, cmp);
+ ret = -ENOSYS;
+ }
+
+ LIN_SDT_PROBE1(futex, futex_atomic_op, return, ret);
+ return (ret);
+}
+
+int
+linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args)
+{
+ int clockrt, nrwake, op_ret, ret;
+ struct linux_pemuldata *pem;
+ struct waiting_proc *wp;
+ struct futex *f, *f2;
+ struct timespec uts, *ts;
+ int error, save;
+ uint32_t flags, val;
+
+ LIN_SDT_PROBE2(futex, linux_sys_futex, entry, td, args);
+
+ if (args->op & LINUX_FUTEX_PRIVATE_FLAG) {
+ flags = 0;
+ args->op &= ~LINUX_FUTEX_PRIVATE_FLAG;
+ } else
+ flags = FUTEX_SHARED;
+
+ /*
+ * Currently support for switching between CLOCK_MONOTONIC and
+ * CLOCK_REALTIME is not present. However Linux forbids the use of
+ * FUTEX_CLOCK_REALTIME with any op except FUTEX_WAIT_BITSET and
+ * FUTEX_WAIT_REQUEUE_PI.
+ */
+ clockrt = args->op & LINUX_FUTEX_CLOCK_REALTIME;
+ args->op = args->op & ~LINUX_FUTEX_CLOCK_REALTIME;
+ if (clockrt && args->op != LINUX_FUTEX_WAIT_BITSET &&
+ args->op != LINUX_FUTEX_WAIT_REQUEUE_PI) {
+ LIN_SDT_PROBE0(futex, linux_sys_futex,
+ unimplemented_clockswitch);
+ LIN_SDT_PROBE1(futex, linux_sys_futex, return, ENOSYS);
+ return (ENOSYS);
+ }
+
+ error = 0;
+ f = f2 = NULL;
+
+ switch (args->op) {
+ case LINUX_FUTEX_WAIT:
+ args->val3 = FUTEX_BITSET_MATCH_ANY;
+ /* FALLTHROUGH */
+
+ case LINUX_FUTEX_WAIT_BITSET:
+ LIN_SDT_PROBE3(futex, linux_sys_futex, debug_wait, args->uaddr,
+ args->val, args->val3);
+ LINUX_CTR3(sys_futex, "WAIT uaddr %p val 0x%x bitset 0x%x",
+ args->uaddr, args->val, args->val3);
+
+ if (args->timeout != NULL) {
+ error = futex_copyin_timeout(args->op, args->timeout,
+ clockrt, &uts);
+ if (error) {
+ LIN_SDT_PROBE1(futex, linux_sys_futex, copyin_error,
+ error);
+ LIN_SDT_PROBE1(futex, linux_sys_futex, return, error);
+ return (error);
+ }
+ ts = &uts;
+ } else
+ ts = NULL;
+
+retry0:
+ error = futex_get(args->uaddr, &wp, &f,
+ flags | FUTEX_CREATE_WP);
+ if (error) {
+ LIN_SDT_PROBE1(futex, linux_sys_futex, return, error);
+ return (error);
+ }
+
+ error = copyin_nofault(args->uaddr, &val, sizeof(val));
+ if (error) {
+ futex_put(f, wp);
+ error = copyin(args->uaddr, &val, sizeof(val));
+ if (error == 0)
+ goto retry0;
+ LIN_SDT_PROBE1(futex, linux_sys_futex, copyin_error,
+ error);
+ LINUX_CTR1(sys_futex, "WAIT copyin failed %d",
+ error);
+ LIN_SDT_PROBE1(futex, linux_sys_futex, return, error);
+ return (error);
+ }
+ if (val != args->val) {
+ LIN_SDT_PROBE4(futex, linux_sys_futex,
+ debug_wait_value_neq, args->uaddr, args->val, val,
+ args->val3);
+ LINUX_CTR3(sys_futex,
+ "WAIT uaddr %p val 0x%x != uval 0x%x",
+ args->uaddr, args->val, val);
+ futex_put(f, wp);
+
+ LIN_SDT_PROBE1(futex, linux_sys_futex, return,
+ EWOULDBLOCK);
+ return (EWOULDBLOCK);
+ }
+
+ error = futex_wait(f, wp, ts, args->val3);
+ break;
+
+ case LINUX_FUTEX_WAKE:
+ args->val3 = FUTEX_BITSET_MATCH_ANY;
+ /* FALLTHROUGH */
+
+ case LINUX_FUTEX_WAKE_BITSET:
+ LIN_SDT_PROBE3(futex, linux_sys_futex, debug_wake, args->uaddr,
+ args->val, args->val3);
+ LINUX_CTR3(sys_futex, "WAKE uaddr %p nrwake 0x%x bitset 0x%x",
+ args->uaddr, args->val, args->val3);
+
+ error = futex_get(args->uaddr, NULL, &f,
+ flags | FUTEX_DONTCREATE);
+ if (error) {
+ LIN_SDT_PROBE1(futex, linux_sys_futex, return, error);
+ return (error);
+ }
+
+ if (f == NULL) {
+ td->td_retval[0] = 0;
+
+ LIN_SDT_PROBE1(futex, linux_sys_futex, return, error);
+ return (error);
+ }
+ td->td_retval[0] = futex_wake(f, args->val, args->val3);
+ futex_put(f, NULL);
+ break;
+
+ case LINUX_FUTEX_CMP_REQUEUE:
+ LIN_SDT_PROBE5(futex, linux_sys_futex, debug_cmp_requeue,
+ args->uaddr, args->val, args->val3, args->uaddr2,
+ args->timeout);
+ LINUX_CTR5(sys_futex, "CMP_REQUEUE uaddr %p "
+ "nrwake 0x%x uval 0x%x uaddr2 %p nrequeue 0x%x",
+ args->uaddr, args->val, args->val3, args->uaddr2,
+ args->timeout);
+
+ /*
+ * Linux allows this, we would not, it is an incorrect
+ * usage of declared ABI, so return EINVAL.
+ */
+ if (args->uaddr == args->uaddr2) {
+ LIN_SDT_PROBE0(futex, linux_sys_futex,
+ invalid_cmp_requeue_use);
+ LIN_SDT_PROBE1(futex, linux_sys_futex, return, EINVAL);
+ return (EINVAL);
+ }
+
+retry1:
+ error = futex_get(args->uaddr, NULL, &f, flags | FUTEX_DONTLOCK);
+ if (error) {
+ LIN_SDT_PROBE1(futex, linux_sys_futex, return, error);
+ return (error);
+ }
+
+ /*
+ * To avoid deadlocks return EINVAL if second futex
+ * exists at this time.
+ *
+ * Glibc fall back to FUTEX_WAKE in case of any error
+ * returned by FUTEX_CMP_REQUEUE.
+ */
+ error = futex_get(args->uaddr2, NULL, &f2,
+ flags | FUTEX_DONTEXISTS | FUTEX_DONTLOCK);
+ if (error) {
+ futex_put(f, NULL);
+
+ LIN_SDT_PROBE1(futex, linux_sys_futex, return, error);
+ return (error);
+ }
+ futex_lock(f);
+ futex_lock(f2);
+ error = copyin_nofault(args->uaddr, &val, sizeof(val));
+ if (error) {
+ futex_put(f2, NULL);
+ futex_put(f, NULL);
+ error = copyin(args->uaddr, &val, sizeof(val));
+ if (error == 0)
+ goto retry1;
+ LIN_SDT_PROBE1(futex, linux_sys_futex, copyin_error,
+ error);
+ LINUX_CTR1(sys_futex, "CMP_REQUEUE copyin failed %d",
+ error);
+ LIN_SDT_PROBE1(futex, linux_sys_futex, return, error);
+ return (error);
+ }
+ if (val != args->val3) {
+ LIN_SDT_PROBE2(futex, linux_sys_futex,
+ debug_cmp_requeue_value_neq, args->val, val);
+ LINUX_CTR2(sys_futex, "CMP_REQUEUE val 0x%x != uval 0x%x",
+ args->val, val);
+ futex_put(f2, NULL);
+ futex_put(f, NULL);
+
+ LIN_SDT_PROBE1(futex, linux_sys_futex, return, EAGAIN);
+ return (EAGAIN);
+ }
+
+ nrwake = (int)(unsigned long)args->timeout;
+ td->td_retval[0] = futex_requeue(f, args->val, f2, nrwake);
+ futex_put(f2, NULL);
+ futex_put(f, NULL);
+ break;
+
+ case LINUX_FUTEX_WAKE_OP:
+ LIN_SDT_PROBE5(futex, linux_sys_futex, debug_wake_op,
+ args->uaddr, args->op, args->val, args->uaddr2, args->val3);
+ LINUX_CTR5(sys_futex, "WAKE_OP "
+ "uaddr %p nrwake 0x%x uaddr2 %p op 0x%x nrwake2 0x%x",
+ args->uaddr, args->val, args->uaddr2, args->val3,
+ args->timeout);
+
+ if (args->uaddr == args->uaddr2) {
+ LIN_SDT_PROBE1(futex, linux_sys_futex, return, EINVAL);
+ return (EINVAL);
+ }
+
+retry2:
+ error = futex_get(args->uaddr, NULL, &f, flags | FUTEX_DONTLOCK);
+ if (error) {
+ LIN_SDT_PROBE1(futex, linux_sys_futex, return, error);
+ return (error);
+ }
+
+ error = futex_get(args->uaddr2, NULL, &f2, flags | FUTEX_DONTLOCK);
+ if (error) {
+ futex_put(f, NULL);
+
+ LIN_SDT_PROBE1(futex, linux_sys_futex, return, error);
+ return (error);
+ }
+ futex_lock(f);
+ futex_lock(f2);
+
+ /*
+ * This function returns positive number as results and
+ * negative as errors
+ */
+ save = vm_fault_disable_pagefaults();
+ op_ret = futex_atomic_op(td, args->val3, args->uaddr2);
+ vm_fault_enable_pagefaults(save);
+
+ LINUX_CTR2(sys_futex, "WAKE_OP atomic_op uaddr %p ret 0x%x",
+ args->uaddr, op_ret);
+
+ if (op_ret < 0) {
+ if (f2 != NULL)
+ futex_put(f2, NULL);
+ futex_put(f, NULL);
+ error = copyin(args->uaddr2, &val, sizeof(val));
+ if (error == 0)
+ goto retry2;
+ LIN_SDT_PROBE1(futex, linux_sys_futex, return, error);
+ return (error);
+ }
+
+ ret = futex_wake(f, args->val, args->val3);
+
+ if (op_ret > 0) {
+ op_ret = 0;
+ nrwake = (int)(unsigned long)args->timeout;
+
+ if (f2 != NULL)
+ op_ret += futex_wake(f2, nrwake, args->val3);
+ else
+ op_ret += futex_wake(f, nrwake, args->val3);
+ ret += op_ret;
+ }
+ if (f2 != NULL)
+ futex_put(f2, NULL);
+ futex_put(f, NULL);
+ td->td_retval[0] = ret;
+ break;
+
+ case LINUX_FUTEX_LOCK_PI:
+ /* not yet implemented */
+ pem = pem_find(td->td_proc);
+ if ((pem->flags & LINUX_XUNSUP_FUTEXPIOP) == 0) {
+ linux_msg(td, "unsupported FUTEX_LOCK_PI");
+ pem->flags |= LINUX_XUNSUP_FUTEXPIOP;
+ LIN_SDT_PROBE0(futex, linux_sys_futex,
+ unimplemented_lock_pi);
+ }
+ LIN_SDT_PROBE1(futex, linux_sys_futex, return, ENOSYS);
+ return (ENOSYS);
+
+ case LINUX_FUTEX_UNLOCK_PI:
+ /* not yet implemented */
+ pem = pem_find(td->td_proc);
+ if ((pem->flags & LINUX_XUNSUP_FUTEXPIOP) == 0) {
+ linux_msg(td, "unsupported FUTEX_UNLOCK_PI");
+ pem->flags |= LINUX_XUNSUP_FUTEXPIOP;
+ LIN_SDT_PROBE0(futex, linux_sys_futex,
+ unimplemented_unlock_pi);
+ }
+ LIN_SDT_PROBE1(futex, linux_sys_futex, return, ENOSYS);
+ return (ENOSYS);
+
+ case LINUX_FUTEX_TRYLOCK_PI:
+ /* not yet implemented */
+ pem = pem_find(td->td_proc);
+ if ((pem->flags & LINUX_XUNSUP_FUTEXPIOP) == 0) {
+ linux_msg(td, "unsupported FUTEX_TRYLOCK_PI");
+ pem->flags |= LINUX_XUNSUP_FUTEXPIOP;
+ LIN_SDT_PROBE0(futex, linux_sys_futex,
+ unimplemented_trylock_pi);
+ }
+ LIN_SDT_PROBE1(futex, linux_sys_futex, return, ENOSYS);
+ return (ENOSYS);
+
+ case LINUX_FUTEX_REQUEUE:
+ /*
+ * Glibc does not use this operation since version 2.3.3,
+ * as it is racy and replaced by FUTEX_CMP_REQUEUE operation.
+ * Glibc versions prior to 2.3.3 fall back to FUTEX_WAKE when
+ * FUTEX_REQUEUE returned EINVAL.
+ */
+ pem = pem_find(td->td_proc);
+ if ((pem->flags & LINUX_XDEPR_REQUEUEOP) == 0) {
+ linux_msg(td, "unsupported FUTEX_REQUEUE");
+ pem->flags |= LINUX_XDEPR_REQUEUEOP;
+ LIN_SDT_PROBE0(futex, linux_sys_futex,
+ deprecated_requeue);
+ }
+
+ LIN_SDT_PROBE1(futex, linux_sys_futex, return, EINVAL);
+ return (EINVAL);
+
+ case LINUX_FUTEX_WAIT_REQUEUE_PI:
+ /* not yet implemented */
+ pem = pem_find(td->td_proc);
+ if ((pem->flags & LINUX_XUNSUP_FUTEXPIOP) == 0) {
+ linux_msg(td, "unsupported FUTEX_WAIT_REQUEUE_PI");
+ pem->flags |= LINUX_XUNSUP_FUTEXPIOP;
+ LIN_SDT_PROBE0(futex, linux_sys_futex,
+ unimplemented_wait_requeue_pi);
+ }
+ LIN_SDT_PROBE1(futex, linux_sys_futex, return, ENOSYS);
+ return (ENOSYS);
+
+ case LINUX_FUTEX_CMP_REQUEUE_PI:
+ /* not yet implemented */
+ pem = pem_find(td->td_proc);
+ if ((pem->flags & LINUX_XUNSUP_FUTEXPIOP) == 0) {
+ linux_msg(td, "unsupported FUTEX_CMP_REQUEUE_PI");
+ pem->flags |= LINUX_XUNSUP_FUTEXPIOP;
+ LIN_SDT_PROBE0(futex, linux_sys_futex,
+ unimplemented_cmp_requeue_pi);
+ }
+ LIN_SDT_PROBE1(futex, linux_sys_futex, return, ENOSYS);
+ return (ENOSYS);
+
+ default:
+ linux_msg(td, "unsupported futex op %d", args->op);
+ LIN_SDT_PROBE1(futex, linux_sys_futex, unknown_operation,
+ args->op);
+ LIN_SDT_PROBE1(futex, linux_sys_futex, return, ENOSYS);
+ return (ENOSYS);
+ }
+
+ LIN_SDT_PROBE1(futex, linux_sys_futex, return, error);
+ return (error);
+}
+
+int
+linux_set_robust_list(struct thread *td, struct linux_set_robust_list_args *args)
+{
+ struct linux_emuldata *em;
+
+ LIN_SDT_PROBE2(futex, linux_set_robust_list, entry, td, args);
+
+ if (args->len != sizeof(struct linux_robust_list_head)) {
+ LIN_SDT_PROBE0(futex, linux_set_robust_list, size_error);
+ LIN_SDT_PROBE1(futex, linux_set_robust_list, return, EINVAL);
+ return (EINVAL);
+ }
+
+ em = em_find(td);
+ em->robust_futexes = args->head;
+
+ LIN_SDT_PROBE1(futex, linux_set_robust_list, return, 0);
+ return (0);
+}
+
+int
+linux_get_robust_list(struct thread *td, struct linux_get_robust_list_args *args)
+{
+ struct linux_emuldata *em;
+ struct linux_robust_list_head *head;
+ l_size_t len = sizeof(struct linux_robust_list_head);
+ struct thread *td2;
+ int error = 0;
+
+ LIN_SDT_PROBE2(futex, linux_get_robust_list, entry, td, args);
+
+ if (!args->pid) {
+ em = em_find(td);
+ KASSERT(em != NULL, ("get_robust_list: emuldata notfound.\n"));
+ head = em->robust_futexes;
+ } else {
+ td2 = tdfind(args->pid, -1);
+ if (td2 == NULL) {
+ LIN_SDT_PROBE1(futex, linux_get_robust_list, return,
+ ESRCH);
+ return (ESRCH);
+ }
+ if (SV_PROC_ABI(td2->td_proc) != SV_ABI_LINUX) {
+ LIN_SDT_PROBE1(futex, linux_get_robust_list, return,
+ EPERM);
+ PROC_UNLOCK(td2->td_proc);
+ return (EPERM);
+ }
+
+ em = em_find(td2);
+ KASSERT(em != NULL, ("get_robust_list: emuldata notfound.\n"));
+ /* XXX: ptrace? */
+ if (priv_check(td, PRIV_CRED_SETUID) ||
+ priv_check(td, PRIV_CRED_SETEUID) ||
+ p_candebug(td, td2->td_proc)) {
+ PROC_UNLOCK(td2->td_proc);
+
+ LIN_SDT_PROBE1(futex, linux_get_robust_list, return,
+ EPERM);
+ return (EPERM);
+ }
+ head = em->robust_futexes;
+
+ PROC_UNLOCK(td2->td_proc);
+ }
+
+ error = copyout(&len, args->len, sizeof(l_size_t));
+ if (error) {
+ LIN_SDT_PROBE1(futex, linux_get_robust_list, copyout_error,
+ error);
+ LIN_SDT_PROBE1(futex, linux_get_robust_list, return, EFAULT);
+ return (EFAULT);
+ }
+
+ error = copyout(&head, args->head, sizeof(head));
+ if (error) {
+ LIN_SDT_PROBE1(futex, linux_get_robust_list, copyout_error,
+ error);
+ }
+
+ LIN_SDT_PROBE1(futex, linux_get_robust_list, return, error);
+ return (error);
+}
+
+static int
+handle_futex_death(struct linux_emuldata *em, uint32_t *uaddr,
+ unsigned int pi)
+{
+ uint32_t uval, nval, mval;
+ struct futex *f;
+ int error;
+
+ LIN_SDT_PROBE3(futex, handle_futex_death, entry, em, uaddr, pi);
+
+retry:
+ error = copyin(uaddr, &uval, 4);
+ if (error) {
+ LIN_SDT_PROBE1(futex, handle_futex_death, copyin_error, error);
+ LIN_SDT_PROBE1(futex, handle_futex_death, return, EFAULT);
+ return (EFAULT);
+ }
+ if ((uval & FUTEX_TID_MASK) == em->em_tid) {
+ mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED;
+ nval = casuword32(uaddr, uval, mval);
+
+ if (nval == -1) {
+ LIN_SDT_PROBE1(futex, handle_futex_death, return,
+ EFAULT);
+ return (EFAULT);
+ }
+
+ if (nval != uval)
+ goto retry;
+
+ if (!pi && (uval & FUTEX_WAITERS)) {
+ error = futex_get(uaddr, NULL, &f,
+ FUTEX_DONTCREATE | FUTEX_SHARED);
+ if (error) {
+ LIN_SDT_PROBE1(futex, handle_futex_death,
+ return, error);
+ return (error);
+ }
+ if (f != NULL) {
+ futex_wake(f, 1, FUTEX_BITSET_MATCH_ANY);
+ futex_put(f, NULL);
+ }
+ }
+ }
+
+ LIN_SDT_PROBE1(futex, handle_futex_death, return, 0);
+ return (0);
+}
+
+static int
+fetch_robust_entry(struct linux_robust_list **entry,
+ struct linux_robust_list **head, unsigned int *pi)
+{
+ l_ulong uentry;
+ int error;
+
+ LIN_SDT_PROBE3(futex, fetch_robust_entry, entry, entry, head, pi);
+
+ error = copyin((const void *)head, &uentry, sizeof(l_ulong));
+ if (error) {
+ LIN_SDT_PROBE1(futex, fetch_robust_entry, copyin_error, error);
+ LIN_SDT_PROBE1(futex, fetch_robust_entry, return, EFAULT);
+ return (EFAULT);
+ }
+
+ *entry = (void *)(uentry & ~1UL);
+ *pi = uentry & 1;
+
+ LIN_SDT_PROBE1(futex, fetch_robust_entry, return, 0);
+ return (0);
+}
+
+/* This walks the list of robust futexes releasing them. */
+void
+release_futexes(struct thread *td, struct linux_emuldata *em)
+{
+ struct linux_robust_list_head *head = NULL;
+ struct linux_robust_list *entry, *next_entry, *pending;
+ unsigned int limit = 2048, pi, next_pi, pip;
+ l_long futex_offset;
+ int rc, error;
+
+ LIN_SDT_PROBE2(futex, release_futexes, entry, td, em);
+
+ head = em->robust_futexes;
+
+ if (head == NULL) {
+ LIN_SDT_PROBE0(futex, release_futexes, return);
+ return;
+ }
+
+ if (fetch_robust_entry(&entry, PTRIN(&head->list.next), &pi)) {
+ LIN_SDT_PROBE0(futex, release_futexes, return);
+ return;
+ }
+
+ error = copyin(&head->futex_offset, &futex_offset,
+ sizeof(futex_offset));
+ if (error) {
+ LIN_SDT_PROBE1(futex, release_futexes, copyin_error, error);
+ LIN_SDT_PROBE0(futex, release_futexes, return);
+ return;
+ }
+
+ if (fetch_robust_entry(&pending, PTRIN(&head->pending_list), &pip)) {
+ LIN_SDT_PROBE0(futex, release_futexes, return);
+ return;
+ }
+
+ while (entry != &head->list) {
+ rc = fetch_robust_entry(&next_entry, PTRIN(&entry->next), &next_pi);
+
+ if (entry != pending)
+ if (handle_futex_death(em,
+ (uint32_t *)((caddr_t)entry + futex_offset), pi)) {
+ LIN_SDT_PROBE0(futex, release_futexes, return);
+ return;
+ }
+ if (rc) {
+ LIN_SDT_PROBE0(futex, release_futexes, return);
+ return;
+ }
+
+ entry = next_entry;
+ pi = next_pi;
+
+ if (!--limit)
+ break;
+
+ sched_relinquish(curthread);
+ }
+
+ if (pending)
+ handle_futex_death(em, (uint32_t *)((caddr_t)pending + futex_offset), pip);
+
+ LIN_SDT_PROBE0(futex, release_futexes, return);
+}
diff --git a/sys/compat/linux/linux_futex.h b/sys/compat/linux/linux_futex.h
new file mode 100644
index 000000000000..bf546538c981
--- /dev/null
+++ b/sys/compat/linux/linux_futex.h
@@ -0,0 +1,86 @@
+/* $NetBSD: linux_futex.h,v 1.2 2005/12/11 12:20:19 christos Exp $ */
+
+/*-
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
+ * Copyright (c) 2005 Emmanuel Dreyfus, all rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Emmanuel Dreyfus
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_FUTEX_H
+#define _LINUX_FUTEX_H
+
+#define LINUX_FUTEX_WAIT 0
+#define LINUX_FUTEX_WAKE 1
+#define LINUX_FUTEX_FD 2 /* unused */
+#define LINUX_FUTEX_REQUEUE 3
+#define LINUX_FUTEX_CMP_REQUEUE 4
+#define LINUX_FUTEX_WAKE_OP 5
+#define LINUX_FUTEX_LOCK_PI 6
+#define LINUX_FUTEX_UNLOCK_PI 7
+#define LINUX_FUTEX_TRYLOCK_PI 8
+#define LINUX_FUTEX_WAIT_BITSET 9
+#define LINUX_FUTEX_WAKE_BITSET 10
+#define LINUX_FUTEX_WAIT_REQUEUE_PI 11
+#define LINUX_FUTEX_CMP_REQUEUE_PI 12
+
+#define LINUX_FUTEX_PRIVATE_FLAG 128
+#define LINUX_FUTEX_CLOCK_REALTIME 256
+
+#define FUTEX_OP_SET 0 /* *(int *)UADDR2 = OPARG; */
+#define FUTEX_OP_ADD 1 /* *(int *)UADDR2 += OPARG; */
+#define FUTEX_OP_OR 2 /* *(int *)UADDR2 |= OPARG; */
+#define FUTEX_OP_ANDN 3 /* *(int *)UADDR2 &= ~OPARG; */
+#define FUTEX_OP_XOR 4 /* *(int *)UADDR2 ^= OPARG; */
+
+#define FUTEX_OP_OPARG_SHIFT 8 /* Use (1 << OPARG) instead of OPARG. */
+
+#define FUTEX_OP_CMP_EQ 0 /* if (oldval == CMPARG) wake */
+#define FUTEX_OP_CMP_NE 1 /* if (oldval != CMPARG) wake */
+#define FUTEX_OP_CMP_LT 2 /* if (oldval < CMPARG) wake */
+#define FUTEX_OP_CMP_LE 3 /* if (oldval <= CMPARG) wake */
+#define FUTEX_OP_CMP_GT 4 /* if (oldval > CMPARG) wake */
+#define FUTEX_OP_CMP_GE 5 /* if (oldval >= CMPARG) wake */
+
+#define FUTEX_WAITERS 0x80000000
+#define FUTEX_OWNER_DIED 0x40000000
+#define FUTEX_TID_MASK 0x3fffffff
+#define FUTEX_BITSET_MATCH_ANY 0xffffffff
+
+int futex_xchgl(int oparg, uint32_t *uaddr, int *oldval);
+int futex_addl(int oparg, uint32_t *uaddr, int *oldval);
+int futex_orl(int oparg, uint32_t *uaddr, int *oldval);
+int futex_andl(int oparg, uint32_t *uaddr, int *oldval);
+int futex_xorl(int oparg, uint32_t *uaddr, int *oldval);
+void release_futexes(struct thread *,
+ struct linux_emuldata *);
+
+#endif /* !_LINUX_FUTEX_H */
diff --git a/sys/compat/linux/linux_getcwd.c b/sys/compat/linux/linux_getcwd.c
new file mode 100644
index 000000000000..c39e69c4e707
--- /dev/null
+++ b/sys/compat/linux/linux_getcwd.c
@@ -0,0 +1,84 @@
+/* $OpenBSD: linux_getcwd.c,v 1.2 2001/05/16 12:50:21 ho Exp $ */
+/* $NetBSD: vfs_getcwd.c,v 1.3.2.3 1999/07/11 10:24:09 sommerfeld Exp $ */
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-NetBSD
+ *
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * Copyright (c) 2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Bill Sommerfeld.
+ *
+ * Portions of this software were developed by Edward Tomasz Napierala
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_compat.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+
+#ifdef COMPAT_LINUX32
+#include <machine/../linux32/linux.h>
+#include <machine/../linux32/linux32_proto.h>
+#else
+#include <machine/../linux/linux.h>
+#include <machine/../linux/linux_proto.h>
+#endif
+#include <compat/linux/linux_misc.h>
+#include <compat/linux/linux_util.h>
+
+/*
+ * Find pathname of process's current directory.
+ */
+int
+linux_getcwd(struct thread *td, struct linux_getcwd_args *uap)
+{
+ char *buf, *retbuf;
+ size_t buflen;
+ int error;
+
+ buflen = uap->bufsize;
+ if (__predict_false(buflen < 2))
+ return (ERANGE);
+ if (buflen > LINUX_PATH_MAX)
+ buflen = LINUX_PATH_MAX;
+
+ buf = malloc(buflen, M_TEMP, M_WAITOK);
+ error = vn_getcwd(buf, &retbuf, &buflen);
+ if (error == 0) {
+ error = copyout(retbuf, uap->buf, buflen);
+ if (error == 0)
+ td->td_retval[0] = buflen;
+ }
+ free(buf, M_TEMP);
+ return (error);
+}
diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c
new file mode 100644
index 000000000000..62cb958aa42f
--- /dev/null
+++ b/sys/compat/linux/linux_ioctl.c
@@ -0,0 +1,3806 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1994-1995 Søren Schmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "opt_compat.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysproto.h>
+#ifdef COMPAT_LINUX32
+#include <sys/abi_compat.h>
+#endif
+#include <sys/capsicum.h>
+#include <sys/cdio.h>
+#include <sys/dvdio.h>
+#include <sys/conf.h>
+#include <sys/disk.h>
+#include <sys/consio.h>
+#include <sys/ctype.h>
+#include <sys/fcntl.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/filio.h>
+#include <sys/jail.h>
+#include <sys/kbio.h>
+#include <sys/kcov.h>
+#include <sys/kernel.h>
+#include <sys/linker_set.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/sbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/soundcard.h>
+#include <sys/stdint.h>
+#include <sys/sx.h>
+#include <sys/sysctl.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/resourcevar.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+
+#include <dev/evdev/input.h>
+#include <dev/usb/usb_ioctl.h>
+
+#ifdef COMPAT_LINUX32
+#include <machine/../linux32/linux.h>
+#include <machine/../linux32/linux32_proto.h>
+#else
+#include <machine/../linux/linux.h>
+#include <machine/../linux/linux_proto.h>
+#endif
+
+#include <compat/linux/linux_common.h>
+#include <compat/linux/linux_ioctl.h>
+#include <compat/linux/linux_mib.h>
+#include <compat/linux/linux_socket.h>
+#include <compat/linux/linux_timer.h>
+#include <compat/linux/linux_util.h>
+
+#include <contrib/v4l/videodev.h>
+#include <compat/linux/linux_videodev_compat.h>
+
+#include <contrib/v4l/videodev2.h>
+#include <compat/linux/linux_videodev2_compat.h>
+
+#include <cam/scsi/scsi_sg.h>
+
+CTASSERT(LINUX_IFNAMSIZ == IFNAMSIZ);
+
+#define DEFINE_LINUX_IOCTL_SET(shortname, SHORTNAME) \
+static linux_ioctl_function_t linux_ioctl_ ## shortname; \
+static struct linux_ioctl_handler shortname ## _handler = { \
+ .func = linux_ioctl_ ## shortname, \
+ .low = LINUX_IOCTL_ ## SHORTNAME ## _MIN, \
+ .high = LINUX_IOCTL_ ## SHORTNAME ## _MAX, \
+}; \
+DATA_SET(linux_ioctl_handler_set, shortname ## _handler)
+
+DEFINE_LINUX_IOCTL_SET(cdrom, CDROM);
+DEFINE_LINUX_IOCTL_SET(vfat, VFAT);
+DEFINE_LINUX_IOCTL_SET(console, CONSOLE);
+DEFINE_LINUX_IOCTL_SET(hdio, HDIO);
+DEFINE_LINUX_IOCTL_SET(disk, DISK);
+DEFINE_LINUX_IOCTL_SET(socket, SOCKET);
+DEFINE_LINUX_IOCTL_SET(sound, SOUND);
+DEFINE_LINUX_IOCTL_SET(termio, TERMIO);
+DEFINE_LINUX_IOCTL_SET(private, PRIVATE);
+DEFINE_LINUX_IOCTL_SET(drm, DRM);
+DEFINE_LINUX_IOCTL_SET(sg, SG);
+DEFINE_LINUX_IOCTL_SET(v4l, VIDEO);
+DEFINE_LINUX_IOCTL_SET(v4l2, VIDEO2);
+DEFINE_LINUX_IOCTL_SET(fbsd_usb, FBSD_LUSB);
+DEFINE_LINUX_IOCTL_SET(evdev, EVDEV);
+DEFINE_LINUX_IOCTL_SET(kcov, KCOV);
+
+#undef DEFINE_LINUX_IOCTL_SET
+
+static int linux_ioctl_special(struct thread *, struct linux_ioctl_args *);
+
+/*
+ * Keep sorted by low.
+ */
+static struct linux_ioctl_handler linux_ioctls[] = {
+ { .func = linux_ioctl_termio, .low = LINUX_IOCTL_TERMIO_MIN,
+ .high = LINUX_IOCTL_TERMIO_MAX },
+};
+
+#ifdef __i386__
+static TAILQ_HEAD(, linux_ioctl_handler_element) linux_ioctl_handlers =
+ TAILQ_HEAD_INITIALIZER(linux_ioctl_handlers);
+static struct sx linux_ioctl_sx;
+SX_SYSINIT(linux_ioctl, &linux_ioctl_sx, "Linux ioctl handlers");
+#else
+extern TAILQ_HEAD(, linux_ioctl_handler_element) linux_ioctl_handlers;
+extern struct sx linux_ioctl_sx;
+#endif
+#ifdef COMPAT_LINUX32
+static TAILQ_HEAD(, linux_ioctl_handler_element) linux32_ioctl_handlers =
+ TAILQ_HEAD_INITIALIZER(linux32_ioctl_handlers);
+#endif
+
+/*
+ * hdio related ioctls for VMWare support
+ */
+
+struct linux_hd_geometry {
+ u_int8_t heads;
+ u_int8_t sectors;
+ u_int16_t cylinders;
+ u_int32_t start;
+};
+
+struct linux_hd_big_geometry {
+ u_int8_t heads;
+ u_int8_t sectors;
+ u_int32_t cylinders;
+ u_int32_t start;
+};
+
+static int
+linux_ioctl_hdio(struct thread *td, struct linux_ioctl_args *args)
+{
+ struct file *fp;
+ int error;
+ u_int sectorsize, fwcylinders, fwheads, fwsectors;
+ off_t mediasize, bytespercyl;
+
+ error = fget(td, args->fd, &cap_ioctl_rights, &fp);
+ if (error != 0)
+ return (error);
+ switch (args->cmd & 0xffff) {
+ case LINUX_HDIO_GET_GEO:
+ case LINUX_HDIO_GET_GEO_BIG:
+ error = fo_ioctl(fp, DIOCGMEDIASIZE,
+ (caddr_t)&mediasize, td->td_ucred, td);
+ if (!error)
+ error = fo_ioctl(fp, DIOCGSECTORSIZE,
+ (caddr_t)&sectorsize, td->td_ucred, td);
+ if (!error)
+ error = fo_ioctl(fp, DIOCGFWHEADS,
+ (caddr_t)&fwheads, td->td_ucred, td);
+ if (!error)
+ error = fo_ioctl(fp, DIOCGFWSECTORS,
+ (caddr_t)&fwsectors, td->td_ucred, td);
+ /*
+ * XXX: DIOCGFIRSTOFFSET is not yet implemented, so
+ * so pretend that GEOM always says 0. This is NOT VALID
+ * for slices or partitions, only the per-disk raw devices.
+ */
+
+ fdrop(fp, td);
+ if (error)
+ return (error);
+ /*
+ * 1. Calculate the number of bytes in a cylinder,
+ * given the firmware's notion of heads and sectors
+ * per cylinder.
+ * 2. Calculate the number of cylinders, given the total
+ * size of the media.
+ * All internal calculations should have 64-bit precision.
+ */
+ bytespercyl = (off_t) sectorsize * fwheads * fwsectors;
+ fwcylinders = mediasize / bytespercyl;
+
+ if ((args->cmd & 0xffff) == LINUX_HDIO_GET_GEO) {
+ struct linux_hd_geometry hdg;
+
+ hdg.cylinders = fwcylinders;
+ hdg.heads = fwheads;
+ hdg.sectors = fwsectors;
+ hdg.start = 0;
+ error = copyout(&hdg, (void *)args->arg, sizeof(hdg));
+ } else if ((args->cmd & 0xffff) == LINUX_HDIO_GET_GEO_BIG) {
+ struct linux_hd_big_geometry hdbg;
+
+ memset(&hdbg, 0, sizeof(hdbg));
+ hdbg.cylinders = fwcylinders;
+ hdbg.heads = fwheads;
+ hdbg.sectors = fwsectors;
+ hdbg.start = 0;
+ error = copyout(&hdbg, (void *)args->arg, sizeof(hdbg));
+ }
+ return (error);
+ break;
+ default:
+ /* XXX */
+ linux_msg(td,
+ "%s fd=%d, cmd=0x%x ('%c',%d) is not implemented",
+ __func__, args->fd, args->cmd,
+ (int)(args->cmd & 0xff00) >> 8,
+ (int)(args->cmd & 0xff));
+ break;
+ }
+ fdrop(fp, td);
+ return (ENOIOCTL);
+}
+
+static int
+linux_ioctl_disk(struct thread *td, struct linux_ioctl_args *args)
+{
+ struct file *fp;
+ int error;
+ u_int sectorsize, psectorsize;
+ uint64_t blksize64;
+ off_t mediasize, stripesize;
+
+ error = fget(td, args->fd, &cap_ioctl_rights, &fp);
+ if (error != 0)
+ return (error);
+ switch (args->cmd & 0xffff) {
+ case LINUX_BLKGETSIZE:
+ error = fo_ioctl(fp, DIOCGSECTORSIZE,
+ (caddr_t)&sectorsize, td->td_ucred, td);
+ if (!error)
+ error = fo_ioctl(fp, DIOCGMEDIASIZE,
+ (caddr_t)&mediasize, td->td_ucred, td);
+ fdrop(fp, td);
+ if (error)
+ return (error);
+ sectorsize = mediasize / sectorsize;
+ /*
+ * XXX: How do we know we return the right size of integer ?
+ */
+ return (copyout(&sectorsize, (void *)args->arg,
+ sizeof(sectorsize)));
+ break;
+ case LINUX_BLKGETSIZE64:
+ error = fo_ioctl(fp, DIOCGMEDIASIZE,
+ (caddr_t)&mediasize, td->td_ucred, td);
+ fdrop(fp, td);
+ if (error)
+ return (error);
+ blksize64 = mediasize;;
+ return (copyout(&blksize64, (void *)args->arg,
+ sizeof(blksize64)));
+ case LINUX_BLKSSZGET:
+ error = fo_ioctl(fp, DIOCGSECTORSIZE,
+ (caddr_t)&sectorsize, td->td_ucred, td);
+ fdrop(fp, td);
+ if (error)
+ return (error);
+ return (copyout(&sectorsize, (void *)args->arg,
+ sizeof(sectorsize)));
+ break;
+ case LINUX_BLKPBSZGET:
+ error = fo_ioctl(fp, DIOCGSTRIPESIZE,
+ (caddr_t)&stripesize, td->td_ucred, td);
+ if (error != 0) {
+ fdrop(fp, td);
+ return (error);
+ }
+ if (stripesize > 0 && stripesize <= 4096) {
+ psectorsize = stripesize;
+ } else {
+ error = fo_ioctl(fp, DIOCGSECTORSIZE,
+ (caddr_t)&sectorsize, td->td_ucred, td);
+ if (error != 0) {
+ fdrop(fp, td);
+ return (error);
+ }
+ psectorsize = sectorsize;
+ }
+ fdrop(fp, td);
+ return (copyout(&psectorsize, (void *)args->arg,
+ sizeof(psectorsize)));
+ }
+ fdrop(fp, td);
+ return (ENOIOCTL);
+}
+
+/*
+ * termio related ioctls
+ */
+
+struct linux_termio {
+ unsigned short c_iflag;
+ unsigned short c_oflag;
+ unsigned short c_cflag;
+ unsigned short c_lflag;
+ unsigned char c_line;
+ unsigned char c_cc[LINUX_NCC];
+};
+
+struct linux_termios {
+ unsigned int c_iflag;
+ unsigned int c_oflag;
+ unsigned int c_cflag;
+ unsigned int c_lflag;
+ unsigned char c_line;
+ unsigned char c_cc[LINUX_NCCS];
+};
+
+struct linux_winsize {
+ unsigned short ws_row, ws_col;
+ unsigned short ws_xpixel, ws_ypixel;
+};
+
+struct speedtab {
+ int sp_speed; /* Speed. */
+ int sp_code; /* Code. */
+};
+
+static struct speedtab sptab[] = {
+ { B0, LINUX_B0 }, { B50, LINUX_B50 },
+ { B75, LINUX_B75 }, { B110, LINUX_B110 },
+ { B134, LINUX_B134 }, { B150, LINUX_B150 },
+ { B200, LINUX_B200 }, { B300, LINUX_B300 },
+ { B600, LINUX_B600 }, { B1200, LINUX_B1200 },
+ { B1800, LINUX_B1800 }, { B2400, LINUX_B2400 },
+ { B4800, LINUX_B4800 }, { B9600, LINUX_B9600 },
+ { B19200, LINUX_B19200 }, { B38400, LINUX_B38400 },
+ { B57600, LINUX_B57600 }, { B115200, LINUX_B115200 },
+ {-1, -1 }
+};
+
+struct linux_serial_struct {
+ int type;
+ int line;
+ int port;
+ int irq;
+ int flags;
+ int xmit_fifo_size;
+ int custom_divisor;
+ int baud_base;
+ unsigned short close_delay;
+ char reserved_char[2];
+ int hub6;
+ unsigned short closing_wait;
+ unsigned short closing_wait2;
+ int reserved[4];
+};
+
+static int
+linux_to_bsd_speed(int code, struct speedtab *table)
+{
+ for ( ; table->sp_code != -1; table++)
+ if (table->sp_code == code)
+ return (table->sp_speed);
+ return (-1);
+}
+
+static int
+bsd_to_linux_speed(int speed, struct speedtab *table)
+{
+ for ( ; table->sp_speed != -1; table++)
+ if (table->sp_speed == speed)
+ return (table->sp_code);
+ return (-1);
+}
+
+static void
+bsd_to_linux_termios(struct termios *bios, struct linux_termios *lios)
+{
+ int i;
+
+ lios->c_iflag = 0;
+ if (bios->c_iflag & IGNBRK)
+ lios->c_iflag |= LINUX_IGNBRK;
+ if (bios->c_iflag & BRKINT)
+ lios->c_iflag |= LINUX_BRKINT;
+ if (bios->c_iflag & IGNPAR)
+ lios->c_iflag |= LINUX_IGNPAR;
+ if (bios->c_iflag & PARMRK)
+ lios->c_iflag |= LINUX_PARMRK;
+ if (bios->c_iflag & INPCK)
+ lios->c_iflag |= LINUX_INPCK;
+ if (bios->c_iflag & ISTRIP)
+ lios->c_iflag |= LINUX_ISTRIP;
+ if (bios->c_iflag & INLCR)
+ lios->c_iflag |= LINUX_INLCR;
+ if (bios->c_iflag & IGNCR)
+ lios->c_iflag |= LINUX_IGNCR;
+ if (bios->c_iflag & ICRNL)
+ lios->c_iflag |= LINUX_ICRNL;
+ if (bios->c_iflag & IXON)
+ lios->c_iflag |= LINUX_IXON;
+ if (bios->c_iflag & IXANY)
+ lios->c_iflag |= LINUX_IXANY;
+ if (bios->c_iflag & IXOFF)
+ lios->c_iflag |= LINUX_IXOFF;
+ if (bios->c_iflag & IMAXBEL)
+ lios->c_iflag |= LINUX_IMAXBEL;
+
+ lios->c_oflag = 0;
+ if (bios->c_oflag & OPOST)
+ lios->c_oflag |= LINUX_OPOST;
+ if (bios->c_oflag & ONLCR)
+ lios->c_oflag |= LINUX_ONLCR;
+ if (bios->c_oflag & TAB3)
+ lios->c_oflag |= LINUX_XTABS;
+
+ lios->c_cflag = bsd_to_linux_speed(bios->c_ispeed, sptab);
+ lios->c_cflag |= (bios->c_cflag & CSIZE) >> 4;
+ if (bios->c_cflag & CSTOPB)
+ lios->c_cflag |= LINUX_CSTOPB;
+ if (bios->c_cflag & CREAD)
+ lios->c_cflag |= LINUX_CREAD;
+ if (bios->c_cflag & PARENB)
+ lios->c_cflag |= LINUX_PARENB;
+ if (bios->c_cflag & PARODD)
+ lios->c_cflag |= LINUX_PARODD;
+ if (bios->c_cflag & HUPCL)
+ lios->c_cflag |= LINUX_HUPCL;
+ if (bios->c_cflag & CLOCAL)
+ lios->c_cflag |= LINUX_CLOCAL;
+ if (bios->c_cflag & CRTSCTS)
+ lios->c_cflag |= LINUX_CRTSCTS;
+
+ lios->c_lflag = 0;
+ if (bios->c_lflag & ISIG)
+ lios->c_lflag |= LINUX_ISIG;
+ if (bios->c_lflag & ICANON)
+ lios->c_lflag |= LINUX_ICANON;
+ if (bios->c_lflag & ECHO)
+ lios->c_lflag |= LINUX_ECHO;
+ if (bios->c_lflag & ECHOE)
+ lios->c_lflag |= LINUX_ECHOE;
+ if (bios->c_lflag & ECHOK)
+ lios->c_lflag |= LINUX_ECHOK;
+ if (bios->c_lflag & ECHONL)
+ lios->c_lflag |= LINUX_ECHONL;
+ if (bios->c_lflag & NOFLSH)
+ lios->c_lflag |= LINUX_NOFLSH;
+ if (bios->c_lflag & TOSTOP)
+ lios->c_lflag |= LINUX_TOSTOP;
+ if (bios->c_lflag & ECHOCTL)
+ lios->c_lflag |= LINUX_ECHOCTL;
+ if (bios->c_lflag & ECHOPRT)
+ lios->c_lflag |= LINUX_ECHOPRT;
+ if (bios->c_lflag & ECHOKE)
+ lios->c_lflag |= LINUX_ECHOKE;
+ if (bios->c_lflag & FLUSHO)
+ lios->c_lflag |= LINUX_FLUSHO;
+ if (bios->c_lflag & PENDIN)
+ lios->c_lflag |= LINUX_PENDIN;
+ if (bios->c_lflag & IEXTEN)
+ lios->c_lflag |= LINUX_IEXTEN;
+
+ for (i=0; i<LINUX_NCCS; i++)
+ lios->c_cc[i] = LINUX_POSIX_VDISABLE;
+ lios->c_cc[LINUX_VINTR] = bios->c_cc[VINTR];
+ lios->c_cc[LINUX_VQUIT] = bios->c_cc[VQUIT];
+ lios->c_cc[LINUX_VERASE] = bios->c_cc[VERASE];
+ lios->c_cc[LINUX_VKILL] = bios->c_cc[VKILL];
+ lios->c_cc[LINUX_VEOF] = bios->c_cc[VEOF];
+ lios->c_cc[LINUX_VEOL] = bios->c_cc[VEOL];
+ lios->c_cc[LINUX_VMIN] = bios->c_cc[VMIN];
+ lios->c_cc[LINUX_VTIME] = bios->c_cc[VTIME];
+ lios->c_cc[LINUX_VEOL2] = bios->c_cc[VEOL2];
+ lios->c_cc[LINUX_VSUSP] = bios->c_cc[VSUSP];
+ lios->c_cc[LINUX_VSTART] = bios->c_cc[VSTART];
+ lios->c_cc[LINUX_VSTOP] = bios->c_cc[VSTOP];
+ lios->c_cc[LINUX_VREPRINT] = bios->c_cc[VREPRINT];
+ lios->c_cc[LINUX_VDISCARD] = bios->c_cc[VDISCARD];
+ lios->c_cc[LINUX_VWERASE] = bios->c_cc[VWERASE];
+ lios->c_cc[LINUX_VLNEXT] = bios->c_cc[VLNEXT];
+ if (linux_preserve_vstatus)
+ lios->c_cc[LINUX_VSTATUS] = bios->c_cc[VSTATUS];
+
+ for (i=0; i<LINUX_NCCS; i++) {
+ if (i != LINUX_VMIN && i != LINUX_VTIME &&
+ lios->c_cc[i] == _POSIX_VDISABLE)
+ lios->c_cc[i] = LINUX_POSIX_VDISABLE;
+ }
+ lios->c_line = 0;
+}
+
+static void
+linux_to_bsd_termios(struct linux_termios *lios, struct termios *bios)
+{
+ int i;
+
+ bios->c_iflag = 0;
+ if (lios->c_iflag & LINUX_IGNBRK)
+ bios->c_iflag |= IGNBRK;
+ if (lios->c_iflag & LINUX_BRKINT)
+ bios->c_iflag |= BRKINT;
+ if (lios->c_iflag & LINUX_IGNPAR)
+ bios->c_iflag |= IGNPAR;
+ if (lios->c_iflag & LINUX_PARMRK)
+ bios->c_iflag |= PARMRK;
+ if (lios->c_iflag & LINUX_INPCK)
+ bios->c_iflag |= INPCK;
+ if (lios->c_iflag & LINUX_ISTRIP)
+ bios->c_iflag |= ISTRIP;
+ if (lios->c_iflag & LINUX_INLCR)
+ bios->c_iflag |= INLCR;
+ if (lios->c_iflag & LINUX_IGNCR)
+ bios->c_iflag |= IGNCR;
+ if (lios->c_iflag & LINUX_ICRNL)
+ bios->c_iflag |= ICRNL;
+ if (lios->c_iflag & LINUX_IXON)
+ bios->c_iflag |= IXON;
+ if (lios->c_iflag & LINUX_IXANY)
+ bios->c_iflag |= IXANY;
+ if (lios->c_iflag & LINUX_IXOFF)
+ bios->c_iflag |= IXOFF;
+ if (lios->c_iflag & LINUX_IMAXBEL)
+ bios->c_iflag |= IMAXBEL;
+
+ bios->c_oflag = 0;
+ if (lios->c_oflag & LINUX_OPOST)
+ bios->c_oflag |= OPOST;
+ if (lios->c_oflag & LINUX_ONLCR)
+ bios->c_oflag |= ONLCR;
+ if (lios->c_oflag & LINUX_XTABS)
+ bios->c_oflag |= TAB3;
+
+ bios->c_cflag = (lios->c_cflag & LINUX_CSIZE) << 4;
+ if (lios->c_cflag & LINUX_CSTOPB)
+ bios->c_cflag |= CSTOPB;
+ if (lios->c_cflag & LINUX_CREAD)
+ bios->c_cflag |= CREAD;
+ if (lios->c_cflag & LINUX_PARENB)
+ bios->c_cflag |= PARENB;
+ if (lios->c_cflag & LINUX_PARODD)
+ bios->c_cflag |= PARODD;
+ if (lios->c_cflag & LINUX_HUPCL)
+ bios->c_cflag |= HUPCL;
+ if (lios->c_cflag & LINUX_CLOCAL)
+ bios->c_cflag |= CLOCAL;
+ if (lios->c_cflag & LINUX_CRTSCTS)
+ bios->c_cflag |= CRTSCTS;
+
+ bios->c_lflag = 0;
+ if (lios->c_lflag & LINUX_ISIG)
+ bios->c_lflag |= ISIG;
+ if (lios->c_lflag & LINUX_ICANON)
+ bios->c_lflag |= ICANON;
+ if (lios->c_lflag & LINUX_ECHO)
+ bios->c_lflag |= ECHO;
+ if (lios->c_lflag & LINUX_ECHOE)
+ bios->c_lflag |= ECHOE;
+ if (lios->c_lflag & LINUX_ECHOK)
+ bios->c_lflag |= ECHOK;
+ if (lios->c_lflag & LINUX_ECHONL)
+ bios->c_lflag |= ECHONL;
+ if (lios->c_lflag & LINUX_NOFLSH)
+ bios->c_lflag |= NOFLSH;
+ if (lios->c_lflag & LINUX_TOSTOP)
+ bios->c_lflag |= TOSTOP;
+ if (lios->c_lflag & LINUX_ECHOCTL)
+ bios->c_lflag |= ECHOCTL;
+ if (lios->c_lflag & LINUX_ECHOPRT)
+ bios->c_lflag |= ECHOPRT;
+ if (lios->c_lflag & LINUX_ECHOKE)
+ bios->c_lflag |= ECHOKE;
+ if (lios->c_lflag & LINUX_FLUSHO)
+ bios->c_lflag |= FLUSHO;
+ if (lios->c_lflag & LINUX_PENDIN)
+ bios->c_lflag |= PENDIN;
+ if (lios->c_lflag & LINUX_IEXTEN)
+ bios->c_lflag |= IEXTEN;
+
+ for (i=0; i<NCCS; i++)
+ bios->c_cc[i] = _POSIX_VDISABLE;
+ bios->c_cc[VINTR] = lios->c_cc[LINUX_VINTR];
+ bios->c_cc[VQUIT] = lios->c_cc[LINUX_VQUIT];
+ bios->c_cc[VERASE] = lios->c_cc[LINUX_VERASE];
+ bios->c_cc[VKILL] = lios->c_cc[LINUX_VKILL];
+ bios->c_cc[VEOF] = lios->c_cc[LINUX_VEOF];
+ bios->c_cc[VEOL] = lios->c_cc[LINUX_VEOL];
+ bios->c_cc[VMIN] = lios->c_cc[LINUX_VMIN];
+ bios->c_cc[VTIME] = lios->c_cc[LINUX_VTIME];
+ bios->c_cc[VEOL2] = lios->c_cc[LINUX_VEOL2];
+ bios->c_cc[VSUSP] = lios->c_cc[LINUX_VSUSP];
+ bios->c_cc[VSTART] = lios->c_cc[LINUX_VSTART];
+ bios->c_cc[VSTOP] = lios->c_cc[LINUX_VSTOP];
+ bios->c_cc[VREPRINT] = lios->c_cc[LINUX_VREPRINT];
+ bios->c_cc[VDISCARD] = lios->c_cc[LINUX_VDISCARD];
+ bios->c_cc[VWERASE] = lios->c_cc[LINUX_VWERASE];
+ bios->c_cc[VLNEXT] = lios->c_cc[LINUX_VLNEXT];
+ if (linux_preserve_vstatus)
+ bios->c_cc[VSTATUS] = lios->c_cc[LINUX_VSTATUS];
+
+ for (i=0; i<NCCS; i++) {
+ if (i != VMIN && i != VTIME &&
+ bios->c_cc[i] == LINUX_POSIX_VDISABLE)
+ bios->c_cc[i] = _POSIX_VDISABLE;
+ }
+
+ bios->c_ispeed = bios->c_ospeed =
+ linux_to_bsd_speed(lios->c_cflag & LINUX_CBAUD, sptab);
+}
+
+static void
+bsd_to_linux_termio(struct termios *bios, struct linux_termio *lio)
+{
+ struct linux_termios lios;
+
+ memset(lio, 0, sizeof(*lio));
+ bsd_to_linux_termios(bios, &lios);
+ lio->c_iflag = lios.c_iflag;
+ lio->c_oflag = lios.c_oflag;
+ lio->c_cflag = lios.c_cflag;
+ lio->c_lflag = lios.c_lflag;
+ lio->c_line = lios.c_line;
+ memcpy(lio->c_cc, lios.c_cc, LINUX_NCC);
+}
+
+static void
+linux_to_bsd_termio(struct linux_termio *lio, struct termios *bios)
+{
+ struct linux_termios lios;
+ int i;
+
+ lios.c_iflag = lio->c_iflag;
+ lios.c_oflag = lio->c_oflag;
+ lios.c_cflag = lio->c_cflag;
+ lios.c_lflag = lio->c_lflag;
+ for (i=LINUX_NCC; i<LINUX_NCCS; i++)
+ lios.c_cc[i] = LINUX_POSIX_VDISABLE;
+ memcpy(lios.c_cc, lio->c_cc, LINUX_NCC);
+ linux_to_bsd_termios(&lios, bios);
+}
+
+static int
+linux_ioctl_termio(struct thread *td, struct linux_ioctl_args *args)
+{
+ struct termios bios;
+ struct linux_termios lios;
+ struct linux_termio lio;
+ struct file *fp;
+ int error;
+
+ error = fget(td, args->fd, &cap_ioctl_rights, &fp);
+ if (error != 0)
+ return (error);
+
+ switch (args->cmd & 0xffff) {
+ case LINUX_TCGETS:
+ error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td->td_ucred,
+ td);
+ if (error)
+ break;
+ bsd_to_linux_termios(&bios, &lios);
+ error = copyout(&lios, (void *)args->arg, sizeof(lios));
+ break;
+
+ case LINUX_TCSETS:
+ error = copyin((void *)args->arg, &lios, sizeof(lios));
+ if (error)
+ break;
+ linux_to_bsd_termios(&lios, &bios);
+ error = (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td->td_ucred,
+ td));
+ break;
+
+ case LINUX_TCSETSW:
+ error = copyin((void *)args->arg, &lios, sizeof(lios));
+ if (error)
+ break;
+ linux_to_bsd_termios(&lios, &bios);
+ error = (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td->td_ucred,
+ td));
+ break;
+
+ case LINUX_TCSETSF:
+ error = copyin((void *)args->arg, &lios, sizeof(lios));
+ if (error)
+ break;
+ linux_to_bsd_termios(&lios, &bios);
+ error = (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td->td_ucred,
+ td));
+ break;
+
+ case LINUX_TCGETA:
+ error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td->td_ucred,
+ td);
+ if (error)
+ break;
+ bsd_to_linux_termio(&bios, &lio);
+ error = (copyout(&lio, (void *)args->arg, sizeof(lio)));
+ break;
+
+ case LINUX_TCSETA:
+ error = copyin((void *)args->arg, &lio, sizeof(lio));
+ if (error)
+ break;
+ linux_to_bsd_termio(&lio, &bios);
+ error = (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td->td_ucred,
+ td));
+ break;
+
+ case LINUX_TCSETAW:
+ error = copyin((void *)args->arg, &lio, sizeof(lio));
+ if (error)
+ break;
+ linux_to_bsd_termio(&lio, &bios);
+ error = (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td->td_ucred,
+ td));
+ break;
+
+ case LINUX_TCSETAF:
+ error = copyin((void *)args->arg, &lio, sizeof(lio));
+ if (error)
+ break;
+ linux_to_bsd_termio(&lio, &bios);
+ error = (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td->td_ucred,
+ td));
+ break;
+
+ /* LINUX_TCSBRK */
+
+ case LINUX_TCXONC: {
+ switch (args->arg) {
+ case LINUX_TCOOFF:
+ args->cmd = TIOCSTOP;
+ break;
+ case LINUX_TCOON:
+ args->cmd = TIOCSTART;
+ break;
+ case LINUX_TCIOFF:
+ case LINUX_TCION: {
+ int c;
+ struct write_args wr;
+ error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios,
+ td->td_ucred, td);
+ if (error)
+ break;
+ fdrop(fp, td);
+ c = (args->arg == LINUX_TCIOFF) ? VSTOP : VSTART;
+ c = bios.c_cc[c];
+ if (c != _POSIX_VDISABLE) {
+ wr.fd = args->fd;
+ wr.buf = &c;
+ wr.nbyte = sizeof(c);
+ return (sys_write(td, &wr));
+ } else
+ return (0);
+ }
+ default:
+ fdrop(fp, td);
+ return (EINVAL);
+ }
+ args->arg = 0;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+ }
+
+ case LINUX_TCFLSH: {
+ int val;
+ switch (args->arg) {
+ case LINUX_TCIFLUSH:
+ val = FREAD;
+ break;
+ case LINUX_TCOFLUSH:
+ val = FWRITE;
+ break;
+ case LINUX_TCIOFLUSH:
+ val = FREAD | FWRITE;
+ break;
+ default:
+ fdrop(fp, td);
+ return (EINVAL);
+ }
+ error = (fo_ioctl(fp,TIOCFLUSH,(caddr_t)&val,td->td_ucred,td));
+ break;
+ }
+
+ case LINUX_TIOCEXCL:
+ args->cmd = TIOCEXCL;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_TIOCNXCL:
+ args->cmd = TIOCNXCL;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_TIOCSCTTY:
+ args->cmd = TIOCSCTTY;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_TIOCGPGRP:
+ args->cmd = TIOCGPGRP;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_TIOCSPGRP:
+ args->cmd = TIOCSPGRP;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ /* LINUX_TIOCOUTQ */
+ /* LINUX_TIOCSTI */
+
+ case LINUX_TIOCGWINSZ:
+ args->cmd = TIOCGWINSZ;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_TIOCSWINSZ:
+ args->cmd = TIOCSWINSZ;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_TIOCMGET:
+ args->cmd = TIOCMGET;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_TIOCMBIS:
+ args->cmd = TIOCMBIS;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_TIOCMBIC:
+ args->cmd = TIOCMBIC;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_TIOCMSET:
+ args->cmd = TIOCMSET;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ /* TIOCGSOFTCAR */
+ /* TIOCSSOFTCAR */
+
+ case LINUX_FIONREAD: /* LINUX_TIOCINQ */
+ args->cmd = FIONREAD;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ /* LINUX_TIOCLINUX */
+
+ case LINUX_TIOCCONS:
+ args->cmd = TIOCCONS;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_TIOCGSERIAL: {
+ struct linux_serial_struct lss;
+
+ bzero(&lss, sizeof(lss));
+ lss.type = LINUX_PORT_16550A;
+ lss.flags = 0;
+ lss.close_delay = 0;
+ error = copyout(&lss, (void *)args->arg, sizeof(lss));
+ break;
+ }
+
+ case LINUX_TIOCSSERIAL: {
+ struct linux_serial_struct lss;
+ error = copyin((void *)args->arg, &lss, sizeof(lss));
+ if (error)
+ break;
+ /* XXX - It really helps to have an implementation that
+ * does nothing. NOT!
+ */
+ error = 0;
+ break;
+ }
+
+ case LINUX_TIOCPKT:
+ args->cmd = TIOCPKT;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_FIONBIO:
+ args->cmd = FIONBIO;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_TIOCNOTTY:
+ args->cmd = TIOCNOTTY;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_TIOCSETD: {
+ int line;
+ switch (args->arg) {
+ case LINUX_N_TTY:
+ line = TTYDISC;
+ break;
+ case LINUX_N_SLIP:
+ line = SLIPDISC;
+ break;
+ case LINUX_N_PPP:
+ line = PPPDISC;
+ break;
+ default:
+ fdrop(fp, td);
+ return (EINVAL);
+ }
+ error = (fo_ioctl(fp, TIOCSETD, (caddr_t)&line, td->td_ucred,
+ td));
+ break;
+ }
+
+ case LINUX_TIOCGETD: {
+ int linux_line;
+ int bsd_line = TTYDISC;
+ error = fo_ioctl(fp, TIOCGETD, (caddr_t)&bsd_line,
+ td->td_ucred, td);
+ if (error)
+ break;
+ switch (bsd_line) {
+ case TTYDISC:
+ linux_line = LINUX_N_TTY;
+ break;
+ case SLIPDISC:
+ linux_line = LINUX_N_SLIP;
+ break;
+ case PPPDISC:
+ linux_line = LINUX_N_PPP;
+ break;
+ default:
+ fdrop(fp, td);
+ return (EINVAL);
+ }
+ error = (copyout(&linux_line, (void *)args->arg, sizeof(int)));
+ break;
+ }
+
+ /* LINUX_TCSBRKP */
+ /* LINUX_TIOCTTYGSTRUCT */
+
+ case LINUX_FIONCLEX:
+ args->cmd = FIONCLEX;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_FIOCLEX:
+ args->cmd = FIOCLEX;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_FIOASYNC:
+ args->cmd = FIOASYNC;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ /* LINUX_TIOCSERCONFIG */
+ /* LINUX_TIOCSERGWILD */
+ /* LINUX_TIOCSERSWILD */
+ /* LINUX_TIOCGLCKTRMIOS */
+ /* LINUX_TIOCSLCKTRMIOS */
+
+ case LINUX_TIOCSBRK:
+ args->cmd = TIOCSBRK;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_TIOCCBRK:
+ args->cmd = TIOCCBRK;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+ case LINUX_TIOCGPTN: {
+ int nb;
+
+ error = fo_ioctl(fp, TIOCGPTN, (caddr_t)&nb, td->td_ucred, td);
+ if (!error)
+ error = copyout(&nb, (void *)args->arg,
+ sizeof(int));
+ break;
+ }
+ case LINUX_TIOCSPTLCK:
+ /* Our unlockpt() does nothing. */
+ error = 0;
+ break;
+ default:
+ error = ENOIOCTL;
+ break;
+ }
+
+ fdrop(fp, td);
+ return (error);
+}
+
+/*
+ * CDROM related ioctls
+ */
+
+struct linux_cdrom_msf
+{
+ u_char cdmsf_min0;
+ u_char cdmsf_sec0;
+ u_char cdmsf_frame0;
+ u_char cdmsf_min1;
+ u_char cdmsf_sec1;
+ u_char cdmsf_frame1;
+};
+
+struct linux_cdrom_tochdr
+{
+ u_char cdth_trk0;
+ u_char cdth_trk1;
+};
+
+union linux_cdrom_addr
+{
+ struct {
+ u_char minute;
+ u_char second;
+ u_char frame;
+ } msf;
+ int lba;
+};
+
+struct linux_cdrom_tocentry
+{
+ u_char cdte_track;
+ u_char cdte_adr:4;
+ u_char cdte_ctrl:4;
+ u_char cdte_format;
+ union linux_cdrom_addr cdte_addr;
+ u_char cdte_datamode;
+};
+
+struct linux_cdrom_subchnl
+{
+ u_char cdsc_format;
+ u_char cdsc_audiostatus;
+ u_char cdsc_adr:4;
+ u_char cdsc_ctrl:4;
+ u_char cdsc_trk;
+ u_char cdsc_ind;
+ union linux_cdrom_addr cdsc_absaddr;
+ union linux_cdrom_addr cdsc_reladdr;
+};
+
+struct l_cdrom_read_audio {
+ union linux_cdrom_addr addr;
+ u_char addr_format;
+ l_int nframes;
+ u_char *buf;
+};
+
+struct l_dvd_layer {
+ u_char book_version:4;
+ u_char book_type:4;
+ u_char min_rate:4;
+ u_char disc_size:4;
+ u_char layer_type:4;
+ u_char track_path:1;
+ u_char nlayers:2;
+ u_char track_density:4;
+ u_char linear_density:4;
+ u_char bca:1;
+ u_int32_t start_sector;
+ u_int32_t end_sector;
+ u_int32_t end_sector_l0;
+};
+
+struct l_dvd_physical {
+ u_char type;
+ u_char layer_num;
+ struct l_dvd_layer layer[4];
+};
+
+struct l_dvd_copyright {
+ u_char type;
+ u_char layer_num;
+ u_char cpst;
+ u_char rmi;
+};
+
+struct l_dvd_disckey {
+ u_char type;
+ l_uint agid:2;
+ u_char value[2048];
+};
+
+struct l_dvd_bca {
+ u_char type;
+ l_int len;
+ u_char value[188];
+};
+
+struct l_dvd_manufact {
+ u_char type;
+ u_char layer_num;
+ l_int len;
+ u_char value[2048];
+};
+
+typedef union {
+ u_char type;
+ struct l_dvd_physical physical;
+ struct l_dvd_copyright copyright;
+ struct l_dvd_disckey disckey;
+ struct l_dvd_bca bca;
+ struct l_dvd_manufact manufact;
+} l_dvd_struct;
+
+typedef u_char l_dvd_key[5];
+typedef u_char l_dvd_challenge[10];
+
+struct l_dvd_lu_send_agid {
+ u_char type;
+ l_uint agid:2;
+};
+
+struct l_dvd_host_send_challenge {
+ u_char type;
+ l_uint agid:2;
+ l_dvd_challenge chal;
+};
+
+struct l_dvd_send_key {
+ u_char type;
+ l_uint agid:2;
+ l_dvd_key key;
+};
+
+struct l_dvd_lu_send_challenge {
+ u_char type;
+ l_uint agid:2;
+ l_dvd_challenge chal;
+};
+
+struct l_dvd_lu_send_title_key {
+ u_char type;
+ l_uint agid:2;
+ l_dvd_key title_key;
+ l_int lba;
+ l_uint cpm:1;
+ l_uint cp_sec:1;
+ l_uint cgms:2;
+};
+
+struct l_dvd_lu_send_asf {
+ u_char type;
+ l_uint agid:2;
+ l_uint asf:1;
+};
+
+struct l_dvd_host_send_rpcstate {
+ u_char type;
+ u_char pdrc;
+};
+
+struct l_dvd_lu_send_rpcstate {
+ u_char type:2;
+ u_char vra:3;
+ u_char ucca:3;
+ u_char region_mask;
+ u_char rpc_scheme;
+};
+
+typedef union {
+ u_char type;
+ struct l_dvd_lu_send_agid lsa;
+ struct l_dvd_host_send_challenge hsc;
+ struct l_dvd_send_key lsk;
+ struct l_dvd_lu_send_challenge lsc;
+ struct l_dvd_send_key hsk;
+ struct l_dvd_lu_send_title_key lstk;
+ struct l_dvd_lu_send_asf lsasf;
+ struct l_dvd_host_send_rpcstate hrpcs;
+ struct l_dvd_lu_send_rpcstate lrpcs;
+} l_dvd_authinfo;
+
+static void
+bsd_to_linux_msf_lba(u_char af, union msf_lba *bp, union linux_cdrom_addr *lp)
+{
+ if (af == CD_LBA_FORMAT)
+ lp->lba = bp->lba;
+ else {
+ lp->msf.minute = bp->msf.minute;
+ lp->msf.second = bp->msf.second;
+ lp->msf.frame = bp->msf.frame;
+ }
+}
+
+static void
+set_linux_cdrom_addr(union linux_cdrom_addr *addr, int format, int lba)
+{
+ if (format == LINUX_CDROM_MSF) {
+ addr->msf.frame = lba % 75;
+ lba /= 75;
+ lba += 2;
+ addr->msf.second = lba % 60;
+ addr->msf.minute = lba / 60;
+ } else
+ addr->lba = lba;
+}
+
+static int
+linux_to_bsd_dvd_struct(l_dvd_struct *lp, struct dvd_struct *bp)
+{
+ bp->format = lp->type;
+ switch (bp->format) {
+ case DVD_STRUCT_PHYSICAL:
+ if (bp->layer_num >= 4)
+ return (EINVAL);
+ bp->layer_num = lp->physical.layer_num;
+ break;
+ case DVD_STRUCT_COPYRIGHT:
+ bp->layer_num = lp->copyright.layer_num;
+ break;
+ case DVD_STRUCT_DISCKEY:
+ bp->agid = lp->disckey.agid;
+ break;
+ case DVD_STRUCT_BCA:
+ case DVD_STRUCT_MANUFACT:
+ break;
+ default:
+ return (EINVAL);
+ }
+ return (0);
+}
+
+static int
+bsd_to_linux_dvd_struct(struct dvd_struct *bp, l_dvd_struct *lp)
+{
+ switch (bp->format) {
+ case DVD_STRUCT_PHYSICAL: {
+ struct dvd_layer *blp = (struct dvd_layer *)bp->data;
+ struct l_dvd_layer *llp = &lp->physical.layer[bp->layer_num];
+ memset(llp, 0, sizeof(*llp));
+ llp->book_version = blp->book_version;
+ llp->book_type = blp->book_type;
+ llp->min_rate = blp->max_rate;
+ llp->disc_size = blp->disc_size;
+ llp->layer_type = blp->layer_type;
+ llp->track_path = blp->track_path;
+ llp->nlayers = blp->nlayers;
+ llp->track_density = blp->track_density;
+ llp->linear_density = blp->linear_density;
+ llp->bca = blp->bca;
+ llp->start_sector = blp->start_sector;
+ llp->end_sector = blp->end_sector;
+ llp->end_sector_l0 = blp->end_sector_l0;
+ break;
+ }
+ case DVD_STRUCT_COPYRIGHT:
+ lp->copyright.cpst = bp->cpst;
+ lp->copyright.rmi = bp->rmi;
+ break;
+ case DVD_STRUCT_DISCKEY:
+ memcpy(lp->disckey.value, bp->data, sizeof(lp->disckey.value));
+ break;
+ case DVD_STRUCT_BCA:
+ lp->bca.len = bp->length;
+ memcpy(lp->bca.value, bp->data, sizeof(lp->bca.value));
+ break;
+ case DVD_STRUCT_MANUFACT:
+ lp->manufact.len = bp->length;
+ memcpy(lp->manufact.value, bp->data,
+ sizeof(lp->manufact.value));
+ /* lp->manufact.layer_num is unused in Linux (redhat 7.0). */
+ break;
+ default:
+ return (EINVAL);
+ }
+ return (0);
+}
+
+static int
+linux_to_bsd_dvd_authinfo(l_dvd_authinfo *lp, int *bcode,
+ struct dvd_authinfo *bp)
+{
+ switch (lp->type) {
+ case LINUX_DVD_LU_SEND_AGID:
+ *bcode = DVDIOCREPORTKEY;
+ bp->format = DVD_REPORT_AGID;
+ bp->agid = lp->lsa.agid;
+ break;
+ case LINUX_DVD_HOST_SEND_CHALLENGE:
+ *bcode = DVDIOCSENDKEY;
+ bp->format = DVD_SEND_CHALLENGE;
+ bp->agid = lp->hsc.agid;
+ memcpy(bp->keychal, lp->hsc.chal, 10);
+ break;
+ case LINUX_DVD_LU_SEND_KEY1:
+ *bcode = DVDIOCREPORTKEY;
+ bp->format = DVD_REPORT_KEY1;
+ bp->agid = lp->lsk.agid;
+ break;
+ case LINUX_DVD_LU_SEND_CHALLENGE:
+ *bcode = DVDIOCREPORTKEY;
+ bp->format = DVD_REPORT_CHALLENGE;
+ bp->agid = lp->lsc.agid;
+ break;
+ case LINUX_DVD_HOST_SEND_KEY2:
+ *bcode = DVDIOCSENDKEY;
+ bp->format = DVD_SEND_KEY2;
+ bp->agid = lp->hsk.agid;
+ memcpy(bp->keychal, lp->hsk.key, 5);
+ break;
+ case LINUX_DVD_LU_SEND_TITLE_KEY:
+ *bcode = DVDIOCREPORTKEY;
+ bp->format = DVD_REPORT_TITLE_KEY;
+ bp->agid = lp->lstk.agid;
+ bp->lba = lp->lstk.lba;
+ break;
+ case LINUX_DVD_LU_SEND_ASF:
+ *bcode = DVDIOCREPORTKEY;
+ bp->format = DVD_REPORT_ASF;
+ bp->agid = lp->lsasf.agid;
+ break;
+ case LINUX_DVD_INVALIDATE_AGID:
+ *bcode = DVDIOCREPORTKEY;
+ bp->format = DVD_INVALIDATE_AGID;
+ bp->agid = lp->lsa.agid;
+ break;
+ case LINUX_DVD_LU_SEND_RPC_STATE:
+ *bcode = DVDIOCREPORTKEY;
+ bp->format = DVD_REPORT_RPC;
+ break;
+ case LINUX_DVD_HOST_SEND_RPC_STATE:
+ *bcode = DVDIOCSENDKEY;
+ bp->format = DVD_SEND_RPC;
+ bp->region = lp->hrpcs.pdrc;
+ break;
+ default:
+ return (EINVAL);
+ }
+ return (0);
+}
+
+static int
+bsd_to_linux_dvd_authinfo(struct dvd_authinfo *bp, l_dvd_authinfo *lp)
+{
+ switch (lp->type) {
+ case LINUX_DVD_LU_SEND_AGID:
+ lp->lsa.agid = bp->agid;
+ break;
+ case LINUX_DVD_HOST_SEND_CHALLENGE:
+ lp->type = LINUX_DVD_LU_SEND_KEY1;
+ break;
+ case LINUX_DVD_LU_SEND_KEY1:
+ memcpy(lp->lsk.key, bp->keychal, sizeof(lp->lsk.key));
+ break;
+ case LINUX_DVD_LU_SEND_CHALLENGE:
+ memcpy(lp->lsc.chal, bp->keychal, sizeof(lp->lsc.chal));
+ break;
+ case LINUX_DVD_HOST_SEND_KEY2:
+ lp->type = LINUX_DVD_AUTH_ESTABLISHED;
+ break;
+ case LINUX_DVD_LU_SEND_TITLE_KEY:
+ memcpy(lp->lstk.title_key, bp->keychal,
+ sizeof(lp->lstk.title_key));
+ lp->lstk.cpm = bp->cpm;
+ lp->lstk.cp_sec = bp->cp_sec;
+ lp->lstk.cgms = bp->cgms;
+ break;
+ case LINUX_DVD_LU_SEND_ASF:
+ lp->lsasf.asf = bp->asf;
+ break;
+ case LINUX_DVD_INVALIDATE_AGID:
+ break;
+ case LINUX_DVD_LU_SEND_RPC_STATE:
+ lp->lrpcs.type = bp->reg_type;
+ lp->lrpcs.vra = bp->vend_rsts;
+ lp->lrpcs.ucca = bp->user_rsts;
+ lp->lrpcs.region_mask = bp->region;
+ lp->lrpcs.rpc_scheme = bp->rpc_scheme;
+ break;
+ case LINUX_DVD_HOST_SEND_RPC_STATE:
+ break;
+ default:
+ return (EINVAL);
+ }
+ return (0);
+}
+
+static int
+linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args)
+{
+ struct file *fp;
+ int error;
+
+ error = fget(td, args->fd, &cap_ioctl_rights, &fp);
+ if (error != 0)
+ return (error);
+ switch (args->cmd & 0xffff) {
+ case LINUX_CDROMPAUSE:
+ args->cmd = CDIOCPAUSE;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_CDROMRESUME:
+ args->cmd = CDIOCRESUME;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_CDROMPLAYMSF:
+ args->cmd = CDIOCPLAYMSF;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_CDROMPLAYTRKIND:
+ args->cmd = CDIOCPLAYTRACKS;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_CDROMREADTOCHDR: {
+ struct ioc_toc_header th;
+ struct linux_cdrom_tochdr lth;
+ error = fo_ioctl(fp, CDIOREADTOCHEADER, (caddr_t)&th,
+ td->td_ucred, td);
+ if (!error) {
+ lth.cdth_trk0 = th.starting_track;
+ lth.cdth_trk1 = th.ending_track;
+ copyout(&lth, (void *)args->arg, sizeof(lth));
+ }
+ break;
+ }
+
+ case LINUX_CDROMREADTOCENTRY: {
+ struct linux_cdrom_tocentry lte;
+ struct ioc_read_toc_single_entry irtse;
+
+ error = copyin((void *)args->arg, &lte, sizeof(lte));
+ if (error)
+ break;
+ irtse.address_format = lte.cdte_format;
+ irtse.track = lte.cdte_track;
+ error = fo_ioctl(fp, CDIOREADTOCENTRY, (caddr_t)&irtse,
+ td->td_ucred, td);
+ if (!error) {
+ lte.cdte_ctrl = irtse.entry.control;
+ lte.cdte_adr = irtse.entry.addr_type;
+ bsd_to_linux_msf_lba(irtse.address_format,
+ &irtse.entry.addr, &lte.cdte_addr);
+ error = copyout(&lte, (void *)args->arg, sizeof(lte));
+ }
+ break;
+ }
+
+ case LINUX_CDROMSTOP:
+ args->cmd = CDIOCSTOP;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_CDROMSTART:
+ args->cmd = CDIOCSTART;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_CDROMEJECT:
+ args->cmd = CDIOCEJECT;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ /* LINUX_CDROMVOLCTRL */
+
+ case LINUX_CDROMSUBCHNL: {
+ struct linux_cdrom_subchnl sc;
+ struct ioc_read_subchannel bsdsc;
+ struct cd_sub_channel_info bsdinfo;
+
+ error = copyin((void *)args->arg, &sc, sizeof(sc));
+ if (error)
+ break;
+
+ /*
+ * Invoke the native ioctl and bounce the returned data through
+ * the userspace buffer. This works because the Linux structure
+ * is the same size as our structures for the subchannel header
+ * and position data.
+ */
+ bsdsc.address_format = CD_LBA_FORMAT;
+ bsdsc.data_format = CD_CURRENT_POSITION;
+ bsdsc.track = 0;
+ bsdsc.data_len = sizeof(sc);
+ bsdsc.data = (void *)args->arg;
+ error = fo_ioctl(fp, CDIOCREADSUBCHANNEL, (caddr_t)&bsdsc,
+ td->td_ucred, td);
+ if (error)
+ break;
+ error = copyin((void *)args->arg, &bsdinfo, sizeof(bsdinfo));
+ if (error)
+ break;
+ sc.cdsc_audiostatus = bsdinfo.header.audio_status;
+ sc.cdsc_adr = bsdinfo.what.position.addr_type;
+ sc.cdsc_ctrl = bsdinfo.what.position.control;
+ sc.cdsc_trk = bsdinfo.what.position.track_number;
+ sc.cdsc_ind = bsdinfo.what.position.index_number;
+ set_linux_cdrom_addr(&sc.cdsc_absaddr, sc.cdsc_format,
+ bsdinfo.what.position.absaddr.lba);
+ set_linux_cdrom_addr(&sc.cdsc_reladdr, sc.cdsc_format,
+ bsdinfo.what.position.reladdr.lba);
+ error = copyout(&sc, (void *)args->arg, sizeof(sc));
+ break;
+ }
+
+ /* LINUX_CDROMREADMODE2 */
+ /* LINUX_CDROMREADMODE1 */
+ /* LINUX_CDROMREADAUDIO */
+ /* LINUX_CDROMEJECT_SW */
+ /* LINUX_CDROMMULTISESSION */
+ /* LINUX_CDROM_GET_UPC */
+
+ case LINUX_CDROMRESET:
+ args->cmd = CDIOCRESET;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ /* LINUX_CDROMVOLREAD */
+ /* LINUX_CDROMREADRAW */
+ /* LINUX_CDROMREADCOOKED */
+ /* LINUX_CDROMSEEK */
+ /* LINUX_CDROMPLAYBLK */
+ /* LINUX_CDROMREADALL */
+ /* LINUX_CDROMCLOSETRAY */
+ /* LINUX_CDROMLOADFROMSLOT */
+ /* LINUX_CDROMGETSPINDOWN */
+ /* LINUX_CDROMSETSPINDOWN */
+ /* LINUX_CDROM_SET_OPTIONS */
+ /* LINUX_CDROM_CLEAR_OPTIONS */
+ /* LINUX_CDROM_SELECT_SPEED */
+ /* LINUX_CDROM_SELECT_DISC */
+ /* LINUX_CDROM_MEDIA_CHANGED */
+ /* LINUX_CDROM_DRIVE_STATUS */
+ /* LINUX_CDROM_DISC_STATUS */
+ /* LINUX_CDROM_CHANGER_NSLOTS */
+ /* LINUX_CDROM_LOCKDOOR */
+ /* LINUX_CDROM_DEBUG */
+ /* LINUX_CDROM_GET_CAPABILITY */
+ /* LINUX_CDROMAUDIOBUFSIZ */
+
+ case LINUX_DVD_READ_STRUCT: {
+ l_dvd_struct *lds;
+ struct dvd_struct *bds;
+
+ lds = malloc(sizeof(*lds), M_LINUX, M_WAITOK);
+ bds = malloc(sizeof(*bds), M_LINUX, M_WAITOK);
+ error = copyin((void *)args->arg, lds, sizeof(*lds));
+ if (error)
+ goto out;
+ error = linux_to_bsd_dvd_struct(lds, bds);
+ if (error)
+ goto out;
+ error = fo_ioctl(fp, DVDIOCREADSTRUCTURE, (caddr_t)bds,
+ td->td_ucred, td);
+ if (error)
+ goto out;
+ error = bsd_to_linux_dvd_struct(bds, lds);
+ if (error)
+ goto out;
+ error = copyout(lds, (void *)args->arg, sizeof(*lds));
+ out:
+ free(bds, M_LINUX);
+ free(lds, M_LINUX);
+ break;
+ }
+
+ /* LINUX_DVD_WRITE_STRUCT */
+
+ case LINUX_DVD_AUTH: {
+ l_dvd_authinfo lda;
+ struct dvd_authinfo bda;
+ int bcode;
+
+ error = copyin((void *)args->arg, &lda, sizeof(lda));
+ if (error)
+ break;
+ error = linux_to_bsd_dvd_authinfo(&lda, &bcode, &bda);
+ if (error)
+ break;
+ error = fo_ioctl(fp, bcode, (caddr_t)&bda, td->td_ucred,
+ td);
+ if (error) {
+ if (lda.type == LINUX_DVD_HOST_SEND_KEY2) {
+ lda.type = LINUX_DVD_AUTH_FAILURE;
+ copyout(&lda, (void *)args->arg, sizeof(lda));
+ }
+ break;
+ }
+ error = bsd_to_linux_dvd_authinfo(&bda, &lda);
+ if (error)
+ break;
+ error = copyout(&lda, (void *)args->arg, sizeof(lda));
+ break;
+ }
+
+ case LINUX_SCSI_GET_BUS_NUMBER:
+ {
+ struct sg_scsi_id id;
+
+ error = fo_ioctl(fp, SG_GET_SCSI_ID, (caddr_t)&id,
+ td->td_ucred, td);
+ if (error)
+ break;
+ error = copyout(&id.channel, (void *)args->arg, sizeof(int));
+ break;
+ }
+
+ case LINUX_SCSI_GET_IDLUN:
+ {
+ struct sg_scsi_id id;
+ struct scsi_idlun idl;
+
+ error = fo_ioctl(fp, SG_GET_SCSI_ID, (caddr_t)&id,
+ td->td_ucred, td);
+ if (error)
+ break;
+ idl.dev_id = (id.scsi_id & 0xff) + ((id.lun & 0xff) << 8) +
+ ((id.channel & 0xff) << 16) + ((id.host_no & 0xff) << 24);
+ idl.host_unique_id = id.host_no;
+ error = copyout(&idl, (void *)args->arg, sizeof(idl));
+ break;
+ }
+
+ /* LINUX_CDROM_SEND_PACKET */
+ /* LINUX_CDROM_NEXT_WRITABLE */
+ /* LINUX_CDROM_LAST_WRITTEN */
+
+ default:
+ error = ENOIOCTL;
+ break;
+ }
+
+ fdrop(fp, td);
+ return (error);
+}
+
+static int
+linux_ioctl_vfat(struct thread *td, struct linux_ioctl_args *args)
+{
+
+ return (ENOTTY);
+}
+
+/*
+ * Sound related ioctls
+ */
+
+struct linux_old_mixer_info {
+ char id[16];
+ char name[32];
+};
+
+static u_int32_t dirbits[4] = { IOC_VOID, IOC_IN, IOC_OUT, IOC_INOUT };
+
+#define SETDIR(c) (((c) & ~IOC_DIRMASK) | dirbits[args->cmd >> 30])
+
+static int
+linux_ioctl_sound(struct thread *td, struct linux_ioctl_args *args)
+{
+
+ switch (args->cmd & 0xffff) {
+ case LINUX_SOUND_MIXER_WRITE_VOLUME:
+ args->cmd = SETDIR(SOUND_MIXER_WRITE_VOLUME);
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SOUND_MIXER_WRITE_BASS:
+ args->cmd = SETDIR(SOUND_MIXER_WRITE_BASS);
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SOUND_MIXER_WRITE_TREBLE:
+ args->cmd = SETDIR(SOUND_MIXER_WRITE_TREBLE);
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SOUND_MIXER_WRITE_SYNTH:
+ args->cmd = SETDIR(SOUND_MIXER_WRITE_SYNTH);
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SOUND_MIXER_WRITE_PCM:
+ args->cmd = SETDIR(SOUND_MIXER_WRITE_PCM);
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SOUND_MIXER_WRITE_SPEAKER:
+ args->cmd = SETDIR(SOUND_MIXER_WRITE_SPEAKER);
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SOUND_MIXER_WRITE_LINE:
+ args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE);
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SOUND_MIXER_WRITE_MIC:
+ args->cmd = SETDIR(SOUND_MIXER_WRITE_MIC);
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SOUND_MIXER_WRITE_CD:
+ args->cmd = SETDIR(SOUND_MIXER_WRITE_CD);
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SOUND_MIXER_WRITE_IMIX:
+ args->cmd = SETDIR(SOUND_MIXER_WRITE_IMIX);
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SOUND_MIXER_WRITE_ALTPCM:
+ args->cmd = SETDIR(SOUND_MIXER_WRITE_ALTPCM);
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SOUND_MIXER_WRITE_RECLEV:
+ args->cmd = SETDIR(SOUND_MIXER_WRITE_RECLEV);
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SOUND_MIXER_WRITE_IGAIN:
+ args->cmd = SETDIR(SOUND_MIXER_WRITE_IGAIN);
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SOUND_MIXER_WRITE_OGAIN:
+ args->cmd = SETDIR(SOUND_MIXER_WRITE_OGAIN);
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SOUND_MIXER_WRITE_LINE1:
+ args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE1);
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SOUND_MIXER_WRITE_LINE2:
+ args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE2);
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SOUND_MIXER_WRITE_LINE3:
+ args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE3);
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SOUND_MIXER_WRITE_MONITOR:
+ args->cmd = SETDIR(SOUND_MIXER_WRITE_MONITOR);
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SOUND_MIXER_INFO: {
+ /* Key on encoded length */
+ switch ((args->cmd >> 16) & 0x1fff) {
+ case 0x005c: { /* SOUND_MIXER_INFO */
+ args->cmd = SOUND_MIXER_INFO;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+ }
+ case 0x0030: { /* SOUND_OLD_MIXER_INFO */
+ struct linux_old_mixer_info info;
+ bzero(&info, sizeof(info));
+ strncpy(info.id, "OSS", sizeof(info.id) - 1);
+ strncpy(info.name, "FreeBSD OSS Mixer", sizeof(info.name) - 1);
+ copyout(&info, (void *)args->arg, sizeof(info));
+ return (0);
+ }
+ default:
+ return (ENOIOCTL);
+ }
+ break;
+ }
+
+ case LINUX_OSS_GETVERSION: {
+ int version = linux_get_oss_version(td);
+ return (copyout(&version, (void *)args->arg, sizeof(int)));
+ }
+
+ case LINUX_SOUND_MIXER_READ_STEREODEVS:
+ args->cmd = SOUND_MIXER_READ_STEREODEVS;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SOUND_MIXER_READ_CAPS:
+ args->cmd = SOUND_MIXER_READ_CAPS;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SOUND_MIXER_READ_RECMASK:
+ args->cmd = SOUND_MIXER_READ_RECMASK;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SOUND_MIXER_READ_DEVMASK:
+ args->cmd = SOUND_MIXER_READ_DEVMASK;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SOUND_MIXER_WRITE_RECSRC:
+ args->cmd = SETDIR(SOUND_MIXER_WRITE_RECSRC);
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_DSP_RESET:
+ args->cmd = SNDCTL_DSP_RESET;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_DSP_SYNC:
+ args->cmd = SNDCTL_DSP_SYNC;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_DSP_SPEED:
+ args->cmd = SNDCTL_DSP_SPEED;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_DSP_STEREO:
+ args->cmd = SNDCTL_DSP_STEREO;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_DSP_GETBLKSIZE: /* LINUX_SNDCTL_DSP_SETBLKSIZE */
+ args->cmd = SNDCTL_DSP_GETBLKSIZE;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_DSP_SETFMT:
+ args->cmd = SNDCTL_DSP_SETFMT;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SOUND_PCM_WRITE_CHANNELS:
+ args->cmd = SOUND_PCM_WRITE_CHANNELS;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SOUND_PCM_WRITE_FILTER:
+ args->cmd = SOUND_PCM_WRITE_FILTER;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_DSP_POST:
+ args->cmd = SNDCTL_DSP_POST;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_DSP_SUBDIVIDE:
+ args->cmd = SNDCTL_DSP_SUBDIVIDE;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_DSP_SETFRAGMENT:
+ args->cmd = SNDCTL_DSP_SETFRAGMENT;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_DSP_GETFMTS:
+ args->cmd = SNDCTL_DSP_GETFMTS;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_DSP_GETOSPACE:
+ args->cmd = SNDCTL_DSP_GETOSPACE;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_DSP_GETISPACE:
+ args->cmd = SNDCTL_DSP_GETISPACE;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_DSP_NONBLOCK:
+ args->cmd = SNDCTL_DSP_NONBLOCK;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_DSP_GETCAPS:
+ args->cmd = SNDCTL_DSP_GETCAPS;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_DSP_SETTRIGGER: /* LINUX_SNDCTL_GETTRIGGER */
+ args->cmd = SNDCTL_DSP_SETTRIGGER;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_DSP_GETIPTR:
+ args->cmd = SNDCTL_DSP_GETIPTR;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_DSP_GETOPTR:
+ args->cmd = SNDCTL_DSP_GETOPTR;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_DSP_SETDUPLEX:
+ args->cmd = SNDCTL_DSP_SETDUPLEX;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_DSP_GETODELAY:
+ args->cmd = SNDCTL_DSP_GETODELAY;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_SEQ_RESET:
+ args->cmd = SNDCTL_SEQ_RESET;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_SEQ_SYNC:
+ args->cmd = SNDCTL_SEQ_SYNC;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_SYNTH_INFO:
+ args->cmd = SNDCTL_SYNTH_INFO;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_SEQ_CTRLRATE:
+ args->cmd = SNDCTL_SEQ_CTRLRATE;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_SEQ_GETOUTCOUNT:
+ args->cmd = SNDCTL_SEQ_GETOUTCOUNT;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_SEQ_GETINCOUNT:
+ args->cmd = SNDCTL_SEQ_GETINCOUNT;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_SEQ_PERCMODE:
+ args->cmd = SNDCTL_SEQ_PERCMODE;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_FM_LOAD_INSTR:
+ args->cmd = SNDCTL_FM_LOAD_INSTR;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_SEQ_TESTMIDI:
+ args->cmd = SNDCTL_SEQ_TESTMIDI;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_SEQ_RESETSAMPLES:
+ args->cmd = SNDCTL_SEQ_RESETSAMPLES;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_SEQ_NRSYNTHS:
+ args->cmd = SNDCTL_SEQ_NRSYNTHS;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_SEQ_NRMIDIS:
+ args->cmd = SNDCTL_SEQ_NRMIDIS;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_MIDI_INFO:
+ args->cmd = SNDCTL_MIDI_INFO;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_SEQ_TRESHOLD:
+ args->cmd = SNDCTL_SEQ_TRESHOLD;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+
+ case LINUX_SNDCTL_SYNTH_MEMAVL:
+ args->cmd = SNDCTL_SYNTH_MEMAVL;
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+ }
+
+ return (ENOIOCTL);
+}
+
+/*
+ * Console related ioctls
+ */
+
+static int
+linux_ioctl_console(struct thread *td, struct linux_ioctl_args *args)
+{
+ struct file *fp;
+ int error;
+
+ error = fget(td, args->fd, &cap_ioctl_rights, &fp);
+ if (error != 0)
+ return (error);
+ switch (args->cmd & 0xffff) {
+ case LINUX_KIOCSOUND:
+ args->cmd = KIOCSOUND;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_KDMKTONE:
+ args->cmd = KDMKTONE;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_KDGETLED:
+ args->cmd = KDGETLED;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_KDSETLED:
+ args->cmd = KDSETLED;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_KDSETMODE:
+ args->cmd = KDSETMODE;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_KDGETMODE:
+ args->cmd = KDGETMODE;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_KDGKBMODE:
+ args->cmd = KDGKBMODE;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_KDSKBMODE: {
+ int kbdmode;
+ switch (args->arg) {
+ case LINUX_KBD_RAW:
+ kbdmode = K_RAW;
+ break;
+ case LINUX_KBD_XLATE:
+ kbdmode = K_XLATE;
+ break;
+ case LINUX_KBD_MEDIUMRAW:
+ kbdmode = K_RAW;
+ break;
+ default:
+ fdrop(fp, td);
+ return (EINVAL);
+ }
+ error = (fo_ioctl(fp, KDSKBMODE, (caddr_t)&kbdmode,
+ td->td_ucred, td));
+ break;
+ }
+
+ case LINUX_VT_OPENQRY:
+ args->cmd = VT_OPENQRY;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_VT_GETMODE:
+ args->cmd = VT_GETMODE;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_VT_SETMODE: {
+ struct vt_mode mode;
+ if ((error = copyin((void *)args->arg, &mode, sizeof(mode))))
+ break;
+ if (LINUX_SIG_VALID(mode.relsig))
+ mode.relsig = linux_to_bsd_signal(mode.relsig);
+ else
+ mode.relsig = 0;
+ if (LINUX_SIG_VALID(mode.acqsig))
+ mode.acqsig = linux_to_bsd_signal(mode.acqsig);
+ else
+ mode.acqsig = 0;
+ /* XXX. Linux ignores frsig and set it to 0. */
+ mode.frsig = 0;
+ if ((error = copyout(&mode, (void *)args->arg, sizeof(mode))))
+ break;
+ args->cmd = VT_SETMODE;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+ }
+
+ case LINUX_VT_GETSTATE:
+ args->cmd = VT_GETACTIVE;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_VT_RELDISP:
+ args->cmd = VT_RELDISP;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_VT_ACTIVATE:
+ args->cmd = VT_ACTIVATE;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ case LINUX_VT_WAITACTIVE:
+ args->cmd = VT_WAITACTIVE;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
+ break;
+
+ default:
+ error = ENOIOCTL;
+ break;
+ }
+
+ fdrop(fp, td);
+ return (error);
+}
+
+/*
+ * Implement the SIOCGIFNAME ioctl
+ */
+
+static int
+linux_ioctl_ifname(struct thread *td, struct l_ifreq *uifr)
+{
+ struct l_ifreq ifr;
+ struct ifnet *ifp;
+ int error, ethno, index;
+
+ error = copyin(uifr, &ifr, sizeof(ifr));
+ if (error != 0)
+ return (error);
+
+ CURVNET_SET(TD_TO_VNET(curthread));
+ IFNET_RLOCK();
+ index = 1; /* ifr.ifr_ifindex starts from 1 */
+ ethno = 0;
+ error = ENODEV;
+ CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+ if (ifr.ifr_ifindex == index) {
+ if (IFP_IS_ETH(ifp))
+ snprintf(ifr.ifr_name, LINUX_IFNAMSIZ,
+ "eth%d", ethno);
+ else
+ strlcpy(ifr.ifr_name, ifp->if_xname,
+ LINUX_IFNAMSIZ);
+ error = 0;
+ break;
+ }
+ if (IFP_IS_ETH(ifp))
+ ethno++;
+ index++;
+ }
+ IFNET_RUNLOCK();
+ if (error == 0)
+ error = copyout(&ifr, uifr, sizeof(ifr));
+ CURVNET_RESTORE();
+
+ return (error);
+}
+
+/*
+ * Implement the SIOCGIFCONF ioctl
+ */
+
+static int
+linux_ifconf(struct thread *td, struct ifconf *uifc)
+{
+#ifdef COMPAT_LINUX32
+ struct l_ifconf ifc;
+#else
+ struct ifconf ifc;
+#endif
+ struct l_ifreq ifr;
+ struct ifnet *ifp;
+ struct ifaddr *ifa;
+ struct sbuf *sb;
+ int error, ethno, full = 0, valid_len, max_len;
+
+ error = copyin(uifc, &ifc, sizeof(ifc));
+ if (error != 0)
+ return (error);
+
+ max_len = maxphys - 1;
+
+ CURVNET_SET(TD_TO_VNET(td));
+ /* handle the 'request buffer size' case */
+ if ((l_uintptr_t)ifc.ifc_buf == PTROUT(NULL)) {
+ ifc.ifc_len = 0;
+ IFNET_RLOCK();
+ CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ struct sockaddr *sa = ifa->ifa_addr;
+ if (sa->sa_family == AF_INET)
+ ifc.ifc_len += sizeof(ifr);
+ }
+ }
+ IFNET_RUNLOCK();
+ error = copyout(&ifc, uifc, sizeof(ifc));
+ CURVNET_RESTORE();
+ return (error);
+ }
+
+ if (ifc.ifc_len <= 0) {
+ CURVNET_RESTORE();
+ return (EINVAL);
+ }
+
+again:
+ /* Keep track of eth interfaces */
+ ethno = 0;
+ if (ifc.ifc_len <= max_len) {
+ max_len = ifc.ifc_len;
+ full = 1;
+ }
+ sb = sbuf_new(NULL, NULL, max_len + 1, SBUF_FIXEDLEN);
+ max_len = 0;
+ valid_len = 0;
+
+ /* Return all AF_INET addresses of all interfaces */
+ IFNET_RLOCK();
+ CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+ int addrs = 0;
+
+ bzero(&ifr, sizeof(ifr));
+ if (IFP_IS_ETH(ifp))
+ snprintf(ifr.ifr_name, LINUX_IFNAMSIZ, "eth%d",
+ ethno++);
+ else
+ strlcpy(ifr.ifr_name, ifp->if_xname, LINUX_IFNAMSIZ);
+
+ /* Walk the address list */
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ struct sockaddr *sa = ifa->ifa_addr;
+
+ if (sa->sa_family == AF_INET) {
+ ifr.ifr_addr.sa_family = LINUX_AF_INET;
+ memcpy(ifr.ifr_addr.sa_data, sa->sa_data,
+ sizeof(ifr.ifr_addr.sa_data));
+ sbuf_bcat(sb, &ifr, sizeof(ifr));
+ max_len += sizeof(ifr);
+ addrs++;
+ }
+
+ if (sbuf_error(sb) == 0)
+ valid_len = sbuf_len(sb);
+ }
+ if (addrs == 0) {
+ bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
+ sbuf_bcat(sb, &ifr, sizeof(ifr));
+ max_len += sizeof(ifr);
+
+ if (sbuf_error(sb) == 0)
+ valid_len = sbuf_len(sb);
+ }
+ }
+ IFNET_RUNLOCK();
+
+ if (valid_len != max_len && !full) {
+ sbuf_delete(sb);
+ goto again;
+ }
+
+ ifc.ifc_len = valid_len;
+ sbuf_finish(sb);
+ error = copyout(sbuf_data(sb), PTRIN(ifc.ifc_buf), ifc.ifc_len);
+ if (error == 0)
+ error = copyout(&ifc, uifc, sizeof(ifc));
+ sbuf_delete(sb);
+ CURVNET_RESTORE();
+
+ return (error);
+}
+
+static int
+linux_gifflags(struct thread *td, struct ifnet *ifp, struct l_ifreq *ifr)
+{
+ l_short flags;
+
+ linux_ifflags(ifp, &flags);
+
+ return (copyout(&flags, &ifr->ifr_flags, sizeof(flags)));
+}
+
+static int
+linux_gifhwaddr(struct ifnet *ifp, struct l_ifreq *ifr)
+{
+ struct l_sockaddr lsa;
+
+ if (linux_ifhwaddr(ifp, &lsa) != 0)
+ return (ENOENT);
+
+ return (copyout(&lsa, &ifr->ifr_hwaddr, sizeof(lsa)));
+}
+
+ /*
+* If we fault in bsd_to_linux_ifreq() then we will fault when we call
+* the native ioctl(). Thus, we don't really need to check the return
+* value of this function.
+*/
+static int
+bsd_to_linux_ifreq(struct ifreq *arg)
+{
+ struct ifreq ifr;
+ size_t ifr_len = sizeof(struct ifreq);
+ int error;
+
+ if ((error = copyin(arg, &ifr, ifr_len)))
+ return (error);
+
+ *(u_short *)&ifr.ifr_addr = ifr.ifr_addr.sa_family;
+
+ error = copyout(&ifr, arg, ifr_len);
+
+ return (error);
+}
+
+/*
+ * Socket related ioctls
+ */
+
+static int
+linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args)
+{
+ char lifname[LINUX_IFNAMSIZ], ifname[IFNAMSIZ];
+ struct ifnet *ifp;
+ struct file *fp;
+ int error, type;
+
+ ifp = NULL;
+ error = 0;
+
+ error = fget(td, args->fd, &cap_ioctl_rights, &fp);
+ if (error != 0)
+ return (error);
+ type = fp->f_type;
+ fdrop(fp, td);
+ if (type != DTYPE_SOCKET) {
+ /* not a socket - probably a tap / vmnet device */
+ switch (args->cmd) {
+ case LINUX_SIOCGIFADDR:
+ case LINUX_SIOCSIFADDR:
+ case LINUX_SIOCGIFFLAGS:
+ return (linux_ioctl_special(td, args));
+ default:
+ return (ENOIOCTL);
+ }
+ }
+
+ switch (args->cmd & 0xffff) {
+ case LINUX_FIOGETOWN:
+ case LINUX_FIOSETOWN:
+ case LINUX_SIOCADDMULTI:
+ case LINUX_SIOCATMARK:
+ case LINUX_SIOCDELMULTI:
+ case LINUX_SIOCGIFNAME:
+ case LINUX_SIOCGIFCONF:
+ case LINUX_SIOCGPGRP:
+ case LINUX_SIOCSPGRP:
+ case LINUX_SIOCGIFCOUNT:
+ /* these ioctls don't take an interface name */
+ break;
+
+ case LINUX_SIOCGIFFLAGS:
+ case LINUX_SIOCGIFADDR:
+ case LINUX_SIOCSIFADDR:
+ case LINUX_SIOCGIFDSTADDR:
+ case LINUX_SIOCGIFBRDADDR:
+ case LINUX_SIOCGIFNETMASK:
+ case LINUX_SIOCSIFNETMASK:
+ case LINUX_SIOCGIFMTU:
+ case LINUX_SIOCSIFMTU:
+ case LINUX_SIOCSIFNAME:
+ case LINUX_SIOCGIFHWADDR:
+ case LINUX_SIOCSIFHWADDR:
+ case LINUX_SIOCDEVPRIVATE:
+ case LINUX_SIOCDEVPRIVATE+1:
+ case LINUX_SIOCGIFINDEX:
+ /* copy in the interface name and translate it. */
+ error = copyin((void *)args->arg, lifname, LINUX_IFNAMSIZ);
+ if (error != 0)
+ return (error);
+ memset(ifname, 0, sizeof(ifname));
+ ifp = ifname_linux_to_bsd(td, lifname, ifname);
+ if (ifp == NULL)
+ return (EINVAL);
+ /*
+ * We need to copy it back out in case we pass the
+ * request on to our native ioctl(), which will expect
+ * the ifreq to be in user space and have the correct
+ * interface name.
+ */
+ error = copyout(ifname, (void *)args->arg, IFNAMSIZ);
+ if (error != 0)
+ return (error);
+ break;
+
+ default:
+ return (ENOIOCTL);
+ }
+
+ switch (args->cmd & 0xffff) {
+ case LINUX_FIOSETOWN:
+ args->cmd = FIOSETOWN;
+ error = sys_ioctl(td, (struct ioctl_args *)args);
+ break;
+
+ case LINUX_SIOCSPGRP:
+ args->cmd = SIOCSPGRP;
+ error = sys_ioctl(td, (struct ioctl_args *)args);
+ break;
+
+ case LINUX_FIOGETOWN:
+ args->cmd = FIOGETOWN;
+ error = sys_ioctl(td, (struct ioctl_args *)args);
+ break;
+
+ case LINUX_SIOCGPGRP:
+ args->cmd = SIOCGPGRP;
+ error = sys_ioctl(td, (struct ioctl_args *)args);
+ break;
+
+ case LINUX_SIOCATMARK:
+ args->cmd = SIOCATMARK;
+ error = sys_ioctl(td, (struct ioctl_args *)args);
+ break;
+
+ /* LINUX_SIOCGSTAMP */
+
+ case LINUX_SIOCGIFNAME:
+ error = linux_ioctl_ifname(td, (struct l_ifreq *)args->arg);
+ break;
+
+ case LINUX_SIOCGIFCONF:
+ error = linux_ifconf(td, (struct ifconf *)args->arg);
+ break;
+
+ case LINUX_SIOCGIFFLAGS:
+ args->cmd = SIOCGIFFLAGS;
+ error = linux_gifflags(td, ifp, (struct l_ifreq *)args->arg);
+ break;
+
+ case LINUX_SIOCGIFADDR:
+ args->cmd = SIOCGIFADDR;
+ error = sys_ioctl(td, (struct ioctl_args *)args);
+ bsd_to_linux_ifreq((struct ifreq *)args->arg);
+ break;
+
+ case LINUX_SIOCSIFADDR:
+ /* XXX probably doesn't work, included for completeness */
+ args->cmd = SIOCSIFADDR;
+ error = sys_ioctl(td, (struct ioctl_args *)args);
+ break;
+
+ case LINUX_SIOCGIFDSTADDR:
+ args->cmd = SIOCGIFDSTADDR;
+ error = sys_ioctl(td, (struct ioctl_args *)args);
+ bsd_to_linux_ifreq((struct ifreq *)args->arg);
+ break;
+
+ case LINUX_SIOCGIFBRDADDR:
+ args->cmd = SIOCGIFBRDADDR;
+ error = sys_ioctl(td, (struct ioctl_args *)args);
+ bsd_to_linux_ifreq((struct ifreq *)args->arg);
+ break;
+
+ case LINUX_SIOCGIFNETMASK:
+ args->cmd = SIOCGIFNETMASK;
+ error = sys_ioctl(td, (struct ioctl_args *)args);
+ bsd_to_linux_ifreq((struct ifreq *)args->arg);
+ break;
+
+ case LINUX_SIOCSIFNETMASK:
+ error = ENOIOCTL;
+ break;
+
+ case LINUX_SIOCGIFMTU:
+ args->cmd = SIOCGIFMTU;
+ error = sys_ioctl(td, (struct ioctl_args *)args);
+ break;
+
+ case LINUX_SIOCSIFMTU:
+ args->cmd = SIOCSIFMTU;
+ error = sys_ioctl(td, (struct ioctl_args *)args);
+ break;
+
+ case LINUX_SIOCSIFNAME:
+ error = ENOIOCTL;
+ break;
+
+ case LINUX_SIOCGIFHWADDR:
+ error = linux_gifhwaddr(ifp, (struct l_ifreq *)args->arg);
+ break;
+
+ case LINUX_SIOCSIFHWADDR:
+ error = ENOIOCTL;
+ break;
+
+ case LINUX_SIOCADDMULTI:
+ args->cmd = SIOCADDMULTI;
+ error = sys_ioctl(td, (struct ioctl_args *)args);
+ break;
+
+ case LINUX_SIOCDELMULTI:
+ args->cmd = SIOCDELMULTI;
+ error = sys_ioctl(td, (struct ioctl_args *)args);
+ break;
+
+ case LINUX_SIOCGIFINDEX:
+ args->cmd = SIOCGIFINDEX;
+ error = sys_ioctl(td, (struct ioctl_args *)args);
+ break;
+
+ case LINUX_SIOCGIFCOUNT:
+ error = 0;
+ break;
+
+ /*
+ * XXX This is slightly bogus, but these ioctls are currently
+ * XXX only used by the aironet (if_an) network driver.
+ */
+ case LINUX_SIOCDEVPRIVATE:
+ args->cmd = SIOCGPRIVATE_0;
+ error = sys_ioctl(td, (struct ioctl_args *)args);
+ break;
+
+ case LINUX_SIOCDEVPRIVATE+1:
+ args->cmd = SIOCGPRIVATE_1;
+ error = sys_ioctl(td, (struct ioctl_args *)args);
+ break;
+ }
+
+ if (ifp != NULL)
+ /* restore the original interface name */
+ copyout(lifname, (void *)args->arg, LINUX_IFNAMSIZ);
+
+ return (error);
+}
+
+/*
+ * Device private ioctl handler
+ */
+static int
+linux_ioctl_private(struct thread *td, struct linux_ioctl_args *args)
+{
+ struct file *fp;
+ int error, type;
+
+ error = fget(td, args->fd, &cap_ioctl_rights, &fp);
+ if (error != 0)
+ return (error);
+ type = fp->f_type;
+ fdrop(fp, td);
+ if (type == DTYPE_SOCKET)
+ return (linux_ioctl_socket(td, args));
+ return (ENOIOCTL);
+}
+
+/*
+ * DRM ioctl handler (sys/dev/drm)
+ */
+static int
+linux_ioctl_drm(struct thread *td, struct linux_ioctl_args *args)
+{
+ args->cmd = SETDIR(args->cmd);
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+}
+
+#ifdef COMPAT_LINUX32
+static int
+linux_ioctl_sg_io(struct thread *td, struct linux_ioctl_args *args)
+{
+ struct sg_io_hdr io;
+ struct sg_io_hdr32 io32;
+ struct file *fp;
+ int error;
+
+ error = fget(td, args->fd, &cap_ioctl_rights, &fp);
+ if (error != 0) {
+ printf("sg_linux_ioctl: fget returned %d\n", error);
+ return (error);
+ }
+
+ if ((error = copyin((void *)args->arg, &io32, sizeof(io32))) != 0)
+ goto out;
+
+ CP(io32, io, interface_id);
+ CP(io32, io, dxfer_direction);
+ CP(io32, io, cmd_len);
+ CP(io32, io, mx_sb_len);
+ CP(io32, io, iovec_count);
+ CP(io32, io, dxfer_len);
+ PTRIN_CP(io32, io, dxferp);
+ PTRIN_CP(io32, io, cmdp);
+ PTRIN_CP(io32, io, sbp);
+ CP(io32, io, timeout);
+ CP(io32, io, flags);
+ CP(io32, io, pack_id);
+ PTRIN_CP(io32, io, usr_ptr);
+ CP(io32, io, status);
+ CP(io32, io, masked_status);
+ CP(io32, io, msg_status);
+ CP(io32, io, sb_len_wr);
+ CP(io32, io, host_status);
+ CP(io32, io, driver_status);
+ CP(io32, io, resid);
+ CP(io32, io, duration);
+ CP(io32, io, info);
+
+ if ((error = fo_ioctl(fp, SG_IO, (caddr_t)&io, td->td_ucred, td)) != 0)
+ goto out;
+
+ CP(io, io32, interface_id);
+ CP(io, io32, dxfer_direction);
+ CP(io, io32, cmd_len);
+ CP(io, io32, mx_sb_len);
+ CP(io, io32, iovec_count);
+ CP(io, io32, dxfer_len);
+ PTROUT_CP(io, io32, dxferp);
+ PTROUT_CP(io, io32, cmdp);
+ PTROUT_CP(io, io32, sbp);
+ CP(io, io32, timeout);
+ CP(io, io32, flags);
+ CP(io, io32, pack_id);
+ PTROUT_CP(io, io32, usr_ptr);
+ CP(io, io32, status);
+ CP(io, io32, masked_status);
+ CP(io, io32, msg_status);
+ CP(io, io32, sb_len_wr);
+ CP(io, io32, host_status);
+ CP(io, io32, driver_status);
+ CP(io, io32, resid);
+ CP(io, io32, duration);
+ CP(io, io32, info);
+
+ error = copyout(&io32, (void *)args->arg, sizeof(io32));
+
+out:
+ fdrop(fp, td);
+ return (error);
+}
+#endif
+
+static int
+linux_ioctl_sg(struct thread *td, struct linux_ioctl_args *args)
+{
+
+ switch (args->cmd) {
+ case LINUX_SG_GET_VERSION_NUM:
+ args->cmd = SG_GET_VERSION_NUM;
+ break;
+ case LINUX_SG_SET_TIMEOUT:
+ args->cmd = SG_SET_TIMEOUT;
+ break;
+ case LINUX_SG_GET_TIMEOUT:
+ args->cmd = SG_GET_TIMEOUT;
+ break;
+ case LINUX_SG_IO:
+ args->cmd = SG_IO;
+#ifdef COMPAT_LINUX32
+ return (linux_ioctl_sg_io(td, args));
+#endif
+ break;
+ case LINUX_SG_GET_RESERVED_SIZE:
+ args->cmd = SG_GET_RESERVED_SIZE;
+ break;
+ case LINUX_SG_GET_SCSI_ID:
+ args->cmd = SG_GET_SCSI_ID;
+ break;
+ case LINUX_SG_GET_SG_TABLESIZE:
+ args->cmd = SG_GET_SG_TABLESIZE;
+ break;
+ default:
+ return (ENODEV);
+ }
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+}
+
+/*
+ * Video4Linux (V4L) ioctl handler
+ */
+static int
+linux_to_bsd_v4l_tuner(struct l_video_tuner *lvt, struct video_tuner *vt)
+{
+ vt->tuner = lvt->tuner;
+ strlcpy(vt->name, lvt->name, LINUX_VIDEO_TUNER_NAME_SIZE);
+ vt->rangelow = lvt->rangelow; /* possible long size conversion */
+ vt->rangehigh = lvt->rangehigh; /* possible long size conversion */
+ vt->flags = lvt->flags;
+ vt->mode = lvt->mode;
+ vt->signal = lvt->signal;
+ return (0);
+}
+
+static int
+bsd_to_linux_v4l_tuner(struct video_tuner *vt, struct l_video_tuner *lvt)
+{
+ lvt->tuner = vt->tuner;
+ strlcpy(lvt->name, vt->name, LINUX_VIDEO_TUNER_NAME_SIZE);
+ lvt->rangelow = vt->rangelow; /* possible long size conversion */
+ lvt->rangehigh = vt->rangehigh; /* possible long size conversion */
+ lvt->flags = vt->flags;
+ lvt->mode = vt->mode;
+ lvt->signal = vt->signal;
+ return (0);
+}
+
+#ifdef COMPAT_LINUX_V4L_CLIPLIST
+static int
+linux_to_bsd_v4l_clip(struct l_video_clip *lvc, struct video_clip *vc)
+{
+ vc->x = lvc->x;
+ vc->y = lvc->y;
+ vc->width = lvc->width;
+ vc->height = lvc->height;
+ vc->next = PTRIN(lvc->next); /* possible pointer size conversion */
+ return (0);
+}
+#endif
+
+static int
+linux_to_bsd_v4l_window(struct l_video_window *lvw, struct video_window *vw)
+{
+ vw->x = lvw->x;
+ vw->y = lvw->y;
+ vw->width = lvw->width;
+ vw->height = lvw->height;
+ vw->chromakey = lvw->chromakey;
+ vw->flags = lvw->flags;
+ vw->clips = PTRIN(lvw->clips); /* possible pointer size conversion */
+ vw->clipcount = lvw->clipcount;
+ return (0);
+}
+
+static int
+bsd_to_linux_v4l_window(struct video_window *vw, struct l_video_window *lvw)
+{
+ memset(lvw, 0, sizeof(*lvw));
+
+ lvw->x = vw->x;
+ lvw->y = vw->y;
+ lvw->width = vw->width;
+ lvw->height = vw->height;
+ lvw->chromakey = vw->chromakey;
+ lvw->flags = vw->flags;
+ lvw->clips = PTROUT(vw->clips); /* possible pointer size conversion */
+ lvw->clipcount = vw->clipcount;
+ return (0);
+}
+
+static int
+linux_to_bsd_v4l_buffer(struct l_video_buffer *lvb, struct video_buffer *vb)
+{
+ vb->base = PTRIN(lvb->base); /* possible pointer size conversion */
+ vb->height = lvb->height;
+ vb->width = lvb->width;
+ vb->depth = lvb->depth;
+ vb->bytesperline = lvb->bytesperline;
+ return (0);
+}
+
+static int
+bsd_to_linux_v4l_buffer(struct video_buffer *vb, struct l_video_buffer *lvb)
+{
+ lvb->base = PTROUT(vb->base); /* possible pointer size conversion */
+ lvb->height = vb->height;
+ lvb->width = vb->width;
+ lvb->depth = vb->depth;
+ lvb->bytesperline = vb->bytesperline;
+ return (0);
+}
+
+static int
+linux_to_bsd_v4l_code(struct l_video_code *lvc, struct video_code *vc)
+{
+ strlcpy(vc->loadwhat, lvc->loadwhat, LINUX_VIDEO_CODE_LOADWHAT_SIZE);
+ vc->datasize = lvc->datasize;
+ vc->data = PTRIN(lvc->data); /* possible pointer size conversion */
+ return (0);
+}
+
+#ifdef COMPAT_LINUX_V4L_CLIPLIST
+static int
+linux_v4l_clip_copy(void *lvc, struct video_clip **ppvc)
+{
+ int error;
+ struct video_clip vclip;
+ struct l_video_clip l_vclip;
+
+ error = copyin(lvc, &l_vclip, sizeof(l_vclip));
+ if (error) return (error);
+ linux_to_bsd_v4l_clip(&l_vclip, &vclip);
+ /* XXX: If there can be no concurrency: s/M_NOWAIT/M_WAITOK/ */
+ if ((*ppvc = malloc(sizeof(**ppvc), M_LINUX, M_NOWAIT)) == NULL)
+ return (ENOMEM); /* XXX: Linux has no ENOMEM here. */
+ memcpy(*ppvc, &vclip, sizeof(vclip));
+ (*ppvc)->next = NULL;
+ return (0);
+}
+
+static int
+linux_v4l_cliplist_free(struct video_window *vw)
+{
+ struct video_clip **ppvc;
+ struct video_clip **ppvc_next;
+
+ for (ppvc = &(vw->clips); *ppvc != NULL; ppvc = ppvc_next) {
+ ppvc_next = &((*ppvc)->next);
+ free(*ppvc, M_LINUX);
+ }
+ vw->clips = NULL;
+
+ return (0);
+}
+
+static int
+linux_v4l_cliplist_copy(struct l_video_window *lvw, struct video_window *vw)
+{
+ int error;
+ int clipcount;
+ void *plvc;
+ struct video_clip **ppvc;
+
+ /*
+ * XXX: The cliplist is used to pass in a list of clipping
+ * rectangles or, if clipcount == VIDEO_CLIP_BITMAP, a
+ * clipping bitmap. Some Linux apps, however, appear to
+ * leave cliplist and clips uninitialized. In any case,
+ * the cliplist is not used by pwc(4), at the time of
+ * writing, FreeBSD's only V4L driver. When a driver
+ * that uses the cliplist is developed, this code may
+ * need re-examiniation.
+ */
+ error = 0;
+ clipcount = vw->clipcount;
+ if (clipcount == VIDEO_CLIP_BITMAP) {
+ /*
+ * In this case, the pointer (clips) is overloaded
+ * to be a "void *" to a bitmap, therefore there
+ * is no struct video_clip to copy now.
+ */
+ } else if (clipcount > 0 && clipcount <= 16384) {
+ /*
+ * Clips points to list of clip rectangles, so
+ * copy the list.
+ *
+ * XXX: Upper limit of 16384 was used here to try to
+ * avoid cases when clipcount and clips pointer
+ * are uninitialized and therefore have high random
+ * values, as is the case in the Linux Skype
+ * application. The value 16384 was chosen as that
+ * is what is used in the Linux stradis(4) MPEG
+ * decoder driver, the only place we found an
+ * example of cliplist use.
+ */
+ plvc = PTRIN(lvw->clips);
+ vw->clips = NULL;
+ ppvc = &(vw->clips);
+ while (clipcount-- > 0) {
+ if (plvc == NULL) {
+ error = EFAULT;
+ break;
+ } else {
+ error = linux_v4l_clip_copy(plvc, ppvc);
+ if (error) {
+ linux_v4l_cliplist_free(vw);
+ break;
+ }
+ }
+ ppvc = &((*ppvc)->next);
+ plvc = PTRIN(((struct l_video_clip *) plvc)->next);
+ }
+ } else {
+ /*
+ * clipcount == 0 or negative (but not VIDEO_CLIP_BITMAP)
+ * Force cliplist to null.
+ */
+ vw->clipcount = 0;
+ vw->clips = NULL;
+ }
+ return (error);
+}
+#endif
+
+static int
+linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args)
+{
+ struct file *fp;
+ int error;
+ struct video_tuner vtun;
+ struct video_window vwin;
+ struct video_buffer vbuf;
+ struct video_code vcode;
+ struct l_video_tuner l_vtun;
+ struct l_video_window l_vwin;
+ struct l_video_buffer l_vbuf;
+ struct l_video_code l_vcode;
+
+ switch (args->cmd & 0xffff) {
+ case LINUX_VIDIOCGCAP: args->cmd = VIDIOCGCAP; break;
+ case LINUX_VIDIOCGCHAN: args->cmd = VIDIOCGCHAN; break;
+ case LINUX_VIDIOCSCHAN: args->cmd = VIDIOCSCHAN; break;
+
+ case LINUX_VIDIOCGTUNER:
+ error = fget(td, args->fd,
+ &cap_ioctl_rights, &fp);
+ if (error != 0)
+ return (error);
+ error = copyin((void *) args->arg, &l_vtun, sizeof(l_vtun));
+ if (error) {
+ fdrop(fp, td);
+ return (error);
+ }
+ linux_to_bsd_v4l_tuner(&l_vtun, &vtun);
+ error = fo_ioctl(fp, VIDIOCGTUNER, &vtun, td->td_ucred, td);
+ if (!error) {
+ bsd_to_linux_v4l_tuner(&vtun, &l_vtun);
+ error = copyout(&l_vtun, (void *) args->arg,
+ sizeof(l_vtun));
+ }
+ fdrop(fp, td);
+ return (error);
+
+ case LINUX_VIDIOCSTUNER:
+ error = fget(td, args->fd,
+ &cap_ioctl_rights, &fp);
+ if (error != 0)
+ return (error);
+ error = copyin((void *) args->arg, &l_vtun, sizeof(l_vtun));
+ if (error) {
+ fdrop(fp, td);
+ return (error);
+ }
+ linux_to_bsd_v4l_tuner(&l_vtun, &vtun);
+ error = fo_ioctl(fp, VIDIOCSTUNER, &vtun, td->td_ucred, td);
+ fdrop(fp, td);
+ return (error);
+
+ case LINUX_VIDIOCGPICT: args->cmd = VIDIOCGPICT; break;
+ case LINUX_VIDIOCSPICT: args->cmd = VIDIOCSPICT; break;
+ case LINUX_VIDIOCCAPTURE: args->cmd = VIDIOCCAPTURE; break;
+
+ case LINUX_VIDIOCGWIN:
+ error = fget(td, args->fd,
+ &cap_ioctl_rights, &fp);
+ if (error != 0)
+ return (error);
+ error = fo_ioctl(fp, VIDIOCGWIN, &vwin, td->td_ucred, td);
+ if (!error) {
+ bsd_to_linux_v4l_window(&vwin, &l_vwin);
+ error = copyout(&l_vwin, (void *) args->arg,
+ sizeof(l_vwin));
+ }
+ fdrop(fp, td);
+ return (error);
+
+ case LINUX_VIDIOCSWIN:
+ error = fget(td, args->fd,
+ &cap_ioctl_rights, &fp);
+ if (error != 0)
+ return (error);
+ error = copyin((void *) args->arg, &l_vwin, sizeof(l_vwin));
+ if (error) {
+ fdrop(fp, td);
+ return (error);
+ }
+ linux_to_bsd_v4l_window(&l_vwin, &vwin);
+#ifdef COMPAT_LINUX_V4L_CLIPLIST
+ error = linux_v4l_cliplist_copy(&l_vwin, &vwin);
+ if (error) {
+ fdrop(fp, td);
+ return (error);
+ }
+#endif
+ error = fo_ioctl(fp, VIDIOCSWIN, &vwin, td->td_ucred, td);
+ fdrop(fp, td);
+#ifdef COMPAT_LINUX_V4L_CLIPLIST
+ linux_v4l_cliplist_free(&vwin);
+#endif
+ return (error);
+
+ case LINUX_VIDIOCGFBUF:
+ error = fget(td, args->fd,
+ &cap_ioctl_rights, &fp);
+ if (error != 0)
+ return (error);
+ error = fo_ioctl(fp, VIDIOCGFBUF, &vbuf, td->td_ucred, td);
+ if (!error) {
+ bsd_to_linux_v4l_buffer(&vbuf, &l_vbuf);
+ error = copyout(&l_vbuf, (void *) args->arg,
+ sizeof(l_vbuf));
+ }
+ fdrop(fp, td);
+ return (error);
+
+ case LINUX_VIDIOCSFBUF:
+ error = fget(td, args->fd,
+ &cap_ioctl_rights, &fp);
+ if (error != 0)
+ return (error);
+ error = copyin((void *) args->arg, &l_vbuf, sizeof(l_vbuf));
+ if (error) {
+ fdrop(fp, td);
+ return (error);
+ }
+ linux_to_bsd_v4l_buffer(&l_vbuf, &vbuf);
+ error = fo_ioctl(fp, VIDIOCSFBUF, &vbuf, td->td_ucred, td);
+ fdrop(fp, td);
+ return (error);
+
+ case LINUX_VIDIOCKEY: args->cmd = VIDIOCKEY; break;
+ case LINUX_VIDIOCGFREQ: args->cmd = VIDIOCGFREQ; break;
+ case LINUX_VIDIOCSFREQ: args->cmd = VIDIOCSFREQ; break;
+ case LINUX_VIDIOCGAUDIO: args->cmd = VIDIOCGAUDIO; break;
+ case LINUX_VIDIOCSAUDIO: args->cmd = VIDIOCSAUDIO; break;
+ case LINUX_VIDIOCSYNC: args->cmd = VIDIOCSYNC; break;
+ case LINUX_VIDIOCMCAPTURE: args->cmd = VIDIOCMCAPTURE; break;
+ case LINUX_VIDIOCGMBUF: args->cmd = VIDIOCGMBUF; break;
+ case LINUX_VIDIOCGUNIT: args->cmd = VIDIOCGUNIT; break;
+ case LINUX_VIDIOCGCAPTURE: args->cmd = VIDIOCGCAPTURE; break;
+ case LINUX_VIDIOCSCAPTURE: args->cmd = VIDIOCSCAPTURE; break;
+ case LINUX_VIDIOCSPLAYMODE: args->cmd = VIDIOCSPLAYMODE; break;
+ case LINUX_VIDIOCSWRITEMODE: args->cmd = VIDIOCSWRITEMODE; break;
+ case LINUX_VIDIOCGPLAYINFO: args->cmd = VIDIOCGPLAYINFO; break;
+
+ case LINUX_VIDIOCSMICROCODE:
+ error = fget(td, args->fd,
+ &cap_ioctl_rights, &fp);
+ if (error != 0)
+ return (error);
+ error = copyin((void *) args->arg, &l_vcode, sizeof(l_vcode));
+ if (error) {
+ fdrop(fp, td);
+ return (error);
+ }
+ linux_to_bsd_v4l_code(&l_vcode, &vcode);
+ error = fo_ioctl(fp, VIDIOCSMICROCODE, &vcode, td->td_ucred, td);
+ fdrop(fp, td);
+ return (error);
+
+ case LINUX_VIDIOCGVBIFMT: args->cmd = VIDIOCGVBIFMT; break;
+ case LINUX_VIDIOCSVBIFMT: args->cmd = VIDIOCSVBIFMT; break;
+ default: return (ENOIOCTL);
+ }
+
+ error = sys_ioctl(td, (struct ioctl_args *)args);
+ return (error);
+}
+
+/*
+ * Special ioctl handler
+ */
+static int
+linux_ioctl_special(struct thread *td, struct linux_ioctl_args *args)
+{
+ int error;
+
+ switch (args->cmd) {
+ case LINUX_SIOCGIFADDR:
+ args->cmd = SIOCGIFADDR;
+ error = sys_ioctl(td, (struct ioctl_args *)args);
+ break;
+ case LINUX_SIOCSIFADDR:
+ args->cmd = SIOCSIFADDR;
+ error = sys_ioctl(td, (struct ioctl_args *)args);
+ break;
+ case LINUX_SIOCGIFFLAGS:
+ args->cmd = SIOCGIFFLAGS;
+ error = sys_ioctl(td, (struct ioctl_args *)args);
+ break;
+ default:
+ error = ENOIOCTL;
+ }
+
+ return (error);
+}
+
+static int
+linux_to_bsd_v4l2_standard(struct l_v4l2_standard *lvstd, struct v4l2_standard *vstd)
+{
+ vstd->index = lvstd->index;
+ vstd->id = lvstd->id;
+ CTASSERT(sizeof(vstd->name) == sizeof(lvstd->name));
+ memcpy(vstd->name, lvstd->name, sizeof(vstd->name));
+ vstd->frameperiod = lvstd->frameperiod;
+ vstd->framelines = lvstd->framelines;
+ CTASSERT(sizeof(vstd->reserved) == sizeof(lvstd->reserved));
+ memcpy(vstd->reserved, lvstd->reserved, sizeof(vstd->reserved));
+ return (0);
+}
+
+static int
+bsd_to_linux_v4l2_standard(struct v4l2_standard *vstd, struct l_v4l2_standard *lvstd)
+{
+ lvstd->index = vstd->index;
+ lvstd->id = vstd->id;
+ CTASSERT(sizeof(vstd->name) == sizeof(lvstd->name));
+ memcpy(lvstd->name, vstd->name, sizeof(lvstd->name));
+ lvstd->frameperiod = vstd->frameperiod;
+ lvstd->framelines = vstd->framelines;
+ CTASSERT(sizeof(vstd->reserved) == sizeof(lvstd->reserved));
+ memcpy(lvstd->reserved, vstd->reserved, sizeof(lvstd->reserved));
+ return (0);
+}
+
+static int
+linux_to_bsd_v4l2_buffer(struct l_v4l2_buffer *lvb, struct v4l2_buffer *vb)
+{
+ vb->index = lvb->index;
+ vb->type = lvb->type;
+ vb->bytesused = lvb->bytesused;
+ vb->flags = lvb->flags;
+ vb->field = lvb->field;
+ vb->timestamp.tv_sec = lvb->timestamp.tv_sec;
+ vb->timestamp.tv_usec = lvb->timestamp.tv_usec;
+ memcpy(&vb->timecode, &lvb->timecode, sizeof (lvb->timecode));
+ vb->sequence = lvb->sequence;
+ vb->memory = lvb->memory;
+ if (lvb->memory == V4L2_MEMORY_USERPTR)
+ /* possible pointer size conversion */
+ vb->m.userptr = (unsigned long)PTRIN(lvb->m.userptr);
+ else
+ vb->m.offset = lvb->m.offset;
+ vb->length = lvb->length;
+ vb->input = lvb->input;
+ vb->reserved = lvb->reserved;
+ return (0);
+}
+
+static int
+bsd_to_linux_v4l2_buffer(struct v4l2_buffer *vb, struct l_v4l2_buffer *lvb)
+{
+ lvb->index = vb->index;
+ lvb->type = vb->type;
+ lvb->bytesused = vb->bytesused;
+ lvb->flags = vb->flags;
+ lvb->field = vb->field;
+ lvb->timestamp.tv_sec = vb->timestamp.tv_sec;
+ lvb->timestamp.tv_usec = vb->timestamp.tv_usec;
+ memcpy(&lvb->timecode, &vb->timecode, sizeof (vb->timecode));
+ lvb->sequence = vb->sequence;
+ lvb->memory = vb->memory;
+ if (vb->memory == V4L2_MEMORY_USERPTR)
+ /* possible pointer size conversion */
+ lvb->m.userptr = PTROUT(vb->m.userptr);
+ else
+ lvb->m.offset = vb->m.offset;
+ lvb->length = vb->length;
+ lvb->input = vb->input;
+ lvb->reserved = vb->reserved;
+ return (0);
+}
+
+static int
+linux_to_bsd_v4l2_format(struct l_v4l2_format *lvf, struct v4l2_format *vf)
+{
+ vf->type = lvf->type;
+ if (lvf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY
+#ifdef V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY
+ || lvf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY
+#endif
+ )
+ /*
+ * XXX TODO - needs 32 -> 64 bit conversion:
+ * (unused by webcams?)
+ */
+ return (EINVAL);
+ memcpy(&vf->fmt, &lvf->fmt, sizeof(vf->fmt));
+ return (0);
+}
+
+static int
+bsd_to_linux_v4l2_format(struct v4l2_format *vf, struct l_v4l2_format *lvf)
+{
+ lvf->type = vf->type;
+ if (vf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY
+#ifdef V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY
+ || vf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY
+#endif
+ )
+ /*
+ * XXX TODO - needs 32 -> 64 bit conversion:
+ * (unused by webcams?)
+ */
+ return (EINVAL);
+ memcpy(&lvf->fmt, &vf->fmt, sizeof(vf->fmt));
+ return (0);
+}
+static int
+linux_ioctl_v4l2(struct thread *td, struct linux_ioctl_args *args)
+{
+ struct file *fp;
+ int error;
+ struct v4l2_format vformat;
+ struct l_v4l2_format l_vformat;
+ struct v4l2_standard vstd;
+ struct l_v4l2_standard l_vstd;
+ struct l_v4l2_buffer l_vbuf;
+ struct v4l2_buffer vbuf;
+ struct v4l2_input vinp;
+
+ switch (args->cmd & 0xffff) {
+ case LINUX_VIDIOC_RESERVED:
+ case LINUX_VIDIOC_LOG_STATUS:
+ if ((args->cmd & IOC_DIRMASK) != LINUX_IOC_VOID)
+ return (ENOIOCTL);
+ args->cmd = (args->cmd & 0xffff) | IOC_VOID;
+ break;
+
+ case LINUX_VIDIOC_OVERLAY:
+ case LINUX_VIDIOC_STREAMON:
+ case LINUX_VIDIOC_STREAMOFF:
+ case LINUX_VIDIOC_S_STD:
+ case LINUX_VIDIOC_S_TUNER:
+ case LINUX_VIDIOC_S_AUDIO:
+ case LINUX_VIDIOC_S_AUDOUT:
+ case LINUX_VIDIOC_S_MODULATOR:
+ case LINUX_VIDIOC_S_FREQUENCY:
+ case LINUX_VIDIOC_S_CROP:
+ case LINUX_VIDIOC_S_JPEGCOMP:
+ case LINUX_VIDIOC_S_PRIORITY:
+ case LINUX_VIDIOC_DBG_S_REGISTER:
+ case LINUX_VIDIOC_S_HW_FREQ_SEEK:
+ case LINUX_VIDIOC_SUBSCRIBE_EVENT:
+ case LINUX_VIDIOC_UNSUBSCRIBE_EVENT:
+ args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_IN;
+ break;
+
+ case LINUX_VIDIOC_QUERYCAP:
+ case LINUX_VIDIOC_G_STD:
+ case LINUX_VIDIOC_G_AUDIO:
+ case LINUX_VIDIOC_G_INPUT:
+ case LINUX_VIDIOC_G_OUTPUT:
+ case LINUX_VIDIOC_G_AUDOUT:
+ case LINUX_VIDIOC_G_JPEGCOMP:
+ case LINUX_VIDIOC_QUERYSTD:
+ case LINUX_VIDIOC_G_PRIORITY:
+ case LINUX_VIDIOC_QUERY_DV_PRESET:
+ args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_OUT;
+ break;
+
+ case LINUX_VIDIOC_ENUM_FMT:
+ case LINUX_VIDIOC_REQBUFS:
+ case LINUX_VIDIOC_G_PARM:
+ case LINUX_VIDIOC_S_PARM:
+ case LINUX_VIDIOC_G_CTRL:
+ case LINUX_VIDIOC_S_CTRL:
+ case LINUX_VIDIOC_G_TUNER:
+ case LINUX_VIDIOC_QUERYCTRL:
+ case LINUX_VIDIOC_QUERYMENU:
+ case LINUX_VIDIOC_S_INPUT:
+ case LINUX_VIDIOC_S_OUTPUT:
+ case LINUX_VIDIOC_ENUMOUTPUT:
+ case LINUX_VIDIOC_G_MODULATOR:
+ case LINUX_VIDIOC_G_FREQUENCY:
+ case LINUX_VIDIOC_CROPCAP:
+ case LINUX_VIDIOC_G_CROP:
+ case LINUX_VIDIOC_ENUMAUDIO:
+ case LINUX_VIDIOC_ENUMAUDOUT:
+ case LINUX_VIDIOC_G_SLICED_VBI_CAP:
+#ifdef VIDIOC_ENUM_FRAMESIZES
+ case LINUX_VIDIOC_ENUM_FRAMESIZES:
+ case LINUX_VIDIOC_ENUM_FRAMEINTERVALS:
+ case LINUX_VIDIOC_ENCODER_CMD:
+ case LINUX_VIDIOC_TRY_ENCODER_CMD:
+#endif
+ case LINUX_VIDIOC_DBG_G_REGISTER:
+ case LINUX_VIDIOC_DBG_G_CHIP_IDENT:
+ case LINUX_VIDIOC_ENUM_DV_PRESETS:
+ case LINUX_VIDIOC_S_DV_PRESET:
+ case LINUX_VIDIOC_G_DV_PRESET:
+ case LINUX_VIDIOC_S_DV_TIMINGS:
+ case LINUX_VIDIOC_G_DV_TIMINGS:
+ args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_INOUT;
+ break;
+
+ case LINUX_VIDIOC_G_FMT:
+ case LINUX_VIDIOC_S_FMT:
+ case LINUX_VIDIOC_TRY_FMT:
+ error = copyin((void *)args->arg, &l_vformat, sizeof(l_vformat));
+ if (error)
+ return (error);
+ error = fget(td, args->fd,
+ &cap_ioctl_rights, &fp);
+ if (error)
+ return (error);
+ if (linux_to_bsd_v4l2_format(&l_vformat, &vformat) != 0)
+ error = EINVAL;
+ else if ((args->cmd & 0xffff) == LINUX_VIDIOC_G_FMT)
+ error = fo_ioctl(fp, VIDIOC_G_FMT, &vformat,
+ td->td_ucred, td);
+ else if ((args->cmd & 0xffff) == LINUX_VIDIOC_S_FMT)
+ error = fo_ioctl(fp, VIDIOC_S_FMT, &vformat,
+ td->td_ucred, td);
+ else
+ error = fo_ioctl(fp, VIDIOC_TRY_FMT, &vformat,
+ td->td_ucred, td);
+ bsd_to_linux_v4l2_format(&vformat, &l_vformat);
+ copyout(&l_vformat, (void *)args->arg, sizeof(l_vformat));
+ fdrop(fp, td);
+ return (error);
+
+ case LINUX_VIDIOC_ENUMSTD:
+ error = copyin((void *)args->arg, &l_vstd, sizeof(l_vstd));
+ if (error)
+ return (error);
+ linux_to_bsd_v4l2_standard(&l_vstd, &vstd);
+ error = fget(td, args->fd,
+ &cap_ioctl_rights, &fp);
+ if (error)
+ return (error);
+ error = fo_ioctl(fp, VIDIOC_ENUMSTD, (caddr_t)&vstd,
+ td->td_ucred, td);
+ if (error) {
+ fdrop(fp, td);
+ return (error);
+ }
+ bsd_to_linux_v4l2_standard(&vstd, &l_vstd);
+ error = copyout(&l_vstd, (void *)args->arg, sizeof(l_vstd));
+ fdrop(fp, td);
+ return (error);
+
+ case LINUX_VIDIOC_ENUMINPUT:
+ /*
+ * The Linux struct l_v4l2_input differs only in size,
+ * it has no padding at the end.
+ */
+ error = copyin((void *)args->arg, &vinp,
+ sizeof(struct l_v4l2_input));
+ if (error != 0)
+ return (error);
+ error = fget(td, args->fd,
+ &cap_ioctl_rights, &fp);
+ if (error != 0)
+ return (error);
+ error = fo_ioctl(fp, VIDIOC_ENUMINPUT, (caddr_t)&vinp,
+ td->td_ucred, td);
+ if (error) {
+ fdrop(fp, td);
+ return (error);
+ }
+ error = copyout(&vinp, (void *)args->arg,
+ sizeof(struct l_v4l2_input));
+ fdrop(fp, td);
+ return (error);
+
+ case LINUX_VIDIOC_QUERYBUF:
+ case LINUX_VIDIOC_QBUF:
+ case LINUX_VIDIOC_DQBUF:
+ error = copyin((void *)args->arg, &l_vbuf, sizeof(l_vbuf));
+ if (error)
+ return (error);
+ error = fget(td, args->fd,
+ &cap_ioctl_rights, &fp);
+ if (error)
+ return (error);
+ linux_to_bsd_v4l2_buffer(&l_vbuf, &vbuf);
+ if ((args->cmd & 0xffff) == LINUX_VIDIOC_QUERYBUF)
+ error = fo_ioctl(fp, VIDIOC_QUERYBUF, &vbuf,
+ td->td_ucred, td);
+ else if ((args->cmd & 0xffff) == LINUX_VIDIOC_QBUF)
+ error = fo_ioctl(fp, VIDIOC_QBUF, &vbuf,
+ td->td_ucred, td);
+ else
+ error = fo_ioctl(fp, VIDIOC_DQBUF, &vbuf,
+ td->td_ucred, td);
+ bsd_to_linux_v4l2_buffer(&vbuf, &l_vbuf);
+ copyout(&l_vbuf, (void *)args->arg, sizeof(l_vbuf));
+ fdrop(fp, td);
+ return (error);
+
+ /*
+ * XXX TODO - these need 32 -> 64 bit conversion:
+ * (are any of them needed for webcams?)
+ */
+ case LINUX_VIDIOC_G_FBUF:
+ case LINUX_VIDIOC_S_FBUF:
+
+ case LINUX_VIDIOC_G_EXT_CTRLS:
+ case LINUX_VIDIOC_S_EXT_CTRLS:
+ case LINUX_VIDIOC_TRY_EXT_CTRLS:
+
+ case LINUX_VIDIOC_DQEVENT:
+
+ default: return (ENOIOCTL);
+ }
+
+ error = sys_ioctl(td, (struct ioctl_args *)args);
+ return (error);
+}
+
+/*
+ * Support for emulators/linux-libusb. This port uses FBSD_LUSB* macros
+ * instead of USB* ones. This lets us to provide correct values for cmd.
+ * 0xffffffe0 -- 0xffffffff range seemed to be the least collision-prone.
+ */
+static int
+linux_ioctl_fbsd_usb(struct thread *td, struct linux_ioctl_args *args)
+{
+ int error;
+
+ error = 0;
+ switch (args->cmd) {
+ case FBSD_LUSB_DEVICEENUMERATE:
+ args->cmd = USB_DEVICEENUMERATE;
+ break;
+ case FBSD_LUSB_DEV_QUIRK_ADD:
+ args->cmd = USB_DEV_QUIRK_ADD;
+ break;
+ case FBSD_LUSB_DEV_QUIRK_GET:
+ args->cmd = USB_DEV_QUIRK_GET;
+ break;
+ case FBSD_LUSB_DEV_QUIRK_REMOVE:
+ args->cmd = USB_DEV_QUIRK_REMOVE;
+ break;
+ case FBSD_LUSB_DO_REQUEST:
+ args->cmd = USB_DO_REQUEST;
+ break;
+ case FBSD_LUSB_FS_CLEAR_STALL_SYNC:
+ args->cmd = USB_FS_CLEAR_STALL_SYNC;
+ break;
+ case FBSD_LUSB_FS_CLOSE:
+ args->cmd = USB_FS_CLOSE;
+ break;
+ case FBSD_LUSB_FS_COMPLETE:
+ args->cmd = USB_FS_COMPLETE;
+ break;
+ case FBSD_LUSB_FS_INIT:
+ args->cmd = USB_FS_INIT;
+ break;
+ case FBSD_LUSB_FS_OPEN:
+ args->cmd = USB_FS_OPEN;
+ break;
+ case FBSD_LUSB_FS_START:
+ args->cmd = USB_FS_START;
+ break;
+ case FBSD_LUSB_FS_STOP:
+ args->cmd = USB_FS_STOP;
+ break;
+ case FBSD_LUSB_FS_UNINIT:
+ args->cmd = USB_FS_UNINIT;
+ break;
+ case FBSD_LUSB_GET_CONFIG:
+ args->cmd = USB_GET_CONFIG;
+ break;
+ case FBSD_LUSB_GET_DEVICEINFO:
+ args->cmd = USB_GET_DEVICEINFO;
+ break;
+ case FBSD_LUSB_GET_DEVICE_DESC:
+ args->cmd = USB_GET_DEVICE_DESC;
+ break;
+ case FBSD_LUSB_GET_FULL_DESC:
+ args->cmd = USB_GET_FULL_DESC;
+ break;
+ case FBSD_LUSB_GET_IFACE_DRIVER:
+ args->cmd = USB_GET_IFACE_DRIVER;
+ break;
+ case FBSD_LUSB_GET_PLUGTIME:
+ args->cmd = USB_GET_PLUGTIME;
+ break;
+ case FBSD_LUSB_GET_POWER_MODE:
+ args->cmd = USB_GET_POWER_MODE;
+ break;
+ case FBSD_LUSB_GET_REPORT_DESC:
+ args->cmd = USB_GET_REPORT_DESC;
+ break;
+ case FBSD_LUSB_GET_REPORT_ID:
+ args->cmd = USB_GET_REPORT_ID;
+ break;
+ case FBSD_LUSB_GET_TEMPLATE:
+ args->cmd = USB_GET_TEMPLATE;
+ break;
+ case FBSD_LUSB_IFACE_DRIVER_ACTIVE:
+ args->cmd = USB_IFACE_DRIVER_ACTIVE;
+ break;
+ case FBSD_LUSB_IFACE_DRIVER_DETACH:
+ args->cmd = USB_IFACE_DRIVER_DETACH;
+ break;
+ case FBSD_LUSB_QUIRK_NAME_GET:
+ args->cmd = USB_QUIRK_NAME_GET;
+ break;
+ case FBSD_LUSB_READ_DIR:
+ args->cmd = USB_READ_DIR;
+ break;
+ case FBSD_LUSB_SET_ALTINTERFACE:
+ args->cmd = USB_SET_ALTINTERFACE;
+ break;
+ case FBSD_LUSB_SET_CONFIG:
+ args->cmd = USB_SET_CONFIG;
+ break;
+ case FBSD_LUSB_SET_IMMED:
+ args->cmd = USB_SET_IMMED;
+ break;
+ case FBSD_LUSB_SET_POWER_MODE:
+ args->cmd = USB_SET_POWER_MODE;
+ break;
+ case FBSD_LUSB_SET_TEMPLATE:
+ args->cmd = USB_SET_TEMPLATE;
+ break;
+ case FBSD_LUSB_FS_OPEN_STREAM:
+ args->cmd = USB_FS_OPEN_STREAM;
+ break;
+ case FBSD_LUSB_GET_DEV_PORT_PATH:
+ args->cmd = USB_GET_DEV_PORT_PATH;
+ break;
+ case FBSD_LUSB_GET_POWER_USAGE:
+ args->cmd = USB_GET_POWER_USAGE;
+ break;
+ case FBSD_LUSB_DEVICESTATS:
+ args->cmd = USB_DEVICESTATS;
+ break;
+ default:
+ error = ENOIOCTL;
+ }
+ if (error != ENOIOCTL)
+ error = sys_ioctl(td, (struct ioctl_args *)args);
+ return (error);
+}
+
+/*
+ * Some evdev ioctls must be translated.
+ * - EVIOCGMTSLOTS is a IOC_READ ioctl on Linux although it has input data
+ * (must be IOC_INOUT on FreeBSD).
+ * - On Linux, EVIOCGRAB, EVIOCREVOKE and EVIOCRMFF are defined as _IOW with
+ * an int argument. You don't pass an int pointer to the ioctl(), however,
+ * but just the int directly. On FreeBSD, they are defined as _IOWINT for
+ * this to work.
+ */
+static int
+linux_ioctl_evdev(struct thread *td, struct linux_ioctl_args *args)
+{
+ struct file *fp;
+ clockid_t clock;
+ int error;
+
+ args->cmd = SETDIR(args->cmd);
+
+ switch (args->cmd) {
+ case (EVIOCGRAB & ~IOC_DIRMASK) | IOC_IN:
+ args->cmd = EVIOCGRAB;
+ break;
+ case (EVIOCREVOKE & ~IOC_DIRMASK) | IOC_IN:
+ args->cmd = EVIOCREVOKE;
+ break;
+ case (EVIOCRMFF & ~IOC_DIRMASK) | IOC_IN:
+ args->cmd = EVIOCRMFF;
+ break;
+ case EVIOCSCLOCKID: {
+ error = copyin(PTRIN(args->arg), &clock, sizeof(clock));
+ if (error != 0)
+ return (error);
+ if (clock & ~(LINUX_IOCTL_EVDEV_CLK))
+ return (EINVAL);
+ error = linux_to_native_clockid(&clock, clock);
+ if (error != 0)
+ return (error);
+
+ error = fget(td, args->fd,
+ &cap_ioctl_rights, &fp);
+ if (error != 0)
+ return (error);
+
+ error = fo_ioctl(fp, EVIOCSCLOCKID, &clock, td->td_ucred, td);
+ fdrop(fp, td);
+ return (error);
+ }
+ default:
+ break;
+ }
+
+ if (IOCBASECMD(args->cmd) ==
+ ((EVIOCGMTSLOTS(0) & ~IOC_DIRMASK) | IOC_OUT))
+ args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_INOUT;
+
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+}
+
+static int
+linux_ioctl_kcov(struct thread *td, struct linux_ioctl_args *args)
+{
+ int error;
+
+ error = 0;
+ switch (args->cmd & 0xffff) {
+ case LINUX_KCOV_INIT_TRACE:
+ args->cmd = KIOSETBUFSIZE;
+ break;
+ case LINUX_KCOV_ENABLE:
+ args->cmd = KIOENABLE;
+ if (args->arg == 0)
+ args->arg = KCOV_MODE_TRACE_PC;
+ else if (args->arg == 1)
+ args->arg = KCOV_MODE_TRACE_CMP;
+ else
+ error = EINVAL;
+ break;
+ case LINUX_KCOV_DISABLE:
+ args->cmd = KIODISABLE;
+ break;
+ default:
+ error = ENOTTY;
+ break;
+ }
+
+ if (error == 0)
+ error = sys_ioctl(td, (struct ioctl_args *)args);
+ return (error);
+}
+
+/*
+ * main ioctl syscall function
+ */
+
+static int
+linux_ioctl_fallback(struct thread *td, struct linux_ioctl_args *args)
+{
+ struct file *fp;
+ struct linux_ioctl_handler_element *he;
+ int error, cmd;
+
+ error = fget(td, args->fd, &cap_ioctl_rights, &fp);
+ if (error != 0)
+ return (error);
+ if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
+ fdrop(fp, td);
+ return (EBADF);
+ }
+
+ /* Iterate over the ioctl handlers */
+ cmd = args->cmd & 0xffff;
+ sx_slock(&linux_ioctl_sx);
+ mtx_lock(&Giant);
+#ifdef COMPAT_LINUX32
+ TAILQ_FOREACH(he, &linux32_ioctl_handlers, list) {
+ if (cmd >= he->low && cmd <= he->high) {
+ error = (*he->func)(td, args);
+ if (error != ENOIOCTL) {
+ mtx_unlock(&Giant);
+ sx_sunlock(&linux_ioctl_sx);
+ fdrop(fp, td);
+ return (error);
+ }
+ }
+ }
+#endif
+ TAILQ_FOREACH(he, &linux_ioctl_handlers, list) {
+ if (cmd >= he->low && cmd <= he->high) {
+ error = (*he->func)(td, args);
+ if (error != ENOIOCTL) {
+ mtx_unlock(&Giant);
+ sx_sunlock(&linux_ioctl_sx);
+ fdrop(fp, td);
+ return (error);
+ }
+ }
+ }
+ mtx_unlock(&Giant);
+ sx_sunlock(&linux_ioctl_sx);
+ fdrop(fp, td);
+
+ switch (args->cmd & 0xffff) {
+ case LINUX_BTRFS_IOC_CLONE:
+ case LINUX_F2FS_IOC_GET_FEATURES:
+ case LINUX_FS_IOC_FIEMAP:
+ return (ENOTSUP);
+
+ default:
+ linux_msg(td, "%s fd=%d, cmd=0x%x ('%c',%d) is not implemented",
+ __func__, args->fd, args->cmd,
+ (int)(args->cmd & 0xff00) >> 8, (int)(args->cmd & 0xff));
+ break;
+ }
+
+ return (EINVAL);
+}
+
+int
+linux_ioctl(struct thread *td, struct linux_ioctl_args *args)
+{
+ struct linux_ioctl_handler *handler;
+ int error, cmd, i;
+
+ cmd = args->cmd & 0xffff;
+
+ /*
+ * array of ioctls known at compilation time. Elides a lot of work on
+ * each call compared to the list variant. Everything frequently used
+ * should be moved here.
+ *
+ * Arguably the magic creating the list should create an array instead.
+ *
+ * For now just a linear scan.
+ */
+ for (i = 0; i < nitems(linux_ioctls); i++) {
+ handler = &linux_ioctls[i];
+ if (cmd >= handler->low && cmd <= handler->high) {
+ error = (*handler->func)(td, args);
+ if (error != ENOIOCTL) {
+ return (error);
+ }
+ }
+ }
+ return (linux_ioctl_fallback(td, args));
+}
+
+int
+linux_ioctl_register_handler(struct linux_ioctl_handler *h)
+{
+ struct linux_ioctl_handler_element *he, *cur;
+
+ if (h == NULL || h->func == NULL)
+ return (EINVAL);
+
+ /*
+ * Reuse the element if the handler is already on the list, otherwise
+ * create a new element.
+ */
+ sx_xlock(&linux_ioctl_sx);
+ TAILQ_FOREACH(he, &linux_ioctl_handlers, list) {
+ if (he->func == h->func)
+ break;
+ }
+ if (he == NULL) {
+ he = malloc(sizeof(*he),
+ M_LINUX, M_WAITOK);
+ he->func = h->func;
+ } else
+ TAILQ_REMOVE(&linux_ioctl_handlers, he, list);
+
+ /* Initialize range information. */
+ he->low = h->low;
+ he->high = h->high;
+ he->span = h->high - h->low + 1;
+
+ /* Add the element to the list, sorted on span. */
+ TAILQ_FOREACH(cur, &linux_ioctl_handlers, list) {
+ if (cur->span > he->span) {
+ TAILQ_INSERT_BEFORE(cur, he, list);
+ sx_xunlock(&linux_ioctl_sx);
+ return (0);
+ }
+ }
+ TAILQ_INSERT_TAIL(&linux_ioctl_handlers, he, list);
+ sx_xunlock(&linux_ioctl_sx);
+
+ return (0);
+}
+
+int
+linux_ioctl_unregister_handler(struct linux_ioctl_handler *h)
+{
+ struct linux_ioctl_handler_element *he;
+
+ if (h == NULL || h->func == NULL)
+ return (EINVAL);
+
+ sx_xlock(&linux_ioctl_sx);
+ TAILQ_FOREACH(he, &linux_ioctl_handlers, list) {
+ if (he->func == h->func) {
+ TAILQ_REMOVE(&linux_ioctl_handlers, he, list);
+ sx_xunlock(&linux_ioctl_sx);
+ free(he, M_LINUX);
+ return (0);
+ }
+ }
+ sx_xunlock(&linux_ioctl_sx);
+
+ return (EINVAL);
+}
+
+#ifdef COMPAT_LINUX32
+int
+linux32_ioctl_register_handler(struct linux_ioctl_handler *h)
+{
+ struct linux_ioctl_handler_element *he, *cur;
+
+ if (h == NULL || h->func == NULL)
+ return (EINVAL);
+
+ /*
+ * Reuse the element if the handler is already on the list, otherwise
+ * create a new element.
+ */
+ sx_xlock(&linux_ioctl_sx);
+ TAILQ_FOREACH(he, &linux32_ioctl_handlers, list) {
+ if (he->func == h->func)
+ break;
+ }
+ if (he == NULL) {
+ he = malloc(sizeof(*he), M_LINUX, M_WAITOK);
+ he->func = h->func;
+ } else
+ TAILQ_REMOVE(&linux32_ioctl_handlers, he, list);
+
+ /* Initialize range information. */
+ he->low = h->low;
+ he->high = h->high;
+ he->span = h->high - h->low + 1;
+
+ /* Add the element to the list, sorted on span. */
+ TAILQ_FOREACH(cur, &linux32_ioctl_handlers, list) {
+ if (cur->span > he->span) {
+ TAILQ_INSERT_BEFORE(cur, he, list);
+ sx_xunlock(&linux_ioctl_sx);
+ return (0);
+ }
+ }
+ TAILQ_INSERT_TAIL(&linux32_ioctl_handlers, he, list);
+ sx_xunlock(&linux_ioctl_sx);
+
+ return (0);
+}
+
+int
+linux32_ioctl_unregister_handler(struct linux_ioctl_handler *h)
+{
+ struct linux_ioctl_handler_element *he;
+
+ if (h == NULL || h->func == NULL)
+ return (EINVAL);
+
+ sx_xlock(&linux_ioctl_sx);
+ TAILQ_FOREACH(he, &linux32_ioctl_handlers, list) {
+ if (he->func == h->func) {
+ TAILQ_REMOVE(&linux32_ioctl_handlers, he, list);
+ sx_xunlock(&linux_ioctl_sx);
+ free(he, M_LINUX);
+ return (0);
+ }
+ }
+ sx_xunlock(&linux_ioctl_sx);
+
+ return (EINVAL);
+}
+#endif
diff --git a/sys/compat/linux/linux_ioctl.h b/sys/compat/linux/linux_ioctl.h
new file mode 100644
index 000000000000..4aaf1114ff39
--- /dev/null
+++ b/sys/compat/linux/linux_ioctl.h
@@ -0,0 +1,809 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1999 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_IOCTL_H_
+#define _LINUX_IOCTL_H_
+
+/*
+ * ioctl
+ *
+ * XXX comments in Linux' <asm-generic/ioctl.h> indicate these
+ * could be arch-dependant...
+ */
+#define LINUX_IOC_VOID 0
+#define LINUX_IOC_IN 0x40000000
+#define LINUX_IOC_OUT 0x80000000
+#define LINUX_IOC_INOUT (LINUX_IOC_IN|LINUX_IOC_OUT)
+
+/*
+ * disk
+ */
+#define LINUX_BLKROSET 0x125d
+#define LINUX_BLKROGET 0x125e
+#define LINUX_BLKRRPART 0x125f
+#define LINUX_BLKGETSIZE 0x1260
+#define LINUX_BLKFLSBUF 0x1261
+#define LINUX_BLKRASET 0x1262
+#define LINUX_BLKRAGET 0x1263
+#define LINUX_BLKFRASET 0x1264
+#define LINUX_BLKFRAGET 0x1265
+#define LINUX_BLKSECTSET 0x1266
+#define LINUX_BLKSECTGET 0x1267
+#define LINUX_BLKSSZGET 0x1268
+#define LINUX_BLKGETSIZE64 0x1272
+#define LINUX_BLKPBSZGET 0x127b
+
+#define LINUX_IOCTL_DISK_MIN LINUX_BLKROSET
+#define LINUX_IOCTL_DISK_MAX LINUX_BLKPBSZGET
+
+/*
+ * hdio
+ */
+#define LINUX_HDIO_GET_GEO 0x0301
+#define LINUX_HDIO_GET_IDENTITY 0x030D /* not yet implemented */
+#define LINUX_HDIO_GET_GEO_BIG 0x0330
+
+#define LINUX_IOCTL_HDIO_MIN LINUX_HDIO_GET_GEO
+#define LINUX_IOCTL_HDIO_MAX LINUX_HDIO_GET_GEO_BIG
+
+/*
+ * cdrom
+ */
+#define LINUX_CDROMPAUSE 0x5301
+#define LINUX_CDROMRESUME 0x5302
+#define LINUX_CDROMPLAYMSF 0x5303
+#define LINUX_CDROMPLAYTRKIND 0x5304
+#define LINUX_CDROMREADTOCHDR 0x5305
+#define LINUX_CDROMREADTOCENTRY 0x5306
+#define LINUX_CDROMSTOP 0x5307
+#define LINUX_CDROMSTART 0x5308
+#define LINUX_CDROMEJECT 0x5309
+#define LINUX_CDROMVOLCTRL 0x530a
+#define LINUX_CDROMSUBCHNL 0x530b
+#define LINUX_CDROMREADMODE2 0x530c
+#define LINUX_CDROMREADMODE1 0x530d
+#define LINUX_CDROMREADAUDIO 0x530e
+#define LINUX_CDROMEJECT_SW 0x530f
+#define LINUX_CDROMMULTISESSION 0x5310
+#define LINUX_CDROM_GET_UPC 0x5311
+#define LINUX_CDROMRESET 0x5312
+#define LINUX_CDROMVOLREAD 0x5313
+#define LINUX_CDROMREADRAW 0x5314
+#define LINUX_CDROMREADCOOKED 0x5315
+#define LINUX_CDROMSEEK 0x5316
+#define LINUX_CDROMPLAYBLK 0x5317
+#define LINUX_CDROMREADALL 0x5318
+#define LINUX_CDROMCLOSETRAY 0x5319
+#define LINUX_CDROMLOADFROMSLOT 0x531a
+#define LINUX_CDROMGETSPINDOWN 0x531d
+#define LINUX_CDROMSETSPINDOWN 0x531e
+#define LINUX_CDROM_SET_OPTIONS 0x5320
+#define LINUX_CDROM_CLEAR_OPTIONS 0x5321
+#define LINUX_CDROM_SELECT_SPEED 0x5322
+#define LINUX_CDROM_SELECT_DISC 0x5323
+#define LINUX_CDROM_MEDIA_CHANGED 0x5325
+#define LINUX_CDROM_DRIVE_STATUS 0x5326
+#define LINUX_CDROM_DISC_STATUS 0x5327
+#define LINUX_CDROM_CHANGER_NSLOTS 0x5328
+#define LINUX_CDROM_LOCKDOOR 0x5329
+#define LINUX_CDROM_DEBUG 0x5330
+#define LINUX_CDROM_GET_CAPABILITY 0x5331
+#define LINUX_CDROMAUDIOBUFSIZ 0x5382
+#define LINUX_SCSI_GET_IDLUN 0x5382
+#define LINUX_SCSI_GET_BUS_NUMBER 0x5386
+#define LINUX_DVD_READ_STRUCT 0x5390
+#define LINUX_DVD_WRITE_STRUCT 0x5391
+#define LINUX_DVD_AUTH 0x5392
+#define LINUX_CDROM_SEND_PACKET 0x5393
+#define LINUX_CDROM_NEXT_WRITABLE 0x5394
+#define LINUX_CDROM_LAST_WRITTEN 0x5395
+
+#define LINUX_IOCTL_CDROM_MIN LINUX_CDROMPAUSE
+#define LINUX_IOCTL_CDROM_MAX LINUX_CDROM_LAST_WRITTEN
+
+#define LINUX_CDROM_LBA 0x01
+#define LINUX_CDROM_MSF 0x02
+
+#define LINUX_DVD_LU_SEND_AGID 0
+#define LINUX_DVD_HOST_SEND_CHALLENGE 1
+#define LINUX_DVD_LU_SEND_KEY1 2
+#define LINUX_DVD_LU_SEND_CHALLENGE 3
+#define LINUX_DVD_HOST_SEND_KEY2 4
+#define LINUX_DVD_AUTH_ESTABLISHED 5
+#define LINUX_DVD_AUTH_FAILURE 6
+#define LINUX_DVD_LU_SEND_TITLE_KEY 7
+#define LINUX_DVD_LU_SEND_ASF 8
+#define LINUX_DVD_INVALIDATE_AGID 9
+#define LINUX_DVD_LU_SEND_RPC_STATE 10
+#define LINUX_DVD_HOST_SEND_RPC_STATE 11
+
+/*
+ * SG
+ */
+#define LINUX_SG_SET_TIMEOUT 0x2201
+#define LINUX_SG_GET_TIMEOUT 0x2202
+#define LINUX_SG_EMULATED_HOST 0x2203
+#define LINUX_SG_SET_TRANSFORM 0x2204
+#define LINUX_SG_GET_TRANSFORM 0x2205
+#define LINUX_SG_GET_COMMAND_Q 0x2270
+#define LINUX_SG_SET_COMMAND_Q 0x2271
+#define LINUX_SG_SET_RESERVED_SIZE 0x2275
+#define LINUX_SG_GET_RESERVED_SIZE 0x2272
+#define LINUX_SG_GET_SCSI_ID 0x2276
+#define LINUX_SG_SET_FORCE_LOW_DMA 0x2279
+#define LINUX_SG_GET_LOW_DMA 0x227a
+#define LINUX_SG_SET_FORCE_PACK_ID 0x227b
+#define LINUX_SG_GET_PACK_ID 0x227c
+#define LINUX_SG_GET_NUM_WAITING 0x227d
+#define LINUX_SG_SET_DEBUG 0x227e
+#define LINUX_SG_GET_SG_TABLESIZE 0x227f
+#define LINUX_SG_GET_VERSION_NUM 0x2282
+#define LINUX_SG_NEXT_CMD_LEN 0x2283
+#define LINUX_SG_SCSI_RESET 0x2284
+#define LINUX_SG_IO 0x2285
+#define LINUX_SG_GET_REQUEST_TABLE 0x2286
+#define LINUX_SG_SET_KEEP_ORPHAN 0x2287
+#define LINUX_SG_GET_KEEP_ORPHAN 0x2288
+#define LINUX_SG_GET_ACCESS_COUNT 0x2289
+
+#define LINUX_IOCTL_SG_MIN 0x2200
+#define LINUX_IOCTL_SG_MAX 0x22ff
+
+/*
+ * VFAT
+ */
+#define LINUX_VFAT_READDIR_BOTH 0x7201
+
+#define LINUX_IOCTL_VFAT_MIN LINUX_VFAT_READDIR_BOTH
+#define LINUX_IOCTL_VFAT_MAX LINUX_VFAT_READDIR_BOTH
+
+/*
+ * console
+ */
+#define LINUX_KIOCSOUND 0x4B2F
+#define LINUX_KDMKTONE 0x4B30
+#define LINUX_KDGETLED 0x4B31
+#define LINUX_KDSETLED 0x4B32
+#define LINUX_KDSETMODE 0x4B3A
+#define LINUX_KDGETMODE 0x4B3B
+#define LINUX_KDGKBMODE 0x4B44
+#define LINUX_KDSKBMODE 0x4B45
+#define LINUX_VT_OPENQRY 0x5600
+#define LINUX_VT_GETMODE 0x5601
+#define LINUX_VT_SETMODE 0x5602
+#define LINUX_VT_GETSTATE 0x5603
+#define LINUX_VT_RELDISP 0x5605
+#define LINUX_VT_ACTIVATE 0x5606
+#define LINUX_VT_WAITACTIVE 0x5607
+
+#define LINUX_IOCTL_CONSOLE_MIN LINUX_KIOCSOUND
+#define LINUX_IOCTL_CONSOLE_MAX LINUX_VT_WAITACTIVE
+
+#define LINUX_LED_SCR 0x01
+#define LINUX_LED_NUM 0x02
+#define LINUX_LED_CAP 0x04
+
+#define LINUX_KD_TEXT 0x0
+#define LINUX_KD_GRAPHICS 0x1
+#define LINUX_KD_TEXT0 0x2
+#define LINUX_KD_TEXT1 0x3
+
+#define LINUX_KBD_RAW 0
+#define LINUX_KBD_XLATE 1
+#define LINUX_KBD_MEDIUMRAW 2
+
+/*
+ * socket
+ */
+#define LINUX_FIOSETOWN 0x8901
+#define LINUX_SIOCSPGRP 0x8902
+#define LINUX_FIOGETOWN 0x8903
+#define LINUX_SIOCGPGRP 0x8904
+#define LINUX_SIOCATMARK 0x8905
+#define LINUX_SIOCGSTAMP 0x8906
+#define LINUX_SIOCGIFNAME 0x8910
+#define LINUX_SIOCGIFCONF 0x8912
+#define LINUX_SIOCGIFFLAGS 0x8913
+#define LINUX_SIOCGIFADDR 0x8915
+#define LINUX_SIOCSIFADDR 0x8916
+#define LINUX_SIOCGIFDSTADDR 0x8917
+#define LINUX_SIOCGIFBRDADDR 0x8919
+#define LINUX_SIOCGIFNETMASK 0x891b
+#define LINUX_SIOCSIFNETMASK 0x891c
+#define LINUX_SIOCGIFMTU 0x8921
+#define LINUX_SIOCSIFMTU 0x8922
+#define LINUX_SIOCSIFNAME 0x8923
+#define LINUX_SIOCSIFHWADDR 0x8924
+#define LINUX_SIOCGIFHWADDR 0x8927
+#define LINUX_SIOCADDMULTI 0x8931
+#define LINUX_SIOCDELMULTI 0x8932
+#define LINUX_SIOCGIFINDEX 0x8933
+#define LINUX_SIOGIFINDEX LINUX_SIOCGIFINDEX
+#define LINUX_SIOCGIFCOUNT 0x8938
+
+#define LINUX_IOCTL_SOCKET_MIN LINUX_FIOSETOWN
+#define LINUX_IOCTL_SOCKET_MAX LINUX_SIOCGIFCOUNT
+
+/*
+ * Device private ioctl calls
+ */
+#define LINUX_SIOCDEVPRIVATE 0x89F0 /* to 89FF */
+#define LINUX_IOCTL_PRIVATE_MIN LINUX_SIOCDEVPRIVATE
+#define LINUX_IOCTL_PRIVATE_MAX LINUX_SIOCDEVPRIVATE+0xf
+
+/*
+ * sound
+ */
+#define LINUX_SOUND_MIXER_WRITE_VOLUME 0x4d00
+#define LINUX_SOUND_MIXER_WRITE_BASS 0x4d01
+#define LINUX_SOUND_MIXER_WRITE_TREBLE 0x4d02
+#define LINUX_SOUND_MIXER_WRITE_SYNTH 0x4d03
+#define LINUX_SOUND_MIXER_WRITE_PCM 0x4d04
+#define LINUX_SOUND_MIXER_WRITE_SPEAKER 0x4d05
+#define LINUX_SOUND_MIXER_WRITE_LINE 0x4d06
+#define LINUX_SOUND_MIXER_WRITE_MIC 0x4d07
+#define LINUX_SOUND_MIXER_WRITE_CD 0x4d08
+#define LINUX_SOUND_MIXER_WRITE_IMIX 0x4d09
+#define LINUX_SOUND_MIXER_WRITE_ALTPCM 0x4d0A
+#define LINUX_SOUND_MIXER_WRITE_RECLEV 0x4d0B
+#define LINUX_SOUND_MIXER_WRITE_IGAIN 0x4d0C
+#define LINUX_SOUND_MIXER_WRITE_OGAIN 0x4d0D
+#define LINUX_SOUND_MIXER_WRITE_LINE1 0x4d0E
+#define LINUX_SOUND_MIXER_WRITE_LINE2 0x4d0F
+#define LINUX_SOUND_MIXER_WRITE_LINE3 0x4d10
+#define LINUX_SOUND_MIXER_WRITE_MONITOR 0x4d18
+#define LINUX_SOUND_MIXER_INFO 0x4d65
+#define LINUX_OSS_GETVERSION 0x4d76
+#define LINUX_SOUND_MIXER_READ_STEREODEVS 0x4dfb
+#define LINUX_SOUND_MIXER_READ_CAPS 0x4dfc
+#define LINUX_SOUND_MIXER_READ_RECMASK 0x4dfd
+#define LINUX_SOUND_MIXER_READ_DEVMASK 0x4dfe
+#define LINUX_SOUND_MIXER_WRITE_RECSRC 0x4dff
+#define LINUX_SNDCTL_DSP_RESET 0x5000
+#define LINUX_SNDCTL_DSP_SYNC 0x5001
+#define LINUX_SNDCTL_DSP_SPEED 0x5002
+#define LINUX_SNDCTL_DSP_STEREO 0x5003
+#define LINUX_SNDCTL_DSP_GETBLKSIZE 0x5004
+#define LINUX_SNDCTL_DSP_SETBLKSIZE LINUX_SNDCTL_DSP_GETBLKSIZE
+#define LINUX_SNDCTL_DSP_SETFMT 0x5005
+#define LINUX_SOUND_PCM_WRITE_CHANNELS 0x5006
+#define LINUX_SOUND_PCM_WRITE_FILTER 0x5007
+#define LINUX_SNDCTL_DSP_POST 0x5008
+#define LINUX_SNDCTL_DSP_SUBDIVIDE 0x5009
+#define LINUX_SNDCTL_DSP_SETFRAGMENT 0x500A
+#define LINUX_SNDCTL_DSP_GETFMTS 0x500B
+#define LINUX_SNDCTL_DSP_GETOSPACE 0x500C
+#define LINUX_SNDCTL_DSP_GETISPACE 0x500D
+#define LINUX_SNDCTL_DSP_NONBLOCK 0x500E
+#define LINUX_SNDCTL_DSP_GETCAPS 0x500F
+#define LINUX_SNDCTL_DSP_GETTRIGGER 0x5010
+#define LINUX_SNDCTL_DSP_SETTRIGGER LINUX_SNDCTL_DSP_GETTRIGGER
+#define LINUX_SNDCTL_DSP_GETIPTR 0x5011
+#define LINUX_SNDCTL_DSP_GETOPTR 0x5012
+#define LINUX_SNDCTL_DSP_SETDUPLEX 0x5016
+#define LINUX_SNDCTL_DSP_GETODELAY 0x5017
+#define LINUX_SNDCTL_SEQ_RESET 0x5100
+#define LINUX_SNDCTL_SEQ_SYNC 0x5101
+#define LINUX_SNDCTL_SYNTH_INFO 0x5102
+#define LINUX_SNDCTL_SEQ_CTRLRATE 0x5103
+#define LINUX_SNDCTL_SEQ_GETOUTCOUNT 0x5104
+#define LINUX_SNDCTL_SEQ_GETINCOUNT 0x5105
+#define LINUX_SNDCTL_SEQ_PERCMODE 0x5106
+#define LINUX_SNDCTL_FM_LOAD_INSTR 0x5107
+#define LINUX_SNDCTL_SEQ_TESTMIDI 0x5108
+#define LINUX_SNDCTL_SEQ_RESETSAMPLES 0x5109
+#define LINUX_SNDCTL_SEQ_NRSYNTHS 0x510A
+#define LINUX_SNDCTL_SEQ_NRMIDIS 0x510B
+#define LINUX_SNDCTL_MIDI_INFO 0x510C
+#define LINUX_SNDCTL_SEQ_TRESHOLD 0x510D
+#define LINUX_SNDCTL_SYNTH_MEMAVL 0x510E
+
+#define LINUX_IOCTL_SOUND_MIN LINUX_SOUND_MIXER_WRITE_VOLUME
+#define LINUX_IOCTL_SOUND_MAX LINUX_SNDCTL_SYNTH_MEMAVL
+
+/*
+ * termio
+ */
+#define LINUX_TCGETS 0x5401
+#define LINUX_TCSETS 0x5402
+#define LINUX_TCSETSW 0x5403
+#define LINUX_TCSETSF 0x5404
+#define LINUX_TCGETA 0x5405
+#define LINUX_TCSETA 0x5406
+#define LINUX_TCSETAW 0x5407
+#define LINUX_TCSETAF 0x5408
+#define LINUX_TCSBRK 0x5409
+#define LINUX_TCXONC 0x540A
+#define LINUX_TCFLSH 0x540B
+
+#define LINUX_TIOCEXCL 0x540C
+#define LINUX_TIOCNXCL 0x540D
+#define LINUX_TIOCSCTTY 0x540E
+
+#define LINUX_TIOCGPGRP 0x540F
+#define LINUX_TIOCSPGRP 0x5410
+
+#define LINUX_TIOCOUTQ 0x5411
+#define LINUX_TIOCSTI 0x5412
+
+#define LINUX_TIOCGWINSZ 0x5413
+#define LINUX_TIOCSWINSZ 0x5414
+
+#define LINUX_TIOCMGET 0x5415
+#define LINUX_TIOCMBIS 0x5416
+#define LINUX_TIOCMBIC 0x5417
+#define LINUX_TIOCMSET 0x5418
+#define LINUX_TIOCGSOFTCAR 0x5419
+#define LINUX_TIOCSSOFTCAR 0x541A
+
+#define LINUX_FIONREAD 0x541B
+
+#define LINUX_TIOCINQ FIONREAD
+#define LINUX_TIOCLINUX 0x541C
+#define LINUX_TIOCCONS 0x541D
+#define LINUX_TIOCGSERIAL 0x541E
+#define LINUX_TIOCSSERIAL 0x541F
+#define LINUX_TIOCPKT 0x5420
+
+#define LINUX_FIONBIO 0x5421
+
+#define LINUX_TIOCNOTTY 0x5422
+#define LINUX_TIOCSETD 0x5423
+#define LINUX_TIOCGETD 0x5424
+#define LINUX_TCSBRKP 0x5425
+#define LINUX_TIOCTTYGSTRUCT 0x5426
+
+#define LINUX_TIOCSBRK 0x5427
+#define LINUX_TIOCCBRK 0x5428
+
+#define LINUX_TIOCGPTN 0x5430
+#define LINUX_TIOCSPTLCK 0x5431
+
+#define LINUX_FIONCLEX 0x5450
+#define LINUX_FIOCLEX 0x5451
+#define LINUX_FIOASYNC 0x5452
+
+#define LINUX_TIOCSERCONFIG 0x5453
+#define LINUX_TIOCSERGWILD 0x5454
+#define LINUX_TIOCSERSWILD 0x5455
+#define LINUX_TIOCGLCKTRMIOS 0x5456
+#define LINUX_TIOCSLCKTRMIOS 0x5457
+
+#define LINUX_IOCTL_TERMIO_MIN LINUX_TCGETS
+#define LINUX_IOCTL_TERMIO_MAX LINUX_TIOCSLCKTRMIOS
+
+/* arguments for tcflow() and LINUX_TCXONC */
+#define LINUX_TCOOFF 0
+#define LINUX_TCOON 1
+#define LINUX_TCIOFF 2
+#define LINUX_TCION 3
+
+/* arguments for tcflush() and LINUX_TCFLSH */
+#define LINUX_TCIFLUSH 0
+#define LINUX_TCOFLUSH 1
+#define LINUX_TCIOFLUSH 2
+
+/* line disciplines */
+#define LINUX_N_TTY 0
+#define LINUX_N_SLIP 1
+#define LINUX_N_MOUSE 2
+#define LINUX_N_PPP 3
+
+/* Linux termio c_cc values */
+#define LINUX_VINTR 0
+#define LINUX_VQUIT 1
+#define LINUX_VERASE 2
+#define LINUX_VKILL 3
+#define LINUX_VEOF 4
+#define LINUX_VTIME 5
+#define LINUX_VMIN 6
+#define LINUX_VSWTC 7
+#define LINUX_NCC 8
+
+/* Linux termios c_cc values */
+/* In addition to the termio values */
+#define LINUX_VSTART 8
+#define LINUX_VSTOP 9
+#define LINUX_VSUSP 10
+#define LINUX_VEOL 11
+#define LINUX_VREPRINT 12
+#define LINUX_VDISCARD 13
+#define LINUX_VWERASE 14
+#define LINUX_VLNEXT 15
+#define LINUX_VEOL2 16
+#define LINUX_VSTATUS 18
+#define LINUX_NCCS 19
+
+#define LINUX_POSIX_VDISABLE '\0'
+
+/* Linux c_iflag masks */
+#define LINUX_IGNBRK 0x0000001
+#define LINUX_BRKINT 0x0000002
+#define LINUX_IGNPAR 0x0000004
+#define LINUX_PARMRK 0x0000008
+#define LINUX_INPCK 0x0000010
+#define LINUX_ISTRIP 0x0000020
+#define LINUX_INLCR 0x0000040
+#define LINUX_IGNCR 0x0000080
+#define LINUX_ICRNL 0x0000100
+
+#define LINUX_IUCLC 0x0000200
+#define LINUX_IXON 0x0000400
+#define LINUX_IXANY 0x0000800
+#define LINUX_IXOFF 0x0001000
+
+#define LINUX_IMAXBEL 0x0002000
+
+/* Linux c_oflag masks */
+#define LINUX_OPOST 0x0000001
+
+#define LINUX_OLCUC 0x0000002
+#define LINUX_ONLCR 0x0000004
+
+#define LINUX_OCRNL 0x0000008
+#define LINUX_ONOCR 0x0000010
+#define LINUX_ONLRET 0x0000020
+#define LINUX_OFILL 0x0000040
+#define LINUX_OFDEL 0x0000080
+
+#define LINUX_NLDLY 0x0000100
+#define LINUX_NL0 0x0000000
+#define LINUX_NL1 0x0000100
+#define LINUX_CRDLY 0x0000600
+#define LINUX_CR0 0x0000000
+#define LINUX_CR1 0x0000200
+#define LINUX_CR2 0x0000400
+#define LINUX_CR3 0x0000600
+#define LINUX_TABDLY 0x0001800
+#define LINUX_TAB0 0x0000000
+#define LINUX_TAB1 0x0000800
+#define LINUX_TAB2 0x0001000
+#define LINUX_TAB3 0x0001800
+#define LINUX_XTABS 0x0001800
+#define LINUX_BSDLY 0x0002000
+#define LINUX_BS0 0x0000000
+#define LINUX_BS1 0x0002000
+#define LINUX_VTDLY 0x0004000
+#define LINUX_VT0 0x0000000
+#define LINUX_VT1 0x0004000
+#define LINUX_FFDLY 0x0008000
+#define LINUX_FF0 0x0000000
+#define LINUX_FF1 0x0008000
+
+#define LINUX_CBAUD 0x0000100f
+
+#define LINUX_B0 0x00000000
+#define LINUX_B50 0x00000001
+#define LINUX_B75 0x00000002
+#define LINUX_B110 0x00000003
+#define LINUX_B134 0x00000004
+#define LINUX_B150 0x00000005
+#define LINUX_B200 0x00000006
+#define LINUX_B300 0x00000007
+#define LINUX_B600 0x00000008
+#define LINUX_B1200 0x00000009
+#define LINUX_B1800 0x0000000a
+#define LINUX_B2400 0x0000000b
+#define LINUX_B4800 0x0000000c
+#define LINUX_B9600 0x0000000d
+#define LINUX_B19200 0x0000000e
+#define LINUX_B38400 0x0000000f
+#define LINUX_EXTA LINUX_B19200
+#define LINUX_EXTB LINUX_B38400
+
+#define LINUX_CBAUDEX 0x00001000
+#define LINUX_B57600 0x00001001
+#define LINUX_B115200 0x00001002
+
+#define LINUX_CSIZE 0x00000030
+#define LINUX_CS5 0x00000000
+#define LINUX_CS6 0x00000010
+#define LINUX_CS7 0x00000020
+#define LINUX_CS8 0x00000030
+#define LINUX_CSTOPB 0x00000040
+#define LINUX_CREAD 0x00000080
+#define LINUX_PARENB 0x00000100
+#define LINUX_PARODD 0x00000200
+#define LINUX_HUPCL 0x00000400
+#define LINUX_CLOCAL 0x00000800
+
+#define LINUX_CRTSCTS 0x80000000
+
+/* Linux c_lflag masks */
+#define LINUX_ISIG 0x00000001
+#define LINUX_ICANON 0x00000002
+#define LINUX_XCASE 0x00000004
+#define LINUX_ECHO 0x00000008
+#define LINUX_ECHOE 0x00000010
+#define LINUX_ECHOK 0x00000020
+#define LINUX_ECHONL 0x00000040
+#define LINUX_NOFLSH 0x00000080
+#define LINUX_TOSTOP 0x00000100
+#define LINUX_ECHOCTL 0x00000200
+#define LINUX_ECHOPRT 0x00000400
+#define LINUX_ECHOKE 0x00000800
+#define LINUX_FLUSHO 0x00001000
+#define LINUX_PENDIN 0x00002000
+#define LINUX_IEXTEN 0x00008000
+
+/* serial_struct values for TIOC[GS]SERIAL ioctls */
+#define LINUX_ASYNC_CLOSING_WAIT_INF 0
+#define LINUX_ASYNC_CLOSING_WAIT_NONE 65535
+
+#define LINUX_PORT_UNKNOWN 0
+#define LINUX_PORT_8250 1
+#define LINUX_PORT_16450 2
+#define LINUX_PORT_16550 3
+#define LINUX_PORT_16550A 4
+#define LINUX_PORT_CIRRUS 5
+#define LINUX_PORT_16650 6
+
+#define LINUX_PORT_MAX 6
+
+#define LINUX_ASYNC_HUP_NOTIFY 0x0001
+#define LINUX_ASYNC_FOURPORT 0x0002
+#define LINUX_ASYNC_SAK 0x0004
+#define LINUX_ASYNC_SPLIT_TERMIOS 0x0008
+#define LINUX_ASYNC_SPD_MASK 0x0030
+#define LINUX_ASYNC_SPD_HI 0x0010
+#define LINUX_ASYNC_SPD_VHI 0x0020
+#define LINUX_ASYNC_SPD_CUST 0x0030
+#define LINUX_ASYNC_SKIP_TEST 0x0040
+#define LINUX_ASYNC_AUTO_IRQ 0x0080
+#define LINUX_ASYNC_SESSION_LOCKOUT 0x0100
+#define LINUX_ASYNC_PGRP_LOCKOUT 0x0200
+#define LINUX_ASYNC_CALLOUT_NOHUP 0x0400
+#define LINUX_ASYNC_FLAGS 0x0FFF
+
+#define LINUX_IOCTL_DRM_MIN 0x6400
+#define LINUX_IOCTL_DRM_MAX 0x64ff
+
+/*
+ * video
+ */
+#define LINUX_VIDIOCGCAP 0x7601
+#define LINUX_VIDIOCGCHAN 0x7602
+#define LINUX_VIDIOCSCHAN 0x7603
+#define LINUX_VIDIOCGTUNER 0x7604
+#define LINUX_VIDIOCSTUNER 0x7605
+#define LINUX_VIDIOCGPICT 0x7606
+#define LINUX_VIDIOCSPICT 0x7607
+#define LINUX_VIDIOCCAPTURE 0x7608
+#define LINUX_VIDIOCGWIN 0x7609
+#define LINUX_VIDIOCSWIN 0x760a
+#define LINUX_VIDIOCGFBUF 0x760b
+#define LINUX_VIDIOCSFBUF 0x760c
+#define LINUX_VIDIOCKEY 0x760d
+#define LINUX_VIDIOCGFREQ 0x760e
+#define LINUX_VIDIOCSFREQ 0x760f
+#define LINUX_VIDIOCGAUDIO 0x7610
+#define LINUX_VIDIOCSAUDIO 0x7611
+#define LINUX_VIDIOCSYNC 0x7623
+#define LINUX_VIDIOCMCAPTURE 0x7613
+#define LINUX_VIDIOCGMBUF 0x7614
+#define LINUX_VIDIOCGUNIT 0x7615
+#define LINUX_VIDIOCGCAPTURE 0x7616
+#define LINUX_VIDIOCSCAPTURE 0x7617
+#define LINUX_VIDIOCSPLAYMODE 0x7618
+#define LINUX_VIDIOCSWRITEMODE 0x7619
+#define LINUX_VIDIOCGPLAYINFO 0x761a
+#define LINUX_VIDIOCSMICROCODE 0x761b
+#define LINUX_VIDIOCGVBIFMT 0x761c
+#define LINUX_VIDIOCSVBIFMT 0x761d
+
+#define LINUX_IOCTL_VIDEO_MIN LINUX_VIDIOCGCAP
+#define LINUX_IOCTL_VIDEO_MAX LINUX_VIDIOCSVBIFMT
+
+/* videodev2 aka V4L2 */
+
+#define LINUX_VIDIOC_QUERYCAP 0x5600 /* 0x80685600 */
+#define LINUX_VIDIOC_RESERVED 0x5601 /* 0x00005601 */
+#define LINUX_VIDIOC_ENUM_FMT 0x5602 /* 0xc0405602 */
+#define LINUX_VIDIOC_G_FMT 0x5604 /* 0xc0cc5604 */
+#define LINUX_VIDIOC_S_FMT 0x5605 /* 0xc0cc5605 */
+#define LINUX_VIDIOC_REQBUFS 0x5608 /* 0xc0145608 */
+#define LINUX_VIDIOC_QUERYBUF 0x5609 /* 0xc0445609 */
+#define LINUX_VIDIOC_G_FBUF 0x560a /* 0x802c560a */
+#define LINUX_VIDIOC_S_FBUF 0x560b /* 0x402c560b */
+#define LINUX_VIDIOC_OVERLAY 0x560e /* 0x4004560e */
+#define LINUX_VIDIOC_QBUF 0x560f /* 0xc044560f */
+#define LINUX_VIDIOC_DQBUF 0x5611 /* 0xc0445611 */
+#define LINUX_VIDIOC_STREAMON 0x5612 /* 0x40045612 */
+#define LINUX_VIDIOC_STREAMOFF 0x5613 /* 0x40045613 */
+#define LINUX_VIDIOC_G_PARM 0x5615 /* 0xc0cc5615 */
+#define LINUX_VIDIOC_S_PARM 0x5616 /* 0xc0cc5616 */
+#define LINUX_VIDIOC_G_STD 0x5617 /* 0x80085617 */
+#define LINUX_VIDIOC_S_STD 0x5618 /* 0x40085618 */
+#define LINUX_VIDIOC_ENUMSTD 0x5619 /* 0xc0405619 */
+#define LINUX_VIDIOC_ENUMINPUT 0x561a /* 0xc04c561a */
+#define LINUX_VIDIOC_G_CTRL 0x561b /* 0xc008561b */
+#define LINUX_VIDIOC_S_CTRL 0x561c /* 0xc008561c */
+#define LINUX_VIDIOC_G_TUNER 0x561d /* 0xc054561d */
+#define LINUX_VIDIOC_S_TUNER 0x561e /* 0x4054561e */
+#define LINUX_VIDIOC_G_AUDIO 0x5621 /* 0x80345621 */
+#define LINUX_VIDIOC_S_AUDIO 0x5622 /* 0x40345622 */
+#define LINUX_VIDIOC_QUERYCTRL 0x5624 /* 0xc0445624 */
+#define LINUX_VIDIOC_QUERYMENU 0x5625 /* 0xc02c5625 */
+#define LINUX_VIDIOC_G_INPUT 0x5626 /* 0x80045626 */
+#define LINUX_VIDIOC_S_INPUT 0x5627 /* 0xc0045627 */
+#define LINUX_VIDIOC_G_OUTPUT 0x562e /* 0x8004562e */
+#define LINUX_VIDIOC_S_OUTPUT 0x562f /* 0xc004562f */
+#define LINUX_VIDIOC_ENUMOUTPUT 0x5630 /* 0xc0485630 */
+#define LINUX_VIDIOC_G_AUDOUT 0x5631 /* 0x80345631 */
+#define LINUX_VIDIOC_S_AUDOUT 0x5632 /* 0x40345632 */
+#define LINUX_VIDIOC_G_MODULATOR 0x5636 /* 0xc0445636 */
+#define LINUX_VIDIOC_S_MODULATOR 0x5637 /* 0x40445637 */
+#define LINUX_VIDIOC_G_FREQUENCY 0x5638 /* 0xc02c5638 */
+#define LINUX_VIDIOC_S_FREQUENCY 0x5639 /* 0x402c5639 */
+#define LINUX_VIDIOC_CROPCAP 0x563a /* 0xc02c563a */
+#define LINUX_VIDIOC_G_CROP 0x563b /* 0xc014563b */
+#define LINUX_VIDIOC_S_CROP 0x563c /* 0x4014563c */
+#define LINUX_VIDIOC_G_JPEGCOMP 0x563d /* 0x808c563d */
+#define LINUX_VIDIOC_S_JPEGCOMP 0x563e /* 0x408c563e */
+#define LINUX_VIDIOC_QUERYSTD 0x563f /* 0x8008563f */
+#define LINUX_VIDIOC_TRY_FMT 0x5640 /* 0xc0cc5640 */
+#define LINUX_VIDIOC_ENUMAUDIO 0x5641 /* 0xc0345641 */
+#define LINUX_VIDIOC_ENUMAUDOUT 0x5642 /* 0xc0345642 */
+#define LINUX_VIDIOC_G_PRIORITY 0x5643 /* 0x80045643 */
+#define LINUX_VIDIOC_S_PRIORITY 0x5644 /* 0x40045644 */
+#define LINUX_VIDIOC_G_SLICED_VBI_CAP 0x5645 /* 0xc0745645 */
+#define LINUX_VIDIOC_LOG_STATUS 0x5646 /* 0x00005646 */
+#define LINUX_VIDIOC_G_EXT_CTRLS 0x5647 /* 0xc0185647 */
+#define LINUX_VIDIOC_S_EXT_CTRLS 0x5648 /* 0xc0185648 */
+#define LINUX_VIDIOC_TRY_EXT_CTRLS 0x5649 /* 0xc0185649 */
+#define LINUX_VIDIOC_ENUM_FRAMESIZES 0x564a /* 0xc02c564a */
+#define LINUX_VIDIOC_ENUM_FRAMEINTERVALS 0x564b /* 0xc034564b */
+#define LINUX_VIDIOC_G_ENC_INDEX 0x564c /* 0x8818564c */
+#define LINUX_VIDIOC_ENCODER_CMD 0x564d /* 0xc028564d */
+#define LINUX_VIDIOC_TRY_ENCODER_CMD 0x564e /* 0xc028564e */
+#define LINUX_VIDIOC_DBG_S_REGISTER 0x564f /* 0x4038564f */
+#define LINUX_VIDIOC_DBG_G_REGISTER 0x5650 /* 0xc0385650 */
+#define LINUX_VIDIOC_DBG_G_CHIP_IDENT 0x5651 /* 0xc02c5651 */
+#define LINUX_VIDIOC_S_HW_FREQ_SEEK 0x5652 /* 0x40305652 */
+#define LINUX_VIDIOC_ENUM_DV_PRESETS 0x5653 /* 0xc0405653 */
+#define LINUX_VIDIOC_S_DV_PRESET 0x5654 /* 0xc0145654 */
+#define LINUX_VIDIOC_G_DV_PRESET 0x5655 /* 0xc0145655 */
+#define LINUX_VIDIOC_QUERY_DV_PRESET 0x5656 /* 0x80145656 */
+#define LINUX_VIDIOC_S_DV_TIMINGS 0x5657 /* 0xc0845657 */
+#define LINUX_VIDIOC_G_DV_TIMINGS 0x5658 /* 0xc0845658 */
+#define LINUX_VIDIOC_DQEVENT 0x5659 /* 0x80785659 */
+#define LINUX_VIDIOC_SUBSCRIBE_EVENT 0x565a /* 0x4020565a */
+#define LINUX_VIDIOC_UNSUBSCRIBE_EVENT 0x565b /* 0x4020565b */
+
+#define LINUX_VIDIOC_OVERLAY_OLD 0x560e /* 0xc004560e */
+#define LINUX_VIDIOC_S_PARM_OLD 0x5616 /* 0x40cc5616 */
+#define LINUX_VIDIOC_S_CTRL_OLD 0x561c /* 0x4008561c */
+#define LINUX_VIDIOC_G_AUDIO_OLD 0x5621 /* 0xc0345621 */
+#define LINUX_VIDIOC_G_AUDOUT_OLD 0x5631 /* 0xc0345631 */
+#define LINUX_VIDIOC_CROPCAP_OLD 0x563a /* 0x802c563a */
+
+#define LINUX_IOCTL_VIDEO2_MIN LINUX_VIDIOC_QUERYCAP
+#define LINUX_IOCTL_VIDEO2_MAX LINUX_VIDIOC_UNSUBSCRIBE_EVENT
+
+#define LINUX_F2FS_IOC_GET_FEATURES 0xf50c /* 0x8004f50c */
+
+#define LINUX_IOCTL_F2FS_MIN 0xf500
+#define LINUX_IOCTL_F2FS_MAX LINUX_F2FS_IOC_GET_FEATURES
+
+/*
+ * Our libusb(8) calls emulated within linux(4).
+ */
+#define FBSD_LUSB_DEVICEENUMERATE 0xffff
+#define FBSD_LUSB_DEV_QUIRK_ADD 0xfffe
+#define FBSD_LUSB_DEV_QUIRK_GET 0xfffd
+#define FBSD_LUSB_DEV_QUIRK_REMOVE 0xfffc
+#define FBSD_LUSB_DO_REQUEST 0xfffb
+#define FBSD_LUSB_FS_CLEAR_STALL_SYNC 0xfffa
+#define FBSD_LUSB_FS_CLOSE 0xfff9
+#define FBSD_LUSB_FS_COMPLETE 0xfff8
+#define FBSD_LUSB_FS_INIT 0xfff7
+#define FBSD_LUSB_FS_OPEN 0xfff6
+#define FBSD_LUSB_FS_START 0xfff5
+#define FBSD_LUSB_FS_STOP 0xfff4
+#define FBSD_LUSB_FS_UNINIT 0xfff3
+#define FBSD_LUSB_GET_CONFIG 0xfff2
+#define FBSD_LUSB_GET_DEVICEINFO 0xfff1
+#define FBSD_LUSB_GET_DEVICE_DESC 0xfff0
+#define FBSD_LUSB_GET_FULL_DESC 0xffef
+#define FBSD_LUSB_GET_IFACE_DRIVER 0xffee
+#define FBSD_LUSB_GET_PLUGTIME 0xffed
+#define FBSD_LUSB_GET_POWER_MODE 0xffec
+#define FBSD_LUSB_GET_REPORT_DESC 0xffeb
+#define FBSD_LUSB_GET_REPORT_ID 0xffea
+#define FBSD_LUSB_GET_TEMPLATE 0xffe9
+#define FBSD_LUSB_IFACE_DRIVER_ACTIVE 0xffe8
+#define FBSD_LUSB_IFACE_DRIVER_DETACH 0xffe7
+#define FBSD_LUSB_QUIRK_NAME_GET 0xffe6
+#define FBSD_LUSB_READ_DIR 0xffe5
+#define FBSD_LUSB_SET_ALTINTERFACE 0xffe4
+#define FBSD_LUSB_SET_CONFIG 0xffe3
+#define FBSD_LUSB_SET_IMMED 0xffe2
+#define FBSD_LUSB_SET_POWER_MODE 0xffe1
+#define FBSD_LUSB_SET_TEMPLATE 0xffe0
+#define FBSD_LUSB_FS_OPEN_STREAM 0xffdf
+#define FBSD_LUSB_GET_DEV_PORT_PATH 0xffde
+#define FBSD_LUSB_GET_POWER_USAGE 0xffdd
+#define FBSD_LUSB_DEVICESTATS 0xffdc
+
+#define LINUX_IOCTL_FBSD_LUSB_MAX 0xffff
+#define LINUX_IOCTL_FBSD_LUSB_MIN 0xffdc
+
+/*
+ * Linux btrfs clone operation
+ */
+#define LINUX_BTRFS_IOC_CLONE 0x9409 /* 0x40049409 */
+#define LINUX_FS_IOC_FIEMAP 0x660b
+
+/*
+ * Linux evdev ioctl min and max
+ */
+#define LINUX_IOCTL_EVDEV_MIN 0x4500
+#define LINUX_IOCTL_EVDEV_MAX 0x45ff
+#define LINUX_IOCTL_EVDEV_CLK LINUX_CLOCK_REALTIME | \
+ LINUX_CLOCK_MONOTONIC |LINUX_CLOCK_BOOTTIME
+
+/*
+ * kcov(4) shims
+ */
+#define LINUX_IOCTL_KCOV_MIN 0x6300
+#define LINUX_IOCTL_KCOV_MAX 0x63ff
+#define LINUX_KCOV_INIT_TRACE 0x6301
+#define LINUX_KCOV_ENABLE 0x6364
+#define LINUX_KCOV_DISABLE 0x6365
+#define LINUX_KCOV_REMOTE_ENABLE 0x6366
+
+/*
+ * Pluggable ioctl handlers
+ */
+struct linux_ioctl_args;
+struct thread;
+
+typedef int linux_ioctl_function_t(struct thread *, struct linux_ioctl_args *);
+
+struct linux_ioctl_handler {
+ linux_ioctl_function_t *func;
+ int low, high;
+};
+
+struct linux_ioctl_handler_element
+{
+ TAILQ_ENTRY(linux_ioctl_handler_element) list;
+ int (*func)(struct thread *, struct linux_ioctl_args *);
+ int low, high, span;
+};
+
+int linux_ioctl_register_handler(struct linux_ioctl_handler *h);
+int linux_ioctl_unregister_handler(struct linux_ioctl_handler *h);
+#ifdef COMPAT_LINUX32
+int linux32_ioctl_register_handler(struct linux_ioctl_handler *h);
+int linux32_ioctl_unregister_handler(struct linux_ioctl_handler *h);
+#endif
+
+#endif /* !_LINUX_IOCTL_H_ */
diff --git a/sys/compat/linux/linux_ipc.c b/sys/compat/linux/linux_ipc.c
new file mode 100644
index 000000000000..82fe54fae65e
--- /dev/null
+++ b/sys/compat/linux/linux_ipc.c
@@ -0,0 +1,930 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1994-1995 Søren Schmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysproto.h>
+#include <sys/proc.h>
+#include <sys/limits.h>
+#include <sys/msg.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+#include <sys/stat.h>
+
+#include "opt_compat.h"
+
+#ifdef COMPAT_LINUX32
+#include <machine/../linux32/linux.h>
+#include <machine/../linux32/linux32_proto.h>
+#else
+#include <machine/../linux/linux.h>
+#include <machine/../linux/linux_proto.h>
+#endif
+#include <compat/linux/linux_ipc.h>
+#include <compat/linux/linux_ipc64.h>
+#include <compat/linux/linux_util.h>
+
+/*
+ * old, pre 2.4 kernel
+ */
+struct l_ipc_perm {
+ l_key_t key;
+ l_uid16_t uid;
+ l_gid16_t gid;
+ l_uid16_t cuid;
+ l_gid16_t cgid;
+ l_ushort mode;
+ l_ushort seq;
+};
+
+struct l_seminfo {
+ l_int semmap;
+ l_int semmni;
+ l_int semmns;
+ l_int semmnu;
+ l_int semmsl;
+ l_int semopm;
+ l_int semume;
+ l_int semusz;
+ l_int semvmx;
+ l_int semaem;
+};
+
+struct l_shminfo {
+ l_int shmmax;
+ l_int shmmin;
+ l_int shmmni;
+ l_int shmseg;
+ l_int shmall;
+};
+
+struct l_shm_info {
+ l_int used_ids;
+ l_ulong shm_tot; /* total allocated shm */
+ l_ulong shm_rss; /* total resident shm */
+ l_ulong shm_swp; /* total swapped shm */
+ l_ulong swap_attempts;
+ l_ulong swap_successes;
+};
+
+struct l_msginfo {
+ l_int msgpool;
+ l_int msgmap;
+ l_int msgmax;
+ l_int msgmnb;
+ l_int msgmni;
+ l_int msgssz;
+ l_int msgtql;
+ l_ushort msgseg;
+};
+
+static void
+bsd_to_linux_shminfo( struct shminfo *bpp, struct l_shminfo64 *lpp)
+{
+
+ lpp->shmmax = bpp->shmmax;
+ lpp->shmmin = bpp->shmmin;
+ lpp->shmmni = bpp->shmmni;
+ lpp->shmseg = bpp->shmseg;
+ lpp->shmall = bpp->shmall;
+}
+
+static void
+bsd_to_linux_shm_info( struct shm_info *bpp, struct l_shm_info *lpp)
+{
+
+ lpp->used_ids = bpp->used_ids;
+ lpp->shm_tot = bpp->shm_tot;
+ lpp->shm_rss = bpp->shm_rss;
+ lpp->shm_swp = bpp->shm_swp;
+ lpp->swap_attempts = bpp->swap_attempts;
+ lpp->swap_successes = bpp->swap_successes;
+}
+
+static void
+linux_to_bsd_ipc_perm(struct l_ipc64_perm *lpp, struct ipc_perm *bpp)
+{
+
+ bpp->key = lpp->key;
+ bpp->uid = lpp->uid;
+ bpp->gid = lpp->gid;
+ bpp->cuid = lpp->cuid;
+ bpp->cgid = lpp->cgid;
+ bpp->mode = lpp->mode;
+ bpp->seq = lpp->seq;
+}
+
+static void
+bsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct l_ipc64_perm *lpp)
+{
+
+ lpp->key = bpp->key;
+ lpp->uid = bpp->uid;
+ lpp->gid = bpp->gid;
+ lpp->cuid = bpp->cuid;
+ lpp->cgid = bpp->cgid;
+ lpp->mode = bpp->mode & (S_IRWXU|S_IRWXG|S_IRWXO);
+ lpp->seq = bpp->seq;
+}
+
+struct l_msqid_ds {
+ struct l_ipc_perm msg_perm;
+ l_uintptr_t msg_first; /* first message on queue,unused */
+ l_uintptr_t msg_last; /* last message in queue,unused */
+ l_time_t msg_stime; /* last msgsnd time */
+ l_time_t msg_rtime; /* last msgrcv time */
+ l_time_t msg_ctime; /* last change time */
+ l_ulong msg_lcbytes; /* Reuse junk fields for 32 bit */
+ l_ulong msg_lqbytes; /* ditto */
+ l_ushort msg_cbytes; /* current number of bytes on queue */
+ l_ushort msg_qnum; /* number of messages in queue */
+ l_ushort msg_qbytes; /* max number of bytes on queue */
+ l_pid_t msg_lspid; /* pid of last msgsnd */
+ l_pid_t msg_lrpid; /* last receive pid */
+};
+
+struct l_semid_ds {
+ struct l_ipc_perm sem_perm;
+ l_time_t sem_otime;
+ l_time_t sem_ctime;
+ l_uintptr_t sem_base;
+ l_uintptr_t sem_pending;
+ l_uintptr_t sem_pending_last;
+ l_uintptr_t undo;
+ l_ushort sem_nsems;
+};
+
+struct l_shmid_ds {
+ struct l_ipc_perm shm_perm;
+ l_int shm_segsz;
+ l_time_t shm_atime;
+ l_time_t shm_dtime;
+ l_time_t shm_ctime;
+ l_ushort shm_cpid;
+ l_ushort shm_lpid;
+ l_short shm_nattch;
+ l_ushort private1;
+ l_uintptr_t private2;
+ l_uintptr_t private3;
+};
+
+static void
+linux_to_bsd_semid_ds(struct l_semid64_ds *lsp, struct semid_ds *bsp)
+{
+
+ linux_to_bsd_ipc_perm(&lsp->sem_perm, &bsp->sem_perm);
+ bsp->sem_otime = lsp->sem_otime;
+ bsp->sem_ctime = lsp->sem_ctime;
+ bsp->sem_nsems = lsp->sem_nsems;
+}
+
+static void
+bsd_to_linux_semid_ds(struct semid_ds *bsp, struct l_semid64_ds *lsp)
+{
+
+ bsd_to_linux_ipc_perm(&bsp->sem_perm, &lsp->sem_perm);
+ lsp->sem_otime = bsp->sem_otime;
+ lsp->sem_ctime = bsp->sem_ctime;
+ lsp->sem_nsems = bsp->sem_nsems;
+}
+
+static void
+linux_to_bsd_shmid_ds(struct l_shmid64_ds *lsp, struct shmid_ds *bsp)
+{
+
+ linux_to_bsd_ipc_perm(&lsp->shm_perm, &bsp->shm_perm);
+ bsp->shm_segsz = lsp->shm_segsz;
+ bsp->shm_lpid = lsp->shm_lpid;
+ bsp->shm_cpid = lsp->shm_cpid;
+ bsp->shm_nattch = lsp->shm_nattch;
+ bsp->shm_atime = lsp->shm_atime;
+ bsp->shm_dtime = lsp->shm_dtime;
+ bsp->shm_ctime = lsp->shm_ctime;
+}
+
+static void
+bsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct l_shmid64_ds *lsp)
+{
+
+ bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->shm_perm);
+ lsp->shm_segsz = bsp->shm_segsz;
+ lsp->shm_lpid = bsp->shm_lpid;
+ lsp->shm_cpid = bsp->shm_cpid;
+ lsp->shm_nattch = bsp->shm_nattch;
+ lsp->shm_atime = bsp->shm_atime;
+ lsp->shm_dtime = bsp->shm_dtime;
+ lsp->shm_ctime = bsp->shm_ctime;
+}
+
+static void
+linux_to_bsd_msqid_ds(struct l_msqid64_ds *lsp, struct msqid_ds *bsp)
+{
+
+ linux_to_bsd_ipc_perm(&lsp->msg_perm, &bsp->msg_perm);
+ bsp->msg_cbytes = lsp->msg_cbytes;
+ bsp->msg_qnum = lsp->msg_qnum;
+ bsp->msg_qbytes = lsp->msg_qbytes;
+ bsp->msg_lspid = lsp->msg_lspid;
+ bsp->msg_lrpid = lsp->msg_lrpid;
+ bsp->msg_stime = lsp->msg_stime;
+ bsp->msg_rtime = lsp->msg_rtime;
+ bsp->msg_ctime = lsp->msg_ctime;
+}
+
+static void
+bsd_to_linux_msqid_ds(struct msqid_ds *bsp, struct l_msqid64_ds *lsp)
+{
+
+ bsd_to_linux_ipc_perm(&bsp->msg_perm, &lsp->msg_perm);
+ lsp->msg_cbytes = bsp->msg_cbytes;
+ lsp->msg_qnum = bsp->msg_qnum;
+ lsp->msg_qbytes = bsp->msg_qbytes;
+ lsp->msg_lspid = bsp->msg_lspid;
+ lsp->msg_lrpid = bsp->msg_lrpid;
+ lsp->msg_stime = bsp->msg_stime;
+ lsp->msg_rtime = bsp->msg_rtime;
+ lsp->msg_ctime = bsp->msg_ctime;
+}
+
+static int
+linux_ipc64_perm_to_ipc_perm(struct l_ipc64_perm *in, struct l_ipc_perm *out)
+{
+
+ out->key = in->key;
+ out->uid = in->uid;
+ out->gid = in->gid;
+ out->cuid = in->cuid;
+ out->cgid = in->cgid;
+ out->mode = in->mode;
+ out->seq = in->seq;
+
+ /* Linux does not check overflow */
+ if (out->uid != in->uid || out->gid != in->gid ||
+ out->cuid != in->cuid || out->cgid != in->cgid ||
+ out->mode != in->mode)
+ return (EOVERFLOW);
+ else
+ return (0);
+}
+
+static int
+linux_msqid_pullup(l_int ver, struct l_msqid64_ds *linux_msqid64, caddr_t uaddr)
+{
+ struct l_msqid_ds linux_msqid;
+ int error;
+
+ if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
+ return (copyin(uaddr, linux_msqid64, sizeof(*linux_msqid64)));
+ else {
+ error = copyin(uaddr, &linux_msqid, sizeof(linux_msqid));
+ if (error != 0)
+ return (error);
+
+ bzero(linux_msqid64, sizeof(*linux_msqid64));
+
+ linux_msqid64->msg_perm.uid = linux_msqid.msg_perm.uid;
+ linux_msqid64->msg_perm.gid = linux_msqid.msg_perm.gid;
+ linux_msqid64->msg_perm.mode = linux_msqid.msg_perm.mode;
+ if (linux_msqid.msg_qbytes == 0)
+ linux_msqid64->msg_qbytes = linux_msqid.msg_lqbytes;
+ else
+ linux_msqid64->msg_qbytes = linux_msqid.msg_qbytes;
+ return (0);
+ }
+}
+
+static int
+linux_msqid_pushdown(l_int ver, struct l_msqid64_ds *linux_msqid64, caddr_t uaddr)
+{
+ struct l_msqid_ds linux_msqid;
+ int error;
+
+ if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
+ return (copyout(linux_msqid64, uaddr, sizeof(*linux_msqid64)));
+ else {
+ bzero(&linux_msqid, sizeof(linux_msqid));
+
+ error = linux_ipc64_perm_to_ipc_perm(&linux_msqid64->msg_perm,
+ &linux_msqid.msg_perm);
+ if (error != 0)
+ return (error);
+
+ linux_msqid.msg_stime = linux_msqid64->msg_stime;
+ linux_msqid.msg_rtime = linux_msqid64->msg_rtime;
+ linux_msqid.msg_ctime = linux_msqid64->msg_ctime;
+
+ if (linux_msqid64->msg_cbytes > USHRT_MAX)
+ linux_msqid.msg_cbytes = USHRT_MAX;
+ else
+ linux_msqid.msg_cbytes = linux_msqid64->msg_cbytes;
+ linux_msqid.msg_lcbytes = linux_msqid64->msg_cbytes;
+ if (linux_msqid64->msg_qnum > USHRT_MAX)
+ linux_msqid.msg_qnum = USHRT_MAX;
+ else
+ linux_msqid.msg_qnum = linux_msqid64->msg_qnum;
+ if (linux_msqid64->msg_qbytes > USHRT_MAX)
+ linux_msqid.msg_qbytes = USHRT_MAX;
+ else
+ linux_msqid.msg_qbytes = linux_msqid64->msg_qbytes;
+ linux_msqid.msg_lqbytes = linux_msqid64->msg_qbytes;
+ linux_msqid.msg_lspid = linux_msqid64->msg_lspid;
+ linux_msqid.msg_lrpid = linux_msqid64->msg_lrpid;
+
+ /* Linux does not check overflow */
+ if (linux_msqid.msg_stime != linux_msqid64->msg_stime ||
+ linux_msqid.msg_rtime != linux_msqid64->msg_rtime ||
+ linux_msqid.msg_ctime != linux_msqid64->msg_ctime)
+ return (EOVERFLOW);
+
+ return (copyout(&linux_msqid, uaddr, sizeof(linux_msqid)));
+ }
+}
+
+static int
+linux_semid_pullup(l_int ver, struct l_semid64_ds *linux_semid64, caddr_t uaddr)
+{
+ struct l_semid_ds linux_semid;
+ int error;
+
+ if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
+ return (copyin(uaddr, linux_semid64, sizeof(*linux_semid64)));
+ else {
+ error = copyin(uaddr, &linux_semid, sizeof(linux_semid));
+ if (error != 0)
+ return (error);
+
+ bzero(linux_semid64, sizeof(*linux_semid64));
+
+ linux_semid64->sem_perm.uid = linux_semid.sem_perm.uid;
+ linux_semid64->sem_perm.gid = linux_semid.sem_perm.gid;
+ linux_semid64->sem_perm.mode = linux_semid.sem_perm.mode;
+ return (0);
+ }
+}
+
+static int
+linux_semid_pushdown(l_int ver, struct l_semid64_ds *linux_semid64, caddr_t uaddr)
+{
+ struct l_semid_ds linux_semid;
+ int error;
+
+ if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
+ return (copyout(linux_semid64, uaddr, sizeof(*linux_semid64)));
+ else {
+ bzero(&linux_semid, sizeof(linux_semid));
+
+ error = linux_ipc64_perm_to_ipc_perm(&linux_semid64->sem_perm,
+ &linux_semid.sem_perm);
+ if (error != 0)
+ return (error);
+
+ linux_semid.sem_otime = linux_semid64->sem_otime;
+ linux_semid.sem_ctime = linux_semid64->sem_ctime;
+ linux_semid.sem_nsems = linux_semid64->sem_nsems;
+
+ /* Linux does not check overflow */
+ if (linux_semid.sem_otime != linux_semid64->sem_otime ||
+ linux_semid.sem_ctime != linux_semid64->sem_ctime ||
+ linux_semid.sem_nsems != linux_semid64->sem_nsems)
+ return (EOVERFLOW);
+
+ return (copyout(&linux_semid, uaddr, sizeof(linux_semid)));
+ }
+}
+
+static int
+linux_shmid_pullup(l_int ver, struct l_shmid64_ds *linux_shmid64, caddr_t uaddr)
+{
+ struct l_shmid_ds linux_shmid;
+ int error;
+
+ if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
+ return (copyin(uaddr, linux_shmid64, sizeof(*linux_shmid64)));
+ else {
+ error = copyin(uaddr, &linux_shmid, sizeof(linux_shmid));
+ if (error != 0)
+ return (error);
+
+ bzero(linux_shmid64, sizeof(*linux_shmid64));
+
+ linux_shmid64->shm_perm.uid = linux_shmid.shm_perm.uid;
+ linux_shmid64->shm_perm.gid = linux_shmid.shm_perm.gid;
+ linux_shmid64->shm_perm.mode = linux_shmid.shm_perm.mode;
+ return (0);
+ }
+}
+
+static int
+linux_shmid_pushdown(l_int ver, struct l_shmid64_ds *linux_shmid64, caddr_t uaddr)
+{
+ struct l_shmid_ds linux_shmid;
+ int error;
+
+ if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
+ return (copyout(linux_shmid64, uaddr, sizeof(*linux_shmid64)));
+ else {
+ bzero(&linux_shmid, sizeof(linux_shmid));
+
+ error = linux_ipc64_perm_to_ipc_perm(&linux_shmid64->shm_perm,
+ &linux_shmid.shm_perm);
+ if (error != 0)
+ return (error);
+
+ linux_shmid.shm_segsz = linux_shmid64->shm_segsz;
+ linux_shmid.shm_atime = linux_shmid64->shm_atime;
+ linux_shmid.shm_dtime = linux_shmid64->shm_dtime;
+ linux_shmid.shm_ctime = linux_shmid64->shm_ctime;
+ linux_shmid.shm_cpid = linux_shmid64->shm_cpid;
+ linux_shmid.shm_lpid = linux_shmid64->shm_lpid;
+ linux_shmid.shm_nattch = linux_shmid64->shm_nattch;
+
+ /* Linux does not check overflow */
+ if (linux_shmid.shm_segsz != linux_shmid64->shm_segsz ||
+ linux_shmid.shm_atime != linux_shmid64->shm_atime ||
+ linux_shmid.shm_dtime != linux_shmid64->shm_dtime ||
+ linux_shmid.shm_ctime != linux_shmid64->shm_ctime ||
+ linux_shmid.shm_cpid != linux_shmid64->shm_cpid ||
+ linux_shmid.shm_lpid != linux_shmid64->shm_lpid ||
+ linux_shmid.shm_nattch != linux_shmid64->shm_nattch)
+ return (EOVERFLOW);
+
+ return (copyout(&linux_shmid, uaddr, sizeof(linux_shmid)));
+ }
+}
+
+static int
+linux_shminfo_pushdown(l_int ver, struct l_shminfo64 *linux_shminfo64,
+ caddr_t uaddr)
+{
+ struct l_shminfo linux_shminfo;
+
+ if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
+ return (copyout(linux_shminfo64, uaddr,
+ sizeof(*linux_shminfo64)));
+ else {
+ bzero(&linux_shminfo, sizeof(linux_shminfo));
+
+ linux_shminfo.shmmax = linux_shminfo64->shmmax;
+ linux_shminfo.shmmin = linux_shminfo64->shmmin;
+ linux_shminfo.shmmni = linux_shminfo64->shmmni;
+ linux_shminfo.shmseg = linux_shminfo64->shmseg;
+ linux_shminfo.shmall = linux_shminfo64->shmall;
+
+ return (copyout(&linux_shminfo, uaddr,
+ sizeof(linux_shminfo)));
+ }
+}
+
+int
+linux_semop(struct thread *td, struct linux_semop_args *args)
+{
+ struct semop_args /* {
+ int semid;
+ struct sembuf *sops;
+ int nsops;
+ } */ bsd_args;
+
+ if (args->nsops < 1 || args->semid < 0)
+ return (EINVAL);
+ bsd_args.semid = args->semid;
+ bsd_args.sops = PTRIN(args->tsops);
+ bsd_args.nsops = args->nsops;
+ return (sys_semop(td, &bsd_args));
+}
+
+int
+linux_semget(struct thread *td, struct linux_semget_args *args)
+{
+ struct semget_args /* {
+ key_t key;
+ int nsems;
+ int semflg;
+ } */ bsd_args;
+
+ if (args->nsems < 0)
+ return (EINVAL);
+ bsd_args.key = args->key;
+ bsd_args.nsems = args->nsems;
+ bsd_args.semflg = args->semflg;
+ return (sys_semget(td, &bsd_args));
+}
+
+int
+linux_semctl(struct thread *td, struct linux_semctl_args *args)
+{
+ struct l_semid64_ds linux_semid64;
+ struct l_seminfo linux_seminfo;
+ struct semid_ds semid;
+ union semun semun;
+ register_t rval;
+ int cmd, error;
+
+ memset(&linux_seminfo, 0, sizeof(linux_seminfo));
+ memset(&linux_semid64, 0, sizeof(linux_semid64));
+
+ switch (args->cmd & ~LINUX_IPC_64) {
+ case LINUX_IPC_RMID:
+ cmd = IPC_RMID;
+ break;
+ case LINUX_GETNCNT:
+ cmd = GETNCNT;
+ break;
+ case LINUX_GETPID:
+ cmd = GETPID;
+ break;
+ case LINUX_GETVAL:
+ cmd = GETVAL;
+ break;
+ case LINUX_GETZCNT:
+ cmd = GETZCNT;
+ break;
+ case LINUX_SETVAL:
+ cmd = SETVAL;
+ semun.val = args->arg.val;
+ break;
+ case LINUX_IPC_SET:
+ cmd = IPC_SET;
+ error = linux_semid_pullup(args->cmd & LINUX_IPC_64,
+ &linux_semid64, PTRIN(args->arg.buf));
+ if (error != 0)
+ return (error);
+ linux_to_bsd_semid_ds(&linux_semid64, &semid);
+ semun.buf = &semid;
+ return (kern_semctl(td, args->semid, args->semnum, cmd, &semun,
+ td->td_retval));
+ case LINUX_IPC_STAT:
+ cmd = IPC_STAT;
+ semun.buf = &semid;
+ error = kern_semctl(td, args->semid, args->semnum, cmd, &semun,
+ &rval);
+ if (error != 0)
+ return (error);
+ bsd_to_linux_semid_ds(&semid, &linux_semid64);
+ return (linux_semid_pushdown(args->cmd & LINUX_IPC_64,
+ &linux_semid64, PTRIN(args->arg.buf)));
+ case LINUX_SEM_STAT:
+ cmd = SEM_STAT;
+ semun.buf = &semid;
+ error = kern_semctl(td, args->semid, args->semnum, cmd, &semun,
+ &rval);
+ if (error != 0)
+ return (error);
+ bsd_to_linux_semid_ds(&semid, &linux_semid64);
+ error = linux_semid_pushdown(args->cmd & LINUX_IPC_64,
+ &linux_semid64, PTRIN(args->arg.buf));
+ if (error == 0)
+ td->td_retval[0] = rval;
+ return (error);
+ case LINUX_IPC_INFO:
+ case LINUX_SEM_INFO:
+ bcopy(&seminfo, &linux_seminfo.semmni, sizeof(linux_seminfo) -
+ sizeof(linux_seminfo.semmap) );
+ /*
+ * Linux does not use the semmap field but populates it with
+ * the defined value from SEMMAP, which really is redefined to
+ * SEMMNS, which they define as SEMMNI * SEMMSL. Try to
+ * simulate this returning our dynamic semmns value.
+ */
+ linux_seminfo.semmap = linux_seminfo.semmns;
+/* XXX BSD equivalent?
+#define used_semids 10
+#define used_sems 10
+ linux_seminfo.semusz = used_semids;
+ linux_seminfo.semaem = used_sems;
+*/
+ error = copyout(&linux_seminfo,
+ PTRIN(args->arg.buf), sizeof(linux_seminfo));
+ if (error != 0)
+ return (error);
+ /*
+ * TODO: Linux return the last assigned id, not the semmni.
+ */
+ td->td_retval[0] = seminfo.semmni;
+ return (0);
+ case LINUX_GETALL:
+ cmd = GETALL;
+ semun.array = PTRIN(args->arg.array);
+ break;
+ case LINUX_SETALL:
+ cmd = SETALL;
+ semun.array = PTRIN(args->arg.array);
+ break;
+ default:
+ linux_msg(td, "ipc type %d is not implemented",
+ args->cmd & ~LINUX_IPC_64);
+ return (EINVAL);
+ }
+ return (kern_semctl(td, args->semid, args->semnum, cmd, &semun,
+ td->td_retval));
+}
+
+int
+linux_msgsnd(struct thread *td, struct linux_msgsnd_args *args)
+{
+ const void *msgp;
+ long mtype;
+ l_long lmtype;
+ int error;
+
+ if ((l_long)args->msgsz < 0 || args->msgsz > (l_long)msginfo.msgmax)
+ return (EINVAL);
+ msgp = PTRIN(args->msgp);
+ if ((error = copyin(msgp, &lmtype, sizeof(lmtype))) != 0)
+ return (error);
+ mtype = (long)lmtype;
+ return (kern_msgsnd(td, args->msqid,
+ (const char *)msgp + sizeof(lmtype),
+ args->msgsz, args->msgflg, mtype));
+}
+
+int
+linux_msgrcv(struct thread *td, struct linux_msgrcv_args *args)
+{
+ void *msgp;
+ long mtype;
+ l_long lmtype;
+ int error;
+
+ if ((l_long)args->msgsz < 0 || args->msgsz > (l_long)msginfo.msgmax)
+ return (EINVAL);
+ msgp = PTRIN(args->msgp);
+ if ((error = kern_msgrcv(td, args->msqid,
+ (char *)msgp + sizeof(lmtype), args->msgsz,
+ args->msgtyp, args->msgflg, &mtype)) != 0)
+ return (error);
+ lmtype = (l_long)mtype;
+ return (copyout(&lmtype, msgp, sizeof(lmtype)));
+}
+
+int
+linux_msgget(struct thread *td, struct linux_msgget_args *args)
+{
+ struct msgget_args /* {
+ key_t key;
+ int msgflg;
+ } */ bsd_args;
+
+ bsd_args.key = args->key;
+ bsd_args.msgflg = args->msgflg;
+ return (sys_msgget(td, &bsd_args));
+}
+
+int
+linux_msgctl(struct thread *td, struct linux_msgctl_args *args)
+{
+ int error, bsd_cmd;
+ struct l_msqid64_ds linux_msqid64;
+ struct msqid_ds bsd_msqid;
+
+ memset(&linux_msqid64, 0, sizeof(linux_msqid64));
+
+ bsd_cmd = args->cmd & ~LINUX_IPC_64;
+ switch (bsd_cmd) {
+ case LINUX_IPC_INFO:
+ case LINUX_MSG_INFO: {
+ struct l_msginfo linux_msginfo;
+
+ memset(&linux_msginfo, 0, sizeof(linux_msginfo));
+ /*
+ * XXX MSG_INFO uses the same data structure but returns different
+ * dynamic counters in msgpool, msgmap, and msgtql fields.
+ */
+ linux_msginfo.msgpool = (long)msginfo.msgmni *
+ (long)msginfo.msgmnb / 1024L; /* XXX MSG_INFO. */
+ linux_msginfo.msgmap = msginfo.msgmnb; /* XXX MSG_INFO. */
+ linux_msginfo.msgmax = msginfo.msgmax;
+ linux_msginfo.msgmnb = msginfo.msgmnb;
+ linux_msginfo.msgmni = msginfo.msgmni;
+ linux_msginfo.msgssz = msginfo.msgssz;
+ linux_msginfo.msgtql = msginfo.msgtql; /* XXX MSG_INFO. */
+ linux_msginfo.msgseg = msginfo.msgseg;
+ error = copyout(&linux_msginfo, PTRIN(args->buf),
+ sizeof(linux_msginfo));
+ if (error == 0)
+ td->td_retval[0] = msginfo.msgmni; /* XXX */
+
+ return (error);
+ }
+
+ /*
+ * TODO: implement this
+ * case LINUX_MSG_STAT:
+ */
+ case LINUX_IPC_STAT:
+ /* NOTHING */
+ break;
+
+ case LINUX_IPC_SET:
+ error = linux_msqid_pullup(args->cmd & LINUX_IPC_64,
+ &linux_msqid64, PTRIN(args->buf));
+ if (error != 0)
+ return (error);
+ linux_to_bsd_msqid_ds(&linux_msqid64, &bsd_msqid);
+ break;
+
+ case LINUX_IPC_RMID:
+ /* NOTHING */
+ break;
+
+ default:
+ return (EINVAL);
+ break;
+ }
+
+ error = kern_msgctl(td, args->msqid, bsd_cmd, &bsd_msqid);
+ if (error != 0) {
+ if (bsd_cmd == LINUX_IPC_RMID && error == EACCES)
+ return (EPERM);
+ if (bsd_cmd != LINUX_IPC_RMID || error != EINVAL)
+ return (error);
+ }
+
+ if (bsd_cmd == LINUX_IPC_STAT) {
+ bsd_to_linux_msqid_ds(&bsd_msqid, &linux_msqid64);
+ return (linux_msqid_pushdown(args->cmd & LINUX_IPC_64,
+ &linux_msqid64, PTRIN(args->buf)));
+ }
+
+ return (0);
+}
+
+int
+linux_shmat(struct thread *td, struct linux_shmat_args *args)
+{
+ struct shmat_args /* {
+ int shmid;
+ void *shmaddr;
+ int shmflg;
+ } */ bsd_args;
+
+ bsd_args.shmid = args->shmid;
+ bsd_args.shmaddr = PTRIN(args->shmaddr);
+ bsd_args.shmflg = args->shmflg;
+ return (sys_shmat(td, &bsd_args));
+}
+
+int
+linux_shmdt(struct thread *td, struct linux_shmdt_args *args)
+{
+ struct shmdt_args /* {
+ void *shmaddr;
+ } */ bsd_args;
+
+ bsd_args.shmaddr = PTRIN(args->shmaddr);
+ return (sys_shmdt(td, &bsd_args));
+}
+
+int
+linux_shmget(struct thread *td, struct linux_shmget_args *args)
+{
+ struct shmget_args /* {
+ key_t key;
+ int size;
+ int shmflg;
+ } */ bsd_args;
+
+ bsd_args.key = args->key;
+ bsd_args.size = args->size;
+ bsd_args.shmflg = args->shmflg;
+ return (sys_shmget(td, &bsd_args));
+}
+
+int
+linux_shmctl(struct thread *td, struct linux_shmctl_args *args)
+{
+ struct l_shmid64_ds linux_shmid64;
+ struct l_shminfo64 linux_shminfo64;
+ struct l_shm_info linux_shm_info;
+ struct shmid_ds bsd_shmid;
+ int error;
+
+ memset(&linux_shm_info, 0, sizeof(linux_shm_info));
+ memset(&linux_shmid64, 0, sizeof(linux_shmid64));
+ memset(&linux_shminfo64, 0, sizeof(linux_shminfo64));
+
+ switch (args->cmd & ~LINUX_IPC_64) {
+ case LINUX_IPC_INFO: {
+ struct shminfo bsd_shminfo;
+
+ /* Perform shmctl wanting removed segments lookup */
+ error = kern_shmctl(td, args->shmid, IPC_INFO,
+ (void *)&bsd_shminfo, NULL);
+ if (error != 0)
+ return (error);
+
+ bsd_to_linux_shminfo(&bsd_shminfo, &linux_shminfo64);
+
+ return (linux_shminfo_pushdown(args->cmd & LINUX_IPC_64,
+ &linux_shminfo64, PTRIN(args->buf)));
+ }
+
+ case LINUX_SHM_INFO: {
+ struct shm_info bsd_shm_info;
+
+ /* Perform shmctl wanting removed segments lookup */
+ error = kern_shmctl(td, args->shmid, SHM_INFO,
+ (void *)&bsd_shm_info, NULL);
+ if (error != 0)
+ return (error);
+
+ bsd_to_linux_shm_info(&bsd_shm_info, &linux_shm_info);
+
+ return (copyout(&linux_shm_info, PTRIN(args->buf),
+ sizeof(struct l_shm_info)));
+ }
+
+ case LINUX_IPC_STAT:
+ /* Perform shmctl wanting removed segments lookup */
+ error = kern_shmctl(td, args->shmid, IPC_STAT,
+ (void *)&bsd_shmid, NULL);
+ if (error != 0)
+ return (error);
+
+ bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid64);
+
+ return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64,
+ &linux_shmid64, PTRIN(args->buf)));
+
+ case LINUX_SHM_STAT:
+ /* Perform shmctl wanting removed segments lookup */
+ error = kern_shmctl(td, args->shmid, IPC_STAT,
+ (void *)&bsd_shmid, NULL);
+ if (error != 0)
+ return (error);
+
+ bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid64);
+
+ return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64,
+ &linux_shmid64, PTRIN(args->buf)));
+
+ case LINUX_IPC_SET:
+ error = linux_shmid_pullup(args->cmd & LINUX_IPC_64,
+ &linux_shmid64, PTRIN(args->buf));
+ if (error != 0)
+ return (error);
+
+ linux_to_bsd_shmid_ds(&linux_shmid64, &bsd_shmid);
+
+ /* Perform shmctl wanting removed segments lookup */
+ return (kern_shmctl(td, args->shmid, IPC_SET,
+ (void *)&bsd_shmid, NULL));
+
+ case LINUX_IPC_RMID: {
+ void *buf;
+
+ if (args->buf == 0)
+ buf = NULL;
+ else {
+ error = linux_shmid_pullup(args->cmd & LINUX_IPC_64,
+ &linux_shmid64, PTRIN(args->buf));
+ if (error != 0)
+ return (error);
+ linux_to_bsd_shmid_ds(&linux_shmid64, &bsd_shmid);
+ buf = (void *)&bsd_shmid;
+ }
+ return (kern_shmctl(td, args->shmid, IPC_RMID, buf, NULL));
+ }
+
+ case LINUX_SHM_LOCK:
+ /* FALLTHROUGH */
+ case LINUX_SHM_UNLOCK:
+ /* FALLTHROUGH */
+ default:
+ linux_msg(td, "ipc type %d not implemented",
+ args->cmd & ~LINUX_IPC_64);
+ return (EINVAL);
+ }
+}
+
+MODULE_DEPEND(linux, sysvmsg, 1, 1, 1);
+MODULE_DEPEND(linux, sysvsem, 1, 1, 1);
+MODULE_DEPEND(linux, sysvshm, 1, 1, 1);
diff --git a/sys/compat/linux/linux_ipc.h b/sys/compat/linux/linux_ipc.h
new file mode 100644
index 000000000000..b1bd3fffa4d6
--- /dev/null
+++ b/sys/compat/linux/linux_ipc.h
@@ -0,0 +1,97 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2000 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_IPC_H_
+#define _LINUX_IPC_H_
+
+/*
+ * SystemV IPC defines
+ */
+#define LINUX_SEMOP 1
+#define LINUX_SEMGET 2
+#define LINUX_SEMCTL 3
+#define LINUX_MSGSND 11
+#define LINUX_MSGRCV 12
+#define LINUX_MSGGET 13
+#define LINUX_MSGCTL 14
+#define LINUX_SHMAT 21
+#define LINUX_SHMDT 22
+#define LINUX_SHMGET 23
+#define LINUX_SHMCTL 24
+
+#define LINUX_IPC_RMID 0
+#define LINUX_IPC_SET 1
+#define LINUX_IPC_STAT 2
+#define LINUX_IPC_INFO 3
+
+#define LINUX_MSG_INFO 12
+
+#define LINUX_SHM_LOCK 11
+#define LINUX_SHM_UNLOCK 12
+#define LINUX_SHM_STAT 13
+#define LINUX_SHM_INFO 14
+
+#define LINUX_SHM_RDONLY 0x1000
+#define LINUX_SHM_RND 0x2000
+#define LINUX_SHM_REMAP 0x4000
+
+/* semctl commands */
+#define LINUX_GETPID 11
+#define LINUX_GETVAL 12
+#define LINUX_GETALL 13
+#define LINUX_GETNCNT 14
+#define LINUX_GETZCNT 15
+#define LINUX_SETVAL 16
+#define LINUX_SETALL 17
+#define LINUX_SEM_STAT 18
+#define LINUX_SEM_INFO 19
+
+/*
+ * Version flags for semctl, msgctl, and shmctl commands
+ * These are passed as bitflags or-ed with the actual command
+ */
+#define LINUX_IPC_OLD 0 /* Old version (no 32-bit UID support on many
+ architectures) */
+#define LINUX_IPC_64 0x0100 /* New version (support 32-bit UIDs, bigger
+ message sizes, etc. */
+
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+
+struct linux_semop_args
+{
+ l_int semid;
+ struct l_sembuf *tsops;
+ l_uint nsops;
+};
+
+int linux_semop(struct thread *, struct linux_semop_args *);
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+
+#endif /* _LINUX_IPC_H_ */
diff --git a/sys/compat/linux/linux_ipc64.h b/sys/compat/linux/linux_ipc64.h
new file mode 100644
index 000000000000..f0aa5618dff1
--- /dev/null
+++ b/sys/compat/linux/linux_ipc64.h
@@ -0,0 +1,158 @@
+/*-
+ * Copyright (c) 2002 Maxim Sobolev <sobomax@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_IPC64_H_
+#define _LINUX_IPC64_H_
+
+/*
+ * The generic ipc64_perm structure.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 32-bit mode_t on architectures that only had 16 bit
+ * - 32-bit seq
+ * - 2 miscellaneous 32-bit values
+ */
+struct l_ipc64_perm
+{
+ l_key_t key;
+ l_uid_t uid;
+ l_gid_t gid;
+ l_uid_t cuid;
+ l_gid_t cgid;
+ l_mode_t mode;
+ /* pad if mode_t is ushort: */
+ unsigned char __pad1[sizeof(l_int) - sizeof(l_mode_t)];
+ l_ushort seq;
+ l_ushort __pad2;
+ l_ulong __unused1;
+ l_ulong __unused2;
+};
+
+/*
+ * The generic msqid64_ds structure fro x86 architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct l_msqid64_ds {
+ struct l_ipc64_perm msg_perm;
+ l_time_t msg_stime; /* last msgsnd time */
+#if !defined(__LP64__) || defined(COMPAT_LINUX32)
+ l_ulong __unused1;
+#endif
+ l_time_t msg_rtime; /* last msgrcv time */
+#if !defined(__LP64__) || defined(COMPAT_LINUX32)
+ l_ulong __unused2;
+#endif
+ l_time_t msg_ctime; /* last change time */
+#if !defined(__LP64__) || defined(COMPAT_LINUX32)
+ l_ulong __unused3;
+#endif
+ l_ulong msg_cbytes; /* current number of bytes on queue */
+ l_ulong msg_qnum; /* number of messages in queue */
+ l_ulong msg_qbytes; /* max number of bytes on queue */
+ l_pid_t msg_lspid; /* pid of last msgsnd */
+ l_pid_t msg_lrpid; /* last receive pid */
+ l_ulong __unused4;
+ l_ulong __unused5;
+};
+
+/*
+ * The generic semid64_ds structure for x86 architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct l_semid64_ds {
+ struct l_ipc64_perm sem_perm; /* permissions */
+ l_time_t sem_otime; /* last semop time */
+ l_ulong __unused1;
+ l_time_t sem_ctime; /* last change time */
+ l_ulong __unused2;
+ l_ulong sem_nsems; /* no. of semaphores in array */
+ l_ulong __unused3;
+ l_ulong __unused4;
+};
+
+/*
+ * The generic shmid64_ds structure for x86 architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct l_shmid64_ds {
+ struct l_ipc64_perm shm_perm; /* operation perms */
+ l_size_t shm_segsz; /* size of segment (bytes) */
+ l_time_t shm_atime; /* last attach time */
+#if !defined(__LP64__) || defined(COMPAT_LINUX32)
+ l_ulong __unused1;
+#endif
+ l_time_t shm_dtime; /* last detach time */
+#if !defined(__LP64__) || defined(COMPAT_LINUX32)
+ l_ulong __unused2;
+#endif
+ l_time_t shm_ctime; /* last change time */
+#if !defined(__LP64__) || defined(COMPAT_LINUX32)
+ l_ulong __unused3;
+#endif
+ l_pid_t shm_cpid; /* pid of creator */
+ l_pid_t shm_lpid; /* pid of last operator */
+ l_ulong shm_nattch; /* no. of current attaches */
+ l_ulong __unused4;
+ l_ulong __unused5;
+};
+
+struct l_shminfo64 {
+ l_ulong shmmax;
+ l_ulong shmmin;
+ l_ulong shmmni;
+ l_ulong shmseg;
+ l_ulong shmall;
+ l_ulong __unused1;
+ l_ulong __unused2;
+ l_ulong __unused3;
+ l_ulong __unused4;
+};
+
+#endif /* !LINUX_IPC64_H_ */
diff --git a/sys/compat/linux/linux_mib.c b/sys/compat/linux/linux_mib.c
new file mode 100644
index 000000000000..cc4207f74a39
--- /dev/null
+++ b/sys/compat/linux/linux_mib.c
@@ -0,0 +1,579 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1999 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/sdt.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/jail.h>
+#include <sys/lock.h>
+#include <sys/sx.h>
+
+#include <compat/linux/linux_mib.h>
+#include <compat/linux/linux_misc.h>
+
+struct linux_prison {
+ char pr_osname[LINUX_MAX_UTSNAME];
+ char pr_osrelease[LINUX_MAX_UTSNAME];
+ int pr_oss_version;
+ int pr_osrel;
+};
+
+static struct linux_prison lprison0 = {
+ .pr_osname = "Linux",
+ .pr_osrelease = LINUX_VERSION_STR,
+ .pr_oss_version = 0x030600,
+ .pr_osrel = LINUX_VERSION_CODE
+};
+
+static unsigned linux_osd_jail_slot;
+
+SYSCTL_NODE(_compat, OID_AUTO, linux, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
+ "Linux mode");
+
+int linux_debug = 3;
+SYSCTL_INT(_compat_linux, OID_AUTO, debug, CTLFLAG_RWTUN,
+ &linux_debug, 0, "Log warnings from linux(4); or 0 to disable");
+
+int linux_default_openfiles = 1024;
+SYSCTL_INT(_compat_linux, OID_AUTO, default_openfiles, CTLFLAG_RWTUN,
+ &linux_default_openfiles, 0,
+ "Default soft openfiles resource limit, or -1 for unlimited");
+
+int linux_default_stacksize = 8 * 1024 * 1024;
+SYSCTL_INT(_compat_linux, OID_AUTO, default_stacksize, CTLFLAG_RWTUN,
+ &linux_default_stacksize, 0,
+ "Default soft stack size resource limit, or -1 for unlimited");
+
+int linux_dummy_rlimits = 0;
+SYSCTL_INT(_compat_linux, OID_AUTO, dummy_rlimits, CTLFLAG_RWTUN,
+ &linux_dummy_rlimits, 0,
+ "Return dummy values for unsupported Linux-specific rlimits");
+
+int linux_ignore_ip_recverr = 1;
+SYSCTL_INT(_compat_linux, OID_AUTO, ignore_ip_recverr, CTLFLAG_RWTUN,
+ &linux_ignore_ip_recverr, 0, "Ignore enabling IP_RECVERR");
+
+int linux_preserve_vstatus = 0;
+SYSCTL_INT(_compat_linux, OID_AUTO, preserve_vstatus, CTLFLAG_RWTUN,
+ &linux_preserve_vstatus, 0, "Preserve VSTATUS termios(4) flag");
+
+bool linux_map_sched_prio = true;
+SYSCTL_BOOL(_compat_linux, OID_AUTO, map_sched_prio, CTLFLAG_RDTUN,
+ &linux_map_sched_prio, 0, "Map scheduler priorities to Linux priorities "
+ "(not POSIX compliant)");
+
+int linux_use_emul_path = 1;
+SYSCTL_INT(_compat_linux, OID_AUTO, use_emul_path, CTLFLAG_RWTUN,
+ &linux_use_emul_path, 0, "Use linux.compat.emul_path");
+
+static int linux_set_osname(struct thread *td, char *osname);
+static int linux_set_osrelease(struct thread *td, char *osrelease);
+static int linux_set_oss_version(struct thread *td, int oss_version);
+
+static int
+linux_sysctl_osname(SYSCTL_HANDLER_ARGS)
+{
+ char osname[LINUX_MAX_UTSNAME];
+ int error;
+
+ linux_get_osname(req->td, osname);
+ error = sysctl_handle_string(oidp, osname, LINUX_MAX_UTSNAME, req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+ error = linux_set_osname(req->td, osname);
+
+ return (error);
+}
+
+SYSCTL_PROC(_compat_linux, OID_AUTO, osname,
+ CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE,
+ 0, 0, linux_sysctl_osname, "A",
+ "Linux kernel OS name");
+
+static int
+linux_sysctl_osrelease(SYSCTL_HANDLER_ARGS)
+{
+ char osrelease[LINUX_MAX_UTSNAME];
+ int error;
+
+ linux_get_osrelease(req->td, osrelease);
+ error = sysctl_handle_string(oidp, osrelease, LINUX_MAX_UTSNAME, req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+ error = linux_set_osrelease(req->td, osrelease);
+
+ return (error);
+}
+
+SYSCTL_PROC(_compat_linux, OID_AUTO, osrelease,
+ CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE,
+ 0, 0, linux_sysctl_osrelease, "A",
+ "Linux kernel OS release");
+
+static int
+linux_sysctl_oss_version(SYSCTL_HANDLER_ARGS)
+{
+ int oss_version;
+ int error;
+
+ oss_version = linux_get_oss_version(req->td);
+ error = sysctl_handle_int(oidp, &oss_version, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+ error = linux_set_oss_version(req->td, oss_version);
+
+ return (error);
+}
+
+SYSCTL_PROC(_compat_linux, OID_AUTO, oss_version,
+ CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE,
+ 0, 0, linux_sysctl_oss_version, "I",
+ "Linux OSS version");
+
+/*
+ * Map the osrelease into integer
+ */
+static int
+linux_map_osrel(char *osrelease, int *osrel)
+{
+ char *sep, *eosrelease;
+ int len, v0, v1, v2, v;
+
+ len = strlen(osrelease);
+ eosrelease = osrelease + len;
+ v0 = strtol(osrelease, &sep, 10);
+ if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.')
+ return (EINVAL);
+ osrelease = sep + 1;
+ v1 = strtol(osrelease, &sep, 10);
+ if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.')
+ return (EINVAL);
+ osrelease = sep + 1;
+ v2 = strtol(osrelease, &sep, 10);
+ if (osrelease == sep ||
+ (sep != eosrelease && (sep + 1 >= eosrelease || *sep != '-')))
+ return (EINVAL);
+
+ v = LINUX_KERNVER(v0, v1, v2);
+ if (v < LINUX_KERNVER(1, 0, 0))
+ return (EINVAL);
+
+ if (osrel != NULL)
+ *osrel = v;
+
+ return (0);
+}
+
+/*
+ * Find a prison with Linux info.
+ * Return the Linux info and the (locked) prison.
+ */
+static struct linux_prison *
+linux_find_prison(struct prison *spr, struct prison **prp)
+{
+ struct prison *pr;
+ struct linux_prison *lpr;
+
+ for (pr = spr;; pr = pr->pr_parent) {
+ mtx_lock(&pr->pr_mtx);
+ lpr = (pr == &prison0)
+ ? &lprison0
+ : osd_jail_get(pr, linux_osd_jail_slot);
+ if (lpr != NULL)
+ break;
+ mtx_unlock(&pr->pr_mtx);
+ }
+ *prp = pr;
+
+ return (lpr);
+}
+
+/*
+ * Ensure a prison has its own Linux info. If lprp is non-null, point it to
+ * the Linux info and lock the prison.
+ */
+static void
+linux_alloc_prison(struct prison *pr, struct linux_prison **lprp)
+{
+ struct prison *ppr;
+ struct linux_prison *lpr, *nlpr;
+ void **rsv;
+
+ /* If this prison already has Linux info, return that. */
+ lpr = linux_find_prison(pr, &ppr);
+ if (ppr == pr)
+ goto done;
+ /*
+ * Allocate a new info record. Then check again, in case something
+ * changed during the allocation.
+ */
+ mtx_unlock(&ppr->pr_mtx);
+ nlpr = malloc(sizeof(struct linux_prison), M_PRISON, M_WAITOK);
+ rsv = osd_reserve(linux_osd_jail_slot);
+ lpr = linux_find_prison(pr, &ppr);
+ if (ppr == pr) {
+ free(nlpr, M_PRISON);
+ osd_free_reserved(rsv);
+ goto done;
+ }
+ /* Inherit the initial values from the ancestor. */
+ mtx_lock(&pr->pr_mtx);
+ (void)osd_jail_set_reserved(pr, linux_osd_jail_slot, rsv, nlpr);
+ bcopy(lpr, nlpr, sizeof(*lpr));
+ lpr = nlpr;
+ mtx_unlock(&ppr->pr_mtx);
+ done:
+ if (lprp != NULL)
+ *lprp = lpr;
+ else
+ mtx_unlock(&pr->pr_mtx);
+}
+
+/*
+ * Jail OSD methods for Linux prison data.
+ */
+static int
+linux_prison_create(void *obj, void *data)
+{
+ struct prison *pr = obj;
+ struct vfsoptlist *opts = data;
+ int jsys;
+
+ if (vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)) == 0 &&
+ jsys == JAIL_SYS_INHERIT)
+ return (0);
+ /*
+ * Inherit a prison's initial values from its parent
+ * (different from JAIL_SYS_INHERIT which also inherits changes).
+ */
+ linux_alloc_prison(pr, NULL);
+ return (0);
+}
+
+static int
+linux_prison_check(void *obj __unused, void *data)
+{
+ struct vfsoptlist *opts = data;
+ char *osname, *osrelease;
+ int error, jsys, len, oss_version;
+
+ /* Check that the parameters are correct. */
+ error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys));
+ if (error != ENOENT) {
+ if (error != 0)
+ return (error);
+ if (jsys != JAIL_SYS_NEW && jsys != JAIL_SYS_INHERIT)
+ return (EINVAL);
+ }
+ error = vfs_getopt(opts, "linux.osname", (void **)&osname, &len);
+ if (error != ENOENT) {
+ if (error != 0)
+ return (error);
+ if (len == 0 || osname[len - 1] != '\0')
+ return (EINVAL);
+ if (len > LINUX_MAX_UTSNAME) {
+ vfs_opterror(opts, "linux.osname too long");
+ return (ENAMETOOLONG);
+ }
+ }
+ error = vfs_getopt(opts, "linux.osrelease", (void **)&osrelease, &len);
+ if (error != ENOENT) {
+ if (error != 0)
+ return (error);
+ if (len == 0 || osrelease[len - 1] != '\0')
+ return (EINVAL);
+ if (len > LINUX_MAX_UTSNAME) {
+ vfs_opterror(opts, "linux.osrelease too long");
+ return (ENAMETOOLONG);
+ }
+ error = linux_map_osrel(osrelease, NULL);
+ if (error != 0) {
+ vfs_opterror(opts, "linux.osrelease format error");
+ return (error);
+ }
+ }
+ error = vfs_copyopt(opts, "linux.oss_version", &oss_version,
+ sizeof(oss_version));
+
+ if (error == ENOENT)
+ error = 0;
+ return (error);
+}
+
+static int
+linux_prison_set(void *obj, void *data)
+{
+ struct linux_prison *lpr;
+ struct prison *pr = obj;
+ struct vfsoptlist *opts = data;
+ char *osname, *osrelease;
+ int error, gotversion, jsys, len, oss_version;
+
+ /* Set the parameters, which should be correct. */
+ error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys));
+ if (error == ENOENT)
+ jsys = -1;
+ error = vfs_getopt(opts, "linux.osname", (void **)&osname, &len);
+ if (error == ENOENT)
+ osname = NULL;
+ else
+ jsys = JAIL_SYS_NEW;
+ error = vfs_getopt(opts, "linux.osrelease", (void **)&osrelease, &len);
+ if (error == ENOENT)
+ osrelease = NULL;
+ else
+ jsys = JAIL_SYS_NEW;
+ error = vfs_copyopt(opts, "linux.oss_version", &oss_version,
+ sizeof(oss_version));
+ if (error == ENOENT)
+ gotversion = 0;
+ else {
+ gotversion = 1;
+ jsys = JAIL_SYS_NEW;
+ }
+ switch (jsys) {
+ case JAIL_SYS_INHERIT:
+ /* "linux=inherit": inherit the parent's Linux info. */
+ mtx_lock(&pr->pr_mtx);
+ osd_jail_del(pr, linux_osd_jail_slot);
+ mtx_unlock(&pr->pr_mtx);
+ break;
+ case JAIL_SYS_NEW:
+ /*
+ * "linux=new" or "linux.*":
+ * the prison gets its own Linux info.
+ */
+ linux_alloc_prison(pr, &lpr);
+ if (osrelease) {
+ (void)linux_map_osrel(osrelease, &lpr->pr_osrel);
+ strlcpy(lpr->pr_osrelease, osrelease,
+ LINUX_MAX_UTSNAME);
+ }
+ if (osname)
+ strlcpy(lpr->pr_osname, osname, LINUX_MAX_UTSNAME);
+ if (gotversion)
+ lpr->pr_oss_version = oss_version;
+ mtx_unlock(&pr->pr_mtx);
+ }
+
+ return (0);
+}
+
+SYSCTL_JAIL_PARAM_SYS_NODE(linux, CTLFLAG_RW, "Jail Linux parameters");
+SYSCTL_JAIL_PARAM_STRING(_linux, osname, CTLFLAG_RW, LINUX_MAX_UTSNAME,
+ "Jail Linux kernel OS name");
+SYSCTL_JAIL_PARAM_STRING(_linux, osrelease, CTLFLAG_RW, LINUX_MAX_UTSNAME,
+ "Jail Linux kernel OS release");
+SYSCTL_JAIL_PARAM(_linux, oss_version, CTLTYPE_INT | CTLFLAG_RW,
+ "I", "Jail Linux OSS version");
+
+static int
+linux_prison_get(void *obj, void *data)
+{
+ struct linux_prison *lpr;
+ struct prison *ppr;
+ struct prison *pr = obj;
+ struct vfsoptlist *opts = data;
+ int error, i;
+
+ static int version0;
+
+ /* See if this prison is the one with the Linux info. */
+ lpr = linux_find_prison(pr, &ppr);
+ i = (ppr == pr) ? JAIL_SYS_NEW : JAIL_SYS_INHERIT;
+ error = vfs_setopt(opts, "linux", &i, sizeof(i));
+ if (error != 0 && error != ENOENT)
+ goto done;
+ if (i) {
+ error = vfs_setopts(opts, "linux.osname", lpr->pr_osname);
+ if (error != 0 && error != ENOENT)
+ goto done;
+ error = vfs_setopts(opts, "linux.osrelease", lpr->pr_osrelease);
+ if (error != 0 && error != ENOENT)
+ goto done;
+ error = vfs_setopt(opts, "linux.oss_version",
+ &lpr->pr_oss_version, sizeof(lpr->pr_oss_version));
+ if (error != 0 && error != ENOENT)
+ goto done;
+ } else {
+ /*
+ * If this prison is inheriting its Linux info, report
+ * empty/zero parameters.
+ */
+ error = vfs_setopts(opts, "linux.osname", "");
+ if (error != 0 && error != ENOENT)
+ goto done;
+ error = vfs_setopts(opts, "linux.osrelease", "");
+ if (error != 0 && error != ENOENT)
+ goto done;
+ error = vfs_setopt(opts, "linux.oss_version", &version0,
+ sizeof(lpr->pr_oss_version));
+ if (error != 0 && error != ENOENT)
+ goto done;
+ }
+ error = 0;
+
+ done:
+ mtx_unlock(&ppr->pr_mtx);
+
+ return (error);
+}
+
+static void
+linux_prison_destructor(void *data)
+{
+
+ free(data, M_PRISON);
+}
+
+void
+linux_osd_jail_register(void)
+{
+ struct prison *pr;
+ osd_method_t methods[PR_MAXMETHOD] = {
+ [PR_METHOD_CREATE] = linux_prison_create,
+ [PR_METHOD_GET] = linux_prison_get,
+ [PR_METHOD_SET] = linux_prison_set,
+ [PR_METHOD_CHECK] = linux_prison_check
+ };
+
+ linux_osd_jail_slot =
+ osd_jail_register(linux_prison_destructor, methods);
+ /* Copy the system Linux info to any current prisons. */
+ sx_slock(&allprison_lock);
+ TAILQ_FOREACH(pr, &allprison, pr_list)
+ linux_alloc_prison(pr, NULL);
+ sx_sunlock(&allprison_lock);
+}
+
+void
+linux_osd_jail_deregister(void)
+{
+
+ osd_jail_deregister(linux_osd_jail_slot);
+}
+
+void
+linux_get_osname(struct thread *td, char *dst)
+{
+ struct prison *pr;
+ struct linux_prison *lpr;
+
+ lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
+ bcopy(lpr->pr_osname, dst, LINUX_MAX_UTSNAME);
+ mtx_unlock(&pr->pr_mtx);
+}
+
+static int
+linux_set_osname(struct thread *td, char *osname)
+{
+ struct prison *pr;
+ struct linux_prison *lpr;
+
+ lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
+ strlcpy(lpr->pr_osname, osname, LINUX_MAX_UTSNAME);
+ mtx_unlock(&pr->pr_mtx);
+
+ return (0);
+}
+
+void
+linux_get_osrelease(struct thread *td, char *dst)
+{
+ struct prison *pr;
+ struct linux_prison *lpr;
+
+ lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
+ bcopy(lpr->pr_osrelease, dst, LINUX_MAX_UTSNAME);
+ mtx_unlock(&pr->pr_mtx);
+}
+
+int
+linux_kernver(struct thread *td)
+{
+ struct prison *pr;
+ struct linux_prison *lpr;
+ int osrel;
+
+ lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
+ osrel = lpr->pr_osrel;
+ mtx_unlock(&pr->pr_mtx);
+
+ return (osrel);
+}
+
+static int
+linux_set_osrelease(struct thread *td, char *osrelease)
+{
+ struct prison *pr;
+ struct linux_prison *lpr;
+ int error;
+
+ lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
+ error = linux_map_osrel(osrelease, &lpr->pr_osrel);
+ if (error == 0)
+ strlcpy(lpr->pr_osrelease, osrelease, LINUX_MAX_UTSNAME);
+ mtx_unlock(&pr->pr_mtx);
+
+ return (error);
+}
+
+int
+linux_get_oss_version(struct thread *td)
+{
+ struct prison *pr;
+ struct linux_prison *lpr;
+ int version;
+
+ lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
+ version = lpr->pr_oss_version;
+ mtx_unlock(&pr->pr_mtx);
+
+ return (version);
+}
+
+static int
+linux_set_oss_version(struct thread *td, int oss_version)
+{
+ struct prison *pr;
+ struct linux_prison *lpr;
+
+ lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
+ lpr->pr_oss_version = oss_version;
+ mtx_unlock(&pr->pr_mtx);
+
+ return (0);
+}
diff --git a/sys/compat/linux/linux_mib.h b/sys/compat/linux/linux_mib.h
new file mode 100644
index 000000000000..0a1baec39826
--- /dev/null
+++ b/sys/compat/linux/linux_mib.h
@@ -0,0 +1,73 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1999 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_MIB_H_
+#define _LINUX_MIB_H_
+
+#ifdef SYSCTL_DECL
+SYSCTL_DECL(_compat_linux);
+#endif
+
+void linux_osd_jail_register(void);
+void linux_osd_jail_deregister(void);
+
+void linux_get_osname(struct thread *td, char *dst);
+
+void linux_get_osrelease(struct thread *td, char *dst);
+
+int linux_get_oss_version(struct thread *td);
+
+int linux_kernver(struct thread *td);
+
+#define LINUX_KVERSION 3
+#define LINUX_KPATCHLEVEL 17
+#define LINUX_KSUBLEVEL 0
+
+#define LINUX_KERNVER(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+#define LINUX_VERSION_CODE LINUX_KERNVER(LINUX_KVERSION, \
+ LINUX_KPATCHLEVEL, LINUX_KSUBLEVEL)
+#define LINUX_KERNVERSTR(x) #x
+#define LINUX_XKERNVERSTR(x) LINUX_KERNVERSTR(x)
+#define LINUX_VERSION_STR LINUX_XKERNVERSTR(LINUX_KVERSION.LINUX_KPATCHLEVEL.LINUX_KSUBLEVEL)
+
+#define LINUX_KERNVER_2004000 LINUX_KERNVER(2,4,0)
+#define LINUX_KERNVER_2006000 LINUX_KERNVER(2,6,0)
+
+#define linux_use26(t) (linux_kernver(t) >= LINUX_KERNVER_2006000)
+
+extern int linux_debug;
+extern int linux_default_openfiles;
+extern int linux_default_stacksize;
+extern int linux_dummy_rlimits;
+extern int linux_ignore_ip_recverr;
+extern int linux_preserve_vstatus;
+extern bool linux_map_sched_prio;
+
+#endif /* _LINUX_MIB_H_ */
diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c
new file mode 100644
index 000000000000..fc846df6689f
--- /dev/null
+++ b/sys/compat/linux/linux_misc.c
@@ -0,0 +1,2643 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2002 Doug Rabson
+ * Copyright (c) 1994-1995 Søren Schmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_compat.h"
+
+#include <sys/param.h>
+#include <sys/blist.h>
+#include <sys/fcntl.h>
+#if defined(__i386__)
+#include <sys/imgact_aout.h>
+#endif
+#include <sys/jail.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/msgbuf.h>
+#include <sys/mutex.h>
+#include <sys/namei.h>
+#include <sys/priv.h>
+#include <sys/proc.h>
+#include <sys/procctl.h>
+#include <sys/reboot.h>
+#include <sys/racct.h>
+#include <sys/random.h>
+#include <sys/resourcevar.h>
+#include <sys/sched.h>
+#include <sys/sdt.h>
+#include <sys/signalvar.h>
+#include <sys/stat.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysctl.h>
+#include <sys/sysproto.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/vmmeter.h>
+#include <sys/vnode.h>
+#include <sys/wait.h>
+#include <sys/cpuset.h>
+#include <sys/uio.h>
+
+#include <security/mac/mac_framework.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_map.h>
+#include <vm/vm_extern.h>
+#include <vm/swap_pager.h>
+
+#ifdef COMPAT_LINUX32
+#include <machine/../linux32/linux.h>
+#include <machine/../linux32/linux32_proto.h>
+#else
+#include <machine/../linux/linux.h>
+#include <machine/../linux/linux_proto.h>
+#endif
+
+#include <compat/linux/linux_dtrace.h>
+#include <compat/linux/linux_file.h>
+#include <compat/linux/linux_mib.h>
+#include <compat/linux/linux_signal.h>
+#include <compat/linux/linux_timer.h>
+#include <compat/linux/linux_util.h>
+#include <compat/linux/linux_sysproto.h>
+#include <compat/linux/linux_emul.h>
+#include <compat/linux/linux_misc.h>
+
+int stclohz; /* Statistics clock frequency */
+
+static unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] = {
+ RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK,
+ RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE,
+ RLIMIT_MEMLOCK, RLIMIT_AS
+};
+
+struct l_sysinfo {
+ l_long uptime; /* Seconds since boot */
+ l_ulong loads[3]; /* 1, 5, and 15 minute load averages */
+#define LINUX_SYSINFO_LOADS_SCALE 65536
+ l_ulong totalram; /* Total usable main memory size */
+ l_ulong freeram; /* Available memory size */
+ l_ulong sharedram; /* Amount of shared memory */
+ l_ulong bufferram; /* Memory used by buffers */
+ l_ulong totalswap; /* Total swap space size */
+ l_ulong freeswap; /* swap space still available */
+ l_ushort procs; /* Number of current processes */
+ l_ushort pads;
+ l_ulong totalhigh;
+ l_ulong freehigh;
+ l_uint mem_unit;
+ char _f[20-2*sizeof(l_long)-sizeof(l_int)]; /* padding */
+};
+
+struct l_pselect6arg {
+ l_uintptr_t ss;
+ l_size_t ss_len;
+};
+
+static int linux_utimensat_nsec_valid(l_long);
+
+int
+linux_sysinfo(struct thread *td, struct linux_sysinfo_args *args)
+{
+ struct l_sysinfo sysinfo;
+ int i, j;
+ struct timespec ts;
+
+ bzero(&sysinfo, sizeof(sysinfo));
+ getnanouptime(&ts);
+ if (ts.tv_nsec != 0)
+ ts.tv_sec++;
+ sysinfo.uptime = ts.tv_sec;
+
+ /* Use the information from the mib to get our load averages */
+ for (i = 0; i < 3; i++)
+ sysinfo.loads[i] = averunnable.ldavg[i] *
+ LINUX_SYSINFO_LOADS_SCALE / averunnable.fscale;
+
+ sysinfo.totalram = physmem * PAGE_SIZE;
+ sysinfo.freeram = (u_long)vm_free_count() * PAGE_SIZE;
+
+ /*
+ * sharedram counts pages allocated to named, swap-backed objects such
+ * as shared memory segments and tmpfs files. There is no cheap way to
+ * compute this, so just leave the field unpopulated. Linux itself only
+ * started setting this field in the 3.x timeframe.
+ */
+ sysinfo.sharedram = 0;
+ sysinfo.bufferram = 0;
+
+ swap_pager_status(&i, &j);
+ sysinfo.totalswap = i * PAGE_SIZE;
+ sysinfo.freeswap = (i - j) * PAGE_SIZE;
+
+ sysinfo.procs = nprocs;
+
+ /*
+ * Platforms supported by the emulation layer do not have a notion of
+ * high memory.
+ */
+ sysinfo.totalhigh = 0;
+ sysinfo.freehigh = 0;
+
+ sysinfo.mem_unit = 1;
+
+ return (copyout(&sysinfo, args->info, sizeof(sysinfo)));
+}
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_alarm(struct thread *td, struct linux_alarm_args *args)
+{
+ struct itimerval it, old_it;
+ u_int secs;
+ int error;
+
+ secs = args->secs;
+ /*
+ * Linux alarm() is always successful. Limit secs to INT32_MAX / 2
+ * to match kern_setitimer()'s limit to avoid error from it.
+ *
+ * XXX. Linux limit secs to INT_MAX on 32 and does not limit on 64-bit
+ * platforms.
+ */
+ if (secs > INT32_MAX / 2)
+ secs = INT32_MAX / 2;
+
+ it.it_value.tv_sec = secs;
+ it.it_value.tv_usec = 0;
+ timevalclear(&it.it_interval);
+ error = kern_setitimer(td, ITIMER_REAL, &it, &old_it);
+ KASSERT(error == 0, ("kern_setitimer returns %d", error));
+
+ if ((old_it.it_value.tv_sec == 0 && old_it.it_value.tv_usec > 0) ||
+ old_it.it_value.tv_usec >= 500000)
+ old_it.it_value.tv_sec++;
+ td->td_retval[0] = old_it.it_value.tv_sec;
+ return (0);
+}
+#endif
+
+int
+linux_brk(struct thread *td, struct linux_brk_args *args)
+{
+ struct vmspace *vm = td->td_proc->p_vmspace;
+ uintptr_t new, old;
+
+ old = (uintptr_t)vm->vm_daddr + ctob(vm->vm_dsize);
+ new = (uintptr_t)args->dsend;
+ if ((caddr_t)new > vm->vm_daddr && !kern_break(td, &new))
+ td->td_retval[0] = (register_t)new;
+ else
+ td->td_retval[0] = (register_t)old;
+
+ return (0);
+}
+
+#if defined(__i386__)
+/* XXX: what about amd64/linux32? */
+
+int
+linux_uselib(struct thread *td, struct linux_uselib_args *args)
+{
+ struct nameidata ni;
+ struct vnode *vp;
+ struct exec *a_out;
+ vm_map_t map;
+ vm_map_entry_t entry;
+ struct vattr attr;
+ vm_offset_t vmaddr;
+ unsigned long file_offset;
+ unsigned long bss_size;
+ char *library;
+ ssize_t aresid;
+ int error;
+ bool locked, opened, textset;
+
+ a_out = NULL;
+ vp = NULL;
+ locked = false;
+ textset = false;
+ opened = false;
+
+ if (!LUSECONVPATH(td)) {
+ NDINIT(&ni, LOOKUP, ISOPEN | FOLLOW | LOCKLEAF | AUDITVNODE1,
+ UIO_USERSPACE, args->library, td);
+ error = namei(&ni);
+ } else {
+ LCONVPATHEXIST(td, args->library, &library);
+ NDINIT(&ni, LOOKUP, ISOPEN | FOLLOW | LOCKLEAF | AUDITVNODE1,
+ UIO_SYSSPACE, library, td);
+ error = namei(&ni);
+ LFREEPATH(library);
+ }
+ if (error)
+ goto cleanup;
+
+ vp = ni.ni_vp;
+ NDFREE(&ni, NDF_ONLY_PNBUF);
+
+ /*
+ * From here on down, we have a locked vnode that must be unlocked.
+ * XXX: The code below largely duplicates exec_check_permissions().
+ */
+ locked = true;
+
+ /* Executable? */
+ error = VOP_GETATTR(vp, &attr, td->td_ucred);
+ if (error)
+ goto cleanup;
+
+ if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
+ ((attr.va_mode & 0111) == 0) || (attr.va_type != VREG)) {
+ /* EACCESS is what exec(2) returns. */
+ error = ENOEXEC;
+ goto cleanup;
+ }
+
+ /* Sensible size? */
+ if (attr.va_size == 0) {
+ error = ENOEXEC;
+ goto cleanup;
+ }
+
+ /* Can we access it? */
+ error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td);
+ if (error)
+ goto cleanup;
+
+ /*
+ * XXX: This should use vn_open() so that it is properly authorized,
+ * and to reduce code redundancy all over the place here.
+ * XXX: Not really, it duplicates far more of exec_check_permissions()
+ * than vn_open().
+ */
+#ifdef MAC
+ error = mac_vnode_check_open(td->td_ucred, vp, VREAD);
+ if (error)
+ goto cleanup;
+#endif
+ error = VOP_OPEN(vp, FREAD, td->td_ucred, td, NULL);
+ if (error)
+ goto cleanup;
+ opened = true;
+
+ /* Pull in executable header into exec_map */
+ error = vm_mmap(exec_map, (vm_offset_t *)&a_out, PAGE_SIZE,
+ VM_PROT_READ, VM_PROT_READ, 0, OBJT_VNODE, vp, 0);
+ if (error)
+ goto cleanup;
+
+ /* Is it a Linux binary ? */
+ if (((a_out->a_magic >> 16) & 0xff) != 0x64) {
+ error = ENOEXEC;
+ goto cleanup;
+ }
+
+ /*
+ * While we are here, we should REALLY do some more checks
+ */
+
+ /* Set file/virtual offset based on a.out variant. */
+ switch ((int)(a_out->a_magic & 0xffff)) {
+ case 0413: /* ZMAGIC */
+ file_offset = 1024;
+ break;
+ case 0314: /* QMAGIC */
+ file_offset = 0;
+ break;
+ default:
+ error = ENOEXEC;
+ goto cleanup;
+ }
+
+ bss_size = round_page(a_out->a_bss);
+
+ /* Check various fields in header for validity/bounds. */
+ if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) {
+ error = ENOEXEC;
+ goto cleanup;
+ }
+
+ /* text + data can't exceed file size */
+ if (a_out->a_data + a_out->a_text > attr.va_size) {
+ error = EFAULT;
+ goto cleanup;
+ }
+
+ /*
+ * text/data/bss must not exceed limits
+ * XXX - this is not complete. it should check current usage PLUS
+ * the resources needed by this library.
+ */
+ PROC_LOCK(td->td_proc);
+ if (a_out->a_text > maxtsiz ||
+ a_out->a_data + bss_size > lim_cur_proc(td->td_proc, RLIMIT_DATA) ||
+ racct_set(td->td_proc, RACCT_DATA, a_out->a_data +
+ bss_size) != 0) {
+ PROC_UNLOCK(td->td_proc);
+ error = ENOMEM;
+ goto cleanup;
+ }
+ PROC_UNLOCK(td->td_proc);
+
+ /*
+ * Prevent more writers.
+ */
+ error = VOP_SET_TEXT(vp);
+ if (error != 0)
+ goto cleanup;
+ textset = true;
+
+ /*
+ * Lock no longer needed
+ */
+ locked = false;
+ VOP_UNLOCK(vp);
+
+ /*
+ * Check if file_offset page aligned. Currently we cannot handle
+ * misalinged file offsets, and so we read in the entire image
+ * (what a waste).
+ */
+ if (file_offset & PAGE_MASK) {
+ /* Map text+data read/write/execute */
+
+ /* a_entry is the load address and is page aligned */
+ vmaddr = trunc_page(a_out->a_entry);
+
+ /* get anon user mapping, read+write+execute */
+ error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0,
+ &vmaddr, a_out->a_text + a_out->a_data, 0, VMFS_NO_SPACE,
+ VM_PROT_ALL, VM_PROT_ALL, 0);
+ if (error)
+ goto cleanup;
+
+ error = vn_rdwr(UIO_READ, vp, (void *)vmaddr, file_offset,
+ a_out->a_text + a_out->a_data, UIO_USERSPACE, 0,
+ td->td_ucred, NOCRED, &aresid, td);
+ if (error != 0)
+ goto cleanup;
+ if (aresid != 0) {
+ error = ENOEXEC;
+ goto cleanup;
+ }
+ } else {
+ /*
+ * for QMAGIC, a_entry is 20 bytes beyond the load address
+ * to skip the executable header
+ */
+ vmaddr = trunc_page(a_out->a_entry);
+
+ /*
+ * Map it all into the process's space as a single
+ * copy-on-write "data" segment.
+ */
+ map = &td->td_proc->p_vmspace->vm_map;
+ error = vm_mmap(map, &vmaddr,
+ a_out->a_text + a_out->a_data, VM_PROT_ALL, VM_PROT_ALL,
+ MAP_PRIVATE | MAP_FIXED, OBJT_VNODE, vp, file_offset);
+ if (error)
+ goto cleanup;
+ vm_map_lock(map);
+ if (!vm_map_lookup_entry(map, vmaddr, &entry)) {
+ vm_map_unlock(map);
+ error = EDOOFUS;
+ goto cleanup;
+ }
+ entry->eflags |= MAP_ENTRY_VN_EXEC;
+ vm_map_unlock(map);
+ textset = false;
+ }
+
+ if (bss_size != 0) {
+ /* Calculate BSS start address */
+ vmaddr = trunc_page(a_out->a_entry) + a_out->a_text +
+ a_out->a_data;
+
+ /* allocate some 'anon' space */
+ error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0,
+ &vmaddr, bss_size, 0, VMFS_NO_SPACE, VM_PROT_ALL,
+ VM_PROT_ALL, 0);
+ if (error)
+ goto cleanup;
+ }
+
+cleanup:
+ if (opened) {
+ if (locked)
+ VOP_UNLOCK(vp);
+ locked = false;
+ VOP_CLOSE(vp, FREAD, td->td_ucred, td);
+ }
+ if (textset) {
+ if (!locked) {
+ locked = true;
+ VOP_LOCK(vp, LK_SHARED | LK_RETRY);
+ }
+ VOP_UNSET_TEXT_CHECKED(vp);
+ }
+ if (locked)
+ VOP_UNLOCK(vp);
+
+ /* Release the temporary mapping. */
+ if (a_out)
+ kmap_free_wakeup(exec_map, (vm_offset_t)a_out, PAGE_SIZE);
+
+ return (error);
+}
+
+#endif /* __i386__ */
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_select(struct thread *td, struct linux_select_args *args)
+{
+ l_timeval ltv;
+ struct timeval tv0, tv1, utv, *tvp;
+ int error;
+
+ /*
+ * Store current time for computation of the amount of
+ * time left.
+ */
+ if (args->timeout) {
+ if ((error = copyin(args->timeout, &ltv, sizeof(ltv))))
+ goto select_out;
+ utv.tv_sec = ltv.tv_sec;
+ utv.tv_usec = ltv.tv_usec;
+
+ if (itimerfix(&utv)) {
+ /*
+ * The timeval was invalid. Convert it to something
+ * valid that will act as it does under Linux.
+ */
+ utv.tv_sec += utv.tv_usec / 1000000;
+ utv.tv_usec %= 1000000;
+ if (utv.tv_usec < 0) {
+ utv.tv_sec -= 1;
+ utv.tv_usec += 1000000;
+ }
+ if (utv.tv_sec < 0)
+ timevalclear(&utv);
+ }
+ microtime(&tv0);
+ tvp = &utv;
+ } else
+ tvp = NULL;
+
+ error = kern_select(td, args->nfds, args->readfds, args->writefds,
+ args->exceptfds, tvp, LINUX_NFDBITS);
+ if (error)
+ goto select_out;
+
+ if (args->timeout) {
+ if (td->td_retval[0]) {
+ /*
+ * Compute how much time was left of the timeout,
+ * by subtracting the current time and the time
+ * before we started the call, and subtracting
+ * that result from the user-supplied value.
+ */
+ microtime(&tv1);
+ timevalsub(&tv1, &tv0);
+ timevalsub(&utv, &tv1);
+ if (utv.tv_sec < 0)
+ timevalclear(&utv);
+ } else
+ timevalclear(&utv);
+ ltv.tv_sec = utv.tv_sec;
+ ltv.tv_usec = utv.tv_usec;
+ if ((error = copyout(&ltv, args->timeout, sizeof(ltv))))
+ goto select_out;
+ }
+
+select_out:
+ return (error);
+}
+#endif
+
+int
+linux_mremap(struct thread *td, struct linux_mremap_args *args)
+{
+ uintptr_t addr;
+ size_t len;
+ int error = 0;
+
+ if (args->flags & ~(LINUX_MREMAP_FIXED | LINUX_MREMAP_MAYMOVE)) {
+ td->td_retval[0] = 0;
+ return (EINVAL);
+ }
+
+ /*
+ * Check for the page alignment.
+ * Linux defines PAGE_MASK to be FreeBSD ~PAGE_MASK.
+ */
+ if (args->addr & PAGE_MASK) {
+ td->td_retval[0] = 0;
+ return (EINVAL);
+ }
+
+ args->new_len = round_page(args->new_len);
+ args->old_len = round_page(args->old_len);
+
+ if (args->new_len > args->old_len) {
+ td->td_retval[0] = 0;
+ return (ENOMEM);
+ }
+
+ if (args->new_len < args->old_len) {
+ addr = args->addr + args->new_len;
+ len = args->old_len - args->new_len;
+ error = kern_munmap(td, addr, len);
+ }
+
+ td->td_retval[0] = error ? 0 : (uintptr_t)args->addr;
+ return (error);
+}
+
+#define LINUX_MS_ASYNC 0x0001
+#define LINUX_MS_INVALIDATE 0x0002
+#define LINUX_MS_SYNC 0x0004
+
+int
+linux_msync(struct thread *td, struct linux_msync_args *args)
+{
+
+ return (kern_msync(td, args->addr, args->len,
+ args->fl & ~LINUX_MS_SYNC));
+}
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_time(struct thread *td, struct linux_time_args *args)
+{
+ struct timeval tv;
+ l_time_t tm;
+ int error;
+
+ microtime(&tv);
+ tm = tv.tv_sec;
+ if (args->tm && (error = copyout(&tm, args->tm, sizeof(tm))))
+ return (error);
+ td->td_retval[0] = tm;
+ return (0);
+}
+#endif
+
+struct l_times_argv {
+ l_clock_t tms_utime;
+ l_clock_t tms_stime;
+ l_clock_t tms_cutime;
+ l_clock_t tms_cstime;
+};
+
+/*
+ * Glibc versions prior to 2.2.1 always use hard-coded CLK_TCK value.
+ * Since 2.2.1 Glibc uses value exported from kernel via AT_CLKTCK
+ * auxiliary vector entry.
+ */
+#define CLK_TCK 100
+
+#define CONVOTCK(r) (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK))
+#define CONVNTCK(r) (r.tv_sec * stclohz + r.tv_usec / (1000000 / stclohz))
+
+#define CONVTCK(r) (linux_kernver(td) >= LINUX_KERNVER_2004000 ? \
+ CONVNTCK(r) : CONVOTCK(r))
+
+int
+linux_times(struct thread *td, struct linux_times_args *args)
+{
+ struct timeval tv, utime, stime, cutime, cstime;
+ struct l_times_argv tms;
+ struct proc *p;
+ int error;
+
+ if (args->buf != NULL) {
+ p = td->td_proc;
+ PROC_LOCK(p);
+ PROC_STATLOCK(p);
+ calcru(p, &utime, &stime);
+ PROC_STATUNLOCK(p);
+ calccru(p, &cutime, &cstime);
+ PROC_UNLOCK(p);
+
+ tms.tms_utime = CONVTCK(utime);
+ tms.tms_stime = CONVTCK(stime);
+
+ tms.tms_cutime = CONVTCK(cutime);
+ tms.tms_cstime = CONVTCK(cstime);
+
+ if ((error = copyout(&tms, args->buf, sizeof(tms))))
+ return (error);
+ }
+
+ microuptime(&tv);
+ td->td_retval[0] = (int)CONVTCK(tv);
+ return (0);
+}
+
+int
+linux_newuname(struct thread *td, struct linux_newuname_args *args)
+{
+ struct l_new_utsname utsname;
+ char osname[LINUX_MAX_UTSNAME];
+ char osrelease[LINUX_MAX_UTSNAME];
+ char *p;
+
+ linux_get_osname(td, osname);
+ linux_get_osrelease(td, osrelease);
+
+ bzero(&utsname, sizeof(utsname));
+ strlcpy(utsname.sysname, osname, LINUX_MAX_UTSNAME);
+ getcredhostname(td->td_ucred, utsname.nodename, LINUX_MAX_UTSNAME);
+ getcreddomainname(td->td_ucred, utsname.domainname, LINUX_MAX_UTSNAME);
+ strlcpy(utsname.release, osrelease, LINUX_MAX_UTSNAME);
+ strlcpy(utsname.version, version, LINUX_MAX_UTSNAME);
+ for (p = utsname.version; *p != '\0'; ++p)
+ if (*p == '\n') {
+ *p = '\0';
+ break;
+ }
+#if defined(__amd64__)
+ /*
+ * On amd64, Linux uname(2) needs to return "x86_64"
+ * for both 64-bit and 32-bit applications. On 32-bit,
+ * the string returned by getauxval(AT_PLATFORM) needs
+ * to remain "i686", though.
+ */
+ strlcpy(utsname.machine, "x86_64", LINUX_MAX_UTSNAME);
+#else
+ strlcpy(utsname.machine, linux_kplatform, LINUX_MAX_UTSNAME);
+#endif
+
+ return (copyout(&utsname, args->buf, sizeof(utsname)));
+}
+
+struct l_utimbuf {
+ l_time_t l_actime;
+ l_time_t l_modtime;
+};
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_utime(struct thread *td, struct linux_utime_args *args)
+{
+ struct timeval tv[2], *tvp;
+ struct l_utimbuf lut;
+ char *fname;
+ int error;
+ bool convpath;
+
+ convpath = LUSECONVPATH(td);
+ if (convpath)
+ LCONVPATHEXIST(td, args->fname, &fname);
+
+ if (args->times) {
+ if ((error = copyin(args->times, &lut, sizeof lut))) {
+ if (convpath)
+ LFREEPATH(fname);
+ return (error);
+ }
+ tv[0].tv_sec = lut.l_actime;
+ tv[0].tv_usec = 0;
+ tv[1].tv_sec = lut.l_modtime;
+ tv[1].tv_usec = 0;
+ tvp = tv;
+ } else
+ tvp = NULL;
+
+ if (!convpath) {
+ error = kern_utimesat(td, AT_FDCWD, args->fname, UIO_USERSPACE,
+ tvp, UIO_SYSSPACE);
+ } else {
+ error = kern_utimesat(td, AT_FDCWD, fname, UIO_SYSSPACE, tvp,
+ UIO_SYSSPACE);
+ LFREEPATH(fname);
+ }
+ return (error);
+}
+#endif
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_utimes(struct thread *td, struct linux_utimes_args *args)
+{
+ l_timeval ltv[2];
+ struct timeval tv[2], *tvp = NULL;
+ char *fname;
+ int error;
+ bool convpath;
+
+ convpath = LUSECONVPATH(td);
+ if (convpath)
+ LCONVPATHEXIST(td, args->fname, &fname);
+
+ if (args->tptr != NULL) {
+ if ((error = copyin(args->tptr, ltv, sizeof ltv))) {
+ LFREEPATH(fname);
+ return (error);
+ }
+ tv[0].tv_sec = ltv[0].tv_sec;
+ tv[0].tv_usec = ltv[0].tv_usec;
+ tv[1].tv_sec = ltv[1].tv_sec;
+ tv[1].tv_usec = ltv[1].tv_usec;
+ tvp = tv;
+ }
+
+ if (!convpath) {
+ error = kern_utimesat(td, AT_FDCWD, args->fname, UIO_USERSPACE,
+ tvp, UIO_SYSSPACE);
+ } else {
+ error = kern_utimesat(td, AT_FDCWD, fname, UIO_SYSSPACE,
+ tvp, UIO_SYSSPACE);
+ LFREEPATH(fname);
+ }
+ return (error);
+}
+#endif
+
+static int
+linux_utimensat_nsec_valid(l_long nsec)
+{
+
+ if (nsec == LINUX_UTIME_OMIT || nsec == LINUX_UTIME_NOW)
+ return (0);
+ if (nsec >= 0 && nsec <= 999999999)
+ return (0);
+ return (1);
+}
+
+int
+linux_utimensat(struct thread *td, struct linux_utimensat_args *args)
+{
+ struct l_timespec l_times[2];
+ struct timespec times[2], *timesp = NULL;
+ char *path = NULL;
+ int error, dfd, flags = 0;
+
+ dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
+
+ if (args->flags & ~LINUX_AT_SYMLINK_NOFOLLOW)
+ return (EINVAL);
+
+ if (args->times != NULL) {
+ error = copyin(args->times, l_times, sizeof(l_times));
+ if (error != 0)
+ return (error);
+
+ if (linux_utimensat_nsec_valid(l_times[0].tv_nsec) != 0 ||
+ linux_utimensat_nsec_valid(l_times[1].tv_nsec) != 0)
+ return (EINVAL);
+
+ times[0].tv_sec = l_times[0].tv_sec;
+ switch (l_times[0].tv_nsec)
+ {
+ case LINUX_UTIME_OMIT:
+ times[0].tv_nsec = UTIME_OMIT;
+ break;
+ case LINUX_UTIME_NOW:
+ times[0].tv_nsec = UTIME_NOW;
+ break;
+ default:
+ times[0].tv_nsec = l_times[0].tv_nsec;
+ }
+
+ times[1].tv_sec = l_times[1].tv_sec;
+ switch (l_times[1].tv_nsec)
+ {
+ case LINUX_UTIME_OMIT:
+ times[1].tv_nsec = UTIME_OMIT;
+ break;
+ case LINUX_UTIME_NOW:
+ times[1].tv_nsec = UTIME_NOW;
+ break;
+ default:
+ times[1].tv_nsec = l_times[1].tv_nsec;
+ break;
+ }
+ timesp = times;
+
+ /* This breaks POSIX, but is what the Linux kernel does
+ * _on purpose_ (documented in the man page for utimensat(2)),
+ * so we must follow that behaviour. */
+ if (times[0].tv_nsec == UTIME_OMIT &&
+ times[1].tv_nsec == UTIME_OMIT)
+ return (0);
+ }
+
+ if (!LUSECONVPATH(td)) {
+ if (args->pathname != NULL) {
+ return (kern_utimensat(td, dfd, args->pathname,
+ UIO_USERSPACE, timesp, UIO_SYSSPACE, flags));
+ }
+ }
+
+ if (args->pathname != NULL)
+ LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
+ else if (args->flags != 0)
+ return (EINVAL);
+
+ if (args->flags & LINUX_AT_SYMLINK_NOFOLLOW)
+ flags |= AT_SYMLINK_NOFOLLOW;
+
+ if (path == NULL)
+ error = kern_futimens(td, dfd, timesp, UIO_SYSSPACE);
+ else {
+ error = kern_utimensat(td, dfd, path, UIO_SYSSPACE, timesp,
+ UIO_SYSSPACE, flags);
+ LFREEPATH(path);
+ }
+
+ return (error);
+}
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_futimesat(struct thread *td, struct linux_futimesat_args *args)
+{
+ l_timeval ltv[2];
+ struct timeval tv[2], *tvp = NULL;
+ char *fname;
+ int error, dfd;
+ bool convpath;
+
+ convpath = LUSECONVPATH(td);
+ dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
+ if (convpath)
+ LCONVPATHEXIST_AT(td, args->filename, &fname, dfd);
+
+ if (args->utimes != NULL) {
+ if ((error = copyin(args->utimes, ltv, sizeof ltv))) {
+ if (convpath)
+ LFREEPATH(fname);
+ return (error);
+ }
+ tv[0].tv_sec = ltv[0].tv_sec;
+ tv[0].tv_usec = ltv[0].tv_usec;
+ tv[1].tv_sec = ltv[1].tv_sec;
+ tv[1].tv_usec = ltv[1].tv_usec;
+ tvp = tv;
+ }
+
+ if (!convpath) {
+ error = kern_utimesat(td, dfd, args->filename, UIO_USERSPACE,
+ tvp, UIO_SYSSPACE);
+ } else {
+ error = kern_utimesat(td, dfd, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE);
+ LFREEPATH(fname);
+ }
+ return (error);
+}
+#endif
+
+static int
+linux_common_wait(struct thread *td, int pid, int *statusp,
+ int options, struct __wrusage *wrup)
+{
+ siginfo_t siginfo;
+ idtype_t idtype;
+ id_t id;
+ int error, status, tmpstat;
+
+ if (pid == WAIT_ANY) {
+ idtype = P_ALL;
+ id = 0;
+ } else if (pid < 0) {
+ idtype = P_PGID;
+ id = (id_t)-pid;
+ } else {
+ idtype = P_PID;
+ id = (id_t)pid;
+ }
+
+ /*
+ * For backward compatibility we implicitly add flags WEXITED
+ * and WTRAPPED here.
+ */
+ options |= WEXITED | WTRAPPED;
+ error = kern_wait6(td, idtype, id, &status, options, wrup, &siginfo);
+ if (error)
+ return (error);
+
+ if (statusp) {
+ tmpstat = status & 0xffff;
+ if (WIFSIGNALED(tmpstat)) {
+ tmpstat = (tmpstat & 0xffffff80) |
+ bsd_to_linux_signal(WTERMSIG(tmpstat));
+ } else if (WIFSTOPPED(tmpstat)) {
+ tmpstat = (tmpstat & 0xffff00ff) |
+ (bsd_to_linux_signal(WSTOPSIG(tmpstat)) << 8);
+#if defined(__amd64__) && !defined(COMPAT_LINUX32)
+ if (WSTOPSIG(status) == SIGTRAP) {
+ tmpstat = linux_ptrace_status(td,
+ siginfo.si_pid, tmpstat);
+ }
+#endif
+ } else if (WIFCONTINUED(tmpstat)) {
+ tmpstat = 0xffff;
+ }
+ error = copyout(&tmpstat, statusp, sizeof(int));
+ }
+
+ return (error);
+}
+
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+int
+linux_waitpid(struct thread *td, struct linux_waitpid_args *args)
+{
+ struct linux_wait4_args wait4_args;
+
+ wait4_args.pid = args->pid;
+ wait4_args.status = args->status;
+ wait4_args.options = args->options;
+ wait4_args.rusage = NULL;
+
+ return (linux_wait4(td, &wait4_args));
+}
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+
+int
+linux_wait4(struct thread *td, struct linux_wait4_args *args)
+{
+ int error, options;
+ struct __wrusage wru, *wrup;
+
+ if (args->options & ~(LINUX_WUNTRACED | LINUX_WNOHANG |
+ LINUX_WCONTINUED | __WCLONE | __WNOTHREAD | __WALL))
+ return (EINVAL);
+
+ options = WEXITED;
+ linux_to_bsd_waitopts(args->options, &options);
+
+ if (args->rusage != NULL)
+ wrup = &wru;
+ else
+ wrup = NULL;
+ error = linux_common_wait(td, args->pid, args->status, options, wrup);
+ if (error != 0)
+ return (error);
+ if (args->rusage != NULL)
+ error = linux_copyout_rusage(&wru.wru_self, args->rusage);
+ return (error);
+}
+
+int
+linux_waitid(struct thread *td, struct linux_waitid_args *args)
+{
+ int status, options, sig;
+ struct __wrusage wru;
+ siginfo_t siginfo;
+ l_siginfo_t lsi;
+ idtype_t idtype;
+ struct proc *p;
+ int error;
+
+ options = 0;
+ linux_to_bsd_waitopts(args->options, &options);
+
+ if (options & ~(WNOHANG | WNOWAIT | WEXITED | WUNTRACED | WCONTINUED))
+ return (EINVAL);
+ if (!(options & (WEXITED | WUNTRACED | WCONTINUED)))
+ return (EINVAL);
+
+ switch (args->idtype) {
+ case LINUX_P_ALL:
+ idtype = P_ALL;
+ break;
+ case LINUX_P_PID:
+ if (args->id <= 0)
+ return (EINVAL);
+ idtype = P_PID;
+ break;
+ case LINUX_P_PGID:
+ if (args->id <= 0)
+ return (EINVAL);
+ idtype = P_PGID;
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ error = kern_wait6(td, idtype, args->id, &status, options,
+ &wru, &siginfo);
+ if (error != 0)
+ return (error);
+ if (args->rusage != NULL) {
+ error = linux_copyout_rusage(&wru.wru_children,
+ args->rusage);
+ if (error != 0)
+ return (error);
+ }
+ if (args->info != NULL) {
+ p = td->td_proc;
+ bzero(&lsi, sizeof(lsi));
+ if (td->td_retval[0] != 0) {
+ sig = bsd_to_linux_signal(siginfo.si_signo);
+ siginfo_to_lsiginfo(&siginfo, &lsi, sig);
+ }
+ error = copyout(&lsi, args->info, sizeof(lsi));
+ }
+ td->td_retval[0] = 0;
+
+ return (error);
+}
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_mknod(struct thread *td, struct linux_mknod_args *args)
+{
+ char *path;
+ int error;
+ enum uio_seg seg;
+ bool convpath;
+
+ convpath = LUSECONVPATH(td);
+ if (!convpath) {
+ path = args->path;
+ seg = UIO_USERSPACE;
+ } else {
+ LCONVPATHCREAT(td, args->path, &path);
+ seg = UIO_SYSSPACE;
+ }
+
+ switch (args->mode & S_IFMT) {
+ case S_IFIFO:
+ case S_IFSOCK:
+ error = kern_mkfifoat(td, AT_FDCWD, path, seg,
+ args->mode);
+ break;
+
+ case S_IFCHR:
+ case S_IFBLK:
+ error = kern_mknodat(td, AT_FDCWD, path, seg,
+ args->mode, args->dev);
+ break;
+
+ case S_IFDIR:
+ error = EPERM;
+ break;
+
+ case 0:
+ args->mode |= S_IFREG;
+ /* FALLTHROUGH */
+ case S_IFREG:
+ error = kern_openat(td, AT_FDCWD, path, seg,
+ O_WRONLY | O_CREAT | O_TRUNC, args->mode);
+ if (error == 0)
+ kern_close(td, td->td_retval[0]);
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ if (convpath)
+ LFREEPATH(path);
+ return (error);
+}
+#endif
+
+int
+linux_mknodat(struct thread *td, struct linux_mknodat_args *args)
+{
+ char *path;
+ int error, dfd;
+ enum uio_seg seg;
+ bool convpath;
+
+ dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
+
+ convpath = LUSECONVPATH(td);
+ if (!convpath) {
+ path = __DECONST(char *, args->filename);
+ seg = UIO_USERSPACE;
+ } else {
+ LCONVPATHCREAT_AT(td, args->filename, &path, dfd);
+ seg = UIO_SYSSPACE;
+ }
+
+ switch (args->mode & S_IFMT) {
+ case S_IFIFO:
+ case S_IFSOCK:
+ error = kern_mkfifoat(td, dfd, path, seg, args->mode);
+ break;
+
+ case S_IFCHR:
+ case S_IFBLK:
+ error = kern_mknodat(td, dfd, path, seg, args->mode,
+ args->dev);
+ break;
+
+ case S_IFDIR:
+ error = EPERM;
+ break;
+
+ case 0:
+ args->mode |= S_IFREG;
+ /* FALLTHROUGH */
+ case S_IFREG:
+ error = kern_openat(td, dfd, path, seg,
+ O_WRONLY | O_CREAT | O_TRUNC, args->mode);
+ if (error == 0)
+ kern_close(td, td->td_retval[0]);
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ if (convpath)
+ LFREEPATH(path);
+ return (error);
+}
+
+/*
+ * UGH! This is just about the dumbest idea I've ever heard!!
+ */
+int
+linux_personality(struct thread *td, struct linux_personality_args *args)
+{
+ struct linux_pemuldata *pem;
+ struct proc *p = td->td_proc;
+ uint32_t old;
+
+ PROC_LOCK(p);
+ pem = pem_find(p);
+ old = pem->persona;
+ if (args->per != 0xffffffff)
+ pem->persona = args->per;
+ PROC_UNLOCK(p);
+
+ td->td_retval[0] = old;
+ return (0);
+}
+
+struct l_itimerval {
+ l_timeval it_interval;
+ l_timeval it_value;
+};
+
+#define B2L_ITIMERVAL(bip, lip) \
+ (bip)->it_interval.tv_sec = (lip)->it_interval.tv_sec; \
+ (bip)->it_interval.tv_usec = (lip)->it_interval.tv_usec; \
+ (bip)->it_value.tv_sec = (lip)->it_value.tv_sec; \
+ (bip)->it_value.tv_usec = (lip)->it_value.tv_usec;
+
+int
+linux_setitimer(struct thread *td, struct linux_setitimer_args *uap)
+{
+ int error;
+ struct l_itimerval ls;
+ struct itimerval aitv, oitv;
+
+ if (uap->itv == NULL) {
+ uap->itv = uap->oitv;
+ return (linux_getitimer(td, (struct linux_getitimer_args *)uap));
+ }
+
+ error = copyin(uap->itv, &ls, sizeof(ls));
+ if (error != 0)
+ return (error);
+ B2L_ITIMERVAL(&aitv, &ls);
+ error = kern_setitimer(td, uap->which, &aitv, &oitv);
+ if (error != 0 || uap->oitv == NULL)
+ return (error);
+ B2L_ITIMERVAL(&ls, &oitv);
+
+ return (copyout(&ls, uap->oitv, sizeof(ls)));
+}
+
+int
+linux_getitimer(struct thread *td, struct linux_getitimer_args *uap)
+{
+ int error;
+ struct l_itimerval ls;
+ struct itimerval aitv;
+
+ error = kern_getitimer(td, uap->which, &aitv);
+ if (error != 0)
+ return (error);
+ B2L_ITIMERVAL(&ls, &aitv);
+ return (copyout(&ls, uap->itv, sizeof(ls)));
+}
+
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+int
+linux_nice(struct thread *td, struct linux_nice_args *args)
+{
+
+ return (kern_setpriority(td, PRIO_PROCESS, 0, args->inc));
+}
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+
+int
+linux_setgroups(struct thread *td, struct linux_setgroups_args *args)
+{
+ struct ucred *newcred, *oldcred;
+ l_gid_t *linux_gidset;
+ gid_t *bsd_gidset;
+ int ngrp, error;
+ struct proc *p;
+
+ ngrp = args->gidsetsize;
+ if (ngrp < 0 || ngrp >= ngroups_max + 1)
+ return (EINVAL);
+ linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_LINUX, M_WAITOK);
+ error = copyin(args->grouplist, linux_gidset, ngrp * sizeof(l_gid_t));
+ if (error)
+ goto out;
+ newcred = crget();
+ crextend(newcred, ngrp + 1);
+ p = td->td_proc;
+ PROC_LOCK(p);
+ oldcred = p->p_ucred;
+ crcopy(newcred, oldcred);
+
+ /*
+ * cr_groups[0] holds egid. Setting the whole set from
+ * the supplied set will cause egid to be changed too.
+ * Keep cr_groups[0] unchanged to prevent that.
+ */
+
+ if ((error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS)) != 0) {
+ PROC_UNLOCK(p);
+ crfree(newcred);
+ goto out;
+ }
+
+ if (ngrp > 0) {
+ newcred->cr_ngroups = ngrp + 1;
+
+ bsd_gidset = newcred->cr_groups;
+ ngrp--;
+ while (ngrp >= 0) {
+ bsd_gidset[ngrp + 1] = linux_gidset[ngrp];
+ ngrp--;
+ }
+ } else
+ newcred->cr_ngroups = 1;
+
+ setsugid(p);
+ proc_set_cred(p, newcred);
+ PROC_UNLOCK(p);
+ crfree(oldcred);
+ error = 0;
+out:
+ free(linux_gidset, M_LINUX);
+ return (error);
+}
+
+int
+linux_getgroups(struct thread *td, struct linux_getgroups_args *args)
+{
+ struct ucred *cred;
+ l_gid_t *linux_gidset;
+ gid_t *bsd_gidset;
+ int bsd_gidsetsz, ngrp, error;
+
+ cred = td->td_ucred;
+ bsd_gidset = cred->cr_groups;
+ bsd_gidsetsz = cred->cr_ngroups - 1;
+
+ /*
+ * cr_groups[0] holds egid. Returning the whole set
+ * here will cause a duplicate. Exclude cr_groups[0]
+ * to prevent that.
+ */
+
+ if ((ngrp = args->gidsetsize) == 0) {
+ td->td_retval[0] = bsd_gidsetsz;
+ return (0);
+ }
+
+ if (ngrp < bsd_gidsetsz)
+ return (EINVAL);
+
+ ngrp = 0;
+ linux_gidset = malloc(bsd_gidsetsz * sizeof(*linux_gidset),
+ M_LINUX, M_WAITOK);
+ while (ngrp < bsd_gidsetsz) {
+ linux_gidset[ngrp] = bsd_gidset[ngrp + 1];
+ ngrp++;
+ }
+
+ error = copyout(linux_gidset, args->grouplist, ngrp * sizeof(l_gid_t));
+ free(linux_gidset, M_LINUX);
+ if (error)
+ return (error);
+
+ td->td_retval[0] = ngrp;
+ return (0);
+}
+
+static bool
+linux_get_dummy_limit(l_uint resource, struct rlimit *rlim)
+{
+
+ if (linux_dummy_rlimits == 0)
+ return (false);
+
+ switch (resource) {
+ case LINUX_RLIMIT_LOCKS:
+ case LINUX_RLIMIT_SIGPENDING:
+ case LINUX_RLIMIT_MSGQUEUE:
+ case LINUX_RLIMIT_RTTIME:
+ rlim->rlim_cur = LINUX_RLIM_INFINITY;
+ rlim->rlim_max = LINUX_RLIM_INFINITY;
+ return (true);
+ case LINUX_RLIMIT_NICE:
+ case LINUX_RLIMIT_RTPRIO:
+ rlim->rlim_cur = 0;
+ rlim->rlim_max = 0;
+ return (true);
+ default:
+ return (false);
+ }
+}
+
+int
+linux_setrlimit(struct thread *td, struct linux_setrlimit_args *args)
+{
+ struct rlimit bsd_rlim;
+ struct l_rlimit rlim;
+ u_int which;
+ int error;
+
+ if (args->resource >= LINUX_RLIM_NLIMITS)
+ return (EINVAL);
+
+ which = linux_to_bsd_resource[args->resource];
+ if (which == -1)
+ return (EINVAL);
+
+ error = copyin(args->rlim, &rlim, sizeof(rlim));
+ if (error)
+ return (error);
+
+ bsd_rlim.rlim_cur = (rlim_t)rlim.rlim_cur;
+ bsd_rlim.rlim_max = (rlim_t)rlim.rlim_max;
+ return (kern_setrlimit(td, which, &bsd_rlim));
+}
+
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+int
+linux_old_getrlimit(struct thread *td, struct linux_old_getrlimit_args *args)
+{
+ struct l_rlimit rlim;
+ struct rlimit bsd_rlim;
+ u_int which;
+
+ if (linux_get_dummy_limit(args->resource, &bsd_rlim)) {
+ rlim.rlim_cur = bsd_rlim.rlim_cur;
+ rlim.rlim_max = bsd_rlim.rlim_max;
+ return (copyout(&rlim, args->rlim, sizeof(rlim)));
+ }
+
+ if (args->resource >= LINUX_RLIM_NLIMITS)
+ return (EINVAL);
+
+ which = linux_to_bsd_resource[args->resource];
+ if (which == -1)
+ return (EINVAL);
+
+ lim_rlimit(td, which, &bsd_rlim);
+
+#ifdef COMPAT_LINUX32
+ rlim.rlim_cur = (unsigned int)bsd_rlim.rlim_cur;
+ if (rlim.rlim_cur == UINT_MAX)
+ rlim.rlim_cur = INT_MAX;
+ rlim.rlim_max = (unsigned int)bsd_rlim.rlim_max;
+ if (rlim.rlim_max == UINT_MAX)
+ rlim.rlim_max = INT_MAX;
+#else
+ rlim.rlim_cur = (unsigned long)bsd_rlim.rlim_cur;
+ if (rlim.rlim_cur == ULONG_MAX)
+ rlim.rlim_cur = LONG_MAX;
+ rlim.rlim_max = (unsigned long)bsd_rlim.rlim_max;
+ if (rlim.rlim_max == ULONG_MAX)
+ rlim.rlim_max = LONG_MAX;
+#endif
+ return (copyout(&rlim, args->rlim, sizeof(rlim)));
+}
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+
+int
+linux_getrlimit(struct thread *td, struct linux_getrlimit_args *args)
+{
+ struct l_rlimit rlim;
+ struct rlimit bsd_rlim;
+ u_int which;
+
+ if (linux_get_dummy_limit(args->resource, &bsd_rlim)) {
+ rlim.rlim_cur = bsd_rlim.rlim_cur;
+ rlim.rlim_max = bsd_rlim.rlim_max;
+ return (copyout(&rlim, args->rlim, sizeof(rlim)));
+ }
+
+ if (args->resource >= LINUX_RLIM_NLIMITS)
+ return (EINVAL);
+
+ which = linux_to_bsd_resource[args->resource];
+ if (which == -1)
+ return (EINVAL);
+
+ lim_rlimit(td, which, &bsd_rlim);
+
+ rlim.rlim_cur = (l_ulong)bsd_rlim.rlim_cur;
+ rlim.rlim_max = (l_ulong)bsd_rlim.rlim_max;
+ return (copyout(&rlim, args->rlim, sizeof(rlim)));
+}
+
+int
+linux_sched_setscheduler(struct thread *td,
+ struct linux_sched_setscheduler_args *args)
+{
+ struct sched_param sched_param;
+ struct thread *tdt;
+ int error, policy;
+
+ switch (args->policy) {
+ case LINUX_SCHED_OTHER:
+ policy = SCHED_OTHER;
+ break;
+ case LINUX_SCHED_FIFO:
+ policy = SCHED_FIFO;
+ break;
+ case LINUX_SCHED_RR:
+ policy = SCHED_RR;
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ error = copyin(args->param, &sched_param, sizeof(sched_param));
+ if (error)
+ return (error);
+
+ if (linux_map_sched_prio) {
+ switch (policy) {
+ case SCHED_OTHER:
+ if (sched_param.sched_priority != 0)
+ return (EINVAL);
+
+ sched_param.sched_priority =
+ PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE;
+ break;
+ case SCHED_FIFO:
+ case SCHED_RR:
+ if (sched_param.sched_priority < 1 ||
+ sched_param.sched_priority >= LINUX_MAX_RT_PRIO)
+ return (EINVAL);
+
+ /*
+ * Map [1, LINUX_MAX_RT_PRIO - 1] to
+ * [0, RTP_PRIO_MAX - RTP_PRIO_MIN] (rounding down).
+ */
+ sched_param.sched_priority =
+ (sched_param.sched_priority - 1) *
+ (RTP_PRIO_MAX - RTP_PRIO_MIN + 1) /
+ (LINUX_MAX_RT_PRIO - 1);
+ break;
+ }
+ }
+
+ tdt = linux_tdfind(td, args->pid, -1);
+ if (tdt == NULL)
+ return (ESRCH);
+
+ error = kern_sched_setscheduler(td, tdt, policy, &sched_param);
+ PROC_UNLOCK(tdt->td_proc);
+ return (error);
+}
+
+int
+linux_sched_getscheduler(struct thread *td,
+ struct linux_sched_getscheduler_args *args)
+{
+ struct thread *tdt;
+ int error, policy;
+
+ tdt = linux_tdfind(td, args->pid, -1);
+ if (tdt == NULL)
+ return (ESRCH);
+
+ error = kern_sched_getscheduler(td, tdt, &policy);
+ PROC_UNLOCK(tdt->td_proc);
+
+ switch (policy) {
+ case SCHED_OTHER:
+ td->td_retval[0] = LINUX_SCHED_OTHER;
+ break;
+ case SCHED_FIFO:
+ td->td_retval[0] = LINUX_SCHED_FIFO;
+ break;
+ case SCHED_RR:
+ td->td_retval[0] = LINUX_SCHED_RR;
+ break;
+ }
+ return (error);
+}
+
+int
+linux_sched_get_priority_max(struct thread *td,
+ struct linux_sched_get_priority_max_args *args)
+{
+ struct sched_get_priority_max_args bsd;
+
+ if (linux_map_sched_prio) {
+ switch (args->policy) {
+ case LINUX_SCHED_OTHER:
+ td->td_retval[0] = 0;
+ return (0);
+ case LINUX_SCHED_FIFO:
+ case LINUX_SCHED_RR:
+ td->td_retval[0] = LINUX_MAX_RT_PRIO - 1;
+ return (0);
+ default:
+ return (EINVAL);
+ }
+ }
+
+ switch (args->policy) {
+ case LINUX_SCHED_OTHER:
+ bsd.policy = SCHED_OTHER;
+ break;
+ case LINUX_SCHED_FIFO:
+ bsd.policy = SCHED_FIFO;
+ break;
+ case LINUX_SCHED_RR:
+ bsd.policy = SCHED_RR;
+ break;
+ default:
+ return (EINVAL);
+ }
+ return (sys_sched_get_priority_max(td, &bsd));
+}
+
+int
+linux_sched_get_priority_min(struct thread *td,
+ struct linux_sched_get_priority_min_args *args)
+{
+ struct sched_get_priority_min_args bsd;
+
+ if (linux_map_sched_prio) {
+ switch (args->policy) {
+ case LINUX_SCHED_OTHER:
+ td->td_retval[0] = 0;
+ return (0);
+ case LINUX_SCHED_FIFO:
+ case LINUX_SCHED_RR:
+ td->td_retval[0] = 1;
+ return (0);
+ default:
+ return (EINVAL);
+ }
+ }
+
+ switch (args->policy) {
+ case LINUX_SCHED_OTHER:
+ bsd.policy = SCHED_OTHER;
+ break;
+ case LINUX_SCHED_FIFO:
+ bsd.policy = SCHED_FIFO;
+ break;
+ case LINUX_SCHED_RR:
+ bsd.policy = SCHED_RR;
+ break;
+ default:
+ return (EINVAL);
+ }
+ return (sys_sched_get_priority_min(td, &bsd));
+}
+
+#define REBOOT_CAD_ON 0x89abcdef
+#define REBOOT_CAD_OFF 0
+#define REBOOT_HALT 0xcdef0123
+#define REBOOT_RESTART 0x01234567
+#define REBOOT_RESTART2 0xA1B2C3D4
+#define REBOOT_POWEROFF 0x4321FEDC
+#define REBOOT_MAGIC1 0xfee1dead
+#define REBOOT_MAGIC2 0x28121969
+#define REBOOT_MAGIC2A 0x05121996
+#define REBOOT_MAGIC2B 0x16041998
+
+int
+linux_reboot(struct thread *td, struct linux_reboot_args *args)
+{
+ struct reboot_args bsd_args;
+
+ if (args->magic1 != REBOOT_MAGIC1)
+ return (EINVAL);
+
+ switch (args->magic2) {
+ case REBOOT_MAGIC2:
+ case REBOOT_MAGIC2A:
+ case REBOOT_MAGIC2B:
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ switch (args->cmd) {
+ case REBOOT_CAD_ON:
+ case REBOOT_CAD_OFF:
+ return (priv_check(td, PRIV_REBOOT));
+ case REBOOT_HALT:
+ bsd_args.opt = RB_HALT;
+ break;
+ case REBOOT_RESTART:
+ case REBOOT_RESTART2:
+ bsd_args.opt = 0;
+ break;
+ case REBOOT_POWEROFF:
+ bsd_args.opt = RB_POWEROFF;
+ break;
+ default:
+ return (EINVAL);
+ }
+ return (sys_reboot(td, &bsd_args));
+}
+
+int
+linux_getpid(struct thread *td, struct linux_getpid_args *args)
+{
+
+ td->td_retval[0] = td->td_proc->p_pid;
+
+ return (0);
+}
+
+int
+linux_gettid(struct thread *td, struct linux_gettid_args *args)
+{
+ struct linux_emuldata *em;
+
+ em = em_find(td);
+ KASSERT(em != NULL, ("gettid: emuldata not found.\n"));
+
+ td->td_retval[0] = em->em_tid;
+
+ return (0);
+}
+
+int
+linux_getppid(struct thread *td, struct linux_getppid_args *args)
+{
+
+ td->td_retval[0] = kern_getppid(td);
+ return (0);
+}
+
+int
+linux_getgid(struct thread *td, struct linux_getgid_args *args)
+{
+
+ td->td_retval[0] = td->td_ucred->cr_rgid;
+ return (0);
+}
+
+int
+linux_getuid(struct thread *td, struct linux_getuid_args *args)
+{
+
+ td->td_retval[0] = td->td_ucred->cr_ruid;
+ return (0);
+}
+
+int
+linux_getsid(struct thread *td, struct linux_getsid_args *args)
+{
+
+ return (kern_getsid(td, args->pid));
+}
+
+int
+linux_nosys(struct thread *td, struct nosys_args *ignore)
+{
+
+ return (ENOSYS);
+}
+
+int
+linux_getpriority(struct thread *td, struct linux_getpriority_args *args)
+{
+ int error;
+
+ error = kern_getpriority(td, args->which, args->who);
+ td->td_retval[0] = 20 - td->td_retval[0];
+ return (error);
+}
+
+int
+linux_sethostname(struct thread *td, struct linux_sethostname_args *args)
+{
+ int name[2];
+
+ name[0] = CTL_KERN;
+ name[1] = KERN_HOSTNAME;
+ return (userland_sysctl(td, name, 2, 0, 0, 0, args->hostname,
+ args->len, 0, 0));
+}
+
+int
+linux_setdomainname(struct thread *td, struct linux_setdomainname_args *args)
+{
+ int name[2];
+
+ name[0] = CTL_KERN;
+ name[1] = KERN_NISDOMAINNAME;
+ return (userland_sysctl(td, name, 2, 0, 0, 0, args->name,
+ args->len, 0, 0));
+}
+
+int
+linux_exit_group(struct thread *td, struct linux_exit_group_args *args)
+{
+
+ LINUX_CTR2(exit_group, "thread(%d) (%d)", td->td_tid,
+ args->error_code);
+
+ /*
+ * XXX: we should send a signal to the parent if
+ * SIGNAL_EXIT_GROUP is set. We ignore that (temporarily?)
+ * as it doesnt occur often.
+ */
+ exit1(td, args->error_code, 0);
+ /* NOTREACHED */
+}
+
+#define _LINUX_CAPABILITY_VERSION_1 0x19980330
+#define _LINUX_CAPABILITY_VERSION_2 0x20071026
+#define _LINUX_CAPABILITY_VERSION_3 0x20080522
+
+struct l_user_cap_header {
+ l_int version;
+ l_int pid;
+};
+
+struct l_user_cap_data {
+ l_int effective;
+ l_int permitted;
+ l_int inheritable;
+};
+
+int
+linux_capget(struct thread *td, struct linux_capget_args *uap)
+{
+ struct l_user_cap_header luch;
+ struct l_user_cap_data lucd[2];
+ int error, u32s;
+
+ if (uap->hdrp == NULL)
+ return (EFAULT);
+
+ error = copyin(uap->hdrp, &luch, sizeof(luch));
+ if (error != 0)
+ return (error);
+
+ switch (luch.version) {
+ case _LINUX_CAPABILITY_VERSION_1:
+ u32s = 1;
+ break;
+ case _LINUX_CAPABILITY_VERSION_2:
+ case _LINUX_CAPABILITY_VERSION_3:
+ u32s = 2;
+ break;
+ default:
+ luch.version = _LINUX_CAPABILITY_VERSION_1;
+ error = copyout(&luch, uap->hdrp, sizeof(luch));
+ if (error)
+ return (error);
+ return (EINVAL);
+ }
+
+ if (luch.pid)
+ return (EPERM);
+
+ if (uap->datap) {
+ /*
+ * The current implementation doesn't support setting
+ * a capability (it's essentially a stub) so indicate
+ * that no capabilities are currently set or available
+ * to request.
+ */
+ memset(&lucd, 0, u32s * sizeof(lucd[0]));
+ error = copyout(&lucd, uap->datap, u32s * sizeof(lucd[0]));
+ }
+
+ return (error);
+}
+
+int
+linux_capset(struct thread *td, struct linux_capset_args *uap)
+{
+ struct l_user_cap_header luch;
+ struct l_user_cap_data lucd[2];
+ int error, i, u32s;
+
+ if (uap->hdrp == NULL || uap->datap == NULL)
+ return (EFAULT);
+
+ error = copyin(uap->hdrp, &luch, sizeof(luch));
+ if (error != 0)
+ return (error);
+
+ switch (luch.version) {
+ case _LINUX_CAPABILITY_VERSION_1:
+ u32s = 1;
+ break;
+ case _LINUX_CAPABILITY_VERSION_2:
+ case _LINUX_CAPABILITY_VERSION_3:
+ u32s = 2;
+ break;
+ default:
+ luch.version = _LINUX_CAPABILITY_VERSION_1;
+ error = copyout(&luch, uap->hdrp, sizeof(luch));
+ if (error)
+ return (error);
+ return (EINVAL);
+ }
+
+ if (luch.pid)
+ return (EPERM);
+
+ error = copyin(uap->datap, &lucd, u32s * sizeof(lucd[0]));
+ if (error != 0)
+ return (error);
+
+ /* We currently don't support setting any capabilities. */
+ for (i = 0; i < u32s; i++) {
+ if (lucd[i].effective || lucd[i].permitted ||
+ lucd[i].inheritable) {
+ linux_msg(td,
+ "capset[%d] effective=0x%x, permitted=0x%x, "
+ "inheritable=0x%x is not implemented", i,
+ (int)lucd[i].effective, (int)lucd[i].permitted,
+ (int)lucd[i].inheritable);
+ return (EPERM);
+ }
+ }
+
+ return (0);
+}
+
+int
+linux_prctl(struct thread *td, struct linux_prctl_args *args)
+{
+ int error = 0, max_size;
+ struct proc *p = td->td_proc;
+ char comm[LINUX_MAX_COMM_LEN];
+ int pdeath_signal, trace_state;
+
+ switch (args->option) {
+ case LINUX_PR_SET_PDEATHSIG:
+ if (!LINUX_SIG_VALID(args->arg2))
+ return (EINVAL);
+ pdeath_signal = linux_to_bsd_signal(args->arg2);
+ return (kern_procctl(td, P_PID, 0, PROC_PDEATHSIG_CTL,
+ &pdeath_signal));
+ case LINUX_PR_GET_PDEATHSIG:
+ error = kern_procctl(td, P_PID, 0, PROC_PDEATHSIG_STATUS,
+ &pdeath_signal);
+ if (error != 0)
+ return (error);
+ pdeath_signal = bsd_to_linux_signal(pdeath_signal);
+ return (copyout(&pdeath_signal,
+ (void *)(register_t)args->arg2,
+ sizeof(pdeath_signal)));
+ /*
+ * In Linux, this flag controls if set[gu]id processes can coredump.
+ * There are additional semantics imposed on processes that cannot
+ * coredump:
+ * - Such processes can not be ptraced.
+ * - There are some semantics around ownership of process-related files
+ * in the /proc namespace.
+ *
+ * In FreeBSD, we can (and by default, do) disable setuid coredump
+ * system-wide with 'sugid_coredump.' We control tracability on a
+ * per-process basis with the procctl PROC_TRACE (=> P2_NOTRACE flag).
+ * By happy coincidence, P2_NOTRACE also prevents coredumping. So the
+ * procctl is roughly analogous to Linux's DUMPABLE.
+ *
+ * So, proxy these knobs to the corresponding PROC_TRACE setting.
+ */
+ case LINUX_PR_GET_DUMPABLE:
+ error = kern_procctl(td, P_PID, p->p_pid, PROC_TRACE_STATUS,
+ &trace_state);
+ if (error != 0)
+ return (error);
+ td->td_retval[0] = (trace_state != -1);
+ return (0);
+ case LINUX_PR_SET_DUMPABLE:
+ /*
+ * It is only valid for userspace to set one of these two
+ * flags, and only one at a time.
+ */
+ switch (args->arg2) {
+ case LINUX_SUID_DUMP_DISABLE:
+ trace_state = PROC_TRACE_CTL_DISABLE_EXEC;
+ break;
+ case LINUX_SUID_DUMP_USER:
+ trace_state = PROC_TRACE_CTL_ENABLE;
+ break;
+ default:
+ return (EINVAL);
+ }
+ return (kern_procctl(td, P_PID, p->p_pid, PROC_TRACE_CTL,
+ &trace_state));
+ case LINUX_PR_GET_KEEPCAPS:
+ /*
+ * Indicate that we always clear the effective and
+ * permitted capability sets when the user id becomes
+ * non-zero (actually the capability sets are simply
+ * always zero in the current implementation).
+ */
+ td->td_retval[0] = 0;
+ break;
+ case LINUX_PR_SET_KEEPCAPS:
+ /*
+ * Ignore requests to keep the effective and permitted
+ * capability sets when the user id becomes non-zero.
+ */
+ break;
+ case LINUX_PR_SET_NAME:
+ /*
+ * To be on the safe side we need to make sure to not
+ * overflow the size a Linux program expects. We already
+ * do this here in the copyin, so that we don't need to
+ * check on copyout.
+ */
+ max_size = MIN(sizeof(comm), sizeof(p->p_comm));
+ error = copyinstr((void *)(register_t)args->arg2, comm,
+ max_size, NULL);
+
+ /* Linux silently truncates the name if it is too long. */
+ if (error == ENAMETOOLONG) {
+ /*
+ * XXX: copyinstr() isn't documented to populate the
+ * array completely, so do a copyin() to be on the
+ * safe side. This should be changed in case
+ * copyinstr() is changed to guarantee this.
+ */
+ error = copyin((void *)(register_t)args->arg2, comm,
+ max_size - 1);
+ comm[max_size - 1] = '\0';
+ }
+ if (error)
+ return (error);
+
+ PROC_LOCK(p);
+ strlcpy(p->p_comm, comm, sizeof(p->p_comm));
+ PROC_UNLOCK(p);
+ break;
+ case LINUX_PR_GET_NAME:
+ PROC_LOCK(p);
+ strlcpy(comm, p->p_comm, sizeof(comm));
+ PROC_UNLOCK(p);
+ error = copyout(comm, (void *)(register_t)args->arg2,
+ strlen(comm) + 1);
+ break;
+ case LINUX_PR_GET_SECCOMP:
+ case LINUX_PR_SET_SECCOMP:
+ /*
+ * Same as returned by Linux without CONFIG_SECCOMP enabled.
+ */
+ error = EINVAL;
+ break;
+ case LINUX_PR_CAPBSET_READ:
+#if 0
+ /*
+ * This makes too much noise with Ubuntu Focal.
+ */
+ linux_msg(td, "unsupported prctl PR_CAPBSET_READ %d",
+ (int)args->arg2);
+#endif
+ error = EINVAL;
+ break;
+ case LINUX_PR_SET_NO_NEW_PRIVS:
+ linux_msg(td, "unsupported prctl PR_SET_NO_NEW_PRIVS");
+ error = EINVAL;
+ break;
+ case LINUX_PR_SET_PTRACER:
+ linux_msg(td, "unsupported prctl PR_SET_PTRACER");
+ error = EINVAL;
+ break;
+ default:
+ linux_msg(td, "unsupported prctl option %d", args->option);
+ error = EINVAL;
+ break;
+ }
+
+ return (error);
+}
+
+int
+linux_sched_setparam(struct thread *td,
+ struct linux_sched_setparam_args *uap)
+{
+ struct sched_param sched_param;
+ struct thread *tdt;
+ int error, policy;
+
+ error = copyin(uap->param, &sched_param, sizeof(sched_param));
+ if (error)
+ return (error);
+
+ tdt = linux_tdfind(td, uap->pid, -1);
+ if (tdt == NULL)
+ return (ESRCH);
+
+ if (linux_map_sched_prio) {
+ error = kern_sched_getscheduler(td, tdt, &policy);
+ if (error)
+ goto out;
+
+ switch (policy) {
+ case SCHED_OTHER:
+ if (sched_param.sched_priority != 0) {
+ error = EINVAL;
+ goto out;
+ }
+ sched_param.sched_priority =
+ PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE;
+ break;
+ case SCHED_FIFO:
+ case SCHED_RR:
+ if (sched_param.sched_priority < 1 ||
+ sched_param.sched_priority >= LINUX_MAX_RT_PRIO) {
+ error = EINVAL;
+ goto out;
+ }
+ /*
+ * Map [1, LINUX_MAX_RT_PRIO - 1] to
+ * [0, RTP_PRIO_MAX - RTP_PRIO_MIN] (rounding down).
+ */
+ sched_param.sched_priority =
+ (sched_param.sched_priority - 1) *
+ (RTP_PRIO_MAX - RTP_PRIO_MIN + 1) /
+ (LINUX_MAX_RT_PRIO - 1);
+ break;
+ }
+ }
+
+ error = kern_sched_setparam(td, tdt, &sched_param);
+out: PROC_UNLOCK(tdt->td_proc);
+ return (error);
+}
+
+int
+linux_sched_getparam(struct thread *td,
+ struct linux_sched_getparam_args *uap)
+{
+ struct sched_param sched_param;
+ struct thread *tdt;
+ int error, policy;
+
+ tdt = linux_tdfind(td, uap->pid, -1);
+ if (tdt == NULL)
+ return (ESRCH);
+
+ error = kern_sched_getparam(td, tdt, &sched_param);
+ if (error) {
+ PROC_UNLOCK(tdt->td_proc);
+ return (error);
+ }
+
+ if (linux_map_sched_prio) {
+ error = kern_sched_getscheduler(td, tdt, &policy);
+ PROC_UNLOCK(tdt->td_proc);
+ if (error)
+ return (error);
+
+ switch (policy) {
+ case SCHED_OTHER:
+ sched_param.sched_priority = 0;
+ break;
+ case SCHED_FIFO:
+ case SCHED_RR:
+ /*
+ * Map [0, RTP_PRIO_MAX - RTP_PRIO_MIN] to
+ * [1, LINUX_MAX_RT_PRIO - 1] (rounding up).
+ */
+ sched_param.sched_priority =
+ (sched_param.sched_priority *
+ (LINUX_MAX_RT_PRIO - 1) +
+ (RTP_PRIO_MAX - RTP_PRIO_MIN - 1)) /
+ (RTP_PRIO_MAX - RTP_PRIO_MIN) + 1;
+ break;
+ }
+ } else
+ PROC_UNLOCK(tdt->td_proc);
+
+ error = copyout(&sched_param, uap->param, sizeof(sched_param));
+ return (error);
+}
+
+/*
+ * Get affinity of a process.
+ */
+int
+linux_sched_getaffinity(struct thread *td,
+ struct linux_sched_getaffinity_args *args)
+{
+ int error;
+ struct thread *tdt;
+
+ if (args->len < sizeof(cpuset_t))
+ return (EINVAL);
+
+ tdt = linux_tdfind(td, args->pid, -1);
+ if (tdt == NULL)
+ return (ESRCH);
+
+ PROC_UNLOCK(tdt->td_proc);
+
+ error = kern_cpuset_getaffinity(td, CPU_LEVEL_WHICH, CPU_WHICH_TID,
+ tdt->td_tid, sizeof(cpuset_t), (cpuset_t *)args->user_mask_ptr);
+ if (error == 0)
+ td->td_retval[0] = sizeof(cpuset_t);
+
+ return (error);
+}
+
+/*
+ * Set affinity of a process.
+ */
+int
+linux_sched_setaffinity(struct thread *td,
+ struct linux_sched_setaffinity_args *args)
+{
+ struct thread *tdt;
+
+ if (args->len < sizeof(cpuset_t))
+ return (EINVAL);
+
+ tdt = linux_tdfind(td, args->pid, -1);
+ if (tdt == NULL)
+ return (ESRCH);
+
+ PROC_UNLOCK(tdt->td_proc);
+
+ return (kern_cpuset_setaffinity(td, CPU_LEVEL_WHICH, CPU_WHICH_TID,
+ tdt->td_tid, sizeof(cpuset_t), (cpuset_t *) args->user_mask_ptr));
+}
+
+struct linux_rlimit64 {
+ uint64_t rlim_cur;
+ uint64_t rlim_max;
+};
+
+int
+linux_prlimit64(struct thread *td, struct linux_prlimit64_args *args)
+{
+ struct rlimit rlim, nrlim;
+ struct linux_rlimit64 lrlim;
+ struct proc *p;
+ u_int which;
+ int flags;
+ int error;
+
+ if (args->new == NULL && args->old != NULL) {
+ if (linux_get_dummy_limit(args->resource, &rlim)) {
+ lrlim.rlim_cur = rlim.rlim_cur;
+ lrlim.rlim_max = rlim.rlim_max;
+ return (copyout(&lrlim, args->old, sizeof(lrlim)));
+ }
+ }
+
+ if (args->resource >= LINUX_RLIM_NLIMITS)
+ return (EINVAL);
+
+ which = linux_to_bsd_resource[args->resource];
+ if (which == -1)
+ return (EINVAL);
+
+ if (args->new != NULL) {
+ /*
+ * Note. Unlike FreeBSD where rlim is signed 64-bit Linux
+ * rlim is unsigned 64-bit. FreeBSD treats negative limits
+ * as INFINITY so we do not need a conversion even.
+ */
+ error = copyin(args->new, &nrlim, sizeof(nrlim));
+ if (error != 0)
+ return (error);
+ }
+
+ flags = PGET_HOLD | PGET_NOTWEXIT;
+ if (args->new != NULL)
+ flags |= PGET_CANDEBUG;
+ else
+ flags |= PGET_CANSEE;
+ if (args->pid == 0) {
+ p = td->td_proc;
+ PHOLD(p);
+ } else {
+ error = pget(args->pid, flags, &p);
+ if (error != 0)
+ return (error);
+ }
+ if (args->old != NULL) {
+ PROC_LOCK(p);
+ lim_rlimit_proc(p, which, &rlim);
+ PROC_UNLOCK(p);
+ if (rlim.rlim_cur == RLIM_INFINITY)
+ lrlim.rlim_cur = LINUX_RLIM_INFINITY;
+ else
+ lrlim.rlim_cur = rlim.rlim_cur;
+ if (rlim.rlim_max == RLIM_INFINITY)
+ lrlim.rlim_max = LINUX_RLIM_INFINITY;
+ else
+ lrlim.rlim_max = rlim.rlim_max;
+ error = copyout(&lrlim, args->old, sizeof(lrlim));
+ if (error != 0)
+ goto out;
+ }
+
+ if (args->new != NULL)
+ error = kern_proc_setrlimit(td, p, which, &nrlim);
+
+ out:
+ PRELE(p);
+ return (error);
+}
+
+int
+linux_pselect6(struct thread *td, struct linux_pselect6_args *args)
+{
+ struct timeval utv, tv0, tv1, *tvp;
+ struct l_pselect6arg lpse6;
+ struct l_timespec lts;
+ struct timespec uts;
+ l_sigset_t l_ss;
+ sigset_t *ssp;
+ sigset_t ss;
+ int error;
+
+ ssp = NULL;
+ if (args->sig != NULL) {
+ error = copyin(args->sig, &lpse6, sizeof(lpse6));
+ if (error != 0)
+ return (error);
+ if (lpse6.ss_len != sizeof(l_ss))
+ return (EINVAL);
+ if (lpse6.ss != 0) {
+ error = copyin(PTRIN(lpse6.ss), &l_ss,
+ sizeof(l_ss));
+ if (error != 0)
+ return (error);
+ linux_to_bsd_sigset(&l_ss, &ss);
+ ssp = &ss;
+ }
+ }
+
+ /*
+ * Currently glibc changes nanosecond number to microsecond.
+ * This mean losing precision but for now it is hardly seen.
+ */
+ if (args->tsp != NULL) {
+ error = copyin(args->tsp, &lts, sizeof(lts));
+ if (error != 0)
+ return (error);
+ error = linux_to_native_timespec(&uts, &lts);
+ if (error != 0)
+ return (error);
+
+ TIMESPEC_TO_TIMEVAL(&utv, &uts);
+ if (itimerfix(&utv))
+ return (EINVAL);
+
+ microtime(&tv0);
+ tvp = &utv;
+ } else
+ tvp = NULL;
+
+ error = kern_pselect(td, args->nfds, args->readfds, args->writefds,
+ args->exceptfds, tvp, ssp, LINUX_NFDBITS);
+
+ if (error == 0 && args->tsp != NULL) {
+ if (td->td_retval[0] != 0) {
+ /*
+ * Compute how much time was left of the timeout,
+ * by subtracting the current time and the time
+ * before we started the call, and subtracting
+ * that result from the user-supplied value.
+ */
+
+ microtime(&tv1);
+ timevalsub(&tv1, &tv0);
+ timevalsub(&utv, &tv1);
+ if (utv.tv_sec < 0)
+ timevalclear(&utv);
+ } else
+ timevalclear(&utv);
+
+ TIMEVAL_TO_TIMESPEC(&utv, &uts);
+
+ error = native_to_linux_timespec(&lts, &uts);
+ if (error == 0)
+ error = copyout(&lts, args->tsp, sizeof(lts));
+ }
+
+ return (error);
+}
+
+int
+linux_ppoll(struct thread *td, struct linux_ppoll_args *args)
+{
+ struct timespec ts0, ts1;
+ struct l_timespec lts;
+ struct timespec uts, *tsp;
+ l_sigset_t l_ss;
+ sigset_t *ssp;
+ sigset_t ss;
+ int error;
+
+ if (args->sset != NULL) {
+ if (args->ssize != sizeof(l_ss))
+ return (EINVAL);
+ error = copyin(args->sset, &l_ss, sizeof(l_ss));
+ if (error)
+ return (error);
+ linux_to_bsd_sigset(&l_ss, &ss);
+ ssp = &ss;
+ } else
+ ssp = NULL;
+ if (args->tsp != NULL) {
+ error = copyin(args->tsp, &lts, sizeof(lts));
+ if (error)
+ return (error);
+ error = linux_to_native_timespec(&uts, &lts);
+ if (error != 0)
+ return (error);
+
+ nanotime(&ts0);
+ tsp = &uts;
+ } else
+ tsp = NULL;
+
+ error = kern_poll(td, args->fds, args->nfds, tsp, ssp);
+
+ if (error == 0 && args->tsp != NULL) {
+ if (td->td_retval[0]) {
+ nanotime(&ts1);
+ timespecsub(&ts1, &ts0, &ts1);
+ timespecsub(&uts, &ts1, &uts);
+ if (uts.tv_sec < 0)
+ timespecclear(&uts);
+ } else
+ timespecclear(&uts);
+
+ error = native_to_linux_timespec(&lts, &uts);
+ if (error == 0)
+ error = copyout(&lts, args->tsp, sizeof(lts));
+ }
+
+ return (error);
+}
+
+int
+linux_sched_rr_get_interval(struct thread *td,
+ struct linux_sched_rr_get_interval_args *uap)
+{
+ struct timespec ts;
+ struct l_timespec lts;
+ struct thread *tdt;
+ int error;
+
+ /*
+ * According to man in case the invalid pid specified
+ * EINVAL should be returned.
+ */
+ if (uap->pid < 0)
+ return (EINVAL);
+
+ tdt = linux_tdfind(td, uap->pid, -1);
+ if (tdt == NULL)
+ return (ESRCH);
+
+ error = kern_sched_rr_get_interval_td(td, tdt, &ts);
+ PROC_UNLOCK(tdt->td_proc);
+ if (error != 0)
+ return (error);
+ error = native_to_linux_timespec(&lts, &ts);
+ if (error != 0)
+ return (error);
+ return (copyout(&lts, uap->interval, sizeof(lts)));
+}
+
+/*
+ * In case when the Linux thread is the initial thread in
+ * the thread group thread id is equal to the process id.
+ * Glibc depends on this magic (assert in pthread_getattr_np.c).
+ */
+struct thread *
+linux_tdfind(struct thread *td, lwpid_t tid, pid_t pid)
+{
+ struct linux_emuldata *em;
+ struct thread *tdt;
+ struct proc *p;
+
+ tdt = NULL;
+ if (tid == 0 || tid == td->td_tid) {
+ tdt = td;
+ PROC_LOCK(tdt->td_proc);
+ } else if (tid > PID_MAX)
+ tdt = tdfind(tid, pid);
+ else {
+ /*
+ * Initial thread where the tid equal to the pid.
+ */
+ p = pfind(tid);
+ if (p != NULL) {
+ if (SV_PROC_ABI(p) != SV_ABI_LINUX) {
+ /*
+ * p is not a Linuxulator process.
+ */
+ PROC_UNLOCK(p);
+ return (NULL);
+ }
+ FOREACH_THREAD_IN_PROC(p, tdt) {
+ em = em_find(tdt);
+ if (tid == em->em_tid)
+ return (tdt);
+ }
+ PROC_UNLOCK(p);
+ }
+ return (NULL);
+ }
+
+ return (tdt);
+}
+
+void
+linux_to_bsd_waitopts(int options, int *bsdopts)
+{
+
+ if (options & LINUX_WNOHANG)
+ *bsdopts |= WNOHANG;
+ if (options & LINUX_WUNTRACED)
+ *bsdopts |= WUNTRACED;
+ if (options & LINUX_WEXITED)
+ *bsdopts |= WEXITED;
+ if (options & LINUX_WCONTINUED)
+ *bsdopts |= WCONTINUED;
+ if (options & LINUX_WNOWAIT)
+ *bsdopts |= WNOWAIT;
+
+ if (options & __WCLONE)
+ *bsdopts |= WLINUXCLONE;
+}
+
+int
+linux_getrandom(struct thread *td, struct linux_getrandom_args *args)
+{
+ struct uio uio;
+ struct iovec iov;
+ int error;
+
+ if (args->flags & ~(LINUX_GRND_NONBLOCK|LINUX_GRND_RANDOM))
+ return (EINVAL);
+ if (args->count > INT_MAX)
+ args->count = INT_MAX;
+
+ iov.iov_base = args->buf;
+ iov.iov_len = args->count;
+
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_resid = iov.iov_len;
+ uio.uio_segflg = UIO_USERSPACE;
+ uio.uio_rw = UIO_READ;
+ uio.uio_td = td;
+
+ error = read_random_uio(&uio, args->flags & LINUX_GRND_NONBLOCK);
+ if (error == 0)
+ td->td_retval[0] = args->count - uio.uio_resid;
+ return (error);
+}
+
+int
+linux_mincore(struct thread *td, struct linux_mincore_args *args)
+{
+
+ /* Needs to be page-aligned */
+ if (args->start & PAGE_MASK)
+ return (EINVAL);
+ return (kern_mincore(td, args->start, args->len, args->vec));
+}
+
+#define SYSLOG_TAG "<6>"
+
+int
+linux_syslog(struct thread *td, struct linux_syslog_args *args)
+{
+ char buf[128], *src, *dst;
+ u_int seq;
+ int buflen, error;
+
+ if (args->type != LINUX_SYSLOG_ACTION_READ_ALL) {
+ linux_msg(td, "syslog unsupported type 0x%x", args->type);
+ return (EINVAL);
+ }
+
+ if (args->len < 6) {
+ td->td_retval[0] = 0;
+ return (0);
+ }
+
+ error = priv_check(td, PRIV_MSGBUF);
+ if (error)
+ return (error);
+
+ mtx_lock(&msgbuf_lock);
+ msgbuf_peekbytes(msgbufp, NULL, 0, &seq);
+ mtx_unlock(&msgbuf_lock);
+
+ dst = args->buf;
+ error = copyout(&SYSLOG_TAG, dst, sizeof(SYSLOG_TAG));
+ /* The -1 is to skip the trailing '\0'. */
+ dst += sizeof(SYSLOG_TAG) - 1;
+
+ while (error == 0) {
+ mtx_lock(&msgbuf_lock);
+ buflen = msgbuf_peekbytes(msgbufp, buf, sizeof(buf), &seq);
+ mtx_unlock(&msgbuf_lock);
+
+ if (buflen == 0)
+ break;
+
+ for (src = buf; src < buf + buflen && error == 0; src++) {
+ if (*src == '\0')
+ continue;
+
+ if (dst >= args->buf + args->len)
+ goto out;
+
+ error = copyout(src, dst, 1);
+ dst++;
+
+ if (*src == '\n' && *(src + 1) != '<' &&
+ dst + sizeof(SYSLOG_TAG) < args->buf + args->len) {
+ error = copyout(&SYSLOG_TAG,
+ dst, sizeof(SYSLOG_TAG));
+ dst += sizeof(SYSLOG_TAG) - 1;
+ }
+ }
+ }
+out:
+ td->td_retval[0] = dst - args->buf;
+ return (error);
+}
+
+int
+linux_getcpu(struct thread *td, struct linux_getcpu_args *args)
+{
+ int cpu, error, node;
+
+ cpu = td->td_oncpu; /* Make sure it doesn't change during copyout(9) */
+ error = 0;
+ node = cpuid_to_pcpu[cpu]->pc_domain;
+
+ if (args->cpu != NULL)
+ error = copyout(&cpu, args->cpu, sizeof(l_int));
+ if (args->node != NULL)
+ error = copyout(&node, args->node, sizeof(l_int));
+ return (error);
+}
diff --git a/sys/compat/linux/linux_misc.h b/sys/compat/linux/linux_misc.h
new file mode 100644
index 000000000000..c7e4fa38682c
--- /dev/null
+++ b/sys/compat/linux/linux_misc.h
@@ -0,0 +1,188 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2006 Roman Divacky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_MISC_H_
+#define _LINUX_MISC_H_
+
+#include <sys/sysctl.h>
+
+ /* bits per mask */
+#define LINUX_NFDBITS sizeof(l_fd_mask) * 8
+
+/*
+ * Miscellaneous
+ */
+#define LINUX_NAME_MAX 255
+#define LINUX_MAX_UTSNAME 65
+
+#define LINUX_CTL_MAXNAME 10
+
+/* defines for prctl */
+#define LINUX_PR_SET_PDEATHSIG 1 /* Second arg is a signal. */
+#define LINUX_PR_GET_PDEATHSIG 2 /*
+ * Second arg is a ptr to return the
+ * signal.
+ */
+#define LINUX_PR_GET_DUMPABLE 3
+#define LINUX_PR_SET_DUMPABLE 4
+#define LINUX_PR_GET_KEEPCAPS 7 /* Get drop capabilities on setuid */
+#define LINUX_PR_SET_KEEPCAPS 8 /* Set drop capabilities on setuid */
+#define LINUX_PR_SET_NAME 15 /* Set process name. */
+#define LINUX_PR_GET_NAME 16 /* Get process name. */
+#define LINUX_PR_GET_SECCOMP 21
+#define LINUX_PR_SET_SECCOMP 22
+#define LINUX_PR_CAPBSET_READ 23
+#define LINUX_PR_SET_NO_NEW_PRIVS 38
+#define LINUX_PR_SET_PTRACER 1499557217
+
+#define LINUX_MAX_COMM_LEN 16 /* Maximum length of the process name. */
+
+/* For GET/SET DUMPABLE */
+#define LINUX_SUID_DUMP_DISABLE 0 /* Don't coredump setuid processes. */
+#define LINUX_SUID_DUMP_USER 1 /* Dump as user of process. */
+#define LINUX_SUID_DUMP_ROOT 2 /* Dump as root. */
+
+#define LINUX_MREMAP_MAYMOVE 1
+#define LINUX_MREMAP_FIXED 2
+
+#define LINUX_PATH_MAX 4096
+
+extern const char *linux_kplatform;
+
+/*
+ * Non-standard aux entry types used in Linux ELF binaries.
+ */
+
+#define LINUX_AT_PLATFORM 15 /* String identifying CPU */
+#define LINUX_AT_HWCAP 16 /* CPU capabilities */
+#define LINUX_AT_CLKTCK 17 /* frequency at which times() increments */
+#define LINUX_AT_SECURE 23 /* secure mode boolean */
+#define LINUX_AT_BASE_PLATFORM 24 /* string identifying real platform, may
+ * differ from AT_PLATFORM.
+ */
+#define LINUX_AT_RANDOM 25 /* address of random bytes */
+#define LINUX_AT_EXECFN 31 /* filename of program */
+#define LINUX_AT_SYSINFO 32 /* vsyscall */
+#define LINUX_AT_SYSINFO_EHDR 33 /* vdso header */
+
+#define LINUX_AT_RANDOM_LEN 16 /* size of random bytes */
+
+/* Linux sets the i387 to extended precision. */
+#if defined(__i386__) || defined(__amd64__)
+#define __LINUX_NPXCW__ 0x37f
+#endif
+
+#define LINUX_CLONE_VM 0x00000100
+#define LINUX_CLONE_FS 0x00000200
+#define LINUX_CLONE_FILES 0x00000400
+#define LINUX_CLONE_SIGHAND 0x00000800
+#define LINUX_CLONE_PID 0x00001000 /* No longer exist in Linux */
+#define LINUX_CLONE_PTRACE 0x00002000
+#define LINUX_CLONE_VFORK 0x00004000
+#define LINUX_CLONE_PARENT 0x00008000
+#define LINUX_CLONE_THREAD 0x00010000
+#define LINUX_CLONE_NEWNS 0x00020000 /* New mount NS */
+#define LINUX_CLONE_SYSVSEM 0x00040000
+#define LINUX_CLONE_SETTLS 0x00080000
+#define LINUX_CLONE_PARENT_SETTID 0x00100000
+#define LINUX_CLONE_CHILD_CLEARTID 0x00200000
+#define LINUX_CLONE_DETACHED 0x00400000 /* Unused */
+#define LINUX_CLONE_UNTRACED 0x00800000
+#define LINUX_CLONE_CHILD_SETTID 0x01000000
+#define LINUX_CLONE_NEWCGROUP 0x02000000 /* New cgroup NS */
+#define LINUX_CLONE_NEWUTS 0x04000000
+#define LINUX_CLONE_NEWIPC 0x08000000
+#define LINUX_CLONE_NEWUSER 0x10000000
+#define LINUX_CLONE_NEWPID 0x20000000
+#define LINUX_CLONE_NEWNET 0x40000000
+#define LINUX_CLONE_IO 0x80000000
+
+/* Scheduling policies */
+#define LINUX_SCHED_OTHER 0
+#define LINUX_SCHED_FIFO 1
+#define LINUX_SCHED_RR 2
+
+#define LINUX_MAX_RT_PRIO 100
+
+struct l_new_utsname {
+ char sysname[LINUX_MAX_UTSNAME];
+ char nodename[LINUX_MAX_UTSNAME];
+ char release[LINUX_MAX_UTSNAME];
+ char version[LINUX_MAX_UTSNAME];
+ char machine[LINUX_MAX_UTSNAME];
+ char domainname[LINUX_MAX_UTSNAME];
+};
+
+#define LINUX_UTIME_NOW 0x3FFFFFFF
+#define LINUX_UTIME_OMIT 0x3FFFFFFE
+
+extern int stclohz;
+
+#define LINUX_WNOHANG 0x00000001
+#define LINUX_WUNTRACED 0x00000002
+#define LINUX_WSTOPPED LINUX_WUNTRACED
+#define LINUX_WEXITED 0x00000004
+#define LINUX_WCONTINUED 0x00000008
+#define LINUX_WNOWAIT 0x01000000
+
+#define __WNOTHREAD 0x20000000
+#define __WALL 0x40000000
+#define __WCLONE 0x80000000
+
+/* Linux waitid idtype */
+#define LINUX_P_ALL 0
+#define LINUX_P_PID 1
+#define LINUX_P_PGID 2
+
+#define LINUX_RLIMIT_LOCKS 10
+#define LINUX_RLIMIT_SIGPENDING 11
+#define LINUX_RLIMIT_MSGQUEUE 12
+#define LINUX_RLIMIT_NICE 13
+#define LINUX_RLIMIT_RTPRIO 14
+#define LINUX_RLIMIT_RTTIME 15
+
+#define LINUX_RLIM_INFINITY (~0UL)
+
+/* Linux getrandom flags */
+#define LINUX_GRND_NONBLOCK 0x0001
+#define LINUX_GRND_RANDOM 0x0002
+
+/* Linux syslog flags */
+#define LINUX_SYSLOG_ACTION_READ_ALL 3
+
+#if defined(__amd64__) && !defined(COMPAT_LINUX32)
+int linux_ptrace_status(struct thread *td, int pid, int status);
+#endif
+void linux_to_bsd_waitopts(int options, int *bsdopts);
+int linux_set_upcall_kse(struct thread *td, register_t stack);
+int linux_set_cloned_tls(struct thread *td, void *desc);
+struct thread *linux_tdfind(struct thread *, lwpid_t, pid_t);
+
+#endif /* _LINUX_MISC_H_ */
diff --git a/sys/compat/linux/linux_mmap.c b/sys/compat/linux/linux_mmap.c
new file mode 100644
index 000000000000..d7f12b782e96
--- /dev/null
+++ b/sys/compat/linux/linux_mmap.c
@@ -0,0 +1,426 @@
+/*-
+ * Copyright (c) 2004 Tim J. Robbins
+ * Copyright (c) 2002 Doug Rabson
+ * Copyright (c) 2000 Marcel Moolenaar
+ * Copyright (c) 1994-1995 Søren Schmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/capsicum.h>
+#include <sys/file.h>
+#include <sys/imgact.h>
+#include <sys/ktr.h>
+#include <sys/lock.h>
+#include <sys/mman.h>
+#include <sys/proc.h>
+#include <sys/resourcevar.h>
+#include <sys/rwlock.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+
+#include <compat/linux/linux_emul.h>
+#include <compat/linux/linux_mmap.h>
+#include <compat/linux/linux_persona.h>
+#include <compat/linux/linux_util.h>
+
+#define STACK_SIZE (2 * 1024 * 1024)
+#define GUARD_SIZE (4 * PAGE_SIZE)
+
+#if defined(__amd64__)
+static void linux_fixup_prot(struct thread *td, int *prot);
+#endif
+
+static int
+linux_mmap_check_fp(struct file *fp, int flags, int prot, int maxprot)
+{
+
+ /* Linux mmap() just fails for O_WRONLY files */
+ if ((fp->f_flag & FREAD) == 0)
+ return (EACCES);
+
+ return (0);
+}
+
+int
+linux_mmap_common(struct thread *td, uintptr_t addr, size_t len, int prot,
+ int flags, int fd, off_t pos)
+{
+ struct mmap_req mr, mr_fixed;
+ struct proc *p = td->td_proc;
+ struct vmspace *vms = td->td_proc->p_vmspace;
+ int bsd_flags, error;
+ struct file *fp;
+
+ LINUX_CTR6(mmap2, "0x%lx, %ld, %ld, 0x%08lx, %ld, 0x%lx",
+ addr, len, prot, flags, fd, pos);
+
+ error = 0;
+ bsd_flags = 0;
+ fp = NULL;
+
+ /*
+ * Linux mmap(2):
+ * You must specify exactly one of MAP_SHARED and MAP_PRIVATE
+ */
+ if (!((flags & LINUX_MAP_SHARED) ^ (flags & LINUX_MAP_PRIVATE)))
+ return (EINVAL);
+
+ if (flags & LINUX_MAP_SHARED)
+ bsd_flags |= MAP_SHARED;
+ if (flags & LINUX_MAP_PRIVATE)
+ bsd_flags |= MAP_PRIVATE;
+ if (flags & LINUX_MAP_FIXED)
+ bsd_flags |= MAP_FIXED;
+ if (flags & LINUX_MAP_ANON) {
+ /* Enforce pos to be on page boundary, then ignore. */
+ if ((pos & PAGE_MASK) != 0)
+ return (EINVAL);
+ pos = 0;
+ bsd_flags |= MAP_ANON;
+ } else
+ bsd_flags |= MAP_NOSYNC;
+ if (flags & LINUX_MAP_GROWSDOWN)
+ bsd_flags |= MAP_STACK;
+
+#if defined(__amd64__)
+ /*
+ * According to the Linux mmap(2) man page, "MAP_32BIT flag
+ * is ignored when MAP_FIXED is set."
+ */
+ if ((flags & LINUX_MAP_32BIT) && (flags & LINUX_MAP_FIXED) == 0)
+ bsd_flags |= MAP_32BIT;
+
+ /*
+ * PROT_READ, PROT_WRITE, or PROT_EXEC implies PROT_READ and PROT_EXEC
+ * on Linux/i386 if the binary requires executable stack.
+ * We do this only for IA32 emulation as on native i386 this is does not
+ * make sense without PAE.
+ *
+ * XXX. Linux checks that the file system is not mounted with noexec.
+ */
+ linux_fixup_prot(td, &prot);
+#endif
+
+ /* Linux does not check file descriptor when MAP_ANONYMOUS is set. */
+ fd = (bsd_flags & MAP_ANON) ? -1 : fd;
+ if (flags & LINUX_MAP_GROWSDOWN) {
+ /*
+ * The Linux MAP_GROWSDOWN option does not limit auto
+ * growth of the region. Linux mmap with this option
+ * takes as addr the initial BOS, and as len, the initial
+ * region size. It can then grow down from addr without
+ * limit. However, Linux threads has an implicit internal
+ * limit to stack size of STACK_SIZE. Its just not
+ * enforced explicitly in Linux. But, here we impose
+ * a limit of (STACK_SIZE - GUARD_SIZE) on the stack
+ * region, since we can do this with our mmap.
+ *
+ * Our mmap with MAP_STACK takes addr as the maximum
+ * downsize limit on BOS, and as len the max size of
+ * the region. It then maps the top SGROWSIZ bytes,
+ * and auto grows the region down, up to the limit
+ * in addr.
+ *
+ * If we don't use the MAP_STACK option, the effect
+ * of this code is to allocate a stack region of a
+ * fixed size of (STACK_SIZE - GUARD_SIZE).
+ */
+
+ if ((caddr_t)addr + len > vms->vm_maxsaddr) {
+ /*
+ * Some Linux apps will attempt to mmap
+ * thread stacks near the top of their
+ * address space. If their TOS is greater
+ * than vm_maxsaddr, vm_map_growstack()
+ * will confuse the thread stack with the
+ * process stack and deliver a SEGV if they
+ * attempt to grow the thread stack past their
+ * current stacksize rlimit. To avoid this,
+ * adjust vm_maxsaddr upwards to reflect
+ * the current stacksize rlimit rather
+ * than the maximum possible stacksize.
+ * It would be better to adjust the
+ * mmap'ed region, but some apps do not check
+ * mmap's return value.
+ */
+ PROC_LOCK(p);
+ vms->vm_maxsaddr = (char *)p->p_sysent->sv_usrstack -
+ lim_cur_proc(p, RLIMIT_STACK);
+ PROC_UNLOCK(p);
+ }
+
+ /*
+ * This gives us our maximum stack size and a new BOS.
+ * If we're using VM_STACK, then mmap will just map
+ * the top SGROWSIZ bytes, and let the stack grow down
+ * to the limit at BOS. If we're not using VM_STACK
+ * we map the full stack, since we don't have a way
+ * to autogrow it.
+ */
+ if (len <= STACK_SIZE - GUARD_SIZE) {
+ addr = addr - (STACK_SIZE - GUARD_SIZE - len);
+ len = STACK_SIZE - GUARD_SIZE;
+ }
+ }
+
+ /*
+ * FreeBSD is free to ignore the address hint if MAP_FIXED wasn't
+ * passed. However, some Linux applications, like the ART runtime,
+ * depend on the hint. If the MAP_FIXED wasn't passed, but the
+ * address is not zero, try with MAP_FIXED and MAP_EXCL first,
+ * and fall back to the normal behaviour if that fails.
+ */
+ mr = (struct mmap_req) {
+ .mr_hint = addr,
+ .mr_len = len,
+ .mr_prot = prot,
+ .mr_flags = bsd_flags,
+ .mr_fd = fd,
+ .mr_pos = pos,
+ .mr_check_fp_fn = linux_mmap_check_fp,
+ };
+ if (addr != 0 && (bsd_flags & MAP_FIXED) == 0 &&
+ (bsd_flags & MAP_EXCL) == 0) {
+ mr_fixed = mr;
+ mr_fixed.mr_flags |= MAP_FIXED | MAP_EXCL;
+ error = kern_mmap(td, &mr_fixed);
+ if (error == 0)
+ goto out;
+ }
+
+ error = kern_mmap(td, &mr);
+out:
+ LINUX_CTR2(mmap2, "return: %d (%p)", error, td->td_retval[0]);
+
+ return (error);
+}
+
+int
+linux_mprotect_common(struct thread *td, uintptr_t addr, size_t len, int prot)
+{
+
+ /* XXX Ignore PROT_GROWSDOWN and PROT_GROWSUP for now. */
+ prot &= ~(LINUX_PROT_GROWSDOWN | LINUX_PROT_GROWSUP);
+ if ((prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) != 0)
+ return (EINVAL);
+
+#if defined(__amd64__)
+ linux_fixup_prot(td, &prot);
+#endif
+ return (kern_mprotect(td, addr, len, prot));
+}
+
+/*
+ * Implement Linux madvise(MADV_DONTNEED), which has unusual semantics: for
+ * anonymous memory, pages in the range are immediately discarded.
+ */
+static int
+linux_madvise_dontneed(struct thread *td, vm_offset_t start, vm_offset_t end)
+{
+ vm_map_t map;
+ vm_map_entry_t entry;
+ vm_object_t backing_object, object;
+ vm_offset_t estart, eend;
+ vm_pindex_t pstart, pend;
+ int error;
+
+ map = &td->td_proc->p_vmspace->vm_map;
+
+ if (!vm_map_range_valid(map, start, end))
+ return (EINVAL);
+ start = trunc_page(start);
+ end = round_page(end);
+
+ error = 0;
+ vm_map_lock_read(map);
+ if (!vm_map_lookup_entry(map, start, &entry))
+ entry = vm_map_entry_succ(entry);
+ for (; entry->start < end; entry = vm_map_entry_succ(entry)) {
+ if ((entry->eflags & MAP_ENTRY_IS_SUB_MAP) != 0)
+ continue;
+
+ if (entry->wired_count != 0) {
+ error = EINVAL;
+ break;
+ }
+
+ object = entry->object.vm_object;
+ if (object == NULL)
+ continue;
+ if ((object->flags & (OBJ_UNMANAGED | OBJ_FICTITIOUS)) != 0)
+ continue;
+
+ pstart = OFF_TO_IDX(entry->offset);
+ if (start > entry->start) {
+ pstart += atop(start - entry->start);
+ estart = start;
+ } else {
+ estart = entry->start;
+ }
+ pend = OFF_TO_IDX(entry->offset) +
+ atop(entry->end - entry->start);
+ if (entry->end > end) {
+ pend -= atop(entry->end - end);
+ eend = end;
+ } else {
+ eend = entry->end;
+ }
+
+ if ((object->flags & (OBJ_ANON | OBJ_ONEMAPPING)) ==
+ (OBJ_ANON | OBJ_ONEMAPPING)) {
+ /*
+ * Singly-mapped anonymous memory is discarded. This
+ * does not match Linux's semantics when the object
+ * belongs to a shadow chain of length > 1, since
+ * subsequent faults may retrieve pages from an
+ * intermediate anonymous object. However, handling
+ * this case correctly introduces a fair bit of
+ * complexity.
+ */
+ VM_OBJECT_WLOCK(object);
+ if ((object->flags & OBJ_ONEMAPPING) != 0) {
+ vm_object_collapse(object);
+ vm_object_page_remove(object, pstart, pend, 0);
+ backing_object = object->backing_object;
+ if (backing_object != NULL &&
+ (backing_object->flags & OBJ_ANON) != 0)
+ linux_msg(td,
+ "possibly incorrect MADV_DONTNEED");
+ VM_OBJECT_WUNLOCK(object);
+ continue;
+ }
+ VM_OBJECT_WUNLOCK(object);
+ }
+
+ /*
+ * Handle shared mappings. Remove them outright instead of
+ * calling pmap_advise(), for consistency with Linux.
+ */
+ pmap_remove(map->pmap, estart, eend);
+ vm_object_madvise(object, pstart, pend, MADV_DONTNEED);
+ }
+ vm_map_unlock_read(map);
+
+ return (error);
+}
+
+int
+linux_madvise_common(struct thread *td, uintptr_t addr, size_t len, int behav)
+{
+
+ switch (behav) {
+ case LINUX_MADV_NORMAL:
+ return (kern_madvise(td, addr, len, MADV_NORMAL));
+ case LINUX_MADV_RANDOM:
+ return (kern_madvise(td, addr, len, MADV_RANDOM));
+ case LINUX_MADV_SEQUENTIAL:
+ return (kern_madvise(td, addr, len, MADV_SEQUENTIAL));
+ case LINUX_MADV_WILLNEED:
+ return (kern_madvise(td, addr, len, MADV_WILLNEED));
+ case LINUX_MADV_DONTNEED:
+ return (linux_madvise_dontneed(td, addr, addr + len));
+ case LINUX_MADV_FREE:
+ return (kern_madvise(td, addr, len, MADV_FREE));
+ case LINUX_MADV_REMOVE:
+ linux_msg(curthread, "unsupported madvise MADV_REMOVE");
+ return (EINVAL);
+ case LINUX_MADV_DONTFORK:
+ return (kern_minherit(td, addr, len, INHERIT_NONE));
+ case LINUX_MADV_DOFORK:
+ return (kern_minherit(td, addr, len, INHERIT_COPY));
+ case LINUX_MADV_MERGEABLE:
+ linux_msg(curthread, "unsupported madvise MADV_MERGEABLE");
+ return (EINVAL);
+ case LINUX_MADV_UNMERGEABLE:
+ /* We don't merge anyway. */
+ return (0);
+ case LINUX_MADV_HUGEPAGE:
+ /* Ignored; on FreeBSD huge pages are always on. */
+ return (0);
+ case LINUX_MADV_NOHUGEPAGE:
+#if 0
+ /*
+ * Don't warn - Firefox uses it a lot, and in real Linux it's
+ * an optional feature.
+ */
+ linux_msg(curthread, "unsupported madvise MADV_NOHUGEPAGE");
+#endif
+ return (EINVAL);
+ case LINUX_MADV_DONTDUMP:
+ return (kern_madvise(td, addr, len, MADV_NOCORE));
+ case LINUX_MADV_DODUMP:
+ return (kern_madvise(td, addr, len, MADV_CORE));
+ case LINUX_MADV_WIPEONFORK:
+ return (kern_minherit(td, addr, len, INHERIT_ZERO));
+ case LINUX_MADV_KEEPONFORK:
+ return (kern_minherit(td, addr, len, INHERIT_COPY));
+ case LINUX_MADV_HWPOISON:
+ linux_msg(curthread, "unsupported madvise MADV_HWPOISON");
+ return (EINVAL);
+ case LINUX_MADV_SOFT_OFFLINE:
+ linux_msg(curthread, "unsupported madvise MADV_SOFT_OFFLINE");
+ return (EINVAL);
+ case -1:
+ /*
+ * -1 is sometimes used as a dummy value to detect simplistic
+ * madvise(2) stub implementations. This safeguard is used by
+ * BoringSSL, for example, before assuming MADV_WIPEONFORK is
+ * safe to use. Don't produce an "unsupported" error message
+ * for this special dummy value, which is unlikely to be used
+ * by any new advisory behavior feature.
+ */
+ return (EINVAL);
+ default:
+ linux_msg(curthread, "unsupported madvise behav %d", behav);
+ return (EINVAL);
+ }
+}
+
+#if defined(__amd64__)
+static void
+linux_fixup_prot(struct thread *td, int *prot)
+{
+ struct linux_pemuldata *pem;
+
+ if (SV_PROC_FLAG(td->td_proc, SV_ILP32) && *prot & PROT_READ) {
+ pem = pem_find(td->td_proc);
+ if (pem->persona & LINUX_READ_IMPLIES_EXEC)
+ *prot |= PROT_EXEC;
+ }
+
+}
+#endif
diff --git a/sys/compat/linux/linux_mmap.h b/sys/compat/linux/linux_mmap.h
new file mode 100644
index 000000000000..3bedc2102f5f
--- /dev/null
+++ b/sys/compat/linux/linux_mmap.h
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 2004 Tim J. Robbins
+ * Copyright (c) 2002 Doug Rabson
+ * Copyright (c) 2000 Marcel Moolenaar
+ * Copyright (c) 1994-1995 Søren Schmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_MMAP_H_
+#define _LINUX_MMAP_H_
+
+/* mmap options */
+#define LINUX_MAP_SHARED 0x0001
+#define LINUX_MAP_PRIVATE 0x0002
+#define LINUX_MAP_FIXED 0x0010
+#define LINUX_MAP_ANON 0x0020
+#define LINUX_MAP_32BIT 0x0040
+#define LINUX_MAP_GROWSDOWN 0x0100
+
+#define LINUX_PROT_GROWSDOWN 0x01000000
+#define LINUX_PROT_GROWSUP 0x02000000
+
+#define LINUX_MADV_NORMAL 0
+#define LINUX_MADV_RANDOM 1
+#define LINUX_MADV_SEQUENTIAL 2
+#define LINUX_MADV_WILLNEED 3
+#define LINUX_MADV_DONTNEED 4
+#define LINUX_MADV_FREE 8
+#define LINUX_MADV_REMOVE 9
+#define LINUX_MADV_DONTFORK 10
+#define LINUX_MADV_DOFORK 11
+#define LINUX_MADV_MERGEABLE 12
+#define LINUX_MADV_UNMERGEABLE 13
+#define LINUX_MADV_HUGEPAGE 14
+#define LINUX_MADV_NOHUGEPAGE 15
+#define LINUX_MADV_DONTDUMP 16
+#define LINUX_MADV_DODUMP 17
+#define LINUX_MADV_WIPEONFORK 18
+#define LINUX_MADV_KEEPONFORK 19
+#define LINUX_MADV_HWPOISON 100
+#define LINUX_MADV_SOFT_OFFLINE 101
+
+int linux_mmap_common(struct thread *, uintptr_t, size_t, int, int,
+ int, off_t);
+int linux_mprotect_common(struct thread *, uintptr_t, size_t, int);
+int linux_madvise_common(struct thread *, uintptr_t, size_t, int);
+
+#endif /* _LINUX_MMAP_H_ */
diff --git a/sys/compat/linux/linux_persona.h b/sys/compat/linux/linux_persona.h
new file mode 100644
index 000000000000..7ae166aeb2cf
--- /dev/null
+++ b/sys/compat/linux/linux_persona.h
@@ -0,0 +1,56 @@
+/*
+ * $FreeBSD$
+ */
+
+#ifndef LINUX_PERSONALITY_H
+#define LINUX_PERSONALITY_H
+
+/*
+ * Flags for bug emulation.
+ *
+ * These occupy the top three bytes.
+ */
+enum {
+ LINUX_UNAME26 = 0x0020000,
+ LINUX_ADDR_NO_RANDOMIZE = 0x0040000, /* disable randomization
+ * of VA space
+ */
+ LINUX_FDPIC_FUNCPTRS = 0x0080000, /* userspace function
+ * ptrs point to descriptors
+ * (signal handling)
+ */
+ LINUX_MMAP_PAGE_ZERO = 0x0100000,
+ LINUX_ADDR_COMPAT_LAYOUT = 0x0200000,
+ LINUX_READ_IMPLIES_EXEC = 0x0400000,
+ LINUX_ADDR_LIMIT_32BIT = 0x0800000,
+ LINUX_SHORT_INODE = 0x1000000,
+ LINUX_WHOLE_SECONDS = 0x2000000,
+ LINUX_STICKY_TIMEOUTS = 0x4000000,
+ LINUX_ADDR_LIMIT_3GB = 0x8000000,
+};
+
+/*
+ * Security-relevant compatibility flags that must be
+ * cleared upon setuid or setgid exec:
+ */
+#define LINUX_PER_CLEAR_ON_SETID (LINUX_READ_IMPLIES_EXEC | \
+ LINUX_ADDR_NO_RANDOMIZE | \
+ LINUX_ADDR_COMPAT_LAYOUT | \
+ LINUX_MMAP_PAGE_ZERO)
+
+/*
+ * Personality types.
+ *
+ * These go in the low byte. Avoid using the top bit, it will
+ * conflict with error returns.
+ */
+enum {
+ LINUX_PER_LINUX = 0x0000,
+ LINUX_PER_LINUX_32BIT = 0x0000 | LINUX_ADDR_LIMIT_32BIT,
+ LINUX_PER_LINUX_FDPIC = 0x0000 | LINUX_FDPIC_FUNCPTRS,
+ LINUX_PER_LINUX32 = 0x0008,
+ LINUX_PER_LINUX32_3GB = 0x0008 | LINUX_ADDR_LIMIT_3GB,
+ LINUX_PER_MASK = 0x00ff,
+};
+
+#endif /* LINUX_PERSONALITY_H */
diff --git a/sys/compat/linux/linux_signal.c b/sys/compat/linux/linux_signal.c
new file mode 100644
index 000000000000..51f08d61bef1
--- /dev/null
+++ b/sys/compat/linux/linux_signal.c
@@ -0,0 +1,744 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 1994-1995 Søren Schmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sx.h>
+#include <sys/proc.h>
+#include <sys/signalvar.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysproto.h>
+
+#include <security/audit/audit.h>
+
+#include "opt_compat.h"
+
+#ifdef COMPAT_LINUX32
+#include <machine/../linux32/linux.h>
+#include <machine/../linux32/linux32_proto.h>
+#else
+#include <machine/../linux/linux.h>
+#include <machine/../linux/linux_proto.h>
+#endif
+#include <compat/linux/linux_signal.h>
+#include <compat/linux/linux_util.h>
+#include <compat/linux/linux_emul.h>
+#include <compat/linux/linux_misc.h>
+
+static int linux_do_tkill(struct thread *td, struct thread *tdt,
+ ksiginfo_t *ksi);
+static void sicode_to_lsicode(int si_code, int *lsi_code);
+
+static void
+linux_to_bsd_sigaction(l_sigaction_t *lsa, struct sigaction *bsa)
+{
+ unsigned long flags;
+
+ linux_to_bsd_sigset(&lsa->lsa_mask, &bsa->sa_mask);
+ bsa->sa_handler = PTRIN(lsa->lsa_handler);
+ bsa->sa_flags = 0;
+
+ flags = lsa->lsa_flags;
+ if (lsa->lsa_flags & LINUX_SA_NOCLDSTOP) {
+ flags &= ~LINUX_SA_NOCLDSTOP;
+ bsa->sa_flags |= SA_NOCLDSTOP;
+ }
+ if (lsa->lsa_flags & LINUX_SA_NOCLDWAIT) {
+ flags &= ~LINUX_SA_NOCLDWAIT;
+ bsa->sa_flags |= SA_NOCLDWAIT;
+ }
+ if (lsa->lsa_flags & LINUX_SA_SIGINFO) {
+ flags &= ~LINUX_SA_SIGINFO;
+ bsa->sa_flags |= SA_SIGINFO;
+#ifdef notyet
+ /*
+ * XXX: We seem to be missing code to convert
+ * some of the fields in ucontext_t.
+ */
+ linux_msg(curthread,
+ "partially unsupported sigaction flag SA_SIGINFO");
+#endif
+ }
+ if (lsa->lsa_flags & LINUX_SA_RESTORER) {
+ flags &= ~LINUX_SA_RESTORER;
+ /* XXX: We might want to handle it; see Linux sigreturn(2). */
+ }
+ if (lsa->lsa_flags & LINUX_SA_ONSTACK) {
+ flags &= ~LINUX_SA_ONSTACK;
+ bsa->sa_flags |= SA_ONSTACK;
+ }
+ if (lsa->lsa_flags & LINUX_SA_RESTART) {
+ flags &= ~LINUX_SA_RESTART;
+ bsa->sa_flags |= SA_RESTART;
+ }
+ if (lsa->lsa_flags & LINUX_SA_INTERRUPT) {
+ flags &= ~LINUX_SA_INTERRUPT;
+ /* Documented to be a "historical no-op". */
+ }
+ if (lsa->lsa_flags & LINUX_SA_ONESHOT) {
+ flags &= ~LINUX_SA_ONESHOT;
+ bsa->sa_flags |= SA_RESETHAND;
+ }
+ if (lsa->lsa_flags & LINUX_SA_NOMASK) {
+ flags &= ~LINUX_SA_NOMASK;
+ bsa->sa_flags |= SA_NODEFER;
+ }
+
+ if (flags != 0)
+ linux_msg(curthread, "unsupported sigaction flag %#lx", flags);
+}
+
+static void
+bsd_to_linux_sigaction(struct sigaction *bsa, l_sigaction_t *lsa)
+{
+
+ bsd_to_linux_sigset(&bsa->sa_mask, &lsa->lsa_mask);
+#ifdef COMPAT_LINUX32
+ lsa->lsa_handler = (uintptr_t)bsa->sa_handler;
+#else
+ lsa->lsa_handler = bsa->sa_handler;
+#endif
+ lsa->lsa_restorer = 0; /* unsupported */
+ lsa->lsa_flags = 0;
+ if (bsa->sa_flags & SA_NOCLDSTOP)
+ lsa->lsa_flags |= LINUX_SA_NOCLDSTOP;
+ if (bsa->sa_flags & SA_NOCLDWAIT)
+ lsa->lsa_flags |= LINUX_SA_NOCLDWAIT;
+ if (bsa->sa_flags & SA_SIGINFO)
+ lsa->lsa_flags |= LINUX_SA_SIGINFO;
+ if (bsa->sa_flags & SA_ONSTACK)
+ lsa->lsa_flags |= LINUX_SA_ONSTACK;
+ if (bsa->sa_flags & SA_RESTART)
+ lsa->lsa_flags |= LINUX_SA_RESTART;
+ if (bsa->sa_flags & SA_RESETHAND)
+ lsa->lsa_flags |= LINUX_SA_ONESHOT;
+ if (bsa->sa_flags & SA_NODEFER)
+ lsa->lsa_flags |= LINUX_SA_NOMASK;
+}
+
+int
+linux_do_sigaction(struct thread *td, int linux_sig, l_sigaction_t *linux_nsa,
+ l_sigaction_t *linux_osa)
+{
+ struct sigaction act, oact, *nsa, *osa;
+ int error, sig;
+
+ if (!LINUX_SIG_VALID(linux_sig))
+ return (EINVAL);
+
+ osa = (linux_osa != NULL) ? &oact : NULL;
+ if (linux_nsa != NULL) {
+ nsa = &act;
+ linux_to_bsd_sigaction(linux_nsa, nsa);
+ } else
+ nsa = NULL;
+ sig = linux_to_bsd_signal(linux_sig);
+
+ error = kern_sigaction(td, sig, nsa, osa, 0);
+ if (error)
+ return (error);
+
+ if (linux_osa != NULL)
+ bsd_to_linux_sigaction(osa, linux_osa);
+
+ return (0);
+}
+
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+int
+linux_signal(struct thread *td, struct linux_signal_args *args)
+{
+ l_sigaction_t nsa, osa;
+ int error;
+
+ nsa.lsa_handler = args->handler;
+ nsa.lsa_flags = LINUX_SA_ONESHOT | LINUX_SA_NOMASK;
+ LINUX_SIGEMPTYSET(nsa.lsa_mask);
+
+ error = linux_do_sigaction(td, args->sig, &nsa, &osa);
+ td->td_retval[0] = (int)(intptr_t)osa.lsa_handler;
+
+ return (error);
+}
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+
+int
+linux_rt_sigaction(struct thread *td, struct linux_rt_sigaction_args *args)
+{
+ l_sigaction_t nsa, osa;
+ int error;
+
+ if (args->sigsetsize != sizeof(l_sigset_t))
+ return (EINVAL);
+
+ if (args->act != NULL) {
+ error = copyin(args->act, &nsa, sizeof(l_sigaction_t));
+ if (error)
+ return (error);
+ }
+
+ error = linux_do_sigaction(td, args->sig,
+ args->act ? &nsa : NULL,
+ args->oact ? &osa : NULL);
+
+ if (args->oact != NULL && !error) {
+ error = copyout(&osa, args->oact, sizeof(l_sigaction_t));
+ }
+
+ return (error);
+}
+
+static int
+linux_do_sigprocmask(struct thread *td, int how, l_sigset_t *new,
+ l_sigset_t *old)
+{
+ sigset_t omask, nmask;
+ sigset_t *nmaskp;
+ int error;
+
+ td->td_retval[0] = 0;
+
+ switch (how) {
+ case LINUX_SIG_BLOCK:
+ how = SIG_BLOCK;
+ break;
+ case LINUX_SIG_UNBLOCK:
+ how = SIG_UNBLOCK;
+ break;
+ case LINUX_SIG_SETMASK:
+ how = SIG_SETMASK;
+ break;
+ default:
+ return (EINVAL);
+ }
+ if (new != NULL) {
+ linux_to_bsd_sigset(new, &nmask);
+ nmaskp = &nmask;
+ } else
+ nmaskp = NULL;
+ error = kern_sigprocmask(td, how, nmaskp, &omask, 0);
+ if (error == 0 && old != NULL)
+ bsd_to_linux_sigset(&omask, old);
+
+ return (error);
+}
+
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+int
+linux_sigprocmask(struct thread *td, struct linux_sigprocmask_args *args)
+{
+ l_osigset_t mask;
+ l_sigset_t set, oset;
+ int error;
+
+ if (args->mask != NULL) {
+ error = copyin(args->mask, &mask, sizeof(l_osigset_t));
+ if (error)
+ return (error);
+ LINUX_SIGEMPTYSET(set);
+ set.__mask = mask;
+ }
+
+ error = linux_do_sigprocmask(td, args->how,
+ args->mask ? &set : NULL,
+ args->omask ? &oset : NULL);
+
+ if (args->omask != NULL && !error) {
+ mask = oset.__mask;
+ error = copyout(&mask, args->omask, sizeof(l_osigset_t));
+ }
+
+ return (error);
+}
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+
+int
+linux_rt_sigprocmask(struct thread *td, struct linux_rt_sigprocmask_args *args)
+{
+ l_sigset_t set, oset;
+ int error;
+
+ if (args->sigsetsize != sizeof(l_sigset_t))
+ return (EINVAL);
+
+ if (args->mask != NULL) {
+ error = copyin(args->mask, &set, sizeof(l_sigset_t));
+ if (error)
+ return (error);
+ }
+
+ error = linux_do_sigprocmask(td, args->how,
+ args->mask ? &set : NULL,
+ args->omask ? &oset : NULL);
+
+ if (args->omask != NULL && !error) {
+ error = copyout(&oset, args->omask, sizeof(l_sigset_t));
+ }
+
+ return (error);
+}
+
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+int
+linux_sgetmask(struct thread *td, struct linux_sgetmask_args *args)
+{
+ struct proc *p = td->td_proc;
+ l_sigset_t mask;
+
+ PROC_LOCK(p);
+ bsd_to_linux_sigset(&td->td_sigmask, &mask);
+ PROC_UNLOCK(p);
+ td->td_retval[0] = mask.__mask;
+ return (0);
+}
+
+int
+linux_ssetmask(struct thread *td, struct linux_ssetmask_args *args)
+{
+ struct proc *p = td->td_proc;
+ l_sigset_t lset;
+ sigset_t bset;
+
+ PROC_LOCK(p);
+ bsd_to_linux_sigset(&td->td_sigmask, &lset);
+ td->td_retval[0] = lset.__mask;
+ LINUX_SIGEMPTYSET(lset);
+ lset.__mask = args->mask;
+ linux_to_bsd_sigset(&lset, &bset);
+ td->td_sigmask = bset;
+ SIG_CANTMASK(td->td_sigmask);
+ signotify(td);
+ PROC_UNLOCK(p);
+ return (0);
+}
+
+int
+linux_sigpending(struct thread *td, struct linux_sigpending_args *args)
+{
+ struct proc *p = td->td_proc;
+ sigset_t bset;
+ l_sigset_t lset;
+ l_osigset_t mask;
+
+ PROC_LOCK(p);
+ bset = p->p_siglist;
+ SIGSETOR(bset, td->td_siglist);
+ SIGSETAND(bset, td->td_sigmask);
+ PROC_UNLOCK(p);
+ bsd_to_linux_sigset(&bset, &lset);
+ mask = lset.__mask;
+ return (copyout(&mask, args->mask, sizeof(mask)));
+}
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+
+/*
+ * MPSAFE
+ */
+int
+linux_rt_sigpending(struct thread *td, struct linux_rt_sigpending_args *args)
+{
+ struct proc *p = td->td_proc;
+ sigset_t bset;
+ l_sigset_t lset;
+
+ if (args->sigsetsize > sizeof(lset))
+ return (EINVAL);
+ /* NOT REACHED */
+
+ PROC_LOCK(p);
+ bset = p->p_siglist;
+ SIGSETOR(bset, td->td_siglist);
+ SIGSETAND(bset, td->td_sigmask);
+ PROC_UNLOCK(p);
+ bsd_to_linux_sigset(&bset, &lset);
+ return (copyout(&lset, args->set, args->sigsetsize));
+}
+
+/*
+ * MPSAFE
+ */
+int
+linux_rt_sigtimedwait(struct thread *td,
+ struct linux_rt_sigtimedwait_args *args)
+{
+ int error, sig;
+ l_timeval ltv;
+ struct timeval tv;
+ struct timespec ts, *tsa;
+ l_sigset_t lset;
+ sigset_t bset;
+ l_siginfo_t linfo;
+ ksiginfo_t info;
+
+ if (args->sigsetsize != sizeof(l_sigset_t))
+ return (EINVAL);
+
+ if ((error = copyin(args->mask, &lset, sizeof(lset))))
+ return (error);
+ linux_to_bsd_sigset(&lset, &bset);
+
+ tsa = NULL;
+ if (args->timeout) {
+ if ((error = copyin(args->timeout, &ltv, sizeof(ltv))))
+ return (error);
+ tv.tv_sec = (long)ltv.tv_sec;
+ tv.tv_usec = (suseconds_t)ltv.tv_usec;
+ if (itimerfix(&tv)) {
+ /*
+ * The timeout was invalid. Convert it to something
+ * valid that will act as it does under Linux.
+ */
+ tv.tv_sec += tv.tv_usec / 1000000;
+ tv.tv_usec %= 1000000;
+ if (tv.tv_usec < 0) {
+ tv.tv_sec -= 1;
+ tv.tv_usec += 1000000;
+ }
+ if (tv.tv_sec < 0)
+ timevalclear(&tv);
+ }
+ TIMEVAL_TO_TIMESPEC(&tv, &ts);
+ tsa = &ts;
+ }
+ error = kern_sigtimedwait(td, bset, &info, tsa);
+ if (error)
+ return (error);
+
+ sig = bsd_to_linux_signal(info.ksi_signo);
+
+ if (args->ptr) {
+ memset(&linfo, 0, sizeof(linfo));
+ ksiginfo_to_lsiginfo(&info, &linfo, sig);
+ error = copyout(&linfo, args->ptr, sizeof(linfo));
+ }
+ if (error == 0)
+ td->td_retval[0] = sig;
+
+ return (error);
+}
+
+int
+linux_kill(struct thread *td, struct linux_kill_args *args)
+{
+ int l_signum;
+
+ /*
+ * Allow signal 0 as a means to check for privileges
+ */
+ if (!LINUX_SIG_VALID(args->signum) && args->signum != 0)
+ return (EINVAL);
+
+ if (args->signum > 0)
+ l_signum = linux_to_bsd_signal(args->signum);
+ else
+ l_signum = 0;
+
+ return (kern_kill(td, args->pid, l_signum));
+}
+
+static int
+linux_do_tkill(struct thread *td, struct thread *tdt, ksiginfo_t *ksi)
+{
+ struct proc *p;
+ int error;
+
+ p = tdt->td_proc;
+ AUDIT_ARG_SIGNUM(ksi->ksi_signo);
+ AUDIT_ARG_PID(p->p_pid);
+ AUDIT_ARG_PROCESS(p);
+
+ error = p_cansignal(td, p, ksi->ksi_signo);
+ if (error != 0 || ksi->ksi_signo == 0)
+ goto out;
+
+ tdksignal(tdt, ksi->ksi_signo, ksi);
+
+out:
+ PROC_UNLOCK(p);
+ return (error);
+}
+
+int
+linux_tgkill(struct thread *td, struct linux_tgkill_args *args)
+{
+ struct thread *tdt;
+ ksiginfo_t ksi;
+ int sig;
+
+ if (args->pid <= 0 || args->tgid <=0)
+ return (EINVAL);
+
+ /*
+ * Allow signal 0 as a means to check for privileges
+ */
+ if (!LINUX_SIG_VALID(args->sig) && args->sig != 0)
+ return (EINVAL);
+
+ if (args->sig > 0)
+ sig = linux_to_bsd_signal(args->sig);
+ else
+ sig = 0;
+
+ tdt = linux_tdfind(td, args->pid, args->tgid);
+ if (tdt == NULL)
+ return (ESRCH);
+
+ ksiginfo_init(&ksi);
+ ksi.ksi_signo = sig;
+ ksi.ksi_code = SI_LWP;
+ ksi.ksi_errno = 0;
+ ksi.ksi_pid = td->td_proc->p_pid;
+ ksi.ksi_uid = td->td_proc->p_ucred->cr_ruid;
+ return (linux_do_tkill(td, tdt, &ksi));
+}
+
+/*
+ * Deprecated since 2.5.75. Replaced by tgkill().
+ */
+int
+linux_tkill(struct thread *td, struct linux_tkill_args *args)
+{
+ struct thread *tdt;
+ ksiginfo_t ksi;
+ int sig;
+
+ if (args->tid <= 0)
+ return (EINVAL);
+
+ if (!LINUX_SIG_VALID(args->sig))
+ return (EINVAL);
+
+ sig = linux_to_bsd_signal(args->sig);
+
+ tdt = linux_tdfind(td, args->tid, -1);
+ if (tdt == NULL)
+ return (ESRCH);
+
+ ksiginfo_init(&ksi);
+ ksi.ksi_signo = sig;
+ ksi.ksi_code = SI_LWP;
+ ksi.ksi_errno = 0;
+ ksi.ksi_pid = td->td_proc->p_pid;
+ ksi.ksi_uid = td->td_proc->p_ucred->cr_ruid;
+ return (linux_do_tkill(td, tdt, &ksi));
+}
+
+void
+ksiginfo_to_lsiginfo(const ksiginfo_t *ksi, l_siginfo_t *lsi, l_int sig)
+{
+
+ siginfo_to_lsiginfo(&ksi->ksi_info, lsi, sig);
+}
+
+static void
+sicode_to_lsicode(int si_code, int *lsi_code)
+{
+
+ switch (si_code) {
+ case SI_USER:
+ *lsi_code = LINUX_SI_USER;
+ break;
+ case SI_KERNEL:
+ *lsi_code = LINUX_SI_KERNEL;
+ break;
+ case SI_QUEUE:
+ *lsi_code = LINUX_SI_QUEUE;
+ break;
+ case SI_TIMER:
+ *lsi_code = LINUX_SI_TIMER;
+ break;
+ case SI_MESGQ:
+ *lsi_code = LINUX_SI_MESGQ;
+ break;
+ case SI_ASYNCIO:
+ *lsi_code = LINUX_SI_ASYNCIO;
+ break;
+ case SI_LWP:
+ *lsi_code = LINUX_SI_TKILL;
+ break;
+ default:
+ *lsi_code = si_code;
+ break;
+ }
+}
+
+void
+siginfo_to_lsiginfo(const siginfo_t *si, l_siginfo_t *lsi, l_int sig)
+{
+
+ /* sig alredy converted */
+ lsi->lsi_signo = sig;
+ sicode_to_lsicode(si->si_code, &lsi->lsi_code);
+
+ switch (si->si_code) {
+ case SI_LWP:
+ lsi->lsi_pid = si->si_pid;
+ lsi->lsi_uid = si->si_uid;
+ break;
+
+ case SI_TIMER:
+ lsi->lsi_int = si->si_value.sival_int;
+ lsi->lsi_ptr = PTROUT(si->si_value.sival_ptr);
+ lsi->lsi_tid = si->si_timerid;
+ break;
+
+ case SI_QUEUE:
+ lsi->lsi_pid = si->si_pid;
+ lsi->lsi_uid = si->si_uid;
+ lsi->lsi_ptr = PTROUT(si->si_value.sival_ptr);
+ break;
+
+ case SI_ASYNCIO:
+ lsi->lsi_int = si->si_value.sival_int;
+ lsi->lsi_ptr = PTROUT(si->si_value.sival_ptr);
+ break;
+
+ default:
+ switch (sig) {
+ case LINUX_SIGPOLL:
+ /* XXX si_fd? */
+ lsi->lsi_band = si->si_band;
+ break;
+
+ case LINUX_SIGCHLD:
+ lsi->lsi_errno = 0;
+ lsi->lsi_pid = si->si_pid;
+ lsi->lsi_uid = si->si_uid;
+
+ if (si->si_code == CLD_STOPPED)
+ lsi->lsi_status = bsd_to_linux_signal(si->si_status);
+ else if (si->si_code == CLD_CONTINUED)
+ lsi->lsi_status = bsd_to_linux_signal(SIGCONT);
+ else
+ lsi->lsi_status = si->si_status;
+ break;
+
+ case LINUX_SIGBUS:
+ case LINUX_SIGILL:
+ case LINUX_SIGFPE:
+ case LINUX_SIGSEGV:
+ lsi->lsi_addr = PTROUT(si->si_addr);
+ break;
+
+ default:
+ lsi->lsi_pid = si->si_pid;
+ lsi->lsi_uid = si->si_uid;
+ if (sig >= LINUX_SIGRTMIN) {
+ lsi->lsi_int = si->si_value.sival_int;
+ lsi->lsi_ptr = PTROUT(si->si_value.sival_ptr);
+ }
+ break;
+ }
+ break;
+ }
+}
+
+void
+lsiginfo_to_ksiginfo(const l_siginfo_t *lsi, ksiginfo_t *ksi, int sig)
+{
+
+ ksi->ksi_signo = sig;
+ ksi->ksi_code = lsi->lsi_code; /* XXX. Convert. */
+ ksi->ksi_pid = lsi->lsi_pid;
+ ksi->ksi_uid = lsi->lsi_uid;
+ ksi->ksi_status = lsi->lsi_status;
+ ksi->ksi_addr = PTRIN(lsi->lsi_addr);
+ ksi->ksi_info.si_value.sival_int = lsi->lsi_int;
+}
+
+int
+linux_rt_sigqueueinfo(struct thread *td, struct linux_rt_sigqueueinfo_args *args)
+{
+ l_siginfo_t linfo;
+ struct proc *p;
+ ksiginfo_t ksi;
+ int error;
+ int sig;
+
+ if (!LINUX_SIG_VALID(args->sig))
+ return (EINVAL);
+
+ error = copyin(args->info, &linfo, sizeof(linfo));
+ if (error != 0)
+ return (error);
+
+ if (linfo.lsi_code >= 0)
+ return (EPERM);
+
+ sig = linux_to_bsd_signal(args->sig);
+
+ error = ESRCH;
+ if ((p = pfind_any(args->pid)) != NULL) {
+ error = p_cansignal(td, p, sig);
+ if (error != 0) {
+ PROC_UNLOCK(p);
+ return (error);
+ }
+
+ ksiginfo_init(&ksi);
+ lsiginfo_to_ksiginfo(&linfo, &ksi, sig);
+ error = tdsendsignal(p, NULL, sig, &ksi);
+ PROC_UNLOCK(p);
+ }
+
+ return (error);
+}
+
+int
+linux_rt_tgsigqueueinfo(struct thread *td, struct linux_rt_tgsigqueueinfo_args *args)
+{
+ l_siginfo_t linfo;
+ struct thread *tds;
+ ksiginfo_t ksi;
+ int error;
+ int sig;
+
+ if (!LINUX_SIG_VALID(args->sig))
+ return (EINVAL);
+
+ error = copyin(args->uinfo, &linfo, sizeof(linfo));
+ if (error != 0)
+ return (error);
+
+ if (linfo.lsi_code >= 0)
+ return (EPERM);
+
+ tds = linux_tdfind(td, args->tid, args->tgid);
+ if (tds == NULL)
+ return (ESRCH);
+
+ sig = linux_to_bsd_signal(args->sig);
+ ksiginfo_init(&ksi);
+ lsiginfo_to_ksiginfo(&linfo, &ksi, sig);
+ return (linux_do_tkill(td, tds, &ksi));
+}
diff --git a/sys/compat/linux/linux_signal.h b/sys/compat/linux/linux_signal.h
new file mode 100644
index 000000000000..5df74fb71029
--- /dev/null
+++ b/sys/compat/linux/linux_signal.h
@@ -0,0 +1,51 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2000 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_SIGNAL_H_
+#define _LINUX_SIGNAL_H_
+
+/*
+ * si_code values
+ */
+#define LINUX_SI_USER 0 /* sent by kill, sigsend, raise */
+#define LINUX_SI_KERNEL 0x80 /* sent by the kernel from somewhere */
+#define LINUX_SI_QUEUE -1 /* sent by sigqueue */
+#define LINUX_SI_TIMER -2 /* sent by timer expiration */
+#define LINUX_SI_MESGQ -3 /* sent by real time mesq state change */
+#define LINUX_SI_ASYNCIO -4 /* sent by AIO completion */
+#define LINUX_SI_SIGIO -5 /* sent by queued SIGIO */
+#define LINUX_SI_TKILL -6 /* sent by tkill system call */
+
+int linux_do_sigaction(struct thread *, int, l_sigaction_t *, l_sigaction_t *);
+void ksiginfo_to_lsiginfo(const ksiginfo_t *ksi, l_siginfo_t *lsi, l_int sig);
+void siginfo_to_lsiginfo(const siginfo_t *si, l_siginfo_t *lsi, l_int sig);
+void lsiginfo_to_ksiginfo(const l_siginfo_t *lsi, ksiginfo_t *ksi, int sig);
+
+#endif /* _LINUX_SIGNAL_H_ */
diff --git a/sys/compat/linux/linux_socket.c b/sys/compat/linux/linux_socket.c
new file mode 100644
index 000000000000..a4c5bf0b581e
--- /dev/null
+++ b/sys/compat/linux/linux_socket.c
@@ -0,0 +1,2224 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1995 Søren Schmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/* XXX we use functions that might not exist. */
+#include "opt_compat.h"
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/sysproto.h>
+#include <sys/capsicum.h>
+#include <sys/fcntl.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/syscallsubr.h>
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <sys/syslog.h>
+#include <sys/un.h>
+#include <sys/unistd.h>
+
+#include <security/audit/audit.h>
+
+#include <net/if.h>
+#include <net/vnet.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#ifdef INET6
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#endif
+
+#ifdef COMPAT_LINUX32
+#include <machine/../linux32/linux.h>
+#include <machine/../linux32/linux32_proto.h>
+#else
+#include <machine/../linux/linux.h>
+#include <machine/../linux/linux_proto.h>
+#endif
+#include <compat/linux/linux_common.h>
+#include <compat/linux/linux_file.h>
+#include <compat/linux/linux_mib.h>
+#include <compat/linux/linux_socket.h>
+#include <compat/linux/linux_timer.h>
+#include <compat/linux/linux_util.h>
+
+#define SECURITY_CONTEXT_STRING "unconfined"
+
+static int linux_sendmsg_common(struct thread *, l_int, struct l_msghdr *,
+ l_uint);
+static int linux_recvmsg_common(struct thread *, l_int, struct l_msghdr *,
+ l_uint, struct msghdr *);
+static int linux_set_socket_flags(int, int *);
+
+static int
+linux_to_bsd_sockopt_level(int level)
+{
+
+ if (level == LINUX_SOL_SOCKET)
+ return (SOL_SOCKET);
+ /* Remaining values are RFC-defined protocol numbers. */
+ return (level);
+}
+
+static int
+bsd_to_linux_sockopt_level(int level)
+{
+
+ if (level == SOL_SOCKET)
+ return (LINUX_SOL_SOCKET);
+ return (level);
+}
+
+static int
+linux_to_bsd_ip_sockopt(int opt)
+{
+
+ switch (opt) {
+ /* known and translated sockopts */
+ case LINUX_IP_TOS:
+ return (IP_TOS);
+ case LINUX_IP_TTL:
+ return (IP_TTL);
+ case LINUX_IP_HDRINCL:
+ return (IP_HDRINCL);
+ case LINUX_IP_OPTIONS:
+ return (IP_OPTIONS);
+ case LINUX_IP_RECVOPTS:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_RECVOPTS");
+ return (IP_RECVOPTS);
+ case LINUX_IP_RETOPTS:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_REETOPTS");
+ return (IP_RETOPTS);
+ case LINUX_IP_RECVTTL:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_RECVTTL");
+ return (IP_RECVTTL);
+ case LINUX_IP_RECVTOS:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_RECVTOS");
+ return (IP_RECVTOS);
+ case LINUX_IP_FREEBIND:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_FREEBIND");
+ return (IP_BINDANY);
+ case LINUX_IP_IPSEC_POLICY:
+ /* we have this option, but not documented in ip(4) manpage */
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_IPSEC_POLICY");
+ return (IP_IPSEC_POLICY);
+ case LINUX_IP_MINTTL:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_MINTTL");
+ return (IP_MINTTL);
+ case LINUX_IP_MULTICAST_IF:
+ return (IP_MULTICAST_IF);
+ case LINUX_IP_MULTICAST_TTL:
+ return (IP_MULTICAST_TTL);
+ case LINUX_IP_MULTICAST_LOOP:
+ return (IP_MULTICAST_LOOP);
+ case LINUX_IP_ADD_MEMBERSHIP:
+ return (IP_ADD_MEMBERSHIP);
+ case LINUX_IP_DROP_MEMBERSHIP:
+ return (IP_DROP_MEMBERSHIP);
+ case LINUX_IP_UNBLOCK_SOURCE:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_UNBLOCK_SOURCE");
+ return (IP_UNBLOCK_SOURCE);
+ case LINUX_IP_BLOCK_SOURCE:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_BLOCK_SOURCE");
+ return (IP_BLOCK_SOURCE);
+ case LINUX_IP_ADD_SOURCE_MEMBERSHIP:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_ADD_SOURCE_MEMBERSHIP");
+ return (IP_ADD_SOURCE_MEMBERSHIP);
+ case LINUX_IP_DROP_SOURCE_MEMBERSHIP:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_DROP_SOURCE_MEMBERSHIP");
+ return (IP_DROP_SOURCE_MEMBERSHIP);
+ case LINUX_MCAST_JOIN_GROUP:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_MCAST_JOIN_GROUP");
+ return (MCAST_JOIN_GROUP);
+ case LINUX_MCAST_LEAVE_GROUP:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_MCAST_LEAVE_GROUP");
+ return (MCAST_LEAVE_GROUP);
+ case LINUX_MCAST_JOIN_SOURCE_GROUP:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_MCAST_JOIN_SOURCE_GROUP");
+ return (MCAST_JOIN_SOURCE_GROUP);
+ case LINUX_MCAST_LEAVE_SOURCE_GROUP:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_MCAST_LEAVE_SOURCE_GROUP");
+ return (MCAST_LEAVE_SOURCE_GROUP);
+
+ /* known but not implemented sockopts */
+ case LINUX_IP_ROUTER_ALERT:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv4 socket option IP_ROUTER_ALERT (%d), you can not do user-space routing from linux programs",
+ opt);
+ return (-2);
+ case LINUX_IP_PKTINFO:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv4 socket option IP_PKTINFO (%d), you can not get extended packet info for datagram sockets in linux programs",
+ opt);
+ return (-2);
+ case LINUX_IP_PKTOPTIONS:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv4 socket option IP_PKTOPTIONS (%d)",
+ opt);
+ return (-2);
+ case LINUX_IP_MTU_DISCOVER:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv4 socket option IP_MTU_DISCOVER (%d), your linux program can not control path-MTU discovery",
+ opt);
+ return (-2);
+ case LINUX_IP_RECVERR:
+ /* needed by steam */
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv4 socket option IP_RECVERR (%d), you can not get extended reliability info in linux programs",
+ opt);
+ return (-2);
+ case LINUX_IP_MTU:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv4 socket option IP_MTU (%d), your linux program can not control the MTU on this socket",
+ opt);
+ return (-2);
+ case LINUX_IP_XFRM_POLICY:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv4 socket option IP_XFRM_POLICY (%d)",
+ opt);
+ return (-2);
+ case LINUX_IP_PASSSEC:
+ /* needed by steam */
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv4 socket option IP_PASSSEC (%d), you can not get IPSEC related credential information associated with this socket in linux programs -- if you do not use IPSEC, you can ignore this",
+ opt);
+ return (-2);
+ case LINUX_IP_TRANSPARENT:
+ /* IP_BINDANY or more? */
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv4 socket option IP_TRANSPARENT (%d), you can not enable transparent proxying in linux programs -- note, IP_FREEBIND is supported, no idea if the FreeBSD IP_BINDANY is equivalent to the Linux IP_TRANSPARENT or not, any info is welcome",
+ opt);
+ return (-2);
+ case LINUX_IP_NODEFRAG:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv4 socket option IP_NODEFRAG (%d)",
+ opt);
+ return (-2);
+ case LINUX_IP_CHECKSUM:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv4 socket option IP_CHECKSUM (%d)",
+ opt);
+ return (-2);
+ case LINUX_IP_BIND_ADDRESS_NO_PORT:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv4 socket option IP_BIND_ADDRESS_NO_PORT (%d)",
+ opt);
+ return (-2);
+ case LINUX_IP_RECVFRAGSIZE:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv4 socket option IP_RECVFRAGSIZE (%d)",
+ opt);
+ return (-2);
+ case LINUX_MCAST_MSFILTER:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv4 socket option IP_MCAST_MSFILTER (%d)",
+ opt);
+ return (-2);
+ case LINUX_IP_MULTICAST_ALL:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv4 socket option IP_MULTICAST_ALL (%d), your linux program will not see all multicast groups joined by the entire system, only those the program joined itself on this socket",
+ opt);
+ return (-2);
+ case LINUX_IP_UNICAST_IF:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv4 socket option IP_UNICAST_IF (%d)",
+ opt);
+ return (-2);
+
+ /* unknown sockopts */
+ default:
+ return (-1);
+ }
+}
+
+static int
+linux_to_bsd_ip6_sockopt(int opt)
+{
+
+ switch (opt) {
+ /* known and translated sockopts */
+ case LINUX_IPV6_2292PKTINFO:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_2292PKTINFO");
+ return (IPV6_2292PKTINFO);
+ case LINUX_IPV6_2292HOPOPTS:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_2292HOPOPTS");
+ return (IPV6_2292HOPOPTS);
+ case LINUX_IPV6_2292DSTOPTS:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_2292DSTOPTS");
+ return (IPV6_2292DSTOPTS);
+ case LINUX_IPV6_2292RTHDR:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_2292RTHDR");
+ return (IPV6_2292RTHDR);
+ case LINUX_IPV6_2292PKTOPTIONS:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_2292PKTOPTIONS");
+ return (IPV6_2292PKTOPTIONS);
+ case LINUX_IPV6_CHECKSUM:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_CHECKSUM");
+ return (IPV6_CHECKSUM);
+ case LINUX_IPV6_2292HOPLIMIT:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_2292HOPLIMIT");
+ return (IPV6_2292HOPLIMIT);
+ case LINUX_IPV6_NEXTHOP:
+ return (IPV6_NEXTHOP);
+ case LINUX_IPV6_UNICAST_HOPS:
+ return (IPV6_UNICAST_HOPS);
+ case LINUX_IPV6_MULTICAST_IF:
+ return (IPV6_MULTICAST_IF);
+ case LINUX_IPV6_MULTICAST_HOPS:
+ return (IPV6_MULTICAST_HOPS);
+ case LINUX_IPV6_MULTICAST_LOOP:
+ return (IPV6_MULTICAST_LOOP);
+ case LINUX_IPV6_ADD_MEMBERSHIP:
+ return (IPV6_JOIN_GROUP);
+ case LINUX_IPV6_DROP_MEMBERSHIP:
+ return (IPV6_LEAVE_GROUP);
+ case LINUX_IPV6_V6ONLY:
+ return (IPV6_V6ONLY);
+ case LINUX_IPV6_IPSEC_POLICY:
+ /* we have this option, but not documented in ip6(4) manpage */
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_IPSEC_POLICY");
+ return (IPV6_IPSEC_POLICY);
+ case LINUX_MCAST_JOIN_GROUP:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_JOIN_GROUP");
+ return (IPV6_JOIN_GROUP);
+ case LINUX_MCAST_LEAVE_GROUP:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_LEAVE_GROUP");
+ return (IPV6_LEAVE_GROUP);
+ case LINUX_IPV6_RECVPKTINFO:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_RECVPKTINFO");
+ return (IPV6_RECVPKTINFO);
+ case LINUX_IPV6_PKTINFO:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_PKTINFO");
+ return (IPV6_PKTINFO);
+ case LINUX_IPV6_RECVHOPLIMIT:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_RECVHOPLIMIT");
+ return (IPV6_RECVHOPLIMIT);
+ case LINUX_IPV6_HOPLIMIT:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_HOPLIMIT");
+ return (IPV6_HOPLIMIT);
+ case LINUX_IPV6_RECVHOPOPTS:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_RECVHOPOPTS");
+ return (IPV6_RECVHOPOPTS);
+ case LINUX_IPV6_HOPOPTS:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_HOPOPTS");
+ return (IPV6_HOPOPTS);
+ case LINUX_IPV6_RTHDRDSTOPTS:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_RTHDRDSTOPTS");
+ return (IPV6_RTHDRDSTOPTS);
+ case LINUX_IPV6_RECVRTHDR:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_RECVRTHDR");
+ return (IPV6_RECVRTHDR);
+ case LINUX_IPV6_RTHDR:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_RTHDR");
+ return (IPV6_RTHDR);
+ case LINUX_IPV6_RECVDSTOPTS:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_RECVDSTOPTS");
+ return (IPV6_RECVDSTOPTS);
+ case LINUX_IPV6_DSTOPTS:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_DSTOPTS");
+ return (IPV6_DSTOPTS);
+ case LINUX_IPV6_RECVPATHMTU:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_RECVPATHMTU");
+ return (IPV6_RECVPATHMTU);
+ case LINUX_IPV6_PATHMTU:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_PATHMTU");
+ return (IPV6_PATHMTU);
+ case LINUX_IPV6_DONTFRAG:
+ return (IPV6_DONTFRAG);
+ case LINUX_IPV6_AUTOFLOWLABEL:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_AUTOFLOWLABEL");
+ return (IPV6_AUTOFLOWLABEL);
+ case LINUX_IPV6_ORIGDSTADDR:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_ORIGDSTADDR");
+ return (IPV6_ORIGDSTADDR);
+ case LINUX_IPV6_FREEBIND:
+ LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_FREEBIND");
+ return (IPV6_BINDANY);
+
+ /* known but not implemented sockopts */
+ case LINUX_IPV6_ADDRFORM:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv6 socket option IPV6_ADDRFORM (%d), you linux program can not convert the socket to IPv4",
+ opt);
+ return (-2);
+ case LINUX_IPV6_AUTHHDR:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv6 socket option IPV6_AUTHHDR (%d), your linux program can not get the authentication header info of IPv6 packets",
+ opt);
+ return (-2);
+ case LINUX_IPV6_FLOWINFO:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv6 socket option IPV6_FLOWINFO (%d), your linux program can not get the flowid of IPv6 packets",
+ opt);
+ return (-2);
+ case LINUX_IPV6_ROUTER_ALERT:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv6 socket option IPV6_ROUTER_ALERT (%d), you can not do user-space routing from linux programs",
+ opt);
+ return (-2);
+ case LINUX_IPV6_MTU_DISCOVER:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv6 socket option IPV6_MTU_DISCOVER (%d), your linux program can not control path-MTU discovery",
+ opt);
+ return (-2);
+ case LINUX_IPV6_MTU:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv6 socket option IPV6_MTU (%d), your linux program can not control the MTU on this socket",
+ opt);
+ return (-2);
+ case LINUX_IPV6_JOIN_ANYCAST:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv6 socket option IPV6_JOIN_ANYCAST (%d)",
+ opt);
+ return (-2);
+ case LINUX_IPV6_LEAVE_ANYCAST:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv6 socket option IPV6_LEAVE_ANYCAST (%d)",
+ opt);
+ return (-2);
+ case LINUX_IPV6_MULTICAST_ALL:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv6 socket option IPV6_MULTICAST_ALL (%d)",
+ opt);
+ return (-2);
+ case LINUX_IPV6_ROUTER_ALERT_ISOLATE:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv6 socket option IPV6_ROUTER_ALERT_ISOLATE (%d)",
+ opt);
+ return (-2);
+ case LINUX_IPV6_FLOWLABEL_MGR:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv6 socket option IPV6_FLOWLABEL_MGR (%d)",
+ opt);
+ return (-2);
+ case LINUX_IPV6_FLOWINFO_SEND:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv6 socket option IPV6_FLOWINFO_SEND (%d)",
+ opt);
+ return (-2);
+ case LINUX_IPV6_XFRM_POLICY:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv6 socket option IPV6_XFRM_POLICY (%d)",
+ opt);
+ return (-2);
+ case LINUX_IPV6_HDRINCL:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv6 socket option IPV6_HDRINCL (%d)",
+ opt);
+ return (-2);
+ case LINUX_MCAST_BLOCK_SOURCE:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv6 socket option MCAST_BLOCK_SOURCE (%d), your linux program may see more multicast stuff than it wants",
+ opt);
+ return (-2);
+ case LINUX_MCAST_UNBLOCK_SOURCE:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv6 socket option MCAST_UNBLOCK_SOURCE (%d), your linux program may not see all the multicast stuff it wants",
+ opt);
+ return (-2);
+ case LINUX_MCAST_JOIN_SOURCE_GROUP:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv6 socket option MCAST_JOIN_SOURCE_GROUP (%d), your linux program is not able to join a multicast source group",
+ opt);
+ return (-2);
+ case LINUX_MCAST_LEAVE_SOURCE_GROUP:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv6 socket option MCAST_LEAVE_SOURCE_GROUP (%d), your linux program is not able to leave a multicast source group -- but it was also not able to join one, so no issue",
+ opt);
+ return (-2);
+ case LINUX_MCAST_MSFILTER:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv6 socket option MCAST_MSFILTER (%d), your linux program can not manipulate the multicast filter, it may see more multicast data than it wants to see",
+ opt);
+ return (-2);
+ case LINUX_IPV6_ADDR_PREFERENCES:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv6 socket option IPV6_ADDR_PREFERENCES (%d)",
+ opt);
+ return (-2);
+ case LINUX_IPV6_MINHOPCOUNT:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv6 socket option IPV6_MINHOPCOUNT (%d)",
+ opt);
+ return (-2);
+ case LINUX_IPV6_TRANSPARENT:
+ /* IP_BINDANY or more? */
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv6 socket option IPV6_TRANSPARENT (%d), you can not enable transparent proxying in linux programs -- note, IP_FREEBIND is supported, no idea if the FreeBSD IP_BINDANY is equivalent to the Linux IP_TRANSPARENT or not, any info is welcome",
+ opt);
+ return (-2);
+ case LINUX_IPV6_UNICAST_IF:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv6 socket option IPV6_UNICAST_IF (%d)",
+ opt);
+ return (-2);
+ case LINUX_IPV6_RECVFRAGSIZE:
+ LINUX_RATELIMIT_MSG_OPT1(
+ "unsupported IPv6 socket option IPV6_RECVFRAGSIZE (%d)",
+ opt);
+ return (-2);
+
+ /* unknown sockopts */
+ default:
+ return (-1);
+ }
+}
+
+static int
+linux_to_bsd_so_sockopt(int opt)
+{
+
+ switch (opt) {
+ case LINUX_SO_DEBUG:
+ return (SO_DEBUG);
+ case LINUX_SO_REUSEADDR:
+ return (SO_REUSEADDR);
+ case LINUX_SO_TYPE:
+ return (SO_TYPE);
+ case LINUX_SO_ERROR:
+ return (SO_ERROR);
+ case LINUX_SO_DONTROUTE:
+ return (SO_DONTROUTE);
+ case LINUX_SO_BROADCAST:
+ return (SO_BROADCAST);
+ case LINUX_SO_SNDBUF:
+ case LINUX_SO_SNDBUFFORCE:
+ return (SO_SNDBUF);
+ case LINUX_SO_RCVBUF:
+ case LINUX_SO_RCVBUFFORCE:
+ return (SO_RCVBUF);
+ case LINUX_SO_KEEPALIVE:
+ return (SO_KEEPALIVE);
+ case LINUX_SO_OOBINLINE:
+ return (SO_OOBINLINE);
+ case LINUX_SO_LINGER:
+ return (SO_LINGER);
+ case LINUX_SO_REUSEPORT:
+ return (SO_REUSEPORT_LB);
+ case LINUX_SO_PASSCRED:
+ return (LOCAL_CREDS_PERSISTENT);
+ case LINUX_SO_PEERCRED:
+ return (LOCAL_PEERCRED);
+ case LINUX_SO_RCVLOWAT:
+ return (SO_RCVLOWAT);
+ case LINUX_SO_SNDLOWAT:
+ return (SO_SNDLOWAT);
+ case LINUX_SO_RCVTIMEO:
+ return (SO_RCVTIMEO);
+ case LINUX_SO_SNDTIMEO:
+ return (SO_SNDTIMEO);
+ case LINUX_SO_TIMESTAMP:
+ return (SO_TIMESTAMP);
+ case LINUX_SO_ACCEPTCONN:
+ return (SO_ACCEPTCONN);
+ case LINUX_SO_PROTOCOL:
+ return (SO_PROTOCOL);
+ }
+ return (-1);
+}
+
+static int
+linux_to_bsd_tcp_sockopt(int opt)
+{
+
+ switch (opt) {
+ case LINUX_TCP_NODELAY:
+ return (TCP_NODELAY);
+ case LINUX_TCP_MAXSEG:
+ return (TCP_MAXSEG);
+ case LINUX_TCP_CORK:
+ return (TCP_NOPUSH);
+ case LINUX_TCP_KEEPIDLE:
+ return (TCP_KEEPIDLE);
+ case LINUX_TCP_KEEPINTVL:
+ return (TCP_KEEPINTVL);
+ case LINUX_TCP_KEEPCNT:
+ return (TCP_KEEPCNT);
+ case LINUX_TCP_MD5SIG:
+ return (TCP_MD5SIG);
+ }
+ return (-1);
+}
+
+static int
+linux_to_bsd_msg_flags(int flags)
+{
+ int ret_flags = 0;
+
+ if (flags & LINUX_MSG_OOB)
+ ret_flags |= MSG_OOB;
+ if (flags & LINUX_MSG_PEEK)
+ ret_flags |= MSG_PEEK;
+ if (flags & LINUX_MSG_DONTROUTE)
+ ret_flags |= MSG_DONTROUTE;
+ if (flags & LINUX_MSG_CTRUNC)
+ ret_flags |= MSG_CTRUNC;
+ if (flags & LINUX_MSG_TRUNC)
+ ret_flags |= MSG_TRUNC;
+ if (flags & LINUX_MSG_DONTWAIT)
+ ret_flags |= MSG_DONTWAIT;
+ if (flags & LINUX_MSG_EOR)
+ ret_flags |= MSG_EOR;
+ if (flags & LINUX_MSG_WAITALL)
+ ret_flags |= MSG_WAITALL;
+ if (flags & LINUX_MSG_NOSIGNAL)
+ ret_flags |= MSG_NOSIGNAL;
+ if (flags & LINUX_MSG_PROXY)
+ LINUX_RATELIMIT_MSG_OPT1("socket message flag MSG_PROXY (%d) not handled",
+ LINUX_MSG_PROXY);
+ if (flags & LINUX_MSG_FIN)
+ LINUX_RATELIMIT_MSG_OPT1("socket message flag MSG_FIN (%d) not handled",
+ LINUX_MSG_FIN);
+ if (flags & LINUX_MSG_SYN)
+ LINUX_RATELIMIT_MSG_OPT1("socket message flag MSG_SYN (%d) not handled",
+ LINUX_MSG_SYN);
+ if (flags & LINUX_MSG_CONFIRM)
+ LINUX_RATELIMIT_MSG_OPT1("socket message flag MSG_CONFIRM (%d) not handled",
+ LINUX_MSG_CONFIRM);
+ if (flags & LINUX_MSG_RST)
+ LINUX_RATELIMIT_MSG_OPT1("socket message flag MSG_RST (%d) not handled",
+ LINUX_MSG_RST);
+ if (flags & LINUX_MSG_ERRQUEUE)
+ LINUX_RATELIMIT_MSG_OPT1("socket message flag MSG_ERRQUEUE (%d) not handled",
+ LINUX_MSG_ERRQUEUE);
+ return (ret_flags);
+}
+
+static int
+linux_to_bsd_cmsg_type(int cmsg_type)
+{
+
+ switch (cmsg_type) {
+ case LINUX_SCM_RIGHTS:
+ return (SCM_RIGHTS);
+ case LINUX_SCM_CREDENTIALS:
+ return (SCM_CREDS);
+ }
+ return (-1);
+}
+
+static int
+bsd_to_linux_cmsg_type(int cmsg_type)
+{
+
+ switch (cmsg_type) {
+ case SCM_RIGHTS:
+ return (LINUX_SCM_RIGHTS);
+ case SCM_CREDS:
+ return (LINUX_SCM_CREDENTIALS);
+ case SCM_CREDS2:
+ return (LINUX_SCM_CREDENTIALS);
+ case SCM_TIMESTAMP:
+ return (LINUX_SCM_TIMESTAMP);
+ }
+ return (-1);
+}
+
+static int
+linux_to_bsd_msghdr(struct msghdr *bhdr, const struct l_msghdr *lhdr)
+{
+ if (lhdr->msg_controllen > INT_MAX)
+ return (ENOBUFS);
+
+ bhdr->msg_name = PTRIN(lhdr->msg_name);
+ bhdr->msg_namelen = lhdr->msg_namelen;
+ bhdr->msg_iov = PTRIN(lhdr->msg_iov);
+ bhdr->msg_iovlen = lhdr->msg_iovlen;
+ bhdr->msg_control = PTRIN(lhdr->msg_control);
+
+ /*
+ * msg_controllen is skipped since BSD and LINUX control messages
+ * are potentially different sizes (e.g. the cred structure used
+ * by SCM_CREDS is different between the two operating system).
+ *
+ * The caller can set it (if necessary) after converting all the
+ * control messages.
+ */
+
+ bhdr->msg_flags = linux_to_bsd_msg_flags(lhdr->msg_flags);
+ return (0);
+}
+
+static int
+bsd_to_linux_msghdr(const struct msghdr *bhdr, struct l_msghdr *lhdr)
+{
+ lhdr->msg_name = PTROUT(bhdr->msg_name);
+ lhdr->msg_namelen = bhdr->msg_namelen;
+ lhdr->msg_iov = PTROUT(bhdr->msg_iov);
+ lhdr->msg_iovlen = bhdr->msg_iovlen;
+ lhdr->msg_control = PTROUT(bhdr->msg_control);
+
+ /*
+ * msg_controllen is skipped since BSD and LINUX control messages
+ * are potentially different sizes (e.g. the cred structure used
+ * by SCM_CREDS is different between the two operating system).
+ *
+ * The caller can set it (if necessary) after converting all the
+ * control messages.
+ */
+
+ /* msg_flags skipped */
+ return (0);
+}
+
+static int
+linux_set_socket_flags(int lflags, int *flags)
+{
+
+ if (lflags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK))
+ return (EINVAL);
+ if (lflags & LINUX_SOCK_NONBLOCK)
+ *flags |= SOCK_NONBLOCK;
+ if (lflags & LINUX_SOCK_CLOEXEC)
+ *flags |= SOCK_CLOEXEC;
+ return (0);
+}
+
+static int
+linux_copyout_sockaddr(const struct sockaddr *sa, void *uaddr, size_t len)
+{
+ struct l_sockaddr *lsa;
+ int error;
+
+ error = bsd_to_linux_sockaddr(sa, &lsa, len);
+ if (error != 0)
+ return (error);
+
+ error = copyout(lsa, uaddr, len);
+ free(lsa, M_SONAME);
+
+ return (error);
+}
+
+static int
+linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags,
+ struct mbuf *control, enum uio_seg segflg)
+{
+ struct sockaddr *to;
+ int error, len;
+
+ if (mp->msg_name != NULL) {
+ len = mp->msg_namelen;
+ error = linux_to_bsd_sockaddr(mp->msg_name, &to, &len);
+ if (error != 0)
+ return (error);
+ mp->msg_name = to;
+ } else
+ to = NULL;
+
+ error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control,
+ segflg);
+
+ if (to)
+ free(to, M_SONAME);
+ return (error);
+}
+
+/* Return 0 if IP_HDRINCL is set for the given socket. */
+static int
+linux_check_hdrincl(struct thread *td, int s)
+{
+ int error, optval;
+ socklen_t size_val;
+
+ size_val = sizeof(optval);
+ error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL,
+ &optval, UIO_SYSSPACE, &size_val);
+ if (error != 0)
+ return (error);
+
+ return (optval == 0);
+}
+
+/*
+ * Updated sendto() when IP_HDRINCL is set:
+ * tweak endian-dependent fields in the IP packet.
+ */
+static int
+linux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args)
+{
+/*
+ * linux_ip_copysize defines how many bytes we should copy
+ * from the beginning of the IP packet before we customize it for BSD.
+ * It should include all the fields we modify (ip_len and ip_off).
+ */
+#define linux_ip_copysize 8
+
+ struct ip *packet;
+ struct msghdr msg;
+ struct iovec aiov[1];
+ int error;
+
+ /* Check that the packet isn't too big or too small. */
+ if (linux_args->len < linux_ip_copysize ||
+ linux_args->len > IP_MAXPACKET)
+ return (EINVAL);
+
+ packet = (struct ip *)malloc(linux_args->len, M_LINUX, M_WAITOK);
+
+ /* Make kernel copy of the packet to be sent */
+ if ((error = copyin(PTRIN(linux_args->msg), packet,
+ linux_args->len)))
+ goto goout;
+
+ /* Convert fields from Linux to BSD raw IP socket format */
+ packet->ip_len = linux_args->len;
+ packet->ip_off = ntohs(packet->ip_off);
+
+ /* Prepare the msghdr and iovec structures describing the new packet */
+ msg.msg_name = PTRIN(linux_args->to);
+ msg.msg_namelen = linux_args->tolen;
+ msg.msg_iov = aiov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+ msg.msg_flags = 0;
+ aiov[0].iov_base = (char *)packet;
+ aiov[0].iov_len = linux_args->len;
+ error = linux_sendit(td, linux_args->s, &msg, linux_args->flags,
+ NULL, UIO_SYSSPACE);
+goout:
+ free(packet, M_LINUX);
+ return (error);
+}
+
+static const char *linux_netlink_names[] = {
+ [LINUX_NETLINK_ROUTE] = "ROUTE",
+ [LINUX_NETLINK_SOCK_DIAG] = "SOCK_DIAG",
+ [LINUX_NETLINK_NFLOG] = "NFLOG",
+ [LINUX_NETLINK_SELINUX] = "SELINUX",
+ [LINUX_NETLINK_AUDIT] = "AUDIT",
+ [LINUX_NETLINK_FIB_LOOKUP] = "FIB_LOOKUP",
+ [LINUX_NETLINK_NETFILTER] = "NETFILTER",
+ [LINUX_NETLINK_KOBJECT_UEVENT] = "KOBJECT_UEVENT",
+};
+
+int
+linux_socket(struct thread *td, struct linux_socket_args *args)
+{
+ int domain, retval_socket, type;
+
+ type = args->type & LINUX_SOCK_TYPE_MASK;
+ if (type < 0 || type > LINUX_SOCK_MAX)
+ return (EINVAL);
+ retval_socket = linux_set_socket_flags(args->type & ~LINUX_SOCK_TYPE_MASK,
+ &type);
+ if (retval_socket != 0)
+ return (retval_socket);
+ domain = linux_to_bsd_domain(args->domain);
+ if (domain == -1) {
+ /* Mask off SOCK_NONBLOCK / CLOEXEC for error messages. */
+ type = args->type & LINUX_SOCK_TYPE_MASK;
+ if (args->domain == LINUX_AF_NETLINK &&
+ args->protocol == LINUX_NETLINK_AUDIT) {
+ ; /* Do nothing, quietly. */
+ } else if (args->domain == LINUX_AF_NETLINK) {
+ const char *nl_name;
+
+ if (args->protocol >= 0 &&
+ args->protocol < nitems(linux_netlink_names))
+ nl_name = linux_netlink_names[args->protocol];
+ else
+ nl_name = NULL;
+ if (nl_name != NULL)
+ linux_msg(curthread,
+ "unsupported socket(AF_NETLINK, %d, "
+ "NETLINK_%s)", type, nl_name);
+ else
+ linux_msg(curthread,
+ "unsupported socket(AF_NETLINK, %d, %d)",
+ type, args->protocol);
+ } else {
+ linux_msg(curthread, "unsupported socket domain %d, "
+ "type %d, protocol %d", args->domain, type,
+ args->protocol);
+ }
+ return (EAFNOSUPPORT);
+ }
+
+ retval_socket = kern_socket(td, domain, type, args->protocol);
+ if (retval_socket)
+ return (retval_socket);
+
+ if (type == SOCK_RAW
+ && (args->protocol == IPPROTO_RAW || args->protocol == 0)
+ && domain == PF_INET) {
+ /* It's a raw IP socket: set the IP_HDRINCL option. */
+ int hdrincl;
+
+ hdrincl = 1;
+ /* We ignore any error returned by kern_setsockopt() */
+ kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL,
+ &hdrincl, UIO_SYSSPACE, sizeof(hdrincl));
+ }
+#ifdef INET6
+ /*
+ * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by default
+ * and some apps depend on this. So, set V6ONLY to 0 for Linux apps.
+ * For simplicity we do this unconditionally of the net.inet6.ip6.v6only
+ * sysctl value.
+ */
+ if (domain == PF_INET6) {
+ int v6only;
+
+ v6only = 0;
+ /* We ignore any error returned by setsockopt() */
+ kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY,
+ &v6only, UIO_SYSSPACE, sizeof(v6only));
+ }
+#endif
+
+ return (retval_socket);
+}
+
+int
+linux_bind(struct thread *td, struct linux_bind_args *args)
+{
+ struct sockaddr *sa;
+ int error;
+
+ error = linux_to_bsd_sockaddr(PTRIN(args->name), &sa,
+ &args->namelen);
+ if (error != 0)
+ return (error);
+
+ error = kern_bindat(td, AT_FDCWD, args->s, sa);
+ free(sa, M_SONAME);
+
+ /* XXX */
+ if (error == EADDRNOTAVAIL && args->namelen != sizeof(struct sockaddr_in))
+ return (EINVAL);
+ return (error);
+}
+
+int
+linux_connect(struct thread *td, struct linux_connect_args *args)
+{
+ struct socket *so;
+ struct sockaddr *sa;
+ struct file *fp;
+ u_int fflag;
+ int error;
+
+ error = linux_to_bsd_sockaddr(PTRIN(args->name), &sa,
+ &args->namelen);
+ if (error != 0)
+ return (error);
+
+ error = kern_connectat(td, AT_FDCWD, args->s, sa);
+ free(sa, M_SONAME);
+ if (error != EISCONN)
+ return (error);
+
+ /*
+ * Linux doesn't return EISCONN the first time it occurs,
+ * when on a non-blocking socket. Instead it returns the
+ * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
+ */
+ error = getsock_cap(td, args->s, &cap_connect_rights,
+ &fp, &fflag, NULL);
+ if (error != 0)
+ return (error);
+
+ error = EISCONN;
+ so = fp->f_data;
+ if (fflag & FNONBLOCK) {
+ SOCK_LOCK(so);
+ if (so->so_emuldata == 0)
+ error = so->so_error;
+ so->so_emuldata = (void *)1;
+ SOCK_UNLOCK(so);
+ }
+ fdrop(fp, td);
+
+ return (error);
+}
+
+int
+linux_listen(struct thread *td, struct linux_listen_args *args)
+{
+
+ return (kern_listen(td, args->s, args->backlog));
+}
+
+static int
+linux_accept_common(struct thread *td, int s, l_uintptr_t addr,
+ l_uintptr_t namelen, int flags)
+{
+ struct sockaddr *sa;
+ struct file *fp, *fp1;
+ int bflags, len;
+ struct socket *so;
+ int error, error1;
+
+ bflags = 0;
+ fp = NULL;
+ sa = NULL;
+
+ error = linux_set_socket_flags(flags, &bflags);
+ if (error != 0)
+ return (error);
+
+ if (PTRIN(addr) == NULL) {
+ len = 0;
+ error = kern_accept4(td, s, NULL, NULL, bflags, NULL);
+ } else {
+ error = copyin(PTRIN(namelen), &len, sizeof(len));
+ if (error != 0)
+ return (error);
+ if (len < 0)
+ return (EINVAL);
+ error = kern_accept4(td, s, &sa, &len, bflags, &fp);
+ }
+
+ /*
+ * Translate errno values into ones used by Linux.
+ */
+ if (error != 0) {
+ /*
+ * XXX. This is wrong, different sockaddr structures
+ * have different sizes.
+ */
+ switch (error) {
+ case EFAULT:
+ if (namelen != sizeof(struct sockaddr_in))
+ error = EINVAL;
+ break;
+ case EINVAL:
+ error1 = getsock_cap(td, s, &cap_accept_rights, &fp1, NULL, NULL);
+ if (error1 != 0) {
+ error = error1;
+ break;
+ }
+ so = fp1->f_data;
+ if (so->so_type == SOCK_DGRAM)
+ error = EOPNOTSUPP;
+ fdrop(fp1, td);
+ break;
+ }
+ return (error);
+ }
+
+ if (len != 0) {
+ error = linux_copyout_sockaddr(sa, PTRIN(addr), len);
+
+ /*
+ * XXX: We should also copyout the len, shouldn't we?
+ */
+
+ if (error != 0) {
+ fdclose(td, fp, td->td_retval[0]);
+ td->td_retval[0] = 0;
+ }
+ }
+ if (fp != NULL)
+ fdrop(fp, td);
+ free(sa, M_SONAME);
+ return (error);
+}
+
+int
+linux_accept(struct thread *td, struct linux_accept_args *args)
+{
+
+ return (linux_accept_common(td, args->s, args->addr,
+ args->namelen, 0));
+}
+
+int
+linux_accept4(struct thread *td, struct linux_accept4_args *args)
+{
+
+ return (linux_accept_common(td, args->s, args->addr,
+ args->namelen, args->flags));
+}
+
+int
+linux_getsockname(struct thread *td, struct linux_getsockname_args *args)
+{
+ struct sockaddr *sa;
+ int len, error;
+
+ error = copyin(PTRIN(args->namelen), &len, sizeof(len));
+ if (error != 0)
+ return (error);
+
+ error = kern_getsockname(td, args->s, &sa, &len);
+ if (error != 0)
+ return (error);
+
+ if (len != 0)
+ error = linux_copyout_sockaddr(sa, PTRIN(args->addr), len);
+
+ free(sa, M_SONAME);
+ if (error == 0)
+ error = copyout(&len, PTRIN(args->namelen), sizeof(len));
+ return (error);
+}
+
+int
+linux_getpeername(struct thread *td, struct linux_getpeername_args *args)
+{
+ struct sockaddr *sa;
+ int len, error;
+
+ error = copyin(PTRIN(args->namelen), &len, sizeof(len));
+ if (error != 0)
+ return (error);
+ if (len < 0)
+ return (EINVAL);
+
+ error = kern_getpeername(td, args->s, &sa, &len);
+ if (error != 0)
+ return (error);
+
+ if (len != 0)
+ error = linux_copyout_sockaddr(sa, PTRIN(args->addr), len);
+
+ free(sa, M_SONAME);
+ if (error == 0)
+ error = copyout(&len, PTRIN(args->namelen), sizeof(len));
+ return (error);
+}
+
+int
+linux_socketpair(struct thread *td, struct linux_socketpair_args *args)
+{
+ int domain, error, sv[2], type;
+
+ domain = linux_to_bsd_domain(args->domain);
+ if (domain != PF_LOCAL)
+ return (EAFNOSUPPORT);
+ type = args->type & LINUX_SOCK_TYPE_MASK;
+ if (type < 0 || type > LINUX_SOCK_MAX)
+ return (EINVAL);
+ error = linux_set_socket_flags(args->type & ~LINUX_SOCK_TYPE_MASK,
+ &type);
+ if (error != 0)
+ return (error);
+ if (args->protocol != 0 && args->protocol != PF_UNIX) {
+ /*
+ * Use of PF_UNIX as protocol argument is not right,
+ * but Linux does it.
+ * Do not map PF_UNIX as its Linux value is identical
+ * to FreeBSD one.
+ */
+ return (EPROTONOSUPPORT);
+ }
+ error = kern_socketpair(td, domain, type, 0, sv);
+ if (error != 0)
+ return (error);
+ error = copyout(sv, PTRIN(args->rsv), 2 * sizeof(int));
+ if (error != 0) {
+ (void)kern_close(td, sv[0]);
+ (void)kern_close(td, sv[1]);
+ }
+ return (error);
+}
+
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+struct linux_send_args {
+ register_t s;
+ register_t msg;
+ register_t len;
+ register_t flags;
+};
+
+static int
+linux_send(struct thread *td, struct linux_send_args *args)
+{
+ struct sendto_args /* {
+ int s;
+ caddr_t buf;
+ int len;
+ int flags;
+ caddr_t to;
+ int tolen;
+ } */ bsd_args;
+ struct file *fp;
+ int error, fflag;
+
+ bsd_args.s = args->s;
+ bsd_args.buf = (caddr_t)PTRIN(args->msg);
+ bsd_args.len = args->len;
+ bsd_args.flags = linux_to_bsd_msg_flags(args->flags);
+ bsd_args.to = NULL;
+ bsd_args.tolen = 0;
+ error = sys_sendto(td, &bsd_args);
+ if (error == ENOTCONN) {
+ /*
+ * Linux doesn't return ENOTCONN for non-blocking sockets.
+ * Instead it returns the EAGAIN.
+ */
+ error = getsock_cap(td, args->s, &cap_send_rights, &fp,
+ &fflag, NULL);
+ if (error == 0) {
+ if (fflag & FNONBLOCK)
+ error = EAGAIN;
+ fdrop(fp, td);
+ }
+ }
+ return (error);
+}
+
+struct linux_recv_args {
+ register_t s;
+ register_t msg;
+ register_t len;
+ register_t flags;
+};
+
+static int
+linux_recv(struct thread *td, struct linux_recv_args *args)
+{
+ struct recvfrom_args /* {
+ int s;
+ caddr_t buf;
+ int len;
+ int flags;
+ struct sockaddr *from;
+ socklen_t fromlenaddr;
+ } */ bsd_args;
+
+ bsd_args.s = args->s;
+ bsd_args.buf = (caddr_t)PTRIN(args->msg);
+ bsd_args.len = args->len;
+ bsd_args.flags = linux_to_bsd_msg_flags(args->flags);
+ bsd_args.from = NULL;
+ bsd_args.fromlenaddr = 0;
+ return (sys_recvfrom(td, &bsd_args));
+}
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+
+int
+linux_sendto(struct thread *td, struct linux_sendto_args *args)
+{
+ struct msghdr msg;
+ struct iovec aiov;
+
+ if (linux_check_hdrincl(td, args->s) == 0)
+ /* IP_HDRINCL set, tweak the packet before sending */
+ return (linux_sendto_hdrincl(td, args));
+
+ msg.msg_name = PTRIN(args->to);
+ msg.msg_namelen = args->tolen;
+ msg.msg_iov = &aiov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+ msg.msg_flags = 0;
+ aiov.iov_base = PTRIN(args->msg);
+ aiov.iov_len = args->len;
+ return (linux_sendit(td, args->s, &msg, args->flags, NULL,
+ UIO_USERSPACE));
+}
+
+int
+linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args)
+{
+ struct sockaddr *sa;
+ struct msghdr msg;
+ struct iovec aiov;
+ int error, fromlen;
+
+ if (PTRIN(args->fromlen) != NULL) {
+ error = copyin(PTRIN(args->fromlen), &fromlen,
+ sizeof(fromlen));
+ if (error != 0)
+ return (error);
+ if (fromlen < 0)
+ return (EINVAL);
+ sa = malloc(fromlen, M_SONAME, M_WAITOK);
+ } else {
+ fromlen = 0;
+ sa = NULL;
+ }
+
+ msg.msg_name = sa;
+ msg.msg_namelen = fromlen;
+ msg.msg_iov = &aiov;
+ msg.msg_iovlen = 1;
+ aiov.iov_base = PTRIN(args->buf);
+ aiov.iov_len = args->len;
+ msg.msg_control = 0;
+ msg.msg_flags = linux_to_bsd_msg_flags(args->flags);
+
+ error = kern_recvit(td, args->s, &msg, UIO_SYSSPACE, NULL);
+ if (error != 0)
+ goto out;
+
+ if (PTRIN(args->from) != NULL)
+ error = linux_copyout_sockaddr(sa, PTRIN(args->from), msg.msg_namelen);
+
+ if (error == 0 && PTRIN(args->fromlen) != NULL)
+ error = copyout(&msg.msg_namelen, PTRIN(args->fromlen),
+ sizeof(msg.msg_namelen));
+out:
+ free(sa, M_SONAME);
+ return (error);
+}
+
+static int
+linux_sendmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
+ l_uint flags)
+{
+ struct cmsghdr *cmsg;
+ struct mbuf *control;
+ struct msghdr msg;
+ struct l_cmsghdr linux_cmsg;
+ struct l_cmsghdr *ptr_cmsg;
+ struct l_msghdr linux_msghdr;
+ struct iovec *iov;
+ socklen_t datalen;
+ struct sockaddr *sa;
+ struct socket *so;
+ sa_family_t sa_family;
+ struct file *fp;
+ void *data;
+ l_size_t len;
+ l_size_t clen;
+ int error, fflag;
+
+ error = copyin(msghdr, &linux_msghdr, sizeof(linux_msghdr));
+ if (error != 0)
+ return (error);
+
+ /*
+ * Some Linux applications (ping) define a non-NULL control data
+ * pointer, but a msg_controllen of 0, which is not allowed in the
+ * FreeBSD system call interface. NULL the msg_control pointer in
+ * order to handle this case. This should be checked, but allows the
+ * Linux ping to work.
+ */
+ if (PTRIN(linux_msghdr.msg_control) != NULL &&
+ linux_msghdr.msg_controllen == 0)
+ linux_msghdr.msg_control = PTROUT(NULL);
+
+ error = linux_to_bsd_msghdr(&msg, &linux_msghdr);
+ if (error != 0)
+ return (error);
+
+#ifdef COMPAT_LINUX32
+ error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen,
+ &iov, EMSGSIZE);
+#else
+ error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
+#endif
+ if (error != 0)
+ return (error);
+
+ control = NULL;
+
+ error = kern_getsockname(td, s, &sa, &datalen);
+ if (error != 0)
+ goto bad;
+ sa_family = sa->sa_family;
+ free(sa, M_SONAME);
+
+ if (flags & LINUX_MSG_OOB) {
+ error = EOPNOTSUPP;
+ if (sa_family == AF_UNIX)
+ goto bad;
+
+ error = getsock_cap(td, s, &cap_send_rights, &fp,
+ &fflag, NULL);
+ if (error != 0)
+ goto bad;
+ so = fp->f_data;
+ if (so->so_type != SOCK_STREAM)
+ error = EOPNOTSUPP;
+ fdrop(fp, td);
+ if (error != 0)
+ goto bad;
+ }
+
+ if (linux_msghdr.msg_controllen >= sizeof(struct l_cmsghdr)) {
+ error = ENOBUFS;
+ control = m_get(M_WAITOK, MT_CONTROL);
+ MCLGET(control, M_WAITOK);
+ data = mtod(control, void *);
+ datalen = 0;
+
+ ptr_cmsg = PTRIN(linux_msghdr.msg_control);
+ clen = linux_msghdr.msg_controllen;
+ do {
+ error = copyin(ptr_cmsg, &linux_cmsg,
+ sizeof(struct l_cmsghdr));
+ if (error != 0)
+ goto bad;
+
+ error = EINVAL;
+ if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr) ||
+ linux_cmsg.cmsg_len > clen)
+ goto bad;
+
+ if (datalen + CMSG_HDRSZ > MCLBYTES)
+ goto bad;
+
+ /*
+ * Now we support only SCM_RIGHTS and SCM_CRED,
+ * so return EINVAL in any other cmsg_type
+ */
+ cmsg = data;
+ cmsg->cmsg_type =
+ linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type);
+ cmsg->cmsg_level =
+ linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level);
+ if (cmsg->cmsg_type == -1
+ || cmsg->cmsg_level != SOL_SOCKET) {
+ linux_msg(curthread,
+ "unsupported sendmsg cmsg level %d type %d",
+ linux_cmsg.cmsg_level, linux_cmsg.cmsg_type);
+ goto bad;
+ }
+
+ /*
+ * Some applications (e.g. pulseaudio) attempt to
+ * send ancillary data even if the underlying protocol
+ * doesn't support it which is not allowed in the
+ * FreeBSD system call interface.
+ */
+ if (sa_family != AF_UNIX)
+ goto next;
+
+ if (cmsg->cmsg_type == SCM_CREDS) {
+ len = sizeof(struct cmsgcred);
+ if (datalen + CMSG_SPACE(len) > MCLBYTES)
+ goto bad;
+
+ /*
+ * The lower levels will fill in the structure
+ */
+ memset(CMSG_DATA(data), 0, len);
+ } else {
+ len = linux_cmsg.cmsg_len - L_CMSG_HDRSZ;
+ if (datalen + CMSG_SPACE(len) < datalen ||
+ datalen + CMSG_SPACE(len) > MCLBYTES)
+ goto bad;
+
+ error = copyin(LINUX_CMSG_DATA(ptr_cmsg),
+ CMSG_DATA(data), len);
+ if (error != 0)
+ goto bad;
+ }
+
+ cmsg->cmsg_len = CMSG_LEN(len);
+ data = (char *)data + CMSG_SPACE(len);
+ datalen += CMSG_SPACE(len);
+
+next:
+ if (clen <= LINUX_CMSG_ALIGN(linux_cmsg.cmsg_len))
+ break;
+
+ clen -= LINUX_CMSG_ALIGN(linux_cmsg.cmsg_len);
+ ptr_cmsg = (struct l_cmsghdr *)((char *)ptr_cmsg +
+ LINUX_CMSG_ALIGN(linux_cmsg.cmsg_len));
+ } while(clen >= sizeof(struct l_cmsghdr));
+
+ control->m_len = datalen;
+ if (datalen == 0) {
+ m_freem(control);
+ control = NULL;
+ }
+ }
+
+ msg.msg_iov = iov;
+ msg.msg_flags = 0;
+ error = linux_sendit(td, s, &msg, flags, control, UIO_USERSPACE);
+ control = NULL;
+
+bad:
+ m_freem(control);
+ free(iov, M_IOV);
+ return (error);
+}
+
+int
+linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
+{
+
+ return (linux_sendmsg_common(td, args->s, PTRIN(args->msg),
+ args->flags));
+}
+
+int
+linux_sendmmsg(struct thread *td, struct linux_sendmmsg_args *args)
+{
+ struct l_mmsghdr *msg;
+ l_uint retval;
+ int error, datagrams;
+
+ if (args->vlen > UIO_MAXIOV)
+ args->vlen = UIO_MAXIOV;
+
+ msg = PTRIN(args->msg);
+ datagrams = 0;
+ while (datagrams < args->vlen) {
+ error = linux_sendmsg_common(td, args->s, &msg->msg_hdr,
+ args->flags);
+ if (error != 0)
+ break;
+
+ retval = td->td_retval[0];
+ error = copyout(&retval, &msg->msg_len, sizeof(msg->msg_len));
+ if (error != 0)
+ break;
+ ++msg;
+ ++datagrams;
+ }
+ if (error == 0)
+ td->td_retval[0] = datagrams;
+ return (error);
+}
+
+static int
+linux_recvmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
+ l_uint flags, struct msghdr *msg)
+{
+ struct cmsghdr *cm;
+ struct cmsgcred *cmcred;
+ struct sockcred2 *scred;
+ struct l_cmsghdr *linux_cmsg = NULL;
+ struct l_ucred linux_ucred;
+ socklen_t datalen, maxlen, outlen;
+ struct l_msghdr linux_msghdr;
+ struct iovec *iov, *uiov;
+ struct mbuf *control = NULL;
+ struct mbuf **controlp;
+ struct timeval *ftmvl;
+ struct sockaddr *sa;
+ l_timeval ltmvl;
+ caddr_t outbuf;
+ void *data;
+ int error, i, fd, fds, *fdp;
+
+ error = copyin(msghdr, &linux_msghdr, sizeof(linux_msghdr));
+ if (error != 0)
+ return (error);
+
+ error = linux_to_bsd_msghdr(msg, &linux_msghdr);
+ if (error != 0)
+ return (error);
+
+#ifdef COMPAT_LINUX32
+ error = linux32_copyiniov(PTRIN(msg->msg_iov), msg->msg_iovlen,
+ &iov, EMSGSIZE);
+#else
+ error = copyiniov(msg->msg_iov, msg->msg_iovlen, &iov, EMSGSIZE);
+#endif
+ if (error != 0)
+ return (error);
+
+ if (msg->msg_name != NULL && msg->msg_namelen > 0) {
+ msg->msg_namelen = min(msg->msg_namelen, SOCK_MAXADDRLEN);
+ sa = malloc(msg->msg_namelen, M_SONAME, M_WAITOK);
+ msg->msg_name = sa;
+ } else {
+ sa = NULL;
+ msg->msg_name = NULL;
+ }
+
+ uiov = msg->msg_iov;
+ msg->msg_iov = iov;
+ controlp = (msg->msg_control != NULL) ? &control : NULL;
+ error = kern_recvit(td, s, msg, UIO_SYSSPACE, controlp);
+ msg->msg_iov = uiov;
+ if (error != 0)
+ goto bad;
+
+ /*
+ * Note that kern_recvit() updates msg->msg_namelen.
+ */
+ if (msg->msg_name != NULL && msg->msg_namelen > 0) {
+ msg->msg_name = PTRIN(linux_msghdr.msg_name);
+ error = linux_copyout_sockaddr(sa,
+ PTRIN(msg->msg_name), msg->msg_namelen);
+ if (error != 0)
+ goto bad;
+ }
+
+ error = bsd_to_linux_msghdr(msg, &linux_msghdr);
+ if (error != 0)
+ goto bad;
+
+ maxlen = linux_msghdr.msg_controllen;
+ linux_msghdr.msg_controllen = 0;
+ if (control) {
+ linux_cmsg = malloc(L_CMSG_HDRSZ, M_LINUX, M_WAITOK | M_ZERO);
+
+ msg->msg_control = mtod(control, struct cmsghdr *);
+ msg->msg_controllen = control->m_len;
+
+ cm = CMSG_FIRSTHDR(msg);
+ outbuf = PTRIN(linux_msghdr.msg_control);
+ outlen = 0;
+ while (cm != NULL) {
+ linux_cmsg->cmsg_type =
+ bsd_to_linux_cmsg_type(cm->cmsg_type);
+ linux_cmsg->cmsg_level =
+ bsd_to_linux_sockopt_level(cm->cmsg_level);
+ if (linux_cmsg->cmsg_type == -1 ||
+ cm->cmsg_level != SOL_SOCKET) {
+ linux_msg(curthread,
+ "unsupported recvmsg cmsg level %d type %d",
+ cm->cmsg_level, cm->cmsg_type);
+ error = EINVAL;
+ goto bad;
+ }
+
+ data = CMSG_DATA(cm);
+ datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
+
+ switch (cm->cmsg_type) {
+ case SCM_RIGHTS:
+ if (flags & LINUX_MSG_CMSG_CLOEXEC) {
+ fds = datalen / sizeof(int);
+ fdp = data;
+ for (i = 0; i < fds; i++) {
+ fd = *fdp++;
+ (void)kern_fcntl(td, fd,
+ F_SETFD, FD_CLOEXEC);
+ }
+ }
+ break;
+
+ case SCM_CREDS:
+ /*
+ * Currently LOCAL_CREDS is never in
+ * effect for Linux so no need to worry
+ * about sockcred
+ */
+ if (datalen != sizeof(*cmcred)) {
+ error = EMSGSIZE;
+ goto bad;
+ }
+ cmcred = (struct cmsgcred *)data;
+ bzero(&linux_ucred, sizeof(linux_ucred));
+ linux_ucred.pid = cmcred->cmcred_pid;
+ linux_ucred.uid = cmcred->cmcred_uid;
+ linux_ucred.gid = cmcred->cmcred_gid;
+ data = &linux_ucred;
+ datalen = sizeof(linux_ucred);
+ break;
+
+ case SCM_CREDS2:
+ scred = data;
+ bzero(&linux_ucred, sizeof(linux_ucred));
+ linux_ucred.pid = scred->sc_pid;
+ linux_ucred.uid = scred->sc_uid;
+ linux_ucred.gid = scred->sc_gid;
+ data = &linux_ucred;
+ datalen = sizeof(linux_ucred);
+ break;
+
+ case SCM_TIMESTAMP:
+ if (datalen != sizeof(struct timeval)) {
+ error = EMSGSIZE;
+ goto bad;
+ }
+ ftmvl = (struct timeval *)data;
+ ltmvl.tv_sec = ftmvl->tv_sec;
+ ltmvl.tv_usec = ftmvl->tv_usec;
+ data = &ltmvl;
+ datalen = sizeof(ltmvl);
+ break;
+ }
+
+ if (outlen + LINUX_CMSG_LEN(datalen) > maxlen) {
+ if (outlen == 0) {
+ error = EMSGSIZE;
+ goto bad;
+ } else {
+ linux_msghdr.msg_flags |= LINUX_MSG_CTRUNC;
+ m_dispose_extcontrolm(control);
+ goto out;
+ }
+ }
+
+ linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen);
+
+ error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ);
+ if (error != 0)
+ goto bad;
+ outbuf += L_CMSG_HDRSZ;
+
+ error = copyout(data, outbuf, datalen);
+ if (error != 0)
+ goto bad;
+
+ outbuf += LINUX_CMSG_ALIGN(datalen);
+ outlen += LINUX_CMSG_LEN(datalen);
+
+ cm = CMSG_NXTHDR(msg, cm);
+ }
+ linux_msghdr.msg_controllen = outlen;
+ }
+
+out:
+ error = copyout(&linux_msghdr, msghdr, sizeof(linux_msghdr));
+
+bad:
+ if (control != NULL) {
+ if (error != 0)
+ m_dispose_extcontrolm(control);
+ m_freem(control);
+ }
+ free(iov, M_IOV);
+ free(linux_cmsg, M_LINUX);
+ free(sa, M_SONAME);
+
+ return (error);
+}
+
+int
+linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
+{
+ struct msghdr bsd_msg;
+
+ return (linux_recvmsg_common(td, args->s, PTRIN(args->msg),
+ args->flags, &bsd_msg));
+}
+
+int
+linux_recvmmsg(struct thread *td, struct linux_recvmmsg_args *args)
+{
+ struct l_mmsghdr *msg;
+ struct msghdr bsd_msg;
+ struct l_timespec lts;
+ struct timespec ts, tts;
+ l_uint retval;
+ int error, datagrams;
+
+ if (args->timeout) {
+ error = copyin(args->timeout, &lts, sizeof(struct l_timespec));
+ if (error != 0)
+ return (error);
+ error = linux_to_native_timespec(&ts, &lts);
+ if (error != 0)
+ return (error);
+ getnanotime(&tts);
+ timespecadd(&tts, &ts, &tts);
+ }
+
+ msg = PTRIN(args->msg);
+ datagrams = 0;
+ while (datagrams < args->vlen) {
+ error = linux_recvmsg_common(td, args->s, &msg->msg_hdr,
+ args->flags & ~LINUX_MSG_WAITFORONE, &bsd_msg);
+ if (error != 0)
+ break;
+
+ retval = td->td_retval[0];
+ error = copyout(&retval, &msg->msg_len, sizeof(msg->msg_len));
+ if (error != 0)
+ break;
+ ++msg;
+ ++datagrams;
+
+ /*
+ * MSG_WAITFORONE turns on MSG_DONTWAIT after one packet.
+ */
+ if (args->flags & LINUX_MSG_WAITFORONE)
+ args->flags |= LINUX_MSG_DONTWAIT;
+
+ /*
+ * See BUGS section of recvmmsg(2).
+ */
+ if (args->timeout) {
+ getnanotime(&ts);
+ timespecsub(&ts, &tts, &ts);
+ if (!timespecisset(&ts) || ts.tv_sec > 0)
+ break;
+ }
+ /* Out of band data, return right away. */
+ if (bsd_msg.msg_flags & MSG_OOB)
+ break;
+ }
+ if (error == 0)
+ td->td_retval[0] = datagrams;
+ return (error);
+}
+
+int
+linux_shutdown(struct thread *td, struct linux_shutdown_args *args)
+{
+
+ return (kern_shutdown(td, args->s, args->how));
+}
+
+int
+linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
+{
+ l_timeval linux_tv;
+ struct sockaddr *sa;
+ struct timeval tv;
+ socklen_t len;
+ int error, level, name;
+
+ level = linux_to_bsd_sockopt_level(args->level);
+ switch (level) {
+ case SOL_SOCKET:
+ name = linux_to_bsd_so_sockopt(args->optname);
+ switch (name) {
+ case LOCAL_CREDS_PERSISTENT:
+ level = SOL_LOCAL;
+ break;
+ case SO_RCVTIMEO:
+ /* FALLTHROUGH */
+ case SO_SNDTIMEO:
+ error = copyin(PTRIN(args->optval), &linux_tv,
+ sizeof(linux_tv));
+ if (error != 0)
+ return (error);
+ tv.tv_sec = linux_tv.tv_sec;
+ tv.tv_usec = linux_tv.tv_usec;
+ return (kern_setsockopt(td, args->s, level,
+ name, &tv, UIO_SYSSPACE, sizeof(tv)));
+ /* NOTREACHED */
+ default:
+ break;
+ }
+ break;
+ case IPPROTO_IP:
+ if (args->optname == LINUX_IP_RECVERR &&
+ linux_ignore_ip_recverr) {
+ /*
+ * XXX: This is a hack to unbreak DNS resolution
+ * with glibc 2.30 and above.
+ */
+ return (0);
+ }
+ name = linux_to_bsd_ip_sockopt(args->optname);
+ break;
+ case IPPROTO_IPV6:
+ name = linux_to_bsd_ip6_sockopt(args->optname);
+ break;
+ case IPPROTO_TCP:
+ name = linux_to_bsd_tcp_sockopt(args->optname);
+ break;
+ default:
+ name = -1;
+ break;
+ }
+ if (name < 0) {
+ if (name == -1)
+ linux_msg(curthread,
+ "unsupported setsockopt level %d optname %d",
+ args->level, args->optname);
+ return (ENOPROTOOPT);
+ }
+
+ if (name == IPV6_NEXTHOP) {
+ len = args->optlen;
+ error = linux_to_bsd_sockaddr(PTRIN(args->optval), &sa, &len);
+ if (error != 0)
+ return (error);
+
+ error = kern_setsockopt(td, args->s, level,
+ name, sa, UIO_SYSSPACE, len);
+ free(sa, M_SONAME);
+ } else {
+ error = kern_setsockopt(td, args->s, level,
+ name, PTRIN(args->optval), UIO_USERSPACE, args->optlen);
+ }
+
+ return (error);
+}
+
+static int
+linux_getsockopt_so_peersec(struct thread *td,
+ struct linux_getsockopt_args *args)
+{
+ socklen_t len;
+ int error;
+
+ len = sizeof(SECURITY_CONTEXT_STRING);
+ if (args->optlen < len) {
+ error = copyout(&len, PTRIN(args->optlen), sizeof(len));
+ if (error == 0)
+ error = ERANGE;
+ return (error);
+ }
+
+ error = copyout(SECURITY_CONTEXT_STRING,
+ PTRIN(args->optval), sizeof(SECURITY_CONTEXT_STRING));
+ if (error == 0)
+ error = copyout(&len, PTRIN(args->optlen), sizeof(len));
+ return (error);
+}
+
+int
+linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
+{
+ l_timeval linux_tv;
+ struct timeval tv;
+ socklen_t tv_len, xulen, len;
+ struct sockaddr *sa;
+ struct xucred xu;
+ struct l_ucred lxu;
+ int error, level, name, newval;
+
+ level = linux_to_bsd_sockopt_level(args->level);
+ switch (level) {
+ case SOL_SOCKET:
+ if (args->optname == LINUX_SO_PEERSEC)
+ return (linux_getsockopt_so_peersec(td, args));
+ name = linux_to_bsd_so_sockopt(args->optname);
+ switch (name) {
+ case LOCAL_CREDS_PERSISTENT:
+ level = SOL_LOCAL;
+ break;
+ case SO_RCVTIMEO:
+ /* FALLTHROUGH */
+ case SO_SNDTIMEO:
+ tv_len = sizeof(tv);
+ error = kern_getsockopt(td, args->s, level,
+ name, &tv, UIO_SYSSPACE, &tv_len);
+ if (error != 0)
+ return (error);
+ linux_tv.tv_sec = tv.tv_sec;
+ linux_tv.tv_usec = tv.tv_usec;
+ return (copyout(&linux_tv, PTRIN(args->optval),
+ sizeof(linux_tv)));
+ /* NOTREACHED */
+ case LOCAL_PEERCRED:
+ if (args->optlen < sizeof(lxu))
+ return (EINVAL);
+ /*
+ * LOCAL_PEERCRED is not served at the SOL_SOCKET level,
+ * but by the Unix socket's level 0.
+ */
+ level = 0;
+ xulen = sizeof(xu);
+ error = kern_getsockopt(td, args->s, level,
+ name, &xu, UIO_SYSSPACE, &xulen);
+ if (error != 0)
+ return (error);
+ lxu.pid = xu.cr_pid;
+ lxu.uid = xu.cr_uid;
+ lxu.gid = xu.cr_gid;
+ return (copyout(&lxu, PTRIN(args->optval), sizeof(lxu)));
+ /* NOTREACHED */
+ case SO_ERROR:
+ len = sizeof(newval);
+ error = kern_getsockopt(td, args->s, level,
+ name, &newval, UIO_SYSSPACE, &len);
+ if (error != 0)
+ return (error);
+ newval = -bsd_to_linux_errno(newval);
+ return (copyout(&newval, PTRIN(args->optval), len));
+ /* NOTREACHED */
+ default:
+ break;
+ }
+ break;
+ case IPPROTO_IP:
+ name = linux_to_bsd_ip_sockopt(args->optname);
+ break;
+ case IPPROTO_IPV6:
+ name = linux_to_bsd_ip6_sockopt(args->optname);
+ break;
+ case IPPROTO_TCP:
+ name = linux_to_bsd_tcp_sockopt(args->optname);
+ break;
+ default:
+ name = -1;
+ break;
+ }
+ if (name < 0) {
+ if (name == -1)
+ linux_msg(curthread,
+ "unsupported getsockopt level %d optname %d",
+ args->level, args->optname);
+ return (EINVAL);
+ }
+
+ if (name == IPV6_NEXTHOP) {
+ error = copyin(PTRIN(args->optlen), &len, sizeof(len));
+ if (error != 0)
+ return (error);
+ sa = malloc(len, M_SONAME, M_WAITOK);
+
+ error = kern_getsockopt(td, args->s, level,
+ name, sa, UIO_SYSSPACE, &len);
+ if (error != 0)
+ goto out;
+
+ error = linux_copyout_sockaddr(sa, PTRIN(args->optval), len);
+ if (error == 0)
+ error = copyout(&len, PTRIN(args->optlen),
+ sizeof(len));
+out:
+ free(sa, M_SONAME);
+ } else {
+ if (args->optval) {
+ error = copyin(PTRIN(args->optlen), &len, sizeof(len));
+ if (error != 0)
+ return (error);
+ }
+ error = kern_getsockopt(td, args->s, level,
+ name, PTRIN(args->optval), UIO_USERSPACE, &len);
+ if (error == 0)
+ error = copyout(&len, PTRIN(args->optlen),
+ sizeof(len));
+ }
+
+ return (error);
+}
+
+static int
+linux_sendfile_common(struct thread *td, l_int out, l_int in,
+ l_loff_t *offset, l_size_t count)
+{
+ off_t bytes_read;
+ int error;
+ l_loff_t current_offset;
+ struct file *fp;
+
+ AUDIT_ARG_FD(in);
+ error = fget_read(td, in, &cap_pread_rights, &fp);
+ if (error != 0)
+ return (error);
+
+ if (offset != NULL) {
+ current_offset = *offset;
+ } else {
+ error = (fp->f_ops->fo_flags & DFLAG_SEEKABLE) != 0 ?
+ fo_seek(fp, 0, SEEK_CUR, td) : ESPIPE;
+ if (error != 0)
+ goto drop;
+ current_offset = td->td_uretoff.tdu_off;
+ }
+
+ bytes_read = 0;
+
+ /* Linux cannot have 0 count. */
+ if (count <= 0 || current_offset < 0) {
+ error = EINVAL;
+ goto drop;
+ }
+
+ error = fo_sendfile(fp, out, NULL, NULL, current_offset, count,
+ &bytes_read, 0, td);
+ if (error != 0)
+ goto drop;
+ current_offset += bytes_read;
+
+ if (offset != NULL) {
+ *offset = current_offset;
+ } else {
+ error = fo_seek(fp, current_offset, SEEK_SET, td);
+ if (error != 0)
+ goto drop;
+ }
+
+ td->td_retval[0] = (ssize_t)bytes_read;
+drop:
+ fdrop(fp, td);
+ return (error);
+}
+
+int
+linux_sendfile(struct thread *td, struct linux_sendfile_args *arg)
+{
+ /*
+ * Differences between FreeBSD and Linux sendfile:
+ * - Linux doesn't send anything when count is 0 (FreeBSD uses 0 to
+ * mean send the whole file.) In linux_sendfile given fds are still
+ * checked for validity when the count is 0.
+ * - Linux can send to any fd whereas FreeBSD only supports sockets.
+ * The same restriction follows for linux_sendfile.
+ * - Linux doesn't have an equivalent for FreeBSD's flags and sf_hdtr.
+ * - Linux takes an offset pointer and updates it to the read location.
+ * FreeBSD takes in an offset and a 'bytes read' parameter which is
+ * only filled if it isn't NULL. We use this parameter to update the
+ * offset pointer if it exists.
+ * - Linux sendfile returns bytes read on success while FreeBSD
+ * returns 0. We use the 'bytes read' parameter to get this value.
+ */
+
+ l_loff_t offset64;
+ l_long offset;
+ int ret;
+ int error;
+
+ if (arg->offset != NULL) {
+ error = copyin(arg->offset, &offset, sizeof(offset));
+ if (error != 0)
+ return (error);
+ offset64 = (l_loff_t)offset;
+ }
+
+ ret = linux_sendfile_common(td, arg->out, arg->in,
+ arg->offset != NULL ? &offset64 : NULL, arg->count);
+
+ if (arg->offset != NULL) {
+#if defined(__i386__) || defined(__arm__) || \
+ (defined(__amd64__) && defined(COMPAT_LINUX32))
+ if (offset64 > INT32_MAX)
+ return (EOVERFLOW);
+#endif
+ offset = (l_long)offset64;
+ error = copyout(&offset, arg->offset, sizeof(offset));
+ if (error != 0)
+ return (error);
+ }
+
+ return (ret);
+}
+
+#if defined(__i386__) || defined(__arm__) || \
+ (defined(__amd64__) && defined(COMPAT_LINUX32))
+
+int
+linux_sendfile64(struct thread *td, struct linux_sendfile64_args *arg)
+{
+ l_loff_t offset;
+ int ret;
+ int error;
+
+ if (arg->offset != NULL) {
+ error = copyin(arg->offset, &offset, sizeof(offset));
+ if (error != 0)
+ return (error);
+ }
+
+ ret = linux_sendfile_common(td, arg->out, arg->in,
+ arg->offset != NULL ? &offset : NULL, arg->count);
+
+ if (arg->offset != NULL) {
+ error = copyout(&offset, arg->offset, sizeof(offset));
+ if (error != 0)
+ return (error);
+ }
+
+ return (ret);
+}
+
+/* Argument list sizes for linux_socketcall */
+static const unsigned char lxs_args_cnt[] = {
+ 0 /* unused*/, 3 /* socket */,
+ 3 /* bind */, 3 /* connect */,
+ 2 /* listen */, 3 /* accept */,
+ 3 /* getsockname */, 3 /* getpeername */,
+ 4 /* socketpair */, 4 /* send */,
+ 4 /* recv */, 6 /* sendto */,
+ 6 /* recvfrom */, 2 /* shutdown */,
+ 5 /* setsockopt */, 5 /* getsockopt */,
+ 3 /* sendmsg */, 3 /* recvmsg */,
+ 4 /* accept4 */, 5 /* recvmmsg */,
+ 4 /* sendmmsg */, 4 /* sendfile */
+};
+#define LINUX_ARGS_CNT (nitems(lxs_args_cnt) - 1)
+#define LINUX_ARG_SIZE(x) (lxs_args_cnt[x] * sizeof(l_ulong))
+
+int
+linux_socketcall(struct thread *td, struct linux_socketcall_args *args)
+{
+ l_ulong a[6];
+#if defined(__amd64__) && defined(COMPAT_LINUX32)
+ register_t l_args[6];
+#endif
+ void *arg;
+ int error;
+
+ if (args->what < LINUX_SOCKET || args->what > LINUX_ARGS_CNT)
+ return (EINVAL);
+ error = copyin(PTRIN(args->args), a, LINUX_ARG_SIZE(args->what));
+ if (error != 0)
+ return (error);
+
+#if defined(__amd64__) && defined(COMPAT_LINUX32)
+ for (int i = 0; i < lxs_args_cnt[args->what]; ++i)
+ l_args[i] = a[i];
+ arg = l_args;
+#else
+ arg = a;
+#endif
+ switch (args->what) {
+ case LINUX_SOCKET:
+ return (linux_socket(td, arg));
+ case LINUX_BIND:
+ return (linux_bind(td, arg));
+ case LINUX_CONNECT:
+ return (linux_connect(td, arg));
+ case LINUX_LISTEN:
+ return (linux_listen(td, arg));
+ case LINUX_ACCEPT:
+ return (linux_accept(td, arg));
+ case LINUX_GETSOCKNAME:
+ return (linux_getsockname(td, arg));
+ case LINUX_GETPEERNAME:
+ return (linux_getpeername(td, arg));
+ case LINUX_SOCKETPAIR:
+ return (linux_socketpair(td, arg));
+ case LINUX_SEND:
+ return (linux_send(td, arg));
+ case LINUX_RECV:
+ return (linux_recv(td, arg));
+ case LINUX_SENDTO:
+ return (linux_sendto(td, arg));
+ case LINUX_RECVFROM:
+ return (linux_recvfrom(td, arg));
+ case LINUX_SHUTDOWN:
+ return (linux_shutdown(td, arg));
+ case LINUX_SETSOCKOPT:
+ return (linux_setsockopt(td, arg));
+ case LINUX_GETSOCKOPT:
+ return (linux_getsockopt(td, arg));
+ case LINUX_SENDMSG:
+ return (linux_sendmsg(td, arg));
+ case LINUX_RECVMSG:
+ return (linux_recvmsg(td, arg));
+ case LINUX_ACCEPT4:
+ return (linux_accept4(td, arg));
+ case LINUX_RECVMMSG:
+ return (linux_recvmmsg(td, arg));
+ case LINUX_SENDMMSG:
+ return (linux_sendmmsg(td, arg));
+ case LINUX_SENDFILE:
+ return (linux_sendfile(td, arg));
+ }
+
+ linux_msg(td, "socket type %d not implemented", args->what);
+ return (ENOSYS);
+}
+#endif /* __i386__ || __arm__ || (__amd64__ && COMPAT_LINUX32) */
diff --git a/sys/compat/linux/linux_socket.h b/sys/compat/linux/linux_socket.h
new file mode 100644
index 000000000000..32a19a348312
--- /dev/null
+++ b/sys/compat/linux/linux_socket.h
@@ -0,0 +1,318 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2000 Assar Westerlund
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_SOCKET_H_
+#define _LINUX_SOCKET_H_
+
+/* msg flags in recvfrom/recvmsg */
+
+#define LINUX_MSG_OOB 0x01
+#define LINUX_MSG_PEEK 0x02
+#define LINUX_MSG_DONTROUTE 0x04
+#define LINUX_MSG_CTRUNC 0x08
+#define LINUX_MSG_PROXY 0x10
+#define LINUX_MSG_TRUNC 0x20
+#define LINUX_MSG_DONTWAIT 0x40
+#define LINUX_MSG_EOR 0x80
+#define LINUX_MSG_WAITALL 0x100
+#define LINUX_MSG_FIN 0x200
+#define LINUX_MSG_SYN 0x400
+#define LINUX_MSG_CONFIRM 0x800
+#define LINUX_MSG_RST 0x1000
+#define LINUX_MSG_ERRQUEUE 0x2000
+#define LINUX_MSG_NOSIGNAL 0x4000
+#define LINUX_MSG_WAITFORONE 0x10000
+#define LINUX_MSG_CMSG_CLOEXEC 0x40000000
+
+/* Socket-level control message types */
+
+#define LINUX_SCM_RIGHTS 0x01
+#define LINUX_SCM_CREDENTIALS 0x02
+#define LINUX_SCM_TIMESTAMP 0x1D
+
+struct l_msghdr {
+ l_uintptr_t msg_name;
+ l_int msg_namelen;
+ l_uintptr_t msg_iov;
+ l_size_t msg_iovlen;
+ l_uintptr_t msg_control;
+ l_size_t msg_controllen;
+ l_uint msg_flags;
+};
+
+struct l_mmsghdr {
+ struct l_msghdr msg_hdr;
+ l_uint msg_len;
+
+};
+
+struct l_cmsghdr {
+ l_size_t cmsg_len;
+ l_int cmsg_level;
+ l_int cmsg_type;
+};
+
+/* Ancillary data object information macros */
+
+#define LINUX_CMSG_ALIGN(len) roundup2(len, sizeof(l_ulong))
+#define LINUX_CMSG_DATA(cmsg) ((void *)((char *)(cmsg) + \
+ LINUX_CMSG_ALIGN(sizeof(struct l_cmsghdr))))
+#define LINUX_CMSG_SPACE(len) (LINUX_CMSG_ALIGN(sizeof(struct l_cmsghdr)) + \
+ LINUX_CMSG_ALIGN(len))
+#define LINUX_CMSG_LEN(len) (LINUX_CMSG_ALIGN(sizeof(struct l_cmsghdr)) + \
+ (len))
+#define LINUX_CMSG_FIRSTHDR(msg) \
+ ((msg)->msg_controllen >= \
+ sizeof(struct l_cmsghdr) ? \
+ (struct l_cmsghdr *) \
+ PTRIN((msg)->msg_control) : \
+ (struct l_cmsghdr *)(NULL))
+#define LINUX_CMSG_NXTHDR(msg, cmsg) \
+ ((((char *)(cmsg) + \
+ LINUX_CMSG_ALIGN((cmsg)->cmsg_len) + \
+ sizeof(*(cmsg))) > \
+ (((char *)PTRIN((msg)->msg_control)) + \
+ (msg)->msg_controllen)) ? \
+ (struct l_cmsghdr *) NULL : \
+ (struct l_cmsghdr *)((char *)(cmsg) + \
+ LINUX_CMSG_ALIGN((cmsg)->cmsg_len)))
+
+#define CMSG_HDRSZ CMSG_LEN(0)
+#define L_CMSG_HDRSZ LINUX_CMSG_LEN(0)
+
+/* Supported socket types */
+
+#define LINUX_SOCK_STREAM 1
+#define LINUX_SOCK_DGRAM 2
+#define LINUX_SOCK_RAW 3
+#define LINUX_SOCK_RDM 4
+#define LINUX_SOCK_SEQPACKET 5
+
+#define LINUX_SOCK_MAX LINUX_SOCK_SEQPACKET
+
+#define LINUX_SOCK_TYPE_MASK 0xf
+
+/* Flags for socket, socketpair, accept4 */
+
+#define LINUX_SOCK_CLOEXEC LINUX_O_CLOEXEC
+#define LINUX_SOCK_NONBLOCK LINUX_O_NONBLOCK
+
+struct l_ucred {
+ uint32_t pid;
+ uint32_t uid;
+ uint32_t gid;
+};
+
+#if defined(__i386__) || defined(__arm__) || \
+ (defined(__amd64__) && defined(COMPAT_LINUX32))
+
+struct linux_accept_args {
+ register_t s;
+ register_t addr;
+ register_t namelen;
+};
+
+int linux_accept(struct thread *td, struct linux_accept_args *args);
+
+/* Operations for socketcall */
+#define LINUX_SOCKET 1
+#define LINUX_BIND 2
+#define LINUX_CONNECT 3
+#define LINUX_LISTEN 4
+#define LINUX_ACCEPT 5
+#define LINUX_GETSOCKNAME 6
+#define LINUX_GETPEERNAME 7
+#define LINUX_SOCKETPAIR 8
+#define LINUX_SEND 9
+#define LINUX_RECV 10
+#define LINUX_SENDTO 11
+#define LINUX_RECVFROM 12
+#define LINUX_SHUTDOWN 13
+#define LINUX_SETSOCKOPT 14
+#define LINUX_GETSOCKOPT 15
+#define LINUX_SENDMSG 16
+#define LINUX_RECVMSG 17
+#define LINUX_ACCEPT4 18
+#define LINUX_RECVMMSG 19
+#define LINUX_SENDMMSG 20
+#define LINUX_SENDFILE 21
+
+#endif /* __i386__ || __arm__ || (__amd64__ && COMPAT_LINUX32) */
+
+/* Socket defines */
+#define LINUX_SOL_SOCKET 1
+
+#define LINUX_SO_DEBUG 1
+#define LINUX_SO_REUSEADDR 2
+#define LINUX_SO_TYPE 3
+#define LINUX_SO_ERROR 4
+#define LINUX_SO_DONTROUTE 5
+#define LINUX_SO_BROADCAST 6
+#define LINUX_SO_SNDBUF 7
+#define LINUX_SO_RCVBUF 8
+#define LINUX_SO_KEEPALIVE 9
+#define LINUX_SO_OOBINLINE 10
+#define LINUX_SO_NO_CHECK 11
+#define LINUX_SO_PRIORITY 12
+#define LINUX_SO_LINGER 13
+#define LINUX_SO_REUSEPORT 15
+#ifndef LINUX_SO_PASSCRED /* powerpc differs */
+#define LINUX_SO_PASSCRED 16
+#define LINUX_SO_PEERCRED 17
+#define LINUX_SO_RCVLOWAT 18
+#define LINUX_SO_SNDLOWAT 19
+#define LINUX_SO_RCVTIMEO 20
+#define LINUX_SO_SNDTIMEO 21
+#endif
+#define LINUX_SO_TIMESTAMP 29
+#define LINUX_SO_ACCEPTCONN 30
+#define LINUX_SO_PEERSEC 31
+#define LINUX_SO_SNDBUFFORCE 32
+#define LINUX_SO_RCVBUFFORCE 33
+#define LINUX_SO_PROTOCOL 38
+
+/* Socket options */
+#define LINUX_IP_TOS 1
+#define LINUX_IP_TTL 2
+#define LINUX_IP_HDRINCL 3
+#define LINUX_IP_OPTIONS 4
+#define LINUX_IP_ROUTER_ALERT 5
+#define LINUX_IP_RECVOPTS 6
+#define LINUX_IP_RETOPTS 7
+#define LINUX_IP_PKTINFO 8
+#define LINUX_IP_PKTOPTIONS 9
+#define LINUX_IP_MTU_DISCOVER 10
+#define LINUX_IP_RECVERR 11
+#define LINUX_IP_RECVTTL 12
+#define LINUX_IP_RECVTOS 13
+#define LINUX_IP_MTU 14
+#define LINUX_IP_FREEBIND 15
+#define LINUX_IP_IPSEC_POLICY 16
+#define LINUX_IP_XFRM_POLICY 17
+#define LINUX_IP_PASSSEC 18
+#define LINUX_IP_TRANSPARENT 19
+
+#define LINUX_IP_MINTTL 21
+#define LINUX_IP_NODEFRAG 22
+#define LINUX_IP_CHECKSUM 23
+#define LINUX_IP_BIND_ADDRESS_NO_PORT 24
+#define LINUX_IP_RECVFRAGSIZE 25
+
+#define LINUX_IP_MULTICAST_IF 32
+#define LINUX_IP_MULTICAST_TTL 33
+#define LINUX_IP_MULTICAST_LOOP 34
+#define LINUX_IP_ADD_MEMBERSHIP 35
+#define LINUX_IP_DROP_MEMBERSHIP 36
+#define LINUX_IP_UNBLOCK_SOURCE 37
+#define LINUX_IP_BLOCK_SOURCE 38
+#define LINUX_IP_ADD_SOURCE_MEMBERSHIP 39
+#define LINUX_IP_DROP_SOURCE_MEMBERSHIP 40
+#define LINUX_IP_MSFILTER 41
+
+#define LINUX_MCAST_JOIN_GROUP 42
+#define LINUX_MCAST_BLOCK_SOURCE 43
+#define LINUX_MCAST_UNBLOCK_SOURCE 44
+#define LINUX_MCAST_LEAVE_GROUP 45
+#define LINUX_MCAST_JOIN_SOURCE_GROUP 46
+#define LINUX_MCAST_LEAVE_SOURCE_GROUP 47
+#define LINUX_MCAST_MSFILTER 48
+#define LINUX_IP_MULTICAST_ALL 49
+#define LINUX_IP_UNICAST_IF 50
+
+#define LINUX_IPV6_ADDRFORM 1
+#define LINUX_IPV6_2292PKTINFO 2
+#define LINUX_IPV6_2292HOPOPTS 3
+#define LINUX_IPV6_2292DSTOPTS 4
+#define LINUX_IPV6_2292RTHDR 5
+#define LINUX_IPV6_2292PKTOPTIONS 6
+#define LINUX_IPV6_CHECKSUM 7
+#define LINUX_IPV6_2292HOPLIMIT 8
+#define LINUX_IPV6_NEXTHOP 9
+#define LINUX_IPV6_AUTHHDR 10
+#define LINUX_IPV6_FLOWINFO 11
+
+#define LINUX_IPV6_UNICAST_HOPS 16
+#define LINUX_IPV6_MULTICAST_IF 17
+#define LINUX_IPV6_MULTICAST_HOPS 18
+#define LINUX_IPV6_MULTICAST_LOOP 19
+#define LINUX_IPV6_ADD_MEMBERSHIP 20
+#define LINUX_IPV6_DROP_MEMBERSHIP 21
+#define LINUX_IPV6_ROUTER_ALERT 22
+#define LINUX_IPV6_MTU_DISCOVER 23
+#define LINUX_IPV6_MTU 24
+#define LINUX_IPV6_RECVERR 25
+#define LINUX_IPV6_V6ONLY 26
+#define LINUX_IPV6_JOIN_ANYCAST 27
+#define LINUX_IPV6_LEAVE_ANYCAST 28
+#define LINUX_IPV6_MULTICAST_ALL 29
+#define LINUX_IPV6_ROUTER_ALERT_ISOLATE 30
+
+#define LINUX_IPV6_FLOWLABEL_MGR 32
+#define LINUX_IPV6_FLOWINFO_SEND 33
+
+#define LINUX_IPV6_IPSEC_POLICY 34
+#define LINUX_IPV6_XFRM_POLICY 35
+#define LINUX_IPV6_HDRINCL 36
+
+#define LINUX_IPV6_RECVPKTINFO 49
+#define LINUX_IPV6_PKTINFO 50
+#define LINUX_IPV6_RECVHOPLIMIT 51
+#define LINUX_IPV6_HOPLIMIT 52
+#define LINUX_IPV6_RECVHOPOPTS 53
+#define LINUX_IPV6_HOPOPTS 54
+#define LINUX_IPV6_RTHDRDSTOPTS 55
+#define LINUX_IPV6_RECVRTHDR 56
+#define LINUX_IPV6_RTHDR 57
+#define LINUX_IPV6_RECVDSTOPTS 58
+#define LINUX_IPV6_DSTOPTS 59
+#define LINUX_IPV6_RECVPATHMTU 60
+#define LINUX_IPV6_PATHMTU 61
+#define LINUX_IPV6_DONTFRAG 62
+
+#define LINUX_IPV6_AUTOFLOWLABEL 70
+#define LINUX_IPV6_ADDR_PREFERENCES 72
+#define LINUX_IPV6_MINHOPCOUNT 73
+#define LINUX_IPV6_ORIGDSTADDR 74
+#define LINUX_IPV6_TRANSPARENT 75
+#define LINUX_IPV6_UNICAST_IF 76
+#define LINUX_IPV6_RECVFRAGSIZE 77
+#define LINUX_IPV6_FREEBIND 78
+
+#define LINUX_TCP_NODELAY 1
+#define LINUX_TCP_MAXSEG 2
+#define LINUX_TCP_CORK 3
+#define LINUX_TCP_KEEPIDLE 4
+#define LINUX_TCP_KEEPINTVL 5
+#define LINUX_TCP_KEEPCNT 6
+#define LINUX_TCP_MD5SIG 14
+
+#endif /* _LINUX_SOCKET_H_ */
diff --git a/sys/compat/linux/linux_stats.c b/sys/compat/linux/linux_stats.c
new file mode 100644
index 000000000000..01f9cada670b
--- /dev/null
+++ b/sys/compat/linux/linux_stats.c
@@ -0,0 +1,723 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1994-1995 Søren Schmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_compat.h"
+
+#include <sys/param.h>
+#include <sys/capsicum.h>
+#include <sys/dirent.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/stat.h>
+#include <sys/syscallsubr.h>
+#include <sys/systm.h>
+#include <sys/tty.h>
+#include <sys/vnode.h>
+#include <sys/conf.h>
+#include <sys/fcntl.h>
+
+#ifdef COMPAT_LINUX32
+#include <machine/../linux32/linux.h>
+#include <machine/../linux32/linux32_proto.h>
+#else
+#include <machine/../linux/linux.h>
+#include <machine/../linux/linux_proto.h>
+#endif
+
+#include <compat/linux/linux_util.h>
+#include <compat/linux/linux_file.h>
+
+static void
+translate_vnhook_major_minor(struct vnode *vp, struct stat *sb)
+{
+ int major, minor;
+
+ if (vn_isdisk(vp)) {
+ sb->st_mode &= ~S_IFMT;
+ sb->st_mode |= S_IFBLK;
+ }
+
+ /*
+ * Return the same st_dev for every devfs instance. The reason
+ * for this is to work around an idiosyncrasy of glibc getttynam()
+ * implementation: it checks whether st_dev returned for fd 0
+ * is the same as st_dev returned for the target of /proc/self/fd/0
+ * symlink, and with linux chroots having their own devfs instance,
+ * the check will fail if you chroot into it.
+ */
+ if (rootdevmp != NULL && vp->v_mount->mnt_vfc == rootdevmp->mnt_vfc)
+ sb->st_dev = rootdevmp->mnt_stat.f_fsid.val[0];
+
+ if (linux_vn_get_major_minor(vp, &major, &minor) == 0)
+ sb->st_rdev = (major << 8 | minor);
+}
+
+static int
+linux_kern_statat(struct thread *td, int flag, int fd, const char *path,
+ enum uio_seg pathseg, struct stat *sbp)
+{
+
+ return (kern_statat(td, flag, fd, path, pathseg, sbp,
+ translate_vnhook_major_minor));
+}
+
+#ifdef LINUX_LEGACY_SYSCALLS
+static int
+linux_kern_stat(struct thread *td, const char *path, enum uio_seg pathseg,
+ struct stat *sbp)
+{
+
+ return (linux_kern_statat(td, 0, AT_FDCWD, path, pathseg, sbp));
+}
+
+static int
+linux_kern_lstat(struct thread *td, const char *path, enum uio_seg pathseg,
+ struct stat *sbp)
+{
+
+ return (linux_kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, path,
+ pathseg, sbp));
+}
+#endif
+
+static void
+translate_fd_major_minor(struct thread *td, int fd, struct stat *buf)
+{
+ struct file *fp;
+ struct vnode *vp;
+ struct mount *mp;
+ int major, minor;
+
+ /*
+ * No capability rights required here.
+ */
+ if ((!S_ISCHR(buf->st_mode) && !S_ISBLK(buf->st_mode)) ||
+ fget(td, fd, &cap_no_rights, &fp) != 0)
+ return;
+ vp = fp->f_vnode;
+ if (vp != NULL && vn_isdisk(vp)) {
+ buf->st_mode &= ~S_IFMT;
+ buf->st_mode |= S_IFBLK;
+ }
+ if (vp != NULL && rootdevmp != NULL) {
+ mp = vp->v_mount;
+ __compiler_membar();
+ if (mp != NULL && mp->mnt_vfc == rootdevmp->mnt_vfc)
+ buf->st_dev = rootdevmp->mnt_stat.f_fsid.val[0];
+ }
+ if (linux_vn_get_major_minor(vp, &major, &minor) == 0) {
+ buf->st_rdev = (major << 8 | minor);
+ } else if (fp->f_type == DTYPE_PTS) {
+ struct tty *tp = fp->f_data;
+
+ /* Convert the numbers for the slave device. */
+ if (linux_driver_get_major_minor(devtoname(tp->t_dev),
+ &major, &minor) == 0) {
+ buf->st_rdev = (major << 8 | minor);
+ }
+ }
+ fdrop(fp, td);
+}
+
+/*
+ * l_dev_t has the same encoding as dev_t in the latter's low 16 bits, so
+ * truncation of a dev_t to 16 bits gives the same result as unpacking
+ * using major() and minor() and repacking in the l_dev_t format. This
+ * detail is hidden in dev_to_ldev(). Overflow in conversions of dev_t's
+ * are not checked for, as for other fields.
+ *
+ * dev_to_ldev() is only used for translating st_dev. When we convert
+ * st_rdev for copying it out, it isn't really a dev_t, but has already
+ * been translated to an l_dev_t in a nontrivial way. Translating it
+ * again would be illogical but would have no effect since the low 16
+ * bits have the same encoding.
+ *
+ * The nontrivial translation for st_rdev renumbers some devices, but not
+ * ones that can be mounted on, so it is consistent with the translation
+ * for st_dev except when the renumbering or truncation causes conflicts.
+ */
+#define dev_to_ldev(d) ((uint16_t)(d))
+
+static int
+newstat_copyout(struct stat *buf, void *ubuf)
+{
+ struct l_newstat tbuf;
+
+ bzero(&tbuf, sizeof(tbuf));
+ tbuf.st_dev = dev_to_ldev(buf->st_dev);
+ tbuf.st_ino = buf->st_ino;
+ tbuf.st_mode = buf->st_mode;
+ tbuf.st_nlink = buf->st_nlink;
+ tbuf.st_uid = buf->st_uid;
+ tbuf.st_gid = buf->st_gid;
+ tbuf.st_rdev = buf->st_rdev;
+ tbuf.st_size = buf->st_size;
+ tbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
+ tbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
+ tbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
+ tbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
+ tbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
+ tbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
+ tbuf.st_blksize = buf->st_blksize;
+ tbuf.st_blocks = buf->st_blocks;
+
+ return (copyout(&tbuf, ubuf, sizeof(tbuf)));
+}
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_newstat(struct thread *td, struct linux_newstat_args *args)
+{
+ struct stat buf;
+ char *path;
+ int error;
+
+ if (!LUSECONVPATH(td)) {
+ error = linux_kern_stat(td, args->path, UIO_USERSPACE, &buf);
+ } else {
+ LCONVPATHEXIST(td, args->path, &path);
+ error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf);
+ LFREEPATH(path);
+ }
+ if (error)
+ return (error);
+ return (newstat_copyout(&buf, args->buf));
+}
+
+int
+linux_newlstat(struct thread *td, struct linux_newlstat_args *args)
+{
+ struct stat sb;
+ char *path;
+ int error;
+
+ if (!LUSECONVPATH(td)) {
+ error = linux_kern_lstat(td, args->path, UIO_USERSPACE, &sb);
+ } else {
+ LCONVPATHEXIST(td, args->path, &path);
+ error = linux_kern_lstat(td, path, UIO_SYSSPACE, &sb);
+ LFREEPATH(path);
+ }
+ if (error)
+ return (error);
+ return (newstat_copyout(&sb, args->buf));
+}
+#endif
+
+int
+linux_newfstat(struct thread *td, struct linux_newfstat_args *args)
+{
+ struct stat buf;
+ int error;
+
+ error = kern_fstat(td, args->fd, &buf);
+ translate_fd_major_minor(td, args->fd, &buf);
+ if (!error)
+ error = newstat_copyout(&buf, args->buf);
+
+ return (error);
+}
+
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+static int
+stat_copyout(struct stat *buf, void *ubuf)
+{
+ struct l_stat lbuf;
+
+ bzero(&lbuf, sizeof(lbuf));
+ lbuf.st_dev = dev_to_ldev(buf->st_dev);
+ lbuf.st_ino = buf->st_ino;
+ lbuf.st_mode = buf->st_mode;
+ lbuf.st_nlink = buf->st_nlink;
+ lbuf.st_uid = buf->st_uid;
+ lbuf.st_gid = buf->st_gid;
+ lbuf.st_rdev = buf->st_rdev;
+ lbuf.st_size = MIN(buf->st_size, INT32_MAX);
+ lbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
+ lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
+ lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
+ lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
+ lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
+ lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
+ lbuf.st_blksize = buf->st_blksize;
+ lbuf.st_blocks = buf->st_blocks;
+ lbuf.st_flags = buf->st_flags;
+ lbuf.st_gen = buf->st_gen;
+
+ return (copyout(&lbuf, ubuf, sizeof(lbuf)));
+}
+
+int
+linux_stat(struct thread *td, struct linux_stat_args *args)
+{
+ struct stat buf;
+ char *path;
+ int error;
+
+ if (!LUSECONVPATH(td)) {
+ error = linux_kern_stat(td, args->path, UIO_USERSPACE, &buf);
+ } else {
+ LCONVPATHEXIST(td, args->path, &path);
+ error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf);
+ LFREEPATH(path);
+ }
+ if (error) {
+ return (error);
+ }
+ return (stat_copyout(&buf, args->up));
+}
+
+int
+linux_lstat(struct thread *td, struct linux_lstat_args *args)
+{
+ struct stat buf;
+ char *path;
+ int error;
+
+ if (!LUSECONVPATH(td)) {
+ error = linux_kern_lstat(td, args->path, UIO_USERSPACE, &buf);
+ } else {
+ LCONVPATHEXIST(td, args->path, &path);
+ error = linux_kern_lstat(td, path, UIO_SYSSPACE, &buf);
+ LFREEPATH(path);
+ }
+ if (error) {
+ return (error);
+ }
+ return (stat_copyout(&buf, args->up));
+}
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+
+struct l_statfs {
+ l_long f_type;
+ l_long f_bsize;
+ l_long f_blocks;
+ l_long f_bfree;
+ l_long f_bavail;
+ l_long f_files;
+ l_long f_ffree;
+ l_fsid_t f_fsid;
+ l_long f_namelen;
+ l_long f_frsize;
+ l_long f_flags;
+ l_long f_spare[4];
+};
+
+#define LINUX_CODA_SUPER_MAGIC 0x73757245L
+#define LINUX_EXT2_SUPER_MAGIC 0xEF53L
+#define LINUX_HPFS_SUPER_MAGIC 0xf995e849L
+#define LINUX_ISOFS_SUPER_MAGIC 0x9660L
+#define LINUX_MSDOS_SUPER_MAGIC 0x4d44L
+#define LINUX_NCP_SUPER_MAGIC 0x564cL
+#define LINUX_NFS_SUPER_MAGIC 0x6969L
+#define LINUX_NTFS_SUPER_MAGIC 0x5346544EL
+#define LINUX_PROC_SUPER_MAGIC 0x9fa0L
+#define LINUX_UFS_SUPER_MAGIC 0x00011954L /* XXX - UFS_MAGIC in Linux */
+#define LINUX_ZFS_SUPER_MAGIC 0x2FC12FC1
+#define LINUX_DEVFS_SUPER_MAGIC 0x1373L
+#define LINUX_SHMFS_MAGIC 0x01021994
+
+static long
+bsd_to_linux_ftype(const char *fstypename)
+{
+ int i;
+ static struct {const char *bsd_name; long linux_type;} b2l_tbl[] = {
+ {"ufs", LINUX_UFS_SUPER_MAGIC},
+ {"zfs", LINUX_ZFS_SUPER_MAGIC},
+ {"cd9660", LINUX_ISOFS_SUPER_MAGIC},
+ {"nfs", LINUX_NFS_SUPER_MAGIC},
+ {"ext2fs", LINUX_EXT2_SUPER_MAGIC},
+ {"procfs", LINUX_PROC_SUPER_MAGIC},
+ {"msdosfs", LINUX_MSDOS_SUPER_MAGIC},
+ {"ntfs", LINUX_NTFS_SUPER_MAGIC},
+ {"nwfs", LINUX_NCP_SUPER_MAGIC},
+ {"hpfs", LINUX_HPFS_SUPER_MAGIC},
+ {"coda", LINUX_CODA_SUPER_MAGIC},
+ {"devfs", LINUX_DEVFS_SUPER_MAGIC},
+ {"tmpfs", LINUX_SHMFS_MAGIC},
+ {NULL, 0L}};
+
+ for (i = 0; b2l_tbl[i].bsd_name != NULL; i++)
+ if (strcmp(b2l_tbl[i].bsd_name, fstypename) == 0)
+ return (b2l_tbl[i].linux_type);
+
+ return (0L);
+}
+
+static int
+bsd_to_linux_statfs(struct statfs *bsd_statfs, struct l_statfs *linux_statfs)
+{
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+ uint64_t tmp;
+
+#define LINUX_HIBITS 0xffffffff00000000ULL
+
+ tmp = bsd_statfs->f_blocks | bsd_statfs->f_bfree | bsd_statfs->f_files |
+ bsd_statfs->f_bsize;
+ if ((bsd_statfs->f_bavail != -1 && (bsd_statfs->f_bavail & LINUX_HIBITS)) ||
+ (bsd_statfs->f_ffree != -1 && (bsd_statfs->f_ffree & LINUX_HIBITS)) ||
+ (tmp & LINUX_HIBITS))
+ return (EOVERFLOW);
+#undef LINUX_HIBITS
+#endif
+ linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename);
+ linux_statfs->f_bsize = bsd_statfs->f_bsize;
+ linux_statfs->f_blocks = bsd_statfs->f_blocks;
+ linux_statfs->f_bfree = bsd_statfs->f_bfree;
+ linux_statfs->f_bavail = bsd_statfs->f_bavail;
+ linux_statfs->f_ffree = bsd_statfs->f_ffree;
+ linux_statfs->f_files = bsd_statfs->f_files;
+ linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0];
+ linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1];
+ linux_statfs->f_namelen = MAXNAMLEN;
+ linux_statfs->f_frsize = bsd_statfs->f_bsize;
+ linux_statfs->f_flags = 0;
+ memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare));
+
+ return (0);
+}
+
+int
+linux_statfs(struct thread *td, struct linux_statfs_args *args)
+{
+ struct l_statfs linux_statfs;
+ struct statfs *bsd_statfs;
+ char *path;
+ int error;
+
+ if (!LUSECONVPATH(td)) {
+ bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
+ error = kern_statfs(td, args->path, UIO_USERSPACE, bsd_statfs);
+ } else {
+ LCONVPATHEXIST(td, args->path, &path);
+ bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
+ error = kern_statfs(td, path, UIO_SYSSPACE, bsd_statfs);
+ LFREEPATH(path);
+ }
+ if (error == 0)
+ error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs);
+ free(bsd_statfs, M_STATFS);
+ if (error != 0)
+ return (error);
+ return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
+}
+
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+static void
+bsd_to_linux_statfs64(struct statfs *bsd_statfs, struct l_statfs64 *linux_statfs)
+{
+
+ linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename);
+ linux_statfs->f_bsize = bsd_statfs->f_bsize;
+ linux_statfs->f_blocks = bsd_statfs->f_blocks;
+ linux_statfs->f_bfree = bsd_statfs->f_bfree;
+ linux_statfs->f_bavail = bsd_statfs->f_bavail;
+ linux_statfs->f_ffree = bsd_statfs->f_ffree;
+ linux_statfs->f_files = bsd_statfs->f_files;
+ linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0];
+ linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1];
+ linux_statfs->f_namelen = MAXNAMLEN;
+ linux_statfs->f_frsize = bsd_statfs->f_bsize;
+ linux_statfs->f_flags = 0;
+ memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare));
+}
+
+int
+linux_statfs64(struct thread *td, struct linux_statfs64_args *args)
+{
+ struct l_statfs64 linux_statfs;
+ struct statfs *bsd_statfs;
+ char *path;
+ int error;
+
+ if (args->bufsize != sizeof(struct l_statfs64))
+ return (EINVAL);
+
+ if (!LUSECONVPATH(td)) {
+ bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
+ error = kern_statfs(td, args->path, UIO_USERSPACE, bsd_statfs);
+ } else {
+ LCONVPATHEXIST(td, args->path, &path);
+ bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
+ error = kern_statfs(td, path, UIO_SYSSPACE, bsd_statfs);
+ LFREEPATH(path);
+ }
+ if (error == 0)
+ bsd_to_linux_statfs64(bsd_statfs, &linux_statfs);
+ free(bsd_statfs, M_STATFS);
+ if (error != 0)
+ return (error);
+ return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
+}
+
+int
+linux_fstatfs64(struct thread *td, struct linux_fstatfs64_args *args)
+{
+ struct l_statfs64 linux_statfs;
+ struct statfs *bsd_statfs;
+ int error;
+
+ if (args->bufsize != sizeof(struct l_statfs64))
+ return (EINVAL);
+
+ bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
+ error = kern_fstatfs(td, args->fd, bsd_statfs);
+ if (error == 0)
+ bsd_to_linux_statfs64(bsd_statfs, &linux_statfs);
+ free(bsd_statfs, M_STATFS);
+ if (error != 0)
+ return (error);
+ return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
+}
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+
+int
+linux_fstatfs(struct thread *td, struct linux_fstatfs_args *args)
+{
+ struct l_statfs linux_statfs;
+ struct statfs *bsd_statfs;
+ int error;
+
+ bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
+ error = kern_fstatfs(td, args->fd, bsd_statfs);
+ if (error == 0)
+ error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs);
+ free(bsd_statfs, M_STATFS);
+ if (error != 0)
+ return (error);
+ return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
+}
+
+struct l_ustat
+{
+ l_daddr_t f_tfree;
+ l_ino_t f_tinode;
+ char f_fname[6];
+ char f_fpack[6];
+};
+
+#ifdef LINUX_LEGACY_SYSCALLS
+int
+linux_ustat(struct thread *td, struct linux_ustat_args *args)
+{
+
+ return (EOPNOTSUPP);
+}
+#endif
+
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+
+static int
+stat64_copyout(struct stat *buf, void *ubuf)
+{
+ struct l_stat64 lbuf;
+
+ bzero(&lbuf, sizeof(lbuf));
+ lbuf.st_dev = dev_to_ldev(buf->st_dev);
+ lbuf.st_ino = buf->st_ino;
+ lbuf.st_mode = buf->st_mode;
+ lbuf.st_nlink = buf->st_nlink;
+ lbuf.st_uid = buf->st_uid;
+ lbuf.st_gid = buf->st_gid;
+ lbuf.st_rdev = buf->st_rdev;
+ lbuf.st_size = buf->st_size;
+ lbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
+ lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
+ lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
+ lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
+ lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
+ lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
+ lbuf.st_blksize = buf->st_blksize;
+ lbuf.st_blocks = buf->st_blocks;
+
+ /*
+ * The __st_ino field makes all the difference. In the Linux kernel
+ * it is conditionally compiled based on STAT64_HAS_BROKEN_ST_INO,
+ * but without the assignment to __st_ino the runtime linker refuses
+ * to mmap(2) any shared libraries. I guess it's broken alright :-)
+ */
+ lbuf.__st_ino = buf->st_ino;
+
+ return (copyout(&lbuf, ubuf, sizeof(lbuf)));
+}
+
+int
+linux_stat64(struct thread *td, struct linux_stat64_args *args)
+{
+ struct stat buf;
+ char *filename;
+ int error;
+
+ if (!LUSECONVPATH(td)) {
+ error = linux_kern_stat(td, args->filename, UIO_USERSPACE, &buf);
+ } else {
+ LCONVPATHEXIST(td, args->filename, &filename);
+ error = linux_kern_stat(td, filename, UIO_SYSSPACE, &buf);
+ LFREEPATH(filename);
+ }
+ if (error)
+ return (error);
+ return (stat64_copyout(&buf, args->statbuf));
+}
+
+int
+linux_lstat64(struct thread *td, struct linux_lstat64_args *args)
+{
+ struct stat sb;
+ char *filename;
+ int error;
+
+ if (!LUSECONVPATH(td)) {
+ error = linux_kern_lstat(td, args->filename, UIO_USERSPACE, &sb);
+ } else {
+ LCONVPATHEXIST(td, args->filename, &filename);
+ error = linux_kern_lstat(td, filename, UIO_SYSSPACE, &sb);
+ LFREEPATH(filename);
+ }
+ if (error)
+ return (error);
+ return (stat64_copyout(&sb, args->statbuf));
+}
+
+int
+linux_fstat64(struct thread *td, struct linux_fstat64_args *args)
+{
+ struct stat buf;
+ int error;
+
+ error = kern_fstat(td, args->fd, &buf);
+ translate_fd_major_minor(td, args->fd, &buf);
+ if (!error)
+ error = stat64_copyout(&buf, args->statbuf);
+
+ return (error);
+}
+
+int
+linux_fstatat64(struct thread *td, struct linux_fstatat64_args *args)
+{
+ char *path;
+ int error, dfd, flag;
+ struct stat buf;
+
+ if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
+ return (EINVAL);
+ flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ?
+ AT_SYMLINK_NOFOLLOW : 0;
+
+ dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
+ if (!LUSECONVPATH(td)) {
+ error = linux_kern_statat(td, flag, dfd, args->pathname,
+ UIO_USERSPACE, &buf);
+ } else {
+ LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
+ error = linux_kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf);
+ LFREEPATH(path);
+ }
+ if (error == 0)
+ error = stat64_copyout(&buf, args->statbuf);
+
+ return (error);
+}
+
+#else /* __amd64__ && !COMPAT_LINUX32 */
+
+int
+linux_newfstatat(struct thread *td, struct linux_newfstatat_args *args)
+{
+ char *path;
+ int error, dfd, flag;
+ struct stat buf;
+
+ if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
+ return (EINVAL);
+ flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ?
+ AT_SYMLINK_NOFOLLOW : 0;
+
+ dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
+ if (!LUSECONVPATH(td)) {
+ error = linux_kern_statat(td, flag, dfd, args->pathname,
+ UIO_USERSPACE, &buf);
+ } else {
+ LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
+ error = linux_kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf);
+ LFREEPATH(path);
+ }
+ if (error == 0)
+ error = newstat_copyout(&buf, args->statbuf);
+
+ return (error);
+}
+
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+
+int
+linux_syncfs(struct thread *td, struct linux_syncfs_args *args)
+{
+ struct mount *mp;
+ struct vnode *vp;
+ int error, save;
+
+ error = fgetvp(td, args->fd, &cap_fsync_rights, &vp);
+ if (error != 0)
+ /*
+ * Linux syncfs() returns only EBADF, however fgetvp()
+ * can return EINVAL in case of file descriptor does
+ * not represent a vnode. XXX.
+ */
+ return (error);
+
+ mp = vp->v_mount;
+ mtx_lock(&mountlist_mtx);
+ error = vfs_busy(mp, MBF_MNTLSTLOCK);
+ if (error != 0) {
+ /* See comment above. */
+ mtx_unlock(&mountlist_mtx);
+ goto out;
+ }
+ if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
+ vn_start_write(NULL, &mp, V_NOWAIT) == 0) {
+ save = curthread_pflags_set(TDP_SYNCIO);
+ vfs_periodic(mp, MNT_NOWAIT);
+ VFS_SYNC(mp, MNT_NOWAIT);
+ curthread_pflags_restore(save);
+ vn_finished_write(mp);
+ }
+ vfs_unbusy(mp);
+
+ out:
+ vrele(vp);
+ return (error);
+}
diff --git a/sys/compat/linux/linux_sysctl.c b/sys/compat/linux/linux_sysctl.c
new file mode 100644
index 000000000000..76d04164a807
--- /dev/null
+++ b/sys/compat/linux/linux_sysctl.c
@@ -0,0 +1,195 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2001 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_compat.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/sdt.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+#include <sys/sbuf.h>
+
+#ifdef COMPAT_LINUX32
+#include <machine/../linux32/linux.h>
+#include <machine/../linux32/linux32_proto.h>
+#else
+#include <machine/../linux/linux.h>
+#include <machine/../linux/linux_proto.h>
+#endif
+
+#include <compat/linux/linux_dtrace.h>
+#include <compat/linux/linux_misc.h>
+#include <compat/linux/linux_util.h>
+
+#define LINUX_CTL_KERN 1
+#define LINUX_CTL_VM 2
+#define LINUX_CTL_NET 3
+#define LINUX_CTL_PROC 4
+#define LINUX_CTL_FS 5
+#define LINUX_CTL_DEBUG 6
+#define LINUX_CTL_DEV 7
+#define LINUX_CTL_BUS 8
+
+/* CTL_KERN names */
+#define LINUX_KERN_OSTYPE 1
+#define LINUX_KERN_OSRELEASE 2
+#define LINUX_KERN_OSREV 3
+#define LINUX_KERN_VERSION 4
+
+/* DTrace init */
+LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
+
+/**
+ * DTrace probes in this module.
+ */
+LIN_SDT_PROBE_DEFINE2(sysctl, handle_string, entry, "struct l___sysctl_args *",
+ "char *");
+LIN_SDT_PROBE_DEFINE1(sysctl, handle_string, copyout_error, "int");
+LIN_SDT_PROBE_DEFINE1(sysctl, handle_string, return, "int");
+LIN_SDT_PROBE_DEFINE2(sysctl, linux_sysctl, entry, "struct l___sysctl_args *",
+ "struct thread *");
+LIN_SDT_PROBE_DEFINE1(sysctl, linux_sysctl, copyin_error, "int");
+LIN_SDT_PROBE_DEFINE2(sysctl, linux_sysctl, wrong_length, "int", "int");
+LIN_SDT_PROBE_DEFINE1(sysctl, linux_sysctl, unsupported_sysctl, "char *");
+LIN_SDT_PROBE_DEFINE1(sysctl, linux_sysctl, return, "int");
+
+#ifdef LINUX_LEGACY_SYSCALLS
+static int
+handle_string(struct l___sysctl_args *la, char *value)
+{
+ int error;
+
+ LIN_SDT_PROBE2(sysctl, handle_string, entry, la, value);
+
+ if (la->oldval != 0) {
+ l_int len = strlen(value);
+ error = copyout(value, PTRIN(la->oldval), len + 1);
+ if (!error && la->oldlenp != 0)
+ error = copyout(&len, PTRIN(la->oldlenp), sizeof(len));
+ if (error) {
+ LIN_SDT_PROBE1(sysctl, handle_string, copyout_error,
+ error);
+ LIN_SDT_PROBE1(sysctl, handle_string, return, error);
+ return (error);
+ }
+ }
+
+ if (la->newval != 0) {
+ LIN_SDT_PROBE1(sysctl, handle_string, return, ENOTDIR);
+ return (ENOTDIR);
+ }
+
+ LIN_SDT_PROBE1(sysctl, handle_string, return, 0);
+ return (0);
+}
+
+int
+linux_sysctl(struct thread *td, struct linux_sysctl_args *args)
+{
+ struct l___sysctl_args la;
+ struct sbuf *sb;
+ l_int *mib;
+ char *sysctl_string;
+ int error, i;
+
+ LIN_SDT_PROBE2(sysctl, linux_sysctl, entry, td, args->args);
+
+ error = copyin(args->args, &la, sizeof(la));
+ if (error) {
+ LIN_SDT_PROBE1(sysctl, linux_sysctl, copyin_error, error);
+ LIN_SDT_PROBE1(sysctl, linux_sysctl, return, error);
+ return (error);
+ }
+
+ if (la.nlen <= 0 || la.nlen > LINUX_CTL_MAXNAME) {
+ LIN_SDT_PROBE2(sysctl, linux_sysctl, wrong_length, la.nlen,
+ LINUX_CTL_MAXNAME);
+ LIN_SDT_PROBE1(sysctl, linux_sysctl, return, ENOTDIR);
+ return (ENOTDIR);
+ }
+
+ mib = malloc(la.nlen * sizeof(l_int), M_LINUX, M_WAITOK);
+ error = copyin(PTRIN(la.name), mib, la.nlen * sizeof(l_int));
+ if (error) {
+ LIN_SDT_PROBE1(sysctl, linux_sysctl, copyin_error, error);
+ LIN_SDT_PROBE1(sysctl, linux_sysctl, return, error);
+ free(mib, M_LINUX);
+ return (error);
+ }
+
+ switch (mib[0]) {
+ case LINUX_CTL_KERN:
+ if (la.nlen < 2)
+ break;
+
+ switch (mib[1]) {
+ case LINUX_KERN_VERSION:
+ error = handle_string(&la, version);
+ free(mib, M_LINUX);
+ LIN_SDT_PROBE1(sysctl, linux_sysctl, return, error);
+ return (error);
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ sb = sbuf_new(NULL, NULL, 20 + la.nlen * 5, SBUF_AUTOEXTEND);
+ if (sb == NULL) {
+ linux_msg(td, "sysctl is not implemented");
+ LIN_SDT_PROBE1(sysctl, linux_sysctl, unsupported_sysctl,
+ "unknown sysctl, ENOMEM during lookup");
+ } else {
+ sbuf_printf(sb, "sysctl ");
+ for (i = 0; i < la.nlen; i++)
+ sbuf_printf(sb, "%c%d", (i) ? ',' : '{', mib[i]);
+ sbuf_printf(sb, "} is not implemented");
+ sbuf_finish(sb);
+ sysctl_string = sbuf_data(sb);
+ linux_msg(td, "%s", sbuf_data(sb));
+ LIN_SDT_PROBE1(sysctl, linux_sysctl, unsupported_sysctl,
+ sysctl_string);
+ sbuf_delete(sb);
+ }
+
+ free(mib, M_LINUX);
+
+ LIN_SDT_PROBE1(sysctl, linux_sysctl, return, ENOTDIR);
+ return (ENOTDIR);
+}
+#endif
diff --git a/sys/compat/linux/linux_sysproto.h b/sys/compat/linux/linux_sysproto.h
new file mode 100644
index 000000000000..cc392fb1b5ea
--- /dev/null
+++ b/sys/compat/linux/linux_sysproto.h
@@ -0,0 +1,38 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2005 Travis Poppe
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef LINUX_SYSPROTO
+#define LINUX_SYSPROTO
+
+int linux_nosys(struct thread *, struct nosys_args *);
+
+#endif
diff --git a/sys/compat/linux/linux_time.c b/sys/compat/linux/linux_time.c
new file mode 100644
index 000000000000..6f1ef36a9114
--- /dev/null
+++ b/sys/compat/linux/linux_time.c
@@ -0,0 +1,655 @@
+/* $NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $ */
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-NetBSD
+ *
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Emmanuel Dreyfus.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#if 0
+__KERNEL_RCSID(0, "$NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $");
+#endif
+
+#include "opt_compat.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/ucred.h>
+#include <sys/limits.h>
+#include <sys/mount.h>
+#include <sys/mutex.h>
+#include <sys/resourcevar.h>
+#include <sys/sdt.h>
+#include <sys/signal.h>
+#include <sys/stdint.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysproto.h>
+#include <sys/time.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+
+#ifdef COMPAT_LINUX32
+#include <machine/../linux32/linux.h>
+#include <machine/../linux32/linux32_proto.h>
+#else
+#include <machine/../linux/linux.h>
+#include <machine/../linux/linux_proto.h>
+#endif
+
+#include <compat/linux/linux_dtrace.h>
+#include <compat/linux/linux_misc.h>
+#include <compat/linux/linux_timer.h>
+#include <compat/linux/linux_util.h>
+
+/* DTrace init */
+LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
+
+/**
+ * DTrace probes in this module.
+ */
+LIN_SDT_PROBE_DEFINE2(time, native_to_linux_timespec, entry,
+ "struct l_timespec *", "struct timespec *");
+LIN_SDT_PROBE_DEFINE0(time, native_to_linux_timespec, return);
+LIN_SDT_PROBE_DEFINE2(time, linux_to_native_timespec, entry,
+ "struct timespec *", "struct l_timespec *");
+LIN_SDT_PROBE_DEFINE1(time, linux_to_native_timespec, return, "int");
+LIN_SDT_PROBE_DEFINE2(time, linux_to_native_clockid, entry, "clockid_t *",
+ "clockid_t");
+LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unsupported_clockid,
+ "clockid_t");
+LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unknown_clockid,
+ "clockid_t");
+LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, return, "int");
+LIN_SDT_PROBE_DEFINE2(time, linux_clock_gettime, entry, "clockid_t",
+ "struct l_timespec *");
+LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, conversion_error, "int");
+LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, gettime_error, "int");
+LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, copyout_error, "int");
+LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, return, "int");
+LIN_SDT_PROBE_DEFINE2(time, linux_clock_settime, entry, "clockid_t",
+ "struct l_timespec *");
+LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, conversion_error, "int");
+LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, settime_error, "int");
+LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, copyin_error, "int");
+LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, return, "int");
+LIN_SDT_PROBE_DEFINE2(time, linux_clock_getres, entry, "clockid_t",
+ "struct l_timespec *");
+LIN_SDT_PROBE_DEFINE0(time, linux_clock_getres, nullcall);
+LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, conversion_error, "int");
+LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, getres_error, "int");
+LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, copyout_error, "int");
+LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, return, "int");
+LIN_SDT_PROBE_DEFINE2(time, linux_nanosleep, entry, "const struct l_timespec *",
+ "struct l_timespec *");
+LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, conversion_error, "int");
+LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyout_error, "int");
+LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyin_error, "int");
+LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, return, "int");
+LIN_SDT_PROBE_DEFINE4(time, linux_clock_nanosleep, entry, "clockid_t", "int",
+ "struct l_timespec *", "struct l_timespec *");
+LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, conversion_error, "int");
+LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyout_error, "int");
+LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyin_error, "int");
+LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, unsupported_flags, "int");
+LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, unsupported_clockid, "int");
+LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, return, "int");
+
+int
+native_to_linux_timespec(struct l_timespec *ltp, struct timespec *ntp)
+{
+
+ LIN_SDT_PROBE2(time, native_to_linux_timespec, entry, ltp, ntp);
+#ifdef COMPAT_LINUX32
+ if (ntp->tv_sec > INT_MAX || ntp->tv_sec < INT_MIN)
+ return (EOVERFLOW);
+#endif
+ ltp->tv_sec = ntp->tv_sec;
+ ltp->tv_nsec = ntp->tv_nsec;
+
+ LIN_SDT_PROBE0(time, native_to_linux_timespec, return);
+ return (0);
+}
+
+int
+linux_to_native_timespec(struct timespec *ntp, struct l_timespec *ltp)
+{
+
+ LIN_SDT_PROBE2(time, linux_to_native_timespec, entry, ntp, ltp);
+
+ if (ltp->tv_sec < 0 || ltp->tv_nsec < 0 || ltp->tv_nsec > 999999999) {
+ LIN_SDT_PROBE1(time, linux_to_native_timespec, return, EINVAL);
+ return (EINVAL);
+ }
+ ntp->tv_sec = ltp->tv_sec;
+ ntp->tv_nsec = ltp->tv_nsec;
+
+ LIN_SDT_PROBE1(time, linux_to_native_timespec, return, 0);
+ return (0);
+}
+
+int
+native_to_linux_itimerspec(struct l_itimerspec *ltp, struct itimerspec *ntp)
+{
+ int error;
+
+ error = native_to_linux_timespec(&ltp->it_interval, &ntp->it_interval);
+ if (error == 0)
+ error = native_to_linux_timespec(&ltp->it_value, &ntp->it_interval);
+ return (error);
+}
+
+int
+linux_to_native_itimerspec(struct itimerspec *ntp, struct l_itimerspec *ltp)
+{
+ int error;
+
+ error = linux_to_native_timespec(&ntp->it_interval, &ltp->it_interval);
+ if (error == 0)
+ error = linux_to_native_timespec(&ntp->it_value, &ltp->it_value);
+ return (error);
+}
+
+int
+linux_to_native_clockid(clockid_t *n, clockid_t l)
+{
+
+ LIN_SDT_PROBE2(time, linux_to_native_clockid, entry, n, l);
+
+ if (l < 0) {
+ /* cpu-clock */
+ if ((l & LINUX_CLOCKFD_MASK) == LINUX_CLOCKFD)
+ return (EINVAL);
+ if (LINUX_CPUCLOCK_WHICH(l) >= LINUX_CPUCLOCK_MAX)
+ return (EINVAL);
+
+ if (LINUX_CPUCLOCK_PERTHREAD(l))
+ *n = CLOCK_THREAD_CPUTIME_ID;
+ else
+ *n = CLOCK_PROCESS_CPUTIME_ID;
+ return (0);
+ }
+
+ switch (l) {
+ case LINUX_CLOCK_REALTIME:
+ *n = CLOCK_REALTIME;
+ break;
+ case LINUX_CLOCK_MONOTONIC:
+ *n = CLOCK_MONOTONIC;
+ break;
+ case LINUX_CLOCK_PROCESS_CPUTIME_ID:
+ *n = CLOCK_PROCESS_CPUTIME_ID;
+ break;
+ case LINUX_CLOCK_THREAD_CPUTIME_ID:
+ *n = CLOCK_THREAD_CPUTIME_ID;
+ break;
+ case LINUX_CLOCK_REALTIME_COARSE:
+ *n = CLOCK_REALTIME_FAST;
+ break;
+ case LINUX_CLOCK_MONOTONIC_COARSE:
+ case LINUX_CLOCK_MONOTONIC_RAW:
+ *n = CLOCK_MONOTONIC_FAST;
+ break;
+ case LINUX_CLOCK_BOOTTIME:
+ *n = CLOCK_UPTIME;
+ break;
+ case LINUX_CLOCK_REALTIME_ALARM:
+ case LINUX_CLOCK_BOOTTIME_ALARM:
+ case LINUX_CLOCK_SGI_CYCLE:
+ case LINUX_CLOCK_TAI:
+ LIN_SDT_PROBE1(time, linux_to_native_clockid,
+ unsupported_clockid, l);
+ LIN_SDT_PROBE1(time, linux_to_native_clockid, return, EINVAL);
+ return (EINVAL);
+ default:
+ LIN_SDT_PROBE1(time, linux_to_native_clockid,
+ unknown_clockid, l);
+ LIN_SDT_PROBE1(time, linux_to_native_clockid, return, EINVAL);
+ return (EINVAL);
+ }
+
+ LIN_SDT_PROBE1(time, linux_to_native_clockid, return, 0);
+ return (0);
+}
+
+int
+linux_to_native_timerflags(int *nflags, int flags)
+{
+
+ if (flags & ~LINUX_TIMER_ABSTIME)
+ return (EINVAL);
+ *nflags = 0;
+ if (flags & LINUX_TIMER_ABSTIME)
+ *nflags |= TIMER_ABSTIME;
+ return (0);
+}
+
+int
+linux_clock_gettime(struct thread *td, struct linux_clock_gettime_args *args)
+{
+ struct l_timespec lts;
+ struct timespec tp;
+ struct rusage ru;
+ struct thread *targettd;
+ struct proc *p;
+ int error, clockwhich;
+ clockid_t nwhich;
+ pid_t pid;
+ lwpid_t tid;
+
+ LIN_SDT_PROBE2(time, linux_clock_gettime, entry, args->which, args->tp);
+
+ error = linux_to_native_clockid(&nwhich, args->which);
+ if (error != 0) {
+ linux_msg(curthread,
+ "unsupported clock_gettime clockid %d", args->which);
+ LIN_SDT_PROBE1(time, linux_clock_gettime, conversion_error,
+ error);
+ LIN_SDT_PROBE1(time, linux_clock_gettime, return, error);
+ return (error);
+ }
+
+ switch (nwhich) {
+ case CLOCK_PROCESS_CPUTIME_ID:
+ if (args->which < 0) {
+ clockwhich = LINUX_CPUCLOCK_WHICH(args->which);
+ pid = LINUX_CPUCLOCK_ID(args->which);
+ } else {
+ clockwhich = LINUX_CPUCLOCK_SCHED;
+ pid = 0;
+ }
+ if (pid == 0) {
+ p = td->td_proc;
+ PROC_LOCK(p);
+ } else {
+ error = pget(pid, PGET_CANSEE, &p);
+ if (error != 0)
+ return (EINVAL);
+ }
+ switch (clockwhich) {
+ case LINUX_CPUCLOCK_PROF:
+ PROC_STATLOCK(p);
+ calcru(p, &ru.ru_utime, &ru.ru_stime);
+ PROC_STATUNLOCK(p);
+ PROC_UNLOCK(p);
+ timevaladd(&ru.ru_utime, &ru.ru_stime);
+ TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
+ break;
+ case LINUX_CPUCLOCK_VIRT:
+ PROC_STATLOCK(p);
+ calcru(p, &ru.ru_utime, &ru.ru_stime);
+ PROC_STATUNLOCK(p);
+ PROC_UNLOCK(p);
+ TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
+ break;
+ case LINUX_CPUCLOCK_SCHED:
+ kern_process_cputime(p, &tp);
+ PROC_UNLOCK(p);
+ break;
+ default:
+ PROC_UNLOCK(p);
+ return (EINVAL);
+ }
+
+ break;
+
+ case CLOCK_THREAD_CPUTIME_ID:
+ if (args->which < 0) {
+ clockwhich = LINUX_CPUCLOCK_WHICH(args->which);
+ tid = LINUX_CPUCLOCK_ID(args->which);
+ } else {
+ clockwhich = LINUX_CPUCLOCK_SCHED;
+ tid = 0;
+ }
+ p = td->td_proc;
+ if (tid == 0) {
+ targettd = td;
+ PROC_LOCK(p);
+ } else {
+ targettd = linux_tdfind(td, tid, p->p_pid);
+ if (targettd == NULL)
+ return (EINVAL);
+ }
+ switch (clockwhich) {
+ case LINUX_CPUCLOCK_PROF:
+ PROC_STATLOCK(p);
+ thread_lock(targettd);
+ rufetchtd(targettd, &ru);
+ thread_unlock(targettd);
+ PROC_STATUNLOCK(p);
+ PROC_UNLOCK(p);
+ timevaladd(&ru.ru_utime, &ru.ru_stime);
+ TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
+ break;
+ case LINUX_CPUCLOCK_VIRT:
+ PROC_STATLOCK(p);
+ thread_lock(targettd);
+ rufetchtd(targettd, &ru);
+ thread_unlock(targettd);
+ PROC_STATUNLOCK(p);
+ PROC_UNLOCK(p);
+ TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
+ break;
+ case LINUX_CPUCLOCK_SCHED:
+ if (td == targettd)
+ targettd = NULL;
+ kern_thread_cputime(targettd, &tp);
+ PROC_UNLOCK(p);
+ break;
+ default:
+ PROC_UNLOCK(p);
+ return (EINVAL);
+ }
+ break;
+
+ default:
+ error = kern_clock_gettime(td, nwhich, &tp);
+ break;
+ }
+ if (error != 0) {
+ LIN_SDT_PROBE1(time, linux_clock_gettime, gettime_error, error);
+ LIN_SDT_PROBE1(time, linux_clock_gettime, return, error);
+ return (error);
+ }
+ error = native_to_linux_timespec(&lts, &tp);
+ if (error != 0)
+ return (error);
+ error = copyout(&lts, args->tp, sizeof lts);
+ if (error != 0)
+ LIN_SDT_PROBE1(time, linux_clock_gettime, copyout_error, error);
+
+ LIN_SDT_PROBE1(time, linux_clock_gettime, return, error);
+ return (error);
+}
+
+int
+linux_clock_settime(struct thread *td, struct linux_clock_settime_args *args)
+{
+ struct timespec ts;
+ struct l_timespec lts;
+ int error;
+ clockid_t nwhich;
+
+ LIN_SDT_PROBE2(time, linux_clock_settime, entry, args->which, args->tp);
+
+ error = linux_to_native_clockid(&nwhich, args->which);
+ if (error != 0) {
+ linux_msg(curthread,
+ "unsupported clock_settime clockid %d", args->which);
+ LIN_SDT_PROBE1(time, linux_clock_settime, conversion_error,
+ error);
+ LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
+ return (error);
+ }
+ error = copyin(args->tp, &lts, sizeof lts);
+ if (error != 0) {
+ LIN_SDT_PROBE1(time, linux_clock_settime, copyin_error, error);
+ LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
+ return (error);
+ }
+ error = linux_to_native_timespec(&ts, &lts);
+ if (error != 0) {
+ LIN_SDT_PROBE1(time, linux_clock_settime, conversion_error,
+ error);
+ LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
+ return (error);
+ }
+
+ error = kern_clock_settime(td, nwhich, &ts);
+ if (error != 0)
+ LIN_SDT_PROBE1(time, linux_clock_settime, settime_error, error);
+
+ LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
+ return (error);
+}
+
+int
+linux_clock_getres(struct thread *td, struct linux_clock_getres_args *args)
+{
+ struct proc *p;
+ struct timespec ts;
+ struct l_timespec lts;
+ int error, clockwhich;
+ clockid_t nwhich;
+ pid_t pid;
+ lwpid_t tid;
+
+ LIN_SDT_PROBE2(time, linux_clock_getres, entry, args->which, args->tp);
+
+ error = linux_to_native_clockid(&nwhich, args->which);
+ if (error != 0) {
+ linux_msg(curthread,
+ "unsupported clock_getres clockid %d", args->which);
+ LIN_SDT_PROBE1(time, linux_clock_getres, conversion_error,
+ error);
+ LIN_SDT_PROBE1(time, linux_clock_getres, return, error);
+ return (error);
+ }
+
+ /*
+ * Check user supplied clock id in case of per-process
+ * or thread-specific cpu-time clock.
+ */
+ if (args->which < 0) {
+ switch (nwhich) {
+ case CLOCK_THREAD_CPUTIME_ID:
+ tid = LINUX_CPUCLOCK_ID(args->which);
+ if (tid != 0) {
+ p = td->td_proc;
+ if (linux_tdfind(td, tid, p->p_pid) == NULL)
+ return (EINVAL);
+ PROC_UNLOCK(p);
+ }
+ break;
+ case CLOCK_PROCESS_CPUTIME_ID:
+ pid = LINUX_CPUCLOCK_ID(args->which);
+ if (pid != 0) {
+ error = pget(pid, PGET_CANSEE, &p);
+ if (error != 0)
+ return (EINVAL);
+ PROC_UNLOCK(p);
+ }
+ break;
+ }
+ }
+
+ if (args->tp == NULL) {
+ LIN_SDT_PROBE0(time, linux_clock_getres, nullcall);
+ LIN_SDT_PROBE1(time, linux_clock_getres, return, 0);
+ return (0);
+ }
+
+ switch (nwhich) {
+ case CLOCK_THREAD_CPUTIME_ID:
+ case CLOCK_PROCESS_CPUTIME_ID:
+ clockwhich = LINUX_CPUCLOCK_WHICH(args->which);
+ /*
+ * In both cases (when the clock id obtained by a call to
+ * clock_getcpuclockid() or using the clock
+ * ID CLOCK_PROCESS_CPUTIME_ID Linux hardcodes precision
+ * of clock. The same for the CLOCK_THREAD_CPUTIME_ID clock.
+ *
+ * See Linux posix_cpu_clock_getres() implementation.
+ */
+ if (args->which > 0 || clockwhich == LINUX_CPUCLOCK_SCHED) {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1;
+ goto out;
+ }
+
+ switch (clockwhich) {
+ case LINUX_CPUCLOCK_PROF:
+ nwhich = CLOCK_PROF;
+ break;
+ case LINUX_CPUCLOCK_VIRT:
+ nwhich = CLOCK_VIRTUAL;
+ break;
+ default:
+ return (EINVAL);
+ }
+ break;
+
+ default:
+ break;
+ }
+ error = kern_clock_getres(td, nwhich, &ts);
+ if (error != 0) {
+ LIN_SDT_PROBE1(time, linux_clock_getres, getres_error, error);
+ LIN_SDT_PROBE1(time, linux_clock_getres, return, error);
+ return (error);
+ }
+
+out:
+ error = native_to_linux_timespec(&lts, &ts);
+ if (error != 0)
+ return (error);
+ error = copyout(&lts, args->tp, sizeof lts);
+ if (error != 0)
+ LIN_SDT_PROBE1(time, linux_clock_getres, copyout_error, error);
+
+ LIN_SDT_PROBE1(time, linux_clock_getres, return, error);
+ return (error);
+}
+
+int
+linux_nanosleep(struct thread *td, struct linux_nanosleep_args *args)
+{
+ struct timespec *rmtp;
+ struct l_timespec lrqts, lrmts;
+ struct timespec rqts, rmts;
+ int error, error2;
+
+ LIN_SDT_PROBE2(time, linux_nanosleep, entry, args->rqtp, args->rmtp);
+
+ error = copyin(args->rqtp, &lrqts, sizeof lrqts);
+ if (error != 0) {
+ LIN_SDT_PROBE1(time, linux_nanosleep, copyin_error, error);
+ LIN_SDT_PROBE1(time, linux_nanosleep, return, error);
+ return (error);
+ }
+
+ if (args->rmtp != NULL)
+ rmtp = &rmts;
+ else
+ rmtp = NULL;
+
+ error = linux_to_native_timespec(&rqts, &lrqts);
+ if (error != 0) {
+ LIN_SDT_PROBE1(time, linux_nanosleep, conversion_error, error);
+ LIN_SDT_PROBE1(time, linux_nanosleep, return, error);
+ return (error);
+ }
+ error = kern_nanosleep(td, &rqts, rmtp);
+ if (error == EINTR && args->rmtp != NULL) {
+ error2 = native_to_linux_timespec(&lrmts, rmtp);
+ if (error2 != 0)
+ return (error2);
+ error2 = copyout(&lrmts, args->rmtp, sizeof(lrmts));
+ if (error2 != 0) {
+ LIN_SDT_PROBE1(time, linux_nanosleep, copyout_error,
+ error2);
+ LIN_SDT_PROBE1(time, linux_nanosleep, return, error2);
+ return (error2);
+ }
+ }
+
+ LIN_SDT_PROBE1(time, linux_nanosleep, return, error);
+ return (error);
+}
+
+int
+linux_clock_nanosleep(struct thread *td, struct linux_clock_nanosleep_args *args)
+{
+ struct timespec *rmtp;
+ struct l_timespec lrqts, lrmts;
+ struct timespec rqts, rmts;
+ int error, error2, flags;
+ clockid_t clockid;
+
+ LIN_SDT_PROBE4(time, linux_clock_nanosleep, entry, args->which,
+ args->flags, args->rqtp, args->rmtp);
+
+ error = linux_to_native_timerflags(&flags, args->flags);
+ if (error != 0) {
+ LIN_SDT_PROBE1(time, linux_clock_nanosleep, unsupported_flags,
+ args->flags);
+ LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error);
+ return (error);
+ }
+
+ error = linux_to_native_clockid(&clockid, args->which);
+ if (error != 0) {
+ linux_msg(curthread,
+ "unsupported clock_nanosleep clockid %d", args->which);
+ LIN_SDT_PROBE1(time, linux_clock_nanosleep, unsupported_clockid,
+ args->which);
+ LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
+ return (error);
+ }
+
+ error = copyin(args->rqtp, &lrqts, sizeof(lrqts));
+ if (error != 0) {
+ LIN_SDT_PROBE1(time, linux_clock_nanosleep, copyin_error,
+ error);
+ LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error);
+ return (error);
+ }
+
+ if (args->rmtp != NULL)
+ rmtp = &rmts;
+ else
+ rmtp = NULL;
+
+ error = linux_to_native_timespec(&rqts, &lrqts);
+ if (error != 0) {
+ LIN_SDT_PROBE1(time, linux_clock_nanosleep, conversion_error,
+ error);
+ LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error);
+ return (error);
+ }
+ error = kern_clock_nanosleep(td, clockid, flags, &rqts, rmtp);
+ if (error == EINTR && (flags & TIMER_ABSTIME) == 0 &&
+ args->rmtp != NULL) {
+ error2 = native_to_linux_timespec(&lrmts, rmtp);
+ if (error2 != 0)
+ return (error2);
+ error2 = copyout(&lrmts, args->rmtp, sizeof(lrmts));
+ if (error2 != 0) {
+ LIN_SDT_PROBE1(time, linux_clock_nanosleep,
+ copyout_error, error2);
+ LIN_SDT_PROBE1(time, linux_clock_nanosleep,
+ return, error2);
+ return (error2);
+ }
+ }
+
+ LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error);
+ return (error);
+}
diff --git a/sys/compat/linux/linux_timer.c b/sys/compat/linux/linux_timer.c
new file mode 100644
index 000000000000..4e1b56d4b2e2
--- /dev/null
+++ b/sys/compat/linux/linux_timer.c
@@ -0,0 +1,168 @@
+/*-
+ * Copyright (c) 2014 Bjoern A. Zeeb
+ * All rights reserved.
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249
+ * ("MRC2"), as part of the DARPA MRC research programme.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_compat.h"
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/signal.h>
+#include <sys/syscallsubr.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#ifdef COMPAT_LINUX32
+#include <machine/../linux32/linux.h>
+#include <machine/../linux32/linux32_proto.h>
+#else
+#include <machine/../linux/linux.h>
+#include <machine/../linux/linux_proto.h>
+#endif
+#include <compat/linux/linux_timer.h>
+
+static int
+linux_convert_l_sigevent(struct l_sigevent *l_sig, struct sigevent *sig)
+{
+
+ CP(*l_sig, *sig, sigev_notify);
+ switch (l_sig->sigev_notify) {
+ case L_SIGEV_SIGNAL:
+ if (!LINUX_SIG_VALID(l_sig->sigev_signo))
+ return (EINVAL);
+ sig->sigev_notify = SIGEV_SIGNAL;
+ sig->sigev_signo = linux_to_bsd_signal(l_sig->sigev_signo);
+ PTRIN_CP(*l_sig, *sig, sigev_value.sival_ptr);
+ break;
+ case L_SIGEV_NONE:
+ sig->sigev_notify = SIGEV_NONE;
+ break;
+ case L_SIGEV_THREAD:
+#if 0
+ /* Seems to not be used anywhere (anymore)? */
+ sig->sigev_notify = SIGEV_THREAD;
+ return (ENOSYS);
+#else
+ return (EINVAL);
+#endif
+ case L_SIGEV_THREAD_ID:
+ if (!LINUX_SIG_VALID(l_sig->sigev_signo))
+ return (EINVAL);
+ sig->sigev_notify = SIGEV_THREAD_ID;
+ CP2(*l_sig, *sig, _l_sigev_un._tid, sigev_notify_thread_id);
+ sig->sigev_signo = linux_to_bsd_signal(l_sig->sigev_signo);
+ PTRIN_CP(*l_sig, *sig, sigev_value.sival_ptr);
+ break;
+ default:
+ return (EINVAL);
+ }
+ return (0);
+}
+
+int
+linux_timer_create(struct thread *td, struct linux_timer_create_args *uap)
+{
+ struct l_sigevent l_ev;
+ struct sigevent ev, *evp;
+ clockid_t nwhich;
+ int error, id;
+
+ if (uap->evp == NULL) {
+ evp = NULL;
+ } else {
+ error = copyin(uap->evp, &l_ev, sizeof(l_ev));
+ if (error != 0)
+ return (error);
+ error = linux_convert_l_sigevent(&l_ev, &ev);
+ if (error != 0)
+ return (error);
+ evp = &ev;
+ }
+ error = linux_to_native_clockid(&nwhich, uap->clock_id);
+ if (error != 0)
+ return (error);
+ error = kern_ktimer_create(td, nwhich, evp, &id, -1);
+ if (error == 0) {
+ error = copyout(&id, uap->timerid, sizeof(int));
+ if (error != 0)
+ kern_ktimer_delete(td, id);
+ }
+ return (error);
+}
+
+int
+linux_timer_settime(struct thread *td, struct linux_timer_settime_args *uap)
+{
+ struct l_itimerspec l_val, l_oval;
+ struct itimerspec val, oval, *ovalp;
+ int error;
+
+ error = copyin(uap->new, &l_val, sizeof(l_val));
+ if (error != 0)
+ return (error);
+ ITS_CP(l_val, val);
+ ovalp = uap->old != NULL ? &oval : NULL;
+ error = kern_ktimer_settime(td, uap->timerid, uap->flags, &val, ovalp);
+ if (error == 0 && uap->old != NULL) {
+ ITS_CP(oval, l_oval);
+ error = copyout(&l_oval, uap->old, sizeof(l_oval));
+ }
+ return (error);
+}
+
+int
+linux_timer_gettime(struct thread *td, struct linux_timer_gettime_args *uap)
+{
+ struct l_itimerspec l_val;
+ struct itimerspec val;
+ int error;
+
+ error = kern_ktimer_gettime(td, uap->timerid, &val);
+ if (error == 0) {
+ ITS_CP(val, l_val);
+ error = copyout(&l_val, uap->setting, sizeof(l_val));
+ }
+ return (error);
+}
+
+int
+linux_timer_getoverrun(struct thread *td, struct linux_timer_getoverrun_args *uap)
+{
+
+ return (kern_ktimer_getoverrun(td, uap->timerid));
+}
+
+int
+linux_timer_delete(struct thread *td, struct linux_timer_delete_args *uap)
+{
+
+ return (kern_ktimer_delete(td, uap->timerid));
+}
diff --git a/sys/compat/linux/linux_timer.h b/sys/compat/linux/linux_timer.h
new file mode 100644
index 000000000000..5344191742bb
--- /dev/null
+++ b/sys/compat/linux/linux_timer.h
@@ -0,0 +1,118 @@
+/*-
+ * Copyright (c) 2014 Bjoern A. Zeeb
+ * All rights reserved.
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249
+ * ("MRC2"), as part of the DARPA MRC research programme.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_TIMER_H
+#define _LINUX_TIMER_H
+
+#include <sys/abi_compat.h>
+
+#ifndef __LINUX_ARCH_SIGEV_PREAMBLE_SIZE
+#define __LINUX_ARCH_SIGEV_PREAMBLE_SIZE \
+ (sizeof(l_int) * 2 + sizeof(l_sigval_t))
+#endif
+
+#define LINUX_SIGEV_MAX_SIZE 64
+#define LINUX_SIGEV_PAD_SIZE \
+ ((LINUX_SIGEV_MAX_SIZE - __LINUX_ARCH_SIGEV_PREAMBLE_SIZE) / \
+ sizeof(l_int))
+
+#define LINUX_CLOCK_REALTIME 0
+#define LINUX_CLOCK_MONOTONIC 1
+#define LINUX_CLOCK_PROCESS_CPUTIME_ID 2
+#define LINUX_CLOCK_THREAD_CPUTIME_ID 3
+#define LINUX_CLOCK_MONOTONIC_RAW 4
+#define LINUX_CLOCK_REALTIME_COARSE 5
+#define LINUX_CLOCK_MONOTONIC_COARSE 6
+#define LINUX_CLOCK_BOOTTIME 7
+#define LINUX_CLOCK_REALTIME_ALARM 8
+#define LINUX_CLOCK_BOOTTIME_ALARM 9
+#define LINUX_CLOCK_SGI_CYCLE 10
+#define LINUX_CLOCK_TAI 11
+
+#define LINUX_CPUCLOCK_PERTHREAD_MASK 4
+#define LINUX_CPUCLOCK_MASK 3
+#define LINUX_CPUCLOCK_WHICH(clock) \
+ ((clock) & (clockid_t) LINUX_CPUCLOCK_MASK)
+#define LINUX_CPUCLOCK_PROF 0
+#define LINUX_CPUCLOCK_VIRT 1
+#define LINUX_CPUCLOCK_SCHED 2
+#define LINUX_CPUCLOCK_MAX 3
+#define LINUX_CLOCKFD LINUX_CPUCLOCK_MAX
+#define LINUX_CLOCKFD_MASK \
+ (LINUX_CPUCLOCK_PERTHREAD_MASK|LINUX_CPUCLOCK_MASK)
+
+#define LINUX_CPUCLOCK_ID(clock) ((pid_t) ~((clock) >> 3))
+#define LINUX_CPUCLOCK_PERTHREAD(clock) \
+ (((clock) & (clockid_t) LINUX_CPUCLOCK_PERTHREAD_MASK) != 0)
+
+#define LINUX_TIMER_ABSTIME 0x01
+
+#define L_SIGEV_SIGNAL 0
+#define L_SIGEV_NONE 1
+#define L_SIGEV_THREAD 2
+#define L_SIGEV_THREAD_ID 4
+
+struct l_sigevent {
+ l_sigval_t sigev_value;
+ l_int sigev_signo;
+ l_int sigev_notify;
+ union {
+ l_int _pad[LINUX_SIGEV_PAD_SIZE];
+ l_int _tid;
+ struct {
+ l_uintptr_t _function;
+ l_uintptr_t _attribute;
+ } _l_sigev_thread;
+ } _l_sigev_un;
+}
+#if defined(__amd64__) && defined(COMPAT_LINUX32)
+__packed
+#endif
+;
+
+struct l_itimerspec {
+ struct l_timespec it_interval;
+ struct l_timespec it_value;
+};
+
+int native_to_linux_timespec(struct l_timespec *,
+ struct timespec *);
+int linux_to_native_timespec(struct timespec *,
+ struct l_timespec *);
+int linux_to_native_clockid(clockid_t *, clockid_t);
+int native_to_linux_itimerspec(struct l_itimerspec *,
+ struct itimerspec *);
+int linux_to_native_itimerspec(struct itimerspec *,
+ struct l_itimerspec *);
+int linux_to_native_timerflags(int *, int);
+
+#endif /* _LINUX_TIMER_H */
diff --git a/sys/compat/linux/linux_uid16.c b/sys/compat/linux/linux_uid16.c
new file mode 100644
index 000000000000..0d1e782b7efa
--- /dev/null
+++ b/sys/compat/linux/linux_uid16.c
@@ -0,0 +1,439 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2001 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_compat.h"
+
+#include <sys/fcntl.h>
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/priv.h>
+#include <sys/proc.h>
+#include <sys/sdt.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysproto.h>
+#include <sys/systm.h>
+
+#ifdef COMPAT_LINUX32
+#include <machine/../linux32/linux.h>
+#include <machine/../linux32/linux32_proto.h>
+#else
+#include <machine/../linux/linux.h>
+#include <machine/../linux/linux_proto.h>
+#endif
+
+#include <compat/linux/linux_dtrace.h>
+#include <compat/linux/linux_util.h>
+
+/* DTrace init */
+LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
+
+/**
+ * DTrace probes in this module.
+ */
+LIN_SDT_PROBE_DEFINE3(uid16, linux_chown16, entry, "char *", "l_uid16_t",
+ "l_gid16_t");
+LIN_SDT_PROBE_DEFINE1(uid16, linux_chown16, conv_path, "char *");
+LIN_SDT_PROBE_DEFINE1(uid16, linux_chown16, return, "int");
+LIN_SDT_PROBE_DEFINE3(uid16, linux_lchown16, entry, "char *", "l_uid16_t",
+ "l_gid16_t");
+LIN_SDT_PROBE_DEFINE1(uid16, linux_lchown16, conv_path, "char *");
+LIN_SDT_PROBE_DEFINE1(uid16, linux_lchown16, return, "int");
+LIN_SDT_PROBE_DEFINE2(uid16, linux_setgroups16, entry, "l_uint", "l_gid16_t *");
+LIN_SDT_PROBE_DEFINE1(uid16, linux_setgroups16, copyin_error, "int");
+LIN_SDT_PROBE_DEFINE1(uid16, linux_setgroups16, priv_check_cred_error, "int");
+LIN_SDT_PROBE_DEFINE1(uid16, linux_setgroups16, return, "int");
+LIN_SDT_PROBE_DEFINE2(uid16, linux_getgroups16, entry, "l_uint", "l_gid16_t *");
+LIN_SDT_PROBE_DEFINE1(uid16, linux_getgroups16, copyout_error, "int");
+LIN_SDT_PROBE_DEFINE1(uid16, linux_getgroups16, return, "int");
+LIN_SDT_PROBE_DEFINE0(uid16, linux_getgid16, entry);
+LIN_SDT_PROBE_DEFINE1(uid16, linux_getgid16, return, "int");
+LIN_SDT_PROBE_DEFINE0(uid16, linux_getuid16, entry);
+LIN_SDT_PROBE_DEFINE1(uid16, linux_getuid16, return, "int");
+LIN_SDT_PROBE_DEFINE0(uid16, linux_getegid16, entry);
+LIN_SDT_PROBE_DEFINE1(uid16, linux_getegid16, return, "int");
+LIN_SDT_PROBE_DEFINE0(uid16, linux_geteuid16, entry);
+LIN_SDT_PROBE_DEFINE1(uid16, linux_geteuid16, return, "int");
+LIN_SDT_PROBE_DEFINE1(uid16, linux_setgid16, entry, "l_gid16_t");
+LIN_SDT_PROBE_DEFINE1(uid16, linux_setgid16, return, "int");
+LIN_SDT_PROBE_DEFINE1(uid16, linux_setuid16, entry, "l_uid16_t");
+LIN_SDT_PROBE_DEFINE1(uid16, linux_setuid16, return, "int");
+LIN_SDT_PROBE_DEFINE2(uid16, linux_setregid16, entry, "l_gid16_t", "l_gid16_t");
+LIN_SDT_PROBE_DEFINE1(uid16, linux_setregid16, return, "int");
+LIN_SDT_PROBE_DEFINE2(uid16, linux_setreuid16, entry, "l_uid16_t", "l_uid16_t");
+LIN_SDT_PROBE_DEFINE1(uid16, linux_setreuid16, return, "int");
+LIN_SDT_PROBE_DEFINE3(uid16, linux_setresgid16, entry, "l_gid16_t", "l_gid16_t",
+ "l_gid16_t");
+LIN_SDT_PROBE_DEFINE1(uid16, linux_setresgid16, return, "int");
+LIN_SDT_PROBE_DEFINE3(uid16, linux_setresuid16, entry, "l_uid16_t", "l_uid16_t",
+ "l_uid16_t");
+LIN_SDT_PROBE_DEFINE1(uid16, linux_setresuid16, return, "int");
+
+DUMMY(setfsuid16);
+DUMMY(setfsgid16);
+DUMMY(getresuid16);
+DUMMY(getresgid16);
+
+#define CAST_NOCHG(x) ((x == 0xFFFF) ? -1 : x)
+
+int
+linux_chown16(struct thread *td, struct linux_chown16_args *args)
+{
+ char *path;
+ int error;
+
+ if (!LUSECONVPATH(td) && !SDT_PROBES_ENABLED()) {
+ error = kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE,
+ CAST_NOCHG(args->uid), CAST_NOCHG(args->gid), 0);
+ } else {
+ LCONVPATHEXIST(td, args->path, &path);
+ /*
+ * The DTrace probes have to be after the LCONVPATHEXIST, as
+ * LCONVPATHEXIST may return on its own and we do not want to
+ * have a stray entry without the corresponding return.
+ */
+ LIN_SDT_PROBE3(uid16, linux_chown16, entry, args->path, args->uid,
+ args->gid);
+ LIN_SDT_PROBE1(uid16, linux_chown16, conv_path, path);
+
+ error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE,
+ CAST_NOCHG(args->uid), CAST_NOCHG(args->gid), 0);
+ LFREEPATH(path);
+ LIN_SDT_PROBE1(uid16, linux_chown16, return, error);
+ }
+ return (error);
+}
+
+int
+linux_lchown16(struct thread *td, struct linux_lchown16_args *args)
+{
+ char *path;
+ int error;
+
+ if (!LUSECONVPATH(td) && !SDT_PROBES_ENABLED()) {
+ error = kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE,
+ CAST_NOCHG(args->uid), CAST_NOCHG(args->gid), AT_SYMLINK_NOFOLLOW);
+ } else {
+ LCONVPATHEXIST(td, args->path, &path);
+
+ /*
+ * The DTrace probes have to be after the LCONVPATHEXIST, as
+ * LCONVPATHEXIST may return on its own and we do not want to
+ * have a stray entry without the corresponding return.
+ */
+ LIN_SDT_PROBE3(uid16, linux_lchown16, entry, args->path, args->uid,
+ args->gid);
+ LIN_SDT_PROBE1(uid16, linux_lchown16, conv_path, path);
+
+ error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE,
+ CAST_NOCHG(args->uid), CAST_NOCHG(args->gid), AT_SYMLINK_NOFOLLOW);
+ LFREEPATH(path);
+ LIN_SDT_PROBE1(uid16, linux_lchown16, return, error);
+ }
+ return (error);
+}
+
+int
+linux_setgroups16(struct thread *td, struct linux_setgroups16_args *args)
+{
+ struct ucred *newcred, *oldcred;
+ l_gid16_t *linux_gidset;
+ gid_t *bsd_gidset;
+ int ngrp, error;
+ struct proc *p;
+
+ LIN_SDT_PROBE2(uid16, linux_setgroups16, entry, args->gidsetsize,
+ args->gidset);
+
+ ngrp = args->gidsetsize;
+ if (ngrp < 0 || ngrp >= ngroups_max + 1) {
+ LIN_SDT_PROBE1(uid16, linux_setgroups16, return, EINVAL);
+ return (EINVAL);
+ }
+ linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_LINUX, M_WAITOK);
+ error = copyin(args->gidset, linux_gidset, ngrp * sizeof(l_gid16_t));
+ if (error) {
+ LIN_SDT_PROBE1(uid16, linux_setgroups16, copyin_error, error);
+ LIN_SDT_PROBE1(uid16, linux_setgroups16, return, error);
+ free(linux_gidset, M_LINUX);
+ return (error);
+ }
+ newcred = crget();
+ p = td->td_proc;
+ PROC_LOCK(p);
+ oldcred = crcopysafe(p, newcred);
+
+ /*
+ * cr_groups[0] holds egid. Setting the whole set from
+ * the supplied set will cause egid to be changed too.
+ * Keep cr_groups[0] unchanged to prevent that.
+ */
+
+ if ((error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS)) != 0) {
+ PROC_UNLOCK(p);
+ crfree(newcred);
+
+ LIN_SDT_PROBE1(uid16, linux_setgroups16, priv_check_cred_error,
+ error);
+ goto out;
+ }
+
+ if (ngrp > 0) {
+ newcred->cr_ngroups = ngrp + 1;
+
+ bsd_gidset = newcred->cr_groups;
+ ngrp--;
+ while (ngrp >= 0) {
+ bsd_gidset[ngrp + 1] = linux_gidset[ngrp];
+ ngrp--;
+ }
+ }
+ else
+ newcred->cr_ngroups = 1;
+
+ setsugid(td->td_proc);
+ proc_set_cred(p, newcred);
+ PROC_UNLOCK(p);
+ crfree(oldcred);
+ error = 0;
+out:
+ free(linux_gidset, M_LINUX);
+
+ LIN_SDT_PROBE1(uid16, linux_setgroups16, return, error);
+ return (error);
+}
+
+int
+linux_getgroups16(struct thread *td, struct linux_getgroups16_args *args)
+{
+ struct ucred *cred;
+ l_gid16_t *linux_gidset;
+ gid_t *bsd_gidset;
+ int bsd_gidsetsz, ngrp, error;
+
+ LIN_SDT_PROBE2(uid16, linux_getgroups16, entry, args->gidsetsize,
+ args->gidset);
+
+ cred = td->td_ucred;
+ bsd_gidset = cred->cr_groups;
+ bsd_gidsetsz = cred->cr_ngroups - 1;
+
+ /*
+ * cr_groups[0] holds egid. Returning the whole set
+ * here will cause a duplicate. Exclude cr_groups[0]
+ * to prevent that.
+ */
+
+ if ((ngrp = args->gidsetsize) == 0) {
+ td->td_retval[0] = bsd_gidsetsz;
+
+ LIN_SDT_PROBE1(uid16, linux_getgroups16, return, 0);
+ return (0);
+ }
+
+ if (ngrp < bsd_gidsetsz) {
+ LIN_SDT_PROBE1(uid16, linux_getgroups16, return, EINVAL);
+ return (EINVAL);
+ }
+
+ ngrp = 0;
+ linux_gidset = malloc(bsd_gidsetsz * sizeof(*linux_gidset),
+ M_LINUX, M_WAITOK);
+ while (ngrp < bsd_gidsetsz) {
+ linux_gidset[ngrp] = bsd_gidset[ngrp + 1];
+ ngrp++;
+ }
+
+ error = copyout(linux_gidset, args->gidset, ngrp * sizeof(l_gid16_t));
+ free(linux_gidset, M_LINUX);
+ if (error) {
+ LIN_SDT_PROBE1(uid16, linux_getgroups16, copyout_error, error);
+ LIN_SDT_PROBE1(uid16, linux_getgroups16, return, error);
+ return (error);
+ }
+
+ td->td_retval[0] = ngrp;
+
+ LIN_SDT_PROBE1(uid16, linux_getgroups16, return, 0);
+ return (0);
+}
+
+int
+linux_getgid16(struct thread *td, struct linux_getgid16_args *args)
+{
+
+ LIN_SDT_PROBE0(uid16, linux_getgid16, entry);
+
+ td->td_retval[0] = td->td_ucred->cr_rgid;
+
+ LIN_SDT_PROBE1(uid16, linux_getgid16, return, 0);
+ return (0);
+}
+
+int
+linux_getuid16(struct thread *td, struct linux_getuid16_args *args)
+{
+
+ LIN_SDT_PROBE0(uid16, linux_getuid16, entry);
+
+ td->td_retval[0] = td->td_ucred->cr_ruid;
+
+ LIN_SDT_PROBE1(uid16, linux_getuid16, return, 0);
+ return (0);
+}
+
+int
+linux_getegid16(struct thread *td, struct linux_getegid16_args *args)
+{
+ struct getegid_args bsd;
+ int error;
+
+ LIN_SDT_PROBE0(uid16, linux_getegid16, entry);
+
+ error = sys_getegid(td, &bsd);
+
+ LIN_SDT_PROBE1(uid16, linux_getegid16, return, error);
+ return (error);
+}
+
+int
+linux_geteuid16(struct thread *td, struct linux_geteuid16_args *args)
+{
+ struct geteuid_args bsd;
+ int error;
+
+ LIN_SDT_PROBE0(uid16, linux_geteuid16, entry);
+
+ error = sys_geteuid(td, &bsd);
+
+ LIN_SDT_PROBE1(uid16, linux_geteuid16, return, error);
+ return (error);
+}
+
+int
+linux_setgid16(struct thread *td, struct linux_setgid16_args *args)
+{
+ struct setgid_args bsd;
+ int error;
+
+ LIN_SDT_PROBE1(uid16, linux_setgid16, entry, args->gid);
+
+ bsd.gid = args->gid;
+ error = sys_setgid(td, &bsd);
+
+ LIN_SDT_PROBE1(uid16, linux_setgid16, return, error);
+ return (error);
+}
+
+int
+linux_setuid16(struct thread *td, struct linux_setuid16_args *args)
+{
+ struct setuid_args bsd;
+ int error;
+
+ LIN_SDT_PROBE1(uid16, linux_setuid16, entry, args->uid);
+
+ bsd.uid = args->uid;
+ error = sys_setuid(td, &bsd);
+
+ LIN_SDT_PROBE1(uid16, linux_setuid16, return, error);
+ return (error);
+}
+
+int
+linux_setregid16(struct thread *td, struct linux_setregid16_args *args)
+{
+ struct setregid_args bsd;
+ int error;
+
+ LIN_SDT_PROBE2(uid16, linux_setregid16, entry, args->rgid, args->egid);
+
+ bsd.rgid = CAST_NOCHG(args->rgid);
+ bsd.egid = CAST_NOCHG(args->egid);
+ error = sys_setregid(td, &bsd);
+
+ LIN_SDT_PROBE1(uid16, linux_setregid16, return, error);
+ return (error);
+}
+
+int
+linux_setreuid16(struct thread *td, struct linux_setreuid16_args *args)
+{
+ struct setreuid_args bsd;
+ int error;
+
+ LIN_SDT_PROBE2(uid16, linux_setreuid16, entry, args->ruid, args->euid);
+
+ bsd.ruid = CAST_NOCHG(args->ruid);
+ bsd.euid = CAST_NOCHG(args->euid);
+ error = sys_setreuid(td, &bsd);
+
+ LIN_SDT_PROBE1(uid16, linux_setreuid16, return, error);
+ return (error);
+}
+
+int
+linux_setresgid16(struct thread *td, struct linux_setresgid16_args *args)
+{
+ struct setresgid_args bsd;
+ int error;
+
+ LIN_SDT_PROBE3(uid16, linux_setresgid16, entry, args->rgid, args->egid,
+ args->sgid);
+
+ bsd.rgid = CAST_NOCHG(args->rgid);
+ bsd.egid = CAST_NOCHG(args->egid);
+ bsd.sgid = CAST_NOCHG(args->sgid);
+ error = sys_setresgid(td, &bsd);
+
+ LIN_SDT_PROBE1(uid16, linux_setresgid16, return, error);
+ return (error);
+}
+
+int
+linux_setresuid16(struct thread *td, struct linux_setresuid16_args *args)
+{
+ struct setresuid_args bsd;
+ int error;
+
+ LIN_SDT_PROBE3(uid16, linux_setresuid16, entry, args->ruid, args->euid,
+ args->suid);
+
+ bsd.ruid = CAST_NOCHG(args->ruid);
+ bsd.euid = CAST_NOCHG(args->euid);
+ bsd.suid = CAST_NOCHG(args->suid);
+ error = sys_setresuid(td, &bsd);
+
+ LIN_SDT_PROBE1(uid16, linux_setresuid16, return, error);
+ return (error);
+}
diff --git a/sys/compat/linux/linux_util.c b/sys/compat/linux/linux_util.c
new file mode 100644
index 000000000000..8e5462636705
--- /dev/null
+++ b/sys/compat/linux/linux_util.c
@@ -0,0 +1,321 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1994 Christos Zoulas
+ * Copyright (c) 1995 Frank van der Linden
+ * Copyright (c) 1995 Scott Bartram
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * from: svr4_util.c,v 1.5 1995/01/22 23:44:50 christos Exp
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/fcntl.h>
+#include <sys/jail.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/linker_set.h>
+#include <sys/mutex.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/sdt.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+
+#include <machine/stdarg.h>
+
+#include <compat/linux/linux_dtrace.h>
+#include <compat/linux/linux_mib.h>
+#include <compat/linux/linux_util.h>
+
+MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
+MALLOC_DEFINE(M_EPOLL, "lepoll", "Linux events structures");
+MALLOC_DEFINE(M_FUTEX, "futex", "Linux futexes");
+MALLOC_DEFINE(M_FUTEX_WP, "futex wp", "Linux futex waiting proc");
+
+FEATURE(linuxulator_v4l, "V4L ioctl wrapper support in the linuxulator");
+FEATURE(linuxulator_v4l2, "V4L2 ioctl wrapper support in the linuxulator");
+
+/**
+ * Special DTrace provider for the linuxulator.
+ *
+ * In this file we define the provider for the entire linuxulator. All
+ * modules (= files of the linuxulator) use it.
+ *
+ * We define a different name depending on the emulated bitsize, see
+ * ../../<ARCH>/linux{,32}/linux.h, e.g.:
+ * native bitsize = linuxulator
+ * amd64, 32bit emulation = linuxulator32
+ */
+LIN_SDT_PROVIDER_DEFINE(linuxulator);
+LIN_SDT_PROVIDER_DEFINE(linuxulator32);
+
+char linux_emul_path[MAXPATHLEN] = "/compat/linux";
+
+SYSCTL_STRING(_compat_linux, OID_AUTO, emul_path, CTLFLAG_RWTUN,
+ linux_emul_path, sizeof(linux_emul_path),
+ "Linux runtime environment path");
+
+/*
+ * Search an alternate path before passing pathname arguments on to
+ * system calls. Useful for keeping a separate 'emulation tree'.
+ *
+ * If cflag is set, we check if an attempt can be made to create the
+ * named file, i.e. we check if the directory it should be in exists.
+ */
+int
+linux_emul_convpath(struct thread *td, const char *path, enum uio_seg pathseg,
+ char **pbuf, int cflag, int dfd)
+{
+ int retval;
+
+ retval = kern_alternate_path(td, linux_emul_path, path, pathseg, pbuf,
+ cflag, dfd);
+
+ return (retval);
+}
+
+void
+linux_msg(const struct thread *td, const char *fmt, ...)
+{
+ va_list ap;
+ struct proc *p;
+
+ if (linux_debug == 0)
+ return;
+
+ p = td->td_proc;
+ printf("linux: jid %d pid %d (%s): ", p->p_ucred->cr_prison->pr_id,
+ (int)p->p_pid, p->p_comm);
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+ printf("\n");
+}
+
+struct device_element
+{
+ TAILQ_ENTRY(device_element) list;
+ struct linux_device_handler entry;
+};
+
+static TAILQ_HEAD(, device_element) devices =
+ TAILQ_HEAD_INITIALIZER(devices);
+
+static struct linux_device_handler null_handler =
+ { "mem", "mem", "null", "null", 1, 3, 1};
+
+DATA_SET(linux_device_handler_set, null_handler);
+
+char *
+linux_driver_get_name_dev(device_t dev)
+{
+ struct device_element *de;
+ const char *device_name = device_get_name(dev);
+
+ if (device_name == NULL)
+ return (NULL);
+ TAILQ_FOREACH(de, &devices, list) {
+ if (strcmp(device_name, de->entry.bsd_driver_name) == 0)
+ return (de->entry.linux_driver_name);
+ }
+
+ return (NULL);
+}
+
+int
+linux_driver_get_major_minor(const char *node, int *major, int *minor)
+{
+ struct device_element *de;
+ unsigned long devno;
+ size_t sz;
+
+ if (node == NULL || major == NULL || minor == NULL)
+ return (1);
+
+ sz = sizeof("pts/") - 1;
+ if (strncmp(node, "pts/", sz) == 0 && node[sz] != '\0') {
+ /*
+ * Linux checks major and minors of the slave device
+ * to make sure it's a pty device, so let's make him
+ * believe it is.
+ */
+ devno = strtoul(node + sz, NULL, 10);
+ *major = 136 + (devno / 256);
+ *minor = devno % 256;
+ return (0);
+ }
+
+ sz = sizeof("dri/card") - 1;
+ if (strncmp(node, "dri/card", sz) == 0 && node[sz] != '\0') {
+ devno = strtoul(node + sz, NULL, 10);
+ *major = 226 + (devno / 256);
+ *minor = devno % 256;
+ return (0);
+ }
+ sz = sizeof("dri/controlD") - 1;
+ if (strncmp(node, "dri/controlD", sz) == 0 && node[sz] != '\0') {
+ devno = strtoul(node + sz, NULL, 10);
+ *major = 226 + (devno / 256);
+ *minor = devno % 256;
+ return (0);
+ }
+ sz = sizeof("dri/renderD") - 1;
+ if (strncmp(node, "dri/renderD", sz) == 0 && node[sz] != '\0') {
+ devno = strtoul(node + sz, NULL, 10);
+ *major = 226 + (devno / 256);
+ *minor = devno % 256;
+ return (0);
+ }
+ sz = sizeof("drm/") - 1;
+ if (strncmp(node, "drm/", sz) == 0 && node[sz] != '\0') {
+ devno = strtoul(node + sz, NULL, 10);
+ *major = 226 + (devno / 256);
+ *minor = devno % 256;
+ return (0);
+ }
+
+ TAILQ_FOREACH(de, &devices, list) {
+ if (strcmp(node, de->entry.bsd_device_name) == 0) {
+ *major = de->entry.linux_major;
+ *minor = de->entry.linux_minor;
+ return (0);
+ }
+ }
+
+ return (1);
+}
+
+int
+linux_vn_get_major_minor(const struct vnode *vp, int *major, int *minor)
+{
+ int error;
+
+ if (vp->v_type != VCHR)
+ return (ENOTBLK);
+ dev_lock();
+ if (vp->v_rdev == NULL) {
+ dev_unlock();
+ return (ENXIO);
+ }
+ error = linux_driver_get_major_minor(devtoname(vp->v_rdev),
+ major, minor);
+ dev_unlock();
+ return (error);
+}
+
+char *
+linux_get_char_devices()
+{
+ struct device_element *de;
+ char *temp, *string, *last;
+ char formated[256];
+ int current_size = 0, string_size = 1024;
+
+ string = malloc(string_size, M_LINUX, M_WAITOK);
+ string[0] = '\000';
+ last = "";
+ TAILQ_FOREACH(de, &devices, list) {
+ if (!de->entry.linux_char_device)
+ continue;
+ temp = string;
+ if (strcmp(last, de->entry.bsd_driver_name) != 0) {
+ last = de->entry.bsd_driver_name;
+
+ snprintf(formated, sizeof(formated), "%3d %s\n",
+ de->entry.linux_major,
+ de->entry.linux_device_name);
+ if (strlen(formated) + current_size
+ >= string_size) {
+ string_size *= 2;
+ string = malloc(string_size,
+ M_LINUX, M_WAITOK);
+ bcopy(temp, string, current_size);
+ free(temp, M_LINUX);
+ }
+ strcat(string, formated);
+ current_size = strlen(string);
+ }
+ }
+
+ return (string);
+}
+
+void
+linux_free_get_char_devices(char *string)
+{
+
+ free(string, M_LINUX);
+}
+
+static int linux_major_starting = 200;
+
+int
+linux_device_register_handler(struct linux_device_handler *d)
+{
+ struct device_element *de;
+
+ if (d == NULL)
+ return (EINVAL);
+
+ de = malloc(sizeof(*de), M_LINUX, M_WAITOK);
+ if (d->linux_major < 0) {
+ d->linux_major = linux_major_starting++;
+ }
+ bcopy(d, &de->entry, sizeof(*d));
+
+ /* Add the element to the list, sorted on span. */
+ TAILQ_INSERT_TAIL(&devices, de, list);
+
+ return (0);
+}
+
+int
+linux_device_unregister_handler(struct linux_device_handler *d)
+{
+ struct device_element *de;
+
+ if (d == NULL)
+ return (EINVAL);
+
+ TAILQ_FOREACH(de, &devices, list) {
+ if (bcmp(d, &de->entry, sizeof(*d)) == 0) {
+ TAILQ_REMOVE(&devices, de, list);
+ free(de, M_LINUX);
+
+ return (0);
+ }
+ }
+
+ return (EINVAL);
+}
diff --git a/sys/compat/linux/linux_util.h b/sys/compat/linux/linux_util.h
new file mode 100644
index 000000000000..436d4313abc8
--- /dev/null
+++ b/sys/compat/linux/linux_util.h
@@ -0,0 +1,187 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1994 Christos Zoulas
+ * Copyright (c) 1995 Frank van der Linden
+ * Copyright (c) 1995 Scott Bartram
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * from: svr4_util.h,v 1.5 1994/11/18 02:54:31 christos Exp
+ * from: linux_util.h,v 1.2 1995/03/05 23:23:50 fvdl Exp
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_UTIL_H_
+#define _LINUX_UTIL_H_
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+#include <sys/exec.h>
+#include <sys/sysent.h>
+#include <sys/syslog.h>
+#include <sys/cdefs.h>
+#include <sys/uio.h>
+
+MALLOC_DECLARE(M_LINUX);
+MALLOC_DECLARE(M_EPOLL);
+MALLOC_DECLARE(M_FUTEX);
+MALLOC_DECLARE(M_FUTEX_WP);
+
+extern char linux_emul_path[];
+extern int linux_use_emul_path;
+
+int linux_emul_convpath(struct thread *, const char *, enum uio_seg, char **, int, int);
+
+#define LUSECONVPATH(td) atomic_load_int(&linux_use_emul_path)
+
+#define LCONVPATH_AT(td, upath, pathp, i, dfd) \
+ do { \
+ int _error; \
+ \
+ _error = linux_emul_convpath(td, upath, UIO_USERSPACE, \
+ pathp, i, dfd); \
+ if (*(pathp) == NULL) \
+ return (_error); \
+ } while (0)
+
+#define LCONVPATH(td, upath, pathp, i) \
+ LCONVPATH_AT(td, upath, pathp, i, AT_FDCWD)
+
+#define LCONVPATHEXIST(td, upath, pathp) LCONVPATH(td, upath, pathp, 0)
+#define LCONVPATHEXIST_AT(td, upath, pathp, dfd) LCONVPATH_AT(td, upath, pathp, 0, dfd)
+#define LCONVPATHCREAT(td, upath, pathp) LCONVPATH(td, upath, pathp, 1)
+#define LCONVPATHCREAT_AT(td, upath, pathp, dfd) LCONVPATH_AT(td, upath, pathp, 1, dfd)
+#define LFREEPATH(path) free(path, M_TEMP)
+
+#define DUMMY(s) \
+LIN_SDT_PROBE_DEFINE0(dummy, s, entry); \
+LIN_SDT_PROBE_DEFINE0(dummy, s, not_implemented); \
+LIN_SDT_PROBE_DEFINE1(dummy, s, return, "int"); \
+int \
+linux_ ## s(struct thread *td, struct linux_ ## s ## _args *args) \
+{ \
+ static pid_t pid; \
+ \
+ LIN_SDT_PROBE0(dummy, s, entry); \
+ \
+ if (pid != td->td_proc->p_pid) { \
+ linux_msg(td, "syscall %s not implemented", #s); \
+ LIN_SDT_PROBE0(dummy, s, not_implemented); \
+ pid = td->td_proc->p_pid; \
+ }; \
+ \
+ LIN_SDT_PROBE1(dummy, s, return, ENOSYS); \
+ return (ENOSYS); \
+} \
+struct __hack
+
+/*
+ * This is for the syscalls that are not even yet implemented in Linux.
+ *
+ * They're marked as UNIMPL in syscall.master so it will
+ * have nosys record in linux_sysent[].
+ */
+#define UNIMPLEMENTED(s)
+
+void linux_msg(const struct thread *td, const char *fmt, ...)
+ __printflike(2, 3);
+
+struct linux_device_handler {
+ char *bsd_driver_name;
+ char *linux_driver_name;
+ char *bsd_device_name;
+ char *linux_device_name;
+ int linux_major;
+ int linux_minor;
+ int linux_char_device;
+};
+
+int linux_device_register_handler(struct linux_device_handler *h);
+int linux_device_unregister_handler(struct linux_device_handler *h);
+char *linux_driver_get_name_dev(device_t dev);
+int linux_driver_get_major_minor(const char *node, int *major, int *minor);
+int linux_vn_get_major_minor(const struct vnode *vn, int *major, int *minor);
+char *linux_get_char_devices(void);
+void linux_free_get_char_devices(char *string);
+
+#if defined(KTR)
+
+#define KTR_LINUX KTR_SUBSYS
+#define LINUX_CTRFMT(nm, fmt) #nm"("fmt")"
+
+#define LINUX_CTR6(f, m, p1, p2, p3, p4, p5, p6) do { \
+ CTR6(KTR_LINUX, LINUX_CTRFMT(f, m), \
+ p1, p2, p3, p4, p5, p6); \
+} while (0)
+
+#define LINUX_CTR(f) LINUX_CTR6(f, "", 0, 0, 0, 0, 0, 0)
+#define LINUX_CTR0(f, m) LINUX_CTR6(f, m, 0, 0, 0, 0, 0, 0)
+#define LINUX_CTR1(f, m, p1) LINUX_CTR6(f, m, p1, 0, 0, 0, 0, 0)
+#define LINUX_CTR2(f, m, p1, p2) LINUX_CTR6(f, m, p1, p2, 0, 0, 0, 0)
+#define LINUX_CTR3(f, m, p1, p2, p3) LINUX_CTR6(f, m, p1, p2, p3, 0, 0, 0)
+#define LINUX_CTR4(f, m, p1, p2, p3, p4) LINUX_CTR6(f, m, p1, p2, p3, p4, 0, 0)
+#define LINUX_CTR5(f, m, p1, p2, p3, p4, p5) LINUX_CTR6(f, m, p1, p2, p3, p4, p5, 0)
+#else
+#define LINUX_CTR(f)
+#define LINUX_CTR0(f, m)
+#define LINUX_CTR1(f, m, p1)
+#define LINUX_CTR2(f, m, p1, p2)
+#define LINUX_CTR3(f, m, p1, p2, p3)
+#define LINUX_CTR4(f, m, p1, p2, p3, p4)
+#define LINUX_CTR5(f, m, p1, p2, p3, p4, p5)
+#define LINUX_CTR6(f, m, p1, p2, p3, p4, p5, p6)
+#endif
+
+/*
+ * Some macros for rate limiting messages:
+ * - noisy if compat.linux.debug = 1
+ * - print only once if compat.linux.debug > 1
+ */
+#define LINUX_RATELIMIT_MSG_NOTTESTED(_what) \
+ do { \
+ static int seen = 0; \
+ \
+ if (seen == 0 && linux_debug >= 2) { \
+ linux_msg(curthread, "%s is not tested, please report on emulation@FreeBSD.org how it works", _what); \
+ \
+ if (linux_debug < 3) \
+ seen = 1; \
+ } \
+ } while (0)
+
+#define LINUX_RATELIMIT_MSG_OPT1(_message, _opt1) \
+ do { \
+ static int seen = 0; \
+ \
+ if (seen == 0) { \
+ linux_msg(curthread, _message, _opt1); \
+ \
+ if (linux_debug < 3) \
+ seen = 1; \
+ } \
+ } while (0)
+
+#endif /* ! _LINUX_UTIL_H_ */
diff --git a/sys/compat/linux/linux_vdso.c b/sys/compat/linux/linux_vdso.c
new file mode 100644
index 000000000000..096f2e424850
--- /dev/null
+++ b/sys/compat/linux/linux_vdso.c
@@ -0,0 +1,244 @@
+/*-
+ * Copyright (c) 2013 Dmitry Chagin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_compat.h"
+
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+#define __ELF_WORD_SIZE 32
+#else
+#define __ELF_WORD_SIZE 64
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/elf.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/rwlock.h>
+#include <sys/queue.h>
+#include <sys/sysent.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+
+#include <compat/linux/linux_vdso.h>
+
+SLIST_HEAD(, linux_vdso_sym) __elfN(linux_vdso_syms) =
+ SLIST_HEAD_INITIALIZER(__elfN(linux_vdso_syms));
+
+static int __elfN(symtabindex);
+static int __elfN(symstrindex);
+
+static void
+__elfN(linux_vdso_lookup)(Elf_Ehdr *, struct linux_vdso_sym *);
+
+void
+__elfN(linux_vdso_sym_init)(struct linux_vdso_sym *s)
+{
+
+ SLIST_INSERT_HEAD(&__elfN(linux_vdso_syms), s, sym);
+}
+
+vm_object_t
+__elfN(linux_shared_page_init)(char **mapping)
+{
+ vm_page_t m;
+ vm_object_t obj;
+ vm_offset_t addr;
+
+ obj = vm_pager_allocate(OBJT_PHYS, 0, PAGE_SIZE,
+ VM_PROT_DEFAULT, 0, NULL);
+ VM_OBJECT_WLOCK(obj);
+ m = vm_page_grab(obj, 0, VM_ALLOC_ZERO);
+ VM_OBJECT_WUNLOCK(obj);
+ vm_page_valid(m);
+ vm_page_xunbusy(m);
+ addr = kva_alloc(PAGE_SIZE);
+ pmap_qenter(addr, &m, 1);
+ *mapping = (char *)addr;
+ return (obj);
+}
+
+void
+__elfN(linux_shared_page_fini)(vm_object_t obj)
+{
+
+ vm_object_deallocate(obj);
+}
+
+void
+__elfN(linux_vdso_fixup)(struct sysentvec *sv)
+{
+ Elf_Ehdr *ehdr;
+ Elf_Shdr *shdr;
+ int i;
+
+ ehdr = (Elf_Ehdr *) sv->sv_sigcode;
+
+ if (!IS_ELF(*ehdr) ||
+ ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||
+ ehdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
+ ehdr->e_ident[EI_VERSION] != EV_CURRENT ||
+ ehdr->e_shoff == 0 ||
+ ehdr->e_shentsize != sizeof(Elf_Shdr))
+ panic("Linux invalid vdso header.\n");
+
+ if (ehdr->e_type != ET_DYN)
+ panic("Linux invalid vdso header.\n");
+
+ shdr = (Elf_Shdr *) ((caddr_t)ehdr + ehdr->e_shoff);
+
+ __elfN(symtabindex) = -1;
+ __elfN(symstrindex) = -1;
+ for (i = 0; i < ehdr->e_shnum; i++) {
+ if (shdr[i].sh_size == 0)
+ continue;
+ if (shdr[i].sh_type == SHT_DYNSYM) {
+ __elfN(symtabindex) = i;
+ __elfN(symstrindex) = shdr[i].sh_link;
+ }
+ }
+
+ if (__elfN(symtabindex) == -1 || __elfN(symstrindex) == -1)
+ panic("Linux invalid vdso header.\n");
+
+ ehdr->e_ident[EI_OSABI] = ELFOSABI_LINUX;
+}
+
+void
+__elfN(linux_vdso_reloc)(struct sysentvec *sv)
+{
+ struct linux_vdso_sym *lsym;
+ Elf_Ehdr *ehdr;
+ Elf_Phdr *phdr;
+ Elf_Shdr *shdr;
+ Elf_Dyn *dyn;
+ Elf_Sym *sym;
+ int i, j, symcnt;
+
+ ehdr = (Elf_Ehdr *) sv->sv_sigcode;
+
+ /* Adjust our so relative to the sigcode_base */
+ if (sv->sv_shared_page_base != 0) {
+ ehdr->e_entry += sv->sv_shared_page_base;
+ phdr = (Elf_Phdr *)((caddr_t)ehdr + ehdr->e_phoff);
+
+ /* phdrs */
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ phdr[i].p_vaddr += sv->sv_shared_page_base;
+ if (phdr[i].p_type != PT_DYNAMIC)
+ continue;
+ dyn = (Elf_Dyn *)((caddr_t)ehdr + phdr[i].p_offset);
+ for(; dyn->d_tag != DT_NULL; dyn++) {
+ switch (dyn->d_tag) {
+ case DT_PLTGOT:
+ case DT_HASH:
+ case DT_STRTAB:
+ case DT_SYMTAB:
+ case DT_RELA:
+ case DT_INIT:
+ case DT_FINI:
+ case DT_REL:
+ case DT_DEBUG:
+ case DT_JMPREL:
+ case DT_VERSYM:
+ case DT_VERDEF:
+ case DT_VERNEED:
+ case DT_ADDRRNGLO ... DT_ADDRRNGHI:
+ dyn->d_un.d_ptr += sv->sv_shared_page_base;
+ break;
+ case DT_ENCODING ... DT_LOOS-1:
+ case DT_LOOS ... DT_HIOS:
+ if (dyn->d_tag >= DT_ENCODING &&
+ (dyn->d_tag & 1) == 0)
+ dyn->d_un.d_ptr += sv->sv_shared_page_base;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /* sections */
+ shdr = (Elf_Shdr *)((caddr_t)ehdr + ehdr->e_shoff);
+ for(i = 0; i < ehdr->e_shnum; i++) {
+ if (!(shdr[i].sh_flags & SHF_ALLOC))
+ continue;
+ shdr[i].sh_addr += sv->sv_shared_page_base;
+ if (shdr[i].sh_type != SHT_SYMTAB &&
+ shdr[i].sh_type != SHT_DYNSYM)
+ continue;
+
+ sym = (Elf_Sym *)((caddr_t)ehdr + shdr[i].sh_offset);
+ symcnt = shdr[i].sh_size / sizeof(*sym);
+
+ for(j = 0; j < symcnt; j++, sym++) {
+ if (sym->st_shndx == SHN_UNDEF ||
+ sym->st_shndx == SHN_ABS)
+ continue;
+ sym->st_value += sv->sv_shared_page_base;
+ }
+ }
+ }
+
+ SLIST_FOREACH(lsym, &__elfN(linux_vdso_syms), sym)
+ __elfN(linux_vdso_lookup)(ehdr, lsym);
+}
+
+static void
+__elfN(linux_vdso_lookup)(Elf_Ehdr *ehdr, struct linux_vdso_sym *vsym)
+{
+ vm_offset_t strtab, symname;
+ uint32_t symcnt;
+ Elf_Shdr *shdr;
+ int i;
+
+ shdr = (Elf_Shdr *) ((caddr_t)ehdr + ehdr->e_shoff);
+
+ strtab = (vm_offset_t)((caddr_t)ehdr +
+ shdr[__elfN(symstrindex)].sh_offset);
+ Elf_Sym *sym = (Elf_Sym *)((caddr_t)ehdr +
+ shdr[__elfN(symtabindex)].sh_offset);
+ symcnt = shdr[__elfN(symtabindex)].sh_size / sizeof(*sym);
+
+ for (i = 0; i < symcnt; ++i, ++sym) {
+ symname = strtab + sym->st_name;
+ if (strncmp(vsym->symname, (char *)symname, vsym->size) == 0) {
+ *vsym->ptr = (uintptr_t)sym->st_value;
+ break;
+ }
+ }
+}
diff --git a/sys/compat/linux/linux_vdso.h b/sys/compat/linux/linux_vdso.h
new file mode 100644
index 000000000000..542efef9cb82
--- /dev/null
+++ b/sys/compat/linux/linux_vdso.h
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 2013 Dmitry Chagin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_VDSO_H_
+#define _LINUX_VDSO_H_
+
+#include <sys/types.h>
+
+struct linux_vdso_sym {
+ SLIST_ENTRY(linux_vdso_sym) sym;
+ uint32_t size;
+ uintptr_t * ptr;
+ char symname[];
+};
+
+vm_object_t __elfN(linux_shared_page_init)(char **);
+void __elfN(linux_shared_page_fini)(vm_object_t);
+void __elfN(linux_vdso_fixup)(struct sysentvec *);
+void __elfN(linux_vdso_reloc)(struct sysentvec *);
+void __elfN(linux_vdso_sym_init)(struct linux_vdso_sym *);
+
+#define LINUX_VDSO_SYM_INTPTR(name) \
+uintptr_t name; \
+LINUX_VDSO_SYM_DEFINE(name)
+
+#define LINUX_VDSO_SYM_CHAR(name) \
+const char * name; \
+LINUX_VDSO_SYM_DEFINE(name)
+
+#define LINUX_VDSO_SYM_DEFINE(name) \
+static struct linux_vdso_sym name ## sym = { \
+ .symname = #name, \
+ .size = sizeof(#name), \
+ .ptr = (uintptr_t *)&name \
+}; \
+SYSINIT(__elfN(name ## _sym_init), SI_SUB_EXEC, \
+ SI_ORDER_FIRST, __elfN(linux_vdso_sym_init), &name ## sym); \
+struct __hack
+
+#endif /* _LINUX_VDSO_H_ */
diff --git a/sys/compat/linux/linux_videodev2_compat.h b/sys/compat/linux/linux_videodev2_compat.h
new file mode 100644
index 000000000000..0d9a3a348b8f
--- /dev/null
+++ b/sys/compat/linux/linux_videodev2_compat.h
@@ -0,0 +1,137 @@
+/*
+ * $FreeBSD$
+ */
+
+/*
+ * This file defines compatibility versions of several video structures
+ * defined in the Linux videodev2.h header (linux_videodev2.h). The
+ * structures defined in this file are the ones that have been determined
+ * to have 32- to 64-bit size dependencies.
+ */
+
+#ifndef _LINUX_VIDEODEV2_COMPAT_H_
+#define _LINUX_VIDEODEV2_COMPAT_H_
+
+struct l_v4l2_buffer {
+ uint32_t index;
+ enum v4l2_buf_type type;
+ uint32_t bytesused;
+ uint32_t flags;
+ enum v4l2_field field;
+ l_timeval timestamp;
+ struct v4l2_timecode timecode;
+ uint32_t sequence;
+
+ /* memory location */
+ enum v4l2_memory memory;
+ union {
+ uint32_t offset;
+ l_ulong userptr;
+ } m;
+ uint32_t length;
+ uint32_t input;
+ uint32_t reserved;
+};
+
+struct l_v4l2_framebuffer {
+ uint32_t capability;
+ uint32_t flags;
+/* FIXME: in theory we should pass something like PCI device + memory
+ * region + offset instead of some physical address */
+ l_uintptr_t base;
+ struct v4l2_pix_format fmt;
+};
+
+struct l_v4l2_clip {
+ struct v4l2_rect c;
+ l_uintptr_t next;
+};
+
+struct l_v4l2_window {
+ struct v4l2_rect w;
+ enum v4l2_field field;
+ uint32_t chromakey;
+ l_uintptr_t clips;
+ uint32_t clipcount;
+ l_uintptr_t bitmap;
+ uint8_t global_alpha;
+};
+
+struct l_v4l2_standard {
+ uint32_t index;
+ v4l2_std_id id;
+ uint8_t name[24];
+ struct v4l2_fract frameperiod; /* Frames, not fields */
+ uint32_t framelines;
+ uint32_t reserved[4];
+}
+#ifdef COMPAT_LINUX32 /* 32bit linuxolator */
+__attribute__ ((packed))
+#endif
+;
+
+struct l_v4l2_ext_control {
+ uint32_t id;
+ uint32_t size;
+ uint32_t reserved2[1];
+ union {
+ int32_t value;
+ int64_t value64;
+ l_uintptr_t string;
+ } u;
+} __attribute__ ((packed));
+
+struct l_v4l2_ext_controls {
+ uint32_t ctrl_class;
+ uint32_t count;
+ uint32_t error_idx;
+ uint32_t reserved[2];
+ l_uintptr_t controls;
+};
+
+struct l_v4l2_format {
+ enum v4l2_buf_type type;
+ union {
+ struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
+ struct l_v4l2_window win; /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
+ struct v4l2_vbi_format vbi; /* V4L2_BUF_TYPE_VBI_CAPTURE */
+ struct v4l2_sliced_vbi_format sliced; /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
+ uint8_t raw_data[200]; /* user-defined */
+ } fmt;
+}
+#ifdef COMPAT_LINUX32 /* 32bit linuxolator */
+__attribute__ ((packed))
+#endif
+;
+
+#ifdef VIDIOC_DQEVENT
+struct l_v4l2_event {
+ uint32_t type;
+ union {
+ struct v4l2_event_vsync vsync;
+ uint8_t data[64];
+ } u;
+ uint32_t pending;
+ uint32_t sequence;
+ struct l_timespec timestamp;
+ uint32_t reserved[9];
+};
+#endif
+
+struct l_v4l2_input {
+ uint32_t index; /* Which input */
+ uint8_t name[32]; /* Label */
+ uint32_t type; /* Type of input */
+ uint32_t audioset; /* Associated audios (bitfield) */
+ uint32_t tuner; /* Associated tuner */
+ v4l2_std_id std;
+ uint32_t status;
+ uint32_t capabilities;
+ uint32_t reserved[3];
+}
+#ifdef COMPAT_LINUX32 /* 32bit linuxolator */
+__attribute__ ((packed))
+#endif
+;
+
+#endif /* _LINUX_VIDEODEV2_COMPAT_H_ */
diff --git a/sys/compat/linux/linux_videodev_compat.h b/sys/compat/linux/linux_videodev_compat.h
new file mode 100644
index 000000000000..98034bcbb04d
--- /dev/null
+++ b/sys/compat/linux/linux_videodev_compat.h
@@ -0,0 +1,59 @@
+/*
+ * $FreeBSD$
+ */
+
+/*
+ * This file defines compatibility versions of several video structures
+ * defined in the Linux videodev.h header (linux_videodev.h). The
+ * structures defined in this file are the ones that have been determined
+ * to have 32- to 64-bit size dependencies.
+ */
+
+#ifndef _LINUX_VIDEODEV_COMPAT_H_
+#define _LINUX_VIDEODEV_COMPAT_H_
+
+struct l_video_tuner
+{
+ l_int tuner;
+#define LINUX_VIDEO_TUNER_NAME_SIZE 32
+ char name[LINUX_VIDEO_TUNER_NAME_SIZE];
+ l_ulong rangelow, rangehigh;
+ uint32_t flags;
+ uint16_t mode;
+ uint16_t signal;
+};
+
+struct l_video_clip
+{
+ int32_t x, y;
+ int32_t width, height;
+ l_uintptr_t next;
+};
+
+struct l_video_window
+{
+ uint32_t x, y;
+ uint32_t width, height;
+ uint32_t chromakey;
+ uint32_t flags;
+ l_uintptr_t clips;
+ l_int clipcount;
+};
+
+struct l_video_buffer
+{
+ l_uintptr_t base;
+ l_int height, width;
+ l_int depth;
+ l_int bytesperline;
+};
+
+struct l_video_code
+{
+#define LINUX_VIDEO_CODE_LOADWHAT_SIZE 16
+ char loadwhat[LINUX_VIDEO_CODE_LOADWHAT_SIZE];
+ l_int datasize;
+ l_uintptr_t data;
+};
+
+#endif /* !_LINUX_VIDEODEV_COMPAT_H_ */
diff --git a/sys/compat/linux/stats_timing.d b/sys/compat/linux/stats_timing.d
new file mode 100644
index 000000000000..66a813a9af92
--- /dev/null
+++ b/sys/compat/linux/stats_timing.d
@@ -0,0 +1,93 @@
+#!/usr/sbin/dtrace -qs
+
+/*-
+ * Copyright (c) 2008-2012 Alexander Leidinger <netchild@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/**
+ * Some statistics (all per provider):
+ * - number of calls to a function per executable binary (not per PID!)
+ * - allows to see where an optimization would be beneficial for a given
+ * application
+ * - graph of CPU time spend in functions per executable binary
+ * - together with the number of calls to this function this allows
+ * to determine if a kernel optimization would be beneficial / is
+ * possible for a given application
+ * - graph of longest running (CPU-time!) function in total
+ * - may help finding problem cases in the kernel code
+ * - graph of longest held (CPU-time!) locks
+ */
+
+#pragma D option dynvarsize=32m
+
+linuxulator*:::entry
+{
+ self->time[probefunc] = vtimestamp;
+ @calls[probeprov, execname, probefunc] = count();
+}
+
+linuxulator*:::return
+/self->time[probefunc] != 0/
+{
+ this->timediff = self->time[probefunc] - vtimestamp;
+
+ @stats[probeprov, execname, probefunc] = quantize(this->timediff);
+ @longest[probeprov, probefunc] = max(this->timediff);
+
+ self->time[probefunc] = 0;
+}
+
+linuxulator*:::locked
+{
+ self->lock[arg0] = vtimestamp;
+}
+
+linuxulator*:::unlock
+/self->lock[arg0] != 0/
+{
+ this->timediff = self->lock[arg0] - vtimestamp;
+
+ @lockstats[probefunc] = quantize(this->timediff);
+ @longlock[probefunc] = max(this->timediff);
+
+ self->lock[arg0] = 0;
+}
+
+END
+{
+ printf("Number of calls per provider/application/kernel function:");
+ printa(@calls);
+ printf("CPU-timing statistics per provider/application/kernel function (in ns):");
+ printa(@stats);
+ printf("Longest running (CPU-time!) functions per provider (in ns):");
+ printa(@longest);
+ printf("Lock CPU-timing statistics:");
+ printa(@lockstats);
+ printf("Longest running (CPU-time!) locks:");
+ printa(@longlock);
+}
+
diff --git a/sys/compat/linux/trace_futexes.d b/sys/compat/linux/trace_futexes.d
new file mode 100644
index 000000000000..94129212043a
--- /dev/null
+++ b/sys/compat/linux/trace_futexes.d
@@ -0,0 +1,182 @@
+#!/usr/sbin/dtrace -qs
+
+/*-
+ * Copyright (c) 2011-2012 Alexander Leidinger <netchild@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/**
+ * Trace futex operations:
+ * - internal locks
+ * - size of the futex list
+ * - report error conditions (emulation errors, kernel errors,
+ * programming errors)
+ * - execution time (wallclock) of futex related functions
+ */
+
+#pragma D option specsize=32m
+
+/* Error conditions */
+linuxulator*:futex:futex_get:error,
+linuxulator*:futex:futex_sleep:requeue_error,
+linuxulator*:futex:futex_sleep:sleep_error,
+linuxulator*:futex:futex_wait:copyin_error,
+linuxulator*:futex:futex_wait:itimerfix_error,
+linuxulator*:futex:futex_wait:sleep_error,
+linuxulator*:futex:futex_atomic_op:missing_access_check,
+linuxulator*:futex:futex_atomic_op:unimplemented_op,
+linuxulator*:futex:futex_atomic_op:unimplemented_cmp,
+linuxulator*:futex:linux_sys_futex:unimplemented_clockswitch,
+linuxulator*:futex:linux_sys_futex:copyin_error,
+linuxulator*:futex:linux_sys_futex:unhandled_efault,
+linuxulator*:futex:linux_sys_futex:unimplemented_lock_pi,
+linuxulator*:futex:linux_sys_futex:unimplemented_unlock_pi,
+linuxulator*:futex:linux_sys_futex:unimplemented_trylock_pi,
+linuxulator*:futex:linux_sys_futex:unimplemented_wait_requeue_pi,
+linuxulator*:futex:linux_sys_futex:unimplemented_cmp_requeue_pi,
+linuxulator*:futex:linux_sys_futex:unknown_operation,
+linuxulator*:futex:linux_get_robust_list:copyout_error,
+linuxulator*:futex:handle_futex_death:copyin_error,
+linuxulator*:futex:fetch_robust_entry:copyin_error,
+linuxulator*:futex:release_futexes:copyin_error
+{
+ printf("ERROR: %s in %s:%s:%s\n", probename, probeprov, probemod,
+ probefunc);
+ stack();
+ ustack();
+}
+
+linuxulator*:futex:linux_sys_futex:invalid_cmp_requeue_use,
+linuxulator*:futex:linux_sys_futex:deprecated_requeue,
+linuxulator*:futex:linux_set_robust_list:size_error
+{
+ printf("WARNING: %s:%s:%s:%s in application %s, maybe an application error?\n",
+ probename, probeprov, probemod, probefunc, execname);
+ stack();
+ ustack();
+}
+
+
+/* Per futex checks/statistics */
+
+linuxulator*:futex:futex:create
+{
+ ++futex_count;
+ @max_futexes = max(futex_count);
+}
+
+linuxulator*:futex:futex:destroy
+/futex_count == 0/
+{
+ printf("ERROR: Request to destroy a futex which was not created,\n");
+ printf(" or this script was started after some futexes where\n");
+ printf(" created. Stack trace:\n");
+ stack();
+ ustack();
+}
+
+linuxulator*:futex:futex:destroy
+{
+ --futex_count;
+}
+
+
+/* Internal locks */
+
+linuxulator*:locks:futex_mtx:locked
+{
+ ++check[probefunc, arg0];
+ @stats[probefunc] = count();
+
+ ts[probefunc] = timestamp;
+ spec[probefunc] = speculation();
+ printf("Stacktrace of last lock operation of the %s:\n", probefunc);
+ stack();
+}
+
+linuxulator*:locks:futex_mtx:unlock
+/check[probefunc, arg0] == 0/
+{
+ printf("ERROR: unlock attempt of unlocked %s (%p),", probefunc, arg0);
+ printf(" missing SDT probe in kernel, or dtrace program started");
+ printf(" while the %s was already held (race condition).", probefunc);
+ printf(" Stack trace follows:");
+ stack();
+}
+
+linuxulator*:locks:futex_mtx:unlock
+{
+ discard(spec[probefunc]);
+ spec[probefunc] = 0;
+ --check[probefunc, arg0];
+}
+
+/* Timeout handling for internal locks */
+
+tick-10s
+/spec["futex_mtx"] != 0 && timestamp - ts["futex_mtx"] >= 9999999000/
+{
+ commit(spec["futex_mtx"]);
+ spec["futex_mtx"] = 0;
+}
+
+
+/* Timing statistings */
+
+linuxulator*:futex::entry
+{
+ self->time[probefunc] = timestamp;
+ @calls[probeprov, execname, probefunc] = count();
+}
+
+linuxulator*:futex::return
+/self->time[probefunc] != 0/
+{
+ this->timediff = self->time[probefunc] - timestamp;
+
+ @timestats[probeprov, execname, probefunc] = quantize(this->timediff);
+ @longest[probeprov, probefunc] = max(this->timediff);
+
+ self->time[probefunc] = 0;
+}
+
+
+/* Statistics */
+
+END
+{
+ printf("Number of locks per type:");
+ printa(@stats);
+ printf("Number of maximum number of futexes in the futex list:");
+ printa(@max_futexes);
+ printf("Number of futexes still existing: %d", futex_count);
+ printf("Number of calls per provider/application/kernel function:");
+ printa(@calls);
+ printf("Wallclock-timing statistics per provider/application/kernel function (in ns):");
+ printa(@timestats);
+ printf("Longest running (wallclock!) functions per provider (in ns):");
+ printa(@longest);
+}
diff --git a/sys/compat/linuxkpi/common/include/acpi/acpi.h b/sys/compat/linuxkpi/common/include/acpi/acpi.h
new file mode 100644
index 000000000000..b6579f42774e
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/acpi/acpi.h
@@ -0,0 +1,100 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2017 Mark Johnston <markj@FreeBSD.org>
+ * Copyright (c) 2020 Vladimir Kondratyev <wulf@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ACPI_ACPI_H_
+#define _ACPI_ACPI_H_
+
+/*
+ * FreeBSD import of ACPICA has a typedef for BOOLEAN which conflicts with
+ * amdgpu driver. Workaround it on preprocessor level.
+ */
+#define ACPI_USE_SYSTEM_INTTYPES
+#define BOOLEAN unsigned char
+typedef unsigned char UINT8;
+typedef unsigned short UINT16;
+typedef short INT16;
+typedef unsigned int UINT32;
+typedef int INT32;
+typedef uint64_t UINT64;
+typedef int64_t INT64;
+#include <contrib/dev/acpica/include/acpi.h>
+#undef BOOLEAN
+
+typedef ACPI_HANDLE acpi_handle;
+typedef ACPI_OBJECT acpi_object;
+typedef ACPI_OBJECT_HANDLER acpi_object_handler;
+typedef ACPI_OBJECT_TYPE acpi_object_type;
+typedef ACPI_STATUS acpi_status;
+typedef ACPI_STRING acpi_string;
+typedef ACPI_SIZE acpi_size;
+typedef ACPI_WALK_CALLBACK acpi_walk_callback;
+
+static inline ACPI_STATUS
+acpi_evaluate_object(ACPI_HANDLE Object, ACPI_STRING Pathname,
+ ACPI_OBJECT_LIST *ParameterObjects, ACPI_BUFFER *ReturnObjectBuffer)
+{
+ return (AcpiEvaluateObject(
+ Object, Pathname, ParameterObjects, ReturnObjectBuffer));
+}
+
+static inline const char *
+acpi_format_exception(ACPI_STATUS Exception)
+{
+ return (AcpiFormatException(Exception));
+}
+
+static inline ACPI_STATUS
+acpi_get_handle(ACPI_HANDLE Parent, ACPI_STRING Pathname,
+ ACPI_HANDLE *RetHandle)
+{
+ return (AcpiGetHandle(Parent, Pathname, RetHandle));
+}
+
+static inline ACPI_STATUS
+acpi_get_data(ACPI_HANDLE ObjHandle, ACPI_OBJECT_HANDLER Handler, void **Data)
+{
+ return (AcpiGetData(ObjHandle, Handler, Data));
+}
+
+static inline ACPI_STATUS
+acpi_get_name(ACPI_HANDLE Object, UINT32 NameType, ACPI_BUFFER *RetPathPtr)
+{
+ return (AcpiGetName(Object, NameType, RetPathPtr));
+}
+
+static inline ACPI_STATUS
+acpi_get_table(ACPI_STRING Signature, UINT32 Instance,
+ ACPI_TABLE_HEADER **OutTable)
+{
+ return (AcpiGetTable(Signature, Instance, OutTable));
+}
+
+#endif /* _ACPI_ACPI_H_ */
diff --git a/sys/compat/linuxkpi/common/include/acpi/acpi_bus.h b/sys/compat/linuxkpi/common/include/acpi/acpi_bus.h
new file mode 100644
index 000000000000..abee5223af60
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/acpi/acpi_bus.h
@@ -0,0 +1,52 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020 Vladimir Kondratyev <wulf@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ACPI_ACPI_BUS_H_
+#define _ACPI_ACPI_BUS_H_
+
+typedef char acpi_device_class[20];
+
+struct acpi_bus_event {
+ acpi_device_class device_class;
+ uint32_t type;
+ uint32_t data;
+};
+
+ACPI_HANDLE bsd_acpi_get_handle(device_t bsddev);
+bool acpi_check_dsm(ACPI_HANDLE handle, const char *uuid, int rev,
+ uint64_t funcs);
+ACPI_OBJECT * acpi_evaluate_dsm_typed(ACPI_HANDLE handle, const char *uuid,
+ int rev, int func, ACPI_OBJECT *argv4,
+ ACPI_OBJECT_TYPE type);
+int register_acpi_notifier(struct notifier_block *nb);
+int unregister_acpi_notifier(struct notifier_block *nb);
+uint32_t acpi_target_system_state(void);
+
+#endif /* !_ACPI_ACPI_BUS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/acpi/video.h b/sys/compat/linuxkpi/common/include/acpi/video.h
new file mode 100644
index 000000000000..5c42153356c0
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/acpi/video.h
@@ -0,0 +1,38 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020 Vladimir Kondratyev <wulf@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ACPI_VIDEO_H_
+#define _ACPI_VIDEO_H_
+
+#define ACPI_VIDEO_CLASS "video"
+
+#define ACPI_VIDEO_NOTIFY_PROBE 0x81
+
+#endif /* !_ACPI_VIDEO_H_ */
diff --git a/sys/compat/linuxkpi/common/include/asm/atomic-long.h b/sys/compat/linuxkpi/common/include/asm/atomic-long.h
new file mode 100644
index 000000000000..c80c348f95f9
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/asm/atomic-long.h
@@ -0,0 +1,133 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _ATOMIC_LONG_H_
+#define _ATOMIC_LONG_H_
+
+#include <linux/compiler.h>
+#include <sys/types.h>
+#include <machine/atomic.h>
+#define ATOMIC_LONG_INIT(x) { .counter = (x) }
+
+typedef struct {
+ volatile long counter;
+} atomic_long_t;
+
+#define atomic_long_add(i, v) atomic_long_add_return((i), (v))
+#define atomic_long_sub(i, v) atomic_long_add_return(-(i), (v))
+#define atomic_long_inc_return(v) atomic_long_add_return(1, (v))
+#define atomic_long_inc_not_zero(v) atomic_long_add_unless((v), 1, 0)
+
+static inline long
+atomic_long_add_return(long i, atomic_long_t *v)
+{
+ return i + atomic_fetchadd_long(&v->counter, i);
+}
+
+static inline void
+atomic_long_set(atomic_long_t *v, long i)
+{
+ WRITE_ONCE(v->counter, i);
+}
+
+static inline long
+atomic_long_read(atomic_long_t *v)
+{
+ return READ_ONCE(v->counter);
+}
+
+static inline long
+atomic_long_inc(atomic_long_t *v)
+{
+ return atomic_fetchadd_long(&v->counter, 1) + 1;
+}
+
+static inline long
+atomic_long_dec(atomic_long_t *v)
+{
+ return atomic_fetchadd_long(&v->counter, -1) - 1;
+}
+
+static inline long
+atomic_long_xchg(atomic_long_t *v, long val)
+{
+ return atomic_swap_long(&v->counter, val);
+}
+
+static inline long
+atomic_long_cmpxchg(atomic_long_t *v, long old, long new)
+{
+ long ret = old;
+
+ for (;;) {
+ if (atomic_fcmpset_long(&v->counter, &ret, new))
+ break;
+ if (ret != old)
+ break;
+ }
+ return (ret);
+}
+
+static inline int
+atomic_long_add_unless(atomic_long_t *v, long a, long u)
+{
+ long c = atomic_long_read(v);
+
+ for (;;) {
+ if (unlikely(c == u))
+ break;
+ if (likely(atomic_fcmpset_long(&v->counter, &c, c + a)))
+ break;
+ }
+ return (c != u);
+}
+
+static inline long
+atomic_long_fetch_add_unless(atomic_long_t *v, long a, long u)
+{
+ long c = atomic_long_read(v);
+
+ for (;;) {
+ if (unlikely(c == u))
+ break;
+ if (likely(atomic_fcmpset_long(&v->counter, &c, c + a)))
+ break;
+ }
+ return (c);
+}
+
+static inline long
+atomic_long_dec_and_test(atomic_long_t *v)
+{
+ long i = atomic_long_add(-1, v);
+ return i == 0 ;
+}
+
+#endif /* _ATOMIC_LONG_H_ */
diff --git a/sys/compat/linuxkpi/common/include/asm/atomic.h b/sys/compat/linuxkpi/common/include/asm/atomic.h
new file mode 100644
index 000000000000..5cdfbe674ef3
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/asm/atomic.h
@@ -0,0 +1,320 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2018 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ASM_ATOMIC_H_
+#define _ASM_ATOMIC_H_
+
+#include <linux/compiler.h>
+#include <sys/types.h>
+#include <machine/atomic.h>
+#define ATOMIC_INIT(x) { .counter = (x) }
+
+typedef struct {
+ volatile int counter;
+} atomic_t;
+
+/*------------------------------------------------------------------------*
+ * 32-bit atomic operations
+ *------------------------------------------------------------------------*/
+
+#define atomic_add(i, v) atomic_add_return((i), (v))
+#define atomic_sub(i, v) atomic_sub_return((i), (v))
+#define atomic_inc_return(v) atomic_add_return(1, (v))
+#define atomic_add_negative(i, v) (atomic_add_return((i), (v)) < 0)
+#define atomic_add_and_test(i, v) (atomic_add_return((i), (v)) == 0)
+#define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0)
+#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
+#define atomic_inc_and_test(v) (atomic_add_return(1, (v)) == 0)
+#define atomic_dec_return(v) atomic_sub_return(1, (v))
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
+static inline int
+atomic_add_return(int i, atomic_t *v)
+{
+ return i + atomic_fetchadd_int(&v->counter, i);
+}
+
+static inline int
+atomic_sub_return(int i, atomic_t *v)
+{
+ return atomic_fetchadd_int(&v->counter, -i) - i;
+}
+
+static inline void
+atomic_set(atomic_t *v, int i)
+{
+ WRITE_ONCE(v->counter, i);
+}
+
+static inline void
+atomic_set_release(atomic_t *v, int i)
+{
+ atomic_store_rel_int(&v->counter, i);
+}
+
+static inline void
+atomic_set_mask(unsigned int mask, atomic_t *v)
+{
+ atomic_set_int(&v->counter, mask);
+}
+
+static inline int
+atomic_read(const atomic_t *v)
+{
+ return READ_ONCE(v->counter);
+}
+
+static inline int
+atomic_inc(atomic_t *v)
+{
+ return atomic_fetchadd_int(&v->counter, 1) + 1;
+}
+
+static inline int
+atomic_dec(atomic_t *v)
+{
+ return atomic_fetchadd_int(&v->counter, -1) - 1;
+}
+
+static inline int
+atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int c = atomic_read(v);
+
+ for (;;) {
+ if (unlikely(c == u))
+ break;
+ if (likely(atomic_fcmpset_int(&v->counter, &c, c + a)))
+ break;
+ }
+ return (c != u);
+}
+
+static inline int
+atomic_fetch_add_unless(atomic_t *v, int a, int u)
+{
+ int c = atomic_read(v);
+
+ for (;;) {
+ if (unlikely(c == u))
+ break;
+ if (likely(atomic_fcmpset_int(&v->counter, &c, c + a)))
+ break;
+ }
+ return (c);
+}
+
+static inline void
+atomic_clear_mask(unsigned int mask, atomic_t *v)
+{
+ atomic_clear_int(&v->counter, mask);
+}
+
+static inline int
+atomic_xchg(atomic_t *v, int i)
+{
+ return (atomic_swap_int(&v->counter, i));
+}
+
+static inline int
+atomic_cmpxchg(atomic_t *v, int old, int new)
+{
+ int ret = old;
+
+ for (;;) {
+ if (atomic_fcmpset_int(&v->counter, &ret, new))
+ break;
+ if (ret != old)
+ break;
+ }
+ return (ret);
+}
+
+#if defined(__amd64__) || defined(__arm64__) || defined(__i386__)
+#define LINUXKPI_ATOMIC_8(...) __VA_ARGS__
+#define LINUXKPI_ATOMIC_16(...) __VA_ARGS__
+#else
+#define LINUXKPI_ATOMIC_8(...)
+#define LINUXKPI_ATOMIC_16(...)
+#endif
+
+#if !(defined(i386) || (defined(__mips__) && !(defined(__mips_n32) || \
+ defined(__mips_n64))) || (defined(__powerpc__) && \
+ !defined(__powerpc64__)))
+#define LINUXKPI_ATOMIC_64(...) __VA_ARGS__
+#else
+#define LINUXKPI_ATOMIC_64(...)
+#endif
+
+#define cmpxchg(ptr, old, new) ({ \
+ union { \
+ __typeof(*(ptr)) val; \
+ u8 u8[0]; \
+ u16 u16[0]; \
+ u32 u32[0]; \
+ u64 u64[0]; \
+ } __ret = { .val = (old) }, __new = { .val = (new) }; \
+ \
+ CTASSERT( \
+ LINUXKPI_ATOMIC_8(sizeof(__ret.val) == 1 ||) \
+ LINUXKPI_ATOMIC_16(sizeof(__ret.val) == 2 ||) \
+ LINUXKPI_ATOMIC_64(sizeof(__ret.val) == 8 ||) \
+ sizeof(__ret.val) == 4); \
+ \
+ switch (sizeof(__ret.val)) { \
+ LINUXKPI_ATOMIC_8( \
+ case 1: \
+ while (!atomic_fcmpset_8((volatile u8 *)(ptr), \
+ __ret.u8, __new.u8[0]) && __ret.val == (old)) \
+ ; \
+ break; \
+ ) \
+ LINUXKPI_ATOMIC_16( \
+ case 2: \
+ while (!atomic_fcmpset_16((volatile u16 *)(ptr), \
+ __ret.u16, __new.u16[0]) && __ret.val == (old)) \
+ ; \
+ break; \
+ ) \
+ case 4: \
+ while (!atomic_fcmpset_32((volatile u32 *)(ptr), \
+ __ret.u32, __new.u32[0]) && __ret.val == (old)) \
+ ; \
+ break; \
+ LINUXKPI_ATOMIC_64( \
+ case 8: \
+ while (!atomic_fcmpset_64((volatile u64 *)(ptr), \
+ __ret.u64, __new.u64[0]) && __ret.val == (old)) \
+ ; \
+ break; \
+ ) \
+ } \
+ __ret.val; \
+})
+
+#define cmpxchg_relaxed(...) cmpxchg(__VA_ARGS__)
+
+#define xchg(ptr, new) ({ \
+ union { \
+ __typeof(*(ptr)) val; \
+ u8 u8[0]; \
+ u16 u16[0]; \
+ u32 u32[0]; \
+ u64 u64[0]; \
+ } __ret, __new = { .val = (new) }; \
+ \
+ CTASSERT( \
+ LINUXKPI_ATOMIC_8(sizeof(__ret.val) == 1 ||) \
+ LINUXKPI_ATOMIC_16(sizeof(__ret.val) == 2 ||) \
+ LINUXKPI_ATOMIC_64(sizeof(__ret.val) == 8 ||) \
+ sizeof(__ret.val) == 4); \
+ \
+ switch (sizeof(__ret.val)) { \
+ LINUXKPI_ATOMIC_8( \
+ case 1: \
+ __ret.val = READ_ONCE(*ptr); \
+ while (!atomic_fcmpset_8((volatile u8 *)(ptr), \
+ __ret.u8, __new.u8[0])) \
+ ; \
+ break; \
+ ) \
+ LINUXKPI_ATOMIC_16( \
+ case 2: \
+ __ret.val = READ_ONCE(*ptr); \
+ while (!atomic_fcmpset_16((volatile u16 *)(ptr), \
+ __ret.u16, __new.u16[0])) \
+ ; \
+ break; \
+ ) \
+ case 4: \
+ __ret.u32[0] = atomic_swap_32((volatile u32 *)(ptr), \
+ __new.u32[0]); \
+ break; \
+ LINUXKPI_ATOMIC_64( \
+ case 8: \
+ __ret.u64[0] = atomic_swap_64((volatile u64 *)(ptr), \
+ __new.u64[0]); \
+ break; \
+ ) \
+ } \
+ __ret.val; \
+})
+
+static inline int
+atomic_dec_if_positive(atomic_t *v)
+{
+ int retval;
+ int old;
+
+ old = atomic_read(v);
+ for (;;) {
+ retval = old - 1;
+ if (unlikely(retval < 0))
+ break;
+ if (likely(atomic_fcmpset_int(&v->counter, &old, retval)))
+ break;
+ }
+ return (retval);
+}
+
+#define LINUX_ATOMIC_OP(op, c_op) \
+static inline void atomic_##op(int i, atomic_t *v) \
+{ \
+ int c, old; \
+ \
+ c = v->counter; \
+ while ((old = atomic_cmpxchg(v, c, c c_op i)) != c) \
+ c = old; \
+}
+
+#define LINUX_ATOMIC_FETCH_OP(op, c_op) \
+static inline int atomic_fetch_##op(int i, atomic_t *v) \
+{ \
+ int c, old; \
+ \
+ c = v->counter; \
+ while ((old = atomic_cmpxchg(v, c, c c_op i)) != c) \
+ c = old; \
+ \
+ return (c); \
+}
+
+LINUX_ATOMIC_OP(or, |)
+LINUX_ATOMIC_OP(and, &)
+LINUX_ATOMIC_OP(andnot, &~)
+LINUX_ATOMIC_OP(xor, ^)
+
+LINUX_ATOMIC_FETCH_OP(or, |)
+LINUX_ATOMIC_FETCH_OP(and, &)
+LINUX_ATOMIC_FETCH_OP(andnot, &~)
+LINUX_ATOMIC_FETCH_OP(xor, ^)
+
+#endif /* _ASM_ATOMIC_H_ */
diff --git a/sys/compat/linuxkpi/common/include/asm/atomic64.h b/sys/compat/linuxkpi/common/include/asm/atomic64.h
new file mode 100644
index 000000000000..b8b87bb2c685
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/asm/atomic64.h
@@ -0,0 +1,148 @@
+/*-
+ * Copyright (c) 2016-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _ASM_ATOMIC64_H_
+#define _ASM_ATOMIC64_H_
+
+#include <linux/compiler.h>
+#include <sys/types.h>
+#include <machine/atomic.h>
+
+typedef struct {
+ volatile int64_t counter;
+} atomic64_t;
+#define ATOMIC64_INIT(x) { .counter = (x) }
+
+/*------------------------------------------------------------------------*
+ * 64-bit atomic operations
+ *------------------------------------------------------------------------*/
+
+#define atomic64_add(i, v) atomic64_add_return((i), (v))
+#define atomic64_sub(i, v) atomic64_sub_return((i), (v))
+#define atomic64_inc_return(v) atomic64_add_return(1, (v))
+#define atomic64_add_negative(i, v) (atomic64_add_return((i), (v)) < 0)
+#define atomic64_add_and_test(i, v) (atomic64_add_return((i), (v)) == 0)
+#define atomic64_sub_and_test(i, v) (atomic64_sub_return((i), (v)) == 0)
+#define atomic64_dec_and_test(v) (atomic64_sub_return(1, (v)) == 0)
+#define atomic64_inc_and_test(v) (atomic64_add_return(1, (v)) == 0)
+#define atomic64_dec_return(v) atomic64_sub_return(1, (v))
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+
+static inline int64_t
+atomic64_add_return(int64_t i, atomic64_t *v)
+{
+ return i + atomic_fetchadd_64(&v->counter, i);
+}
+
+static inline int64_t
+atomic64_sub_return(int64_t i, atomic64_t *v)
+{
+ return atomic_fetchadd_64(&v->counter, -i) - i;
+}
+
+static inline void
+atomic64_set(atomic64_t *v, int64_t i)
+{
+ atomic_store_rel_64(&v->counter, i);
+}
+
+static inline int64_t
+atomic64_read(atomic64_t *v)
+{
+ return READ_ONCE(v->counter);
+}
+
+static inline int64_t
+atomic64_inc(atomic64_t *v)
+{
+ return atomic_fetchadd_64(&v->counter, 1) + 1;
+}
+
+static inline int64_t
+atomic64_dec(atomic64_t *v)
+{
+ return atomic_fetchadd_64(&v->counter, -1) - 1;
+}
+
+static inline int64_t
+atomic64_add_unless(atomic64_t *v, int64_t a, int64_t u)
+{
+ int64_t c = atomic64_read(v);
+
+ for (;;) {
+ if (unlikely(c == u))
+ break;
+ if (likely(atomic_fcmpset_64(&v->counter, &c, c + a)))
+ break;
+ }
+ return (c != u);
+}
+
+static inline int64_t
+atomic64_fetch_add_unless(atomic64_t *v, int64_t a, int64_t u)
+{
+ int64_t c = atomic64_read(v);
+
+ for (;;) {
+ if (unlikely(c == u))
+ break;
+ if (likely(atomic_fcmpset_64(&v->counter, &c, c + a)))
+ break;
+ }
+ return (c);
+}
+
+static inline int64_t
+atomic64_xchg(atomic64_t *v, int64_t i)
+{
+#if !((defined(__mips__) && !(defined(__mips_n32) || defined(__mips_n64))) || \
+ (defined(__powerpc__) && !defined(__powerpc64__)))
+ return (atomic_swap_64(&v->counter, i));
+#else
+ int64_t ret = atomic64_read(v);
+
+ while (!atomic_fcmpset_64(&v->counter, &ret, i))
+ ;
+ return (ret);
+#endif
+}
+
+static inline int64_t
+atomic64_cmpxchg(atomic64_t *v, int64_t old, int64_t new)
+{
+ int64_t ret = old;
+
+ for (;;) {
+ if (atomic_fcmpset_64(&v->counter, &ret, new))
+ break;
+ if (ret != old)
+ break;
+ }
+ return (ret);
+}
+
+#endif /* _ASM_ATOMIC64_H_ */
diff --git a/sys/compat/linuxkpi/common/include/asm/byteorder.h b/sys/compat/linuxkpi/common/include/asm/byteorder.h
new file mode 100644
index 000000000000..0a6c2b039c66
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/asm/byteorder.h
@@ -0,0 +1,94 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _ASM_BYTEORDER_H_
+#define _ASM_BYTEORDER_H_
+
+#include <sys/types.h>
+#include <sys/endian.h>
+#include <asm/types.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define __LITTLE_ENDIAN
+#else
+#define __BIG_ENDIAN
+#endif
+
+#define cpu_to_le64(x) htole64(x)
+#define le64_to_cpu(x) le64toh(x)
+#define cpu_to_le32(x) htole32(x)
+#define le32_to_cpu(x) le32toh(x)
+#define cpu_to_le16(x) htole16(x)
+#define le16_to_cpu(x) le16toh(x)
+#define cpu_to_be64(x) htobe64(x)
+#define be64_to_cpu(x) be64toh(x)
+#define cpu_to_be32(x) htobe32(x)
+#define be32_to_cpu(x) be32toh(x)
+#define cpu_to_be16(x) htobe16(x)
+#define be16_to_cpu(x) be16toh(x)
+#define __be16_to_cpu(x) be16toh(x)
+
+#define cpu_to_le64p(x) htole64(*((const uint64_t *)(x)))
+#define le64_to_cpup(x) le64toh(*((const uint64_t *)(x)))
+#define cpu_to_le32p(x) htole32(*((const uint32_t *)(x)))
+#define le32_to_cpup(x) le32toh(*((const uint32_t *)(x)))
+#define cpu_to_le16p(x) htole16(*((const uint16_t *)(x)))
+#define le16_to_cpup(x) le16toh(*((const uint16_t *)(x)))
+#define cpu_to_be64p(x) htobe64(*((const uint64_t *)(x)))
+#define be64_to_cpup(x) be64toh(*((const uint64_t *)(x)))
+#define cpu_to_be32p(x) htobe32(*((const uint32_t *)(x)))
+#define be32_to_cpup(x) be32toh(*((const uint32_t *)(x)))
+#define cpu_to_be16p(x) htobe16(*((const uint16_t *)(x)))
+#define be16_to_cpup(x) be16toh(*((const uint16_t *)(x)))
+
+#define cpu_to_le64s(x) do { *((uint64_t *)(x)) = cpu_to_le64p((x)); } while (0)
+#define le64_to_cpus(x) do { *((uint64_t *)(x)) = le64_to_cpup((x)); } while (0)
+#define cpu_to_le32s(x) do { *((uint32_t *)(x)) = cpu_to_le32p((x)); } while (0)
+#define le32_to_cpus(x) do { *((uint32_t *)(x)) = le32_to_cpup((x)); } while (0)
+#define cpu_to_le16s(x) do { *((uint16_t *)(x)) = cpu_to_le16p((x)); } while (0)
+#define le16_to_cpus(x) do { *((uint16_t *)(x)) = le16_to_cpup((x)); } while (0)
+#define cpu_to_be64s(x) do { *((uint64_t *)(x)) = cpu_to_be64p((x)); } while (0)
+#define be64_to_cpus(x) do { *((uint64_t *)(x)) = be64_to_cpup((x)); } while (0)
+#define cpu_to_be32s(x) do { *((uint32_t *)(x)) = cpu_to_be32p((x)); } while (0)
+#define be32_to_cpus(x) do { *((uint32_t *)(x)) = be32_to_cpup((x)); } while (0)
+#define cpu_to_be16s(x) do { *((uint16_t *)(x)) = cpu_to_be16p((x)); } while (0)
+#define be16_to_cpus(x) do { *((uint16_t *)(x)) = be16_to_cpup((x)); } while (0)
+
+#define swab16(x) bswap16(x)
+#define swab32(x) bswap32(x)
+#define swab64(x) bswap64(x)
+
+static inline void
+be16_add_cpu(uint16_t *var, uint16_t val)
+{
+ *var = cpu_to_be16(be16_to_cpu(*var) + val);
+}
+
+#endif /* _ASM_BYTEORDER_H_ */
diff --git a/sys/compat/linuxkpi/common/include/asm/fcntl.h b/sys/compat/linuxkpi/common/include/asm/fcntl.h
new file mode 100644
index 000000000000..f24624e6eeed
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/asm/fcntl.h
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _ASM_FCNTL_H_
+#define _ASM_FCNTL_H_
+
+#include <sys/fcntl.h>
+
+#endif /* _ASM_FCNTL_H_ */
diff --git a/sys/compat/linuxkpi/common/include/asm/fpu/api.h b/sys/compat/linuxkpi/common/include/asm/fpu/api.h
new file mode 100644
index 000000000000..035ec3620fdd
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/asm/fpu/api.h
@@ -0,0 +1,68 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020 Greg V <greg@unrelenting.technology>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _FPU_API_H_
+#define _FPU_API_H_
+
+#if defined(__aarch64__) || defined(__amd64__) || defined(__i386__)
+
+#include <machine/fpu.h>
+
+extern struct fpu_kern_ctx *__lkpi_fpu_ctx;
+extern unsigned int __lkpi_fpu_ctx_level;
+
+static inline void
+kernel_fpu_begin()
+{
+ if (__lkpi_fpu_ctx_level++ == 0) {
+ fpu_kern_enter(curthread, __lkpi_fpu_ctx, FPU_KERN_NORMAL);
+ }
+}
+
+static inline void
+kernel_fpu_end()
+{
+ if (--__lkpi_fpu_ctx_level == 0) {
+ fpu_kern_leave(curthread, __lkpi_fpu_ctx);
+ }
+}
+
+#else
+
+static inline void
+kernel_fpu_begin()
+{
+}
+
+static inline void
+kernel_fpu_end()
+{
+}
+
+#endif
+
+#endif /* _FPU_API_H_ */
diff --git a/sys/compat/linuxkpi/common/include/asm/io.h b/sys/compat/linuxkpi/common/include/asm/io.h
new file mode 100644
index 000000000000..24d350f4743e
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/asm/io.h
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _ASM_IO_H_
+#define _ASM_IO_H_
+
+#include <linux/io.h>
+
+#endif /* _ASM_IO_H_ */
diff --git a/sys/compat/linuxkpi/common/include/asm/msr.h b/sys/compat/linuxkpi/common/include/asm/msr.h
new file mode 100644
index 000000000000..1697c20767a5
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/asm/msr.h
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2017 Mark Johnston <markj@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ASM_MSR_H_
+#define _ASM_MSR_H_
+
+#include <machine/cpufunc.h>
+
+#define rdmsrl(msr, val) ((val) = rdmsr(msr))
+#define rdmsrl_safe(msr, val) rdmsr_safe(msr, val)
+
+#endif /* _ASM_MSR_H_ */
diff --git a/sys/compat/linuxkpi/common/include/asm/pgtable.h b/sys/compat/linuxkpi/common/include/asm/pgtable.h
new file mode 100644
index 000000000000..1df103060368
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/asm/pgtable.h
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _ASM_PGTABLE_H_
+#define _ASM_PGTABLE_H_
+
+#include <linux/page.h>
+
+typedef unsigned long pteval_t;
+typedef unsigned long pmdval_t;
+typedef unsigned long pudval_t;
+typedef unsigned long pgdval_t;
+typedef unsigned long pgprotval_t;
+typedef struct page *pgtable_t;
+
+#endif /* _ASM_PGTABLE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/asm/smp.h b/sys/compat/linuxkpi/common/include/asm/smp.h
new file mode 100644
index 000000000000..dd25b02115a8
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/asm/smp.h
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2017 Mark Johnston <markj@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ASM_SMP_H_
+#define _ASM_SMP_H_
+
+#if defined(__i386__) || defined(__amd64__)
+
+#define wbinvd_on_all_cpus() linux_wbinvd_on_all_cpus()
+
+int linux_wbinvd_on_all_cpus(void);
+
+#endif
+
+#define get_cpu() ({ \
+ critical_enter(); \
+ PCPU_GET(cpuid); \
+})
+
+#define put_cpu() \
+ critical_exit()
+
+#endif /* _ASM_SMP_H_ */
diff --git a/sys/compat/linuxkpi/common/include/asm/types.h b/sys/compat/linuxkpi/common/include/asm/types.h
new file mode 100644
index 000000000000..daa5d83616a2
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/asm/types.h
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _ASM_TYPES_H_
+#define _ASM_TYPES_H_
+
+#if defined(_KERNEL) || defined(_STANDALONE)
+
+#include <sys/types.h>
+
+typedef uint8_t u8;
+typedef uint8_t __u8;
+typedef uint16_t u16;
+typedef uint16_t __u16;
+typedef uint32_t u32;
+typedef uint32_t __u32;
+typedef uint64_t u64;
+typedef uint64_t __u64;
+
+typedef int8_t s8;
+typedef int8_t __s8;
+typedef int16_t s16;
+typedef int16_t __s16;
+typedef int32_t s32;
+typedef int32_t __s32;
+typedef int64_t s64;
+typedef int64_t __s64;
+
+/* DMA addresses come in generic and 64-bit flavours. */
+typedef vm_paddr_t dma_addr_t;
+typedef vm_paddr_t dma64_addr_t;
+
+typedef unsigned short umode_t;
+
+#endif /* _KERNEL || _STANDALONE */
+
+#endif /* _ASM_TYPES_H_ */
diff --git a/sys/compat/linuxkpi/common/include/asm/uaccess.h b/sys/compat/linuxkpi/common/include/asm/uaccess.h
new file mode 100644
index 000000000000..0ae20b09dc8c
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/asm/uaccess.h
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _ASM_UACCESS_H_
+#define _ASM_UACCESS_H_
+
+#include <linux/uaccess.h>
+
+static inline long
+copy_to_user(void *to, const void *from, unsigned long n)
+{
+ if (linux_copyout(from, to, n) != 0)
+ return n;
+ return 0;
+}
+#define __copy_to_user(...) copy_to_user(__VA_ARGS__)
+
+static inline long
+copy_from_user(void *to, const void *from, unsigned long n)
+{
+ if (linux_copyin(from, to, n) != 0)
+ return n;
+ return 0;
+}
+#define __copy_from_user(...) copy_from_user(__VA_ARGS__)
+#define __copy_in_user(...) copy_from_user(__VA_ARGS__)
+
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 50000
+#define user_access_begin(ptr, len) access_ok(ptr, len)
+#else
+#define user_access_begin() do { } while (0)
+#endif
+#define user_access_end() do { } while (0)
+
+#define unsafe_get_user(x, ptr, err) do { \
+ if (unlikely(__get_user(x, ptr))) \
+ goto err; \
+} while (0)
+
+#define unsafe_put_user(x, ptr, err) do { \
+ if (unlikely(__put_user(x, ptr))) \
+ goto err; \
+} while (0)
+
+#endif /* _ASM_UACCESS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/asm/unaligned.h b/sys/compat/linuxkpi/common/include/asm/unaligned.h
new file mode 100644
index 000000000000..7597f00f7596
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/asm/unaligned.h
@@ -0,0 +1,78 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Björn Zeeb under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ASM_UNALIGNED_H
+#define _ASM_UNALIGNED_H
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+static __inline uint32_t
+get_unaligned_le32(const void *p)
+{
+
+ return (le32_to_cpup((const __le32 *)p));
+}
+
+static __inline void
+put_unaligned_le32(__le32 v, void *p)
+{
+ __le32 x;
+
+ x = cpu_to_le32(v);
+ memcpy(p, &x, sizeof(x));
+}
+
+static __inline void
+put_unaligned_le64(__le64 v, void *p)
+{
+ __le64 x;
+
+ x = cpu_to_le64(v);
+ memcpy(p, &x, sizeof(x));
+}
+
+static __inline uint16_t
+get_unaligned_be16(const void *p)
+{
+
+ return (be16_to_cpup((const __be16 *)p));
+}
+
+static __inline uint32_t
+get_unaligned_be32(const void *p)
+{
+
+ return (be32_to_cpup((const __be32 *)p));
+}
+
+#endif /* _ASM_UNALIGNED_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/acpi.h b/sys/compat/linuxkpi/common/include/linux/acpi.h
new file mode 100644
index 000000000000..068e0fe6fb06
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/acpi.h
@@ -0,0 +1,46 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020 Vladimir Kondratyev <wulf@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_ACPI_H_
+#define _LINUX_ACPI_H_
+
+#include <linux/device.h>
+
+#if defined(__aarch64__) || defined(__amd64__) || defined(__i386__)
+
+#include <acpi/acpi.h>
+#include <acpi/acpi_bus.h>
+
+#define ACPI_HANDLE(dev) \
+ ((dev)->bsddev != NULL ? bsd_acpi_get_handle((dev)->bsddev) : NULL)
+
+#endif
+
+#endif /* _LINUX_ACPI_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/atomic.h b/sys/compat/linuxkpi/common/include/linux/atomic.h
new file mode 100644
index 000000000000..f8aa5c9276e7
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/atomic.h
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2017 Mark Johnston <markj@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_ATOMIC_H_
+#define _LINUX_ATOMIC_H_
+
+#include <asm/atomic.h>
+#include <asm/atomic64.h>
+#include <asm/atomic-long.h>
+
+#endif /* _LINUX_ATOMIC_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/backlight.h b/sys/compat/linuxkpi/common/include/linux/backlight.h
new file mode 100644
index 000000000000..1d2224811124
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/backlight.h
@@ -0,0 +1,94 @@
+/*-
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Emmanuel Vadot under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_BACKLIGHT_H_
+#define _LINUX_BACKLIGHT_H_
+
+#include <linux/notifier.h>
+
+struct backlight_device;
+
+enum backlight_type {
+ BACKLIGHT_RAW = 0,
+};
+
+struct backlight_properties {
+ int type;
+ int max_brightness;
+ int brightness;
+ int power;
+};
+
+enum backlight_notification {
+ BACKLIGHT_REGISTERED,
+ BACKLIGHT_UNREGISTERED,
+};
+
+enum backlight_update_reason {
+ BACKLIGHT_UPDATE_HOTKEY = 0
+};
+
+struct backlight_ops {
+ int options;
+#define BL_CORE_SUSPENDRESUME 1
+ int (*update_status)(struct backlight_device *);
+ int (*get_brightness)(struct backlight_device *);
+};
+
+struct backlight_device {
+ const struct backlight_ops *ops;
+ struct backlight_properties props;
+ void *data;
+ struct device *dev;
+ char *name;
+};
+
+#define bl_get_data(bd) (bd)->data
+
+struct backlight_device *linux_backlight_device_register(const char *name,
+ struct device *dev, void *data, const struct backlight_ops *ops, struct backlight_properties *props);
+void linux_backlight_device_unregister(struct backlight_device *bd);
+#define backlight_device_register(name, dev, data, ops, props) \
+ linux_backlight_device_register(name, dev, data, ops, props)
+#define backlight_device_unregister(bd) linux_backlight_device_unregister(bd)
+
+static inline void
+backlight_update_status(struct backlight_device *bd)
+{
+ bd->ops->update_status(bd);
+}
+
+static inline void
+backlight_force_update(struct backlight_device *bd, int reason)
+{
+ bd->props.brightness = bd->ops->get_brightness(bd);
+}
+
+#endif /* _LINUX_BACKLIGHT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/bitfield.h b/sys/compat/linuxkpi/common/include/linux/bitfield.h
new file mode 100644
index 000000000000..4749cc4454e7
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/bitfield.h
@@ -0,0 +1,105 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Björn Zeeb under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_BITFIELD_H
+#define _LINUX_BITFIELD_H
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+/* Use largest possible type. */
+static inline uint64_t ___lsb(uint64_t f) { return (f & -f); }
+static inline uint64_t ___bitmask(uint64_t f) { return (f / ___lsb(f)); }
+
+#define _uX_get_bits(_n) \
+ static __inline uint ## _n ## _t \
+ u ## _n ## _get_bits(uint ## _n ## _t v, uint ## _n ## _t f) \
+ { \
+ return ((v & f) / ___lsb(f)); \
+ }
+
+_uX_get_bits(64)
+_uX_get_bits(32)
+_uX_get_bits(16)
+_uX_get_bits(8)
+
+#define _leX_get_bits(_n) \
+ static __inline uint ## _n ## _t \
+ le ## _n ## _get_bits(__le ## _n v, uint ## _n ## _t f) \
+ { \
+ return ((le ## _n ## _to_cpu(v) & f) / ___lsb(f)); \
+ }
+
+_leX_get_bits(64)
+_leX_get_bits(32)
+_leX_get_bits(16)
+
+#define _uX_encode_bits(_n) \
+ static __inline uint ## _n ## _t \
+ u ## _n ## _encode_bits(uint ## _n ## _t v, uint ## _n ## _t f) \
+ { \
+ return ((v & ___bitmask(f)) * ___lsb(f)); \
+ }
+
+_uX_encode_bits(64)
+_uX_encode_bits(32)
+_uX_encode_bits(16)
+_uX_encode_bits(8)
+
+#define _leX_encode_bits(_n) \
+ static __inline uint ## _n ## _t \
+ le ## _n ## _encode_bits(__le ## _n v, uint ## _n ## _t f)\
+ { \
+ return (cpu_to_le ## _n((v & ___bitmask(f)) * ___lsb(f))); \
+ }
+
+_leX_encode_bits(64)
+_leX_encode_bits(32)
+_leX_encode_bits(16)
+
+static __inline void
+le32p_replace_bits(uint32_t *p, uint32_t v, uint32_t f)
+{
+
+ *p = (*p & ~(cpu_to_le32(v))) | le32_encode_bits(v, f);
+ return;
+}
+
+#define __bf_shf(x) (__builtin_ffsll(x) - 1)
+
+#define FIELD_PREP(_mask, _value) \
+ (((typeof(_mask))(_value) << __bf_shf(_mask)) & (_mask))
+
+#define FIELD_GET(_mask, _value) \
+ ((typeof(_mask))(((_value) & (_mask)) >> __bf_shf(_mask)))
+
+#endif /* _LINUX_BITFIELD_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/bitmap.h b/sys/compat/linuxkpi/common/include/linux/bitmap.h
new file mode 100644
index 000000000000..4de94333c99f
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/bitmap.h
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_BITMAP_H_
+#define _LINUX_BITMAP_H_
+
+#include <linux/bitops.h>
+#include <linux/slab.h>
+
+static inline void
+bitmap_zero(unsigned long *addr, const unsigned int size)
+{
+ memset(addr, 0, BITS_TO_LONGS(size) * sizeof(long));
+}
+
+static inline void
+bitmap_fill(unsigned long *addr, const unsigned int size)
+{
+ const unsigned int tail = size & (BITS_PER_LONG - 1);
+
+ memset(addr, 0xff, BIT_WORD(size) * sizeof(long));
+
+ if (tail)
+ addr[BIT_WORD(size)] = BITMAP_LAST_WORD_MASK(tail);
+}
+
+static inline int
+bitmap_full(unsigned long *addr, const unsigned int size)
+{
+ const unsigned int end = BIT_WORD(size);
+ const unsigned int tail = size & (BITS_PER_LONG - 1);
+ unsigned int i;
+
+ for (i = 0; i != end; i++) {
+ if (addr[i] != ~0UL)
+ return (0);
+ }
+
+ if (tail) {
+ const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
+
+ if ((addr[end] & mask) != mask)
+ return (0);
+ }
+ return (1);
+}
+
+static inline int
+bitmap_empty(unsigned long *addr, const unsigned int size)
+{
+ const unsigned int end = BIT_WORD(size);
+ const unsigned int tail = size & (BITS_PER_LONG - 1);
+ unsigned int i;
+
+ for (i = 0; i != end; i++) {
+ if (addr[i] != 0)
+ return (0);
+ }
+
+ if (tail) {
+ const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
+
+ if ((addr[end] & mask) != 0)
+ return (0);
+ }
+ return (1);
+}
+
+static inline void
+bitmap_set(unsigned long *map, unsigned int start, int nr)
+{
+ const unsigned int size = start + nr;
+ int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG);
+ unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start);
+
+ map += BIT_WORD(start);
+
+ while (nr - bits_to_set >= 0) {
+ *map |= mask_to_set;
+ nr -= bits_to_set;
+ bits_to_set = BITS_PER_LONG;
+ mask_to_set = ~0UL;
+ map++;
+ }
+
+ if (nr) {
+ mask_to_set &= BITMAP_LAST_WORD_MASK(size);
+ *map |= mask_to_set;
+ }
+}
+
+static inline void
+bitmap_clear(unsigned long *map, unsigned int start, int nr)
+{
+ const unsigned int size = start + nr;
+ int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG);
+ unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start);
+
+ map += BIT_WORD(start);
+
+ while (nr - bits_to_clear >= 0) {
+ *map &= ~mask_to_clear;
+ nr -= bits_to_clear;
+ bits_to_clear = BITS_PER_LONG;
+ mask_to_clear = ~0UL;
+ map++;
+ }
+
+ if (nr) {
+ mask_to_clear &= BITMAP_LAST_WORD_MASK(size);
+ *map &= ~mask_to_clear;
+ }
+}
+
+static inline unsigned int
+bitmap_find_next_zero_area_off(const unsigned long *map,
+ const unsigned int size, unsigned int start,
+ unsigned int nr, unsigned int align_mask,
+ unsigned int align_offset)
+{
+ unsigned int index;
+ unsigned int end;
+ unsigned int i;
+
+retry:
+ index = find_next_zero_bit(map, size, start);
+
+ index = (((index + align_offset) + align_mask) & ~align_mask) - align_offset;
+
+ end = index + nr;
+ if (end > size)
+ return (end);
+
+ i = find_next_bit(map, end, index);
+ if (i < end) {
+ start = i + 1;
+ goto retry;
+ }
+ return (index);
+}
+
+static inline unsigned int
+bitmap_find_next_zero_area(const unsigned long *map,
+ const unsigned int size, unsigned int start,
+ unsigned int nr, unsigned int align_mask)
+{
+ return (bitmap_find_next_zero_area_off(map, size,
+ start, nr, align_mask, 0));
+}
+
+static inline int
+bitmap_find_free_region(unsigned long *bitmap, int bits, int order)
+{
+ int pos;
+ int end;
+
+ for (pos = 0; (end = pos + (1 << order)) <= bits; pos = end) {
+ if (!linux_reg_op(bitmap, pos, order, REG_OP_ISFREE))
+ continue;
+ linux_reg_op(bitmap, pos, order, REG_OP_ALLOC);
+ return (pos);
+ }
+ return (-ENOMEM);
+}
+
+static inline int
+bitmap_allocate_region(unsigned long *bitmap, int pos, int order)
+{
+ if (!linux_reg_op(bitmap, pos, order, REG_OP_ISFREE))
+ return (-EBUSY);
+ linux_reg_op(bitmap, pos, order, REG_OP_ALLOC);
+ return (0);
+}
+
+static inline void
+bitmap_release_region(unsigned long *bitmap, int pos, int order)
+{
+ linux_reg_op(bitmap, pos, order, REG_OP_RELEASE);
+}
+
+static inline unsigned int
+bitmap_weight(unsigned long *addr, const unsigned int size)
+{
+ const unsigned int end = BIT_WORD(size);
+ const unsigned int tail = size & (BITS_PER_LONG - 1);
+ unsigned int retval = 0;
+ unsigned int i;
+
+ for (i = 0; i != end; i++)
+ retval += hweight_long(addr[i]);
+
+ if (tail) {
+ const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
+
+ retval += hweight_long(addr[end] & mask);
+ }
+ return (retval);
+}
+
+static inline int
+bitmap_equal(const unsigned long *pa,
+ const unsigned long *pb, unsigned size)
+{
+ const unsigned int end = BIT_WORD(size);
+ const unsigned int tail = size & (BITS_PER_LONG - 1);
+ unsigned int i;
+
+ for (i = 0; i != end; i++) {
+ if (pa[i] != pb[i])
+ return (0);
+ }
+
+ if (tail) {
+ const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
+
+ if ((pa[end] ^ pb[end]) & mask)
+ return (0);
+ }
+ return (1);
+}
+
+static inline int
+bitmap_subset(const unsigned long *pa,
+ const unsigned long *pb, unsigned size)
+{
+ const unsigned end = BIT_WORD(size);
+ const unsigned tail = size & (BITS_PER_LONG - 1);
+ unsigned i;
+
+ for (i = 0; i != end; i++) {
+ if (pa[i] & ~pb[i])
+ return (0);
+ }
+
+ if (tail) {
+ const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
+
+ if (pa[end] & ~pb[end] & mask)
+ return (0);
+ }
+ return (1);
+}
+
+static inline void
+bitmap_complement(unsigned long *dst, const unsigned long *src,
+ const unsigned int size)
+{
+ const unsigned int end = BITS_TO_LONGS(size);
+ unsigned int i;
+
+ for (i = 0; i != end; i++)
+ dst[i] = ~src[i];
+}
+
+static inline void
+bitmap_copy(unsigned long *dst, const unsigned long *src,
+ const unsigned int size)
+{
+ const unsigned int end = BITS_TO_LONGS(size);
+ unsigned int i;
+
+ for (i = 0; i != end; i++)
+ dst[i] = src[i];
+}
+
+static inline void
+bitmap_or(unsigned long *dst, const unsigned long *src1,
+ const unsigned long *src2, const unsigned int size)
+{
+ const unsigned int end = BITS_TO_LONGS(size);
+ unsigned int i;
+
+ for (i = 0; i != end; i++)
+ dst[i] = src1[i] | src2[i];
+}
+
+static inline void
+bitmap_and(unsigned long *dst, const unsigned long *src1,
+ const unsigned long *src2, const unsigned int size)
+{
+ const unsigned int end = BITS_TO_LONGS(size);
+ unsigned int i;
+
+ for (i = 0; i != end; i++)
+ dst[i] = src1[i] & src2[i];
+}
+
+static inline void
+bitmap_andnot(unsigned long *dst, const unsigned long *src1,
+ const unsigned long *src2, const unsigned int size)
+{
+ const unsigned int end = BITS_TO_LONGS(size);
+ unsigned int i;
+
+ for (i = 0; i != end; i++)
+ dst[i] = src1[i] & ~src2[i];
+}
+
+static inline void
+bitmap_xor(unsigned long *dst, const unsigned long *src1,
+ const unsigned long *src2, const unsigned int size)
+{
+ const unsigned int end = BITS_TO_LONGS(size);
+ unsigned int i;
+
+ for (i = 0; i != end; i++)
+ dst[i] = src1[i] ^ src2[i];
+}
+
+static inline unsigned long *
+bitmap_alloc(unsigned int size, gfp_t flags)
+{
+ return (kmalloc_array(BITS_TO_LONGS(size),
+ sizeof(unsigned long), flags));
+}
+
+static inline unsigned long *
+bitmap_zalloc(unsigned int size, gfp_t flags)
+{
+ return (bitmap_alloc(size, flags | __GFP_ZERO));
+}
+
+static inline void
+bitmap_free(const unsigned long *bitmap)
+{
+ kfree(bitmap);
+}
+
+#endif /* _LINUX_BITMAP_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/bitops.h b/sys/compat/linuxkpi/common/include/linux/bitops.h
new file mode 100644
index 000000000000..0e25fd3cfb1d
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/bitops.h
@@ -0,0 +1,410 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_BITOPS_H_
+#define _LINUX_BITOPS_H_
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/libkern.h>
+
+#define BIT(nr) (1UL << (nr))
+#define BIT_ULL(nr) (1ULL << (nr))
+#ifdef __LP64__
+#define BITS_PER_LONG 64
+#else
+#define BITS_PER_LONG 32
+#endif
+
+#define BITS_PER_LONG_LONG 64
+
+#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) % BITS_PER_LONG))
+#define BITMAP_LAST_WORD_MASK(n) (~0UL >> (BITS_PER_LONG - (n)))
+#define BITS_TO_LONGS(n) howmany((n), BITS_PER_LONG)
+#define BIT_MASK(nr) (1UL << ((nr) & (BITS_PER_LONG - 1)))
+#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
+#define GENMASK(h, l) (((~0UL) >> (BITS_PER_LONG - (h) - 1)) & ((~0UL) << (l)))
+#define GENMASK_ULL(h, l) (((~0ULL) >> (BITS_PER_LONG_LONG - (h) - 1)) & ((~0ULL) << (l)))
+#define BITS_PER_BYTE 8
+#define BITS_PER_TYPE(t) (sizeof(t) * BITS_PER_BYTE)
+
+#define hweight8(x) bitcount((uint8_t)(x))
+#define hweight16(x) bitcount16(x)
+#define hweight32(x) bitcount32(x)
+#define hweight64(x) bitcount64(x)
+#define hweight_long(x) bitcountl(x)
+
+static inline int
+__ffs(int mask)
+{
+ return (ffs(mask) - 1);
+}
+
+static inline int
+__fls(int mask)
+{
+ return (fls(mask) - 1);
+}
+
+static inline int
+__ffsl(long mask)
+{
+ return (ffsl(mask) - 1);
+}
+
+static inline int
+__flsl(long mask)
+{
+ return (flsl(mask) - 1);
+}
+
+static inline int
+fls64(uint64_t mask)
+{
+ return (flsll(mask));
+}
+
+static inline uint32_t
+ror32(uint32_t word, unsigned int shift)
+{
+ return ((word >> shift) | (word << (32 - shift)));
+}
+
+#define ffz(mask) __ffs(~(mask))
+
+static inline int get_count_order(unsigned int count)
+{
+ int order;
+
+ order = fls(count) - 1;
+ if (count & (count - 1))
+ order++;
+ return order;
+}
+
+static inline unsigned long
+find_first_bit(const unsigned long *addr, unsigned long size)
+{
+ long mask;
+ int bit;
+
+ for (bit = 0; size >= BITS_PER_LONG;
+ size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) {
+ if (*addr == 0)
+ continue;
+ return (bit + __ffsl(*addr));
+ }
+ if (size) {
+ mask = (*addr) & BITMAP_LAST_WORD_MASK(size);
+ if (mask)
+ bit += __ffsl(mask);
+ else
+ bit += size;
+ }
+ return (bit);
+}
+
+static inline unsigned long
+find_first_zero_bit(const unsigned long *addr, unsigned long size)
+{
+ long mask;
+ int bit;
+
+ for (bit = 0; size >= BITS_PER_LONG;
+ size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) {
+ if (~(*addr) == 0)
+ continue;
+ return (bit + __ffsl(~(*addr)));
+ }
+ if (size) {
+ mask = ~(*addr) & BITMAP_LAST_WORD_MASK(size);
+ if (mask)
+ bit += __ffsl(mask);
+ else
+ bit += size;
+ }
+ return (bit);
+}
+
+static inline unsigned long
+find_last_bit(const unsigned long *addr, unsigned long size)
+{
+ long mask;
+ int offs;
+ int bit;
+ int pos;
+
+ pos = size / BITS_PER_LONG;
+ offs = size % BITS_PER_LONG;
+ bit = BITS_PER_LONG * pos;
+ addr += pos;
+ if (offs) {
+ mask = (*addr) & BITMAP_LAST_WORD_MASK(offs);
+ if (mask)
+ return (bit + __flsl(mask));
+ }
+ while (pos--) {
+ addr--;
+ bit -= BITS_PER_LONG;
+ if (*addr)
+ return (bit + __flsl(*addr));
+ }
+ return (size);
+}
+
+static inline unsigned long
+find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset)
+{
+ long mask;
+ int offs;
+ int bit;
+ int pos;
+
+ if (offset >= size)
+ return (size);
+ pos = offset / BITS_PER_LONG;
+ offs = offset % BITS_PER_LONG;
+ bit = BITS_PER_LONG * pos;
+ addr += pos;
+ if (offs) {
+ mask = (*addr) & ~BITMAP_LAST_WORD_MASK(offs);
+ if (mask)
+ return (bit + __ffsl(mask));
+ if (size - bit <= BITS_PER_LONG)
+ return (size);
+ bit += BITS_PER_LONG;
+ addr++;
+ }
+ for (size -= bit; size >= BITS_PER_LONG;
+ size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) {
+ if (*addr == 0)
+ continue;
+ return (bit + __ffsl(*addr));
+ }
+ if (size) {
+ mask = (*addr) & BITMAP_LAST_WORD_MASK(size);
+ if (mask)
+ bit += __ffsl(mask);
+ else
+ bit += size;
+ }
+ return (bit);
+}
+
+static inline unsigned long
+find_next_zero_bit(const unsigned long *addr, unsigned long size,
+ unsigned long offset)
+{
+ long mask;
+ int offs;
+ int bit;
+ int pos;
+
+ if (offset >= size)
+ return (size);
+ pos = offset / BITS_PER_LONG;
+ offs = offset % BITS_PER_LONG;
+ bit = BITS_PER_LONG * pos;
+ addr += pos;
+ if (offs) {
+ mask = ~(*addr) & ~BITMAP_LAST_WORD_MASK(offs);
+ if (mask)
+ return (bit + __ffsl(mask));
+ if (size - bit <= BITS_PER_LONG)
+ return (size);
+ bit += BITS_PER_LONG;
+ addr++;
+ }
+ for (size -= bit; size >= BITS_PER_LONG;
+ size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) {
+ if (~(*addr) == 0)
+ continue;
+ return (bit + __ffsl(~(*addr)));
+ }
+ if (size) {
+ mask = ~(*addr) & BITMAP_LAST_WORD_MASK(size);
+ if (mask)
+ bit += __ffsl(mask);
+ else
+ bit += size;
+ }
+ return (bit);
+}
+
+#define __set_bit(i, a) \
+ atomic_set_long(&((volatile unsigned long *)(a))[BIT_WORD(i)], BIT_MASK(i))
+
+#define set_bit(i, a) \
+ atomic_set_long(&((volatile unsigned long *)(a))[BIT_WORD(i)], BIT_MASK(i))
+
+#define __clear_bit(i, a) \
+ atomic_clear_long(&((volatile unsigned long *)(a))[BIT_WORD(i)], BIT_MASK(i))
+
+#define clear_bit(i, a) \
+ atomic_clear_long(&((volatile unsigned long *)(a))[BIT_WORD(i)], BIT_MASK(i))
+
+#define clear_bit_unlock(i, a) \
+ atomic_clear_rel_long(&((volatile unsigned long *)(a))[BIT_WORD(i)], BIT_MASK(i))
+
+#define test_bit(i, a) \
+ !!(READ_ONCE(((volatile const unsigned long *)(a))[BIT_WORD(i)]) & BIT_MASK(i))
+
+static inline int
+test_and_clear_bit(long bit, volatile unsigned long *var)
+{
+ long val;
+
+ var += BIT_WORD(bit);
+ bit %= BITS_PER_LONG;
+ bit = (1UL << bit);
+
+ val = *var;
+ while (!atomic_fcmpset_long(var, &val, val & ~bit))
+ ;
+ return !!(val & bit);
+}
+
+static inline int
+__test_and_clear_bit(long bit, volatile unsigned long *var)
+{
+ long val;
+
+ var += BIT_WORD(bit);
+ bit %= BITS_PER_LONG;
+ bit = (1UL << bit);
+
+ val = *var;
+ *var &= ~bit;
+
+ return !!(val & bit);
+}
+
+static inline int
+test_and_set_bit(long bit, volatile unsigned long *var)
+{
+ long val;
+
+ var += BIT_WORD(bit);
+ bit %= BITS_PER_LONG;
+ bit = (1UL << bit);
+
+ val = *var;
+ while (!atomic_fcmpset_long(var, &val, val | bit))
+ ;
+ return !!(val & bit);
+}
+
+static inline int
+__test_and_set_bit(long bit, volatile unsigned long *var)
+{
+ long val;
+
+ var += BIT_WORD(bit);
+ bit %= BITS_PER_LONG;
+ bit = (1UL << bit);
+
+ val = *var;
+ *var |= bit;
+
+ return !!(val & bit);
+}
+
+enum {
+ REG_OP_ISFREE,
+ REG_OP_ALLOC,
+ REG_OP_RELEASE,
+};
+
+static inline int
+linux_reg_op(unsigned long *bitmap, int pos, int order, int reg_op)
+{
+ int nbits_reg;
+ int index;
+ int offset;
+ int nlongs_reg;
+ int nbitsinlong;
+ unsigned long mask;
+ int i;
+ int ret = 0;
+
+ nbits_reg = 1 << order;
+ index = pos / BITS_PER_LONG;
+ offset = pos - (index * BITS_PER_LONG);
+ nlongs_reg = BITS_TO_LONGS(nbits_reg);
+ nbitsinlong = MIN(nbits_reg, BITS_PER_LONG);
+
+ mask = (1UL << (nbitsinlong - 1));
+ mask += mask - 1;
+ mask <<= offset;
+
+ switch (reg_op) {
+ case REG_OP_ISFREE:
+ for (i = 0; i < nlongs_reg; i++) {
+ if (bitmap[index + i] & mask)
+ goto done;
+ }
+ ret = 1;
+ break;
+
+ case REG_OP_ALLOC:
+ for (i = 0; i < nlongs_reg; i++)
+ bitmap[index + i] |= mask;
+ break;
+
+ case REG_OP_RELEASE:
+ for (i = 0; i < nlongs_reg; i++)
+ bitmap[index + i] &= ~mask;
+ break;
+ }
+done:
+ return ret;
+}
+
+#define for_each_set_bit(bit, addr, size) \
+ for ((bit) = find_first_bit((addr), (size)); \
+ (bit) < (size); \
+ (bit) = find_next_bit((addr), (size), (bit) + 1))
+
+#define for_each_clear_bit(bit, addr, size) \
+ for ((bit) = find_first_zero_bit((addr), (size)); \
+ (bit) < (size); \
+ (bit) = find_next_zero_bit((addr), (size), (bit) + 1))
+
+static inline uint64_t
+sign_extend64(uint64_t value, int index)
+{
+ uint8_t shift = 63 - index;
+
+ return ((int64_t)(value << shift) >> shift);
+}
+
+#endif /* _LINUX_BITOPS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/bottom_half.h b/sys/compat/linuxkpi/common/include/linux/bottom_half.h
new file mode 100644
index 000000000000..9f8dc02f2798
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/bottom_half.h
@@ -0,0 +1,34 @@
+/*-
+ * Copyright (c) 2017 Hans Petter Selasky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_BOTTOM_HALF_H_
+#define _LINUX_BOTTOM_HALF_H_
+
+extern void local_bh_enable(void);
+extern void local_bh_disable(void);
+
+#endif /* _LINUX_BOTTOM_HALF_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/cache.h b/sys/compat/linuxkpi/common/include/linux/cache.h
new file mode 100644
index 000000000000..a269e55eb90b
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/cache.h
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_CACHE_H_
+#define _LINUX_CACHE_H_
+
+#define cache_line_size() CACHE_LINE_SIZE
+#define L1_CACHE_BYTES CACHE_LINE_SIZE
+
+#endif /* _LINUX_CACHE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/cdev.h b/sys/compat/linuxkpi/common/include/linux/cdev.h
new file mode 100644
index 000000000000..2a472da91866
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/cdev.h
@@ -0,0 +1,152 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_CDEV_H_
+#define _LINUX_CDEV_H_
+
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/kdev_t.h>
+#include <linux/list.h>
+
+#include <asm/atomic-long.h>
+
+struct file_operations;
+struct inode;
+struct module;
+
+extern struct cdevsw linuxcdevsw;
+extern const struct kobj_type linux_cdev_ktype;
+extern const struct kobj_type linux_cdev_static_ktype;
+
+struct linux_cdev {
+ struct kobject kobj;
+ struct module *owner;
+ struct cdev *cdev;
+ dev_t dev;
+ const struct file_operations *ops;
+ u_int refs;
+ u_int siref;
+};
+
+static inline void
+cdev_init(struct linux_cdev *cdev, const struct file_operations *ops)
+{
+
+ kobject_init(&cdev->kobj, &linux_cdev_static_ktype);
+ cdev->ops = ops;
+ cdev->refs = 1;
+}
+
+static inline struct linux_cdev *
+cdev_alloc(void)
+{
+ struct linux_cdev *cdev;
+
+ cdev = kzalloc(sizeof(struct linux_cdev), M_WAITOK);
+ kobject_init(&cdev->kobj, &linux_cdev_ktype);
+ cdev->refs = 1;
+ return (cdev);
+}
+
+static inline void
+cdev_put(struct linux_cdev *p)
+{
+ kobject_put(&p->kobj);
+}
+
+static inline int
+cdev_add(struct linux_cdev *cdev, dev_t dev, unsigned count)
+{
+ struct make_dev_args args;
+ int error;
+
+ if (count != 1)
+ return (-EINVAL);
+
+ cdev->dev = dev;
+
+ /* Setup arguments for make_dev_s() */
+ make_dev_args_init(&args);
+ args.mda_devsw = &linuxcdevsw;
+ args.mda_uid = 0;
+ args.mda_gid = 0;
+ args.mda_mode = 0700;
+ args.mda_si_drv1 = cdev;
+
+ error = make_dev_s(&args, &cdev->cdev, "%s",
+ kobject_name(&cdev->kobj));
+ if (error)
+ return (-error);
+
+ kobject_get(cdev->kobj.parent);
+ return (0);
+}
+
+static inline int
+cdev_add_ext(struct linux_cdev *cdev, dev_t dev, uid_t uid, gid_t gid, int mode)
+{
+ struct make_dev_args args;
+ int error;
+
+ cdev->dev = dev;
+
+ /* Setup arguments for make_dev_s() */
+ make_dev_args_init(&args);
+ args.mda_devsw = &linuxcdevsw;
+ args.mda_uid = uid;
+ args.mda_gid = gid;
+ args.mda_mode = mode;
+ args.mda_si_drv1 = cdev;
+
+ error = make_dev_s(&args, &cdev->cdev, "%s/%d",
+ kobject_name(&cdev->kobj), MINOR(dev));
+ if (error)
+ return (-error);
+
+ kobject_get(cdev->kobj.parent);
+ return (0);
+}
+
+void linux_destroy_dev(struct linux_cdev *);
+
+static inline void
+cdev_del(struct linux_cdev *cdev)
+{
+
+ linux_destroy_dev(cdev);
+ kobject_put(&cdev->kobj);
+}
+
+struct linux_cdev *linux_find_cdev(const char *name, unsigned major, unsigned minor);
+
+#define cdev linux_cdev
+
+#endif /* _LINUX_CDEV_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/clocksource.h b/sys/compat/linuxkpi/common/include/linux/clocksource.h
new file mode 100644
index 000000000000..f775aa6bb329
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/clocksource.h
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_CLOCKSOURCE_H
+#define _LINUX_CLOCKSOURCE_H
+
+#include <asm/types.h>
+
+#define CLOCKSOURCE_MASK(x) ((u64)(-1ULL >> ((-(x)) & 63)))
+
+#endif /* _LINUX_CLOCKSOURCE_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/compat.h b/sys/compat/linuxkpi/common/include/linux/compat.h
new file mode 100644
index 000000000000..03b7dc60b7a1
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/compat.h
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_COMPAT_H_
+#define _LINUX_COMPAT_H_
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+
+struct thread;
+struct task_struct;
+
+extern int linux_alloc_current(struct thread *, int flags);
+extern void linux_free_current(struct task_struct *);
+
+static inline void
+linux_set_current(struct thread *td)
+{
+ if (__predict_false(td->td_lkpi_task == NULL))
+ lkpi_alloc_current(td, M_WAITOK);
+}
+
+static inline int
+linux_set_current_flags(struct thread *td, int flags)
+{
+ if (__predict_false(td->td_lkpi_task == NULL))
+ return (lkpi_alloc_current(td, flags));
+ return (0);
+}
+
+#endif /* _LINUX_COMPAT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/compiler.h b/sys/compat/linuxkpi/common/include/linux/compiler.h
new file mode 100644
index 000000000000..1177674aa68f
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/compiler.h
@@ -0,0 +1,117 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * Copyright (c) 2015 François Tigeot
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_COMPILER_H_
+#define _LINUX_COMPILER_H_
+
+#include <sys/cdefs.h>
+
+#define __user
+#define __kernel
+#define __safe
+#define __force
+#define __nocast
+#define __iomem
+#define __chk_user_ptr(x) ((void)0)
+#define __chk_io_ptr(x) ((void)0)
+#define __builtin_warning(x, y...) (1)
+#define __acquires(x)
+#define __releases(x)
+#define __acquire(x) do { } while (0)
+#define __release(x) do { } while (0)
+#define __cond_lock(x,c) (c)
+#define __bitwise
+#define __devinitdata
+#define __deprecated
+#define __init
+#define __initconst
+#define __devinit
+#define __devexit
+#define __exit
+#define __rcu
+#define __percpu
+#define __weak __weak_symbol
+#define __malloc
+#define ___stringify(...) #__VA_ARGS__
+#define __stringify(...) ___stringify(__VA_ARGS__)
+#define __attribute_const__ __attribute__((__const__))
+#undef __always_inline
+#define __always_inline inline
+#define noinline __noinline
+#define ____cacheline_aligned __aligned(CACHE_LINE_SIZE)
+
+#define likely(x) __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#define typeof(x) __typeof(x)
+
+#define uninitialized_var(x) x = x
+#define __maybe_unused __unused
+#define __always_unused __unused
+#define __must_check __result_use_check
+
+#define __printf(a,b) __printflike(a,b)
+
+#define barrier() __asm__ __volatile__("": : :"memory")
+
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 50000
+/* Moved from drm_os_freebsd.h */
+#define lower_32_bits(n) ((u32)(n))
+#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16))
+#endif
+
+#define ___PASTE(a,b) a##b
+#define __PASTE(a,b) ___PASTE(a,b)
+
+#define ACCESS_ONCE(x) (*(volatile __typeof(x) *)&(x))
+
+#define WRITE_ONCE(x,v) do { \
+ barrier(); \
+ ACCESS_ONCE(x) = (v); \
+ barrier(); \
+} while (0)
+
+#define READ_ONCE(x) ({ \
+ __typeof(x) __var = ({ \
+ barrier(); \
+ ACCESS_ONCE(x); \
+ }); \
+ barrier(); \
+ __var; \
+})
+
+#define lockless_dereference(p) READ_ONCE(p)
+
+#define _AT(T,X) ((T)(X))
+
+#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
+#define __must_be_array(a) __same_type(a, &(a)[0])
+
+#endif /* _LINUX_COMPILER_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/completion.h b/sys/compat/linuxkpi/common/include/linux/completion.h
new file mode 100644
index 000000000000..09d499309e5a
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/completion.h
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_COMPLETION_H_
+#define _LINUX_COMPLETION_H_
+
+#include <linux/errno.h>
+
+struct completion {
+ unsigned int done;
+};
+
+#define INIT_COMPLETION(c) \
+ ((c).done = 0)
+#define init_completion(c) \
+ do { (c)->done = 0; } while (0)
+#define reinit_completion(c) \
+ do { (c)->done = 0; } while (0)
+#define complete(c) \
+ linux_complete_common((c), 0)
+#define complete_all(c) \
+ linux_complete_common((c), 1)
+#define wait_for_completion(c) \
+ linux_wait_for_common((c), 0)
+#define wait_for_completion_interruptible(c) \
+ linux_wait_for_common((c), 1)
+#define wait_for_completion_timeout(c, timeout) \
+ linux_wait_for_timeout_common((c), (timeout), 0)
+#define wait_for_completion_interruptible_timeout(c, timeout) \
+ linux_wait_for_timeout_common((c), (timeout), 1)
+#define try_wait_for_completion(c) \
+ linux_try_wait_for_completion(c)
+#define completion_done(c) \
+ linux_completion_done(c)
+
+extern void linux_complete_common(struct completion *, int);
+extern int linux_wait_for_common(struct completion *, int);
+extern int linux_wait_for_timeout_common(struct completion *, int, int);
+extern int linux_try_wait_for_completion(struct completion *);
+extern int linux_completion_done(struct completion *);
+
+#endif /* _LINUX_COMPLETION_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/dcache.h b/sys/compat/linuxkpi/common/include/linux/dcache.h
new file mode 100644
index 000000000000..1bafa3dbd1fe
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/dcache.h
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2017 Limelight Networks, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __LINUX_DCACHE_H
+#define __LINUX_DCACHE_H
+
+struct vnode;
+struct pfs_node;
+
+struct dentry {
+ struct vnode *d_inode;
+ struct pfs_node *d_pfs_node; /* FreeBSD specific field */
+};
+
+static inline struct vnode *
+d_inode(const struct dentry *dentry)
+{
+ return (dentry->d_inode);
+}
+
+#endif /* __LINUX_DCACHE_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/debugfs.h b/sys/compat/linuxkpi/common/include/linux/debugfs.h
new file mode 100644
index 000000000000..406016d7e2c8
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/debugfs.h
@@ -0,0 +1,51 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2016-2018, Matthew Macy <mmacy@freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_DEBUGFS_H_
+#define _LINUX_DEBUGFS_H_
+
+#include <linux/fs.h>
+#include <linux/seq_file.h>
+
+#include <linux/types.h>
+
+void debugfs_remove(struct dentry *dentry);
+
+struct dentry *debugfs_create_file(const char *name, umode_t mode,
+ struct dentry *parent, void *data,
+ const struct file_operations *fops);
+
+struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
+
+struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent,
+ const char *dest);
+
+void debugfs_remove_recursive(struct dentry *dentry);
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/delay.h b/sys/compat/linuxkpi/common/include/linux/delay.h
new file mode 100644
index 000000000000..860d36368a8e
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/delay.h
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2015 Mellanox Technologies, Ltd.
+ * Copyright (c) 2014 François Tigeot
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_DELAY_H_
+#define _LINUX_DELAY_H_
+
+#include <linux/jiffies.h>
+#include <sys/systm.h>
+
+static inline void
+linux_msleep(unsigned int ms)
+{
+ /* guard against invalid values */
+ if (ms == 0)
+ ms = 1;
+ pause_sbt("lnxsleep", mstosbt(ms), 0, C_HARDCLOCK);
+}
+
+#undef msleep
+#define msleep(ms) linux_msleep(ms)
+
+#undef msleep_interruptible
+#define msleep_interruptible(ms) linux_msleep_interruptible(ms)
+
+#define udelay(t) DELAY(t)
+
+static inline void
+mdelay(unsigned long msecs)
+{
+ while (msecs--)
+ DELAY(1000);
+}
+
+static inline void
+ndelay(unsigned long x)
+{
+ DELAY(howmany(x, 1000));
+}
+
+static inline void
+usleep_range(unsigned long min, unsigned long max)
+{
+ DELAY(min);
+}
+
+extern unsigned int linux_msleep_interruptible(unsigned int ms);
+
+#endif /* _LINUX_DELAY_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/device.h b/sys/compat/linuxkpi/common/include/linux/device.h
new file mode 100644
index 000000000000..2ffe70f45c6e
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/device.h
@@ -0,0 +1,608 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_DEVICE_H_
+#define _LINUX_DEVICE_H_
+
+#include <linux/err.h>
+#include <linux/types.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/kdev_t.h>
+#include <linux/backlight.h>
+#include <asm/atomic.h>
+
+#include <sys/bus.h>
+#include <sys/backlight.h>
+
+struct device;
+struct fwnode_handle;
+
+struct class {
+ const char *name;
+ struct module *owner;
+ struct kobject kobj;
+ devclass_t bsdclass;
+ const struct dev_pm_ops *pm;
+ const struct attribute_group **dev_groups;
+ void (*class_release)(struct class *class);
+ void (*dev_release)(struct device *dev);
+ char * (*devnode)(struct device *dev, umode_t *mode);
+};
+
+struct dev_pm_ops {
+ int (*prepare)(struct device *dev);
+ int (*suspend)(struct device *dev);
+ int (*suspend_late)(struct device *dev);
+ int (*resume)(struct device *dev);
+ int (*resume_early)(struct device *dev);
+ int (*freeze)(struct device *dev);
+ int (*freeze_late)(struct device *dev);
+ int (*thaw)(struct device *dev);
+ int (*thaw_early)(struct device *dev);
+ int (*poweroff)(struct device *dev);
+ int (*poweroff_late)(struct device *dev);
+ int (*restore)(struct device *dev);
+ int (*restore_early)(struct device *dev);
+ int (*runtime_suspend)(struct device *dev);
+ int (*runtime_resume)(struct device *dev);
+ int (*runtime_idle)(struct device *dev);
+};
+
+struct device_driver {
+ const char *name;
+ const struct dev_pm_ops *pm;
+};
+
+struct device_type {
+ const char *name;
+};
+
+struct device {
+ struct device *parent;
+ struct list_head irqents;
+ device_t bsddev;
+ /*
+ * The following flag is used to determine if the LinuxKPI is
+ * responsible for detaching the BSD device or not. If the
+ * LinuxKPI got the BSD device using devclass_get_device(), it
+ * must not try to detach or delete it, because it's already
+ * done somewhere else.
+ */
+ bool bsddev_attached_here;
+ struct device_driver *driver;
+ struct device_type *type;
+ dev_t devt;
+ struct class *class;
+ void (*release)(struct device *dev);
+ struct kobject kobj;
+ void *dma_priv;
+ void *driver_data;
+ unsigned int irq;
+#define LINUX_IRQ_INVALID 65535
+ unsigned int irq_start;
+ unsigned int irq_end;
+ const struct attribute_group **groups;
+ struct fwnode_handle *fwnode;
+ struct cdev *backlight_dev;
+ struct backlight_device *bd;
+
+ spinlock_t devres_lock;
+ struct list_head devres_head;
+};
+
+extern struct device linux_root_device;
+extern struct kobject linux_class_root;
+extern const struct kobj_type linux_dev_ktype;
+extern const struct kobj_type linux_class_ktype;
+
+struct class_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct class *, struct class_attribute *, char *);
+ ssize_t (*store)(struct class *, struct class_attribute *, const char *, size_t);
+ const void *(*namespace)(struct class *, const struct class_attribute *);
+};
+
+#define CLASS_ATTR(_name, _mode, _show, _store) \
+ struct class_attribute class_attr_##_name = \
+ { { #_name, NULL, _mode }, _show, _store }
+
+struct device_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct device *,
+ struct device_attribute *, char *);
+ ssize_t (*store)(struct device *,
+ struct device_attribute *, const char *,
+ size_t);
+};
+
+#define DEVICE_ATTR(_name, _mode, _show, _store) \
+ struct device_attribute dev_attr_##_name = \
+ __ATTR(_name, _mode, _show, _store)
+#define DEVICE_ATTR_RO(_name) \
+ struct device_attribute dev_attr_##_name = __ATTR_RO(_name)
+#define DEVICE_ATTR_WO(_name) \
+ struct device_attribute dev_attr_##_name = __ATTR_WO(_name)
+#define DEVICE_ATTR_RW(_name) \
+ struct device_attribute dev_attr_##_name = __ATTR_RW(_name)
+
+/* Simple class attribute that is just a static string */
+struct class_attribute_string {
+ struct class_attribute attr;
+ char *str;
+};
+
+static inline ssize_t
+show_class_attr_string(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ struct class_attribute_string *cs;
+ cs = container_of(attr, struct class_attribute_string, attr);
+ return snprintf(buf, PAGE_SIZE, "%s\n", cs->str);
+}
+
+/* Currently read-only only */
+#define _CLASS_ATTR_STRING(_name, _mode, _str) \
+ { __ATTR(_name, _mode, show_class_attr_string, NULL), _str }
+#define CLASS_ATTR_STRING(_name, _mode, _str) \
+ struct class_attribute_string class_attr_##_name = \
+ _CLASS_ATTR_STRING(_name, _mode, _str)
+
+#define dev_err(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
+#define dev_warn(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
+#define dev_info(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
+#define dev_notice(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
+#define dev_dbg(dev, fmt, ...) do { } while (0)
+#define dev_printk(lvl, dev, fmt, ...) \
+ device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
+
+#define dev_err_once(dev, ...) do { \
+ static bool __dev_err_once; \
+ if (!__dev_err_once) { \
+ __dev_err_once = 1; \
+ dev_err(dev, __VA_ARGS__); \
+ } \
+} while (0)
+
+#define dev_err_ratelimited(dev, ...) do { \
+ static linux_ratelimit_t __ratelimited; \
+ if (linux_ratelimited(&__ratelimited)) \
+ dev_err(dev, __VA_ARGS__); \
+} while (0)
+
+#define dev_warn_ratelimited(dev, ...) do { \
+ static linux_ratelimit_t __ratelimited; \
+ if (linux_ratelimited(&__ratelimited)) \
+ dev_warn(dev, __VA_ARGS__); \
+} while (0)
+
+static inline void *
+dev_get_drvdata(const struct device *dev)
+{
+
+ return dev->driver_data;
+}
+
+static inline void
+dev_set_drvdata(struct device *dev, void *data)
+{
+
+ dev->driver_data = data;
+}
+
+static inline struct device *
+get_device(struct device *dev)
+{
+
+ if (dev)
+ kobject_get(&dev->kobj);
+
+ return (dev);
+}
+
+static inline char *
+dev_name(const struct device *dev)
+{
+
+ return kobject_name(&dev->kobj);
+}
+
+#define dev_set_name(_dev, _fmt, ...) \
+ kobject_set_name(&(_dev)->kobj, (_fmt), ##__VA_ARGS__)
+
+static inline void
+put_device(struct device *dev)
+{
+
+ if (dev)
+ kobject_put(&dev->kobj);
+}
+
+static inline int
+class_register(struct class *class)
+{
+
+ class->bsdclass = devclass_create(class->name);
+ kobject_init(&class->kobj, &linux_class_ktype);
+ kobject_set_name(&class->kobj, class->name);
+ kobject_add(&class->kobj, &linux_class_root, class->name);
+
+ return (0);
+}
+
+static inline void
+class_unregister(struct class *class)
+{
+
+ kobject_put(&class->kobj);
+}
+
+static inline struct device *kobj_to_dev(struct kobject *kobj)
+{
+ return container_of(kobj, struct device, kobj);
+}
+
+/*
+ * Devices are registered and created for exporting to sysfs. Create
+ * implies register and register assumes the device fields have been
+ * setup appropriately before being called.
+ */
+static inline void
+device_initialize(struct device *dev)
+{
+ device_t bsddev = NULL;
+ int unit = -1;
+
+ if (dev->devt) {
+ unit = MINOR(dev->devt);
+ bsddev = devclass_get_device(dev->class->bsdclass, unit);
+ dev->bsddev_attached_here = false;
+ } else if (dev->parent == NULL) {
+ bsddev = devclass_get_device(dev->class->bsdclass, 0);
+ dev->bsddev_attached_here = false;
+ } else {
+ dev->bsddev_attached_here = true;
+ }
+
+ if (bsddev == NULL && dev->parent != NULL) {
+ bsddev = device_add_child(dev->parent->bsddev,
+ dev->class->kobj.name, unit);
+ }
+
+ if (bsddev != NULL)
+ device_set_softc(bsddev, dev);
+
+ dev->bsddev = bsddev;
+ MPASS(dev->bsddev != NULL);
+ kobject_init(&dev->kobj, &linux_dev_ktype);
+
+ spin_lock_init(&dev->devres_lock);
+ INIT_LIST_HEAD(&dev->devres_head);
+}
+
+static inline int
+device_add(struct device *dev)
+{
+ if (dev->bsddev != NULL) {
+ if (dev->devt == 0)
+ dev->devt = makedev(0, device_get_unit(dev->bsddev));
+ }
+ kobject_add(&dev->kobj, &dev->class->kobj, dev_name(dev));
+
+ if (dev->groups)
+ return (sysfs_create_groups(&dev->kobj, dev->groups));
+
+ return (0);
+}
+
+static inline void
+device_create_release(struct device *dev)
+{
+ kfree(dev);
+}
+
+static inline struct device *
+device_create_groups_vargs(struct class *class, struct device *parent,
+ dev_t devt, void *drvdata, const struct attribute_group **groups,
+ const char *fmt, va_list args)
+{
+ struct device *dev = NULL;
+ int retval = -ENODEV;
+
+ if (class == NULL || IS_ERR(class))
+ goto error;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ dev->devt = devt;
+ dev->class = class;
+ dev->parent = parent;
+ dev->groups = groups;
+ dev->release = device_create_release;
+ /* device_initialize() needs the class and parent to be set */
+ device_initialize(dev);
+ dev_set_drvdata(dev, drvdata);
+
+ retval = kobject_set_name_vargs(&dev->kobj, fmt, args);
+ if (retval)
+ goto error;
+
+ retval = device_add(dev);
+ if (retval)
+ goto error;
+
+ return dev;
+
+error:
+ put_device(dev);
+ return ERR_PTR(retval);
+}
+
+static inline struct device *
+device_create_with_groups(struct class *class,
+ struct device *parent, dev_t devt, void *drvdata,
+ const struct attribute_group **groups, const char *fmt, ...)
+{
+ va_list vargs;
+ struct device *dev;
+
+ va_start(vargs, fmt);
+ dev = device_create_groups_vargs(class, parent, devt, drvdata,
+ groups, fmt, vargs);
+ va_end(vargs);
+ return dev;
+}
+
+static inline bool
+device_is_registered(struct device *dev)
+{
+
+ return (dev->bsddev != NULL);
+}
+
+static inline int
+device_register(struct device *dev)
+{
+ device_t bsddev = NULL;
+ int unit = -1;
+
+ if (device_is_registered(dev))
+ goto done;
+
+ if (dev->devt) {
+ unit = MINOR(dev->devt);
+ bsddev = devclass_get_device(dev->class->bsdclass, unit);
+ dev->bsddev_attached_here = false;
+ } else if (dev->parent == NULL) {
+ bsddev = devclass_get_device(dev->class->bsdclass, 0);
+ dev->bsddev_attached_here = false;
+ } else {
+ dev->bsddev_attached_here = true;
+ }
+ if (bsddev == NULL && dev->parent != NULL) {
+ bsddev = device_add_child(dev->parent->bsddev,
+ dev->class->kobj.name, unit);
+ }
+ if (bsddev != NULL) {
+ if (dev->devt == 0)
+ dev->devt = makedev(0, device_get_unit(bsddev));
+ device_set_softc(bsddev, dev);
+ }
+ dev->bsddev = bsddev;
+done:
+ kobject_init(&dev->kobj, &linux_dev_ktype);
+ kobject_add(&dev->kobj, &dev->class->kobj, dev_name(dev));
+
+ sysfs_create_groups(&dev->kobj, dev->class->dev_groups);
+
+ return (0);
+}
+
+static inline void
+device_unregister(struct device *dev)
+{
+ device_t bsddev;
+
+ sysfs_remove_groups(&dev->kobj, dev->class->dev_groups);
+
+ bsddev = dev->bsddev;
+ dev->bsddev = NULL;
+
+ if (bsddev != NULL && dev->bsddev_attached_here) {
+ mtx_lock(&Giant);
+ device_delete_child(device_get_parent(bsddev), bsddev);
+ mtx_unlock(&Giant);
+ }
+ put_device(dev);
+}
+
+static inline void
+device_del(struct device *dev)
+{
+ device_t bsddev;
+
+ bsddev = dev->bsddev;
+ dev->bsddev = NULL;
+
+ if (bsddev != NULL && dev->bsddev_attached_here) {
+ mtx_lock(&Giant);
+ device_delete_child(device_get_parent(bsddev), bsddev);
+ mtx_unlock(&Giant);
+ }
+}
+
+struct device *device_create(struct class *class, struct device *parent,
+ dev_t devt, void *drvdata, const char *fmt, ...);
+
+static inline void
+device_destroy(struct class *class, dev_t devt)
+{
+ device_t bsddev;
+ int unit;
+
+ unit = MINOR(devt);
+ bsddev = devclass_get_device(class->bsdclass, unit);
+ if (bsddev != NULL)
+ device_unregister(device_get_softc(bsddev));
+}
+
+#define dev_pm_set_driver_flags(dev, flags) do { \
+} while (0)
+
+static inline void
+linux_class_kfree(struct class *class)
+{
+
+ kfree(class);
+}
+
+static inline struct class *
+class_create(struct module *owner, const char *name)
+{
+ struct class *class;
+ int error;
+
+ class = kzalloc(sizeof(*class), M_WAITOK);
+ class->owner = owner;
+ class->name = name;
+ class->class_release = linux_class_kfree;
+ error = class_register(class);
+ if (error) {
+ kfree(class);
+ return (NULL);
+ }
+
+ return (class);
+}
+
+static inline void
+class_destroy(struct class *class)
+{
+
+ if (class == NULL)
+ return;
+ class_unregister(class);
+}
+
+static inline int
+device_create_file(struct device *dev, const struct device_attribute *attr)
+{
+
+ if (dev)
+ return sysfs_create_file(&dev->kobj, &attr->attr);
+ return -EINVAL;
+}
+
+static inline void
+device_remove_file(struct device *dev, const struct device_attribute *attr)
+{
+
+ if (dev)
+ sysfs_remove_file(&dev->kobj, &attr->attr);
+}
+
+static inline int
+class_create_file(struct class *class, const struct class_attribute *attr)
+{
+
+ if (class)
+ return sysfs_create_file(&class->kobj, &attr->attr);
+ return -EINVAL;
+}
+
+static inline void
+class_remove_file(struct class *class, const struct class_attribute *attr)
+{
+
+ if (class)
+ sysfs_remove_file(&class->kobj, &attr->attr);
+}
+
+static inline int
+dev_to_node(struct device *dev)
+{
+ return -1;
+}
+
+char *kvasprintf(gfp_t, const char *, va_list);
+char *kasprintf(gfp_t, const char *, ...);
+char *lkpi_devm_kasprintf(struct device *, gfp_t, const char *, ...);
+
+#define devm_kasprintf(_dev, _gfp, _fmt, ...) \
+ lkpi_devm_kasprintf(_dev, _gfp, _fmt, ##__VA_ARGS__)
+
+void *lkpi_devres_alloc(void(*release)(struct device *, void *), size_t, gfp_t);
+void lkpi_devres_add(struct device *, void *);
+void lkpi_devres_free(void *);
+void *lkpi_devres_find(struct device *, void(*release)(struct device *, void *),
+ int (*match)(struct device *, void *, void *), void *);
+int lkpi_devres_destroy(struct device *, void(*release)(struct device *, void *),
+ int (*match)(struct device *, void *, void *), void *);
+#define devres_alloc(_r, _s, _g) lkpi_devres_alloc(_r, _s, _g)
+#define devres_add(_d, _p) lkpi_devres_add(_d, _p)
+#define devres_free(_p) lkpi_devres_free(_p)
+#define devres_find(_d, _rfn, _mfn, _mp) \
+ lkpi_devres_find(_d, _rfn, _mfn, _mp)
+#define devres_destroy(_d, _rfn, _mfn, _mp) \
+ lkpi_devres_destroy(_d, _rfn, _mfn, _mp)
+
+/* LinuxKPI internal functions. */
+void lkpi_devres_release_free_list(struct device *);
+void lkpi_devres_unlink(struct device *, void *);
+void lkpi_devm_kmalloc_release(struct device *, void *);
+
+static __inline void *
+devm_kmalloc(struct device *dev, size_t size, gfp_t gfp)
+{
+ void *p;
+
+ p = lkpi_devres_alloc(lkpi_devm_kmalloc_release, size, gfp);
+ if (p != NULL)
+ lkpi_devres_add(dev, p);
+
+ return (p);
+}
+
+#define devm_kzalloc(_dev, _size, _gfp) \
+ devm_kmalloc((_dev), (_size), (_gfp) | __GFP_ZERO)
+
+#define devm_kcalloc(_dev, _sizen, _size, _gfp) \
+ devm_kmalloc((_dev), ((_sizen) * (_size)), (_gfp) | __GFP_ZERO)
+
+#endif /* _LINUX_DEVICE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/dma-attrs.h b/sys/compat/linuxkpi/common/include/linux/dma-attrs.h
new file mode 100644
index 000000000000..d424d16164a6
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/dma-attrs.h
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_DMA_ATTR_H_
+#define _LINUX_DMA_ATTR_H_
+
+#define DMA_ATTR_WRITE_BARRIER (1 << 0)
+#define DMA_ATTR_WEAK_ORDERING (1 << 1)
+#define DMA_ATTR_WRITE_COMBINE (1 << 2)
+#define DMA_ATTR_NON_CONSISTENT (1 << 3)
+#define DMA_ATTR_NO_KERNEL_MAPPING (1 << 4)
+#define DMA_ATTR_SKIP_CPU_SYNC (1 << 5)
+#define DMA_ATTR_FORCE_CONTIGUOUS (1 << 6)
+#define DMA_ATTR_ALLOC_SINGLE_PAGES (1 << 7)
+#define DMA_ATTR_NO_WARN (1 << 8)
+#define DMA_ATTR_PRIVILEGED (1 << 9)
+
+struct dma_attrs {
+ unsigned long flags;
+};
+#define DEFINE_DMA_ATTRS(x) struct dma_attrs x = { }
+
+static inline void
+init_dma_attrs(struct dma_attrs *attrs)
+{
+ attrs->flags = 0;
+}
+
+#endif /* _LINUX_DMA_ATTR_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/dma-mapping.h b/sys/compat/linuxkpi/common/include/linux/dma-mapping.h
new file mode 100644
index 000000000000..d074b563cd41
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/dma-mapping.h
@@ -0,0 +1,294 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_DMA_MAPPING_H_
+#define _LINUX_DMA_MAPPING_H_
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/dma-attrs.h>
+#include <linux/scatterlist.h>
+#include <linux/mm.h>
+#include <linux/page.h>
+#include <linux/sizes.h>
+
+#include <sys/systm.h>
+#include <sys/malloc.h>
+
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+#include <vm/pmap.h>
+
+#include <machine/bus.h>
+
+enum dma_data_direction {
+ DMA_BIDIRECTIONAL = 0,
+ DMA_TO_DEVICE = 1,
+ DMA_FROM_DEVICE = 2,
+ DMA_NONE = 3,
+};
+
+struct dma_map_ops {
+ void* (*alloc_coherent)(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp);
+ void (*free_coherent)(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle);
+ dma_addr_t (*map_page)(struct device *dev, struct page *page,
+ unsigned long offset, size_t size, enum dma_data_direction dir,
+ struct dma_attrs *attrs);
+ void (*unmap_page)(struct device *dev, dma_addr_t dma_handle,
+ size_t size, enum dma_data_direction dir, struct dma_attrs *attrs);
+ int (*map_sg)(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir, struct dma_attrs *attrs);
+ void (*unmap_sg)(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction dir, struct dma_attrs *attrs);
+ void (*sync_single_for_cpu)(struct device *dev, dma_addr_t dma_handle,
+ size_t size, enum dma_data_direction dir);
+ void (*sync_single_for_device)(struct device *dev,
+ dma_addr_t dma_handle, size_t size, enum dma_data_direction dir);
+ void (*sync_single_range_for_cpu)(struct device *dev,
+ dma_addr_t dma_handle, unsigned long offset, size_t size,
+ enum dma_data_direction dir);
+ void (*sync_single_range_for_device)(struct device *dev,
+ dma_addr_t dma_handle, unsigned long offset, size_t size,
+ enum dma_data_direction dir);
+ void (*sync_sg_for_cpu)(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir);
+ void (*sync_sg_for_device)(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir);
+ int (*mapping_error)(struct device *dev, dma_addr_t dma_addr);
+ int (*dma_supported)(struct device *dev, u64 mask);
+ int is_phys;
+};
+
+#define DMA_BIT_MASK(n) ((2ULL << ((n) - 1)) - 1ULL)
+
+int linux_dma_tag_init(struct device *dev, u64 mask);
+void *linux_dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag);
+dma_addr_t linux_dma_map_phys(struct device *dev, vm_paddr_t phys, size_t len);
+void linux_dma_unmap(struct device *dev, dma_addr_t dma_addr, size_t size);
+int linux_dma_map_sg_attrs(struct device *dev, struct scatterlist *sgl,
+ int nents, enum dma_data_direction dir, struct dma_attrs *attrs);
+void linux_dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir, struct dma_attrs *attrs);
+
+static inline int
+dma_supported(struct device *dev, u64 mask)
+{
+
+ /* XXX busdma takes care of this elsewhere. */
+ return (1);
+}
+
+static inline int
+dma_set_mask(struct device *dev, u64 dma_mask)
+{
+
+ if (!dev->dma_priv || !dma_supported(dev, dma_mask))
+ return -EIO;
+
+ return (linux_dma_tag_init(dev, dma_mask));
+}
+
+static inline int
+dma_set_coherent_mask(struct device *dev, u64 mask)
+{
+
+ if (!dma_supported(dev, mask))
+ return -EIO;
+ /* XXX Currently we don't support a separate coherent mask. */
+ return 0;
+}
+
+static inline int
+dma_set_mask_and_coherent(struct device *dev, u64 mask)
+{
+ int r;
+
+ r = dma_set_mask(dev, mask);
+ if (r == 0)
+ dma_set_coherent_mask(dev, mask);
+ return (r);
+}
+
+static inline void *
+dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
+ gfp_t flag)
+{
+ return (linux_dma_alloc_coherent(dev, size, dma_handle, flag));
+}
+
+static inline void *
+dma_zalloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
+ gfp_t flag)
+{
+
+ return (dma_alloc_coherent(dev, size, dma_handle, flag | __GFP_ZERO));
+}
+
+static inline void
+dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
+ dma_addr_t dma_addr)
+{
+
+ linux_dma_unmap(dev, dma_addr, size);
+ kmem_free((vm_offset_t)cpu_addr, size);
+}
+
+static inline dma_addr_t
+dma_map_single_attrs(struct device *dev, void *ptr, size_t size,
+ enum dma_data_direction dir, struct dma_attrs *attrs)
+{
+
+ return (linux_dma_map_phys(dev, vtophys(ptr), size));
+}
+
+static inline void
+dma_unmap_single_attrs(struct device *dev, dma_addr_t dma_addr, size_t size,
+ enum dma_data_direction dir, struct dma_attrs *attrs)
+{
+
+ linux_dma_unmap(dev, dma_addr, size);
+}
+
+static inline dma_addr_t
+dma_map_page_attrs(struct device *dev, struct page *page, size_t offset,
+ size_t size, enum dma_data_direction dir, unsigned long attrs)
+{
+
+ return (linux_dma_map_phys(dev, VM_PAGE_TO_PHYS(page) + offset, size));
+}
+
+static inline int
+dma_map_sg_attrs(struct device *dev, struct scatterlist *sgl, int nents,
+ enum dma_data_direction dir, struct dma_attrs *attrs)
+{
+
+ return (linux_dma_map_sg_attrs(dev, sgl, nents, dir, attrs));
+}
+
+static inline void
+dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction dir, struct dma_attrs *attrs)
+{
+
+ linux_dma_unmap_sg_attrs(dev, sg, nents, dir, attrs);
+}
+
+static inline dma_addr_t
+dma_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size, enum dma_data_direction direction)
+{
+
+ return (linux_dma_map_phys(dev, VM_PAGE_TO_PHYS(page) + offset, size));
+}
+
+static inline void
+dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
+ enum dma_data_direction direction)
+{
+
+ linux_dma_unmap(dev, dma_address, size);
+}
+
+static inline void
+dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
+ enum dma_data_direction direction)
+{
+}
+
+static inline void
+dma_sync_single(struct device *dev, dma_addr_t addr, size_t size,
+ enum dma_data_direction dir)
+{
+ dma_sync_single_for_cpu(dev, addr, size, dir);
+}
+
+static inline void
+dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
+ size_t size, enum dma_data_direction direction)
+{
+}
+
+static inline void
+dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
+ enum dma_data_direction direction)
+{
+}
+
+static inline void
+dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
+ enum dma_data_direction direction)
+{
+}
+
+static inline void
+dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
+ unsigned long offset, size_t size, int direction)
+{
+}
+
+static inline void
+dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
+ unsigned long offset, size_t size, int direction)
+{
+}
+
+static inline int
+dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+
+ return (dma_addr == 0);
+}
+
+static inline unsigned int dma_set_max_seg_size(struct device *dev,
+ unsigned int size)
+{
+ return (0);
+}
+
+#define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, NULL)
+#define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, NULL)
+#define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, NULL)
+#define dma_unmap_sg(d, s, n, r) dma_unmap_sg_attrs(d, s, n, r, NULL)
+
+#define DEFINE_DMA_UNMAP_ADDR(name) dma_addr_t name
+#define DEFINE_DMA_UNMAP_LEN(name) __u32 name
+#define dma_unmap_addr(p, name) ((p)->name)
+#define dma_unmap_addr_set(p, name, v) (((p)->name) = (v))
+#define dma_unmap_len(p, name) ((p)->name)
+#define dma_unmap_len_set(p, name, v) (((p)->name) = (v))
+
+extern int uma_align_cache;
+#define dma_get_cache_alignment() uma_align_cache
+
+#endif /* _LINUX_DMA_MAPPING_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/dmapool.h b/sys/compat/linuxkpi/common/include/linux/dmapool.h
new file mode 100644
index 000000000000..980d5d74884f
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/dmapool.h
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_DMAPOOL_H_
+#define _LINUX_DMAPOOL_H_
+
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/scatterlist.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+
+struct dma_pool;
+struct dma_pool *linux_dma_pool_create(char *name, struct device *dev,
+ size_t size, size_t align, size_t boundary);
+void linux_dma_pool_destroy(struct dma_pool *pool);
+void *linux_dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags,
+ dma_addr_t *handle);
+void linux_dma_pool_free(struct dma_pool *pool, void *vaddr,
+ dma_addr_t dma_addr);
+
+static inline struct dma_pool *
+dma_pool_create(char *name, struct device *dev, size_t size,
+ size_t align, size_t boundary)
+{
+
+ return (linux_dma_pool_create(name, dev, size, align, boundary));
+}
+
+static inline void
+dma_pool_destroy(struct dma_pool *pool)
+{
+
+ linux_dma_pool_destroy(pool);
+}
+
+static inline void *
+dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags, dma_addr_t *handle)
+{
+
+ return (linux_dma_pool_alloc(pool, mem_flags, handle));
+}
+
+static inline void *
+dma_pool_zalloc(struct dma_pool *pool, gfp_t mem_flags, dma_addr_t *handle)
+{
+
+ return (dma_pool_alloc(pool, mem_flags | __GFP_ZERO, handle));
+}
+
+static inline void
+dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t dma_addr)
+{
+
+ linux_dma_pool_free(pool, vaddr, dma_addr);
+}
+
+#endif /* _LINUX_DMAPOOL_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/dmi.h b/sys/compat/linuxkpi/common/include/linux/dmi.h
new file mode 100644
index 000000000000..b921cc906917
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/dmi.h
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Emmanuel Vadot under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __LINUX_DMI_H__
+#define __LINUX_DMI_H__
+
+#include <linux/mod_devicetable.h>
+
+int linux_dmi_check_system(const struct dmi_system_id *);
+bool linux_dmi_match(enum dmi_field, const char *);
+const struct dmi_system_id *linux_dmi_first_match(const struct dmi_system_id *);
+const char *linux_dmi_get_system_info(int);
+
+#define dmi_check_system(sysid) linux_dmi_check_system(sysid)
+#define dmi_match(f, str) linux_dmi_match(f, str)
+#define dmi_first_match(sysid) linux_dmi_first_match(sysid)
+#define dmi_get_system_info(sysid) linux_dmi_get_system_info(sysid)
+
+#endif /* __LINUX_DMI_H__ */
diff --git a/sys/compat/linuxkpi/common/include/linux/err.h b/sys/compat/linuxkpi/common/include/linux/err.h
new file mode 100644
index 000000000000..40a8ba82dfda
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/err.h
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_ERR_H_
+#define _LINUX_ERR_H_
+
+#include <sys/types.h>
+
+#include <linux/compiler.h>
+
+#define MAX_ERRNO 4095
+
+#define IS_ERR_VALUE(x) unlikely((x) >= (uintptr_t)-MAX_ERRNO)
+
+static inline void *
+ERR_PTR(long error)
+{
+ return (void *)(intptr_t)error;
+}
+
+static inline long
+PTR_ERR(const void *ptr)
+{
+ return (intptr_t)ptr;
+}
+
+static inline bool
+IS_ERR(const void *ptr)
+{
+ return IS_ERR_VALUE((uintptr_t)ptr);
+}
+
+static inline bool
+IS_ERR_OR_NULL(const void *ptr)
+{
+ return !ptr || IS_ERR_VALUE((uintptr_t)ptr);
+}
+
+static inline void *
+ERR_CAST(const void *ptr)
+{
+ return __DECONST(void *, ptr);
+}
+
+static inline int
+PTR_ERR_OR_ZERO(const void *ptr)
+{
+ if (IS_ERR(ptr))
+ return PTR_ERR(ptr);
+ else
+ return 0;
+}
+
+#define PTR_RET(p) PTR_ERR_OR_ZERO(p)
+
+#endif /* _LINUX_ERR_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/errno.h b/sys/compat/linuxkpi/common/include/linux/errno.h
new file mode 100644
index 000000000000..e824480ab640
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/errno.h
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_ERRNO_H_
+#define _LINUX_ERRNO_H_
+
+#include <sys/errno.h>
+
+#define EBADRQC 56 /* Bad request code */
+
+#define ECHRNG EDOM
+#define ETIME ETIMEDOUT
+#define ECOMM ESTALE
+#define ENODATA ECONNREFUSED
+#define ENOIOCTLCMD ENOIOCTL
+/* Use same value as Linux, because BSD's ERESTART is negative */
+#define ERESTARTSYS 512
+#define ENOTSUPP EOPNOTSUPP
+#define ENONET EHOSTDOWN
+
+#define ERESTARTNOINTR 513
+#define ERESTARTNOHAND 514
+#define ERESTART_RESTARTBLOCK 516
+#define EPROBE_DEFER 517
+#define EOPENSTALE 518
+#define EBADHANDLE 521
+#define ENOTSYNC 522
+#define EBADCOOKIE 523
+#define ETOOSMALL 525
+#define ESERVERFAULT 526
+#define EBADTYPE 527
+#define EJUKEBOX 528
+#define EIOCBQUEUED 529
+
+#endif /* _LINUX_ERRNO_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/etherdevice.h b/sys/compat/linuxkpi/common/include/linux/etherdevice.h
new file mode 100644
index 000000000000..392f395a5feb
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/etherdevice.h
@@ -0,0 +1,117 @@
+/*-
+ * Copyright (c) 2015-2016 Mellanox Technologies, Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_ETHERDEVICE
+#define _LINUX_ETHERDEVICE
+
+#include <linux/types.h>
+
+#include <sys/random.h>
+#include <sys/libkern.h>
+
+#define ETH_MODULE_SFF_8079 1
+#define ETH_MODULE_SFF_8079_LEN 256
+#define ETH_MODULE_SFF_8472 2
+#define ETH_MODULE_SFF_8472_LEN 512
+#define ETH_MODULE_SFF_8636 3
+#define ETH_MODULE_SFF_8636_LEN 256
+#define ETH_MODULE_SFF_8436 4
+#define ETH_MODULE_SFF_8436_LEN 256
+
+struct ethtool_eeprom {
+ u32 offset;
+ u32 len;
+};
+
+struct ethtool_modinfo {
+ u32 type;
+ u32 eeprom_len;
+};
+
+static inline bool
+is_zero_ether_addr(const u8 * addr)
+{
+ return ((addr[0] + addr[1] + addr[2] + addr[3] + addr[4] + addr[5]) == 0x00);
+}
+
+static inline bool
+is_multicast_ether_addr(const u8 * addr)
+{
+ return (0x01 & addr[0]);
+}
+
+static inline bool
+is_broadcast_ether_addr(const u8 * addr)
+{
+ return ((addr[0] + addr[1] + addr[2] + addr[3] + addr[4] + addr[5]) == (6 * 0xff));
+}
+
+static inline bool
+is_valid_ether_addr(const u8 * addr)
+{
+ return !is_multicast_ether_addr(addr) && !is_zero_ether_addr(addr);
+}
+
+static inline void
+ether_addr_copy(u8 * dst, const u8 * src)
+{
+ memcpy(dst, src, 6);
+}
+
+static inline bool
+ether_addr_equal(const u8 *pa, const u8 *pb)
+{
+ return (memcmp(pa, pb, 6) == 0);
+}
+
+static inline bool
+ether_addr_equal_64bits(const u8 *pa, const u8 *pb)
+{
+ return (memcmp(pa, pb, 6) == 0);
+}
+
+static inline void
+eth_broadcast_addr(u8 *pa)
+{
+ memset(pa, 0xff, 6);
+}
+
+static inline void
+eth_zero_addr(u8 *pa)
+{
+ memset(pa, 0, 6);
+}
+
+static inline void
+random_ether_addr(u8 * dst)
+{
+ arc4random_buf(dst, 6);
+
+ dst[0] &= 0xfe;
+ dst[0] |= 0x02;
+}
+
+#endif /* _LINUX_ETHERDEVICE */
diff --git a/sys/compat/linuxkpi/common/include/linux/export.h b/sys/compat/linuxkpi/common/include/linux/export.h
new file mode 100644
index 000000000000..00d51114f774
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/export.h
@@ -0,0 +1,33 @@
+/*-
+ * Copyright (c) 2018 Johannes Lundberg <johalun0@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_EXPORT_H
+#define _LINUX_EXPORT_H
+
+#define EXPORT_SYMBOL(name)
+#define EXPORT_SYMBOL_GPL(name)
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/file.h b/sys/compat/linuxkpi/common/include/linux/file.h
new file mode 100644
index 000000000000..21b254211cfd
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/file.h
@@ -0,0 +1,190 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_FILE_H_
+#define _LINUX_FILE_H_
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/refcount.h>
+#include <sys/capsicum.h>
+#include <sys/proc.h>
+
+#include <linux/fs.h>
+#include <linux/slab.h>
+
+struct linux_file;
+
+#undef file
+
+extern struct fileops linuxfileops;
+
+static inline struct linux_file *
+linux_fget(unsigned int fd)
+{
+ struct file *file;
+
+ /* lookup file pointer by file descriptor index */
+ if (fget_unlocked(curthread->td_proc->p_fd, fd,
+ &cap_no_rights, &file) != 0)
+ return (NULL);
+
+ /* check if file handle really belongs to us */
+ if (file->f_data == NULL ||
+ file->f_ops != &linuxfileops) {
+ fdrop(file, curthread);
+ return (NULL);
+ }
+ return ((struct linux_file *)file->f_data);
+}
+
+extern void linux_file_free(struct linux_file *filp);
+
+static inline void
+fput(struct linux_file *filp)
+{
+ if (refcount_release(filp->_file == NULL ?
+ &filp->f_count : &filp->_file->f_count)) {
+ linux_file_free(filp);
+ }
+}
+
+static inline unsigned int
+file_count(struct linux_file *filp)
+{
+ return (filp->_file == NULL ?
+ filp->f_count : filp->_file->f_count);
+}
+
+static inline void
+put_unused_fd(unsigned int fd)
+{
+ struct file *file;
+
+ if (fget_unlocked(curthread->td_proc->p_fd, fd,
+ &cap_no_rights, &file) != 0) {
+ return;
+ }
+ /*
+ * NOTE: We should only get here when the "fd" has not been
+ * installed, so no need to free the associated Linux file
+ * structure.
+ */
+ fdclose(curthread, file, fd);
+
+ /* drop extra reference */
+ fdrop(file, curthread);
+}
+
+static inline void
+fd_install(unsigned int fd, struct linux_file *filp)
+{
+ struct file *file;
+
+ if (fget_unlocked(curthread->td_proc->p_fd, fd,
+ &cap_no_rights, &file) != 0) {
+ filp->_file = NULL;
+ } else {
+ filp->_file = file;
+ finit(file, filp->f_mode, DTYPE_DEV, filp, &linuxfileops);
+
+ /* transfer reference count from "filp" to "file" */
+ while (refcount_release(&filp->f_count) == 0)
+ refcount_acquire(&file->f_count);
+ }
+
+ /* drop the extra reference */
+ fput(filp);
+}
+
+static inline int
+get_unused_fd(void)
+{
+ struct file *file;
+ int error;
+ int fd;
+
+ error = falloc(curthread, &file, &fd, 0);
+ if (error)
+ return -error;
+ /* drop the extra reference */
+ fdrop(file, curthread);
+ return fd;
+}
+
+static inline int
+get_unused_fd_flags(int flags)
+{
+ struct file *file;
+ int error;
+ int fd;
+
+ error = falloc(curthread, &file, &fd, flags);
+ if (error)
+ return -error;
+ /* drop the extra reference */
+ fdrop(file, curthread);
+ return fd;
+}
+
+extern struct linux_file *linux_file_alloc(void);
+
+static inline struct linux_file *
+alloc_file(int mode, const struct file_operations *fops)
+{
+ struct linux_file *filp;
+
+ filp = linux_file_alloc();
+ filp->f_op = fops;
+ filp->f_mode = mode;
+
+ return (filp);
+}
+
+struct fd {
+ struct linux_file *linux_file;
+};
+
+static inline void fdput(struct fd fd)
+{
+ fput(fd.linux_file);
+}
+
+static inline struct fd fdget(unsigned int fd)
+{
+ struct linux_file *f = linux_fget(fd);
+ return (struct fd){f};
+}
+
+#define file linux_file
+#define fget(...) linux_fget(__VA_ARGS__)
+
+#endif /* _LINUX_FILE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/firmware.h b/sys/compat/linuxkpi/common/include/linux/firmware.h
new file mode 100644
index 000000000000..ada7d0d73edf
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/firmware.h
@@ -0,0 +1,105 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020-2021 The FreeBSD Foundation
+ *
+ * This software was developed by Björn Zeeb under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUXKPI_LINUX_FIRMWARE_H
+#define _LINUXKPI_LINUX_FIRMWARE_H
+
+#include <sys/types.h>
+#include <linux/types.h>
+#include <linux/device.h>
+
+struct firmware;
+
+struct linuxkpi_firmware {
+ size_t size;
+ const uint8_t *data;
+ /* XXX Does Linux expose anything else? */
+
+ /* This is LinuxKPI implementation private. */
+ const struct firmware *fbdfw;
+};
+
+int linuxkpi_request_firmware_nowait(struct module *, bool, const char *,
+ struct device *, gfp_t, void *,
+ void(*cont)(const struct linuxkpi_firmware *, void *));
+int linuxkpi_request_firmware(const struct linuxkpi_firmware **,
+ const char *, struct device *);
+int linuxkpi_firmware_request_nowarn(const struct linuxkpi_firmware **,
+ const char *, struct device *);
+void linuxkpi_release_firmware(const struct linuxkpi_firmware *);
+
+
+static __inline int
+request_firmware_nowait(struct module *mod, bool _t,
+ const char *fw_name, struct device *dev, gfp_t gfp, void *drv,
+ void(*cont)(const struct linuxkpi_firmware *, void *))
+{
+
+
+ return (linuxkpi_request_firmware_nowait(mod, _t, fw_name, dev, gfp,
+ drv, cont));
+}
+
+static __inline int
+request_firmware(const struct linuxkpi_firmware **fw,
+ const char *fw_name, struct device *dev)
+{
+
+ return (linuxkpi_request_firmware(fw, fw_name, dev));
+}
+
+static __inline int
+request_firmware_direct(const struct linuxkpi_firmware **fw,
+ const char *fw_name, struct device *dev)
+{
+
+ return (linuxkpi_request_firmware(fw, fw_name, dev));
+}
+
+static __inline int
+firmware_request_nowarn(const struct linuxkpi_firmware **fw,
+ const char *fw_name, struct device *dev)
+{
+
+ return (linuxkpi_firmware_request_nowarn(fw, fw_name, dev));
+}
+
+static __inline void
+release_firmware(const struct linuxkpi_firmware *fw)
+{
+
+ linuxkpi_release_firmware(fw);
+}
+
+#define firmware linuxkpi_firmware
+
+#endif /* _LINUXKPI_LINUX_FIRMWARE_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/fs.h b/sys/compat/linuxkpi/common/include/linux/fs.h
new file mode 100644
index 000000000000..38911c276216
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/fs.h
@@ -0,0 +1,304 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2018 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_FS_H_
+#define _LINUX_FS_H_
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/vnode.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/dcache.h>
+
+struct module;
+struct kiocb;
+struct iovec;
+struct dentry;
+struct page;
+struct file_lock;
+struct pipe_inode_info;
+struct vm_area_struct;
+struct poll_table_struct;
+struct files_struct;
+struct pfs_node;
+struct linux_cdev;
+
+#define inode vnode
+#define i_cdev v_rdev
+#define i_private v_data
+
+#define S_IRUGO (S_IRUSR | S_IRGRP | S_IROTH)
+#define S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH)
+
+typedef struct files_struct *fl_owner_t;
+
+struct file_operations;
+
+struct linux_file_wait_queue {
+ struct wait_queue wq;
+ struct wait_queue_head *wqh;
+ atomic_t state;
+#define LINUX_FWQ_STATE_INIT 0
+#define LINUX_FWQ_STATE_NOT_READY 1
+#define LINUX_FWQ_STATE_QUEUED 2
+#define LINUX_FWQ_STATE_READY 3
+#define LINUX_FWQ_STATE_MAX 4
+};
+
+struct linux_file {
+ struct file *_file;
+ const struct file_operations *f_op;
+ void *private_data;
+ int f_flags;
+ int f_mode; /* Just starting mode. */
+ struct dentry *f_dentry;
+ struct dentry f_dentry_store;
+ struct selinfo f_selinfo;
+ struct sigio *f_sigio;
+ struct vnode *f_vnode;
+#define f_inode f_vnode
+ volatile u_int f_count;
+
+ /* anonymous shmem object */
+ vm_object_t f_shmem;
+
+ /* kqfilter support */
+ int f_kqflags;
+#define LINUX_KQ_FLAG_HAS_READ (1 << 0)
+#define LINUX_KQ_FLAG_HAS_WRITE (1 << 1)
+#define LINUX_KQ_FLAG_NEED_READ (1 << 2)
+#define LINUX_KQ_FLAG_NEED_WRITE (1 << 3)
+ /* protects f_selinfo.si_note */
+ spinlock_t f_kqlock;
+ struct linux_file_wait_queue f_wait_queue;
+
+ /* pointer to associated character device, if any */
+ struct linux_cdev *f_cdev;
+};
+
+#define file linux_file
+#define fasync_struct sigio *
+
+#define fasync_helper(fd, filp, on, queue) \
+({ \
+ if ((on)) \
+ *(queue) = &(filp)->f_sigio; \
+ else \
+ *(queue) = NULL; \
+ 0; \
+})
+
+#define kill_fasync(queue, sig, pollstat) \
+do { \
+ if (*(queue) != NULL) \
+ pgsigio(*(queue), (sig), 0); \
+} while (0)
+
+typedef int (*filldir_t)(void *, const char *, int, off_t, u64, unsigned);
+
+struct file_operations {
+ struct module *owner;
+ ssize_t (*read)(struct linux_file *, char __user *, size_t, off_t *);
+ ssize_t (*write)(struct linux_file *, const char __user *, size_t, off_t *);
+ unsigned int (*poll) (struct linux_file *, struct poll_table_struct *);
+ long (*unlocked_ioctl)(struct linux_file *, unsigned int, unsigned long);
+ long (*compat_ioctl)(struct linux_file *, unsigned int, unsigned long);
+ int (*mmap)(struct linux_file *, struct vm_area_struct *);
+ int (*open)(struct inode *, struct file *);
+ int (*release)(struct inode *, struct linux_file *);
+ int (*fasync)(int, struct linux_file *, int);
+
+/* Although not supported in FreeBSD, to align with Linux code
+ * we are adding llseek() only when it is mapped to no_llseek which returns
+ * an illegal seek error
+ */
+ off_t (*llseek)(struct linux_file *, off_t, int);
+#if 0
+ /* We do not support these methods. Don't permit them to compile. */
+ loff_t (*llseek)(struct file *, loff_t, int);
+ ssize_t (*aio_read)(struct kiocb *, const struct iovec *,
+ unsigned long, loff_t);
+ ssize_t (*aio_write)(struct kiocb *, const struct iovec *,
+ unsigned long, loff_t);
+ int (*readdir)(struct file *, void *, filldir_t);
+ int (*ioctl)(struct inode *, struct file *, unsigned int,
+ unsigned long);
+ int (*flush)(struct file *, fl_owner_t id);
+ int (*fsync)(struct file *, struct dentry *, int datasync);
+ int (*aio_fsync)(struct kiocb *, int datasync);
+ int (*lock)(struct file *, int, struct file_lock *);
+ ssize_t (*sendpage)(struct file *, struct page *, int, size_t,
+ loff_t *, int);
+ unsigned long (*get_unmapped_area)(struct file *, unsigned long,
+ unsigned long, unsigned long, unsigned long);
+ int (*check_flags)(int);
+ int (*flock)(struct file *, int, struct file_lock *);
+ ssize_t (*splice_write)(struct pipe_inode_info *, struct file *,
+ loff_t *, size_t, unsigned int);
+ ssize_t (*splice_read)(struct file *, loff_t *,
+ struct pipe_inode_info *, size_t, unsigned int);
+ int (*setlease)(struct file *, long, struct file_lock **);
+#endif
+};
+#define fops_get(fops) (fops)
+#define replace_fops(f, fops) ((f)->f_op = (fops))
+
+#define FMODE_READ FREAD
+#define FMODE_WRITE FWRITE
+#define FMODE_EXEC FEXEC
+#define FMODE_UNSIGNED_OFFSET 0x2000
+int __register_chrdev(unsigned int major, unsigned int baseminor,
+ unsigned int count, const char *name,
+ const struct file_operations *fops);
+int __register_chrdev_p(unsigned int major, unsigned int baseminor,
+ unsigned int count, const char *name,
+ const struct file_operations *fops, uid_t uid,
+ gid_t gid, int mode);
+void __unregister_chrdev(unsigned int major, unsigned int baseminor,
+ unsigned int count, const char *name);
+
+static inline void
+unregister_chrdev(unsigned int major, const char *name)
+{
+
+ __unregister_chrdev(major, 0, 256, name);
+}
+
+static inline int
+register_chrdev(unsigned int major, const char *name,
+ const struct file_operations *fops)
+{
+
+ return (__register_chrdev(major, 0, 256, name, fops));
+}
+
+static inline int
+register_chrdev_p(unsigned int major, const char *name,
+ const struct file_operations *fops, uid_t uid, gid_t gid, int mode)
+{
+
+ return (__register_chrdev_p(major, 0, 256, name, fops, uid, gid, mode));
+}
+
+static inline int
+register_chrdev_region(dev_t dev, unsigned range, const char *name)
+{
+
+ return 0;
+}
+
+static inline void
+unregister_chrdev_region(dev_t dev, unsigned range)
+{
+
+ return;
+}
+
+static inline int
+alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
+ const char *name)
+{
+
+ return 0;
+}
+
+/* No current support for seek op in FreeBSD */
+static inline int
+nonseekable_open(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+extern unsigned int linux_iminor(struct inode *);
+#define iminor(...) linux_iminor(__VA_ARGS__)
+
+static inline struct linux_file *
+get_file(struct linux_file *f)
+{
+
+ refcount_acquire(f->_file == NULL ? &f->f_count : &f->_file->f_count);
+ return (f);
+}
+
+static inline struct inode *
+igrab(struct inode *inode)
+{
+ int error;
+
+ error = vget(inode, 0);
+ if (error)
+ return (NULL);
+
+ return (inode);
+}
+
+static inline void
+iput(struct inode *inode)
+{
+
+ vrele(inode);
+}
+
+static inline loff_t
+no_llseek(struct file *file, loff_t offset, int whence)
+{
+
+ return (-ESPIPE);
+}
+
+static inline loff_t
+noop_llseek(struct linux_file *file, loff_t offset, int whence)
+{
+
+ return (file->_file->f_offset);
+}
+
+static inline struct vnode *
+file_inode(const struct linux_file *file)
+{
+
+ return (file->f_vnode);
+}
+
+static inline int
+call_mmap(struct linux_file *file, struct vm_area_struct *vma)
+{
+
+ return (file->f_op->mmap(file, vma));
+}
+
+#endif /* _LINUX_FS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/gcd.h b/sys/compat/linuxkpi/common/include/linux/gcd.h
new file mode 100644
index 000000000000..bff28340cfae
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/gcd.h
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_GCD_H_
+#define _LINUX_GCD_H_
+
+static inline unsigned long
+gcd(unsigned long a, unsigned long b)
+{
+ unsigned long c;
+
+ c = a % b;
+ while (c != 0) {
+ a = b;
+ b = c;
+ c = a % b;
+ }
+
+ return (b);
+}
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/gfp.h b/sys/compat/linuxkpi/common/include/linux/gfp.h
new file mode 100644
index 000000000000..1366e75ad26a
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/gfp.h
@@ -0,0 +1,187 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_GFP_H_
+#define _LINUX_GFP_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+
+#include <linux/page.h>
+
+#include <vm/vm_param.h>
+#include <vm/vm_object.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+
+#define __GFP_NOWARN 0
+#define __GFP_HIGHMEM 0
+#define __GFP_ZERO M_ZERO
+#define __GFP_NORETRY 0
+#define __GFP_RECLAIM 0
+#define __GFP_RECLAIMABLE 0
+#define __GFP_RETRY_MAYFAIL 0
+#define __GFP_MOVABLE 0
+#define __GFP_COMP 0
+#define __GFP_KSWAPD_RECLAIM 0
+
+#define __GFP_IO 0
+#define __GFP_NO_KSWAPD 0
+#define __GFP_KSWAPD_RECLAIM 0
+#define __GFP_WAIT M_WAITOK
+#define __GFP_DMA32 (1U << 24) /* LinuxKPI only */
+#define __GFP_BITS_SHIFT 25
+#define __GFP_BITS_MASK ((1 << __GFP_BITS_SHIFT) - 1)
+#define __GFP_NOFAIL M_WAITOK
+
+#define GFP_NOWAIT M_NOWAIT
+#define GFP_ATOMIC (M_NOWAIT | M_USE_RESERVE)
+#define GFP_KERNEL M_WAITOK
+#define GFP_USER M_WAITOK
+#define GFP_HIGHUSER M_WAITOK
+#define GFP_HIGHUSER_MOVABLE M_WAITOK
+#define GFP_IOFS M_NOWAIT
+#define GFP_NOIO M_NOWAIT
+#define GFP_DMA32 __GFP_DMA32
+#define GFP_TEMPORARY M_NOWAIT
+#define GFP_NATIVE_MASK (M_NOWAIT | M_WAITOK | M_USE_RESERVE | M_ZERO)
+#define GFP_TRANSHUGE 0
+#define GFP_TRANSHUGE_LIGHT 0
+
+CTASSERT((__GFP_DMA32 & GFP_NATIVE_MASK) == 0);
+CTASSERT((__GFP_BITS_MASK & GFP_NATIVE_MASK) == GFP_NATIVE_MASK);
+
+/*
+ * Resolve a page into a virtual address:
+ *
+ * NOTE: This function only works for pages allocated by the kernel.
+ */
+extern void *linux_page_address(struct page *);
+
+#define page_address(page) linux_page_address(page)
+
+/*
+ * Page management for unmapped pages:
+ */
+extern vm_page_t linux_alloc_pages(gfp_t flags, unsigned int order);
+extern void linux_free_pages(vm_page_t page, unsigned int order);
+
+static inline struct page *
+alloc_page(gfp_t flags)
+{
+
+ return (linux_alloc_pages(flags, 0));
+}
+
+static inline struct page *
+alloc_pages(gfp_t flags, unsigned int order)
+{
+
+ return (linux_alloc_pages(flags, order));
+}
+
+static inline struct page *
+alloc_pages_node(int node_id, gfp_t flags, unsigned int order)
+{
+
+ return (linux_alloc_pages(flags, order));
+}
+
+static inline void
+__free_pages(struct page *page, unsigned int order)
+{
+
+ linux_free_pages(page, order);
+}
+
+static inline void
+__free_page(struct page *page)
+{
+
+ linux_free_pages(page, 0);
+}
+
+/*
+ * Page management for mapped pages:
+ */
+extern vm_offset_t linux_alloc_kmem(gfp_t flags, unsigned int order);
+extern void linux_free_kmem(vm_offset_t, unsigned int order);
+
+static inline vm_offset_t
+get_zeroed_page(gfp_t flags)
+{
+
+ return (linux_alloc_kmem(flags | __GFP_ZERO, 0));
+}
+
+static inline vm_offset_t
+__get_free_page(gfp_t flags)
+{
+
+ return (linux_alloc_kmem(flags, 0));
+}
+
+static inline vm_offset_t
+__get_free_pages(gfp_t flags, unsigned int order)
+{
+
+ return (linux_alloc_kmem(flags, order));
+}
+
+static inline void
+free_pages(uintptr_t addr, unsigned int order)
+{
+ if (addr == 0)
+ return;
+
+ linux_free_kmem(addr, order);
+}
+
+static inline void
+free_page(uintptr_t addr)
+{
+ if (addr == 0)
+ return;
+
+ linux_free_kmem(addr, 0);
+}
+
+static inline bool
+gfpflags_allow_blocking(const gfp_t gfp_flags)
+{
+ return ((gfp_flags & (M_WAITOK | M_NOWAIT)) == M_WAITOK);
+}
+
+#define SetPageReserved(page) do { } while (0) /* NOP */
+#define ClearPageReserved(page) do { } while (0) /* NOP */
+
+#endif /* _LINUX_GFP_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/hardirq.h b/sys/compat/linuxkpi/common/include/linux/hardirq.h
new file mode 100644
index 000000000000..d338e11c5a6f
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/hardirq.h
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_HARDIRQ_H_
+#define _LINUX_HARDIRQ_H_
+
+#include <linux/types.h>
+#include <linux/lockdep.h>
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/interrupt.h>
+
+#define synchronize_irq(irq) _intr_drain((irq))
+
+#endif /* _LINUX_HARDIRQ_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/hrtimer.h b/sys/compat/linuxkpi/common/include/linux/hrtimer.h
new file mode 100644
index 000000000000..a5ff7480a271
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/hrtimer.h
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 2017 Mark Johnston <markj@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_HRTIMER_H_
+#define _LINUX_HRTIMER_H_
+
+#include <sys/_callout.h>
+#include <sys/_mutex.h>
+
+#include <linux/ktime.h>
+#include <linux/timer.h>
+
+enum hrtimer_mode {
+ HRTIMER_MODE_REL,
+ HRTIMER_MODE_REL_PINNED = HRTIMER_MODE_REL,
+};
+
+enum hrtimer_restart {
+ HRTIMER_RESTART,
+ HRTIMER_NORESTART,
+};
+
+struct hrtimer {
+ enum hrtimer_restart (*function)(struct hrtimer *);
+ struct mtx mtx;
+ struct callout callout;
+ s64 expires; /* relative time in nanoseconds */
+ s64 precision; /* in nanoseconds */
+};
+
+#define hrtimer_active(hrtimer) linux_hrtimer_active(hrtimer)
+#define hrtimer_cancel(hrtimer) linux_hrtimer_cancel(hrtimer)
+
+#define hrtimer_init(hrtimer, clock, mode) do { \
+ CTASSERT((clock) == CLOCK_MONOTONIC); \
+ CTASSERT((mode) == HRTIMER_MODE_REL); \
+ linux_hrtimer_init(hrtimer); \
+} while (0)
+
+#define hrtimer_set_expires(hrtimer, time) \
+ linux_hrtimer_set_expires(hrtimer, time)
+
+#define hrtimer_start(hrtimer, time, mode) do { \
+ CTASSERT((mode) == HRTIMER_MODE_REL); \
+ linux_hrtimer_start(hrtimer, time); \
+} while (0)
+
+#define hrtimer_start_range_ns(hrtimer, time, prec, mode) do { \
+ CTASSERT((mode) == HRTIMER_MODE_REL); \
+ linux_hrtimer_start_range_ns(hrtimer, time, prec); \
+} while (0)
+
+#define hrtimer_forward_now(hrtimer, interval) do { \
+ linux_hrtimer_forward_now(hrtimer, interval); \
+} while (0)
+
+bool linux_hrtimer_active(struct hrtimer *);
+int linux_hrtimer_cancel(struct hrtimer *);
+void linux_hrtimer_init(struct hrtimer *);
+void linux_hrtimer_set_expires(struct hrtimer *, ktime_t);
+void linux_hrtimer_start(struct hrtimer *, ktime_t);
+void linux_hrtimer_start_range_ns(struct hrtimer *, ktime_t, int64_t);
+void linux_hrtimer_forward_now(struct hrtimer *, ktime_t);
+
+#endif /* _LINUX_HRTIMER_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/idr.h b/sys/compat/linuxkpi/common/include/linux/idr.h
new file mode 100644
index 000000000000..7387032fd989
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/idr.h
@@ -0,0 +1,150 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_IDR_H_
+#define _LINUX_IDR_H_
+
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#include <linux/types.h>
+
+#define IDR_BITS 5
+#define IDR_SIZE (1 << IDR_BITS)
+#define IDR_MASK (IDR_SIZE - 1)
+
+#define MAX_ID_SHIFT ((sizeof(int) * NBBY) - 1)
+#define MAX_ID_BIT (1U << MAX_ID_SHIFT)
+#define MAX_ID_MASK (MAX_ID_BIT - 1)
+#define MAX_LEVEL (MAX_ID_SHIFT + IDR_BITS - 1) / IDR_BITS
+
+#define MAX_IDR_SHIFT (sizeof(int)*8 - 1)
+#define MAX_IDR_BIT (1U << MAX_IDR_SHIFT)
+#define MAX_IDR_MASK (MAX_IDR_BIT - 1)
+
+struct idr_layer {
+ unsigned long bitmap;
+ struct idr_layer *ary[IDR_SIZE];
+};
+
+struct idr {
+ struct mtx lock;
+ struct idr_layer *top;
+ struct idr_layer *free;
+ int layers;
+ int next_cyclic_id;
+};
+
+/* NOTE: It is the applications responsibility to destroy the IDR */
+#define DEFINE_IDR(name) \
+ struct idr name; \
+ SYSINIT(name##_idr_sysinit, SI_SUB_DRIVERS, SI_ORDER_FIRST, \
+ idr_init, &(name))
+
+/* NOTE: It is the applications responsibility to destroy the IDA */
+#define DEFINE_IDA(name) \
+ struct ida name; \
+ SYSINIT(name##_ida_sysinit, SI_SUB_DRIVERS, SI_ORDER_FIRST, \
+ ida_init, &(name))
+
+void idr_preload(gfp_t gfp_mask);
+void idr_preload_end(void);
+void *idr_find(struct idr *idp, int id);
+void *idr_get_next(struct idr *idp, int *nextid);
+bool idr_is_empty(struct idr *idp);
+int idr_pre_get(struct idr *idp, gfp_t gfp_mask);
+int idr_get_new(struct idr *idp, void *ptr, int *id);
+int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id);
+void *idr_replace(struct idr *idp, void *ptr, int id);
+void *idr_remove(struct idr *idp, int id);
+void idr_remove_all(struct idr *idp);
+void idr_destroy(struct idr *idp);
+void idr_init(struct idr *idp);
+int idr_alloc(struct idr *idp, void *ptr, int start, int end, gfp_t);
+int idr_alloc_cyclic(struct idr *idp, void *ptr, int start, int end, gfp_t);
+int idr_for_each(struct idr *idp, int (*fn)(int id, void *p, void *data), void *data);
+
+#define idr_for_each_entry(idp, entry, id) \
+ for ((id) = 0; ((entry) = idr_get_next(idp, &(id))) != NULL; ++(id))
+
+#define IDA_CHUNK_SIZE 128 /* 128 bytes per chunk */
+#define IDA_BITMAP_LONGS (IDA_CHUNK_SIZE / sizeof(long) - 1)
+#define IDA_BITMAP_BITS (IDA_BITMAP_LONGS * sizeof(long) * 8)
+
+struct ida_bitmap {
+ long nr_busy;
+ unsigned long bitmap[IDA_BITMAP_LONGS];
+};
+
+struct ida {
+ struct idr idr;
+ struct ida_bitmap *free_bitmap;
+};
+
+int ida_pre_get(struct ida *ida, gfp_t gfp_mask);
+int ida_get_new_above(struct ida *ida, int starting_id, int *p_id);
+void ida_remove(struct ida *ida, int id);
+void ida_destroy(struct ida *ida);
+void ida_init(struct ida *ida);
+
+int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end,
+ gfp_t gfp_mask);
+void ida_simple_remove(struct ida *ida, unsigned int id);
+
+static inline void
+ida_free(struct ida *ida, int id)
+{
+
+ ida_remove(ida, id);
+}
+
+static inline int
+ida_get_new(struct ida *ida, int *p_id)
+{
+
+ return (ida_get_new_above(ida, 0, p_id));
+}
+
+static inline int
+ida_alloc_max(struct ida *ida, unsigned int max, gfp_t gfp)
+{
+
+ return (ida_simple_get(ida, 0, max, gfp));
+}
+
+static inline bool
+ida_is_empty(struct ida *ida)
+{
+
+ return (idr_is_empty(&ida->idr));
+}
+
+#endif /* _LINUX_IDR_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/if_arp.h b/sys/compat/linuxkpi/common/include/linux/if_arp.h
new file mode 100644
index 000000000000..9235e2dff9cf
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/if_arp.h
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_IF_ARP_H_
+#define _LINUX_IF_ARP_H_
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if_arp.h>
+#endif /* _LINUX_IF_ARP_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/if_ether.h b/sys/compat/linuxkpi/common/include/linux/if_ether.h
new file mode 100644
index 000000000000..77e8f1192816
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/if_ether.h
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_IF_ETHER_H_
+#define _LINUX_IF_ETHER_H_
+
+#include <linux/types.h>
+
+#include <net/ethernet.h>
+
+#define ETH_HLEN ETHER_HDR_LEN /* Total octets in header. */
+#ifndef ETH_ALEN
+#define ETH_ALEN ETHER_ADDR_LEN
+#endif
+#define ETH_FCS_LEN 4 /* Octets in the FCS */
+#define VLAN_HLEN 4 /* The additional bytes (on top of the Ethernet header)
+ * that VLAN requires. */
+/*
+ * defined Ethernet Protocol ID's.
+ */
+#define ETH_P_IP ETHERTYPE_IP
+#define ETH_P_IPV6 ETHERTYPE_IPV6
+#define ETH_P_MPLS_UC ETHERTYPE_MPLS
+#define ETH_P_MPLS_MC ETHERTYPE_MPLS_MCAST
+#define ETH_P_8021Q ETHERTYPE_VLAN
+#define ETH_P_8021AD ETHERTYPE_QINQ
+
+#endif /* _LINUX_IF_ETHER_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/if_vlan.h b/sys/compat/linuxkpi/common/include/linux/if_vlan.h
new file mode 100644
index 000000000000..4d8b8926a032
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/if_vlan.h
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_IF_VLAN_H_
+#define _LINUX_IF_VLAN_H_
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_var.h>
+#include <net/if_vlan_var.h>
+#include <net/if_types.h>
+
+#define VLAN_N_VID 4096
+
+static inline int
+is_vlan_dev(struct ifnet *ifp)
+{
+ return (ifp->if_type == IFT_L2VLAN);
+}
+
+static inline uint16_t
+vlan_dev_vlan_id(struct ifnet *ifp)
+{
+ uint16_t vtag;
+ if (VLAN_TAG(ifp, &vtag) == 0)
+ return (vtag);
+ return (0);
+}
+
+#endif /* _LINUX_IF_VLAN_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/in.h b/sys/compat/linuxkpi/common/include/linux/in.h
new file mode 100644
index 000000000000..96d66fbae2f0
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/in.h
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_IN_H_
+#define _LINUX_IN_H_
+
+#include "opt_inet.h"
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <netinet/in.h>
+#include <asm/byteorder.h>
+
+#define ipv4_is_zeronet(be) IN_ZERONET(ntohl(be))
+#define ipv4_is_loopback(be) IN_LOOPBACK(ntohl(be))
+#define ipv4_is_multicast(be) IN_MULTICAST(ntohl(be))
+#define ipv4_is_lbcast(be) ((be) == INADDR_BROADCAST)
+
+#endif /* _LINUX_IN_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/in6.h b/sys/compat/linuxkpi/common/include/linux/in6.h
new file mode 100644
index 000000000000..c72bfb6f0b88
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/in6.h
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_IN6_H_
+#define _LINUX_IN6_H_
+
+#include "opt_inet6.h"
+
+#endif /* _LINUX_IN6_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/inetdevice.h b/sys/compat/linuxkpi/common/include/linux/inetdevice.h
new file mode 100644
index 000000000000..87c880392b71
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/inetdevice.h
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_INETDEVICE_H_
+#define _LINUX_INETDEVICE_H_
+
+#include <linux/netdevice.h>
+
+static inline struct net_device *
+ip_dev_find(struct vnet *vnet, uint32_t addr)
+{
+ struct sockaddr_in sin;
+ struct epoch_tracker et;
+ struct ifaddr *ifa;
+ struct ifnet *ifp;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_addr.s_addr = addr;
+ sin.sin_len = sizeof(sin);
+ sin.sin_family = AF_INET;
+ NET_EPOCH_ENTER(et);
+ CURVNET_SET_QUIET(vnet);
+ ifa = ifa_ifwithaddr((struct sockaddr *)&sin);
+ CURVNET_RESTORE();
+ if (ifa) {
+ ifp = ifa->ifa_ifp;
+ if_ref(ifp);
+ } else {
+ ifp = NULL;
+ }
+ NET_EPOCH_EXIT(et);
+ return (ifp);
+}
+
+static inline struct net_device *
+ip6_dev_find(struct vnet *vnet, struct in6_addr addr, uint16_t scope_id)
+{
+ struct sockaddr_in6 sin6;
+ struct epoch_tracker et;
+ struct ifaddr *ifa;
+ struct ifnet *ifp;
+
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_addr = addr;
+ sin6.sin6_len = sizeof(sin6);
+ sin6.sin6_family = AF_INET6;
+ if (IN6_IS_SCOPE_LINKLOCAL(&addr) ||
+ IN6_IS_ADDR_MC_INTFACELOCAL(&addr)) {
+ /* embed the IPv6 scope ID */
+ sin6.sin6_addr.s6_addr16[1] = htons(scope_id);
+ }
+ NET_EPOCH_ENTER(et);
+ CURVNET_SET_QUIET(vnet);
+ ifa = ifa_ifwithaddr((struct sockaddr *)&sin6);
+ CURVNET_RESTORE();
+ if (ifa != NULL) {
+ ifp = ifa->ifa_ifp;
+ if_ref(ifp);
+ } else {
+ ifp = NULL;
+ }
+ NET_EPOCH_EXIT(et);
+ return (ifp);
+}
+
+#endif /* _LINUX_INETDEVICE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/interrupt.h b/sys/compat/linuxkpi/common/include/linux/interrupt.h
new file mode 100644
index 000000000000..ca26cd24ffda
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/interrupt.h
@@ -0,0 +1,215 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2015 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_INTERRUPT_H_
+#define _LINUX_INTERRUPT_H_
+
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/irqreturn.h>
+
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+typedef irqreturn_t (*irq_handler_t)(int, void *);
+
+#define IRQF_SHARED RF_SHAREABLE
+
+struct irq_ent {
+ struct list_head links;
+ struct device *dev;
+ struct resource *res;
+ void *arg;
+ irqreturn_t (*handler)(int, void *);
+ void *tag;
+ unsigned int irq;
+};
+
+static inline int
+linux_irq_rid(struct device *dev, unsigned int irq)
+{
+ /* check for MSI- or MSIX- interrupt */
+ if (irq >= dev->irq_start && irq < dev->irq_end)
+ return (irq - dev->irq_start + 1);
+ else
+ return (0);
+}
+
+extern void linux_irq_handler(void *);
+
+static inline struct irq_ent *
+linux_irq_ent(struct device *dev, unsigned int irq)
+{
+ struct irq_ent *irqe;
+
+ list_for_each_entry(irqe, &dev->irqents, links)
+ if (irqe->irq == irq)
+ return (irqe);
+
+ return (NULL);
+}
+
+static inline int
+request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
+ const char *name, void *arg)
+{
+ struct resource *res;
+ struct irq_ent *irqe;
+ struct device *dev;
+ int error;
+ int rid;
+
+ dev = linux_pci_find_irq_dev(irq);
+ if (dev == NULL)
+ return -ENXIO;
+ rid = linux_irq_rid(dev, irq);
+ res = bus_alloc_resource_any(dev->bsddev, SYS_RES_IRQ, &rid,
+ flags | RF_ACTIVE);
+ if (res == NULL)
+ return (-ENXIO);
+ irqe = kmalloc(sizeof(*irqe), GFP_KERNEL);
+ irqe->dev = dev;
+ irqe->res = res;
+ irqe->arg = arg;
+ irqe->handler = handler;
+ irqe->irq = irq;
+ error = bus_setup_intr(dev->bsddev, res, INTR_TYPE_NET | INTR_MPSAFE,
+ NULL, linux_irq_handler, irqe, &irqe->tag);
+ if (error) {
+ bus_release_resource(dev->bsddev, SYS_RES_IRQ, rid, irqe->res);
+ kfree(irqe);
+ return (-error);
+ }
+ list_add(&irqe->links, &dev->irqents);
+
+ return 0;
+}
+
+static inline int
+enable_irq(unsigned int irq)
+{
+ struct irq_ent *irqe;
+ struct device *dev;
+
+ dev = linux_pci_find_irq_dev(irq);
+ if (dev == NULL)
+ return -EINVAL;
+ irqe = linux_irq_ent(dev, irq);
+ if (irqe == NULL || irqe->tag != NULL)
+ return -EINVAL;
+ return -bus_setup_intr(dev->bsddev, irqe->res, INTR_TYPE_NET | INTR_MPSAFE,
+ NULL, linux_irq_handler, irqe, &irqe->tag);
+}
+
+static inline void
+disable_irq(unsigned int irq)
+{
+ struct irq_ent *irqe;
+ struct device *dev;
+
+ dev = linux_pci_find_irq_dev(irq);
+ if (dev == NULL)
+ return;
+ irqe = linux_irq_ent(dev, irq);
+ if (irqe == NULL)
+ return;
+ if (irqe->tag != NULL)
+ bus_teardown_intr(dev->bsddev, irqe->res, irqe->tag);
+ irqe->tag = NULL;
+}
+
+static inline int
+bind_irq_to_cpu(unsigned int irq, int cpu_id)
+{
+ struct irq_ent *irqe;
+ struct device *dev;
+
+ dev = linux_pci_find_irq_dev(irq);
+ if (dev == NULL)
+ return (-ENOENT);
+
+ irqe = linux_irq_ent(dev, irq);
+ if (irqe == NULL)
+ return (-ENOENT);
+
+ return (-bus_bind_intr(dev->bsddev, irqe->res, cpu_id));
+}
+
+static inline void
+free_irq(unsigned int irq, void *device)
+{
+ struct irq_ent *irqe;
+ struct device *dev;
+ int rid;
+
+ dev = linux_pci_find_irq_dev(irq);
+ if (dev == NULL)
+ return;
+ rid = linux_irq_rid(dev, irq);
+ irqe = linux_irq_ent(dev, irq);
+ if (irqe == NULL)
+ return;
+ if (irqe->tag != NULL)
+ bus_teardown_intr(dev->bsddev, irqe->res, irqe->tag);
+ bus_release_resource(dev->bsddev, SYS_RES_IRQ, rid, irqe->res);
+ list_del(&irqe->links);
+ kfree(irqe);
+}
+
+/*
+ * LinuxKPI tasklet support
+ */
+typedef void tasklet_func_t(unsigned long);
+
+struct tasklet_struct {
+ TAILQ_ENTRY(tasklet_struct) entry;
+ tasklet_func_t *func;
+ /* Our "state" implementation is different. Avoid same name as Linux. */
+ volatile u_int tasklet_state;
+ atomic_t count;
+ unsigned long data;
+};
+
+#define DECLARE_TASKLET(_name, _func, _data) \
+struct tasklet_struct _name = { .func = (_func), .data = (_data) }
+
+#define tasklet_hi_schedule(t) tasklet_schedule(t)
+
+extern void tasklet_schedule(struct tasklet_struct *);
+extern void tasklet_kill(struct tasklet_struct *);
+extern void tasklet_init(struct tasklet_struct *, tasklet_func_t *,
+ unsigned long data);
+extern void tasklet_enable(struct tasklet_struct *);
+extern void tasklet_disable(struct tasklet_struct *);
+extern int tasklet_trylock(struct tasklet_struct *);
+extern void tasklet_unlock(struct tasklet_struct *);
+extern void tasklet_unlock_wait(struct tasklet_struct *ts);
+
+#endif /* _LINUX_INTERRUPT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/io-mapping.h b/sys/compat/linuxkpi/common/include/linux/io-mapping.h
new file mode 100644
index 000000000000..12643be9c6e6
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/io-mapping.h
@@ -0,0 +1,117 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_IO_MAPPING_H_
+#define _LINUX_IO_MAPPING_H_
+
+#include <sys/types.h>
+#include <machine/vm.h>
+
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+struct io_mapping {
+ unsigned long base;
+ unsigned long size;
+ void *mem;
+ vm_memattr_t attr;
+};
+
+static inline struct io_mapping *
+io_mapping_init_wc(struct io_mapping *mapping, resource_size_t base,
+ unsigned long size)
+{
+
+ mapping->base = base;
+ mapping->size = size;
+#ifdef VM_MEMATTR_WRITE_COMBINING
+ mapping->mem = ioremap_wc(base, size);
+ mapping->attr = VM_MEMATTR_WRITE_COMBINING;
+#else
+ mapping->mem = ioremap_nocache(base, size);
+ mapping->attr = VM_MEMATTR_UNCACHEABLE;
+#endif
+ return (mapping);
+}
+
+static inline struct io_mapping *
+io_mapping_create_wc(resource_size_t base, unsigned long size)
+{
+ struct io_mapping *mapping;
+
+ mapping = kmalloc(sizeof(*mapping), GFP_KERNEL);
+ if (mapping == NULL)
+ return (NULL);
+ return (io_mapping_init_wc(mapping, base, size));
+}
+
+static inline void
+io_mapping_fini(struct io_mapping *mapping)
+{
+
+ iounmap(mapping->mem);
+}
+
+static inline void
+io_mapping_free(struct io_mapping *mapping)
+{
+
+ io_mapping_fini(mapping->mem);
+ kfree(mapping);
+}
+
+static inline void *
+io_mapping_map_atomic_wc(struct io_mapping *mapping, unsigned long offset)
+{
+
+ return ((char *)mapping->mem + offset);
+}
+
+static inline void
+io_mapping_unmap_atomic(void *vaddr)
+{
+}
+
+static inline void *
+io_mapping_map_wc(struct io_mapping *mapping, unsigned long offset,
+ unsigned long size)
+{
+
+ return ((char *)mapping->mem + offset);
+}
+
+static inline void
+io_mapping_unmap(void *vaddr)
+{
+}
+
+#endif /* _LINUX_IO_MAPPING_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/io.h b/sys/compat/linuxkpi/common/include/linux/io.h
new file mode 100644
index 000000000000..0104eea90ace
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/io.h
@@ -0,0 +1,481 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2015 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_IO_H_
+#define _LINUX_IO_H_
+
+#include <sys/endian.h>
+#include <sys/types.h>
+
+#include <machine/vm.h>
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+/*
+ * XXX This is all x86 specific. It should be bus space access.
+ */
+
+/* rmb and wmb are declared in machine/atomic.h, so should be included first. */
+#ifndef __io_br
+#define __io_br() __compiler_membar()
+#endif
+
+#ifndef __io_ar
+#ifdef rmb
+#define __io_ar() rmb()
+#else
+#define __io_ar() __compiler_membar()
+#endif
+#endif
+
+#ifndef __io_bw
+#ifdef wmb
+#define __io_bw() wmb()
+#else
+#define __io_bw() __compiler_membar()
+#endif
+#endif
+
+#ifndef __io_aw
+#define __io_aw() __compiler_membar()
+#endif
+
+/* Access MMIO registers atomically without barriers and byte swapping. */
+
+static inline uint8_t
+__raw_readb(const volatile void *addr)
+{
+ return (*(const volatile uint8_t *)addr);
+}
+#define __raw_readb(addr) __raw_readb(addr)
+
+static inline void
+__raw_writeb(uint8_t v, volatile void *addr)
+{
+ *(volatile uint8_t *)addr = v;
+}
+#define __raw_writeb(v, addr) __raw_writeb(v, addr)
+
+static inline uint16_t
+__raw_readw(const volatile void *addr)
+{
+ return (*(const volatile uint16_t *)addr);
+}
+#define __raw_readw(addr) __raw_readw(addr)
+
+static inline void
+__raw_writew(uint16_t v, volatile void *addr)
+{
+ *(volatile uint16_t *)addr = v;
+}
+#define __raw_writew(v, addr) __raw_writew(v, addr)
+
+static inline uint32_t
+__raw_readl(const volatile void *addr)
+{
+ return (*(const volatile uint32_t *)addr);
+}
+#define __raw_readl(addr) __raw_readl(addr)
+
+static inline void
+__raw_writel(uint32_t v, volatile void *addr)
+{
+ *(volatile uint32_t *)addr = v;
+}
+#define __raw_writel(v, addr) __raw_writel(v, addr)
+
+#ifdef __LP64__
+static inline uint64_t
+__raw_readq(const volatile void *addr)
+{
+ return (*(const volatile uint64_t *)addr);
+}
+#define __raw_readq(addr) __raw_readq(addr)
+
+static inline void
+__raw_writeq(uint64_t v, volatile void *addr)
+{
+ *(volatile uint64_t *)addr = v;
+}
+#define __raw_writeq(v, addr) __raw_writeq(v, addr)
+#endif
+
+#define mmiowb() barrier()
+
+/* Access little-endian MMIO registers atomically with memory barriers. */
+
+#undef readb
+static inline uint8_t
+readb(const volatile void *addr)
+{
+ uint8_t v;
+
+ __io_br();
+ v = *(const volatile uint8_t *)addr;
+ __io_ar();
+ return (v);
+}
+#define readb(addr) readb(addr)
+
+#undef writeb
+static inline void
+writeb(uint8_t v, volatile void *addr)
+{
+ __io_bw();
+ *(volatile uint8_t *)addr = v;
+ __io_aw();
+}
+#define writeb(v, addr) writeb(v, addr)
+
+#undef readw
+static inline uint16_t
+readw(const volatile void *addr)
+{
+ uint16_t v;
+
+ __io_br();
+ v = le16toh(__raw_readw(addr));
+ __io_ar();
+ return (v);
+}
+#define readw(addr) readw(addr)
+
+#undef writew
+static inline void
+writew(uint16_t v, volatile void *addr)
+{
+ __io_bw();
+ __raw_writew(htole16(v), addr);
+ __io_aw();
+}
+#define writew(v, addr) writew(v, addr)
+
+#undef readl
+static inline uint32_t
+readl(const volatile void *addr)
+{
+ uint32_t v;
+
+ __io_br();
+ v = le32toh(__raw_readl(addr));
+ __io_ar();
+ return (v);
+}
+#define readl(addr) readl(addr)
+
+#undef writel
+static inline void
+writel(uint32_t v, volatile void *addr)
+{
+ __io_bw();
+ __raw_writel(htole32(v), addr);
+ __io_aw();
+}
+#define writel(v, addr) writel(v, addr)
+
+#undef readq
+#undef writeq
+#ifdef __LP64__
+static inline uint64_t
+readq(const volatile void *addr)
+{
+ uint64_t v;
+
+ __io_br();
+ v = le64toh(__raw_readq(addr));
+ __io_ar();
+ return (v);
+}
+#define readq(addr) readq(addr)
+
+static inline void
+writeq(uint64_t v, volatile void *addr)
+{
+ __io_bw();
+ __raw_writeq(htole64(v), addr);
+ __io_aw();
+}
+#define writeq(v, addr) writeq(v, addr)
+#endif
+
+/* Access little-endian MMIO registers atomically without memory barriers. */
+
+#undef readb_relaxed
+static inline uint8_t
+readb_relaxed(const volatile void *addr)
+{
+ return (__raw_readb(addr));
+}
+#define readb_relaxed(addr) readb_relaxed(addr)
+
+#undef writeb_relaxed
+static inline void
+writeb_relaxed(uint8_t v, volatile void *addr)
+{
+ __raw_writeb(v, addr);
+}
+#define writeb_relaxed(v, addr) writeb_relaxed(v, addr)
+
+#undef readw_relaxed
+static inline uint16_t
+readw_relaxed(const volatile void *addr)
+{
+ return (le16toh(__raw_readw(addr)));
+}
+#define readw_relaxed(addr) readw_relaxed(addr)
+
+#undef writew_relaxed
+static inline void
+writew_relaxed(uint16_t v, volatile void *addr)
+{
+ __raw_writew(htole16(v), addr);
+}
+#define writew_relaxed(v, addr) writew_relaxed(v, addr)
+
+#undef readl_relaxed
+static inline uint32_t
+readl_relaxed(const volatile void *addr)
+{
+ return (le32toh(__raw_readl(addr)));
+}
+#define readl_relaxed(addr) readl_relaxed(addr)
+
+#undef writel_relaxed
+static inline void
+writel_relaxed(uint32_t v, volatile void *addr)
+{
+ __raw_writel(htole32(v), addr);
+}
+#define writel_relaxed(v, addr) writel_relaxed(v, addr)
+
+#undef readq_relaxed
+#undef writeq_relaxed
+#ifdef __LP64__
+static inline uint64_t
+readq_relaxed(const volatile void *addr)
+{
+ return (le64toh(__raw_readq(addr)));
+}
+#define readq_relaxed(addr) readq_relaxed(addr)
+
+static inline void
+writeq_relaxed(uint64_t v, volatile void *addr)
+{
+ __raw_writeq(htole64(v), addr);
+}
+#define writeq_relaxed(v, addr) writeq_relaxed(v, addr)
+#endif
+
+/* XXX On Linux ioread and iowrite handle both MMIO and port IO. */
+
+#undef ioread8
+static inline uint8_t
+ioread8(const volatile void *addr)
+{
+ return (readb(addr));
+}
+#define ioread8(addr) ioread8(addr)
+
+#undef ioread16
+static inline uint16_t
+ioread16(const volatile void *addr)
+{
+ return (readw(addr));
+}
+#define ioread16(addr) ioread16(addr)
+
+#undef ioread16be
+static inline uint16_t
+ioread16be(const volatile void *addr)
+{
+ uint16_t v;
+
+ __io_br();
+ v = (be16toh(__raw_readw(addr)));
+ __io_ar();
+
+ return (v);
+}
+#define ioread16be(addr) ioread16be(addr)
+
+#undef ioread32
+static inline uint32_t
+ioread32(const volatile void *addr)
+{
+ return (readl(addr));
+}
+#define ioread32(addr) ioread32(addr)
+
+#undef ioread32be
+static inline uint32_t
+ioread32be(const volatile void *addr)
+{
+ uint32_t v;
+
+ __io_br();
+ v = (be32toh(__raw_readl(addr)));
+ __io_ar();
+
+ return (v);
+}
+#define ioread32be(addr) ioread32be(addr)
+
+#undef iowrite8
+static inline void
+iowrite8(uint8_t v, volatile void *addr)
+{
+ writeb(v, addr);
+}
+#define iowrite8(v, addr) iowrite8(v, addr)
+
+#undef iowrite16
+static inline void
+iowrite16(uint16_t v, volatile void *addr)
+{
+ writew(v, addr);
+}
+#define iowrite16 iowrite16
+
+#undef iowrite32
+static inline void
+iowrite32(uint32_t v, volatile void *addr)
+{
+ writel(v, addr);
+}
+#define iowrite32(v, addr) iowrite32(v, addr)
+
+#undef iowrite32be
+static inline void
+iowrite32be(uint32_t v, volatile void *addr)
+{
+ __io_bw();
+ __raw_writel(htobe32(v), addr);
+ __io_aw();
+}
+#define iowrite32be(v, addr) iowrite32be(v, addr)
+
+#if defined(__i386__) || defined(__amd64__)
+static inline void
+_outb(u_char data, u_int port)
+{
+ __asm __volatile("outb %0, %w1" : : "a" (data), "Nd" (port));
+}
+#endif
+
+#if defined(__i386__) || defined(__amd64__) || defined(__powerpc__) || defined(__aarch64__)
+void *_ioremap_attr(vm_paddr_t phys_addr, unsigned long size, int attr);
+#else
+#define _ioremap_attr(...) NULL
+#endif
+
+#ifdef VM_MEMATTR_DEVICE
+#define ioremap_nocache(addr, size) \
+ _ioremap_attr((addr), (size), VM_MEMATTR_DEVICE)
+#define ioremap_wt(addr, size) \
+ _ioremap_attr((addr), (size), VM_MEMATTR_DEVICE)
+#define ioremap(addr, size) \
+ _ioremap_attr((addr), (size), VM_MEMATTR_DEVICE)
+#else
+#define ioremap_nocache(addr, size) \
+ _ioremap_attr((addr), (size), VM_MEMATTR_UNCACHEABLE)
+#define ioremap_wt(addr, size) \
+ _ioremap_attr((addr), (size), VM_MEMATTR_WRITE_THROUGH)
+#define ioremap(addr, size) \
+ _ioremap_attr((addr), (size), VM_MEMATTR_UNCACHEABLE)
+#endif
+#define ioremap_wc(addr, size) \
+ _ioremap_attr((addr), (size), VM_MEMATTR_WRITE_COMBINING)
+#define ioremap_wb(addr, size) \
+ _ioremap_attr((addr), (size), VM_MEMATTR_WRITE_BACK)
+void iounmap(void *addr);
+
+#define memset_io(a, b, c) memset((a), (b), (c))
+#define memcpy_fromio(a, b, c) memcpy((a), (b), (c))
+#define memcpy_toio(a, b, c) memcpy((a), (b), (c))
+
+static inline void
+__iowrite32_copy(void *to, void *from, size_t count)
+{
+ uint32_t *src;
+ uint32_t *dst;
+ int i;
+
+ for (i = 0, src = from, dst = to; i < count; i++, src++, dst++)
+ __raw_writel(*src, dst);
+}
+
+static inline void
+__iowrite64_copy(void *to, void *from, size_t count)
+{
+#ifdef __LP64__
+ uint64_t *src;
+ uint64_t *dst;
+ int i;
+
+ for (i = 0, src = from, dst = to; i < count; i++, src++, dst++)
+ __raw_writeq(*src, dst);
+#else
+ __iowrite32_copy(to, from, count * 2);
+#endif
+}
+
+enum {
+ MEMREMAP_WB = 1 << 0,
+ MEMREMAP_WT = 1 << 1,
+ MEMREMAP_WC = 1 << 2,
+};
+
+static inline void *
+memremap(resource_size_t offset, size_t size, unsigned long flags)
+{
+ void *addr = NULL;
+
+ if ((flags & MEMREMAP_WB) &&
+ (addr = ioremap_wb(offset, size)) != NULL)
+ goto done;
+ if ((flags & MEMREMAP_WT) &&
+ (addr = ioremap_wt(offset, size)) != NULL)
+ goto done;
+ if ((flags & MEMREMAP_WC) &&
+ (addr = ioremap_wc(offset, size)) != NULL)
+ goto done;
+done:
+ return (addr);
+}
+
+static inline void
+memunmap(void *addr)
+{
+ /* XXX May need to check if this is RAM */
+ iounmap(addr);
+}
+
+#endif /* _LINUX_IO_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/ioctl.h b/sys/compat/linuxkpi/common/include/linux/ioctl.h
new file mode 100644
index 000000000000..fdedf9c4a179
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/ioctl.h
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_IOCTL_H_
+#define _LINUX_IOCTL_H_
+
+#include <sys/ioccom.h>
+
+#define _IOC_SIZE(cmd) IOCPARM_LEN(cmd)
+
+#endif /* _LINUX_IOCTL_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/irq_work.h b/sys/compat/linuxkpi/common/include/linux/irq_work.h
new file mode 100644
index 000000000000..eb1798a4e450
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/irq_work.h
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Emmanuel Vadot under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __LINUX_IRQ_WORK_H__
+#define __LINUX_IRQ_WORK_H__
+
+#include <sys/param.h>
+#include <sys/taskqueue.h>
+
+struct irq_work;
+typedef void (*irq_work_func_t)(struct irq_work *);
+
+struct irq_work {
+ struct task irq_task;
+ irq_work_func_t func;
+};
+
+extern struct taskqueue *linux_irq_work_tq;
+
+#define DEFINE_IRQ_WORK(name, _func) struct irq_work name = { \
+ .irq_task = TASK_INITIALIZER(0, linux_irq_work_fn, &(name)), \
+ .func = (_func), \
+}
+
+void linux_irq_work_fn(void *, int);
+
+static inline void
+init_irq_work(struct irq_work *irqw, irq_work_func_t func)
+{
+ TASK_INIT(&irqw->irq_task, 0, linux_irq_work_fn, irqw);
+ irqw->func = func;
+}
+
+static inline void
+irq_work_queue(struct irq_work *irqw)
+{
+ taskqueue_enqueue(linux_irq_work_tq, &irqw->irq_task);
+}
+
+#endif /* __LINUX_IRQ_WORK_H__ */
diff --git a/sys/compat/linuxkpi/common/include/linux/irqreturn.h b/sys/compat/linuxkpi/common/include/linux/irqreturn.h
new file mode 100644
index 000000000000..780fccad017c
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/irqreturn.h
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2017 Limelight Networks, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_IRQRETURN_H
+#define _LINUX_IRQRETURN_H
+
+typedef enum irqreturn {
+ IRQ_NONE = 0,
+ IRQ_HANDLED = 1,
+ IRQ_WAKE_THREAD = 2
+} irqreturn_t;
+
+#define IRQ_RETVAL(x) ((x) ? IRQ_HANDLED : IRQ_NONE)
+
+#endif /* _LINUX_IRQRETURN_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/jhash.h b/sys/compat/linuxkpi/common/include/linux/jhash.h
new file mode 100644
index 000000000000..08300083212f
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/jhash.h
@@ -0,0 +1,146 @@
+#ifndef _LINUX_JHASH_H_
+#define _LINUX_JHASH_H_
+
+#include <asm/types.h>
+
+/* jhash.h: Jenkins hash support.
+ *
+ * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net)
+ *
+ * http://burtleburtle.net/bob/hash/
+ *
+ * These are the credits from Bob's sources:
+ *
+ * lookup2.c, by Bob Jenkins, December 1996, Public Domain.
+ * hash(), hash2(), hash3, and mix() are externally useful functions.
+ * Routines to test the hash are included if SELF_TEST is defined.
+ * You can use this free for any purpose. It has no warranty.
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ *
+ * I've modified Bob's hash to be useful in the Linux kernel, and
+ * any bugs present are surely my fault. -DaveM
+ *
+ * $FreeBSD$
+ */
+
+/* NOTE: Arguments are modified. */
+#define __jhash_mix(a, b, c) \
+{ \
+ a -= b; a -= c; a ^= (c>>13); \
+ b -= c; b -= a; b ^= (a<<8); \
+ c -= a; c -= b; c ^= (b>>13); \
+ a -= b; a -= c; a ^= (c>>12); \
+ b -= c; b -= a; b ^= (a<<16); \
+ c -= a; c -= b; c ^= (b>>5); \
+ a -= b; a -= c; a ^= (c>>3); \
+ b -= c; b -= a; b ^= (a<<10); \
+ c -= a; c -= b; c ^= (b>>15); \
+}
+
+/* The golden ration: an arbitrary value */
+#define JHASH_GOLDEN_RATIO 0x9e3779b9
+
+/* The most generic version, hashes an arbitrary sequence
+ * of bytes. No alignment or length assumptions are made about
+ * the input key.
+ */
+static inline u32 jhash(const void *key, u32 length, u32 initval)
+{
+ u32 a, b, c, len;
+ const u8 *k = key;
+
+ len = length;
+ a = b = JHASH_GOLDEN_RATIO;
+ c = initval;
+
+ while (len >= 12) {
+ a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24));
+ b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24));
+ c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24));
+
+ __jhash_mix(a,b,c);
+
+ k += 12;
+ len -= 12;
+ }
+
+ c += length;
+ switch (len) {
+ case 11: c += ((u32)k[10]<<24);
+ case 10: c += ((u32)k[9]<<16);
+ case 9 : c += ((u32)k[8]<<8);
+ case 8 : b += ((u32)k[7]<<24);
+ case 7 : b += ((u32)k[6]<<16);
+ case 6 : b += ((u32)k[5]<<8);
+ case 5 : b += k[4];
+ case 4 : a += ((u32)k[3]<<24);
+ case 3 : a += ((u32)k[2]<<16);
+ case 2 : a += ((u32)k[1]<<8);
+ case 1 : a += k[0];
+ };
+
+ __jhash_mix(a,b,c);
+
+ return c;
+}
+
+/* A special optimized version that handles 1 or more of u32s.
+ * The length parameter here is the number of u32s in the key.
+ */
+static inline u32 jhash2(const u32 *k, u32 length, u32 initval)
+{
+ u32 a, b, c, len;
+
+ a = b = JHASH_GOLDEN_RATIO;
+ c = initval;
+ len = length;
+
+ while (len >= 3) {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ __jhash_mix(a, b, c);
+ k += 3; len -= 3;
+ }
+
+ c += length * 4;
+
+ switch (len) {
+ case 2 : b += k[1];
+ case 1 : a += k[0];
+ };
+
+ __jhash_mix(a,b,c);
+
+ return c;
+}
+
+/* A special ultra-optimized versions that knows they are hashing exactly
+ * 3, 2 or 1 word(s).
+ *
+ * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally
+ * done at the end is not done here.
+ */
+static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)
+{
+ a += JHASH_GOLDEN_RATIO;
+ b += JHASH_GOLDEN_RATIO;
+ c += initval;
+
+ __jhash_mix(a, b, c);
+
+ return c;
+}
+
+static inline u32 jhash_2words(u32 a, u32 b, u32 initval)
+{
+ return jhash_3words(a, b, 0, initval);
+}
+
+static inline u32 jhash_1word(u32 a, u32 initval)
+{
+ return jhash_3words(a, 0, 0, initval);
+}
+
+#endif /* _LINUX_JHASH_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/jiffies.h b/sys/compat/linuxkpi/common/include/linux/jiffies.h
new file mode 100644
index 000000000000..ed2c5f774d23
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/jiffies.h
@@ -0,0 +1,166 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_JIFFIES_H_
+#define _LINUX_JIFFIES_H_
+
+#include <linux/types.h>
+#include <linux/time.h>
+
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+
+#define jiffies ticks
+#define jiffies_64 ticks
+#define jiffies_to_msecs(x) (((int64_t)(int)(x)) * 1000 / hz)
+
+#define MAX_JIFFY_OFFSET ((INT_MAX >> 1) - 1)
+
+#define time_after(a, b) ((int)((b) - (a)) < 0)
+#define time_after32(a, b) ((int32_t)((uint32_t)(b) - (uint32_t)(a)) < 0)
+#define time_before(a, b) time_after(b,a)
+#define time_before32(a, b) time_after32(b, a)
+#define time_after_eq(a, b) ((int)((a) - (b)) >= 0)
+#define time_before_eq(a, b) time_after_eq(b, a)
+#define time_in_range(a,b,c) \
+ (time_after_eq(a,b) && time_before_eq(a,c))
+#define time_is_after_eq_jiffies(a) time_after_eq(a, jiffies)
+
+#define HZ hz
+
+extern uint64_t lkpi_nsec2hz_rem;
+extern uint64_t lkpi_nsec2hz_div;
+extern uint64_t lkpi_nsec2hz_max;
+
+extern uint64_t lkpi_usec2hz_rem;
+extern uint64_t lkpi_usec2hz_div;
+extern uint64_t lkpi_usec2hz_max;
+
+extern uint64_t lkpi_msec2hz_rem;
+extern uint64_t lkpi_msec2hz_div;
+extern uint64_t lkpi_msec2hz_max;
+
+static inline int
+timespec_to_jiffies(const struct timespec *ts)
+{
+ u64 result;
+
+ result = ((u64)hz * ts->tv_sec) +
+ (((u64)hz * ts->tv_nsec + NSEC_PER_SEC - 1) / NSEC_PER_SEC);
+ if (result > MAX_JIFFY_OFFSET)
+ result = MAX_JIFFY_OFFSET;
+
+ return ((int)result);
+}
+
+static inline int
+msecs_to_jiffies(uint64_t msec)
+{
+ uint64_t result;
+
+ if (msec > lkpi_msec2hz_max)
+ msec = lkpi_msec2hz_max;
+ result = howmany(msec * lkpi_msec2hz_rem, lkpi_msec2hz_div);
+ if (result > MAX_JIFFY_OFFSET)
+ result = MAX_JIFFY_OFFSET;
+
+ return ((int)result);
+}
+
+static inline int
+usecs_to_jiffies(uint64_t usec)
+{
+ uint64_t result;
+
+ if (usec > lkpi_usec2hz_max)
+ usec = lkpi_usec2hz_max;
+ result = howmany(usec * lkpi_usec2hz_rem, lkpi_usec2hz_div);
+ if (result > MAX_JIFFY_OFFSET)
+ result = MAX_JIFFY_OFFSET;
+
+ return ((int)result);
+}
+
+static inline uint64_t
+nsecs_to_jiffies64(uint64_t nsec)
+{
+
+ if (nsec > lkpi_nsec2hz_max)
+ nsec = lkpi_nsec2hz_max;
+ return (howmany(nsec * lkpi_nsec2hz_rem, lkpi_nsec2hz_div));
+}
+
+static inline unsigned long
+nsecs_to_jiffies(uint64_t nsec)
+{
+
+ if (sizeof(unsigned long) >= sizeof(uint64_t)) {
+ if (nsec > lkpi_nsec2hz_max)
+ nsec = lkpi_nsec2hz_max;
+ } else {
+ if (nsec > (lkpi_nsec2hz_max >> 32))
+ nsec = (lkpi_nsec2hz_max >> 32);
+ }
+ return (howmany(nsec * lkpi_nsec2hz_rem, lkpi_nsec2hz_div));
+}
+
+static inline uint64_t
+jiffies_to_nsecs(int j)
+{
+
+ return ((1000000000ULL / hz) * (uint64_t)(unsigned int)j);
+}
+
+static inline uint64_t
+jiffies_to_usecs(int j)
+{
+
+ return ((1000000ULL / hz) * (uint64_t)(unsigned int)j);
+}
+
+static inline uint64_t
+get_jiffies_64(void)
+{
+
+ return ((uint64_t)(unsigned int)ticks);
+}
+
+static inline int
+linux_timer_jiffies_until(int expires)
+{
+ int delta = expires - jiffies;
+ /* guard against already expired values */
+ if (delta < 1)
+ delta = 1;
+ return (delta);
+}
+
+#endif /* _LINUX_JIFFIES_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/kdev_t.h b/sys/compat/linuxkpi/common/include/linux/kdev_t.h
new file mode 100644
index 000000000000..9477ba739e31
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/kdev_t.h
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_KDEV_T_H_
+#define _LINUX_KDEV_T_H_
+
+#include <sys/types.h>
+
+#define MAJOR(dev) major(dev)
+#define MINOR(dev) minor(dev)
+#define MKDEV(ma, mi) makedev(ma, mi)
+
+static inline uint16_t
+old_encode_dev(dev_t dev)
+{
+ return ((MAJOR(dev) << 8) | MINOR(dev));
+}
+
+#endif /* _LINUX_KDEV_T_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/kernel.h b/sys/compat/linuxkpi/common/include/linux/kernel.h
new file mode 100644
index 000000000000..daef6216a151
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/kernel.h
@@ -0,0 +1,638 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * Copyright (c) 2014-2015 François Tigeot
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_KERNEL_H_
+#define _LINUX_KERNEL_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/param.h>
+#include <sys/libkern.h>
+#include <sys/stat.h>
+#include <sys/smp.h>
+#include <sys/stddef.h>
+#include <sys/syslog.h>
+#include <sys/time.h>
+
+#include <linux/bitops.h>
+#include <linux/compiler.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/jiffies.h>
+#include <linux/log2.h>
+
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+#include <machine/stdarg.h>
+
+#define KERN_CONT ""
+#define KERN_EMERG "<0>"
+#define KERN_ALERT "<1>"
+#define KERN_CRIT "<2>"
+#define KERN_ERR "<3>"
+#define KERN_WARNING "<4>"
+#define KERN_NOTICE "<5>"
+#define KERN_INFO "<6>"
+#define KERN_DEBUG "<7>"
+
+#define U8_MAX ((u8)~0U)
+#define S8_MAX ((s8)(U8_MAX >> 1))
+#define S8_MIN ((s8)(-S8_MAX - 1))
+#define U16_MAX ((u16)~0U)
+#define S16_MAX ((s16)(U16_MAX >> 1))
+#define S16_MIN ((s16)(-S16_MAX - 1))
+#define U32_MAX ((u32)~0U)
+#define S32_MAX ((s32)(U32_MAX >> 1))
+#define S32_MIN ((s32)(-S32_MAX - 1))
+#define U64_MAX ((u64)~0ULL)
+#define S64_MAX ((s64)(U64_MAX >> 1))
+#define S64_MIN ((s64)(-S64_MAX - 1))
+
+#define S8_C(x) x
+#define U8_C(x) x ## U
+#define S16_C(x) x
+#define U16_C(x) x ## U
+#define S32_C(x) x
+#define U32_C(x) x ## U
+#define S64_C(x) x ## LL
+#define U64_C(x) x ## ULL
+
+#define BUILD_BUG() do { CTASSERT(0); } while (0)
+#define BUILD_BUG_ON(x) CTASSERT(!(x))
+#define BUILD_BUG_ON_MSG(x, msg) BUILD_BUG_ON(x)
+#define BUILD_BUG_ON_NOT_POWER_OF_2(x) BUILD_BUG_ON(!powerof2(x))
+#define BUILD_BUG_ON_INVALID(expr) while (0) { (void)(expr); }
+
+extern const volatile int lkpi_build_bug_on_zero;
+#define BUILD_BUG_ON_ZERO(x) ((x) ? lkpi_build_bug_on_zero : 0)
+
+#define BUG() panic("BUG at %s:%d", __FILE__, __LINE__)
+#define BUG_ON(cond) do { \
+ if (cond) { \
+ panic("BUG ON %s failed at %s:%d", \
+ __stringify(cond), __FILE__, __LINE__); \
+ } \
+} while (0)
+
+#define WARN_ON(cond) ({ \
+ bool __ret = (cond); \
+ if (__ret) { \
+ printf("WARNING %s failed at %s:%d\n", \
+ __stringify(cond), __FILE__, __LINE__); \
+ linux_dump_stack(); \
+ } \
+ unlikely(__ret); \
+})
+
+#define WARN_ON_SMP(cond) WARN_ON(cond)
+
+#define WARN_ON_ONCE(cond) ({ \
+ static bool __warn_on_once; \
+ bool __ret = (cond); \
+ if (__ret && !__warn_on_once) { \
+ __warn_on_once = 1; \
+ printf("WARNING %s failed at %s:%d\n", \
+ __stringify(cond), __FILE__, __LINE__); \
+ linux_dump_stack(); \
+ } \
+ unlikely(__ret); \
+})
+
+#define oops_in_progress SCHEDULER_STOPPED()
+
+#undef ALIGN
+#define ALIGN(x, y) roundup2((x), (y))
+#undef PTR_ALIGN
+#define PTR_ALIGN(p, a) ((__typeof(p))ALIGN((uintptr_t)(p), (a)))
+#define IS_ALIGNED(x, a) (((x) & ((__typeof(x))(a) - 1)) == 0)
+#define DIV_ROUND_UP(x, n) howmany(x, n)
+#define __KERNEL_DIV_ROUND_UP(x, n) howmany(x, n)
+#define DIV_ROUND_UP_ULL(x, n) DIV_ROUND_UP((unsigned long long)(x), (n))
+#define DIV_ROUND_DOWN_ULL(x, n) (((unsigned long long)(x) / (n)) * (n))
+#define FIELD_SIZEOF(t, f) sizeof(((t *)0)->f)
+
+#define printk(...) printf(__VA_ARGS__)
+#define vprintk(f, a) vprintf(f, a)
+
+#define asm __asm
+
+extern void linux_dump_stack(void);
+#define dump_stack() linux_dump_stack()
+
+struct va_format {
+ const char *fmt;
+ va_list *va;
+};
+
+static inline int
+vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
+{
+ ssize_t ssize = size;
+ int i;
+
+ i = vsnprintf(buf, size, fmt, args);
+
+ return ((i >= ssize) ? (ssize - 1) : i);
+}
+
+static inline int
+scnprintf(char *buf, size_t size, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ i = vscnprintf(buf, size, fmt, args);
+ va_end(args);
+
+ return (i);
+}
+
+/*
+ * The "pr_debug()" and "pr_devel()" macros should produce zero code
+ * unless DEBUG is defined:
+ */
+#ifdef DEBUG
+extern int linuxkpi_debug;
+#define pr_debug(fmt, ...) \
+ do { \
+ if (linuxkpi_debug) \
+ log(LOG_DEBUG, fmt, ##__VA_ARGS__); \
+ } while (0)
+#define pr_devel(fmt, ...) \
+ log(LOG_DEBUG, pr_fmt(fmt), ##__VA_ARGS__)
+#else
+#define pr_debug(fmt, ...) \
+ ({ if (0) log(LOG_DEBUG, fmt, ##__VA_ARGS__); 0; })
+#define pr_devel(fmt, ...) \
+ ({ if (0) log(LOG_DEBUG, pr_fmt(fmt), ##__VA_ARGS__); 0; })
+#endif
+
+#ifndef pr_fmt
+#define pr_fmt(fmt) fmt
+#endif
+
+/*
+ * Print a one-time message (analogous to WARN_ONCE() et al):
+ */
+#define printk_once(...) do { \
+ static bool __print_once; \
+ \
+ if (!__print_once) { \
+ __print_once = true; \
+ printk(__VA_ARGS__); \
+ } \
+} while (0)
+
+/*
+ * Log a one-time message (analogous to WARN_ONCE() et al):
+ */
+#define log_once(level,...) do { \
+ static bool __log_once; \
+ \
+ if (unlikely(!__log_once)) { \
+ __log_once = true; \
+ log(level, __VA_ARGS__); \
+ } \
+} while (0)
+
+#define pr_emerg(fmt, ...) \
+ log(LOG_EMERG, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_alert(fmt, ...) \
+ log(LOG_ALERT, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_crit(fmt, ...) \
+ log(LOG_CRIT, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_err(fmt, ...) \
+ log(LOG_ERR, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_warning(fmt, ...) \
+ log(LOG_WARNING, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_warn(...) \
+ pr_warning(__VA_ARGS__)
+#define pr_warn_once(fmt, ...) \
+ log_once(LOG_WARNING, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_notice(fmt, ...) \
+ log(LOG_NOTICE, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_info(fmt, ...) \
+ log(LOG_INFO, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_info_once(fmt, ...) \
+ log_once(LOG_INFO, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_cont(fmt, ...) \
+ printk(KERN_CONT fmt, ##__VA_ARGS__)
+#define pr_warn_ratelimited(...) do { \
+ static linux_ratelimit_t __ratelimited; \
+ if (linux_ratelimited(&__ratelimited)) \
+ pr_warning(__VA_ARGS__); \
+} while (0)
+
+#ifndef WARN
+#define WARN(condition, ...) ({ \
+ bool __ret_warn_on = (condition); \
+ if (unlikely(__ret_warn_on)) \
+ pr_warning(__VA_ARGS__); \
+ unlikely(__ret_warn_on); \
+})
+#endif
+
+#ifndef WARN_ONCE
+#define WARN_ONCE(condition, ...) ({ \
+ bool __ret_warn_on = (condition); \
+ if (unlikely(__ret_warn_on)) \
+ pr_warn_once(__VA_ARGS__); \
+ unlikely(__ret_warn_on); \
+})
+#endif
+
+#define container_of(ptr, type, member) \
+({ \
+ const __typeof(((type *)0)->member) *__p = (ptr); \
+ (type *)((uintptr_t)__p - offsetof(type, member)); \
+})
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+#define u64_to_user_ptr(val) ((void *)(uintptr_t)(val))
+
+static inline unsigned long long
+simple_strtoull(const char *cp, char **endp, unsigned int base)
+{
+ return (strtouq(cp, endp, base));
+}
+
+static inline long long
+simple_strtoll(const char *cp, char **endp, unsigned int base)
+{
+ return (strtoq(cp, endp, base));
+}
+
+static inline unsigned long
+simple_strtoul(const char *cp, char **endp, unsigned int base)
+{
+ return (strtoul(cp, endp, base));
+}
+
+static inline long
+simple_strtol(const char *cp, char **endp, unsigned int base)
+{
+ return (strtol(cp, endp, base));
+}
+
+static inline int
+kstrtoul(const char *cp, unsigned int base, unsigned long *res)
+{
+ char *end;
+
+ *res = strtoul(cp, &end, base);
+
+ /* skip newline character, if any */
+ if (*end == '\n')
+ end++;
+ if (*cp == 0 || *end != 0)
+ return (-EINVAL);
+ return (0);
+}
+
+static inline int
+kstrtol(const char *cp, unsigned int base, long *res)
+{
+ char *end;
+
+ *res = strtol(cp, &end, base);
+
+ /* skip newline character, if any */
+ if (*end == '\n')
+ end++;
+ if (*cp == 0 || *end != 0)
+ return (-EINVAL);
+ return (0);
+}
+
+static inline int
+kstrtoint(const char *cp, unsigned int base, int *res)
+{
+ char *end;
+ long temp;
+
+ *res = temp = strtol(cp, &end, base);
+
+ /* skip newline character, if any */
+ if (*end == '\n')
+ end++;
+ if (*cp == 0 || *end != 0)
+ return (-EINVAL);
+ if (temp != (int)temp)
+ return (-ERANGE);
+ return (0);
+}
+
+static inline int
+kstrtouint(const char *cp, unsigned int base, unsigned int *res)
+{
+ char *end;
+ unsigned long temp;
+
+ *res = temp = strtoul(cp, &end, base);
+
+ /* skip newline character, if any */
+ if (*end == '\n')
+ end++;
+ if (*cp == 0 || *end != 0)
+ return (-EINVAL);
+ if (temp != (unsigned int)temp)
+ return (-ERANGE);
+ return (0);
+}
+
+static inline int
+kstrtou16(const char *cp, unsigned int base, u16 *res)
+{
+ char *end;
+ unsigned long temp;
+
+ *res = temp = strtoul(cp, &end, base);
+
+ /* skip newline character, if any */
+ if (*end == '\n')
+ end++;
+ if (*cp == 0 || *end != 0)
+ return (-EINVAL);
+ if (temp != (u16)temp)
+ return (-ERANGE);
+ return (0);
+}
+
+static inline int
+kstrtou32(const char *cp, unsigned int base, u32 *res)
+{
+ char *end;
+ unsigned long temp;
+
+ *res = temp = strtoul(cp, &end, base);
+
+ /* skip newline character, if any */
+ if (*end == '\n')
+ end++;
+ if (*cp == 0 || *end != 0)
+ return (-EINVAL);
+ if (temp != (u32)temp)
+ return (-ERANGE);
+ return (0);
+}
+
+static inline int
+kstrtou64(const char *cp, unsigned int base, u64 *res)
+{
+ char *end;
+
+ *res = strtouq(cp, &end, base);
+
+ /* skip newline character, if any */
+ if (*end == '\n')
+ end++;
+ if (*cp == 0 || *end != 0)
+ return (-EINVAL);
+ return (0);
+}
+
+static inline int
+kstrtobool(const char *s, bool *res)
+{
+ int len;
+
+ if (s == NULL || (len = strlen(s)) == 0 || res == NULL)
+ return (-EINVAL);
+
+ /* skip newline character, if any */
+ if (s[len - 1] == '\n')
+ len--;
+
+ if (len == 1 && strchr("yY1", s[0]) != NULL)
+ *res = true;
+ else if (len == 1 && strchr("nN0", s[0]) != NULL)
+ *res = false;
+ else if (strncasecmp("on", s, len) == 0)
+ *res = true;
+ else if (strncasecmp("off", s, len) == 0)
+ *res = false;
+ else
+ return (-EINVAL);
+
+ return (0);
+}
+
+static inline int
+kstrtobool_from_user(const char __user *s, size_t count, bool *res)
+{
+ char buf[8] = {};
+
+ if (count > (sizeof(buf) - 1))
+ count = (sizeof(buf) - 1);
+
+ if (copy_from_user(buf, s, count))
+ return (-EFAULT);
+
+ return (kstrtobool(buf, res));
+}
+
+#define min(x, y) ((x) < (y) ? (x) : (y))
+#define max(x, y) ((x) > (y) ? (x) : (y))
+
+#define min3(a, b, c) min(a, min(b,c))
+#define max3(a, b, c) max(a, max(b,c))
+
+#define min_t(type, x, y) ({ \
+ type __min1 = (x); \
+ type __min2 = (y); \
+ __min1 < __min2 ? __min1 : __min2; })
+
+#define max_t(type, x, y) ({ \
+ type __max1 = (x); \
+ type __max2 = (y); \
+ __max1 > __max2 ? __max1 : __max2; })
+
+#define offsetofend(t, m) \
+ (offsetof(t, m) + sizeof((((t *)0)->m)))
+
+#define clamp_t(type, _x, min, max) min_t(type, max_t(type, _x, min), max)
+#define clamp(x, lo, hi) min( max(x,lo), hi)
+#define clamp_val(val, lo, hi) clamp_t(typeof(val), val, lo, hi)
+
+/*
+ * This looks more complex than it should be. But we need to
+ * get the type for the ~ right in round_down (it needs to be
+ * as wide as the result!), and we want to evaluate the macro
+ * arguments just once each.
+ */
+#define __round_mask(x, y) ((__typeof__(x))((y)-1))
+#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1)
+#define round_down(x, y) ((x) & ~__round_mask(x, y))
+
+#define smp_processor_id() PCPU_GET(cpuid)
+#define num_possible_cpus() mp_ncpus
+#define num_online_cpus() mp_ncpus
+
+#if defined(__i386__) || defined(__amd64__)
+extern bool linux_cpu_has_clflush;
+#define cpu_has_clflush linux_cpu_has_clflush
+#endif
+
+typedef struct pm_message {
+ int event;
+} pm_message_t;
+
+/* Swap values of a and b */
+#define swap(a, b) do { \
+ typeof(a) _swap_tmp = a; \
+ a = b; \
+ b = _swap_tmp; \
+} while (0)
+
+#define DIV_ROUND_CLOSEST(x, divisor) (((x) + ((divisor) / 2)) / (divisor))
+
+#define DIV_ROUND_CLOSEST_ULL(x, divisor) ({ \
+ __typeof(divisor) __d = (divisor); \
+ unsigned long long __ret = (x) + (__d) / 2; \
+ __ret /= __d; \
+ __ret; \
+})
+
+static inline uintmax_t
+mult_frac(uintmax_t x, uintmax_t multiplier, uintmax_t divisor)
+{
+ uintmax_t q = (x / divisor);
+ uintmax_t r = (x % divisor);
+
+ return ((q * multiplier) + ((r * multiplier) / divisor));
+}
+
+static inline int64_t
+abs64(int64_t x)
+{
+ return (x < 0 ? -x : x);
+}
+
+typedef struct linux_ratelimit {
+ struct timeval lasttime;
+ int counter;
+} linux_ratelimit_t;
+
+static inline bool
+linux_ratelimited(linux_ratelimit_t *rl)
+{
+ return (ppsratecheck(&rl->lasttime, &rl->counter, 1));
+}
+
+#define struct_size(ptr, field, num) ({ \
+ const size_t __size = offsetof(__typeof(*(ptr)), field); \
+ const size_t __max = (SIZE_MAX - __size) / sizeof((ptr)->field[0]); \
+ ((num) > __max) ? SIZE_MAX : (__size + sizeof((ptr)->field[0]) * (num)); \
+})
+
+#define __is_constexpr(x) \
+ __builtin_constant_p(x)
+
+/*
+ * The is_signed() macro below returns true if the passed data type is
+ * signed. Else false is returned.
+ */
+#define is_signed(datatype) (((datatype)-1 / (datatype)2) == (datatype)0)
+
+/*
+ * The type_max() macro below returns the maxium positive value the
+ * passed data type can hold.
+ */
+#define type_max(datatype) ( \
+ (sizeof(datatype) >= 8) ? (is_signed(datatype) ? INT64_MAX : UINT64_MAX) : \
+ (sizeof(datatype) >= 4) ? (is_signed(datatype) ? INT32_MAX : UINT32_MAX) : \
+ (sizeof(datatype) >= 2) ? (is_signed(datatype) ? INT16_MAX : UINT16_MAX) : \
+ (is_signed(datatype) ? INT8_MAX : UINT8_MAX) \
+)
+
+/*
+ * The type_min() macro below returns the minimum value the passed
+ * data type can hold. For unsigned types the minimum value is always
+ * zero. For signed types it may vary.
+ */
+#define type_min(datatype) ( \
+ (sizeof(datatype) >= 8) ? (is_signed(datatype) ? INT64_MIN : 0) : \
+ (sizeof(datatype) >= 4) ? (is_signed(datatype) ? INT32_MIN : 0) : \
+ (sizeof(datatype) >= 2) ? (is_signed(datatype) ? INT16_MIN : 0) : \
+ (is_signed(datatype) ? INT8_MIN : 0) \
+)
+
+#define TAINT_WARN 0
+#define test_taint(x) (0)
+
+/*
+ * Checking if an option is defined would be easy if we could do CPP inside CPP.
+ * The defined case whether -Dxxx or -Dxxx=1 are easy to deal with. In either
+ * case the defined value is "1". A more general -Dxxx=<c> case will require
+ * more effort to deal with all possible "true" values. Hope we do not have
+ * to do this as well.
+ * The real problem is the undefined case. To avoid this problem we do the
+ * concat/varargs trick: "yyy" ## xxx can make two arguments if xxx is "1"
+ * by having a #define for yyy_1 which is "ignore,".
+ * Otherwise we will just get "yyy".
+ * Need to be careful about variable substitutions in macros though.
+ * This way we make a (true, false) problem a (don't care, true, false) or a
+ * (don't care true, false). Then we can use a variadic macro to only select
+ * the always well known and defined argument #2. And that seems to be
+ * exactly what we need. Use 1 for true and 0 for false to also allow
+ * #if IS_*() checks pre-compiler checks which do not like #if true.
+ */
+#define ___XAB_1 dontcare,
+#define ___IS_XAB(_ignore, _x, ...) (_x)
+#define __IS_XAB(_x) ___IS_XAB(_x 1, 0)
+#define _IS_XAB(_x) __IS_XAB(__CONCAT(___XAB_, _x))
+
+/* This is if CONFIG_ccc=y. */
+#define IS_BUILTIN(_x) _IS_XAB(_x)
+/* This is if CONFIG_ccc=m. */
+#define IS_MODULE(_x) _IS_XAB(_x ## _MODULE)
+/* This is if CONFIG_ccc is compiled in(=y) or a module(=m). */
+#define IS_ENABLED(_x) (IS_BUILTIN(_x) || IS_MODULE(_x))
+/*
+ * This is weird case. If the CONFIG_ccc is builtin (=y) this returns true;
+ * or if the CONFIG_ccc is a module (=m) and the caller is built as a module
+ * (-DMODULE defined) this returns true, but if the callers is not a module
+ * (-DMODULE not defined, which means caller is BUILTIN) then it returns
+ * false. In other words, a module can reach the kernel, a module can reach
+ * a module, but the kernel cannot reach a module, and code never compiled
+ * cannot be reached either.
+ * XXX -- I'd hope the module-to-module case would be handled by a proper
+ * module dependency definition (MODULE_DEPEND() in FreeBSD).
+ */
+#define IS_REACHABLE(_x) (IS_BUILTIN(_x) || \
+ (IS_MODULE(_x) && IS_BUILTIN(MODULE)))
+
+#endif /* _LINUX_KERNEL_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/kmod.h b/sys/compat/linuxkpi/common/include/linux/kmod.h
new file mode 100644
index 000000000000..b8a1a8b677ed
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/kmod.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_KMOD_H_
+#define _LINUX_KMOD_H_
+
+#include <sys/types.h>
+#include <sys/syscallsubr.h>
+#include <sys/refcount.h>
+#include <sys/sbuf.h>
+#include <machine/stdarg.h>
+#include <sys/proc.h>
+
+#define request_module(...) \
+({\
+ char modname[128]; \
+ int fileid; \
+ snprintf(modname, sizeof(modname), __VA_ARGS__); \
+ kern_kldload(curthread, modname, &fileid); \
+})
+
+#define request_module_nowait request_module
+
+#endif /* _LINUX_KMOD_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/kobject.h b/sys/compat/linuxkpi/common/include/linux/kobject.h
new file mode 100644
index 000000000000..403ec1495c32
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/kobject.h
@@ -0,0 +1,168 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_KOBJECT_H_
+#define _LINUX_KOBJECT_H_
+
+#include <machine/stdarg.h>
+
+#include <linux/kernel.h>
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+
+struct kobject;
+struct sysctl_oid;
+
+#define KOBJ_CHANGE 0x01
+
+struct kobj_type {
+ void (*release)(struct kobject *kobj);
+ const struct sysfs_ops *sysfs_ops;
+ struct attribute **default_attrs;
+};
+
+extern const struct kobj_type linux_kfree_type;
+
+struct kobject {
+ struct kobject *parent;
+ char *name;
+ struct kref kref;
+ const struct kobj_type *ktype;
+ struct list_head entry;
+ struct sysctl_oid *oidp;
+};
+
+extern struct kobject *mm_kobj;
+
+struct attribute {
+ const char *name;
+ struct module *owner;
+ mode_t mode;
+};
+
+struct kobj_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf);
+ ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count);
+};
+
+static inline void
+kobject_init(struct kobject *kobj, const struct kobj_type *ktype)
+{
+
+ kref_init(&kobj->kref);
+ INIT_LIST_HEAD(&kobj->entry);
+ kobj->ktype = ktype;
+ kobj->oidp = NULL;
+}
+
+void linux_kobject_release(struct kref *kref);
+
+static inline void
+kobject_put(struct kobject *kobj)
+{
+
+ if (kobj)
+ kref_put(&kobj->kref, linux_kobject_release);
+}
+
+static inline struct kobject *
+kobject_get(struct kobject *kobj)
+{
+
+ if (kobj)
+ kref_get(&kobj->kref);
+ return kobj;
+}
+
+int kobject_set_name_vargs(struct kobject *kobj, const char *fmt, va_list);
+int kobject_add(struct kobject *kobj, struct kobject *parent,
+ const char *fmt, ...);
+
+static inline struct kobject *
+kobject_create(void)
+{
+ struct kobject *kobj;
+
+ kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
+ if (kobj == NULL)
+ return (NULL);
+ kobject_init(kobj, &linux_kfree_type);
+
+ return (kobj);
+}
+
+static inline struct kobject *
+kobject_create_and_add(const char *name, struct kobject *parent)
+{
+ struct kobject *kobj;
+
+ kobj = kobject_create();
+ if (kobj == NULL)
+ return (NULL);
+ if (kobject_add(kobj, parent, "%s", name) == 0)
+ return (kobj);
+ kobject_put(kobj);
+
+ return (NULL);
+}
+
+static inline void
+kobject_del(struct kobject *kobj __unused)
+{
+}
+
+static inline char *
+kobject_name(const struct kobject *kobj)
+{
+
+ return kobj->name;
+}
+
+int kobject_set_name(struct kobject *kobj, const char *fmt, ...);
+int kobject_init_and_add(struct kobject *kobj, const struct kobj_type *ktype,
+ struct kobject *parent, const char *fmt, ...);
+
+static __inline void
+kobject_uevent_env(struct kobject *kobj, int action, char *envp[])
+{
+
+ /*
+ * iwlwifi(4) sends an INACCESSIBLE event when it detects that the card
+ * (pice endpoint) is gone and it attempts a removal cleanup.
+ * Not sure if we do anything related to udev/sysfs at the moment or
+ * need a shortcut or simply ignore it (for now).
+ */
+}
+
+#endif /* _LINUX_KOBJECT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/kref.h b/sys/compat/linuxkpi/common/include/linux/kref.h
new file mode 100644
index 000000000000..d5b45ba59313
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/kref.h
@@ -0,0 +1,131 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2015 Mellanox Technologies, Ltd.
+ * Copyright (c) 2013 François Tigeot
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_KREF_H_
+#define _LINUX_KREF_H_
+
+#include <sys/types.h>
+#include <sys/refcount.h>
+
+#include <linux/compiler.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/refcount.h>
+
+#include <asm/atomic.h>
+
+struct kref {
+ atomic_t refcount;
+};
+
+static inline void
+kref_init(struct kref *kref)
+{
+
+ refcount_init(&kref->refcount.counter, 1);
+}
+
+static inline unsigned int
+kref_read(const struct kref *kref)
+{
+
+ return (atomic_read(&kref->refcount));
+}
+
+static inline void
+kref_get(struct kref *kref)
+{
+
+ refcount_acquire(&kref->refcount.counter);
+}
+
+static inline int
+kref_put(struct kref *kref, void (*rel)(struct kref *kref))
+{
+
+ if (refcount_release(&kref->refcount.counter)) {
+ rel(kref);
+ return 1;
+ }
+ return 0;
+}
+
+static inline int
+kref_put_lock(struct kref *kref, void (*rel)(struct kref *kref),
+ spinlock_t *lock)
+{
+
+ if (refcount_release(&kref->refcount.counter)) {
+ spin_lock(lock);
+ rel(kref);
+ return (1);
+ }
+ return (0);
+}
+
+static inline int
+kref_sub(struct kref *kref, unsigned int count,
+ void (*rel)(struct kref *kref))
+{
+
+ while (count--) {
+ if (refcount_release(&kref->refcount.counter)) {
+ rel(kref);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static inline int __must_check
+kref_get_unless_zero(struct kref *kref)
+{
+
+ return atomic_add_unless(&kref->refcount, 1, 0);
+}
+
+static inline int kref_put_mutex(struct kref *kref,
+ void (*release)(struct kref *kref), struct mutex *lock)
+{
+ WARN_ON(release == NULL);
+ if (unlikely(!atomic_add_unless(&kref->refcount, -1, 1))) {
+ mutex_lock(lock);
+ if (unlikely(!atomic_dec_and_test(&kref->refcount))) {
+ mutex_unlock(lock);
+ return 0;
+ }
+ release(kref);
+ return 1;
+ }
+ return 0;
+}
+
+#endif /* _LINUX_KREF_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/kthread.h b/sys/compat/linuxkpi/common/include/linux/kthread.h
new file mode 100644
index 000000000000..3afd21dc9356
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/kthread.h
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_KTHREAD_H_
+#define _LINUX_KTHREAD_H_
+
+#include <linux/sched.h>
+
+#include <sys/unistd.h>
+#include <sys/kthread.h>
+
+#define kthread_run(fn, data, fmt, ...) ({ \
+ struct task_struct *__task; \
+ struct thread *__td; \
+ \
+ if (kthread_add(linux_kthread_fn, NULL, NULL, &__td, \
+ RFSTOPPED, 0, fmt, ## __VA_ARGS__)) \
+ __task = NULL; \
+ else \
+ __task = linux_kthread_setup_and_run(__td, fn, data); \
+ __task; \
+})
+
+int linux_kthread_stop(struct task_struct *);
+bool linux_kthread_should_stop_task(struct task_struct *);
+bool linux_kthread_should_stop(void);
+int linux_kthread_park(struct task_struct *);
+void linux_kthread_parkme(void);
+bool linux_kthread_should_park(void);
+void linux_kthread_unpark(struct task_struct *);
+void linux_kthread_fn(void *);
+struct task_struct *linux_kthread_setup_and_run(struct thread *,
+ linux_task_fn_t *, void *arg);
+int linux_in_atomic(void);
+
+#define kthread_stop(task) linux_kthread_stop(task)
+#define kthread_should_stop() linux_kthread_should_stop()
+#define kthread_should_stop_task(task) linux_kthread_should_stop_task(task)
+#define kthread_park(task) linux_kthread_park(task)
+#define kthread_parkme() linux_kthread_parkme()
+#define kthread_should_park() linux_kthread_should_park()
+#define kthread_unpark(task) linux_kthread_unpark(task)
+
+#define in_atomic() linux_in_atomic()
+
+#endif /* _LINUX_KTHREAD_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/ktime.h b/sys/compat/linuxkpi/common/include/linux/ktime.h
new file mode 100644
index 000000000000..e480de3181a9
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/ktime.h
@@ -0,0 +1,259 @@
+/*-
+ * Copyright (c) 2018 Limelight Networks, Inc.
+ * Copyright (c) 2014-2018 Mellanox Technologies, Ltd.
+ * Copyright (c) 2015 François Tigeot
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_KTIME_H
+#define _LINUX_KTIME_H
+
+#include <linux/types.h>
+#include <linux/time.h>
+#include <linux/jiffies.h>
+
+/* time values in nanoseconds */
+typedef s64 ktime_t;
+
+#define KTIME_MAX ((s64)~((u64)1 << 63))
+#define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC)
+
+static inline int64_t
+ktime_to_ns(ktime_t kt)
+{
+ return (kt);
+}
+
+static inline ktime_t
+ns_to_ktime(uint64_t nsec)
+{
+ return (nsec);
+}
+
+static inline int64_t
+ktime_divns(const ktime_t kt, int64_t div)
+{
+ return (kt / div);
+}
+
+static inline int64_t
+ktime_to_us(ktime_t kt)
+{
+ return (ktime_divns(kt, NSEC_PER_USEC));
+}
+
+static inline int64_t
+ktime_to_ms(ktime_t kt)
+{
+ return (ktime_divns(kt, NSEC_PER_MSEC));
+}
+
+static inline struct timeval
+ktime_to_timeval(ktime_t kt)
+{
+ return (ns_to_timeval(kt));
+}
+
+static inline ktime_t
+ktime_add_ns(ktime_t kt, int64_t ns)
+{
+ return (kt + ns);
+}
+
+static inline ktime_t
+ktime_add_ms(ktime_t kt, int64_t ms)
+{
+
+ return (ktime_add_ns(kt, ms * NSEC_PER_MSEC));
+}
+
+static inline ktime_t
+ktime_add_us(ktime_t kt, int64_t us)
+{
+
+ return (ktime_add_ns(kt, us * NSEC_PER_USEC));
+}
+
+static inline ktime_t
+ktime_sub_ns(ktime_t kt, int64_t ns)
+{
+ return (kt - ns);
+}
+
+static inline ktime_t
+ktime_set(const long secs, const unsigned long nsecs)
+{
+ ktime_t retval = {(s64) secs * NSEC_PER_SEC + (s64) nsecs};
+
+ return (retval);
+}
+
+static inline ktime_t
+ktime_sub(ktime_t lhs, ktime_t rhs)
+{
+ return (lhs - rhs);
+}
+
+static inline int64_t
+ktime_us_delta(ktime_t later, ktime_t earlier)
+{
+ ktime_t diff = ktime_sub(later, earlier);
+
+ return (ktime_to_us(diff));
+}
+
+static inline int64_t
+ktime_ms_delta(ktime_t later, ktime_t earlier)
+{
+ ktime_t diff = ktime_sub(later, earlier);
+
+ return (ktime_to_ms(diff));
+}
+
+static inline ktime_t
+ktime_add(ktime_t lhs, ktime_t rhs)
+{
+ return (lhs + rhs);
+}
+
+static inline int
+ktime_compare(const ktime_t cmp1, const ktime_t cmp2)
+{
+
+ if (cmp1 > cmp2)
+ return (1);
+ else if (cmp1 < cmp2)
+ return (-1);
+ else
+ return (0);
+}
+
+static inline bool
+ktime_after(const ktime_t cmp1, const ktime_t cmp2)
+{
+
+ return (ktime_compare(cmp1, cmp2) > 0);
+}
+
+static inline bool
+ktime_before(const ktime_t cmp1, const ktime_t cmp2)
+{
+
+ return (ktime_compare(cmp1, cmp2) < 0);
+}
+
+static inline ktime_t
+timespec_to_ktime(struct timespec ts)
+{
+ return (ktime_set(ts.tv_sec, ts.tv_nsec));
+}
+
+static inline ktime_t
+timeval_to_ktime(struct timeval tv)
+{
+ return (ktime_set(tv.tv_sec, tv.tv_usec * NSEC_PER_USEC));
+}
+
+static inline int64_t
+timespec64_to_ns(struct timespec64 *ts)
+{
+ return (timespec_to_ns(ts));
+}
+
+#define ktime_to_timespec(kt) ns_to_timespec(kt)
+#define ktime_to_timespec64(kt) ns_to_timespec(kt)
+#define ktime_to_timeval(kt) ns_to_timeval(kt)
+#define ktime_to_ns(kt) (kt)
+#define ktime_get_ts(ts) getnanouptime(ts)
+#define ktime_get_ts64(ts) getnanouptime(ts)
+#define ktime_get_raw_ts64(ts) getnanouptime(ts)
+#define getrawmonotonic64(ts) getnanouptime(ts)
+
+static inline int64_t
+ktime_get_ns(void)
+{
+ struct timespec ts;
+
+ ktime_get_ts(&ts);
+
+ return (ktime_to_ns(timespec_to_ktime(ts)));
+}
+
+static inline ktime_t
+ktime_get(void)
+{
+ struct timespec ts;
+
+ ktime_get_ts(&ts);
+ return (timespec_to_ktime(ts));
+}
+
+static inline ktime_t
+ktime_get_boottime(void)
+{
+ struct timespec ts;
+
+ nanouptime(&ts);
+ return (timespec_to_ktime(ts));
+}
+
+static inline ktime_t
+ktime_get_real(void)
+{
+ struct timespec ts;
+
+ nanotime(&ts);
+ return (timespec_to_ktime(ts));
+}
+
+static inline ktime_t
+ktime_get_real_seconds(void)
+{
+ struct timespec ts;
+
+ nanotime(&ts);
+ return (ts.tv_sec);
+}
+
+static inline ktime_t
+ktime_get_raw(void)
+{
+ struct timespec ts;
+
+ nanouptime(&ts);
+ return (timespec_to_ktime(ts));
+}
+
+static inline u64
+ktime_get_raw_ns(void)
+{
+ struct timespec ts;
+
+ nanouptime(&ts);
+ return (ktime_to_ns(timespec_to_ktime(ts)));
+}
+
+#endif /* _LINUX_KTIME_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/list.h b/sys/compat/linuxkpi/common/include/linux/list.h
new file mode 100644
index 000000000000..1f3db8e43a08
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/list.h
@@ -0,0 +1,498 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_LIST_H_
+#define _LINUX_LIST_H_
+
+#ifndef _STANDALONE
+/*
+ * Since LIST_HEAD conflicts with the Linux definition we must include any
+ * FreeBSD header which requires it here so it is resolved with the correct
+ * definition prior to the undef.
+ */
+#include <linux/types.h>
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/cpuset.h>
+#include <sys/jail.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/conf.h>
+#include <sys/socket.h>
+#include <sys/mbuf.h>
+
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_types.h>
+#include <net/if_media.h>
+#include <net/vnet.h>
+
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+#include <netinet/in_var.h>
+#include <netinet/tcp_lro.h>
+
+#include <netinet6/in6_var.h>
+#include <netinet6/nd6.h>
+
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/pmap.h>
+#endif
+
+#ifndef prefetch
+#define prefetch(x)
+#endif
+
+#define LINUX_LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LINUX_LIST_HEAD(name) \
+ struct list_head name = LINUX_LIST_HEAD_INIT(name)
+
+#ifndef LIST_HEAD_DEF
+#define LIST_HEAD_DEF
+struct list_head {
+ struct list_head *next;
+ struct list_head *prev;
+};
+#endif
+
+static inline void
+INIT_LIST_HEAD(struct list_head *list)
+{
+
+ list->next = list->prev = list;
+}
+
+static inline int
+list_empty(const struct list_head *head)
+{
+
+ return (head->next == head);
+}
+
+static inline int
+list_empty_careful(const struct list_head *head)
+{
+ struct list_head *next = head->next;
+
+ return ((next == head) && (next == head->prev));
+}
+
+static inline void
+__list_del(struct list_head *prev, struct list_head *next)
+{
+ next->prev = prev;
+ WRITE_ONCE(prev->next, next);
+}
+
+static inline void
+__list_del_entry(struct list_head *entry)
+{
+
+ __list_del(entry->prev, entry->next);
+}
+
+static inline void
+list_del(struct list_head *entry)
+{
+
+ __list_del(entry->prev, entry->next);
+}
+
+static inline void
+list_replace(struct list_head *old, struct list_head *new)
+{
+ new->next = old->next;
+ new->next->prev = new;
+ new->prev = old->prev;
+ new->prev->next = new;
+}
+
+static inline void
+list_replace_init(struct list_head *old, struct list_head *new)
+{
+ list_replace(old, new);
+ INIT_LIST_HEAD(old);
+}
+
+static inline void
+linux_list_add(struct list_head *new, struct list_head *prev,
+ struct list_head *next)
+{
+
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+static inline void
+list_del_init(struct list_head *entry)
+{
+
+ list_del(entry);
+ INIT_LIST_HEAD(entry);
+}
+
+#define list_entry(ptr, type, field) container_of(ptr, type, field)
+
+#define list_first_entry(ptr, type, member) \
+ list_entry((ptr)->next, type, member)
+
+#define list_last_entry(ptr, type, member) \
+ list_entry((ptr)->prev, type, member)
+
+#define list_first_entry_or_null(ptr, type, member) \
+ (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL)
+
+#define list_next_entry(ptr, member) \
+ list_entry(((ptr)->member.next), typeof(*(ptr)), member)
+
+#define list_safe_reset_next(ptr, n, member) \
+ (n) = list_next_entry(ptr, member)
+
+#define list_prev_entry(ptr, member) \
+ list_entry(((ptr)->member.prev), typeof(*(ptr)), member)
+
+#define list_for_each(p, head) \
+ for (p = (head)->next; p != (head); p = (p)->next)
+
+#define list_for_each_safe(p, n, head) \
+ for (p = (head)->next, n = (p)->next; p != (head); p = n, n = (p)->next)
+
+#define list_for_each_entry(p, h, field) \
+ for (p = list_entry((h)->next, typeof(*p), field); &(p)->field != (h); \
+ p = list_entry((p)->field.next, typeof(*p), field))
+
+#define list_for_each_entry_safe(p, n, h, field) \
+ for (p = list_entry((h)->next, typeof(*p), field), \
+ n = list_entry((p)->field.next, typeof(*p), field); &(p)->field != (h);\
+ p = n, n = list_entry(n->field.next, typeof(*n), field))
+
+#define list_for_each_entry_from(p, h, field) \
+ for ( ; &(p)->field != (h); \
+ p = list_entry((p)->field.next, typeof(*p), field))
+
+#define list_for_each_entry_continue(p, h, field) \
+ for (p = list_next_entry((p), field); &(p)->field != (h); \
+ p = list_next_entry((p), field))
+
+#define list_for_each_entry_safe_from(pos, n, head, member) \
+ for (n = list_entry((pos)->member.next, typeof(*pos), member); \
+ &(pos)->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+#define list_for_each_entry_reverse(p, h, field) \
+ for (p = list_entry((h)->prev, typeof(*p), field); &(p)->field != (h); \
+ p = list_entry((p)->field.prev, typeof(*p), field))
+
+#define list_for_each_entry_safe_reverse(p, n, h, field) \
+ for (p = list_entry((h)->prev, typeof(*p), field), \
+ n = list_entry((p)->field.prev, typeof(*p), field); &(p)->field != (h); \
+ p = n, n = list_entry(n->field.prev, typeof(*n), field))
+
+#define list_for_each_entry_continue_reverse(p, h, field) \
+ for (p = list_entry((p)->field.prev, typeof(*p), field); &(p)->field != (h); \
+ p = list_entry((p)->field.prev, typeof(*p), field))
+
+#define list_for_each_prev(p, h) for (p = (h)->prev; p != (h); p = (p)->prev)
+
+#define list_for_each_entry_from_reverse(p, h, field) \
+ for (; &p->field != (h); \
+ p = list_prev_entry(p, field))
+
+static inline void
+list_add(struct list_head *new, struct list_head *head)
+{
+
+ linux_list_add(new, head, head->next);
+}
+
+static inline void
+list_add_tail(struct list_head *new, struct list_head *head)
+{
+
+ linux_list_add(new, head->prev, head);
+}
+
+static inline void
+list_move(struct list_head *list, struct list_head *head)
+{
+
+ list_del(list);
+ list_add(list, head);
+}
+
+static inline void
+list_move_tail(struct list_head *entry, struct list_head *head)
+{
+
+ list_del(entry);
+ list_add_tail(entry, head);
+}
+
+static inline void
+list_bulk_move_tail(struct list_head *head, struct list_head *first,
+ struct list_head *last)
+{
+ first->prev->next = last->next;
+ last->next->prev = first->prev;
+ head->prev->next = first;
+ first->prev = head->prev;
+ last->next = head;
+ head->prev = last;
+}
+
+static inline void
+linux_list_splice(const struct list_head *list, struct list_head *prev,
+ struct list_head *next)
+{
+ struct list_head *first;
+ struct list_head *last;
+
+ if (list_empty(list))
+ return;
+ first = list->next;
+ last = list->prev;
+ first->prev = prev;
+ prev->next = first;
+ last->next = next;
+ next->prev = last;
+}
+
+static inline void
+list_splice(const struct list_head *list, struct list_head *head)
+{
+
+ linux_list_splice(list, head, head->next);
+}
+
+static inline void
+list_splice_tail(struct list_head *list, struct list_head *head)
+{
+
+ linux_list_splice(list, head->prev, head);
+}
+
+static inline void
+list_splice_init(struct list_head *list, struct list_head *head)
+{
+
+ linux_list_splice(list, head, head->next);
+ INIT_LIST_HEAD(list);
+}
+
+static inline void
+list_splice_tail_init(struct list_head *list, struct list_head *head)
+{
+
+ linux_list_splice(list, head->prev, head);
+ INIT_LIST_HEAD(list);
+}
+
+#undef LIST_HEAD
+#define LIST_HEAD(name) struct list_head name = { &(name), &(name) }
+
+struct hlist_head {
+ struct hlist_node *first;
+};
+
+struct hlist_node {
+ struct hlist_node *next, **pprev;
+};
+#define HLIST_HEAD_INIT { }
+#define HLIST_HEAD(name) struct hlist_head name = HLIST_HEAD_INIT
+#define INIT_HLIST_HEAD(head) (head)->first = NULL
+#define INIT_HLIST_NODE(node) \
+do { \
+ (node)->next = NULL; \
+ (node)->pprev = NULL; \
+} while (0)
+
+static inline int
+hlist_unhashed(const struct hlist_node *h)
+{
+
+ return !h->pprev;
+}
+
+static inline int
+hlist_empty(const struct hlist_head *h)
+{
+
+ return !READ_ONCE(h->first);
+}
+
+static inline void
+hlist_del(struct hlist_node *n)
+{
+
+ WRITE_ONCE(*(n->pprev), n->next);
+ if (n->next != NULL)
+ n->next->pprev = n->pprev;
+}
+
+static inline void
+hlist_del_init(struct hlist_node *n)
+{
+
+ if (hlist_unhashed(n))
+ return;
+ hlist_del(n);
+ INIT_HLIST_NODE(n);
+}
+
+static inline void
+hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+
+ n->next = h->first;
+ if (h->first != NULL)
+ h->first->pprev = &n->next;
+ WRITE_ONCE(h->first, n);
+ n->pprev = &h->first;
+}
+
+static inline void
+hlist_add_before(struct hlist_node *n, struct hlist_node *next)
+{
+
+ n->pprev = next->pprev;
+ n->next = next;
+ next->pprev = &n->next;
+ WRITE_ONCE(*(n->pprev), n);
+}
+
+static inline void
+hlist_add_behind(struct hlist_node *n, struct hlist_node *prev)
+{
+
+ n->next = prev->next;
+ WRITE_ONCE(prev->next, n);
+ n->pprev = &prev->next;
+
+ if (n->next != NULL)
+ n->next->pprev = &n->next;
+}
+
+static inline void
+hlist_move_list(struct hlist_head *old, struct hlist_head *new)
+{
+
+ new->first = old->first;
+ if (new->first)
+ new->first->pprev = &new->first;
+ old->first = NULL;
+}
+
+static inline int list_is_singular(const struct list_head *head)
+{
+ return !list_empty(head) && (head->next == head->prev);
+}
+
+static inline void __list_cut_position(struct list_head *list,
+ struct list_head *head, struct list_head *entry)
+{
+ struct list_head *new_first = entry->next;
+ list->next = head->next;
+ list->next->prev = list;
+ list->prev = entry;
+ entry->next = list;
+ head->next = new_first;
+ new_first->prev = head;
+}
+
+static inline void list_cut_position(struct list_head *list,
+ struct list_head *head, struct list_head *entry)
+{
+ if (list_empty(head))
+ return;
+ if (list_is_singular(head) &&
+ (head->next != entry && head != entry))
+ return;
+ if (entry == head)
+ INIT_LIST_HEAD(list);
+ else
+ __list_cut_position(list, head, entry);
+}
+
+static inline int list_is_first(const struct list_head *list,
+ const struct list_head *head)
+{
+
+ return (list->prev == head);
+}
+
+static inline int list_is_last(const struct list_head *list,
+ const struct list_head *head)
+{
+ return list->next == head;
+}
+
+#define hlist_entry(ptr, type, field) container_of(ptr, type, field)
+
+#define hlist_for_each(p, head) \
+ for (p = (head)->first; p; p = (p)->next)
+
+#define hlist_for_each_safe(p, n, head) \
+ for (p = (head)->first; p && ({ n = (p)->next; 1; }); p = n)
+
+#define hlist_entry_safe(ptr, type, member) \
+ ((ptr) ? hlist_entry(ptr, type, member) : NULL)
+
+#define hlist_for_each_entry(pos, head, member) \
+ for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
+ pos; \
+ pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
+
+#define hlist_for_each_entry_continue(pos, member) \
+ for (pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member); \
+ (pos); \
+ pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
+
+#define hlist_for_each_entry_from(pos, member) \
+ for (; (pos); \
+ pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
+
+#define hlist_for_each_entry_safe(pos, n, head, member) \
+ for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member); \
+ (pos) && ({ n = (pos)->member.next; 1; }); \
+ pos = hlist_entry_safe(n, typeof(*(pos)), member))
+
+extern void list_sort(void *priv, struct list_head *head, int (*cmp)(void *priv,
+ struct list_head *a, struct list_head *b));
+
+#endif /* _LINUX_LIST_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/llist.h b/sys/compat/linuxkpi/common/include/linux/llist.h
new file mode 100644
index 000000000000..b3c89516e710
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/llist.h
@@ -0,0 +1,101 @@
+/* Public domain. */
+
+#ifndef _LINUX_LLIST_H
+#define _LINUX_LLIST_H
+
+#include <sys/types.h>
+#include <machine/atomic.h>
+
+struct llist_node {
+ struct llist_node *next;
+};
+
+struct llist_head {
+ struct llist_node *first;
+};
+
+#define LLIST_HEAD_INIT(name) { NULL }
+#define LLIST_HEAD(name) struct llist_head name = LLIST_HEAD_INIT(name)
+
+#define llist_entry(ptr, type, member) \
+ ((ptr) ? container_of(ptr, type, member) : NULL)
+
+static inline struct llist_node *
+llist_del_all(struct llist_head *head)
+{
+ return ((void *)atomic_readandclear_ptr((uintptr_t *)&head->first));
+}
+
+static inline struct llist_node *
+llist_del_first(struct llist_head *head)
+{
+ struct llist_node *first, *next;
+
+ do {
+ first = head->first;
+ if (first == NULL)
+ return NULL;
+ next = first->next;
+ } while (atomic_cmpset_ptr((uintptr_t *)&head->first,
+ (uintptr_t)first, (uintptr_t)next) == 0);
+
+ return (first);
+}
+
+static inline bool
+llist_add(struct llist_node *new, struct llist_head *head)
+{
+ struct llist_node *first;
+
+ do {
+ new->next = first = head->first;
+ } while (atomic_cmpset_ptr((uintptr_t *)&head->first,
+ (uintptr_t)first, (uintptr_t)new) == 0);
+
+ return (first == NULL);
+}
+
+static inline bool
+llist_add_batch(struct llist_node *new_first, struct llist_node *new_last,
+ struct llist_head *head)
+{
+ struct llist_node *first;
+
+ do {
+ new_last->next = first = head->first;
+ } while (atomic_cmpset_ptr((uintptr_t *)&head->first,
+ (uintptr_t)first, (uintptr_t)new_first) == 0);
+
+ return (first == NULL);
+}
+
+static inline void
+init_llist_head(struct llist_head *head)
+{
+ head->first = NULL;
+}
+
+static inline bool
+llist_empty(struct llist_head *head)
+{
+ return (head->first == NULL);
+}
+
+#define llist_for_each_safe(pos, n, node) \
+ for ((pos) = (node); \
+ (pos) != NULL && \
+ ((n) = (pos)->next, pos); \
+ (pos) = (n))
+
+#define llist_for_each_entry_safe(pos, n, node, member) \
+ for (pos = llist_entry((node), __typeof(*pos), member); \
+ pos != NULL && \
+ (n = llist_entry(pos->member.next, __typeof(*pos), member), pos); \
+ pos = n)
+
+#define llist_for_each_entry(pos, node, member) \
+ for ((pos) = llist_entry((node), __typeof(*(pos)), member); \
+ (pos) != NULL; \
+ (pos) = llist_entry((pos)->member.next, __typeof(*(pos)), member))
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/lockdep.h b/sys/compat/linuxkpi/common/include/linux/lockdep.h
new file mode 100644
index 000000000000..a86157ba5924
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/lockdep.h
@@ -0,0 +1,88 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_LOCKDEP_H_
+#define _LINUX_LOCKDEP_H_
+
+#include <sys/lock.h>
+
+struct lock_class_key {
+};
+
+#define lockdep_set_class(lock, key)
+#define lockdep_set_subclass(lock, sub)
+#define lockdep_set_class_and_name(lock, key, name)
+#define lockdep_set_current_reclaim_state(g) do { } while (0)
+#define lockdep_clear_current_reclaim_state() do { } while (0)
+#define lockdep_init_map(_map, _name, _key, _x) do { } while(0)
+
+#ifdef INVARIANTS
+#define lockdep_assert_held(m) do { \
+ struct lock_object *__lock = (struct lock_object *)(m); \
+ LOCK_CLASS(__lock)->lc_assert(__lock, LA_LOCKED); \
+} while (0)
+
+#define lockdep_assert_held_once(m) do { \
+ struct lock_object *__lock = (struct lock_object *)(m); \
+ LOCK_CLASS(__lock)->lc_assert(__lock, LA_LOCKED | LA_NOTRECURSED); \
+} while (0)
+
+static __inline bool
+lockdep_is_held(void *__m)
+{
+ struct lock_object *__lock;
+ struct thread *__td;
+
+ __lock = __m;
+ return (LOCK_CLASS(__lock)->lc_owner(__lock, &__td) != 0);
+}
+#define lockdep_is_held_type(_m, _t) lockdep_is_held(_m)
+
+#else
+#define lockdep_assert_held(m) do { } while (0)
+
+#define lockdep_assert_held_once(m) do { } while (0)
+
+#define lockdep_is_held(m) 1
+#define lockdep_is_held_type(_m, _t) 1
+#endif
+
+#define might_lock(m) do { } while (0)
+#define might_lock_read(m) do { } while (0)
+
+#define lock_acquire(...) do { } while (0)
+#define lock_release(...) do { } while (0)
+#define lock_acquire_shared_recursive(...) do { } while (0)
+
+#define mutex_acquire(...) do { } while (0)
+#define mutex_release(...) do { } while (0)
+
+#endif /* _LINUX_LOCKDEP_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/log2.h b/sys/compat/linuxkpi/common/include/linux/log2.h
new file mode 100644
index 000000000000..d79eedf38176
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/log2.h
@@ -0,0 +1,131 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2015 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_LOG2_H_
+#define _LINUX_LOG2_H_
+
+#include <linux/types.h>
+
+#include <sys/libkern.h>
+
+static inline unsigned long
+roundup_pow_of_two(unsigned long x)
+{
+ return (1UL << flsl(x - 1));
+}
+
+static inline int
+is_power_of_2(unsigned long n)
+{
+ return (n == roundup_pow_of_two(n));
+}
+
+static inline unsigned long
+rounddown_pow_of_two(unsigned long x)
+{
+ return (1UL << (flsl(x) - 1));
+}
+
+#define ilog2(n) \
+( \
+ __builtin_constant_p(n) ? ( \
+ (n) < 1 ? -1 : \
+ (n) & (1ULL << 63) ? 63 : \
+ (n) & (1ULL << 62) ? 62 : \
+ (n) & (1ULL << 61) ? 61 : \
+ (n) & (1ULL << 60) ? 60 : \
+ (n) & (1ULL << 59) ? 59 : \
+ (n) & (1ULL << 58) ? 58 : \
+ (n) & (1ULL << 57) ? 57 : \
+ (n) & (1ULL << 56) ? 56 : \
+ (n) & (1ULL << 55) ? 55 : \
+ (n) & (1ULL << 54) ? 54 : \
+ (n) & (1ULL << 53) ? 53 : \
+ (n) & (1ULL << 52) ? 52 : \
+ (n) & (1ULL << 51) ? 51 : \
+ (n) & (1ULL << 50) ? 50 : \
+ (n) & (1ULL << 49) ? 49 : \
+ (n) & (1ULL << 48) ? 48 : \
+ (n) & (1ULL << 47) ? 47 : \
+ (n) & (1ULL << 46) ? 46 : \
+ (n) & (1ULL << 45) ? 45 : \
+ (n) & (1ULL << 44) ? 44 : \
+ (n) & (1ULL << 43) ? 43 : \
+ (n) & (1ULL << 42) ? 42 : \
+ (n) & (1ULL << 41) ? 41 : \
+ (n) & (1ULL << 40) ? 40 : \
+ (n) & (1ULL << 39) ? 39 : \
+ (n) & (1ULL << 38) ? 38 : \
+ (n) & (1ULL << 37) ? 37 : \
+ (n) & (1ULL << 36) ? 36 : \
+ (n) & (1ULL << 35) ? 35 : \
+ (n) & (1ULL << 34) ? 34 : \
+ (n) & (1ULL << 33) ? 33 : \
+ (n) & (1ULL << 32) ? 32 : \
+ (n) & (1ULL << 31) ? 31 : \
+ (n) & (1ULL << 30) ? 30 : \
+ (n) & (1ULL << 29) ? 29 : \
+ (n) & (1ULL << 28) ? 28 : \
+ (n) & (1ULL << 27) ? 27 : \
+ (n) & (1ULL << 26) ? 26 : \
+ (n) & (1ULL << 25) ? 25 : \
+ (n) & (1ULL << 24) ? 24 : \
+ (n) & (1ULL << 23) ? 23 : \
+ (n) & (1ULL << 22) ? 22 : \
+ (n) & (1ULL << 21) ? 21 : \
+ (n) & (1ULL << 20) ? 20 : \
+ (n) & (1ULL << 19) ? 19 : \
+ (n) & (1ULL << 18) ? 18 : \
+ (n) & (1ULL << 17) ? 17 : \
+ (n) & (1ULL << 16) ? 16 : \
+ (n) & (1ULL << 15) ? 15 : \
+ (n) & (1ULL << 14) ? 14 : \
+ (n) & (1ULL << 13) ? 13 : \
+ (n) & (1ULL << 12) ? 12 : \
+ (n) & (1ULL << 11) ? 11 : \
+ (n) & (1ULL << 10) ? 10 : \
+ (n) & (1ULL << 9) ? 9 : \
+ (n) & (1ULL << 8) ? 8 : \
+ (n) & (1ULL << 7) ? 7 : \
+ (n) & (1ULL << 6) ? 6 : \
+ (n) & (1ULL << 5) ? 5 : \
+ (n) & (1ULL << 4) ? 4 : \
+ (n) & (1ULL << 3) ? 3 : \
+ (n) & (1ULL << 2) ? 2 : \
+ (n) & (1ULL << 1) ? 1 : \
+ (n) & (1ULL << 0) ? 0 : \
+ -1) : \
+ (sizeof(n) <= 4) ? \
+ fls((u32)(n)) - 1 : flsll((u64)(n)) - 1 \
+)
+
+#define order_base_2(x) ilog2(roundup_pow_of_two(x))
+
+#endif /* _LINUX_LOG2_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/math64.h b/sys/compat/linuxkpi/common/include/linux/math64.h
new file mode 100644
index 000000000000..a3af81c92c9e
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/math64.h
@@ -0,0 +1,103 @@
+/*-
+ * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2014-2015 Mellanox Technologies, Ltd. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_MATH64_H
+#define _LINUX_MATH64_H
+
+#include <sys/stdint.h>
+
+#define do_div(n, base) ({ \
+ uint32_t __base = (base); \
+ uint32_t __rem; \
+ __rem = ((uint64_t)(n)) % __base; \
+ (n) = ((uint64_t)(n)) / __base; \
+ __rem; \
+})
+
+static inline uint64_t
+div64_u64_rem(uint64_t dividend, uint64_t divisor, uint64_t *remainder)
+{
+
+ *remainder = dividend % divisor;
+ return (dividend / divisor);
+}
+
+static inline int64_t
+div64_s64(int64_t dividend, int64_t divisor)
+{
+
+ return (dividend / divisor);
+}
+
+static inline uint64_t
+div64_u64(uint64_t dividend, uint64_t divisor)
+{
+
+ return (dividend / divisor);
+}
+
+static inline uint64_t
+div_u64_rem(uint64_t dividend, uint32_t divisor, uint32_t *remainder)
+{
+
+ *remainder = dividend % divisor;
+ return (dividend / divisor);
+}
+
+static inline int64_t
+div_s64(int64_t dividend, int32_t divisor)
+{
+
+ return (dividend / divisor);
+}
+
+static inline uint64_t
+div_u64(uint64_t dividend, uint32_t divisor)
+{
+
+ return (dividend / divisor);
+}
+
+static inline uint64_t
+mul_u32_u32(uint32_t a, uint32_t b)
+{
+
+ return ((uint64_t)a * b);
+}
+
+static inline uint64_t
+div64_u64_round_up(uint64_t dividend, uint64_t divisor)
+{
+ return ((dividend + divisor - 1) / divisor);
+}
+
+#define DIV64_U64_ROUND_UP(...) \
+ div64_u64_round_up(__VA_ARGS__)
+
+#endif /* _LINUX_MATH64_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/miscdevice.h b/sys/compat/linuxkpi/common/include/linux/miscdevice.h
new file mode 100644
index 000000000000..26a4a2c049c1
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/miscdevice.h
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_MISCDEVICE_H_
+#define _LINUX_MISCDEVICE_H_
+
+#define MISC_DYNAMIC_MINOR -1
+
+#include <linux/device.h>
+#include <linux/cdev.h>
+
+struct miscdevice {
+ const char *name;
+ struct device *this_device;
+ const struct file_operations *fops;
+ struct cdev *cdev;
+ int minor;
+ const char *nodename;
+ umode_t mode;
+};
+
+extern struct class linux_class_misc;
+
+static inline int
+misc_register(struct miscdevice *misc)
+{
+ misc->this_device = device_create(&linux_class_misc,
+ &linux_root_device, 0, misc, misc->name);
+ misc->cdev = cdev_alloc();
+ if (misc->cdev == NULL)
+ return -ENOMEM;
+ misc->cdev->owner = THIS_MODULE;
+ misc->cdev->ops = misc->fops;
+ kobject_set_name(&misc->cdev->kobj, misc->name);
+ if (cdev_add(misc->cdev, misc->this_device->devt, 1))
+ return -EINVAL;
+ return (0);
+}
+
+static inline int
+misc_deregister(struct miscdevice *misc)
+{
+ device_destroy(&linux_class_misc, misc->this_device->devt);
+ cdev_del(misc->cdev);
+
+ return (0);
+}
+
+#endif /* _LINUX_MISCDEVICE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/mm.h b/sys/compat/linuxkpi/common/include/linux/mm.h
new file mode 100644
index 000000000000..f6f53afbc8a9
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/mm.h
@@ -0,0 +1,266 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * Copyright (c) 2015 François Tigeot
+ * Copyright (c) 2015 Matthew Dillon <dillon@backplane.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_MM_H_
+#define _LINUX_MM_H_
+
+#include <linux/spinlock.h>
+#include <linux/gfp.h>
+#include <linux/kernel.h>
+#include <linux/mm_types.h>
+#include <linux/pfn.h>
+#include <linux/list.h>
+
+#include <asm/pgtable.h>
+
+#define PAGE_ALIGN(x) ALIGN(x, PAGE_SIZE)
+
+/*
+ * Make sure our LinuxKPI defined virtual memory flags don't conflict
+ * with the ones defined by FreeBSD:
+ */
+CTASSERT((VM_PROT_ALL & -(1 << 8)) == 0);
+
+#define VM_READ VM_PROT_READ
+#define VM_WRITE VM_PROT_WRITE
+#define VM_EXEC VM_PROT_EXECUTE
+
+#define VM_PFNINTERNAL (1 << 8) /* FreeBSD private flag to vm_insert_pfn() */
+#define VM_MIXEDMAP (1 << 9)
+#define VM_NORESERVE (1 << 10)
+#define VM_PFNMAP (1 << 11)
+#define VM_IO (1 << 12)
+#define VM_MAYWRITE (1 << 13)
+#define VM_DONTCOPY (1 << 14)
+#define VM_DONTEXPAND (1 << 15)
+#define VM_DONTDUMP (1 << 16)
+
+#define VMA_MAX_PREFAULT_RECORD 1
+
+#define FOLL_WRITE (1 << 0)
+#define FOLL_FORCE (1 << 1)
+
+#define VM_FAULT_OOM (1 << 0)
+#define VM_FAULT_SIGBUS (1 << 1)
+#define VM_FAULT_MAJOR (1 << 2)
+#define VM_FAULT_WRITE (1 << 3)
+#define VM_FAULT_HWPOISON (1 << 4)
+#define VM_FAULT_HWPOISON_LARGE (1 << 5)
+#define VM_FAULT_SIGSEGV (1 << 6)
+#define VM_FAULT_NOPAGE (1 << 7)
+#define VM_FAULT_LOCKED (1 << 8)
+#define VM_FAULT_RETRY (1 << 9)
+#define VM_FAULT_FALLBACK (1 << 10)
+
+#define FAULT_FLAG_WRITE (1 << 0)
+#define FAULT_FLAG_MKWRITE (1 << 1)
+#define FAULT_FLAG_ALLOW_RETRY (1 << 2)
+#define FAULT_FLAG_RETRY_NOWAIT (1 << 3)
+#define FAULT_FLAG_KILLABLE (1 << 4)
+#define FAULT_FLAG_TRIED (1 << 5)
+#define FAULT_FLAG_USER (1 << 6)
+#define FAULT_FLAG_REMOTE (1 << 7)
+#define FAULT_FLAG_INSTRUCTION (1 << 8)
+
+typedef int (*pte_fn_t)(linux_pte_t *, pgtable_t, unsigned long addr, void *data);
+
+struct vm_area_struct {
+ vm_offset_t vm_start;
+ vm_offset_t vm_end;
+ vm_offset_t vm_pgoff;
+ pgprot_t vm_page_prot;
+ unsigned long vm_flags;
+ struct mm_struct *vm_mm;
+ void *vm_private_data;
+ const struct vm_operations_struct *vm_ops;
+ struct linux_file *vm_file;
+
+ /* internal operation */
+ vm_paddr_t vm_pfn; /* PFN for memory map */
+ vm_size_t vm_len; /* length for memory map */
+ vm_pindex_t vm_pfn_first;
+ int vm_pfn_count;
+ int *vm_pfn_pcount;
+ vm_object_t vm_obj;
+ vm_map_t vm_cached_map;
+ TAILQ_ENTRY(vm_area_struct) vm_entry;
+};
+
+struct vm_fault {
+ unsigned int flags;
+ pgoff_t pgoff;
+ union {
+ /* user-space address */
+ void *virtual_address; /* < 4.11 */
+ unsigned long address; /* >= 4.11 */
+ };
+ struct page *page;
+ struct vm_area_struct *vma;
+};
+
+struct vm_operations_struct {
+ void (*open) (struct vm_area_struct *);
+ void (*close) (struct vm_area_struct *);
+ int (*fault) (struct vm_area_struct *, struct vm_fault *);
+ int (*access) (struct vm_area_struct *, unsigned long, void *, int, int);
+};
+
+struct sysinfo {
+ uint64_t totalram;
+ uint64_t totalhigh;
+ uint32_t mem_unit;
+};
+
+/*
+ * Compute log2 of the power of two rounded up count of pages
+ * needed for size bytes.
+ */
+static inline int
+get_order(unsigned long size)
+{
+ int order;
+
+ size = (size - 1) >> PAGE_SHIFT;
+ order = 0;
+ while (size) {
+ order++;
+ size >>= 1;
+ }
+ return (order);
+}
+
+static inline void *
+lowmem_page_address(struct page *page)
+{
+ return (page_address(page));
+}
+
+/*
+ * This only works via memory map operations.
+ */
+static inline int
+io_remap_pfn_range(struct vm_area_struct *vma,
+ unsigned long addr, unsigned long pfn, unsigned long size,
+ vm_memattr_t prot)
+{
+ vma->vm_page_prot = prot;
+ vma->vm_pfn = pfn;
+ vma->vm_len = size;
+
+ return (0);
+}
+
+static inline int
+apply_to_page_range(struct mm_struct *mm, unsigned long address,
+ unsigned long size, pte_fn_t fn, void *data)
+{
+ return (-ENOTSUP);
+}
+
+int zap_vma_ptes(struct vm_area_struct *vma, unsigned long address,
+ unsigned long size);
+
+static inline int
+remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
+ unsigned long pfn, unsigned long size, pgprot_t prot)
+{
+ return (-ENOTSUP);
+}
+
+static inline unsigned long
+vma_pages(struct vm_area_struct *vma)
+{
+ return ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT);
+}
+
+#define offset_in_page(off) ((off) & (PAGE_SIZE - 1))
+
+static inline void
+set_page_dirty(struct vm_page *page)
+{
+ vm_page_dirty(page);
+}
+
+static inline void
+mark_page_accessed(struct vm_page *page)
+{
+ vm_page_reference(page);
+}
+
+static inline void
+get_page(struct vm_page *page)
+{
+ vm_page_wire(page);
+}
+
+extern long
+get_user_pages(unsigned long start, unsigned long nr_pages,
+ int gup_flags, struct page **,
+ struct vm_area_struct **);
+
+extern int
+__get_user_pages_fast(unsigned long start, int nr_pages, int write,
+ struct page **);
+
+extern long
+get_user_pages_remote(struct task_struct *, struct mm_struct *,
+ unsigned long start, unsigned long nr_pages,
+ int gup_flags, struct page **,
+ struct vm_area_struct **);
+
+static inline void
+put_page(struct vm_page *page)
+{
+ vm_page_unwire(page, PQ_ACTIVE);
+}
+
+#define copy_highpage(to, from) pmap_copy_page(from, to)
+
+static inline pgprot_t
+vm_get_page_prot(unsigned long vm_flags)
+{
+ return (vm_flags & VM_PROT_ALL);
+}
+
+static inline vm_page_t
+vmalloc_to_page(const void *addr)
+{
+ vm_paddr_t paddr;
+
+ paddr = pmap_kextract((vm_offset_t)addr);
+ return (PHYS_TO_VM_PAGE(paddr));
+}
+
+extern int is_vmalloc_addr(const void *addr);
+void si_meminfo(struct sysinfo *si);
+
+#endif /* _LINUX_MM_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/mm_types.h b/sys/compat/linuxkpi/common/include/linux/mm_types.h
new file mode 100644
index 000000000000..4c9eddf500d6
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/mm_types.h
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_MM_TYPES_H_
+#define _LINUX_MM_TYPES_H_
+
+#include <linux/types.h>
+#include <linux/page.h>
+#include <linux/rwsem.h>
+
+#include <asm/atomic.h>
+
+typedef int vm_fault_t;
+
+struct vm_area_struct;
+struct task_struct;
+
+struct mm_struct {
+ struct vm_area_struct *mmap;
+ atomic_t mm_count;
+ atomic_t mm_users;
+ size_t pinned_vm;
+ struct rw_semaphore mmap_sem;
+};
+
+extern void linux_mm_dtor(struct mm_struct *mm);
+
+static inline void
+mmdrop(struct mm_struct *mm)
+{
+ if (__predict_false(atomic_dec_and_test(&mm->mm_count)))
+ linux_mm_dtor(mm);
+}
+
+static inline bool
+mmget_not_zero(struct mm_struct *mm)
+{
+ return (atomic_inc_not_zero(&mm->mm_users));
+}
+
+static inline void
+mmput(struct mm_struct *mm)
+{
+ if (__predict_false(atomic_dec_and_test(&mm->mm_users)))
+ mmdrop(mm);
+}
+
+static inline void
+mmgrab(struct mm_struct *mm)
+{
+ atomic_inc(&mm->mm_count);
+}
+
+extern struct mm_struct *linux_get_task_mm(struct task_struct *);
+#define get_task_mm(task) linux_get_task_mm(task)
+
+#endif /* _LINUX_MM_TYPES_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/mod_devicetable.h b/sys/compat/linuxkpi/common/include/linux/mod_devicetable.h
new file mode 100644
index 000000000000..f2a913bc6346
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/mod_devicetable.h
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Emmanuel Vadot under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __LINUX_MOD_DEVICETABLE_H__
+#define __LINUX_MOD_DEVICETABLE_H__
+
+enum dmi_field {
+ DMI_NONE,
+ DMI_BIOS_VENDOR,
+ DMI_BIOS_VERSION,
+ DMI_BIOS_DATE,
+ DMI_SYS_VENDOR,
+ DMI_PRODUCT_NAME,
+ DMI_PRODUCT_VERSION,
+ DMI_PRODUCT_SERIAL,
+ DMI_PRODUCT_UUID,
+ DMI_BOARD_VENDOR,
+ DMI_BOARD_NAME,
+ DMI_BOARD_VERSION,
+ DMI_BOARD_SERIAL,
+ DMI_BOARD_ASSET_TAG,
+ DMI_CHASSIS_VENDOR,
+ DMI_CHASSIS_TYPE,
+ DMI_CHASSIS_VERSION,
+ DMI_CHASSIS_SERIAL,
+ DMI_CHASSIS_ASSET_TAG,
+ DMI_STRING_MAX,
+};
+
+struct dmi_strmatch {
+ unsigned char slot;
+ char substr[79];
+};
+
+struct dmi_system_id {
+ int (*callback)(const struct dmi_system_id *);
+ const char *ident;
+ struct dmi_strmatch matches[4];
+ void *driver_data;
+};
+
+#define DMI_MATCH(a, b) { .slot = a, .substr = b }
+#define DMI_EXACT_MATCH(a, b) { .slot = a, .substr = b, }
+
+#endif /* __LINUX_MOD_DEVICETABLE_H__ */
diff --git a/sys/compat/linuxkpi/common/include/linux/module.h b/sys/compat/linuxkpi/common/include/linux/module.h
new file mode 100644
index 000000000000..a5a8dd540dd6
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/module.h
@@ -0,0 +1,105 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_MODULE_H_
+#define _LINUX_MODULE_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/module.h>
+
+#include <linux/list.h>
+#include <linux/compiler.h>
+#include <linux/kmod.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+
+#define MODULE_AUTHOR(name)
+#define MODULE_DESCRIPTION(name)
+#define MODULE_LICENSE(name)
+#define MODULE_INFO(tag, info)
+#define MODULE_FIRMWARE(firmware)
+
+#define THIS_MODULE ((struct module *)0)
+
+#define __MODULE_STRING(x) __stringify(x)
+
+/* OFED pre-module initialization */
+#define SI_SUB_OFED_PREINIT (SI_SUB_ROOT_CONF - 2)
+/* OFED default module initialization */
+#define SI_SUB_OFED_MODINIT (SI_SUB_ROOT_CONF - 1)
+
+#include <sys/linker.h>
+
+static inline void
+_module_run(void *arg)
+{
+ void (*fn)(void);
+#ifdef OFED_DEBUG_INIT
+ char name[1024];
+ caddr_t pc;
+ long offset;
+
+ pc = (caddr_t)arg;
+ if (linker_search_symbol_name(pc, name, sizeof(name), &offset) != 0)
+ printf("Running ??? (%p)\n", pc);
+ else
+ printf("Running %s (%p)\n", name, pc);
+#endif
+ fn = arg;
+ fn();
+}
+
+#define module_init(fn) \
+ SYSINIT(fn, SI_SUB_OFED_MODINIT, SI_ORDER_FIRST, _module_run, (fn))
+
+#define module_exit(fn) \
+ SYSUNINIT(fn, SI_SUB_OFED_MODINIT, SI_ORDER_SECOND, _module_run, (fn))
+
+/*
+ * The following two macros are a workaround for not having a module
+ * load and unload order resolver:
+ */
+#define module_init_order(fn, order) \
+ SYSINIT(fn, SI_SUB_OFED_MODINIT, (order), _module_run, (fn))
+
+#define module_exit_order(fn, order) \
+ SYSUNINIT(fn, SI_SUB_OFED_MODINIT, (order), _module_run, (fn))
+
+#define module_get(module)
+#define module_put(module)
+#define try_module_get(module) 1
+
+#define postcore_initcall(fn) module_init(fn)
+
+#endif /* _LINUX_MODULE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/moduleparam.h b/sys/compat/linuxkpi/common/include/linux/moduleparam.h
new file mode 100644
index 000000000000..3a16c20fd92e
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/moduleparam.h
@@ -0,0 +1,133 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_MODULEPARAM_H_
+#define _LINUX_MODULEPARAM_H_
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include <linux/types.h>
+
+#ifndef LINUXKPI_PARAM_PARENT
+#define LINUXKPI_PARAM_PARENT _compat_linuxkpi
+#endif
+
+#ifndef LINUXKPI_PARAM_PREFIX
+#define LINUXKPI_PARAM_PREFIX /* empty prefix is the default */
+#endif
+
+#ifndef LINUXKPI_PARAM_PERM
+#define LINUXKPI_PARAM_PERM(perm) (((perm) & 0222) ? CTLFLAG_RWTUN : CTLFLAG_RDTUN)
+#endif
+
+#define LINUXKPI_PARAM_CONCAT_SUB(a,b,c,d) a##b##c##d
+#define LINUXKPI_PARAM_CONCAT(...) LINUXKPI_PARAM_CONCAT_SUB(__VA_ARGS__)
+#define LINUXKPI_PARAM_PASS(...) __VA_ARGS__
+#define LINUXKPI_PARAM_DESC(name) LINUXKPI_PARAM_CONCAT(linuxkpi_,LINUXKPI_PARAM_PREFIX,name,_desc)
+#define LINUXKPI_PARAM_NAME(name) LINUXKPI_PARAM_CONCAT(LINUXKPI_PARAM_PREFIX,name,,)
+
+#define LINUXKPI_PARAM_bool(name, var, perm) \
+ extern const char LINUXKPI_PARAM_DESC(name)[]; \
+ LINUXKPI_PARAM_PASS(SYSCTL_BOOL(LINUXKPI_PARAM_PARENT, OID_AUTO,\
+ LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), &(var), 0, \
+ LINUXKPI_PARAM_DESC(name)))
+
+#define LINUXKPI_PARAM_byte(name, var, perm) \
+ extern const char LINUXKPI_PARAM_DESC(name)[]; \
+ LINUXKPI_PARAM_PASS(SYSCTL_U8(LINUXKPI_PARAM_PARENT, OID_AUTO, \
+ LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), &(var), 0, \
+ LINUXKPI_PARAM_DESC(name)))
+
+#define LINUXKPI_PARAM_short(name, var, perm) \
+ extern const char LINUXKPI_PARAM_DESC(name)[]; \
+ LINUXKPI_PARAM_PASS(SYSCTL_S16(LINUXKPI_PARAM_PARENT, OID_AUTO, \
+ LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), &(var), 0, \
+ LINUXKPI_PARAM_DESC(name)))
+
+#define LINUXKPI_PARAM_ushort(name, var, perm) \
+ extern const char LINUXKPI_PARAM_DESC(name)[]; \
+ LINUXKPI_PARAM_PASS(SYSCTL_U16(LINUXKPI_PARAM_PARENT, OID_AUTO, \
+ LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), &(var), 0, \
+ LINUXKPI_PARAM_DESC(name)))
+
+#define LINUXKPI_PARAM_int(name, var, perm) \
+ extern const char LINUXKPI_PARAM_DESC(name)[]; \
+ LINUXKPI_PARAM_PASS(SYSCTL_INT(LINUXKPI_PARAM_PARENT, OID_AUTO, \
+ LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), &(var), 0,\
+ LINUXKPI_PARAM_DESC(name)))
+
+#define LINUXKPI_PARAM_uint(name, var, perm) \
+ extern const char LINUXKPI_PARAM_DESC(name)[]; \
+ LINUXKPI_PARAM_PASS(SYSCTL_UINT(LINUXKPI_PARAM_PARENT, OID_AUTO, \
+ LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), &(var), 0, \
+ LINUXKPI_PARAM_DESC(name)))
+
+#define LINUXKPI_PARAM_long(name, var, perm) \
+ extern const char LINUXKPI_PARAM_DESC(name)[]; \
+ LINUXKPI_PARAM_PASS(SYSCTL_LONG(LINUXKPI_PARAM_PARENT, OID_AUTO, \
+ LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), &(var), 0, \
+ LINUXKPI_PARAM_DESC(name)))
+
+#define LINUXKPI_PARAM_ulong(name, var, perm) \
+ extern const char LINUXKPI_PARAM_DESC(name)[]; \
+ LINUXKPI_PARAM_PASS(SYSCTL_ULONG(LINUXKPI_PARAM_PARENT, OID_AUTO, \
+ LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), &(var), 0, \
+ LINUXKPI_PARAM_DESC(name)))
+
+#define module_param_string(name, str, len, perm) \
+ extern const char LINUXKPI_PARAM_DESC(name)[]; \
+ LINUXKPI_PARAM_PASS(SYSCTL_STRING(LINUXKPI_PARAM_PARENT, OID_AUTO, \
+ LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), (str), (len), \
+ LINUXKPI_PARAM_DESC(name)))
+
+#define module_param_named(name, var, type, mode) \
+ LINUXKPI_PARAM_##type(name, var, mode)
+
+#define module_param(var, type, mode) \
+ LINUXKPI_PARAM_##type(var, var, mode)
+
+#define module_param_named_unsafe(name, var, type, mode) \
+ LINUXKPI_PARAM_##type(name, var, mode)
+
+#define module_param_unsafe(var, type, mode) \
+ LINUXKPI_PARAM_##type(var, var, mode)
+
+#define module_param_array(var, type, addr_argc, mode)
+
+#define MODULE_PARM_DESC(name, desc) \
+ const char LINUXKPI_PARAM_DESC(name)[] = { desc }
+
+#define kernel_param_lock(...) do {} while (0)
+#define kernel_param_unlock(...) do {} while (0)
+
+SYSCTL_DECL(_compat_linuxkpi);
+
+#endif /* _LINUX_MODULEPARAM_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/mutex.h b/sys/compat/linuxkpi/common/include/linux/mutex.h
new file mode 100644
index 000000000000..bdf0b4dbdb2d
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/mutex.h
@@ -0,0 +1,176 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_MUTEX_H_
+#define _LINUX_MUTEX_H_
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/lock.h>
+#include <sys/sx.h>
+
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+
+typedef struct mutex {
+ struct sx sx;
+} mutex_t;
+
+/*
+ * By defining CONFIG_NO_MUTEX_SKIP LinuxKPI mutexes and asserts will
+ * not be skipped during panic().
+ */
+#ifdef CONFIG_NO_MUTEX_SKIP
+#define MUTEX_SKIP(void) 0
+#else
+#define MUTEX_SKIP(void) unlikely(SCHEDULER_STOPPED() || kdb_active)
+#endif
+
+#define mutex_lock(_m) do { \
+ if (MUTEX_SKIP()) \
+ break; \
+ sx_xlock(&(_m)->sx); \
+} while (0)
+
+#define mutex_lock_nested(_m, _s) mutex_lock(_m)
+#define mutex_lock_nest_lock(_m, _s) mutex_lock(_m)
+
+#define mutex_lock_interruptible(_m) ({ \
+ MUTEX_SKIP() ? 0 : \
+ linux_mutex_lock_interruptible(_m); \
+})
+
+#define mutex_lock_interruptible_nested(m, c) mutex_lock_interruptible(m)
+
+/*
+ * Reuse the interruptable method since the SX
+ * lock handles both signals and interrupts:
+ */
+#define mutex_lock_killable(_m) ({ \
+ MUTEX_SKIP() ? 0 : \
+ linux_mutex_lock_interruptible(_m); \
+})
+
+#define mutex_lock_killable_nested(_m, _sub) \
+ mutex_lock_killable(_m)
+
+#define mutex_unlock(_m) do { \
+ if (MUTEX_SKIP()) \
+ break; \
+ sx_xunlock(&(_m)->sx); \
+} while (0)
+
+#define mutex_trylock(_m) ({ \
+ MUTEX_SKIP() ? 1 : \
+ !!sx_try_xlock(&(_m)->sx); \
+})
+
+enum mutex_trylock_recursive_enum {
+ MUTEX_TRYLOCK_FAILED = 0,
+ MUTEX_TRYLOCK_SUCCESS = 1,
+ MUTEX_TRYLOCK_RECURSIVE = 2,
+};
+
+static inline __must_check enum mutex_trylock_recursive_enum
+mutex_trylock_recursive(struct mutex *lock)
+{
+ if (unlikely(sx_xholder(&lock->sx) == curthread))
+ return (MUTEX_TRYLOCK_RECURSIVE);
+
+ return (mutex_trylock(lock));
+}
+
+#define mutex_init(_m) \
+ linux_mutex_init(_m, mutex_name(#_m), SX_NOWITNESS)
+
+#define __mutex_init(_m, _n, _l) \
+ linux_mutex_init(_m, _n, SX_NOWITNESS)
+
+#define mutex_init_witness(_m) \
+ linux_mutex_init(_m, mutex_name(#_m), SX_DUPOK)
+
+#define mutex_destroy(_m) \
+ linux_mutex_destroy(_m)
+
+static inline bool
+mutex_is_locked(mutex_t *m)
+{
+ return ((struct thread *)SX_OWNER(m->sx.sx_lock) != NULL);
+}
+
+static inline bool
+mutex_is_owned(mutex_t *m)
+{
+ return (sx_xlocked(&m->sx));
+}
+
+static inline int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *m)
+{
+ if (atomic_dec_and_test(cnt)) {
+ mutex_lock(m);
+ return (1);
+ }
+
+ return (0);
+}
+
+#ifdef WITNESS_ALL
+/* NOTE: the maximum WITNESS name is 64 chars */
+#define __mutex_name(name, file, line) \
+ (((const char *){file ":" #line "-" name}) + \
+ (sizeof(file) > 16 ? sizeof(file) - 16 : 0))
+#else
+#define __mutex_name(name, file, line) name
+#endif
+#define _mutex_name(...) __mutex_name(__VA_ARGS__)
+#define mutex_name(name) _mutex_name(name, __FILE__, __LINE__)
+
+#define DEFINE_MUTEX(lock) \
+ mutex_t lock; \
+ SX_SYSINIT_FLAGS(lock, &(lock).sx, mutex_name(#lock), SX_DUPOK)
+
+static inline void
+linux_mutex_init(mutex_t *m, const char *name, int flags)
+{
+ memset(m, 0, sizeof(*m));
+ sx_init_flags(&m->sx, name, flags);
+}
+
+static inline void
+linux_mutex_destroy(mutex_t *m)
+{
+ if (mutex_is_owned(m))
+ mutex_unlock(m);
+ sx_destroy(&m->sx);
+}
+
+extern int linux_mutex_lock_interruptible(mutex_t *m);
+
+#endif /* _LINUX_MUTEX_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/net.h b/sys/compat/linuxkpi/common/include/linux/net.h
new file mode 100644
index 000000000000..282a45d2db32
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/net.h
@@ -0,0 +1,79 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_NET_H_
+#define _LINUX_NET_H_
+
+#include <sys/types.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/errno.h>
+
+static inline int
+sock_create_kern(int family, int type, int proto, struct socket **res)
+{
+ return -socreate(family, res, type, proto, curthread->td_ucred,
+ curthread);
+}
+
+static inline int
+sock_getname(struct socket *so, struct sockaddr *addr, int *sockaddr_len,
+ int peer)
+{
+ struct sockaddr *nam;
+ int error;
+
+ nam = NULL;
+ if (peer) {
+ if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0)
+ return (-ENOTCONN);
+
+ error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, &nam);
+ } else
+ error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, &nam);
+ if (error)
+ return (-error);
+ *addr = *nam;
+ *sockaddr_len = addr->sa_len;
+
+ free(nam, M_SONAME);
+ return (0);
+}
+
+static inline void
+sock_release(struct socket *so)
+{
+ soclose(so);
+}
+
+#endif /* _LINUX_NET_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/net_dim.h b/sys/compat/linuxkpi/common/include/linux/net_dim.h
new file mode 100644
index 000000000000..f1b7e06b820e
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/net_dim.h
@@ -0,0 +1,410 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0
+ *
+ * Copyright (c) 2016, Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2017-2018, Broadcom Limited. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+/* This file implements Dynamic Interrupt Moderation, DIM */
+
+#ifndef NET_DIM_H
+#define NET_DIM_H
+
+#include <asm/types.h>
+
+#include <linux/workqueue.h>
+#include <linux/ktime.h>
+
+struct net_dim_cq_moder {
+ u16 usec;
+ u16 pkts;
+ u8 cq_period_mode;
+};
+
+struct net_dim_sample {
+ ktime_t time;
+ u32 pkt_ctr;
+ u32 byte_ctr;
+ u16 event_ctr;
+};
+
+struct net_dim_stats {
+ int ppms; /* packets per msec */
+ int bpms; /* bytes per msec */
+ int epms; /* events per msec */
+};
+
+struct net_dim { /* Adaptive Moderation */
+ u8 state;
+ struct net_dim_stats prev_stats;
+ struct net_dim_sample start_sample;
+ struct work_struct work;
+ u16 event_ctr;
+ u8 profile_ix;
+ u8 mode;
+ u8 tune_state;
+ u8 steps_right;
+ u8 steps_left;
+ u8 tired;
+};
+
+enum {
+ NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE = 0x0,
+ NET_DIM_CQ_PERIOD_MODE_START_FROM_CQE = 0x1,
+ NET_DIM_CQ_PERIOD_NUM_MODES = 0x2,
+ NET_DIM_CQ_PERIOD_MODE_DISABLED = 0xFF,
+};
+
+/* Adaptive moderation logic */
+enum {
+ NET_DIM_START_MEASURE,
+ NET_DIM_MEASURE_IN_PROGRESS,
+ NET_DIM_APPLY_NEW_PROFILE,
+};
+
+enum {
+ NET_DIM_PARKING_ON_TOP,
+ NET_DIM_PARKING_TIRED,
+ NET_DIM_GOING_RIGHT,
+ NET_DIM_GOING_LEFT,
+};
+
+enum {
+ NET_DIM_STATS_WORSE,
+ NET_DIM_STATS_SAME,
+ NET_DIM_STATS_BETTER,
+};
+
+enum {
+ NET_DIM_STEPPED,
+ NET_DIM_TOO_TIRED,
+ NET_DIM_ON_EDGE,
+};
+
+#define NET_DIM_PARAMS_NUM_PROFILES 5
+/* Adaptive moderation profiles */
+#define NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE 256
+#define NET_DIM_DEF_PROFILE_CQE 1
+#define NET_DIM_DEF_PROFILE_EQE 1
+
+/* All profiles sizes must be NET_PARAMS_DIM_NUM_PROFILES */
+#define NET_DIM_EQE_PROFILES { \
+ {1, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
+ {8, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
+ {64, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
+ {128, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
+ {256, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
+}
+
+#define NET_DIM_CQE_PROFILES { \
+ {2, 256}, \
+ {8, 128}, \
+ {16, 64}, \
+ {32, 64}, \
+ {64, 64} \
+}
+
+static const struct net_dim_cq_moder
+ net_dim_profile[NET_DIM_CQ_PERIOD_NUM_MODES][NET_DIM_PARAMS_NUM_PROFILES] = {
+ NET_DIM_EQE_PROFILES,
+ NET_DIM_CQE_PROFILES,
+};
+
+static inline struct net_dim_cq_moder
+net_dim_get_profile(u8 cq_period_mode,
+ int ix)
+{
+ struct net_dim_cq_moder cq_moder;
+
+ cq_moder = net_dim_profile[cq_period_mode][ix];
+ cq_moder.cq_period_mode = cq_period_mode;
+ return cq_moder;
+}
+
+static inline struct net_dim_cq_moder
+net_dim_get_def_profile(u8 rx_cq_period_mode)
+{
+ int default_profile_ix;
+
+ if (rx_cq_period_mode == NET_DIM_CQ_PERIOD_MODE_START_FROM_CQE)
+ default_profile_ix = NET_DIM_DEF_PROFILE_CQE;
+ else /* NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE */
+ default_profile_ix = NET_DIM_DEF_PROFILE_EQE;
+
+ return net_dim_get_profile(rx_cq_period_mode, default_profile_ix);
+}
+
+static inline bool
+net_dim_on_top(struct net_dim *dim)
+{
+ switch (dim->tune_state) {
+ case NET_DIM_PARKING_ON_TOP:
+ case NET_DIM_PARKING_TIRED:
+ return true;
+ case NET_DIM_GOING_RIGHT:
+ return (dim->steps_left > 1) && (dim->steps_right == 1);
+ default: /* NET_DIM_GOING_LEFT */
+ return (dim->steps_right > 1) && (dim->steps_left == 1);
+ }
+}
+
+static inline void
+net_dim_turn(struct net_dim *dim)
+{
+ switch (dim->tune_state) {
+ case NET_DIM_PARKING_ON_TOP:
+ case NET_DIM_PARKING_TIRED:
+ break;
+ case NET_DIM_GOING_RIGHT:
+ dim->tune_state = NET_DIM_GOING_LEFT;
+ dim->steps_left = 0;
+ break;
+ case NET_DIM_GOING_LEFT:
+ dim->tune_state = NET_DIM_GOING_RIGHT;
+ dim->steps_right = 0;
+ break;
+ }
+}
+
+static inline int
+net_dim_step(struct net_dim *dim)
+{
+ if (dim->tired == (NET_DIM_PARAMS_NUM_PROFILES * 2))
+ return NET_DIM_TOO_TIRED;
+
+ switch (dim->tune_state) {
+ case NET_DIM_PARKING_ON_TOP:
+ case NET_DIM_PARKING_TIRED:
+ break;
+ case NET_DIM_GOING_RIGHT:
+ if (dim->profile_ix == (NET_DIM_PARAMS_NUM_PROFILES - 1))
+ return NET_DIM_ON_EDGE;
+ dim->profile_ix++;
+ dim->steps_right++;
+ break;
+ case NET_DIM_GOING_LEFT:
+ if (dim->profile_ix == 0)
+ return NET_DIM_ON_EDGE;
+ dim->profile_ix--;
+ dim->steps_left++;
+ break;
+ }
+
+ dim->tired++;
+ return NET_DIM_STEPPED;
+}
+
+static inline void
+net_dim_park_on_top(struct net_dim *dim)
+{
+ dim->steps_right = 0;
+ dim->steps_left = 0;
+ dim->tired = 0;
+ dim->tune_state = NET_DIM_PARKING_ON_TOP;
+}
+
+static inline void
+net_dim_park_tired(struct net_dim *dim)
+{
+ dim->steps_right = 0;
+ dim->steps_left = 0;
+ dim->tune_state = NET_DIM_PARKING_TIRED;
+}
+
+static inline void
+net_dim_exit_parking(struct net_dim *dim)
+{
+ dim->tune_state = dim->profile_ix ? NET_DIM_GOING_LEFT :
+ NET_DIM_GOING_RIGHT;
+ net_dim_step(dim);
+}
+
+#define IS_SIGNIFICANT_DIFF(val, ref) \
+ (((100UL * abs((val) - (ref))) / (ref)) > 10) /* more than 10%
+ * difference */
+
+static inline int
+net_dim_stats_compare(struct net_dim_stats *curr,
+ struct net_dim_stats *prev)
+{
+ if (!prev->bpms)
+ return curr->bpms ? NET_DIM_STATS_BETTER :
+ NET_DIM_STATS_SAME;
+
+ if (IS_SIGNIFICANT_DIFF(curr->bpms, prev->bpms))
+ return (curr->bpms > prev->bpms) ? NET_DIM_STATS_BETTER :
+ NET_DIM_STATS_WORSE;
+
+ if (!prev->ppms)
+ return curr->ppms ? NET_DIM_STATS_BETTER :
+ NET_DIM_STATS_SAME;
+
+ if (IS_SIGNIFICANT_DIFF(curr->ppms, prev->ppms))
+ return (curr->ppms > prev->ppms) ? NET_DIM_STATS_BETTER :
+ NET_DIM_STATS_WORSE;
+
+ if (!prev->epms)
+ return NET_DIM_STATS_SAME;
+
+ if (IS_SIGNIFICANT_DIFF(curr->epms, prev->epms))
+ return (curr->epms < prev->epms) ? NET_DIM_STATS_BETTER :
+ NET_DIM_STATS_WORSE;
+
+ return NET_DIM_STATS_SAME;
+}
+
+static inline bool
+net_dim_decision(struct net_dim_stats *curr_stats,
+ struct net_dim *dim)
+{
+ int prev_state = dim->tune_state;
+ int prev_ix = dim->profile_ix;
+ int stats_res;
+ int step_res;
+
+ switch (dim->tune_state) {
+ case NET_DIM_PARKING_ON_TOP:
+ stats_res = net_dim_stats_compare(curr_stats, &dim->prev_stats);
+ if (stats_res != NET_DIM_STATS_SAME)
+ net_dim_exit_parking(dim);
+ break;
+
+ case NET_DIM_PARKING_TIRED:
+ dim->tired--;
+ if (!dim->tired)
+ net_dim_exit_parking(dim);
+ break;
+
+ case NET_DIM_GOING_RIGHT:
+ case NET_DIM_GOING_LEFT:
+ stats_res = net_dim_stats_compare(curr_stats, &dim->prev_stats);
+ if (stats_res != NET_DIM_STATS_BETTER)
+ net_dim_turn(dim);
+
+ if (net_dim_on_top(dim)) {
+ net_dim_park_on_top(dim);
+ break;
+ }
+ step_res = net_dim_step(dim);
+ switch (step_res) {
+ case NET_DIM_ON_EDGE:
+ net_dim_park_on_top(dim);
+ break;
+ case NET_DIM_TOO_TIRED:
+ net_dim_park_tired(dim);
+ break;
+ }
+
+ break;
+ }
+
+ if ((prev_state != NET_DIM_PARKING_ON_TOP) ||
+ (dim->tune_state != NET_DIM_PARKING_ON_TOP))
+ dim->prev_stats = *curr_stats;
+
+ return dim->profile_ix != prev_ix;
+}
+
+static inline void
+net_dim_sample(u16 event_ctr,
+ u64 packets,
+ u64 bytes,
+ struct net_dim_sample *s)
+{
+ s->time = ktime_get();
+ s->pkt_ctr = packets;
+ s->byte_ctr = bytes;
+ s->event_ctr = event_ctr;
+}
+
+#define NET_DIM_NEVENTS 64
+#define BIT_GAP(bits, end, start) ((((end) - (start)) + BIT_ULL(bits)) & (BIT_ULL(bits) - 1))
+
+static inline void
+net_dim_calc_stats(struct net_dim_sample *start,
+ struct net_dim_sample *end,
+ struct net_dim_stats *curr_stats)
+{
+ /* u32 holds up to 71 minutes, should be enough */
+ u32 delta_us = ktime_us_delta(end->time, start->time);
+ u32 npkts = BIT_GAP(BITS_PER_TYPE(u32), end->pkt_ctr, start->pkt_ctr);
+ u32 nbytes = BIT_GAP(BITS_PER_TYPE(u32), end->byte_ctr,
+ start->byte_ctr);
+
+ if (!delta_us)
+ return;
+
+ curr_stats->ppms = DIV_ROUND_UP(npkts * USEC_PER_MSEC, delta_us);
+ curr_stats->bpms = DIV_ROUND_UP(nbytes * USEC_PER_MSEC, delta_us);
+ curr_stats->epms = DIV_ROUND_UP(NET_DIM_NEVENTS * USEC_PER_MSEC,
+ delta_us);
+}
+
+static inline void
+net_dim(struct net_dim *dim,
+ u64 packets, u64 bytes)
+{
+ struct net_dim_stats curr_stats;
+ struct net_dim_sample end_sample;
+ u16 nevents;
+
+ dim->event_ctr++;
+
+ switch (dim->state) {
+ case NET_DIM_MEASURE_IN_PROGRESS:
+ nevents = BIT_GAP(BITS_PER_TYPE(u16),
+ dim->event_ctr,
+ dim->start_sample.event_ctr);
+ if (nevents < NET_DIM_NEVENTS)
+ break;
+ net_dim_sample(dim->event_ctr, packets, bytes, &end_sample);
+ net_dim_calc_stats(&dim->start_sample, &end_sample,
+ &curr_stats);
+ if (net_dim_decision(&curr_stats, dim)) {
+ dim->state = NET_DIM_APPLY_NEW_PROFILE;
+ schedule_work(&dim->work);
+ break;
+ }
+ /* FALLTHROUGH */
+ case NET_DIM_START_MEASURE:
+ net_dim_sample(dim->event_ctr, packets, bytes, &dim->start_sample);
+ dim->state = NET_DIM_MEASURE_IN_PROGRESS;
+ break;
+ case NET_DIM_APPLY_NEW_PROFILE:
+ break;
+ default:
+ break;
+ }
+}
+
+#endif /* NET_DIM_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/netdevice.h b/sys/compat/linuxkpi/common/include/linux/netdevice.h
new file mode 100644
index 000000000000..336215b9f7c5
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/netdevice.h
@@ -0,0 +1,143 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2019 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_NETDEVICE_H_
+#define _LINUX_NETDEVICE_H_
+
+#include <linux/types.h>
+
+#include <sys/socket.h>
+
+#include <net/if_types.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+
+#include <linux/list.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/net.h>
+#include <linux/notifier.h>
+
+#ifdef VIMAGE
+#define init_net *vnet0
+#else
+#define init_net *((struct vnet *)0)
+#endif
+
+#define MAX_ADDR_LEN 20
+
+#define net_device ifnet
+
+static inline struct ifnet *
+dev_get_by_index(struct vnet *vnet, int if_index)
+{
+ struct epoch_tracker et;
+ struct ifnet *retval;
+
+ NET_EPOCH_ENTER(et);
+ CURVNET_SET(vnet);
+ retval = ifnet_byindex_ref(if_index);
+ CURVNET_RESTORE();
+ NET_EPOCH_EXIT(et);
+
+ return (retval);
+}
+
+#define dev_hold(d) if_ref(d)
+#define dev_put(d) if_rele(d)
+#define dev_net(d) ((d)->if_vnet)
+
+#define net_eq(a,b) ((a) == (b))
+
+#define netif_running(dev) !!((dev)->if_drv_flags & IFF_DRV_RUNNING)
+#define netif_oper_up(dev) !!((dev)->if_flags & IFF_UP)
+#define netif_carrier_ok(dev) ((dev)->if_link_state == LINK_STATE_UP)
+
+static inline void *
+netdev_priv(const struct net_device *dev)
+{
+ return (dev->if_softc);
+}
+
+static inline struct net_device *
+netdev_notifier_info_to_dev(void *ifp)
+{
+ return (ifp);
+}
+
+int register_netdevice_notifier(struct notifier_block *);
+int register_inetaddr_notifier(struct notifier_block *);
+int unregister_netdevice_notifier(struct notifier_block *);
+int unregister_inetaddr_notifier(struct notifier_block *);
+
+#define rtnl_lock()
+#define rtnl_unlock()
+
+static inline int
+dev_mc_delete(struct net_device *dev, void *addr, int alen, int all)
+{
+ struct sockaddr_dl sdl;
+
+ if (alen > sizeof(sdl.sdl_data))
+ return (-EINVAL);
+ memset(&sdl, 0, sizeof(sdl));
+ sdl.sdl_len = sizeof(sdl);
+ sdl.sdl_family = AF_LINK;
+ sdl.sdl_alen = alen;
+ memcpy(&sdl.sdl_data, addr, alen);
+
+ return -if_delmulti(dev, (struct sockaddr *)&sdl);
+}
+
+static inline int
+dev_mc_del(struct net_device *dev, void *addr)
+{
+ return (dev_mc_delete(dev, addr, 6, 0));
+}
+
+static inline int
+dev_mc_add(struct net_device *dev, void *addr, int alen, int newonly)
+{
+ struct sockaddr_dl sdl;
+
+ if (alen > sizeof(sdl.sdl_data))
+ return (-EINVAL);
+ memset(&sdl, 0, sizeof(sdl));
+ sdl.sdl_len = sizeof(sdl);
+ sdl.sdl_family = AF_LINK;
+ sdl.sdl_alen = alen;
+ memcpy(&sdl.sdl_data, addr, alen);
+
+ return -if_addmulti(dev, (struct sockaddr *)&sdl, NULL);
+}
+
+#endif /* _LINUX_NETDEVICE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/notifier.h b/sys/compat/linuxkpi/common/include/linux/notifier.h
new file mode 100644
index 000000000000..ae292439bf54
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/notifier.h
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_NOTIFIER_H_
+#define _LINUX_NOTIFIER_H_
+
+#include <sys/types.h>
+#include <sys/eventhandler.h>
+
+#define NOTIFY_DONE 0
+
+enum {
+ NETDEV_CHANGE,
+ NETDEV_UP,
+ NETDEV_DOWN,
+ NETDEV_REGISTER,
+ NETDEV_UNREGISTER,
+ NETDEV_CHANGEADDR,
+ NETDEV_CHANGEIFADDR,
+ LINUX_NOTIFY_TAGS /* must be last */
+};
+
+struct notifier_block {
+ int (*notifier_call) (struct notifier_block *, unsigned long, void *);
+ struct notifier_block *next;
+ int priority;
+ eventhandler_tag tags[LINUX_NOTIFY_TAGS];
+};
+
+#endif /* _LINUX_NOTIFIER_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/numa.h b/sys/compat/linuxkpi/common/include/linux/numa.h
new file mode 100644
index 000000000000..19455349a7a6
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/numa.h
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Emmanuel Vadot under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_NUMA_H_
+#define _LINUX_NUMA_H_
+
+#define NUMA_NO_NODE -1
+
+#endif /* _LINUX_NUMA_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/overflow.h b/sys/compat/linuxkpi/common/include/linux/overflow.h
new file mode 100644
index 000000000000..6f53f0b59384
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/overflow.h
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Emmanuel Vadot under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __LINUX_OVERFLOW_H__
+#define __LINUX_OVERFLOW_H__
+
+#include <sys/stdint.h>
+#include <sys/types.h>
+
+#ifndef __has_builtin
+#define __has_builtin(x) 0
+#endif
+
+#if __has_builtin(__builtin_add_overflow)
+#define check_add_overflow(a, b, c) \
+ __builtin_add_overflow(a, b, c)
+#else
+#error "Compiler does not support __builtin_add_overflow"
+#endif
+
+#if __has_builtin(__builtin_mul_overflow)
+#define check_mul_overflow(a, b, c) \
+ __builtin_mul_overflow(a, b, c)
+
+static inline size_t
+array_size(size_t x, size_t y)
+{
+ size_t retval;
+
+ if (__builtin_mul_overflow(x, y, &retval))
+ retval = SIZE_MAX;
+ return (retval);
+}
+#else
+#error "Compiler does not support __builtin_mul_overflow"
+#endif
+
+#endif /* __LINUX_OVERFLOW_H__ */
diff --git a/sys/compat/linuxkpi/common/include/linux/page.h b/sys/compat/linuxkpi/common/include/linux/page.h
new file mode 100644
index 000000000000..c2dbab769c2a
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/page.h
@@ -0,0 +1,96 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_PAGE_H_
+#define _LINUX_PAGE_H_
+
+#include <linux/types.h>
+
+#include <sys/param.h>
+#include <sys/vmmeter.h>
+
+#include <machine/atomic.h>
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+#include <vm/pmap.h>
+
+typedef unsigned long linux_pte_t;
+typedef unsigned long linux_pmd_t;
+typedef unsigned long linux_pgd_t;
+typedef unsigned long pgprot_t;
+
+#define page vm_page
+
+#define LINUXKPI_PROT_VALID (1 << 3)
+#define LINUXKPI_CACHE_MODE_SHIFT 4
+
+CTASSERT((VM_PROT_ALL & -LINUXKPI_PROT_VALID) == 0);
+
+static inline pgprot_t
+cachemode2protval(vm_memattr_t attr)
+{
+ return ((attr << LINUXKPI_CACHE_MODE_SHIFT) | LINUXKPI_PROT_VALID);
+}
+
+static inline vm_memattr_t
+pgprot2cachemode(pgprot_t prot)
+{
+ if (prot & LINUXKPI_PROT_VALID)
+ return (prot >> LINUXKPI_CACHE_MODE_SHIFT);
+ else
+ return (VM_MEMATTR_DEFAULT);
+}
+
+#define virt_to_page(x) PHYS_TO_VM_PAGE(vtophys(x))
+#define page_to_pfn(pp) (VM_PAGE_TO_PHYS(pp) >> PAGE_SHIFT)
+#define pfn_to_page(pfn) (PHYS_TO_VM_PAGE((pfn) << PAGE_SHIFT))
+#define nth_page(page,n) pfn_to_page(page_to_pfn(page) + (n))
+
+#define clear_page(page) memset(page, 0, PAGE_SIZE)
+#define pgprot_noncached(prot) \
+ (((prot) & VM_PROT_ALL) | cachemode2protval(VM_MEMATTR_UNCACHEABLE))
+#define pgprot_writecombine(prot) \
+ (((prot) & VM_PROT_ALL) | cachemode2protval(VM_MEMATTR_WRITE_COMBINING))
+
+#undef PAGE_MASK
+#define PAGE_MASK (~(PAGE_SIZE-1))
+/*
+ * Modifying PAGE_MASK in the above way breaks trunc_page, round_page,
+ * and btoc macros. Therefore, redefine them in a way that makes sense
+ * so the LinuxKPI consumers don't get totally broken behavior.
+ */
+#undef btoc
+#define btoc(x) (((vm_offset_t)(x) + PAGE_SIZE - 1) >> PAGE_SHIFT)
+#undef round_page
+#define round_page(x) ((((uintptr_t)(x)) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
+#undef trunc_page
+#define trunc_page(x) ((uintptr_t)(x) & ~(PAGE_SIZE - 1))
+
+#endif /* _LINUX_PAGE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/pagemap.h b/sys/compat/linuxkpi/common/include/linux/pagemap.h
new file mode 100644
index 000000000000..100bcfaeb433
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/pagemap.h
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Emmanuel Vadot under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_PAGEMAP_H_
+#define _LINUX_PAGEMAP_H_
+
+#include <linux/mm.h>
+
+static inline void
+release_pages(struct page **pages, int nr)
+{
+ int i;
+
+ for (i = 0; i < nr; i++)
+ put_page(pages[i]);
+}
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/pci.h b/sys/compat/linuxkpi/common/include/linux/pci.h
new file mode 100644
index 000000000000..ddb3f0b222a5
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/pci.h
@@ -0,0 +1,1165 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_PCI_H_
+#define _LINUX_PCI_H_
+
+#define CONFIG_PCI_MSI
+
+#include <linux/types.h>
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/nv.h>
+#include <sys/pciio.h>
+#include <sys/rman.h>
+#include <sys/bus.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pci_private.h>
+
+#include <machine/resource.h>
+
+#include <linux/list.h>
+#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
+#include <linux/compiler.h>
+#include <linux/errno.h>
+#include <asm/atomic.h>
+#include <linux/device.h>
+
+struct pci_device_id {
+ uint32_t vendor;
+ uint32_t device;
+ uint32_t subvendor;
+ uint32_t subdevice;
+ uint32_t class;
+ uint32_t class_mask;
+ uintptr_t driver_data;
+};
+
+#define MODULE_DEVICE_TABLE(bus, table)
+
+#define PCI_BASE_CLASS_DISPLAY 0x03
+#define PCI_CLASS_DISPLAY_VGA 0x0300
+#define PCI_CLASS_DISPLAY_OTHER 0x0380
+#define PCI_BASE_CLASS_BRIDGE 0x06
+#define PCI_CLASS_BRIDGE_ISA 0x0601
+
+#define PCI_ANY_ID -1U
+#define PCI_VENDOR_ID_APPLE 0x106b
+#define PCI_VENDOR_ID_ASUSTEK 0x1043
+#define PCI_VENDOR_ID_ATI 0x1002
+#define PCI_VENDOR_ID_DELL 0x1028
+#define PCI_VENDOR_ID_HP 0x103c
+#define PCI_VENDOR_ID_IBM 0x1014
+#define PCI_VENDOR_ID_INTEL 0x8086
+#define PCI_VENDOR_ID_MELLANOX 0x15b3
+#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4
+#define PCI_VENDOR_ID_SERVERWORKS 0x1166
+#define PCI_VENDOR_ID_SONY 0x104d
+#define PCI_VENDOR_ID_TOPSPIN 0x1867
+#define PCI_VENDOR_ID_VIA 0x1106
+#define PCI_SUBVENDOR_ID_REDHAT_QUMRANET 0x1af4
+#define PCI_DEVICE_ID_ATI_RADEON_QY 0x5159
+#define PCI_DEVICE_ID_MELLANOX_TAVOR 0x5a44
+#define PCI_DEVICE_ID_MELLANOX_TAVOR_BRIDGE 0x5a46
+#define PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT 0x6278
+#define PCI_DEVICE_ID_MELLANOX_ARBEL 0x6282
+#define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c
+#define PCI_DEVICE_ID_MELLANOX_SINAI 0x6274
+#define PCI_SUBDEVICE_ID_QEMU 0x1100
+
+#define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
+#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
+#define PCI_FUNC(devfn) ((devfn) & 0x07)
+#define PCI_BUS_NUM(devfn) (((devfn) >> 8) & 0xff)
+
+#define PCI_VDEVICE(_vendor, _device) \
+ .vendor = PCI_VENDOR_ID_##_vendor, .device = (_device), \
+ .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
+#define PCI_DEVICE(_vendor, _device) \
+ .vendor = (_vendor), .device = (_device), \
+ .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
+
+#define to_pci_dev(n) container_of(n, struct pci_dev, dev)
+
+#define PCI_VENDOR_ID PCIR_DEVVENDOR
+#define PCI_COMMAND PCIR_COMMAND
+#define PCI_EXP_DEVCTL PCIER_DEVICE_CTL /* Device Control */
+#define PCI_EXP_LNKCTL PCIER_LINK_CTL /* Link Control */
+#define PCI_EXP_FLAGS_TYPE PCIEM_FLAGS_TYPE /* Device/Port type */
+#define PCI_EXP_DEVCAP PCIER_DEVICE_CAP /* Device capabilities */
+#define PCI_EXP_DEVSTA PCIER_DEVICE_STA /* Device Status */
+#define PCI_EXP_LNKCAP PCIER_LINK_CAP /* Link Capabilities */
+#define PCI_EXP_LNKSTA PCIER_LINK_STA /* Link Status */
+#define PCI_EXP_SLTCAP PCIER_SLOT_CAP /* Slot Capabilities */
+#define PCI_EXP_SLTCTL PCIER_SLOT_CTL /* Slot Control */
+#define PCI_EXP_SLTSTA PCIER_SLOT_STA /* Slot Status */
+#define PCI_EXP_RTCTL PCIER_ROOT_CTL /* Root Control */
+#define PCI_EXP_RTCAP PCIER_ROOT_CAP /* Root Capabilities */
+#define PCI_EXP_RTSTA PCIER_ROOT_STA /* Root Status */
+#define PCI_EXP_DEVCAP2 PCIER_DEVICE_CAP2 /* Device Capabilities 2 */
+#define PCI_EXP_DEVCTL2 PCIER_DEVICE_CTL2 /* Device Control 2 */
+#define PCI_EXP_LNKCAP2 PCIER_LINK_CAP2 /* Link Capabilities 2 */
+#define PCI_EXP_LNKCTL2 PCIER_LINK_CTL2 /* Link Control 2 */
+#define PCI_EXP_LNKSTA2 PCIER_LINK_STA2 /* Link Status 2 */
+#define PCI_EXP_FLAGS PCIER_FLAGS /* Capabilities register */
+#define PCI_EXP_FLAGS_VERS PCIEM_FLAGS_VERSION /* Capability version */
+#define PCI_EXP_TYPE_ROOT_PORT PCIEM_TYPE_ROOT_PORT /* Root Port */
+#define PCI_EXP_TYPE_ENDPOINT PCIEM_TYPE_ENDPOINT /* Express Endpoint */
+#define PCI_EXP_TYPE_LEG_END PCIEM_TYPE_LEGACY_ENDPOINT /* Legacy Endpoint */
+#define PCI_EXP_TYPE_DOWNSTREAM PCIEM_TYPE_DOWNSTREAM_PORT /* Downstream Port */
+#define PCI_EXP_FLAGS_SLOT PCIEM_FLAGS_SLOT /* Slot implemented */
+#define PCI_EXP_TYPE_RC_EC PCIEM_TYPE_ROOT_EC /* Root Complex Event Collector */
+#define PCI_EXP_LNKCAP_SLS_2_5GB 0x01 /* Supported Link Speed 2.5GT/s */
+#define PCI_EXP_LNKCAP_SLS_5_0GB 0x02 /* Supported Link Speed 5.0GT/s */
+#define PCI_EXP_LNKCAP_SLS_8_0GB 0x04 /* Supported Link Speed 8.0GT/s */
+#define PCI_EXP_LNKCAP_SLS_16_0GB 0x08 /* Supported Link Speed 16.0GT/s */
+#define PCI_EXP_LNKCAP_MLW 0x03f0 /* Maximum Link Width */
+#define PCI_EXP_LNKCAP2_SLS_2_5GB 0x02 /* Supported Link Speed 2.5GT/s */
+#define PCI_EXP_LNKCAP2_SLS_5_0GB 0x04 /* Supported Link Speed 5.0GT/s */
+#define PCI_EXP_LNKCAP2_SLS_8_0GB 0x08 /* Supported Link Speed 8.0GT/s */
+#define PCI_EXP_LNKCAP2_SLS_16_0GB 0x10 /* Supported Link Speed 16.0GT/s */
+
+#define PCI_EXP_LNKCTL_HAWD PCIEM_LINK_CTL_HAWD
+#define PCI_EXP_LNKCAP_CLKPM 0x00040000
+#define PCI_EXP_DEVSTA_TRPND 0x0020
+
+#define IORESOURCE_MEM (1 << SYS_RES_MEMORY)
+#define IORESOURCE_IO (1 << SYS_RES_IOPORT)
+#define IORESOURCE_IRQ (1 << SYS_RES_IRQ)
+
+enum pci_bus_speed {
+ PCI_SPEED_UNKNOWN = -1,
+ PCIE_SPEED_2_5GT,
+ PCIE_SPEED_5_0GT,
+ PCIE_SPEED_8_0GT,
+ PCIE_SPEED_16_0GT,
+};
+
+enum pcie_link_width {
+ PCIE_LNK_WIDTH_RESRV = 0x00,
+ PCIE_LNK_X1 = 0x01,
+ PCIE_LNK_X2 = 0x02,
+ PCIE_LNK_X4 = 0x04,
+ PCIE_LNK_X8 = 0x08,
+ PCIE_LNK_X12 = 0x0c,
+ PCIE_LNK_X16 = 0x10,
+ PCIE_LNK_X32 = 0x20,
+ PCIE_LNK_WIDTH_UNKNOWN = 0xff,
+};
+
+typedef int pci_power_t;
+
+#define PCI_D0 PCI_POWERSTATE_D0
+#define PCI_D1 PCI_POWERSTATE_D1
+#define PCI_D2 PCI_POWERSTATE_D2
+#define PCI_D3hot PCI_POWERSTATE_D3
+#define PCI_D3cold 4
+
+#define PCI_POWER_ERROR PCI_POWERSTATE_UNKNOWN
+
+struct pci_dev;
+
+struct pci_driver {
+ struct list_head links;
+ char *name;
+ const struct pci_device_id *id_table;
+ int (*probe)(struct pci_dev *dev, const struct pci_device_id *id);
+ void (*remove)(struct pci_dev *dev);
+ int (*suspend) (struct pci_dev *dev, pm_message_t state); /* Device suspended */
+ int (*resume) (struct pci_dev *dev); /* Device woken up */
+ void (*shutdown) (struct pci_dev *dev); /* Device shutdown */
+ driver_t bsddriver;
+ devclass_t bsdclass;
+ struct device_driver driver;
+ const struct pci_error_handlers *err_handler;
+ bool isdrm;
+ int (*bsd_iov_init)(device_t dev, uint16_t num_vfs,
+ const nvlist_t *pf_config);
+ void (*bsd_iov_uninit)(device_t dev);
+ int (*bsd_iov_add_vf)(device_t dev, uint16_t vfnum,
+ const nvlist_t *vf_config);
+};
+
+struct pci_bus {
+ struct pci_dev *self;
+ int domain;
+ int number;
+};
+
+extern struct list_head pci_drivers;
+extern struct list_head pci_devices;
+extern spinlock_t pci_lock;
+
+#define __devexit_p(x) x
+
+struct pci_mmio_region {
+ TAILQ_ENTRY(pci_mmio_region) next;
+ struct resource *res;
+ int rid;
+ int type;
+};
+
+struct pci_dev {
+ struct device dev;
+ struct list_head links;
+ struct pci_driver *pdrv;
+ struct pci_bus *bus;
+ uint16_t device;
+ uint16_t vendor;
+ uint16_t subsystem_vendor;
+ uint16_t subsystem_device;
+ unsigned int irq;
+ unsigned int devfn;
+ uint32_t class;
+ uint8_t revision;
+ bool msi_enabled;
+
+ TAILQ_HEAD(, pci_mmio_region) mmio;
+};
+
+static inline struct resource_list_entry *
+linux_pci_get_rle(struct pci_dev *pdev, int type, int rid)
+{
+ struct pci_devinfo *dinfo;
+ struct resource_list *rl;
+
+ dinfo = device_get_ivars(pdev->dev.bsddev);
+ rl = &dinfo->resources;
+ return resource_list_find(rl, type, rid);
+}
+
+static inline struct resource_list_entry *
+linux_pci_get_bar(struct pci_dev *pdev, int bar)
+{
+ struct resource_list_entry *rle;
+
+ bar = PCIR_BAR(bar);
+ if ((rle = linux_pci_get_rle(pdev, SYS_RES_MEMORY, bar)) == NULL)
+ rle = linux_pci_get_rle(pdev, SYS_RES_IOPORT, bar);
+ return (rle);
+}
+
+static inline struct device *
+linux_pci_find_irq_dev(unsigned int irq)
+{
+ struct pci_dev *pdev;
+ struct device *found;
+
+ found = NULL;
+ spin_lock(&pci_lock);
+ list_for_each_entry(pdev, &pci_devices, links) {
+ if (irq == pdev->dev.irq ||
+ (irq >= pdev->dev.irq_start && irq < pdev->dev.irq_end)) {
+ found = &pdev->dev;
+ break;
+ }
+ }
+ spin_unlock(&pci_lock);
+ return (found);
+}
+
+static inline int
+pci_resource_type(struct pci_dev *pdev, int bar)
+{
+ struct pci_map *pm;
+
+ pm = pci_find_bar(pdev->dev.bsddev, PCIR_BAR(bar));
+ if (!pm)
+ return (-1);
+
+ if (PCI_BAR_IO(pm->pm_value))
+ return (SYS_RES_IOPORT);
+ else
+ return (SYS_RES_MEMORY);
+}
+
+/*
+ * All drivers just seem to want to inspect the type not flags.
+ */
+static inline int
+pci_resource_flags(struct pci_dev *pdev, int bar)
+{
+ int type;
+
+ type = pci_resource_type(pdev, bar);
+ if (type < 0)
+ return (0);
+ return (1 << type);
+}
+
+static inline const char *
+pci_name(struct pci_dev *d)
+{
+
+ return device_get_desc(d->dev.bsddev);
+}
+
+static inline void *
+pci_get_drvdata(struct pci_dev *pdev)
+{
+
+ return dev_get_drvdata(&pdev->dev);
+}
+
+static inline void
+pci_set_drvdata(struct pci_dev *pdev, void *data)
+{
+
+ dev_set_drvdata(&pdev->dev, data);
+}
+
+static __inline void
+pci_dev_put(struct pci_dev *pdev)
+{
+
+ if (pdev != NULL)
+ put_device(&pdev->dev);
+}
+
+static inline int
+pci_enable_device(struct pci_dev *pdev)
+{
+
+ pci_enable_io(pdev->dev.bsddev, SYS_RES_IOPORT);
+ pci_enable_io(pdev->dev.bsddev, SYS_RES_MEMORY);
+ return (0);
+}
+
+static inline void
+pci_disable_device(struct pci_dev *pdev)
+{
+
+ pci_disable_busmaster(pdev->dev.bsddev);
+}
+
+static inline int
+pci_set_master(struct pci_dev *pdev)
+{
+
+ pci_enable_busmaster(pdev->dev.bsddev);
+ return (0);
+}
+
+static inline int
+pci_set_power_state(struct pci_dev *pdev, int state)
+{
+
+ pci_set_powerstate(pdev->dev.bsddev, state);
+ return (0);
+}
+
+static inline int
+pci_clear_master(struct pci_dev *pdev)
+{
+
+ pci_disable_busmaster(pdev->dev.bsddev);
+ return (0);
+}
+
+static inline int
+pci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
+{
+ int rid;
+ int type;
+
+ type = pci_resource_type(pdev, bar);
+ if (type < 0)
+ return (-ENODEV);
+ rid = PCIR_BAR(bar);
+ if (bus_alloc_resource_any(pdev->dev.bsddev, type, &rid,
+ RF_ACTIVE) == NULL)
+ return (-EINVAL);
+ return (0);
+}
+
+static inline void
+pci_release_region(struct pci_dev *pdev, int bar)
+{
+ struct resource_list_entry *rle;
+
+ if ((rle = linux_pci_get_bar(pdev, bar)) == NULL)
+ return;
+ bus_release_resource(pdev->dev.bsddev, rle->type, rle->rid, rle->res);
+}
+
+static inline void
+pci_release_regions(struct pci_dev *pdev)
+{
+ int i;
+
+ for (i = 0; i <= PCIR_MAX_BAR_0; i++)
+ pci_release_region(pdev, i);
+}
+
+static inline int
+pci_request_regions(struct pci_dev *pdev, const char *res_name)
+{
+ int error;
+ int i;
+
+ for (i = 0; i <= PCIR_MAX_BAR_0; i++) {
+ error = pci_request_region(pdev, i, res_name);
+ if (error && error != -ENODEV) {
+ pci_release_regions(pdev);
+ return (error);
+ }
+ }
+ return (0);
+}
+
+static inline void
+pci_disable_msix(struct pci_dev *pdev)
+{
+
+ pci_release_msi(pdev->dev.bsddev);
+
+ /*
+ * The MSIX IRQ numbers associated with this PCI device are no
+ * longer valid and might be re-assigned. Make sure
+ * linux_pci_find_irq_dev() does no longer see them by
+ * resetting their references to zero:
+ */
+ pdev->dev.irq_start = 0;
+ pdev->dev.irq_end = 0;
+}
+
+#define pci_disable_msi(pdev) \
+ linux_pci_disable_msi(pdev)
+
+static inline void
+linux_pci_disable_msi(struct pci_dev *pdev)
+{
+
+ pci_release_msi(pdev->dev.bsddev);
+
+ pdev->dev.irq_start = 0;
+ pdev->dev.irq_end = 0;
+ pdev->irq = pdev->dev.irq;
+ pdev->msi_enabled = false;
+}
+
+#define pci_free_irq_vectors(pdev) \
+ linux_pci_disable_msi(pdev)
+
+unsigned long pci_resource_start(struct pci_dev *pdev, int bar);
+unsigned long pci_resource_len(struct pci_dev *pdev, int bar);
+
+static inline bus_addr_t
+pci_bus_address(struct pci_dev *pdev, int bar)
+{
+
+ return (pci_resource_start(pdev, bar));
+}
+
+#define PCI_CAP_ID_EXP PCIY_EXPRESS
+#define PCI_CAP_ID_PCIX PCIY_PCIX
+#define PCI_CAP_ID_AGP PCIY_AGP
+#define PCI_CAP_ID_PM PCIY_PMG
+
+#define PCI_EXP_DEVCTL PCIER_DEVICE_CTL
+#define PCI_EXP_DEVCTL_PAYLOAD PCIEM_CTL_MAX_PAYLOAD
+#define PCI_EXP_DEVCTL_READRQ PCIEM_CTL_MAX_READ_REQUEST
+#define PCI_EXP_LNKCTL PCIER_LINK_CTL
+#define PCI_EXP_LNKSTA PCIER_LINK_STA
+
+static inline int
+pci_find_capability(struct pci_dev *pdev, int capid)
+{
+ int reg;
+
+ if (pci_find_cap(pdev->dev.bsddev, capid, &reg))
+ return (0);
+ return (reg);
+}
+
+static inline int pci_pcie_cap(struct pci_dev *dev)
+{
+ return pci_find_capability(dev, PCI_CAP_ID_EXP);
+}
+
+static inline int
+pci_read_config_byte(struct pci_dev *pdev, int where, u8 *val)
+{
+
+ *val = (u8)pci_read_config(pdev->dev.bsddev, where, 1);
+ return (0);
+}
+
+static inline int
+pci_read_config_word(struct pci_dev *pdev, int where, u16 *val)
+{
+
+ *val = (u16)pci_read_config(pdev->dev.bsddev, where, 2);
+ return (0);
+}
+
+static inline int
+pci_read_config_dword(struct pci_dev *pdev, int where, u32 *val)
+{
+
+ *val = (u32)pci_read_config(pdev->dev.bsddev, where, 4);
+ return (0);
+}
+
+static inline int
+pci_write_config_byte(struct pci_dev *pdev, int where, u8 val)
+{
+
+ pci_write_config(pdev->dev.bsddev, where, val, 1);
+ return (0);
+}
+
+static inline int
+pci_write_config_word(struct pci_dev *pdev, int where, u16 val)
+{
+
+ pci_write_config(pdev->dev.bsddev, where, val, 2);
+ return (0);
+}
+
+static inline int
+pci_write_config_dword(struct pci_dev *pdev, int where, u32 val)
+{
+
+ pci_write_config(pdev->dev.bsddev, where, val, 4);
+ return (0);
+}
+
+int linux_pci_register_driver(struct pci_driver *pdrv);
+int linux_pci_register_drm_driver(struct pci_driver *pdrv);
+void linux_pci_unregister_driver(struct pci_driver *pdrv);
+void linux_pci_unregister_drm_driver(struct pci_driver *pdrv);
+
+#define pci_register_driver(pdrv) linux_pci_register_driver(pdrv)
+#define pci_unregister_driver(pdrv) linux_pci_unregister_driver(pdrv)
+
+struct msix_entry {
+ int entry;
+ int vector;
+};
+
+/*
+ * Enable msix, positive errors indicate actual number of available
+ * vectors. Negative errors are failures.
+ *
+ * NB: define added to prevent this definition of pci_enable_msix from
+ * clashing with the native FreeBSD version.
+ */
+#define pci_enable_msix(...) \
+ linux_pci_enable_msix(__VA_ARGS__)
+
+static inline int
+pci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries, int nreq)
+{
+ struct resource_list_entry *rle;
+ int error;
+ int avail;
+ int i;
+
+ avail = pci_msix_count(pdev->dev.bsddev);
+ if (avail < nreq) {
+ if (avail == 0)
+ return -EINVAL;
+ return avail;
+ }
+ avail = nreq;
+ if ((error = -pci_alloc_msix(pdev->dev.bsddev, &avail)) != 0)
+ return error;
+ /*
+ * Handle case where "pci_alloc_msix()" may allocate less
+ * interrupts than available and return with no error:
+ */
+ if (avail < nreq) {
+ pci_release_msi(pdev->dev.bsddev);
+ return avail;
+ }
+ rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 1);
+ pdev->dev.irq_start = rle->start;
+ pdev->dev.irq_end = rle->start + avail;
+ for (i = 0; i < nreq; i++)
+ entries[i].vector = pdev->dev.irq_start + i;
+ return (0);
+}
+
+#define pci_enable_msix_range(...) \
+ linux_pci_enable_msix_range(__VA_ARGS__)
+
+static inline int
+pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
+ int minvec, int maxvec)
+{
+ int nvec = maxvec;
+ int rc;
+
+ if (maxvec < minvec)
+ return (-ERANGE);
+
+ do {
+ rc = pci_enable_msix(dev, entries, nvec);
+ if (rc < 0) {
+ return (rc);
+ } else if (rc > 0) {
+ if (rc < minvec)
+ return (-ENOSPC);
+ nvec = rc;
+ }
+ } while (rc);
+ return (nvec);
+}
+
+#define pci_enable_msi(pdev) \
+ linux_pci_enable_msi(pdev)
+
+static inline int
+pci_enable_msi(struct pci_dev *pdev)
+{
+ struct resource_list_entry *rle;
+ int error;
+ int avail;
+
+ avail = pci_msi_count(pdev->dev.bsddev);
+ if (avail < 1)
+ return -EINVAL;
+
+ avail = 1; /* this function only enable one MSI IRQ */
+ if ((error = -pci_alloc_msi(pdev->dev.bsddev, &avail)) != 0)
+ return error;
+
+ rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 1);
+ pdev->dev.irq_start = rle->start;
+ pdev->dev.irq_end = rle->start + avail;
+ pdev->irq = rle->start;
+ pdev->msi_enabled = true;
+ return (0);
+}
+
+static inline int
+pci_channel_offline(struct pci_dev *pdev)
+{
+
+ return (pci_read_config(pdev->dev.bsddev, PCIR_VENDOR, 2) == PCIV_INVALID);
+}
+
+static inline int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
+{
+ return -ENODEV;
+}
+static inline void pci_disable_sriov(struct pci_dev *dev)
+{
+}
+
+static inline void *
+pci_iomap(struct pci_dev *dev, int mmio_bar, int mmio_size __unused)
+{
+ struct pci_mmio_region *mmio;
+
+ mmio = malloc(sizeof(*mmio), M_DEVBUF, M_WAITOK | M_ZERO);
+ mmio->rid = PCIR_BAR(mmio_bar);
+ mmio->type = pci_resource_type(dev, mmio_bar);
+ mmio->res = bus_alloc_resource_any(dev->dev.bsddev, mmio->type,
+ &mmio->rid, RF_ACTIVE);
+ if (mmio->res == NULL) {
+ free(mmio, M_DEVBUF);
+ return (NULL);
+ }
+ TAILQ_INSERT_TAIL(&dev->mmio, mmio, next);
+
+ return ((void *)rman_get_bushandle(mmio->res));
+}
+
+static inline void
+pci_iounmap(struct pci_dev *dev, void *res)
+{
+ struct pci_mmio_region *mmio, *p;
+
+ TAILQ_FOREACH_SAFE(mmio, &dev->mmio, next, p) {
+ if (res != (void *)rman_get_bushandle(mmio->res))
+ continue;
+ bus_release_resource(dev->dev.bsddev,
+ mmio->type, mmio->rid, mmio->res);
+ TAILQ_REMOVE(&dev->mmio, mmio, next);
+ free(mmio, M_DEVBUF);
+ return;
+ }
+}
+
+static inline void
+lkpi_pci_save_state(struct pci_dev *pdev)
+{
+
+ pci_save_state(pdev->dev.bsddev);
+}
+
+static inline void
+lkpi_pci_restore_state(struct pci_dev *pdev)
+{
+
+ pci_restore_state(pdev->dev.bsddev);
+}
+
+#define pci_save_state(dev) lkpi_pci_save_state(dev)
+#define pci_restore_state(dev) lkpi_pci_restore_state(dev)
+
+#define DEFINE_PCI_DEVICE_TABLE(_table) \
+ const struct pci_device_id _table[] __devinitdata
+
+/* XXX This should not be necessary. */
+#define pcix_set_mmrbc(d, v) 0
+#define pcix_get_max_mmrbc(d) 0
+#define pcie_set_readrq(d, v) pci_set_max_read_req(&(d)->dev, (v))
+
+#define PCI_DMA_BIDIRECTIONAL 0
+#define PCI_DMA_TODEVICE 1
+#define PCI_DMA_FROMDEVICE 2
+#define PCI_DMA_NONE 3
+
+#define pci_pool dma_pool
+#define pci_pool_destroy(...) dma_pool_destroy(__VA_ARGS__)
+#define pci_pool_alloc(...) dma_pool_alloc(__VA_ARGS__)
+#define pci_pool_free(...) dma_pool_free(__VA_ARGS__)
+#define pci_pool_create(_name, _pdev, _size, _align, _alloc) \
+ dma_pool_create(_name, &(_pdev)->dev, _size, _align, _alloc)
+#define pci_free_consistent(_hwdev, _size, _vaddr, _dma_handle) \
+ dma_free_coherent((_hwdev) == NULL ? NULL : &(_hwdev)->dev, \
+ _size, _vaddr, _dma_handle)
+#define pci_map_sg(_hwdev, _sg, _nents, _dir) \
+ dma_map_sg((_hwdev) == NULL ? NULL : &(_hwdev->dev), \
+ _sg, _nents, (enum dma_data_direction)_dir)
+#define pci_map_single(_hwdev, _ptr, _size, _dir) \
+ dma_map_single((_hwdev) == NULL ? NULL : &(_hwdev->dev), \
+ (_ptr), (_size), (enum dma_data_direction)_dir)
+#define pci_unmap_single(_hwdev, _addr, _size, _dir) \
+ dma_unmap_single((_hwdev) == NULL ? NULL : &(_hwdev)->dev, \
+ _addr, _size, (enum dma_data_direction)_dir)
+#define pci_unmap_sg(_hwdev, _sg, _nents, _dir) \
+ dma_unmap_sg((_hwdev) == NULL ? NULL : &(_hwdev)->dev, \
+ _sg, _nents, (enum dma_data_direction)_dir)
+#define pci_map_page(_hwdev, _page, _offset, _size, _dir) \
+ dma_map_page((_hwdev) == NULL ? NULL : &(_hwdev)->dev, _page,\
+ _offset, _size, (enum dma_data_direction)_dir)
+#define pci_unmap_page(_hwdev, _dma_address, _size, _dir) \
+ dma_unmap_page((_hwdev) == NULL ? NULL : &(_hwdev)->dev, \
+ _dma_address, _size, (enum dma_data_direction)_dir)
+#define pci_set_dma_mask(_pdev, mask) dma_set_mask(&(_pdev)->dev, (mask))
+#define pci_dma_mapping_error(_pdev, _dma_addr) \
+ dma_mapping_error(&(_pdev)->dev, _dma_addr)
+#define pci_set_consistent_dma_mask(_pdev, _mask) \
+ dma_set_coherent_mask(&(_pdev)->dev, (_mask))
+#define DECLARE_PCI_UNMAP_ADDR(x) DEFINE_DMA_UNMAP_ADDR(x);
+#define DECLARE_PCI_UNMAP_LEN(x) DEFINE_DMA_UNMAP_LEN(x);
+#define pci_unmap_addr dma_unmap_addr
+#define pci_unmap_addr_set dma_unmap_addr_set
+#define pci_unmap_len dma_unmap_len
+#define pci_unmap_len_set dma_unmap_len_set
+
+typedef unsigned int __bitwise pci_channel_state_t;
+typedef unsigned int __bitwise pci_ers_result_t;
+
+enum pci_channel_state {
+ pci_channel_io_normal = 1,
+ pci_channel_io_frozen = 2,
+ pci_channel_io_perm_failure = 3,
+};
+
+enum pci_ers_result {
+ PCI_ERS_RESULT_NONE = 1,
+ PCI_ERS_RESULT_CAN_RECOVER = 2,
+ PCI_ERS_RESULT_NEED_RESET = 3,
+ PCI_ERS_RESULT_DISCONNECT = 4,
+ PCI_ERS_RESULT_RECOVERED = 5,
+};
+
+/* PCI bus error event callbacks */
+struct pci_error_handlers {
+ pci_ers_result_t (*error_detected)(struct pci_dev *dev,
+ enum pci_channel_state error);
+ pci_ers_result_t (*mmio_enabled)(struct pci_dev *dev);
+ pci_ers_result_t (*link_reset)(struct pci_dev *dev);
+ pci_ers_result_t (*slot_reset)(struct pci_dev *dev);
+ void (*resume)(struct pci_dev *dev);
+};
+
+/* FreeBSD does not support SRIOV - yet */
+static inline struct pci_dev *pci_physfn(struct pci_dev *dev)
+{
+ return dev;
+}
+
+static inline bool pci_is_pcie(struct pci_dev *dev)
+{
+ return !!pci_pcie_cap(dev);
+}
+
+static inline u16 pcie_flags_reg(struct pci_dev *dev)
+{
+ int pos;
+ u16 reg16;
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (!pos)
+ return 0;
+
+ pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &reg16);
+
+ return reg16;
+}
+
+static inline int pci_pcie_type(struct pci_dev *dev)
+{
+ return (pcie_flags_reg(dev) & PCI_EXP_FLAGS_TYPE) >> 4;
+}
+
+static inline int pcie_cap_version(struct pci_dev *dev)
+{
+ return pcie_flags_reg(dev) & PCI_EXP_FLAGS_VERS;
+}
+
+static inline bool pcie_cap_has_lnkctl(struct pci_dev *dev)
+{
+ int type = pci_pcie_type(dev);
+
+ return pcie_cap_version(dev) > 1 ||
+ type == PCI_EXP_TYPE_ROOT_PORT ||
+ type == PCI_EXP_TYPE_ENDPOINT ||
+ type == PCI_EXP_TYPE_LEG_END;
+}
+
+static inline bool pcie_cap_has_devctl(const struct pci_dev *dev)
+{
+ return true;
+}
+
+static inline bool pcie_cap_has_sltctl(struct pci_dev *dev)
+{
+ int type = pci_pcie_type(dev);
+
+ return pcie_cap_version(dev) > 1 || type == PCI_EXP_TYPE_ROOT_PORT ||
+ (type == PCI_EXP_TYPE_DOWNSTREAM &&
+ pcie_flags_reg(dev) & PCI_EXP_FLAGS_SLOT);
+}
+
+static inline bool pcie_cap_has_rtctl(struct pci_dev *dev)
+{
+ int type = pci_pcie_type(dev);
+
+ return pcie_cap_version(dev) > 1 || type == PCI_EXP_TYPE_ROOT_PORT ||
+ type == PCI_EXP_TYPE_RC_EC;
+}
+
+static bool pcie_capability_reg_implemented(struct pci_dev *dev, int pos)
+{
+ if (!pci_is_pcie(dev))
+ return false;
+
+ switch (pos) {
+ case PCI_EXP_FLAGS_TYPE:
+ return true;
+ case PCI_EXP_DEVCAP:
+ case PCI_EXP_DEVCTL:
+ case PCI_EXP_DEVSTA:
+ return pcie_cap_has_devctl(dev);
+ case PCI_EXP_LNKCAP:
+ case PCI_EXP_LNKCTL:
+ case PCI_EXP_LNKSTA:
+ return pcie_cap_has_lnkctl(dev);
+ case PCI_EXP_SLTCAP:
+ case PCI_EXP_SLTCTL:
+ case PCI_EXP_SLTSTA:
+ return pcie_cap_has_sltctl(dev);
+ case PCI_EXP_RTCTL:
+ case PCI_EXP_RTCAP:
+ case PCI_EXP_RTSTA:
+ return pcie_cap_has_rtctl(dev);
+ case PCI_EXP_DEVCAP2:
+ case PCI_EXP_DEVCTL2:
+ case PCI_EXP_LNKCAP2:
+ case PCI_EXP_LNKCTL2:
+ case PCI_EXP_LNKSTA2:
+ return pcie_cap_version(dev) > 1;
+ default:
+ return false;
+ }
+}
+
+static inline int
+pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *dst)
+{
+ if (pos & 3)
+ return -EINVAL;
+
+ if (!pcie_capability_reg_implemented(dev, pos))
+ return -EINVAL;
+
+ return pci_read_config_dword(dev, pci_pcie_cap(dev) + pos, dst);
+}
+
+static inline int
+pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *dst)
+{
+ if (pos & 3)
+ return -EINVAL;
+
+ if (!pcie_capability_reg_implemented(dev, pos))
+ return -EINVAL;
+
+ return pci_read_config_word(dev, pci_pcie_cap(dev) + pos, dst);
+}
+
+static inline int
+pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val)
+{
+ if (pos & 1)
+ return -EINVAL;
+
+ if (!pcie_capability_reg_implemented(dev, pos))
+ return 0;
+
+ return pci_write_config_word(dev, pci_pcie_cap(dev) + pos, val);
+}
+
+static inline int pcie_get_minimum_link(struct pci_dev *dev,
+ enum pci_bus_speed *speed, enum pcie_link_width *width)
+{
+ *speed = PCI_SPEED_UNKNOWN;
+ *width = PCIE_LNK_WIDTH_UNKNOWN;
+ return (0);
+}
+
+static inline int
+pci_num_vf(struct pci_dev *dev)
+{
+ return (0);
+}
+
+static inline enum pci_bus_speed
+pcie_get_speed_cap(struct pci_dev *dev)
+{
+ device_t root;
+ uint32_t lnkcap, lnkcap2;
+ int error, pos;
+
+ root = device_get_parent(dev->dev.bsddev);
+ if (root == NULL)
+ return (PCI_SPEED_UNKNOWN);
+ root = device_get_parent(root);
+ if (root == NULL)
+ return (PCI_SPEED_UNKNOWN);
+ root = device_get_parent(root);
+ if (root == NULL)
+ return (PCI_SPEED_UNKNOWN);
+
+ if (pci_get_vendor(root) == PCI_VENDOR_ID_VIA ||
+ pci_get_vendor(root) == PCI_VENDOR_ID_SERVERWORKS)
+ return (PCI_SPEED_UNKNOWN);
+
+ if ((error = pci_find_cap(root, PCIY_EXPRESS, &pos)) != 0)
+ return (PCI_SPEED_UNKNOWN);
+
+ lnkcap2 = pci_read_config(root, pos + PCIER_LINK_CAP2, 4);
+
+ if (lnkcap2) { /* PCIe r3.0-compliant */
+ if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_2_5GB)
+ return (PCIE_SPEED_2_5GT);
+ if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_5_0GB)
+ return (PCIE_SPEED_5_0GT);
+ if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_8_0GB)
+ return (PCIE_SPEED_8_0GT);
+ if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_16_0GB)
+ return (PCIE_SPEED_16_0GT);
+ } else { /* pre-r3.0 */
+ lnkcap = pci_read_config(root, pos + PCIER_LINK_CAP, 4);
+ if (lnkcap & PCI_EXP_LNKCAP_SLS_2_5GB)
+ return (PCIE_SPEED_2_5GT);
+ if (lnkcap & PCI_EXP_LNKCAP_SLS_5_0GB)
+ return (PCIE_SPEED_5_0GT);
+ if (lnkcap & PCI_EXP_LNKCAP_SLS_8_0GB)
+ return (PCIE_SPEED_8_0GT);
+ if (lnkcap & PCI_EXP_LNKCAP_SLS_16_0GB)
+ return (PCIE_SPEED_16_0GT);
+ }
+ return (PCI_SPEED_UNKNOWN);
+}
+
+static inline enum pcie_link_width
+pcie_get_width_cap(struct pci_dev *dev)
+{
+ uint32_t lnkcap;
+
+ pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap);
+ if (lnkcap)
+ return ((lnkcap & PCI_EXP_LNKCAP_MLW) >> 4);
+
+ return (PCIE_LNK_WIDTH_UNKNOWN);
+}
+
+static inline int
+pcie_get_mps(struct pci_dev *dev)
+{
+ return (pci_get_max_payload(dev->dev.bsddev));
+}
+
+static inline uint32_t
+PCIE_SPEED2MBS_ENC(enum pci_bus_speed spd)
+{
+
+ switch(spd) {
+ case PCIE_SPEED_16_0GT:
+ return (16000 * 128 / 130);
+ case PCIE_SPEED_8_0GT:
+ return (8000 * 128 / 130);
+ case PCIE_SPEED_5_0GT:
+ return (5000 * 8 / 10);
+ case PCIE_SPEED_2_5GT:
+ return (2500 * 8 / 10);
+ default:
+ return (0);
+ }
+}
+
+static inline uint32_t
+pcie_bandwidth_available(struct pci_dev *pdev,
+ struct pci_dev **limiting,
+ enum pci_bus_speed *speed,
+ enum pcie_link_width *width)
+{
+ enum pci_bus_speed nspeed = pcie_get_speed_cap(pdev);
+ enum pcie_link_width nwidth = pcie_get_width_cap(pdev);
+
+ if (speed)
+ *speed = nspeed;
+ if (width)
+ *width = nwidth;
+
+ return (nwidth * PCIE_SPEED2MBS_ENC(nspeed));
+}
+
+/*
+ * The following functions can be used to attach/detach the LinuxKPI's
+ * PCI device runtime. The pci_driver and pci_device_id pointer is
+ * allowed to be NULL. Other pointers must be all valid.
+ * The pci_dev structure should be zero-initialized before passed
+ * to the linux_pci_attach_device function.
+ */
+extern int linux_pci_attach_device(device_t, struct pci_driver *,
+ const struct pci_device_id *, struct pci_dev *);
+extern int linux_pci_detach_device(struct pci_dev *);
+
+static inline int
+pci_dev_present(const struct pci_device_id *cur)
+{
+ while (cur != NULL && (cur->vendor || cur->device)) {
+ if (pci_find_device(cur->vendor, cur->device) != NULL) {
+ return (1);
+ }
+ cur++;
+ }
+ return (0);
+}
+
+static inline bool
+pci_is_root_bus(struct pci_bus *pbus)
+{
+
+ return (pbus->self == NULL);
+}
+
+struct pci_dev *lkpi_pci_get_domain_bus_and_slot(int domain,
+ unsigned int bus, unsigned int devfn);
+#define pci_get_domain_bus_and_slot(domain, bus, devfn) \
+ lkpi_pci_get_domain_bus_and_slot(domain, bus, devfn)
+
+static inline int
+pci_domain_nr(struct pci_bus *pbus)
+{
+
+ return (pbus->domain);
+}
+
+static inline int
+pci_bus_read_config(struct pci_bus *bus, unsigned int devfn,
+ int pos, uint32_t *val, int len)
+{
+
+ *val = pci_read_config(bus->self->dev.bsddev, pos, len);
+ return (0);
+}
+
+static inline int
+pci_bus_read_config_word(struct pci_bus *bus, unsigned int devfn, int pos, u16 *val)
+{
+ uint32_t tmp;
+ int ret;
+
+ ret = pci_bus_read_config(bus, devfn, pos, &tmp, 2);
+ *val = (u16)tmp;
+ return (ret);
+}
+
+static inline int
+pci_bus_read_config_byte(struct pci_bus *bus, unsigned int devfn, int pos, u8 *val)
+{
+ uint32_t tmp;
+ int ret;
+
+ ret = pci_bus_read_config(bus, devfn, pos, &tmp, 1);
+ *val = (u8)tmp;
+ return (ret);
+}
+
+static inline int
+pci_bus_write_config(struct pci_bus *bus, unsigned int devfn, int pos,
+ uint32_t val, int size)
+{
+
+ pci_write_config(bus->self->dev.bsddev, pos, val, size);
+ return (0);
+}
+
+static inline int
+pci_bus_write_config_byte(struct pci_bus *bus, unsigned int devfn, int pos,
+ uint8_t val)
+{
+ return (pci_bus_write_config(bus, devfn, pos, val, 1));
+}
+
+static inline int
+pci_bus_write_config_word(struct pci_bus *bus, unsigned int devfn, int pos,
+ uint16_t val)
+{
+ return (pci_bus_write_config(bus, devfn, pos, val, 2));
+}
+
+struct pci_dev *lkpi_pci_get_class(unsigned int class, struct pci_dev *from);
+#define pci_get_class(class, from) lkpi_pci_get_class(class, from)
+
+#endif /* _LINUX_PCI_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/pfn.h b/sys/compat/linuxkpi/common/include/linux/pfn.h
new file mode 100644
index 000000000000..162ca102c951
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/pfn.h
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_PFN_H_
+#define _LINUX_PFN_H_
+
+#include <linux/types.h>
+
+typedef struct {
+ u64 val;
+} pfn_t;
+
+#define PFN_ALIGN(x) (((unsigned long)(x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
+#define PFN_UP(x) (((x) + PAGE_SIZE - 1) >> PAGE_SHIFT)
+#define PFN_DOWN(x) ((x) >> PAGE_SHIFT)
+#define PFN_PHYS(x) ((phys_addr_t)(x) << PAGE_SHIFT)
+#define PHYS_PFN(x) ((unsigned long)((x) >> PAGE_SHIFT))
+
+#endif /* _LINUX_PFN_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/pfn_t.h b/sys/compat/linuxkpi/common/include/linux/pfn_t.h
new file mode 100644
index 000000000000..bfa80b14ae94
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/pfn_t.h
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_PFN_T_H_
+#define _LINUX_PFN_T_H_
+
+#include <linux/mm.h>
+
+CTASSERT(PAGE_SHIFT > 4);
+
+#define PFN_FLAGS_MASK (((u64)(PAGE_SIZE - 1)) << (64 - PAGE_SHIFT))
+#define PFN_SG_CHAIN (1ULL << (64 - 1))
+#define PFN_SG_LAST (1ULL << (64 - 2))
+#define PFN_DEV (1ULL << (64 - 3))
+#define PFN_MAP (1ULL << (64 - 4))
+
+static inline pfn_t
+__pfn_to_pfn_t(unsigned long pfn, u64 flags)
+{
+ pfn_t pfn_t = { pfn | (flags & PFN_FLAGS_MASK) };
+
+ return (pfn_t);
+}
+
+static inline pfn_t
+pfn_to_pfn_t(unsigned long pfn)
+{
+ return (__pfn_to_pfn_t (pfn, 0));
+}
+
+#endif /* _LINUX_PFN_T_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/pid.h b/sys/compat/linuxkpi/common/include/linux/pid.h
new file mode 100644
index 000000000000..73d8f1f6edfe
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/pid.h
@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_PID_H_
+#define _LINUX_PID_H_
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+
+enum pid_type {
+ PIDTYPE_PID,
+ PIDTYPE_PGID,
+ PIDTYPE_SID,
+ PIDTYPE_MAX
+};
+
+#define pid_nr(n) (n)
+#define pid_vnr(n) (n)
+#define from_kuid_munged(a, uid) (uid)
+
+#define pid_task(pid, type) ({ \
+ struct task_struct *__ts; \
+ CTASSERT((type) == PIDTYPE_PID); \
+ __ts = linux_pid_task(pid); \
+ __ts; \
+})
+
+#define get_pid_task(pid, type) ({ \
+ struct task_struct *__ts; \
+ CTASSERT((type) == PIDTYPE_PID); \
+ __ts = linux_get_pid_task(pid); \
+ __ts; \
+})
+
+#define get_task_pid(task, type) ({ \
+ CTASSERT((type) == PIDTYPE_PID); \
+ (task)->task_thread->td_tid; \
+})
+
+struct task_struct;
+extern struct task_struct *linux_pid_task(pid_t);
+extern struct task_struct *linux_get_pid_task(pid_t);
+
+#endif /* _LINUX_PID_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/pm.h b/sys/compat/linuxkpi/common/include/linux/pm.h
new file mode 100644
index 000000000000..6b8a7e768a8c
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/pm.h
@@ -0,0 +1,52 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Björn Zeeb under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUXKPI_LINUX_PM_H
+#define _LINUXKPI_LINUX_PM_H
+
+#ifdef CONFIG_PM_SLEEP
+#define SIMPLE_DEV_PM_OPS(_name, _suspendfunc, _resumefunc) \
+const struct dev_pm_ops _name = { \
+ .suspend = _suspendfunc, \
+ .resume = _resumefunc, \
+ .freeze = _suspendfunc, \
+ .thaw = _resumefunc, \
+ .poweroff = _suspendfunc, \
+ .restore = _resumefunc, \
+}
+#else
+#define SIMPLE_DEV_PM_OPS(_name, _suspendfunc, _resumefunc) \
+const struct dev_pm_ops _name = { \
+}
+#endif
+
+#endif /* _LINUXKPI_LINUX_PM_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/poll.h b/sys/compat/linuxkpi/common/include/linux/poll.h
new file mode 100644
index 000000000000..33501165df24
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/poll.h
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_POLL_H_
+#define _LINUX_POLL_H_
+
+#include <sys/poll.h>
+#include <sys/fcntl.h>
+
+#include <linux/wait.h>
+#include <linux/file.h>
+
+typedef struct poll_table_struct {
+} poll_table;
+
+extern void linux_poll_wait(struct linux_file *, wait_queue_head_t *, poll_table *);
+#define poll_wait(...) linux_poll_wait(__VA_ARGS__)
+
+extern void linux_poll_wakeup(struct linux_file *);
+
+#endif /* _LINUX_POLL_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/power_supply.h b/sys/compat/linuxkpi/common/include/linux/power_supply.h
new file mode 100644
index 000000000000..6f6d8b28c5ee
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/power_supply.h
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Emmanuel Vadot under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_POWER_SUPPLY_H_
+#define _LINUX_POWER_SUPPLY_H_
+
+#include <sys/types.h>
+#include <sys/power.h>
+
+static inline int
+power_supply_is_system_supplied(void)
+{
+
+ return (power_profile_get_state() == POWER_PROFILE_PERFORMANCE);
+}
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/preempt.h b/sys/compat/linuxkpi/common/include/linux/preempt.h
new file mode 100644
index 000000000000..e19e7ee09a48
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/preempt.h
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_PREEMPT_H_
+#define _LINUX_PREEMPT_H_
+
+#include <linux/hardirq.h>
+#include <linux/list.h>
+
+#define in_interrupt() \
+ (curthread->td_intr_nesting_level || curthread->td_critnest)
+
+#define in_task() (curthread->td_priority >= PI_SOFT)
+
+#define preempt_disable() critical_enter()
+#define preempt_enable() critical_exit()
+
+#endif /* _LINUX_PREEMPT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/prefetch.h b/sys/compat/linuxkpi/common/include/linux/prefetch.h
new file mode 100644
index 000000000000..ed8f1838e178
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/prefetch.h
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Emmanuel Vadot under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_PREFETCH_H_
+#define _LINUX_PREFETCH_H_
+
+#define prefetchw(x) __builtin_prefetch(x,1)
+
+#endif /* _LINUX_PREFETCH_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/printk.h b/sys/compat/linuxkpi/common/include/linux/printk.h
new file mode 100644
index 000000000000..e6510e9e9834
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/printk.h
@@ -0,0 +1,130 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_PRINTK_H_
+#define _LINUX_PRINTK_H_
+
+#include <linux/kernel.h>
+
+/* GID printing macros */
+#define GID_PRINT_FMT "%.4x:%.4x:%.4x:%.4x:%.4x:%.4x:%.4x:%.4x"
+#define GID_PRINT_ARGS(gid_raw) htons(((u16 *)gid_raw)[0]), htons(((u16 *)gid_raw)[1]),\
+ htons(((u16 *)gid_raw)[2]), htons(((u16 *)gid_raw)[3]),\
+ htons(((u16 *)gid_raw)[4]), htons(((u16 *)gid_raw)[5]),\
+ htons(((u16 *)gid_raw)[6]), htons(((u16 *)gid_raw)[7])
+
+enum {
+ DUMP_PREFIX_NONE,
+ DUMP_PREFIX_ADDRESS,
+ DUMP_PREFIX_OFFSET
+};
+
+static inline void
+print_hex_dump(const char *level, const char *prefix_str,
+ const int prefix_type, const int rowsize, const int groupsize,
+ const void *buf, size_t len, const bool ascii)
+{
+ typedef const struct { long long value; } __packed *print_64p_t;
+ typedef const struct { uint32_t value; } __packed *print_32p_t;
+ typedef const struct { uint16_t value; } __packed *print_16p_t;
+ const void *buf_old = buf;
+ int row;
+
+ while (len > 0) {
+ if (level != NULL)
+ printf("%s", level);
+ if (prefix_str != NULL)
+ printf("%s ", prefix_str);
+
+ switch (prefix_type) {
+ case DUMP_PREFIX_ADDRESS:
+ printf("[%p] ", buf);
+ break;
+ case DUMP_PREFIX_OFFSET:
+ printf("[%#tx] ", ((const char *)buf -
+ (const char *)buf_old));
+ break;
+ default:
+ break;
+ }
+ for (row = 0; row != rowsize; row++) {
+ if (groupsize == 8 && len > 7) {
+ printf("%016llx ", ((print_64p_t)buf)->value);
+ buf = (const uint8_t *)buf + 8;
+ len -= 8;
+ } else if (groupsize == 4 && len > 3) {
+ printf("%08x ", ((print_32p_t)buf)->value);
+ buf = (const uint8_t *)buf + 4;
+ len -= 4;
+ } else if (groupsize == 2 && len > 1) {
+ printf("%04x ", ((print_16p_t)buf)->value);
+ buf = (const uint8_t *)buf + 2;
+ len -= 2;
+ } else if (len > 0) {
+ printf("%02x ", *(const uint8_t *)buf);
+ buf = (const uint8_t *)buf + 1;
+ len--;
+ } else {
+ break;
+ }
+ }
+ printf("\n");
+ }
+}
+
+static inline void
+print_hex_dump_bytes(const char *prefix_str, const int prefix_type,
+ const void *buf, size_t len)
+{
+ print_hex_dump(NULL, prefix_str, prefix_type, 16, 1, buf, len, 0);
+}
+
+#define printk_ratelimit() ({ \
+ static linux_ratelimit_t __ratelimited; \
+ linux_ratelimited(&__ratelimited); \
+})
+
+#define printk_ratelimited(...) ({ \
+ bool __retval = printk_ratelimit(); \
+ if (__retval) \
+ printk(__VA_ARGS__); \
+ __retval; \
+})
+
+#define pr_err_ratelimited(fmt, ...) \
+ printk_ratelimited(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
+
+#define print_hex_dump_debug(...) \
+ print_hex_dump(KERN_DEBUG, ##__VA_ARGS__)
+
+#define pr_info_ratelimited(fmt, ...) \
+ printk_ratelimited(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
+
+#endif /* _LINUX_PRINTK_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/radix-tree.h b/sys/compat/linuxkpi/common/include/linux/radix-tree.h
new file mode 100644
index 000000000000..1bef60c44c41
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/radix-tree.h
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2018 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_RADIX_TREE_H_
+#define _LINUX_RADIX_TREE_H_
+
+#include <linux/types.h>
+
+#define RADIX_TREE_MAP_SHIFT 6
+#define RADIX_TREE_MAP_SIZE (1UL << RADIX_TREE_MAP_SHIFT)
+#define RADIX_TREE_MAP_MASK (RADIX_TREE_MAP_SIZE - 1UL)
+#define RADIX_TREE_MAX_HEIGHT \
+ howmany(sizeof(long) * NBBY, RADIX_TREE_MAP_SHIFT)
+
+#define RADIX_TREE_ENTRY_MASK 3UL
+#define RADIX_TREE_EXCEPTIONAL_ENTRY 2UL
+#define RADIX_TREE_EXCEPTIONAL_SHIFT 2
+
+struct radix_tree_node {
+ void *slots[RADIX_TREE_MAP_SIZE];
+ int count;
+};
+
+struct radix_tree_root {
+ struct radix_tree_node *rnode;
+ gfp_t gfp_mask;
+ int height;
+};
+
+struct radix_tree_iter {
+ unsigned long index;
+};
+
+#define RADIX_TREE_INIT(mask) \
+ { .rnode = NULL, .gfp_mask = mask, .height = 0 };
+#define INIT_RADIX_TREE(root, mask) \
+ { (root)->rnode = NULL; (root)->gfp_mask = mask; (root)->height = 0; }
+#define RADIX_TREE(name, mask) \
+ struct radix_tree_root name = RADIX_TREE_INIT(mask)
+
+#define radix_tree_for_each_slot(slot, root, iter, start) \
+ for ((iter)->index = (start); \
+ radix_tree_iter_find(root, iter, &(slot)); (iter)->index++)
+
+static inline int
+radix_tree_exception(void *arg)
+{
+ return ((uintptr_t)arg & RADIX_TREE_ENTRY_MASK);
+}
+
+void *radix_tree_lookup(struct radix_tree_root *, unsigned long);
+void *radix_tree_delete(struct radix_tree_root *, unsigned long);
+int radix_tree_insert(struct radix_tree_root *, unsigned long, void *);
+int radix_tree_store(struct radix_tree_root *, unsigned long, void **);
+bool radix_tree_iter_find(struct radix_tree_root *, struct radix_tree_iter *, void ***);
+void radix_tree_iter_delete(struct radix_tree_root *, struct radix_tree_iter *, void **);
+
+#endif /* _LINUX_RADIX_TREE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/random.h b/sys/compat/linuxkpi/common/include/linux/random.h
new file mode 100644
index 000000000000..31d8b996aa0b
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/random.h
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_RANDOM_H_
+#define _LINUX_RANDOM_H_
+
+#include <linux/types.h>
+#include <sys/random.h>
+#include <sys/libkern.h>
+
+#define get_random_u32() get_random_int()
+
+static inline void
+get_random_bytes(void *buf, int nbytes)
+{
+
+ arc4random_buf(buf, nbytes);
+}
+
+static inline u_int
+get_random_int(void)
+{
+ u_int val;
+
+ get_random_bytes(&val, sizeof(val));
+ return (val);
+}
+
+static inline u_long
+get_random_long(void)
+{
+ u_long val;
+
+ get_random_bytes(&val, sizeof(val));
+ return (val);
+}
+
+static inline u32
+prandom_u32_max(u32 max)
+{
+ return (arc4random_uniform(max));
+}
+
+#endif /* _LINUX_RANDOM_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/rbtree.h b/sys/compat/linuxkpi/common/include/linux/rbtree.h
new file mode 100644
index 000000000000..78da33ad2658
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/rbtree.h
@@ -0,0 +1,101 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_RBTREE_H_
+#define _LINUX_RBTREE_H_
+
+#ifndef _STANDALONE
+#include <sys/stddef.h>
+#endif
+
+#include <sys/tree.h>
+
+struct rb_node {
+ RB_ENTRY(rb_node) __entry;
+};
+#define rb_left __entry.rbe_left
+#define rb_right __entry.rbe_right
+
+/*
+ * We provide a false structure that has the same bit pattern as tree.h
+ * presents so it matches the member names expected by linux.
+ */
+struct rb_root {
+ struct rb_node *rb_node;
+};
+
+/*
+ * In linux all of the comparisons are done by the caller.
+ */
+int panic_cmp(struct rb_node *one, struct rb_node *two);
+
+RB_HEAD(linux_root, rb_node);
+RB_PROTOTYPE(linux_root, rb_node, __entry, panic_cmp);
+
+#define rb_entry(ptr, type, member) container_of(ptr, type, member)
+
+#define RB_EMPTY_ROOT(root) RB_EMPTY((struct linux_root *)root)
+#define RB_EMPTY_NODE(node) (RB_PARENT(node, __entry) == node)
+#define RB_CLEAR_NODE(node) RB_SET_PARENT(node, node, __entry)
+
+#define rb_insert_color(node, root) \
+ linux_root_RB_INSERT_COLOR((struct linux_root *)(root), (node))
+#define rb_erase(node, root) \
+ linux_root_RB_REMOVE((struct linux_root *)(root), (node))
+#define rb_next(node) RB_NEXT(linux_root, NULL, (node))
+#define rb_prev(node) RB_PREV(linux_root, NULL, (node))
+#define rb_first(root) RB_MIN(linux_root, (struct linux_root *)(root))
+#define rb_last(root) RB_MAX(linux_root, (struct linux_root *)(root))
+
+static inline void
+rb_link_node(struct rb_node *node, struct rb_node *parent,
+ struct rb_node **rb_link)
+{
+ RB_SET(node, parent, __entry);
+ *rb_link = node;
+}
+
+static inline void
+rb_replace_node(struct rb_node *victim, struct rb_node *new,
+ struct rb_root *root)
+{
+
+ RB_SWAP_CHILD((struct linux_root *)root, victim, new, __entry);
+ if (victim->rb_left)
+ RB_SET_PARENT(victim->rb_left, new, __entry);
+ if (victim->rb_right)
+ RB_SET_PARENT(victim->rb_right, new, __entry);
+ *new = *victim;
+}
+
+#undef RB_ROOT
+#define RB_ROOT (struct rb_root) { NULL }
+
+#endif /* _LINUX_RBTREE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/rculist.h b/sys/compat/linuxkpi/common/include/linux/rculist.h
new file mode 100644
index 000000000000..bff2f7e13184
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/rculist.h
@@ -0,0 +1,141 @@
+/*-
+ * Copyright (c) 2015 François Tigeot
+ * Copyright (c) 2016-2020 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_RCULIST_H_
+#define _LINUX_RCULIST_H_
+
+#include <linux/list.h>
+#include <linux/rcupdate.h>
+
+#define list_entry_rcu(ptr, type, member) \
+ container_of(READ_ONCE(ptr), type, member)
+
+#define list_next_rcu(head) (*((struct list_head **)(&(head)->next)))
+#define list_prev_rcu(head) (*((struct list_head **)(&(head)->prev)))
+
+#define list_for_each_entry_rcu(pos, head, member) \
+ for (pos = list_entry_rcu((head)->next, typeof(*(pos)), member); \
+ &(pos)->member != (head); \
+ pos = list_entry_rcu((pos)->member.next, typeof(*(pos)), member))
+
+static inline void
+linux_list_add_rcu(struct list_head *new, struct list_head *prev,
+ struct list_head *next)
+{
+ new->next = next;
+ new->prev = prev;
+ rcu_assign_pointer(list_next_rcu(prev), new);
+ next->prev = new;
+}
+
+static inline void
+list_add_rcu(struct list_head *new, struct list_head *head)
+{
+ linux_list_add_rcu(new, head, head->next);
+}
+
+static inline void
+list_add_tail_rcu(struct list_head *new, struct list_head *head)
+{
+ linux_list_add_rcu(new, head->prev, head);
+}
+
+static inline void
+__list_del_rcu(struct list_head *prev, struct list_head *next)
+{
+ next->prev = prev;
+ rcu_assign_pointer(list_next_rcu(prev), next);
+}
+
+static inline void
+__list_del_entry_rcu(struct list_head *entry)
+{
+ __list_del_rcu(entry->prev, entry->next);
+}
+
+static inline void
+list_del_rcu(struct list_head *entry)
+{
+ __list_del_rcu(entry->prev, entry->next);
+}
+
+#define hlist_first_rcu(head) (*((struct hlist_node **)(&(head)->first)))
+#define hlist_next_rcu(node) (*((struct hlist_node **)(&(node)->next)))
+#define hlist_pprev_rcu(node) (*((struct hlist_node **)((node)->pprev)))
+
+static inline void
+hlist_add_behind_rcu(struct hlist_node *n, struct hlist_node *prev)
+{
+ n->next = prev->next;
+ n->pprev = &prev->next;
+ rcu_assign_pointer(hlist_next_rcu(prev), n);
+ if (n->next)
+ n->next->pprev = &n->next;
+}
+
+#define hlist_for_each_entry_rcu(pos, head, member) \
+ for (pos = hlist_entry_safe (rcu_dereference_raw(hlist_first_rcu(head)),\
+ typeof(*(pos)), member); \
+ (pos); \
+ pos = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu( \
+ &(pos)->member)), typeof(*(pos)), member))
+
+static inline void
+hlist_del_rcu(struct hlist_node *n)
+{
+ struct hlist_node *next = n->next;
+ struct hlist_node **pprev = n->pprev;
+
+ WRITE_ONCE(*pprev, next);
+ if (next)
+ next->pprev = pprev;
+}
+
+static inline void
+hlist_add_head_rcu(struct hlist_node *n, struct hlist_head *h)
+{
+ struct hlist_node *first = h->first;
+
+ n->next = first;
+ n->pprev = &h->first;
+ rcu_assign_pointer(hlist_first_rcu(h), n);
+ if (first)
+ first->pprev = &n->next;
+}
+
+static inline void
+hlist_del_init_rcu(struct hlist_node *n)
+{
+ if (!hlist_unhashed(n)) {
+ hlist_del_rcu(n);
+ n->pprev = NULL;
+ }
+}
+
+#endif /* _LINUX_RCULIST_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/rcupdate.h b/sys/compat/linuxkpi/common/include/linux/rcupdate.h
new file mode 100644
index 000000000000..a43736e0285f
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/rcupdate.h
@@ -0,0 +1,120 @@
+/*-
+ * Copyright (c) 2016-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_RCUPDATE_H_
+#define _LINUX_RCUPDATE_H_
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+#include <machine/atomic.h>
+
+#define LINUX_KFREE_RCU_OFFSET_MAX 4096 /* exclusive */
+
+/* BSD specific defines */
+#define RCU_TYPE_REGULAR 0
+#define RCU_TYPE_SLEEPABLE 1
+#define RCU_TYPE_MAX 2
+
+#define RCU_INITIALIZER(v) \
+ ((__typeof(*(v)) *)(v))
+
+#define RCU_INIT_POINTER(p, v) do { \
+ (p) = (v); \
+} while (0)
+
+#define call_rcu(ptr, func) do { \
+ linux_call_rcu(RCU_TYPE_REGULAR, ptr, func); \
+} while (0)
+
+#define rcu_barrier(void) do { \
+ linux_rcu_barrier(RCU_TYPE_REGULAR); \
+} while (0)
+
+#define rcu_read_lock(void) do { \
+ linux_rcu_read_lock(RCU_TYPE_REGULAR); \
+} while (0)
+
+#define rcu_read_unlock(void) do { \
+ linux_rcu_read_unlock(RCU_TYPE_REGULAR);\
+} while (0)
+
+#define synchronize_rcu(void) do { \
+ linux_synchronize_rcu(RCU_TYPE_REGULAR); \
+} while (0)
+
+#define synchronize_rcu_expedited(void) do { \
+ linux_synchronize_rcu(RCU_TYPE_REGULAR); \
+} while (0)
+
+#define kfree_rcu(ptr, rcu_head) do { \
+ CTASSERT(offsetof(__typeof(*(ptr)), rcu_head) < \
+ LINUX_KFREE_RCU_OFFSET_MAX); \
+ call_rcu(&(ptr)->rcu_head, (rcu_callback_t)(uintptr_t) \
+ offsetof(__typeof(*(ptr)), rcu_head)); \
+} while (0)
+
+#define rcu_access_pointer(p) \
+ ((__typeof(*p) *)READ_ONCE(p))
+
+#define rcu_dereference_protected(p, c) \
+ ((__typeof(*p) *)READ_ONCE(p))
+
+#define rcu_dereference(p) \
+ rcu_dereference_protected(p, 0)
+
+#define rcu_dereference_raw(p) \
+ ((__typeof(*p) *)READ_ONCE(p))
+
+#define rcu_pointer_handoff(p) (p)
+
+#define rcu_assign_pointer(p, v) do { \
+ atomic_store_rel_ptr((volatile uintptr_t *)&(p), \
+ (uintptr_t)(v)); \
+} while (0)
+
+#define rcu_swap_protected(rcu, ptr, c) do { \
+ typeof(ptr) p = rcu_dereference_protected(rcu, c); \
+ rcu_assign_pointer(rcu, ptr); \
+ (ptr) = p; \
+} while (0)
+
+/* prototypes */
+
+extern void linux_call_rcu(unsigned type, struct rcu_head *ptr, rcu_callback_t func);
+extern void linux_rcu_barrier(unsigned type);
+extern void linux_rcu_read_lock(unsigned type);
+extern void linux_rcu_read_unlock(unsigned type);
+extern void linux_synchronize_rcu(unsigned type);
+
+/* Empty implementation for !DEBUG */
+#define init_rcu_head(...)
+#define destroy_rcu_head(...)
+#define init_rcu_head_on_stack(...)
+#define destroy_rcu_head_on_stack(...)
+
+#endif /* _LINUX_RCUPDATE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/refcount.h b/sys/compat/linuxkpi/common/include/linux/refcount.h
new file mode 100644
index 000000000000..02f9f32f7eb4
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/refcount.h
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Emmanuel Vadot under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_REFCOUNT_H
+#define _LINUX_REFCOUNT_H
+
+#include <linux/atomic.h>
+
+struct refcount_linux {
+ atomic_t value;
+};
+typedef struct refcount_linux refcount_t;
+
+static inline void
+refcount_set(refcount_t *ref, unsigned int i)
+{
+ atomic_set(&ref->value, i);
+}
+
+static inline void
+refcount_inc(refcount_t *ref)
+{
+ atomic_inc(&ref->value);
+}
+
+static inline bool
+refcount_inc_not_zero(refcount_t *ref)
+{
+ return (atomic_inc_not_zero(&ref->value));
+}
+
+static inline void
+refcount_dec(refcount_t *ref)
+{
+ atomic_dec(&ref->value);
+}
+
+static inline unsigned int
+refcount_read(refcount_t *ref)
+{
+ return atomic_read(&ref->value);
+}
+
+static inline bool
+refcount_dec_and_lock_irqsave(refcount_t *ref, spinlock_t *lock,
+ unsigned long *flags)
+{
+ if (atomic_dec_and_test(&ref->value) == true) {
+ spin_lock_irqsave(lock, flags);
+ return (true);
+ }
+ return (false);
+}
+
+#endif /* __LINUX_REFCOUNT_H__ */
diff --git a/sys/compat/linuxkpi/common/include/linux/rwlock.h b/sys/compat/linuxkpi/common/include/linux/rwlock.h
new file mode 100644
index 000000000000..621afb1e954b
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/rwlock.h
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_RWLOCK_H_
+#define _LINUX_RWLOCK_H_
+
+#include <sys/types.h>
+#include <sys/lock.h>
+#include <sys/rwlock.h>
+#include <sys/libkern.h>
+
+typedef struct {
+ struct rwlock rw;
+} rwlock_t;
+
+#define read_lock(_l) rw_rlock(&(_l)->rw)
+#define write_lock(_l) rw_wlock(&(_l)->rw)
+#define read_unlock(_l) rw_runlock(&(_l)->rw)
+#define write_unlock(_l) rw_wunlock(&(_l)->rw)
+#define read_lock_irq(lock) read_lock((lock))
+#define read_unlock_irq(lock) read_unlock((lock))
+#define write_lock_irq(lock) write_lock((lock))
+#define write_unlock_irq(lock) write_unlock((lock))
+#define read_lock_irqsave(lock, flags) \
+ do {(flags) = 0; read_lock(lock); } while (0)
+#define write_lock_irqsave(lock, flags) \
+ do {(flags) = 0; write_lock(lock); } while (0)
+#define read_unlock_irqrestore(lock, flags) \
+ do { read_unlock(lock); } while (0)
+#define write_unlock_irqrestore(lock, flags) \
+ do { write_unlock(lock); } while (0)
+
+static inline void
+rwlock_init(rwlock_t *lock)
+{
+
+ memset(&lock->rw, 0, sizeof(lock->rw));
+ rw_init_flags(&lock->rw, "lnxrw", RW_NOWITNESS);
+}
+
+#endif /* _LINUX_RWLOCK_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/rwsem.h b/sys/compat/linuxkpi/common/include/linux/rwsem.h
new file mode 100644
index 000000000000..8850da91bd4d
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/rwsem.h
@@ -0,0 +1,84 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_RWSEM_H_
+#define _LINUX_RWSEM_H_
+
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/sx.h>
+#include <sys/libkern.h>
+#include <sys/kernel.h>
+
+struct rw_semaphore {
+ struct sx sx;
+};
+
+#define down_write(_rw) sx_xlock(&(_rw)->sx)
+#define up_write(_rw) sx_xunlock(&(_rw)->sx)
+#define down_read(_rw) sx_slock(&(_rw)->sx)
+#define up_read(_rw) sx_sunlock(&(_rw)->sx)
+#define down_read_trylock(_rw) !!sx_try_slock(&(_rw)->sx)
+#define down_write_trylock(_rw) !!sx_try_xlock(&(_rw)->sx)
+#define down_write_killable(_rw) linux_down_write_killable(_rw)
+#define downgrade_write(_rw) sx_downgrade(&(_rw)->sx)
+#define down_read_nested(_rw, _sc) down_read(_rw)
+#define init_rwsem(_rw) linux_init_rwsem(_rw, rwsem_name("lnxrwsem"))
+
+#ifdef WITNESS_ALL
+/* NOTE: the maximum WITNESS name is 64 chars */
+#define __rwsem_name(name, file, line) \
+ (((const char *){file ":" #line "-" name}) + \
+ (sizeof(file) > 16 ? sizeof(file) - 16 : 0))
+#else
+#define __rwsem_name(name, file, line) name
+#endif
+#define _rwsem_name(...) __rwsem_name(__VA_ARGS__)
+#define rwsem_name(name) _rwsem_name(name, __FILE__, __LINE__)
+
+#define DECLARE_RWSEM(name) \
+struct rw_semaphore name; \
+static void name##_rwsem_init(void *arg) \
+{ \
+ linux_init_rwsem(&name, rwsem_name(#name)); \
+} \
+SYSINIT(name, SI_SUB_LOCK, SI_ORDER_SECOND, name##_rwsem_init, NULL)
+
+static inline void
+linux_init_rwsem(struct rw_semaphore *rw, const char *name)
+{
+
+ memset(rw, 0, sizeof(*rw));
+ sx_init_flags(&rw->sx, name, SX_NOWITNESS);
+}
+
+extern int linux_down_write_killable(struct rw_semaphore *);
+
+#endif /* _LINUX_RWSEM_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/scatterlist.h b/sys/compat/linuxkpi/common/include/linux/scatterlist.h
new file mode 100644
index 000000000000..ebf0632f6f58
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/scatterlist.h
@@ -0,0 +1,536 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * Copyright (c) 2015 Matthew Dillon <dillon@backplane.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_SCATTERLIST_H_
+#define _LINUX_SCATTERLIST_H_
+
+#include <sys/types.h>
+#include <sys/sf_buf.h>
+
+#include <linux/page.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+
+struct bus_dmamap;
+struct scatterlist {
+ unsigned long page_link;
+#define SG_PAGE_LINK_CHAIN 0x1UL
+#define SG_PAGE_LINK_LAST 0x2UL
+#define SG_PAGE_LINK_MASK 0x3UL
+ unsigned int offset;
+ unsigned int length;
+ dma_addr_t dma_address;
+ struct bus_dmamap *dma_map; /* FreeBSD specific */
+};
+
+CTASSERT((sizeof(struct scatterlist) & SG_PAGE_LINK_MASK) == 0);
+
+struct sg_table {
+ struct scatterlist *sgl;
+ unsigned int nents;
+ unsigned int orig_nents;
+};
+
+struct sg_page_iter {
+ struct scatterlist *sg;
+ unsigned int sg_pgoffset;
+ unsigned int maxents;
+ struct {
+ unsigned int nents;
+ int pg_advance;
+ } internal;
+};
+
+struct sg_dma_page_iter {
+ struct sg_page_iter base;
+};
+
+#define SCATTERLIST_MAX_SEGMENT (-1U & ~(PAGE_SIZE - 1))
+
+#define SG_MAX_SINGLE_ALLOC (PAGE_SIZE / sizeof(struct scatterlist))
+
+#define SG_MAGIC 0x87654321UL
+#define SG_CHAIN SG_PAGE_LINK_CHAIN
+#define SG_END SG_PAGE_LINK_LAST
+
+#define sg_is_chain(sg) ((sg)->page_link & SG_PAGE_LINK_CHAIN)
+#define sg_is_last(sg) ((sg)->page_link & SG_PAGE_LINK_LAST)
+#define sg_chain_ptr(sg) \
+ ((struct scatterlist *) ((sg)->page_link & ~SG_PAGE_LINK_MASK))
+
+#define sg_dma_address(sg) (sg)->dma_address
+#define sg_dma_len(sg) (sg)->length
+
+#define for_each_sg_page(sgl, iter, nents, pgoffset) \
+ for (_sg_iter_init(sgl, iter, nents, pgoffset); \
+ (iter)->sg; _sg_iter_next(iter))
+#define for_each_sg_dma_page(sgl, iter, nents, pgoffset) \
+ for_each_sg_page(sgl, &(iter)->base, nents, pgoffset)
+
+#define for_each_sg(sglist, sg, sgmax, iter) \
+ for (iter = 0, sg = (sglist); iter < (sgmax); iter++, sg = sg_next(sg))
+
+typedef struct scatterlist *(sg_alloc_fn) (unsigned int, gfp_t);
+typedef void (sg_free_fn) (struct scatterlist *, unsigned int);
+
+static inline void
+sg_assign_page(struct scatterlist *sg, struct page *page)
+{
+ unsigned long page_link = sg->page_link & SG_PAGE_LINK_MASK;
+
+ sg->page_link = page_link | (unsigned long)page;
+}
+
+static inline void
+sg_set_page(struct scatterlist *sg, struct page *page, unsigned int len,
+ unsigned int offset)
+{
+ sg_assign_page(sg, page);
+ sg->offset = offset;
+ sg->length = len;
+}
+
+static inline struct page *
+sg_page(struct scatterlist *sg)
+{
+ return ((struct page *)((sg)->page_link & ~SG_PAGE_LINK_MASK));
+}
+
+static inline void
+sg_set_buf(struct scatterlist *sg, const void *buf, unsigned int buflen)
+{
+ sg_set_page(sg, virt_to_page(buf), buflen,
+ ((uintptr_t)buf) & (PAGE_SIZE - 1));
+}
+
+static inline struct scatterlist *
+sg_next(struct scatterlist *sg)
+{
+ if (sg_is_last(sg))
+ return (NULL);
+ sg++;
+ if (sg_is_chain(sg))
+ sg = sg_chain_ptr(sg);
+ return (sg);
+}
+
+static inline vm_paddr_t
+sg_phys(struct scatterlist *sg)
+{
+ return (VM_PAGE_TO_PHYS(sg_page(sg)) + sg->offset);
+}
+
+static inline void *
+sg_virt(struct scatterlist *sg)
+{
+
+ return ((void *)((unsigned long)page_address(sg_page(sg)) + sg->offset));
+}
+
+static inline void
+sg_chain(struct scatterlist *prv, unsigned int prv_nents,
+ struct scatterlist *sgl)
+{
+ struct scatterlist *sg = &prv[prv_nents - 1];
+
+ sg->offset = 0;
+ sg->length = 0;
+ sg->page_link = ((unsigned long)sgl |
+ SG_PAGE_LINK_CHAIN) & ~SG_PAGE_LINK_LAST;
+}
+
+static inline void
+sg_mark_end(struct scatterlist *sg)
+{
+ sg->page_link |= SG_PAGE_LINK_LAST;
+ sg->page_link &= ~SG_PAGE_LINK_CHAIN;
+}
+
+static inline void
+sg_init_table(struct scatterlist *sg, unsigned int nents)
+{
+ bzero(sg, sizeof(*sg) * nents);
+ sg_mark_end(&sg[nents - 1]);
+}
+
+static struct scatterlist *
+sg_kmalloc(unsigned int nents, gfp_t gfp_mask)
+{
+ if (nents == SG_MAX_SINGLE_ALLOC) {
+ return ((void *)__get_free_page(gfp_mask));
+ } else
+ return (kmalloc(nents * sizeof(struct scatterlist), gfp_mask));
+}
+
+static inline void
+sg_kfree(struct scatterlist *sg, unsigned int nents)
+{
+ if (nents == SG_MAX_SINGLE_ALLOC) {
+ free_page((unsigned long)sg);
+ } else
+ kfree(sg);
+}
+
+static inline void
+__sg_free_table(struct sg_table *table, unsigned int max_ents,
+ bool skip_first_chunk, sg_free_fn * free_fn)
+{
+ struct scatterlist *sgl, *next;
+
+ if (unlikely(!table->sgl))
+ return;
+
+ sgl = table->sgl;
+ while (table->orig_nents) {
+ unsigned int alloc_size = table->orig_nents;
+ unsigned int sg_size;
+
+ if (alloc_size > max_ents) {
+ next = sg_chain_ptr(&sgl[max_ents - 1]);
+ alloc_size = max_ents;
+ sg_size = alloc_size - 1;
+ } else {
+ sg_size = alloc_size;
+ next = NULL;
+ }
+
+ table->orig_nents -= sg_size;
+ if (skip_first_chunk)
+ skip_first_chunk = 0;
+ else
+ free_fn(sgl, alloc_size);
+ sgl = next;
+ }
+
+ table->sgl = NULL;
+}
+
+static inline void
+sg_free_table(struct sg_table *table)
+{
+ __sg_free_table(table, SG_MAX_SINGLE_ALLOC, 0, sg_kfree);
+}
+
+static inline int
+__sg_alloc_table(struct sg_table *table, unsigned int nents,
+ unsigned int max_ents, struct scatterlist *first_chunk,
+ gfp_t gfp_mask, sg_alloc_fn *alloc_fn)
+{
+ struct scatterlist *sg, *prv;
+ unsigned int left;
+
+ memset(table, 0, sizeof(*table));
+
+ if (nents == 0)
+ return (-EINVAL);
+ left = nents;
+ prv = NULL;
+ do {
+ unsigned int sg_size;
+ unsigned int alloc_size = left;
+
+ if (alloc_size > max_ents) {
+ alloc_size = max_ents;
+ sg_size = alloc_size - 1;
+ } else
+ sg_size = alloc_size;
+
+ left -= sg_size;
+
+ if (first_chunk) {
+ sg = first_chunk;
+ first_chunk = NULL;
+ } else {
+ sg = alloc_fn(alloc_size, gfp_mask);
+ }
+ if (unlikely(!sg)) {
+ if (prv)
+ table->nents = ++table->orig_nents;
+
+ return (-ENOMEM);
+ }
+ sg_init_table(sg, alloc_size);
+ table->nents = table->orig_nents += sg_size;
+
+ if (prv)
+ sg_chain(prv, max_ents, sg);
+ else
+ table->sgl = sg;
+
+ if (!left)
+ sg_mark_end(&sg[sg_size - 1]);
+
+ prv = sg;
+ } while (left);
+
+ return (0);
+}
+
+static inline int
+sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)
+{
+ int ret;
+
+ ret = __sg_alloc_table(table, nents, SG_MAX_SINGLE_ALLOC,
+ NULL, gfp_mask, sg_kmalloc);
+ if (unlikely(ret))
+ __sg_free_table(table, SG_MAX_SINGLE_ALLOC, 0, sg_kfree);
+
+ return (ret);
+}
+
+static inline int
+__sg_alloc_table_from_pages(struct sg_table *sgt,
+ struct page **pages, unsigned int count,
+ unsigned long off, unsigned long size,
+ unsigned int max_segment, gfp_t gfp_mask)
+{
+ unsigned int i, segs, cur, len;
+ int rc;
+ struct scatterlist *s;
+
+ if (__predict_false(!max_segment || offset_in_page(max_segment)))
+ return (-EINVAL);
+
+ len = 0;
+ for (segs = i = 1; i < count; ++i) {
+ len += PAGE_SIZE;
+ if (len >= max_segment ||
+ page_to_pfn(pages[i]) != page_to_pfn(pages[i - 1]) + 1) {
+ ++segs;
+ len = 0;
+ }
+ }
+ if (__predict_false((rc = sg_alloc_table(sgt, segs, gfp_mask))))
+ return (rc);
+
+ cur = 0;
+ for_each_sg(sgt->sgl, s, sgt->orig_nents, i) {
+ unsigned long seg_size;
+ unsigned int j;
+
+ len = 0;
+ for (j = cur + 1; j < count; ++j) {
+ len += PAGE_SIZE;
+ if (len >= max_segment || page_to_pfn(pages[j]) !=
+ page_to_pfn(pages[j - 1]) + 1)
+ break;
+ }
+
+ seg_size = ((j - cur) << PAGE_SHIFT) - off;
+ sg_set_page(s, pages[cur], MIN(size, seg_size), off);
+ size -= seg_size;
+ off = 0;
+ cur = j;
+ }
+ return (0);
+}
+
+static inline int
+sg_alloc_table_from_pages(struct sg_table *sgt,
+ struct page **pages, unsigned int count,
+ unsigned long off, unsigned long size,
+ gfp_t gfp_mask)
+{
+
+ return (__sg_alloc_table_from_pages(sgt, pages, count, off, size,
+ SCATTERLIST_MAX_SEGMENT, gfp_mask));
+}
+
+static inline int
+sg_nents(struct scatterlist *sg)
+{
+ int nents;
+
+ for (nents = 0; sg; sg = sg_next(sg))
+ nents++;
+ return (nents);
+}
+
+static inline void
+__sg_page_iter_start(struct sg_page_iter *piter,
+ struct scatterlist *sglist, unsigned int nents,
+ unsigned long pgoffset)
+{
+ piter->internal.pg_advance = 0;
+ piter->internal.nents = nents;
+
+ piter->sg = sglist;
+ piter->sg_pgoffset = pgoffset;
+}
+
+static inline void
+_sg_iter_next(struct sg_page_iter *iter)
+{
+ struct scatterlist *sg;
+ unsigned int pgcount;
+
+ sg = iter->sg;
+ pgcount = (sg->offset + sg->length + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+ ++iter->sg_pgoffset;
+ while (iter->sg_pgoffset >= pgcount) {
+ iter->sg_pgoffset -= pgcount;
+ sg = sg_next(sg);
+ --iter->maxents;
+ if (sg == NULL || iter->maxents == 0)
+ break;
+ pgcount = (sg->offset + sg->length + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ }
+ iter->sg = sg;
+}
+
+static inline int
+sg_page_count(struct scatterlist *sg)
+{
+ return (PAGE_ALIGN(sg->offset + sg->length) >> PAGE_SHIFT);
+}
+#define sg_dma_page_count(sg) \
+ sg_page_count(sg)
+
+static inline bool
+__sg_page_iter_next(struct sg_page_iter *piter)
+{
+ unsigned int pgcount;
+
+ if (piter->internal.nents == 0)
+ return (0);
+ if (piter->sg == NULL)
+ return (0);
+
+ piter->sg_pgoffset += piter->internal.pg_advance;
+ piter->internal.pg_advance = 1;
+
+ while (1) {
+ pgcount = sg_page_count(piter->sg);
+ if (likely(piter->sg_pgoffset < pgcount))
+ break;
+ piter->sg_pgoffset -= pgcount;
+ piter->sg = sg_next(piter->sg);
+ if (--piter->internal.nents == 0)
+ return (0);
+ if (piter->sg == NULL)
+ return (0);
+ }
+ return (1);
+}
+#define __sg_page_iter_dma_next(itr) \
+ __sg_page_iter_next(&(itr)->base)
+
+static inline void
+_sg_iter_init(struct scatterlist *sgl, struct sg_page_iter *iter,
+ unsigned int nents, unsigned long pgoffset)
+{
+ if (nents) {
+ iter->sg = sgl;
+ iter->sg_pgoffset = pgoffset - 1;
+ iter->maxents = nents;
+ _sg_iter_next(iter);
+ } else {
+ iter->sg = NULL;
+ iter->sg_pgoffset = 0;
+ iter->maxents = 0;
+ }
+}
+
+/*
+ * sg_page_iter_dma_address() is implemented as a macro because it
+ * needs to accept two different and identical structure types. This
+ * allows both old and new code to co-exist. The compile time assert
+ * adds some safety, that the structure sizes match.
+ */
+#define sg_page_iter_dma_address(spi) ({ \
+ struct sg_page_iter *__spi = (void *)(spi); \
+ dma_addr_t __dma_address; \
+ CTASSERT(sizeof(*(spi)) == sizeof(*__spi)); \
+ __dma_address = __spi->sg->dma_address + \
+ (__spi->sg_pgoffset << PAGE_SHIFT); \
+ __dma_address; \
+})
+
+static inline struct page *
+sg_page_iter_page(struct sg_page_iter *piter)
+{
+ return (nth_page(sg_page(piter->sg), piter->sg_pgoffset));
+}
+
+static __inline size_t
+sg_pcopy_from_buffer(struct scatterlist *sgl, unsigned int nents,
+ const void *buf, size_t buflen, off_t skip)
+{
+ struct sg_page_iter piter;
+ struct page *page;
+ struct sf_buf *sf;
+ size_t len, copied;
+ char *p, *b;
+
+ if (buflen == 0)
+ return (0);
+
+ b = __DECONST(char *, buf);
+ copied = 0;
+ sched_pin();
+ for_each_sg_page(sgl, &piter, nents, 0) {
+
+ /* Skip to the start. */
+ if (piter.sg->length <= skip) {
+ skip -= piter.sg->length;
+ continue;
+ }
+
+ /* See how much to copy. */
+ KASSERT(((piter.sg->length - skip) != 0 && (buflen != 0)),
+ ("%s: sg len %u - skip %ju || buflen %zu is 0\n",
+ __func__, piter.sg->length, (uintmax_t)skip, buflen));
+ len = min(piter.sg->length - skip, buflen);
+
+ page = sg_page_iter_page(&piter);
+ sf = sf_buf_alloc(page, SFB_CPUPRIVATE | SFB_NOWAIT);
+ if (sf == NULL)
+ break;
+ p = (char *)sf_buf_kva(sf) + piter.sg_pgoffset + skip;
+ memcpy(p, b, len);
+ sf_buf_free(sf);
+
+ copied += len;
+ /* Either we exactly filled the page, or we are done. */
+ buflen -= len;
+ if (buflen == 0)
+ break;
+ skip -= len;
+ b += len;
+ }
+ sched_unpin();
+
+ return (copied);
+}
+
+#endif /* _LINUX_SCATTERLIST_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/sched.h b/sys/compat/linuxkpi/common/include/linux/sched.h
new file mode 100644
index 000000000000..da38d89eb639
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/sched.h
@@ -0,0 +1,198 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2018 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_SCHED_H_
+#define _LINUX_SCHED_H_
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/sched.h>
+#include <sys/sleepqueue.h>
+#include <sys/time.h>
+
+#include <linux/bitmap.h>
+#include <linux/compat.h>
+#include <linux/completion.h>
+#include <linux/mm_types.h>
+#include <linux/pid.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/time.h>
+
+#include <asm/atomic.h>
+
+#define MAX_SCHEDULE_TIMEOUT INT_MAX
+
+#define TASK_RUNNING 0x0000
+#define TASK_INTERRUPTIBLE 0x0001
+#define TASK_UNINTERRUPTIBLE 0x0002
+#define TASK_NORMAL (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE)
+#define TASK_WAKING 0x0100
+#define TASK_PARKED 0x0200
+
+#define TASK_COMM_LEN (MAXCOMLEN + 1)
+
+struct work_struct;
+struct task_struct {
+ struct thread *task_thread;
+ struct mm_struct *mm;
+ linux_task_fn_t *task_fn;
+ void *task_data;
+ int task_ret;
+ atomic_t usage;
+ atomic_t state;
+ atomic_t kthread_flags;
+ pid_t pid; /* BSD thread ID */
+ const char *comm;
+ void *bsd_ioctl_data;
+ unsigned bsd_ioctl_len;
+ struct completion parked;
+ struct completion exited;
+#define TS_RCU_TYPE_MAX 2
+ TAILQ_ENTRY(task_struct) rcu_entry[TS_RCU_TYPE_MAX];
+ int rcu_recurse[TS_RCU_TYPE_MAX];
+ int bsd_interrupt_value;
+ struct work_struct *work; /* current work struct, if set */
+ struct task_struct *group_leader;
+};
+
+#define current ({ \
+ struct thread *__td = curthread; \
+ linux_set_current(__td); \
+ ((struct task_struct *)__td->td_lkpi_task); \
+})
+
+#define task_pid_group_leader(task) (task)->task_thread->td_proc->p_pid
+#define task_pid(task) ((task)->pid)
+#define task_pid_nr(task) ((task)->pid)
+#define task_pid_vnr(task) ((task)->pid)
+#define get_pid(x) (x)
+#define put_pid(x) do { } while (0)
+#define current_euid() (curthread->td_ucred->cr_uid)
+#define task_euid(task) ((task)->task_thread->td_ucred->cr_uid)
+
+#define get_task_state(task) atomic_read(&(task)->state)
+#define set_task_state(task, x) atomic_set(&(task)->state, (x))
+#define __set_task_state(task, x) ((task)->state.counter = (x))
+#define set_current_state(x) set_task_state(current, x)
+#define __set_current_state(x) __set_task_state(current, x)
+
+static inline void
+get_task_struct(struct task_struct *task)
+{
+ atomic_inc(&task->usage);
+}
+
+static inline void
+put_task_struct(struct task_struct *task)
+{
+ if (atomic_dec_and_test(&task->usage))
+ linux_free_current(task);
+}
+
+#define cond_resched() do { if (!cold) sched_relinquish(curthread); } while (0)
+
+#define yield() kern_yield(PRI_UNCHANGED)
+#define sched_yield() sched_relinquish(curthread)
+
+#define need_resched() (curthread->td_flags & TDF_NEEDRESCHED)
+
+bool linux_signal_pending(struct task_struct *task);
+bool linux_fatal_signal_pending(struct task_struct *task);
+bool linux_signal_pending_state(long state, struct task_struct *task);
+void linux_send_sig(int signo, struct task_struct *task);
+
+#define signal_pending(task) linux_signal_pending(task)
+#define fatal_signal_pending(task) linux_fatal_signal_pending(task)
+#define signal_pending_state(state, task) \
+ linux_signal_pending_state(state, task)
+#define send_sig(signo, task, priv) do { \
+ CTASSERT((priv) == 0); \
+ linux_send_sig(signo, task); \
+} while (0)
+
+int linux_schedule_timeout(int timeout);
+
+static inline void
+linux_schedule_save_interrupt_value(struct task_struct *task, int value)
+{
+ task->bsd_interrupt_value = value;
+}
+
+bool linux_task_exiting(struct task_struct *task);
+
+#define current_exiting() \
+ linux_task_exiting(current)
+
+static inline int
+linux_schedule_get_interrupt_value(struct task_struct *task)
+{
+ int value = task->bsd_interrupt_value;
+ task->bsd_interrupt_value = 0;
+ return (value);
+}
+
+#define schedule() \
+ (void)linux_schedule_timeout(MAX_SCHEDULE_TIMEOUT)
+#define schedule_timeout(timeout) \
+ linux_schedule_timeout(timeout)
+#define schedule_timeout_killable(timeout) \
+ schedule_timeout_interruptible(timeout)
+#define schedule_timeout_interruptible(timeout) ({ \
+ set_current_state(TASK_INTERRUPTIBLE); \
+ schedule_timeout(timeout); \
+})
+#define schedule_timeout_uninterruptible(timeout) ({ \
+ set_current_state(TASK_UNINTERRUPTIBLE); \
+ schedule_timeout(timeout); \
+})
+
+#define io_schedule() schedule()
+#define io_schedule_timeout(timeout) schedule_timeout(timeout)
+
+static inline uint64_t
+local_clock(void)
+{
+ struct timespec ts;
+
+ nanotime(&ts);
+ return ((uint64_t)ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec);
+}
+
+static inline const char *
+get_task_comm(char *buf, struct task_struct *task)
+{
+
+ buf[0] = 0; /* buffer is too small */
+ return (task->comm);
+}
+
+#endif /* _LINUX_SCHED_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/semaphore.h b/sys/compat/linuxkpi/common/include/linux/semaphore.h
new file mode 100644
index 000000000000..e4a72fd9b47a
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/semaphore.h
@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_SEMAPHORE_H_
+#define _LINUX_SEMAPHORE_H_
+
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/sema.h>
+#include <sys/libkern.h>
+
+/*
+ * XXX BSD semaphores are disused and slow. They also do not provide a
+ * sema_wait_sig method. This must be resolved eventually.
+ */
+struct semaphore {
+ struct sema sema;
+};
+
+#define down(_sem) sema_wait(&(_sem)->sema)
+#define down_interruptible(_sem) sema_wait(&(_sem)->sema), 0
+#define down_trylock(_sem) !sema_trywait(&(_sem)->sema)
+#define up(_sem) sema_post(&(_sem)->sema)
+
+static inline void
+linux_sema_init(struct semaphore *sem, int val)
+{
+
+ memset(&sem->sema, 0, sizeof(sem->sema));
+ sema_init(&sem->sema, val, "lnxsema");
+}
+
+static inline void
+init_MUTEX(struct semaphore *sem)
+{
+
+ memset(&sem->sema, 0, sizeof(sem->sema));
+ sema_init(&sem->sema, 1, "lnxsema");
+}
+
+#define sema_init(...) linux_sema_init(__VA_ARGS__)
+
+#endif /* _LINUX_SEMAPHORE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/seq_file.h b/sys/compat/linuxkpi/common/include/linux/seq_file.h
new file mode 100644
index 000000000000..dab8020a0336
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/seq_file.h
@@ -0,0 +1,88 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2016-2018, Matthew Macy <mmacy@freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_SEQ_FILE_H_
+#define _LINUX_SEQ_FILE_H_
+
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <sys/sbuf.h>
+
+#undef file
+#define inode vnode
+
+#define DEFINE_SHOW_ATTRIBUTE(__name) \
+static int __name ## _open(struct inode *inode, struct linux_file *file) \
+{ \
+ return single_open(file, __name ## _show, inode->i_private); \
+} \
+ \
+static const struct file_operations __name ## _fops = { \
+ .owner = THIS_MODULE, \
+ .open = __name ## _open, \
+ .read = seq_read, \
+ .llseek = seq_lseek, \
+ .release = single_release, \
+}
+
+struct seq_operations;
+
+struct seq_file {
+ struct sbuf *buf;
+
+ const struct seq_operations *op;
+ const struct linux_file *file;
+ void *private;
+};
+
+struct seq_operations {
+ void * (*start) (struct seq_file *m, off_t *pos);
+ void (*stop) (struct seq_file *m, void *v);
+ void * (*next) (struct seq_file *m, void *v, off_t *pos);
+ int (*show) (struct seq_file *m, void *v);
+};
+
+ssize_t seq_read(struct linux_file *, char *, size_t, off_t *);
+int seq_write(struct seq_file *seq, const void *data, size_t len);
+
+int seq_open(struct linux_file *f, const struct seq_operations *op);
+int seq_release(struct inode *inode, struct linux_file *file);
+
+off_t seq_lseek(struct linux_file *file, off_t offset, int whence);
+int single_open(struct linux_file *, int (*)(struct seq_file *, void *), void *);
+int single_release(struct inode *, struct linux_file *);
+
+#define seq_printf(m, fmt, ...) sbuf_printf((m)->buf, (fmt), ##__VA_ARGS__)
+
+#define seq_puts(m, str) sbuf_printf((m)->buf, str)
+#define seq_putc(m, str) sbuf_putc((m)->buf, str)
+
+#define file linux_file
+
+#endif /* _LINUX_SEQ_FILE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/shmem_fs.h b/sys/compat/linuxkpi/common/include/linux/shmem_fs.h
new file mode 100644
index 000000000000..63aff012c6bb
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/shmem_fs.h
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2018 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_SHMEM_FS_H_
+#define _LINUX_SHMEM_FS_H_
+
+/* Shared memory support */
+unsigned long linux_invalidate_mapping_pages(vm_object_t, pgoff_t, pgoff_t);
+struct page *linux_shmem_read_mapping_page_gfp(vm_object_t, int, gfp_t);
+struct linux_file *linux_shmem_file_setup(const char *, loff_t, unsigned long);
+void linux_shmem_truncate_range(vm_object_t, loff_t, loff_t);
+
+#define invalidate_mapping_pages(...) \
+ linux_invalidate_mapping_pages(__VA_ARGS__)
+
+#define shmem_read_mapping_page(...) \
+ linux_shmem_read_mapping_page_gfp(__VA_ARGS__, 0)
+
+#define shmem_read_mapping_page_gfp(...) \
+ linux_shmem_read_mapping_page_gfp(__VA_ARGS__)
+
+#define shmem_file_setup(...) \
+ linux_shmem_file_setup(__VA_ARGS__)
+
+#define shmem_truncate_range(...) \
+ linux_shmem_truncate_range(__VA_ARGS__)
+
+#endif /* _LINUX_SHMEM_FS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/shrinker.h b/sys/compat/linuxkpi/common/include/linux/shrinker.h
new file mode 100644
index 000000000000..d18bb60645f8
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/shrinker.h
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2020 Emmanuel Vadot <manu@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __LINUX_SHRINKER_H__
+#define __LINUX_SHRINKER_H__
+
+#include <sys/queue.h>
+
+struct shrink_control {
+ unsigned long nr_to_scan;
+ unsigned long nr_scanned;
+};
+
+struct shrinker {
+ unsigned long (*count_objects)(struct shrinker *, struct shrink_control *);
+ unsigned long (*scan_objects)(struct shrinker *, struct shrink_control *);
+ int seeks;
+ long batch;
+ TAILQ_ENTRY(shrinker) next;
+};
+
+#define SHRINK_STOP (~0UL)
+
+#define DEFAULT_SEEKS 2
+
+int linuxkpi_register_shrinker(struct shrinker *s);
+void linuxkpi_unregister_shrinker(struct shrinker *s);
+
+#define register_shrinker(s) linuxkpi_register_shrinker(s)
+#define unregister_shrinker(s) linuxkpi_unregister_shrinker(s)
+
+#endif /* __LINUX_SHRINKER_H__ */
diff --git a/sys/compat/linuxkpi/common/include/linux/sizes.h b/sys/compat/linuxkpi/common/include/linux/sizes.h
new file mode 100644
index 000000000000..a180cee5f022
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/sizes.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Emmanuel Vadot under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __LINUX_SIZES_H__
+#define __LINUX_SIZES_H__
+
+#define SZ_1K (1024 * 1)
+#define SZ_4K (1024 * 4)
+#define SZ_8K (1024 * 8)
+#define SZ_16K (1024 * 16)
+#define SZ_32K (1024 * 32)
+#define SZ_64K (1024 * 64)
+#define SZ_128K (1024 * 128)
+#define SZ_256K (1024 * 256)
+#define SZ_512K (1024 * 512)
+
+#define SZ_1M (1024 * 1024 * 1)
+#define SZ_2M (1024 * 1024 * 2)
+#define SZ_8M (1024 * 1024 * 8)
+#define SZ_16M (1024 * 1024 * 16)
+#define SZ_32M (1024 * 1024 * 32)
+#define SZ_64M (1024 * 1024 * 64)
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/slab.h b/sys/compat/linuxkpi/common/include/linux/slab.h
new file mode 100644
index 000000000000..0cd748b7ecb9
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/slab.h
@@ -0,0 +1,209 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_SLAB_H_
+#define _LINUX_SLAB_H_
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/limits.h>
+#include <sys/proc.h>
+#include <vm/uma.h>
+
+#include <linux/types.h>
+#include <linux/gfp.h>
+#include <linux/llist.h>
+
+MALLOC_DECLARE(M_KMALLOC);
+
+#define kvmalloc(size, flags) kmalloc(size, flags)
+#define kvzalloc(size, flags) kmalloc(size, (flags) | __GFP_ZERO)
+#define kvcalloc(n, size, flags) kvmalloc_array(n, size, (flags) | __GFP_ZERO)
+#define kzalloc(size, flags) kmalloc(size, (flags) | __GFP_ZERO)
+#define kzalloc_node(size, flags, node) kmalloc(size, (flags) | __GFP_ZERO)
+#define kfree_const(ptr) kfree(ptr)
+#define vzalloc(size) __vmalloc(size, GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO, 0)
+#define vfree(arg) kfree(arg)
+#define kvfree(arg) kfree(arg)
+#define vmalloc_node(size, node) __vmalloc(size, GFP_KERNEL, 0)
+#define vmalloc_user(size) __vmalloc(size, GFP_KERNEL | __GFP_ZERO, 0)
+#define vmalloc(size) __vmalloc(size, GFP_KERNEL, 0)
+#define __kmalloc(...) kmalloc(__VA_ARGS__)
+#define kmalloc_node(chunk, flags, n) kmalloc(chunk, flags)
+
+/*
+ * Prefix some functions with linux_ to avoid namespace conflict
+ * with the OpenSolaris code in the kernel.
+ */
+#define kmem_cache linux_kmem_cache
+#define kmem_cache_create(...) linux_kmem_cache_create(__VA_ARGS__)
+#define kmem_cache_alloc(...) linux_kmem_cache_alloc(__VA_ARGS__)
+#define kmem_cache_free(...) linux_kmem_cache_free(__VA_ARGS__)
+#define kmem_cache_destroy(...) linux_kmem_cache_destroy(__VA_ARGS__)
+
+#define KMEM_CACHE(__struct, flags) \
+ linux_kmem_cache_create(#__struct, sizeof(struct __struct), \
+ __alignof(struct __struct), (flags), NULL)
+
+typedef void linux_kmem_ctor_t (void *);
+
+struct linux_kmem_cache {
+ uma_zone_t cache_zone;
+ linux_kmem_ctor_t *cache_ctor;
+ unsigned cache_flags;
+ unsigned cache_size;
+};
+
+#define SLAB_HWCACHE_ALIGN (1 << 0)
+#define SLAB_TYPESAFE_BY_RCU (1 << 1)
+#define SLAB_RECLAIM_ACCOUNT (1 << 2)
+
+#define SLAB_DESTROY_BY_RCU \
+ SLAB_TYPESAFE_BY_RCU
+
+#define ARCH_KMALLOC_MINALIGN \
+ __alignof(unsigned long long)
+
+/*
+ * Critical section-friendly version of kfree().
+ * Requires knowledge of the allocation size at build time.
+ */
+#define kfree_async(ptr) do { \
+ _Static_assert(sizeof(*(ptr)) >= sizeof(struct llist_node), \
+ "Size of object to free is unknown or too small"); \
+ if (curthread->td_critnest != 0) \
+ linux_kfree_async(ptr); \
+ else \
+ kfree(ptr); \
+} while (0)
+
+static inline gfp_t
+linux_check_m_flags(gfp_t flags)
+{
+ const gfp_t m = M_NOWAIT | M_WAITOK;
+
+ /* make sure either M_NOWAIT or M_WAITOK is set */
+ if ((flags & m) == 0)
+ flags |= M_NOWAIT;
+ else if ((flags & m) == m)
+ flags &= ~M_WAITOK;
+
+ /* mask away LinuxKPI specific flags */
+ return (flags & GFP_NATIVE_MASK);
+}
+
+static inline void *
+kmalloc(size_t size, gfp_t flags)
+{
+ return (malloc(size, M_KMALLOC, linux_check_m_flags(flags)));
+}
+
+static inline void *
+kcalloc(size_t n, size_t size, gfp_t flags)
+{
+ flags |= __GFP_ZERO;
+ return (mallocarray(n, size, M_KMALLOC, linux_check_m_flags(flags)));
+}
+
+static inline void *
+__vmalloc(size_t size, gfp_t flags, int other)
+{
+ return (malloc(size, M_KMALLOC, linux_check_m_flags(flags)));
+}
+
+static inline void *
+vmalloc_32(size_t size)
+{
+ return (contigmalloc(size, M_KMALLOC, M_WAITOK, 0, UINT_MAX, 1, 1));
+}
+
+static inline void *
+kmalloc_array(size_t n, size_t size, gfp_t flags)
+{
+ return (mallocarray(n, size, M_KMALLOC, linux_check_m_flags(flags)));
+}
+
+static inline void *
+kvmalloc_array(size_t n, size_t size, gfp_t flags)
+{
+ return (mallocarray(n, size, M_KMALLOC, linux_check_m_flags(flags)));
+}
+
+static inline void *
+krealloc(void *ptr, size_t size, gfp_t flags)
+{
+ return (realloc(ptr, size, M_KMALLOC, linux_check_m_flags(flags)));
+}
+
+static inline void
+kfree(const void *ptr)
+{
+ free(__DECONST(void *, ptr), M_KMALLOC);
+}
+
+static inline size_t
+ksize(const void *ptr)
+{
+ return (malloc_usable_size(ptr));
+}
+
+extern struct linux_kmem_cache *linux_kmem_cache_create(const char *name,
+ size_t size, size_t align, unsigned flags, linux_kmem_ctor_t *ctor);
+
+static inline void *
+linux_kmem_cache_alloc(struct linux_kmem_cache *c, gfp_t flags)
+{
+ return (uma_zalloc_arg(c->cache_zone, c,
+ linux_check_m_flags(flags)));
+}
+
+static inline void *
+kmem_cache_zalloc(struct linux_kmem_cache *c, gfp_t flags)
+{
+ return (uma_zalloc_arg(c->cache_zone, c,
+ linux_check_m_flags(flags | M_ZERO)));
+}
+
+extern void linux_kmem_cache_free_rcu(struct linux_kmem_cache *, void *);
+
+static inline void
+linux_kmem_cache_free(struct linux_kmem_cache *c, void *m)
+{
+ if (unlikely(c->cache_flags & SLAB_TYPESAFE_BY_RCU))
+ linux_kmem_cache_free_rcu(c, m);
+ else
+ uma_zfree(c->cache_zone, m);
+}
+
+extern void linux_kmem_cache_destroy(struct linux_kmem_cache *);
+void linux_kfree_async(void *);
+
+#endif /* _LINUX_SLAB_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/smp.h b/sys/compat/linuxkpi/common/include/linux/smp.h
new file mode 100644
index 000000000000..3f5684015547
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/smp.h
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2017 Mark Johnston <markj@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_SMP_H_
+#define _LINUX_SMP_H_
+
+#define on_each_cpu(cb, data, wait) ({ \
+ CTASSERT(wait); \
+ linux_on_each_cpu(cb, data); \
+})
+
+extern int linux_on_each_cpu(void (*)(void *), void *);
+
+#endif /* _LINUX_SMP_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/socket.h b/sys/compat/linuxkpi/common/include/linux/socket.h
new file mode 100644
index 000000000000..a9a952e4ffd8
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/socket.h
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_SOCKET_H_
+#define _LINUX_SOCKET_H_
+
+#include <sys/socket.h>
+
+#ifdef notyet
+static inline int
+memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len)
+{
+ struct uio uio;
+ int error;
+
+ uio.uio_iov = v;
+ uio.uio_iovcnt = -1;
+ uio.uio_offset = 0;
+ uio.uio_resid = len;
+ uio.uio_segflag = UIO_USERSPACE;
+ uio.uio_rw = UIO_READ;
+ error = -uiomove(kdata, len, &uio);
+ return (error);
+}
+
+static inline int
+memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len)
+{
+ struct uio uio;
+ int error;
+
+ uio.uio_iov = v;
+ uio.uio_iovcnt = -1;
+ uio.uio_offset = 0;
+ uio.uio_resid = len;
+ uio.uio_segflag = UIO_USERSPACE;
+ uio.uio_rw = UIO_WRITE;
+ error = -uiomove(kdata, len, &uio);
+}
+#endif
+
+#endif /* _LINUX_SOCKET_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/spinlock.h b/sys/compat/linuxkpi/common/include/linux/spinlock.h
new file mode 100644
index 000000000000..2309794b26ec
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/spinlock.h
@@ -0,0 +1,163 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_SPINLOCK_H_
+#define _LINUX_SPINLOCK_H_
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/kdb.h>
+
+#include <linux/compiler.h>
+#include <linux/rwlock.h>
+#include <linux/bottom_half.h>
+
+typedef struct {
+ struct mtx m;
+} spinlock_t;
+
+/*
+ * By defining CONFIG_SPIN_SKIP LinuxKPI spinlocks and asserts will be
+ * skipped during panic(). By default it is disabled due to
+ * performance reasons.
+ */
+#ifdef CONFIG_SPIN_SKIP
+#define SPIN_SKIP(void) unlikely(SCHEDULER_STOPPED() || kdb_active)
+#else
+#define SPIN_SKIP(void) 0
+#endif
+
+#define spin_lock(_l) do { \
+ if (SPIN_SKIP()) \
+ break; \
+ mtx_lock(&(_l)->m); \
+ local_bh_disable(); \
+} while (0)
+
+#define spin_lock_bh(_l) do { \
+ spin_lock(_l); \
+} while (0)
+
+#define spin_lock_irq(_l) do { \
+ spin_lock(_l); \
+} while (0)
+
+#define spin_unlock(_l) do { \
+ if (SPIN_SKIP()) \
+ break; \
+ local_bh_enable(); \
+ mtx_unlock(&(_l)->m); \
+} while (0)
+
+#define spin_unlock_bh(_l) do { \
+ spin_unlock(_l); \
+} while (0)
+
+#define spin_unlock_irq(_l) do { \
+ spin_unlock(_l); \
+} while (0)
+
+#define spin_trylock(_l) ({ \
+ int __ret; \
+ if (SPIN_SKIP()) { \
+ __ret = 1; \
+ } else { \
+ __ret = mtx_trylock(&(_l)->m); \
+ if (likely(__ret != 0)) \
+ local_bh_disable(); \
+ } \
+ __ret; \
+})
+
+#define spin_trylock_irq(_l) \
+ spin_trylock(_l)
+
+#define spin_lock_nested(_l, _n) do { \
+ if (SPIN_SKIP()) \
+ break; \
+ mtx_lock_flags(&(_l)->m, MTX_DUPOK); \
+ local_bh_disable(); \
+} while (0)
+
+#define spin_lock_irqsave(_l, flags) do { \
+ (flags) = 0; \
+ spin_lock(_l); \
+} while (0)
+
+#define spin_lock_irqsave_nested(_l, flags, _n) do { \
+ (flags) = 0; \
+ spin_lock_nested(_l, _n); \
+} while (0)
+
+#define spin_unlock_irqrestore(_l, flags) do { \
+ spin_unlock(_l); \
+} while (0)
+
+#ifdef WITNESS_ALL
+/* NOTE: the maximum WITNESS name is 64 chars */
+#define __spin_lock_name(name, file, line) \
+ (((const char *){file ":" #line "-" name}) + \
+ (sizeof(file) > 16 ? sizeof(file) - 16 : 0))
+#else
+#define __spin_lock_name(name, file, line) name
+#endif
+#define _spin_lock_name(...) __spin_lock_name(__VA_ARGS__)
+#define spin_lock_name(name) _spin_lock_name(name, __FILE__, __LINE__)
+
+#define spin_lock_init(lock) linux_spin_lock_init(lock, spin_lock_name("lnxspin"))
+
+static inline void
+linux_spin_lock_init(spinlock_t *lock, const char *name)
+{
+
+ memset(lock, 0, sizeof(*lock));
+ mtx_init(&lock->m, name, NULL, MTX_DEF | MTX_NOWITNESS);
+}
+
+static inline void
+spin_lock_destroy(spinlock_t *lock)
+{
+
+ mtx_destroy(&lock->m);
+}
+
+#define DEFINE_SPINLOCK(lock) \
+ spinlock_t lock; \
+ MTX_SYSINIT(lock, &(lock).m, spin_lock_name("lnxspin"), MTX_DEF)
+
+#define assert_spin_locked(_l) do { \
+ if (SPIN_SKIP()) \
+ break; \
+ mtx_assert(&(_l)->m, MA_OWNED); \
+} while (0)
+
+#endif /* _LINUX_SPINLOCK_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/srcu.h b/sys/compat/linuxkpi/common/include/linux/srcu.h
new file mode 100644
index 000000000000..1de7e8acedb8
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/srcu.h
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2015-2020 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_SRCU_H_
+#define _LINUX_SRCU_H_
+
+#include <linux/compiler.h>
+
+struct srcu_struct {
+};
+
+#define srcu_dereference(p, srcu) \
+ ((__typeof(*(p)) *)READ_ONCE(p))
+
+#define DEFINE_STATIC_SRCU(name) \
+ static struct srcu_struct name
+
+/* prototypes */
+
+extern int srcu_read_lock(struct srcu_struct *);
+extern void srcu_read_unlock(struct srcu_struct *, int index);
+extern void synchronize_srcu(struct srcu_struct *);
+extern void srcu_barrier(struct srcu_struct *);
+extern int init_srcu_struct(struct srcu_struct *);
+extern void cleanup_srcu_struct(struct srcu_struct *);
+
+#define synchronize_srcu_expedited(srcu) do { \
+ synchronize_srcu(srcu); \
+} while (0)
+
+#endif /* _LINUX_SRCU_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/string.h b/sys/compat/linuxkpi/common/include/linux/string.h
new file mode 100644
index 000000000000..39201e203162
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/string.h
@@ -0,0 +1,170 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_STRING_H_
+#define _LINUX_STRING_H_
+
+#include <sys/ctype.h>
+
+#include <linux/types.h>
+#include <linux/gfp.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/err.h>
+
+#include <sys/libkern.h>
+
+#define strnicmp(...) strncasecmp(__VA_ARGS__)
+
+static inline int
+match_string(const char *const *table, int n, const char *key)
+{
+ int i;
+
+ for (i = 0; i != n && table[i] != NULL; i++) {
+ if (strcmp(table[i], key) == 0)
+ return (i);
+ }
+ return (-EINVAL);
+}
+
+static inline void *
+memdup_user(const void *ptr, size_t len)
+{
+ void *retval;
+ int error;
+
+ retval = malloc(len, M_KMALLOC, M_WAITOK);
+ error = linux_copyin(ptr, retval, len);
+ if (error != 0) {
+ free(retval, M_KMALLOC);
+ return (ERR_PTR(error));
+ }
+ return (retval);
+}
+
+static inline void *
+memdup_user_nul(const void *ptr, size_t len)
+{
+ char *retval;
+ int error;
+
+ retval = malloc(len + 1, M_KMALLOC, M_WAITOK);
+ error = linux_copyin(ptr, retval, len);
+ if (error != 0) {
+ free(retval, M_KMALLOC);
+ return (ERR_PTR(error));
+ }
+ retval[len] = '\0';
+ return (retval);
+}
+
+static inline void *
+kmemdup(const void *src, size_t len, gfp_t gfp)
+{
+ void *dst;
+
+ dst = kmalloc(len, gfp);
+ if (dst != NULL)
+ memcpy(dst, src, len);
+ return (dst);
+}
+
+static inline char *
+kstrdup(const char *string, gfp_t gfp)
+{
+ char *retval;
+ size_t len;
+
+ if (string == NULL)
+ return (NULL);
+ len = strlen(string) + 1;
+ retval = kmalloc(len, gfp);
+ if (retval != NULL)
+ memcpy(retval, string, len);
+ return (retval);
+}
+
+static inline char *
+kstrndup(const char *string, size_t len, gfp_t gfp)
+{
+ char *retval;
+
+ if (string == NULL)
+ return (NULL);
+ retval = kmalloc(len + 1, gfp);
+ if (retval != NULL)
+ strncpy(retval, string, len);
+ return (retval);
+}
+
+static inline const char *
+kstrdup_const(const char *src, gfp_t gfp)
+{
+ return (kmemdup(src, strlen(src) + 1, gfp));
+}
+
+static inline char *
+skip_spaces(const char *str)
+{
+ while (isspace(*str))
+ ++str;
+ return (__DECONST(char *, str));
+}
+
+static inline void *
+memchr_inv(const void *start, int c, size_t length)
+{
+ const u8 *ptr;
+ const u8 *end;
+ u8 ch;
+
+ ch = c;
+ ptr = start;
+ end = ptr + length;
+
+ while (ptr != end) {
+ if (*ptr != ch)
+ return (__DECONST(void *, ptr));
+ ptr++;
+ }
+ return (NULL);
+}
+
+static inline size_t
+str_has_prefix(const char *str, const char *prefix)
+{
+ size_t len;
+
+ len = strlen(prefix);
+ return (strncmp(str, prefix, len) == 0 ? len : 0);
+}
+
+#endif /* _LINUX_STRING_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/swap.h b/sys/compat/linuxkpi/common/include/linux/swap.h
new file mode 100644
index 000000000000..33f8de4721a4
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/swap.h
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2018 Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_SWAP_H_
+#define _LINUX_SWAP_H_
+
+#include <vm/swap_pager.h>
+#include <vm/vm_pageout.h>
+
+static inline long
+get_nr_swap_pages(void)
+{
+ int i, j;
+
+ /* NB: This could be done cheaply by obtaining swap_total directly */
+ swap_pager_status(&i, &j);
+ return i - j;
+}
+
+static inline int
+current_is_kswapd(void)
+{
+
+ return (curproc == pageproc);
+}
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/sysfs.h b/sys/compat/linuxkpi/common/include/linux/sysfs.h
new file mode 100644
index 000000000000..c645d9fdf45a
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/sysfs.h
@@ -0,0 +1,299 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_SYSFS_H_
+#define _LINUX_SYSFS_H_
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/errno.h>
+
+#include <linux/kobject.h>
+
+struct sysfs_ops {
+ ssize_t (*show)(struct kobject *, struct attribute *, char *);
+ ssize_t (*store)(struct kobject *, struct attribute *, const char *,
+ size_t);
+};
+
+struct attribute_group {
+ const char *name;
+ mode_t (*is_visible)(struct kobject *,
+ struct attribute *, int);
+ struct attribute **attrs;
+};
+
+#define __ATTR(_name, _mode, _show, _store) { \
+ .attr = { .name = __stringify(_name), .mode = _mode }, \
+ .show = _show, .store = _store, \
+}
+#define __ATTR_RO(_name) __ATTR(_name, 0444, _name##_show, NULL)
+#define __ATTR_WO(_name) __ATTR(_name, 0200, NULL, _name##_store)
+#define __ATTR_RW(_name) __ATTR(_name, 0644, _name##_show, _name##_store)
+#define __ATTR_NULL { .attr = { .name = NULL } }
+
+#define ATTRIBUTE_GROUPS(_name) \
+ static struct attribute_group _name##_group = { \
+ .name = __stringify(_name), \
+ .attrs = _name##_attrs, \
+ }; \
+ static const struct attribute_group *_name##_groups[] = { \
+ &_name##_group, \
+ NULL, \
+ }
+
+/*
+ * Handle our generic '\0' terminated 'C' string.
+ * Two cases:
+ * a variable string: point arg1 at it, arg2 is max length.
+ * a constant string: point arg1 at it, arg2 is zero.
+ */
+
+static inline int
+sysctl_handle_attr(SYSCTL_HANDLER_ARGS)
+{
+ struct kobject *kobj;
+ struct attribute *attr;
+ const struct sysfs_ops *ops;
+ char *buf;
+ int error;
+ ssize_t len;
+
+ kobj = arg1;
+ attr = (struct attribute *)(intptr_t)arg2;
+ if (kobj->ktype == NULL || kobj->ktype->sysfs_ops == NULL)
+ return (ENODEV);
+ buf = (char *)get_zeroed_page(GFP_KERNEL);
+ if (buf == NULL)
+ return (ENOMEM);
+ ops = kobj->ktype->sysfs_ops;
+ if (ops->show) {
+ len = ops->show(kobj, attr, buf);
+ /*
+ * It's valid to not have a 'show' so just return an
+ * empty string.
+ */
+ if (len < 0) {
+ error = -len;
+ if (error != EIO)
+ goto out;
+ buf[0] = '\0';
+ } else if (len) {
+ len--;
+ if (len >= PAGE_SIZE)
+ len = PAGE_SIZE - 1;
+ /* Trim trailing newline. */
+ buf[len] = '\0';
+ }
+ }
+
+ /* Leave one trailing byte to append a newline. */
+ error = sysctl_handle_string(oidp, buf, PAGE_SIZE - 1, req);
+ if (error != 0 || req->newptr == NULL || ops->store == NULL)
+ goto out;
+ len = strlcat(buf, "\n", PAGE_SIZE);
+ KASSERT(len < PAGE_SIZE, ("new attribute truncated"));
+ len = ops->store(kobj, attr, buf, len);
+ if (len < 0)
+ error = -len;
+out:
+ free_page((unsigned long)buf);
+
+ return (error);
+}
+
+static inline int
+sysfs_create_file(struct kobject *kobj, const struct attribute *attr)
+{
+ struct sysctl_oid *oid;
+
+ oid = SYSCTL_ADD_OID(NULL, SYSCTL_CHILDREN(kobj->oidp), OID_AUTO,
+ attr->name, CTLTYPE_STRING|CTLFLAG_RW|CTLFLAG_MPSAFE, kobj,
+ (uintptr_t)attr, sysctl_handle_attr, "A", "");
+ if (!oid) {
+ return (-ENOMEM);
+ }
+
+ return (0);
+}
+
+static inline void
+sysfs_remove_file(struct kobject *kobj, const struct attribute *attr)
+{
+
+ if (kobj->oidp)
+ sysctl_remove_name(kobj->oidp, attr->name, 1, 1);
+}
+
+static inline int
+sysfs_create_files(struct kobject *kobj, const struct attribute * const *attrs)
+{
+ int error = 0;
+ int i;
+
+ for (i = 0; attrs[i] && !error; i++)
+ error = sysfs_create_file(kobj, attrs[i]);
+ while (error && --i >= 0)
+ sysfs_remove_file(kobj, attrs[i]);
+
+ return (error);
+}
+
+static inline void
+sysfs_remove_files(struct kobject *kobj, const struct attribute * const *attrs)
+{
+ int i;
+
+ for (i = 0; attrs[i]; i++)
+ sysfs_remove_file(kobj, attrs[i]);
+}
+
+static inline int
+sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp)
+{
+ struct attribute **attr;
+ struct sysctl_oid *oidp;
+
+ /* Don't create the group node if grp->name is undefined. */
+ if (grp->name)
+ oidp = SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(kobj->oidp),
+ OID_AUTO, grp->name, CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, grp->name);
+ else
+ oidp = kobj->oidp;
+ for (attr = grp->attrs; *attr != NULL; attr++) {
+ SYSCTL_ADD_OID(NULL, SYSCTL_CHILDREN(oidp), OID_AUTO,
+ (*attr)->name, CTLTYPE_STRING|CTLFLAG_RW|CTLFLAG_MPSAFE,
+ kobj, (uintptr_t)*attr, sysctl_handle_attr, "A", "");
+ }
+
+ return (0);
+}
+
+static inline void
+sysfs_remove_group(struct kobject *kobj, const struct attribute_group *grp)
+{
+
+ if (kobj->oidp)
+ sysctl_remove_name(kobj->oidp, grp->name, 1, 1);
+}
+
+static inline int
+sysfs_create_groups(struct kobject *kobj, const struct attribute_group **grps)
+{
+ int error = 0;
+ int i;
+
+ if (grps == NULL)
+ goto done;
+ for (i = 0; grps[i] && !error; i++)
+ error = sysfs_create_group(kobj, grps[i]);
+ while (error && --i >= 0)
+ sysfs_remove_group(kobj, grps[i]);
+done:
+ return (error);
+}
+
+static inline void
+sysfs_remove_groups(struct kobject *kobj, const struct attribute_group **grps)
+{
+ int i;
+
+ if (grps == NULL)
+ return;
+ for (i = 0; grps[i]; i++)
+ sysfs_remove_group(kobj, grps[i]);
+}
+
+static inline int
+sysfs_merge_group(struct kobject *kobj, const struct attribute_group *grp)
+{
+
+ /* Really expected behavior is to return failure if group exists. */
+ return (sysfs_create_group(kobj, grp));
+}
+
+static inline void
+sysfs_unmerge_group(struct kobject *kobj, const struct attribute_group *grp)
+{
+ struct attribute **attr;
+ struct sysctl_oid *oidp;
+
+ SLIST_FOREACH(oidp, SYSCTL_CHILDREN(kobj->oidp), oid_link) {
+ if (strcmp(oidp->oid_name, grp->name) != 0)
+ continue;
+ for (attr = grp->attrs; *attr != NULL; attr++) {
+ sysctl_remove_name(oidp, (*attr)->name, 1, 1);
+ }
+ }
+}
+
+static inline int
+sysfs_create_dir(struct kobject *kobj)
+{
+ struct sysctl_oid *oid;
+
+ oid = SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(kobj->parent->oidp),
+ OID_AUTO, kobj->name, CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, kobj->name);
+ if (!oid) {
+ return (-ENOMEM);
+ }
+ kobj->oidp = oid;
+
+ return (0);
+}
+
+static inline void
+sysfs_remove_dir(struct kobject *kobj)
+{
+
+ if (kobj->oidp == NULL)
+ return;
+ sysctl_remove_oid(kobj->oidp, 1, 1);
+}
+
+static inline bool
+sysfs_streq(const char *s1, const char *s2)
+{
+ int l1, l2;
+
+ l1 = strlen(s1);
+ l2 = strlen(s2);
+
+ if (l1 != 0 && s1[l1-1] == '\n')
+ l1--;
+ if (l2 != 0 && s2[l2-1] == '\n')
+ l2--;
+
+ return (l1 == l2 && strncmp(s1, s2, l1) == 0);
+}
+
+#define sysfs_attr_init(attr) do {} while(0)
+
+#endif /* _LINUX_SYSFS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/time.h b/sys/compat/linuxkpi/common/include/linux/time.h
new file mode 100644
index 000000000000..1c07c69a67a6
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/time.h
@@ -0,0 +1,135 @@
+/*-
+ * Copyright (c) 2014-2015 François Tigeot
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_TIME_H_
+#define _LINUX_TIME_H_
+
+#define NSEC_PER_USEC 1000L
+#define NSEC_PER_MSEC 1000000L
+#define NSEC_PER_SEC 1000000000L
+
+#define USEC_PER_MSEC 1000L
+#define USEC_PER_SEC 1000000L
+
+#define timespec64 timespec
+
+#include <sys/time.h>
+#include <sys/stdint.h>
+
+static inline struct timeval
+ns_to_timeval(const int64_t nsec)
+{
+ struct timeval tv;
+ long rem;
+
+ if (nsec == 0) {
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ return (tv);
+ }
+
+ tv.tv_sec = nsec / NSEC_PER_SEC;
+ rem = nsec % NSEC_PER_SEC;
+ if (rem < 0) {
+ tv.tv_sec--;
+ rem += NSEC_PER_SEC;
+ }
+ tv.tv_usec = rem / 1000;
+ return (tv);
+}
+
+static inline int64_t
+timeval_to_ns(const struct timeval *tv)
+{
+ return ((int64_t)tv->tv_sec * NSEC_PER_SEC) +
+ tv->tv_usec * NSEC_PER_USEC;
+}
+
+#define getrawmonotonic(ts) nanouptime(ts)
+
+static inline struct timespec
+timespec_sub(struct timespec lhs, struct timespec rhs)
+{
+ struct timespec ts;
+
+ timespecsub(&lhs, &rhs, &ts);
+
+ return ts;
+}
+
+static inline void
+set_normalized_timespec(struct timespec *ts, time_t sec, int64_t nsec)
+{
+ /* XXX: this doesn't actually normalize anything */
+ ts->tv_sec = sec;
+ ts->tv_nsec = nsec;
+}
+
+static inline int64_t
+timespec_to_ns(const struct timespec *ts)
+{
+ return ((ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec);
+}
+
+static inline struct timespec
+ns_to_timespec(const int64_t nsec)
+{
+ struct timespec ts;
+ int32_t rem;
+
+ if (nsec == 0) {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ return (ts);
+ }
+
+ ts.tv_sec = nsec / NSEC_PER_SEC;
+ rem = nsec % NSEC_PER_SEC;
+ if (rem < 0) {
+ ts.tv_sec--;
+ rem += NSEC_PER_SEC;
+ }
+ ts.tv_nsec = rem;
+ return (ts);
+}
+
+static inline int
+timespec_valid(const struct timespec *ts)
+{
+ if (ts->tv_sec < 0 || ts->tv_sec > 100000000 ||
+ ts->tv_nsec < 0 || ts->tv_nsec >= 1000000000)
+ return (0);
+ return (1);
+}
+
+static inline unsigned long
+get_seconds(void)
+{
+ return time_uptime;
+}
+
+#endif /* _LINUX_TIME_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/timer.h b/sys/compat/linuxkpi/common/include/linux/timer.h
new file mode 100644
index 000000000000..86048af31b2d
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/timer.h
@@ -0,0 +1,94 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_TIMER_H_
+#define _LINUX_TIMER_H_
+
+#include <linux/types.h>
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/callout.h>
+
+struct timer_list {
+ struct callout callout;
+ union {
+ void (*function) (unsigned long); /* < v4.15 */
+ void (*function_415) (struct timer_list *);
+ };
+ unsigned long data;
+ int expires;
+};
+
+extern unsigned long linux_timer_hz_mask;
+
+#define TIMER_IRQSAFE 0x0001
+
+#define from_timer(var, arg, field) \
+ container_of(arg, typeof(*(var)), field)
+
+#define timer_setup(timer, func, flags) do { \
+ CTASSERT(((flags) & ~TIMER_IRQSAFE) == 0); \
+ (timer)->function_415 = (func); \
+ (timer)->data = (unsigned long)(timer); \
+ callout_init(&(timer)->callout, 1); \
+} while (0)
+
+#define setup_timer(timer, func, dat) do { \
+ (timer)->function = (func); \
+ (timer)->data = (dat); \
+ callout_init(&(timer)->callout, 1); \
+} while (0)
+
+#define __setup_timer(timer, func, dat, flags) do { \
+ CTASSERT(((flags) & ~TIMER_IRQSAFE) == 0); \
+ setup_timer(timer, func, dat); \
+} while (0)
+
+#define init_timer(timer) do { \
+ (timer)->function = NULL; \
+ (timer)->data = 0; \
+ callout_init(&(timer)->callout, 1); \
+} while (0)
+
+extern int mod_timer(struct timer_list *, int);
+extern void add_timer(struct timer_list *);
+extern void add_timer_on(struct timer_list *, int cpu);
+extern int del_timer(struct timer_list *);
+extern int del_timer_sync(struct timer_list *);
+
+#define timer_pending(timer) callout_pending(&(timer)->callout)
+#define round_jiffies(j) \
+ ((int)(((j) + linux_timer_hz_mask) & ~linux_timer_hz_mask))
+#define round_jiffies_relative(j) round_jiffies(j)
+#define round_jiffies_up(j) round_jiffies(j)
+#define round_jiffies_up_relative(j) round_jiffies_up(j)
+
+#endif /* _LINUX_TIMER_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/types.h b/sys/compat/linuxkpi/common/include/linux/types.h
new file mode 100644
index 000000000000..aa3580c81a27
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/types.h
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_TYPES_H_
+#define _LINUX_TYPES_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <linux/compiler.h>
+#include <asm/types.h>
+
+#ifndef __bitwise__
+#ifdef __CHECKER__
+#define __bitwise__ __attribute__((bitwise))
+#else
+#define __bitwise__
+#endif
+#endif
+
+typedef uint16_t __le16;
+typedef uint16_t __be16;
+typedef uint32_t __le32;
+typedef uint32_t __be32;
+typedef uint64_t __le64;
+typedef uint64_t __be64;
+
+typedef uint16_t __aligned_u16 __aligned(sizeof(uint16_t));
+typedef uint32_t __aligned_u32 __aligned(sizeof(uint32_t));
+typedef uint64_t __aligned_u64 __aligned(sizeof(uint64_t));
+
+#ifdef _KERNEL
+typedef unsigned short ushort;
+typedef unsigned int uint;
+#endif
+typedef unsigned long ulong;
+typedef unsigned gfp_t;
+typedef off_t loff_t;
+typedef vm_paddr_t resource_size_t;
+typedef uint16_t __bitwise__ __sum16;
+typedef unsigned long pgoff_t;
+typedef unsigned __poll_t;
+
+typedef uint64_t phys_addr_t;
+
+typedef size_t __kernel_size_t;
+
+#define DECLARE_BITMAP(n, bits) \
+ unsigned long n[howmany(bits, sizeof(long) * 8)]
+
+typedef unsigned long irq_hw_number_t;
+
+struct rcu_head {
+ void *raw[2];
+} __aligned(sizeof(void *));
+
+typedef void (*rcu_callback_t)(struct rcu_head *head);
+typedef void (*call_rcu_func_t)(struct rcu_head *head, rcu_callback_t func);
+typedef int linux_task_fn_t(void *data);
+
+#endif /* _LINUX_TYPES_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/uaccess.h b/sys/compat/linuxkpi/common/include/linux/uaccess.h
new file mode 100644
index 000000000000..c09c363a98a7
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/uaccess.h
@@ -0,0 +1,96 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * Copyright (c) 2015 François Tigeot
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_UACCESS_H_
+#define _LINUX_UACCESS_H_
+
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/proc.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+
+#include <linux/compiler.h>
+
+#define VERIFY_READ VM_PROT_READ
+#define VERIFY_WRITE VM_PROT_WRITE
+
+#define __get_user(_x, _p) ({ \
+ int __err; \
+ __typeof(*(_p)) __x; \
+ __err = linux_copyin((_p), &(__x), sizeof(*(_p))); \
+ (_x) = __x; \
+ __err; \
+})
+
+#define __put_user(_x, _p) ({ \
+ __typeof(*(_p)) __x = (_x); \
+ linux_copyout(&(__x), (_p), sizeof(*(_p))); \
+})
+#define get_user(_x, _p) linux_copyin((_p), &(_x), sizeof(*(_p)))
+#define put_user(_x, _p) __put_user(_x, _p)
+#define clear_user(...) linux_clear_user(__VA_ARGS__)
+
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 50000
+#define access_ok(a,b) linux_access_ok(a,b)
+#else
+#define access_ok(a,b,c) linux_access_ok(b,c)
+#endif
+
+extern int linux_copyin(const void *uaddr, void *kaddr, size_t len);
+extern int linux_copyout(const void *kaddr, void *uaddr, size_t len);
+extern size_t linux_clear_user(void *uaddr, size_t len);
+extern int linux_access_ok(const void *uaddr, size_t len);
+
+/*
+ * NOTE: Each pagefault_disable() call must have a corresponding
+ * pagefault_enable() call in the same scope. The former creates a new
+ * block and defines a temporary variable, and the latter uses the
+ * temporary variable and closes the block. Failure to balance the
+ * calls will result in a compile-time error.
+ */
+#define pagefault_disable(void) do { \
+ int __saved_pflags = \
+ vm_fault_disable_pagefaults()
+
+#define pagefault_enable(void) \
+ vm_fault_enable_pagefaults(__saved_pflags); \
+} while (0)
+
+static inline bool
+pagefault_disabled(void)
+{
+ return ((curthread->td_pflags & TDP_NOFAULTING) != 0);
+}
+
+#endif /* _LINUX_UACCESS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/usb.h b/sys/compat/linuxkpi/common/include/linux/usb.h
new file mode 100644
index 000000000000..032c1e53a015
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/usb.h
@@ -0,0 +1,318 @@
+/* $FreeBSD$ */
+/*-
+ * Copyright (c) 2007 Luigi Rizzo - Universita` di Pisa. All rights reserved.
+ * Copyright (c) 2007 Hans Petter Selasky. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _USB_COMPAT_LINUX_H
+#define _USB_COMPAT_LINUX_H
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/condvar.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+
+struct usb_device;
+struct usb_interface;
+struct usb_driver;
+struct urb;
+
+typedef void *pm_message_t;
+typedef void (usb_complete_t)(struct urb *);
+
+#define USB_MAX_FULL_SPEED_ISOC_FRAMES (60 * 1)
+#define USB_MAX_HIGH_SPEED_ISOC_FRAMES (60 * 8)
+
+#define USB_DEVICE_ID_MATCH_DEVICE \
+ (USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT)
+
+#define USB_DEVICE(vend,prod) \
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = (vend), \
+ .idProduct = (prod)
+
+/* The "usb_driver" structure holds the Linux USB device driver
+ * callbacks, and a pointer to device ID's which this entry should
+ * match against. Usually this entry is exposed to the USB emulation
+ * layer using the "USB_DRIVER_EXPORT()" macro, which is defined
+ * below.
+ */
+struct usb_driver {
+ const char *name;
+
+ int (*probe)(struct usb_interface *intf,
+ const struct usb_device_id *id);
+
+ void (*disconnect)(struct usb_interface *intf);
+
+ int (*ioctl)(struct usb_interface *intf, unsigned int code, void *buf);
+
+ int (*suspend)(struct usb_interface *intf, pm_message_t message);
+ int (*resume)(struct usb_interface *intf);
+
+ const struct usb_device_id *id_table;
+
+ void (*shutdown)(struct usb_interface *intf);
+
+ LIST_ENTRY(usb_driver) linux_driver_list;
+};
+
+#define USB_DRIVER_EXPORT(id,p_usb_drv) \
+ SYSINIT(id,SI_SUB_KLD,SI_ORDER_FIRST,usb_linux_register,p_usb_drv); \
+ SYSUNINIT(id,SI_SUB_KLD,SI_ORDER_ANY,usb_linux_deregister,p_usb_drv)
+
+#define USB_DT_ENDPOINT_SIZE 7
+#define USB_DT_ENDPOINT_AUDIO_SIZE 9
+
+/*
+ * Endpoints
+ */
+#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */
+#define USB_ENDPOINT_DIR_MASK 0x80
+
+#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */
+#define USB_ENDPOINT_XFER_CONTROL 0
+#define USB_ENDPOINT_XFER_ISOC 1
+#define USB_ENDPOINT_XFER_BULK 2
+#define USB_ENDPOINT_XFER_INT 3
+#define USB_ENDPOINT_MAX_ADJUSTABLE 0x80
+
+/* CONTROL REQUEST SUPPORT */
+
+/*
+ * Definition of direction mask for
+ * "bEndpointAddress" and "bmRequestType":
+ */
+#define USB_DIR_MASK 0x80
+#define USB_DIR_OUT 0x00 /* write to USB device */
+#define USB_DIR_IN 0x80 /* read from USB device */
+
+/*
+ * Definition of type mask for
+ * "bmRequestType":
+ */
+#define USB_TYPE_MASK (0x03 << 5)
+#define USB_TYPE_STANDARD (0x00 << 5)
+#define USB_TYPE_CLASS (0x01 << 5)
+#define USB_TYPE_VENDOR (0x02 << 5)
+#define USB_TYPE_RESERVED (0x03 << 5)
+
+/*
+ * Definition of receiver mask for
+ * "bmRequestType":
+ */
+#define USB_RECIP_MASK 0x1f
+#define USB_RECIP_DEVICE 0x00
+#define USB_RECIP_INTERFACE 0x01
+#define USB_RECIP_ENDPOINT 0x02
+#define USB_RECIP_OTHER 0x03
+
+/*
+ * Definition of standard request values for
+ * "bRequest":
+ */
+#define USB_REQ_GET_STATUS 0x00
+#define USB_REQ_CLEAR_FEATURE 0x01
+#define USB_REQ_SET_FEATURE 0x03
+#define USB_REQ_SET_ADDRESS 0x05
+#define USB_REQ_GET_DESCRIPTOR 0x06
+#define USB_REQ_SET_DESCRIPTOR 0x07
+#define USB_REQ_GET_CONFIGURATION 0x08
+#define USB_REQ_SET_CONFIGURATION 0x09
+#define USB_REQ_GET_INTERFACE 0x0A
+#define USB_REQ_SET_INTERFACE 0x0B
+#define USB_REQ_SYNCH_FRAME 0x0C
+
+#define USB_REQ_SET_ENCRYPTION 0x0D /* Wireless USB */
+#define USB_REQ_GET_ENCRYPTION 0x0E
+#define USB_REQ_SET_HANDSHAKE 0x0F
+#define USB_REQ_GET_HANDSHAKE 0x10
+#define USB_REQ_SET_CONNECTION 0x11
+#define USB_REQ_SET_SECURITY_DATA 0x12
+#define USB_REQ_GET_SECURITY_DATA 0x13
+#define USB_REQ_SET_WUSB_DATA 0x14
+#define USB_REQ_LOOPBACK_DATA_WRITE 0x15
+#define USB_REQ_LOOPBACK_DATA_READ 0x16
+#define USB_REQ_SET_INTERFACE_DS 0x17
+
+/*
+ * USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and
+ * are read as a bit array returned by USB_REQ_GET_STATUS. (So there
+ * are at most sixteen features of each type.)
+ */
+#define USB_DEVICE_SELF_POWERED 0 /* (read only) */
+#define USB_DEVICE_REMOTE_WAKEUP 1 /* dev may initiate wakeup */
+#define USB_DEVICE_TEST_MODE 2 /* (wired high speed only) */
+#define USB_DEVICE_BATTERY 2 /* (wireless) */
+#define USB_DEVICE_B_HNP_ENABLE 3 /* (otg) dev may initiate HNP */
+#define USB_DEVICE_WUSB_DEVICE 3 /* (wireless) */
+#define USB_DEVICE_A_HNP_SUPPORT 4 /* (otg) RH port supports HNP */
+#define USB_DEVICE_A_ALT_HNP_SUPPORT 5 /* (otg) other RH port does */
+#define USB_DEVICE_DEBUG_MODE 6 /* (special devices only) */
+
+#define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */
+
+#define PIPE_ISOCHRONOUS 0x01 /* UE_ISOCHRONOUS */
+#define PIPE_INTERRUPT 0x03 /* UE_INTERRUPT */
+#define PIPE_CONTROL 0x00 /* UE_CONTROL */
+#define PIPE_BULK 0x02 /* UE_BULK */
+
+/* Whenever Linux references an USB endpoint:
+ * a) to initialize "urb->endpoint"
+ * b) second argument passed to "usb_control_msg()"
+ *
+ * Then it uses one of the following macros. The "endpoint" argument
+ * is the physical endpoint value masked by 0xF. The "dev" argument
+ * is a pointer to "struct usb_device".
+ */
+#define usb_sndctrlpipe(dev,endpoint) \
+ usb_find_host_endpoint(dev, PIPE_CONTROL, (endpoint) | USB_DIR_OUT)
+
+#define usb_rcvctrlpipe(dev,endpoint) \
+ usb_find_host_endpoint(dev, PIPE_CONTROL, (endpoint) | USB_DIR_IN)
+
+#define usb_sndisocpipe(dev,endpoint) \
+ usb_find_host_endpoint(dev, PIPE_ISOCHRONOUS, (endpoint) | USB_DIR_OUT)
+
+#define usb_rcvisocpipe(dev,endpoint) \
+ usb_find_host_endpoint(dev, PIPE_ISOCHRONOUS, (endpoint) | USB_DIR_IN)
+
+#define usb_sndbulkpipe(dev,endpoint) \
+ usb_find_host_endpoint(dev, PIPE_BULK, (endpoint) | USB_DIR_OUT)
+
+#define usb_rcvbulkpipe(dev,endpoint) \
+ usb_find_host_endpoint(dev, PIPE_BULK, (endpoint) | USB_DIR_IN)
+
+#define usb_sndintpipe(dev,endpoint) \
+ usb_find_host_endpoint(dev, PIPE_INTERRUPT, (endpoint) | USB_DIR_OUT)
+
+#define usb_rcvintpipe(dev,endpoint) \
+ usb_find_host_endpoint(dev, PIPE_INTERRUPT, (endpoint) | USB_DIR_IN)
+
+/*
+ * The following structure is used to extend "struct urb" when we are
+ * dealing with an isochronous endpoint. It contains information about
+ * the data offset and data length of an isochronous packet.
+ * The "actual_length" field is updated before the "complete"
+ * callback in the "urb" structure is called.
+ */
+struct usb_iso_packet_descriptor {
+ uint32_t offset; /* depreciated buffer offset (the
+ * packets are usually back to back) */
+ uint16_t length; /* expected length */
+ uint16_t actual_length;
+ int16_t status; /* transfer status */
+};
+
+/*
+ * The following structure holds various information about an USB
+ * transfer. This structure is used for all kinds of USB transfers.
+ *
+ * URB is short for USB Request Block.
+ */
+struct urb {
+ TAILQ_ENTRY(urb) bsd_urb_list;
+ struct cv cv_wait;
+
+ struct usb_device *dev; /* (in) pointer to associated device */
+ struct usb_host_endpoint *endpoint; /* (in) pipe pointer */
+ uint8_t *setup_packet; /* (in) setup packet (control only) */
+ uint8_t *bsd_data_ptr;
+ void *transfer_buffer; /* (in) associated data buffer */
+ void *context; /* (in) context for completion */
+ usb_complete_t *complete; /* (in) completion routine */
+
+ usb_size_t transfer_buffer_length;/* (in) data buffer length */
+ usb_size_t bsd_length_rem;
+ usb_size_t actual_length; /* (return) actual transfer length */
+ usb_timeout_t timeout; /* FreeBSD specific */
+
+ uint16_t transfer_flags; /* (in) */
+#define URB_SHORT_NOT_OK 0x0001 /* report short transfers like errors */
+#define URB_ISO_ASAP 0x0002 /* ignore "start_frame" field */
+#define URB_ZERO_PACKET 0x0004 /* the USB transfer ends with a short
+ * packet */
+#define URB_NO_TRANSFER_DMA_MAP 0x0008 /* "transfer_dma" is valid on submit */
+#define URB_WAIT_WAKEUP 0x0010 /* custom flags */
+#define URB_IS_SLEEPING 0x0020 /* custom flags */
+
+ usb_frcount_t start_frame; /* (modify) start frame (ISO) */
+ usb_frcount_t number_of_packets; /* (in) number of ISO packets */
+ uint16_t interval; /* (modify) transfer interval
+ * (INT/ISO) */
+ uint16_t error_count; /* (return) number of ISO errors */
+ int16_t status; /* (return) status */
+
+ uint8_t setup_dma; /* (in) not used on FreeBSD */
+ uint8_t transfer_dma; /* (in) not used on FreeBSD */
+ uint8_t bsd_isread;
+ uint8_t kill_count; /* FreeBSD specific */
+
+ struct usb_iso_packet_descriptor iso_frame_desc[]; /* (in) ISO ONLY */
+};
+
+/* various prototypes */
+
+int usb_submit_urb(struct urb *urb, uint16_t mem_flags);
+int usb_unlink_urb(struct urb *urb);
+int usb_clear_halt(struct usb_device *dev, struct usb_host_endpoint *uhe);
+int usb_control_msg(struct usb_device *dev, struct usb_host_endpoint *ep,
+ uint8_t request, uint8_t requesttype, uint16_t value,
+ uint16_t index, void *data, uint16_t size, usb_timeout_t timeout);
+int usb_set_interface(struct usb_device *dev, uint8_t ifnum,
+ uint8_t alternate);
+int usb_setup_endpoint(struct usb_device *dev,
+ struct usb_host_endpoint *uhe, usb_frlength_t bufsize);
+
+struct usb_host_endpoint *usb_find_host_endpoint(struct usb_device *dev,
+ uint8_t type, uint8_t ep);
+struct urb *usb_alloc_urb(uint16_t iso_packets, uint16_t mem_flags);
+struct usb_host_interface *usb_altnum_to_altsetting(
+ const struct usb_interface *intf, uint8_t alt_index);
+struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, uint8_t iface_no);
+
+void *usb_buffer_alloc(struct usb_device *dev, usb_size_t size,
+ uint16_t mem_flags, uint8_t *dma_addr);
+void *usbd_get_intfdata(struct usb_interface *intf);
+
+void usb_buffer_free(struct usb_device *dev, usb_size_t size, void *addr, uint8_t dma_addr);
+void usb_free_urb(struct urb *urb);
+void usb_init_urb(struct urb *urb);
+void usb_kill_urb(struct urb *urb);
+void usb_set_intfdata(struct usb_interface *intf, void *data);
+void usb_linux_register(void *arg);
+void usb_linux_deregister(void *arg);
+
+void usb_fill_bulk_urb(struct urb *, struct usb_device *,
+ struct usb_host_endpoint *, void *, int, usb_complete_t, void *);
+int usb_bulk_msg(struct usb_device *, struct usb_host_endpoint *,
+ void *, int, uint16_t *, usb_timeout_t);
+
+#define interface_to_usbdev(intf) (intf)->linux_udev
+#define interface_to_bsddev(intf) (intf)->linux_udev
+
+#endif /* _USB_COMPAT_LINUX_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/vmalloc.h b/sys/compat/linuxkpi/common/include/linux/vmalloc.h
new file mode 100644
index 000000000000..53178314c35a
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/vmalloc.h
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_VMALLOC_H_
+#define _LINUX_VMALLOC_H_
+
+#include <linux/page.h>
+
+#define VM_MAP 0x0000
+#define PAGE_KERNEL 0x0000
+
+void *vmap(struct page **pages, unsigned int count, unsigned long flags,
+ int prot);
+void vunmap(void *addr);
+
+#endif /* _LINUX_VMALLOC_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/wait.h b/sys/compat/linuxkpi/common/include/linux/wait.h
new file mode 100644
index 000000000000..348464fb27df
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/wait.h
@@ -0,0 +1,313 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * Copyright (c) 2017 Mark Johnston <markj@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_WAIT_H_
+#define _LINUX_WAIT_H_
+
+#include <linux/compiler.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+
+#include <asm/atomic.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#define SKIP_SLEEP() (SCHEDULER_STOPPED() || kdb_active)
+
+#define might_sleep() \
+ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "might_sleep()")
+
+#define might_sleep_if(cond) do { \
+ if (cond) { might_sleep(); } \
+} while (0)
+
+struct wait_queue;
+struct wait_queue_head;
+
+#define wait_queue_entry wait_queue
+
+typedef struct wait_queue wait_queue_t;
+typedef struct wait_queue_entry wait_queue_entry_t;
+typedef struct wait_queue_head wait_queue_head_t;
+
+typedef int wait_queue_func_t(wait_queue_t *, unsigned int, int, void *);
+
+/*
+ * Many API consumers directly reference these fields and those of
+ * wait_queue_head.
+ */
+struct wait_queue {
+ unsigned int flags; /* always 0 */
+ void *private;
+ wait_queue_func_t *func;
+ union {
+ struct list_head task_list; /* < v4.13 */
+ struct list_head entry; /* >= v4.13 */
+ };
+};
+
+struct wait_queue_head {
+ spinlock_t lock;
+ union {
+ struct list_head task_list; /* < v4.13 */
+ struct list_head head; /* >= v4.13 */
+ };
+};
+
+/*
+ * This function is referenced by at least one DRM driver, so it may not be
+ * renamed and furthermore must be the default wait queue callback.
+ */
+extern wait_queue_func_t autoremove_wake_function;
+extern wait_queue_func_t default_wake_function;
+
+#define DEFINE_WAIT_FUNC(name, function) \
+ wait_queue_t name = { \
+ .private = current, \
+ .func = function, \
+ .task_list = LINUX_LIST_HEAD_INIT(name.task_list) \
+ }
+
+#define DEFINE_WAIT(name) \
+ DEFINE_WAIT_FUNC(name, autoremove_wake_function)
+
+#define DECLARE_WAITQUEUE(name, task) \
+ wait_queue_t name = { \
+ .private = task, \
+ .task_list = LINUX_LIST_HEAD_INIT(name.task_list) \
+ }
+
+#define DECLARE_WAIT_QUEUE_HEAD(name) \
+ wait_queue_head_t name = { \
+ .task_list = LINUX_LIST_HEAD_INIT(name.task_list), \
+ }; \
+ MTX_SYSINIT(name, &(name).lock.m, spin_lock_name("wqhead"), MTX_DEF)
+
+#define init_waitqueue_head(wqh) do { \
+ mtx_init(&(wqh)->lock.m, spin_lock_name("wqhead"), \
+ NULL, MTX_DEF | MTX_NEW | MTX_NOWITNESS); \
+ INIT_LIST_HEAD(&(wqh)->task_list); \
+} while (0)
+
+#define __init_waitqueue_head(wqh, name, lk) init_waitqueue_head(wqh)
+
+void linux_init_wait_entry(wait_queue_t *, int);
+void linux_wake_up(wait_queue_head_t *, unsigned int, int, bool);
+
+#define init_wait_entry(wq, flags) \
+ linux_init_wait_entry(wq, flags)
+#define wake_up(wqh) \
+ linux_wake_up(wqh, TASK_NORMAL, 1, false)
+#define wake_up_all(wqh) \
+ linux_wake_up(wqh, TASK_NORMAL, 0, false)
+#define wake_up_locked(wqh) \
+ linux_wake_up(wqh, TASK_NORMAL, 1, true)
+#define wake_up_all_locked(wqh) \
+ linux_wake_up(wqh, TASK_NORMAL, 0, true)
+#define wake_up_interruptible(wqh) \
+ linux_wake_up(wqh, TASK_INTERRUPTIBLE, 1, false)
+#define wake_up_interruptible_all(wqh) \
+ linux_wake_up(wqh, TASK_INTERRUPTIBLE, 0, false)
+
+int linux_wait_event_common(wait_queue_head_t *, wait_queue_t *, int,
+ unsigned int, spinlock_t *);
+
+/*
+ * Returns -ERESTARTSYS for a signal, 0 if cond is false after timeout, 1 if
+ * cond is true after timeout, remaining jiffies (> 0) if cond is true before
+ * timeout.
+ */
+#define __wait_event_common(wqh, cond, timeout, state, lock) ({ \
+ DEFINE_WAIT(__wq); \
+ const int __timeout = ((int)(timeout)) < 1 ? 1 : (timeout); \
+ int __start = ticks; \
+ int __ret = 0; \
+ \
+ for (;;) { \
+ linux_prepare_to_wait(&(wqh), &__wq, state); \
+ if (cond) \
+ break; \
+ __ret = linux_wait_event_common(&(wqh), &__wq, \
+ __timeout, state, lock); \
+ if (__ret != 0) \
+ break; \
+ } \
+ linux_finish_wait(&(wqh), &__wq); \
+ if (__timeout != MAX_SCHEDULE_TIMEOUT) { \
+ if (__ret == -EWOULDBLOCK) \
+ __ret = !!(cond); \
+ else if (__ret != -ERESTARTSYS) { \
+ __ret = __timeout + __start - ticks; \
+ /* range check return value */ \
+ if (__ret < 1) \
+ __ret = 1; \
+ else if (__ret > __timeout) \
+ __ret = __timeout; \
+ } \
+ } \
+ __ret; \
+})
+
+#define wait_event(wqh, cond) do { \
+ (void) __wait_event_common(wqh, cond, MAX_SCHEDULE_TIMEOUT, \
+ TASK_UNINTERRUPTIBLE, NULL); \
+} while (0)
+
+#define wait_event_timeout(wqh, cond, timeout) ({ \
+ __wait_event_common(wqh, cond, timeout, TASK_UNINTERRUPTIBLE, \
+ NULL); \
+})
+
+#define wait_event_killable(wqh, cond) ({ \
+ __wait_event_common(wqh, cond, MAX_SCHEDULE_TIMEOUT, \
+ TASK_INTERRUPTIBLE, NULL); \
+})
+
+#define wait_event_interruptible(wqh, cond) ({ \
+ __wait_event_common(wqh, cond, MAX_SCHEDULE_TIMEOUT, \
+ TASK_INTERRUPTIBLE, NULL); \
+})
+
+#define wait_event_interruptible_timeout(wqh, cond, timeout) ({ \
+ __wait_event_common(wqh, cond, timeout, TASK_INTERRUPTIBLE, \
+ NULL); \
+})
+
+/*
+ * Wait queue is already locked.
+ */
+#define wait_event_interruptible_locked(wqh, cond) ({ \
+ int __ret; \
+ \
+ spin_unlock(&(wqh).lock); \
+ __ret = __wait_event_common(wqh, cond, MAX_SCHEDULE_TIMEOUT, \
+ TASK_INTERRUPTIBLE, NULL); \
+ spin_lock(&(wqh).lock); \
+ __ret; \
+})
+
+/*
+ * The passed spinlock is held when testing the condition.
+ */
+#define wait_event_interruptible_lock_irq(wqh, cond, lock) ({ \
+ __wait_event_common(wqh, cond, MAX_SCHEDULE_TIMEOUT, \
+ TASK_INTERRUPTIBLE, &(lock)); \
+})
+
+/*
+ * The passed spinlock is held when testing the condition.
+ */
+#define wait_event_lock_irq(wqh, cond, lock) ({ \
+ __wait_event_common(wqh, cond, MAX_SCHEDULE_TIMEOUT, \
+ TASK_UNINTERRUPTIBLE, &(lock)); \
+})
+
+static inline void
+__add_wait_queue(wait_queue_head_t *wqh, wait_queue_t *wq)
+{
+ list_add(&wq->task_list, &wqh->task_list);
+}
+
+static inline void
+add_wait_queue(wait_queue_head_t *wqh, wait_queue_t *wq)
+{
+
+ spin_lock(&wqh->lock);
+ __add_wait_queue(wqh, wq);
+ spin_unlock(&wqh->lock);
+}
+
+static inline void
+__add_wait_queue_tail(wait_queue_head_t *wqh, wait_queue_t *wq)
+{
+ list_add_tail(&wq->task_list, &wqh->task_list);
+}
+
+static inline void
+__add_wait_queue_entry_tail(wait_queue_head_t *wqh, wait_queue_entry_t *wq)
+{
+ list_add_tail(&wq->entry, &wqh->head);
+}
+
+static inline void
+__remove_wait_queue(wait_queue_head_t *wqh, wait_queue_t *wq)
+{
+ list_del(&wq->task_list);
+}
+
+static inline void
+remove_wait_queue(wait_queue_head_t *wqh, wait_queue_t *wq)
+{
+
+ spin_lock(&wqh->lock);
+ __remove_wait_queue(wqh, wq);
+ spin_unlock(&wqh->lock);
+}
+
+bool linux_waitqueue_active(wait_queue_head_t *);
+
+#define waitqueue_active(wqh) linux_waitqueue_active(wqh)
+
+void linux_prepare_to_wait(wait_queue_head_t *, wait_queue_t *, int);
+void linux_finish_wait(wait_queue_head_t *, wait_queue_t *);
+
+#define prepare_to_wait(wqh, wq, state) linux_prepare_to_wait(wqh, wq, state)
+#define finish_wait(wqh, wq) linux_finish_wait(wqh, wq)
+
+void linux_wake_up_bit(void *, int);
+int linux_wait_on_bit_timeout(unsigned long *, int, unsigned int, int);
+void linux_wake_up_atomic_t(atomic_t *);
+int linux_wait_on_atomic_t(atomic_t *, unsigned int);
+
+#define wake_up_bit(word, bit) linux_wake_up_bit(word, bit)
+#define wait_on_bit(word, bit, state) \
+ linux_wait_on_bit_timeout(word, bit, state, MAX_SCHEDULE_TIMEOUT)
+#define wait_on_bit_timeout(word, bit, state, timeout) \
+ linux_wait_on_bit_timeout(word, bit, state, timeout)
+#define wake_up_atomic_t(a) linux_wake_up_atomic_t(a)
+/*
+ * All existing callers have a cb that just schedule()s. To avoid adding
+ * complexity, just emulate that internally. The prototype is different so that
+ * callers must be manually modified; a cb that does something other than call
+ * schedule() will require special treatment.
+ */
+#define wait_on_atomic_t(a, state) linux_wait_on_atomic_t(a, state)
+
+struct task_struct;
+bool linux_wake_up_state(struct task_struct *, unsigned int);
+
+#define wake_up_process(task) linux_wake_up_state(task, TASK_NORMAL)
+#define wake_up_state(task, state) linux_wake_up_state(task, state)
+
+#endif /* _LINUX_WAIT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/wait_bit.h b/sys/compat/linuxkpi/common/include/linux/wait_bit.h
new file mode 100644
index 000000000000..e3dddaade498
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/wait_bit.h
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Emmanuel Vadot under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __LINUX_WAITBIT_H__
+#define __LINUX_WAITBIT_H__
+
+#include <linux/wait.h>
+#include <linux/bitops.h>
+
+extern wait_queue_head_t linux_bit_waitq;
+extern wait_queue_head_t linux_var_waitq;
+
+#define wait_var_event_killable(var, cond) \
+ wait_event_killable(linux_var_waitq, cond)
+
+static inline void
+clear_and_wake_up_bit(int bit, void *word)
+{
+ clear_bit_unlock(bit, word);
+ wake_up_bit(word, bit);
+}
+
+static inline wait_queue_head_t *
+bit_waitqueue(void *word, int bit)
+{
+
+ return (&linux_bit_waitq);
+}
+
+static inline void
+wake_up_var(void *var)
+{
+
+ wake_up(&linux_var_waitq);
+}
+
+#endif /* __LINUX_WAITBIT_H__ */
diff --git a/sys/compat/linuxkpi/common/include/linux/workqueue.h b/sys/compat/linuxkpi/common/include/linux/workqueue.h
new file mode 100644
index 000000000000..768ce33bb20d
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/workqueue.h
@@ -0,0 +1,259 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_WORKQUEUE_H_
+#define _LINUX_WORKQUEUE_H_
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+
+#include <asm/atomic.h>
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/taskqueue.h>
+#include <sys/mutex.h>
+
+#define WORK_CPU_UNBOUND MAXCPU
+#define WQ_UNBOUND (1 << 0)
+#define WQ_HIGHPRI (1 << 1)
+
+struct work_struct;
+typedef void (*work_func_t)(struct work_struct *);
+
+struct work_exec {
+ TAILQ_ENTRY(work_exec) entry;
+ struct work_struct *target;
+};
+
+struct workqueue_struct {
+ struct taskqueue *taskqueue;
+ struct mtx exec_mtx;
+ TAILQ_HEAD(, work_exec) exec_head;
+ atomic_t draining;
+};
+
+#define WQ_EXEC_LOCK(wq) mtx_lock(&(wq)->exec_mtx)
+#define WQ_EXEC_UNLOCK(wq) mtx_unlock(&(wq)->exec_mtx)
+
+struct work_struct {
+ struct task work_task;
+ struct workqueue_struct *work_queue;
+ work_func_t func;
+ atomic_t state;
+};
+
+struct rcu_work {
+ struct work_struct work;
+ struct rcu_head rcu;
+
+ struct workqueue_struct *wq;
+};
+
+#define DECLARE_WORK(name, fn) \
+ struct work_struct name; \
+ static void name##_init(void *arg) \
+ { \
+ INIT_WORK(&name, fn); \
+ } \
+ SYSINIT(name, SI_SUB_LOCK, SI_ORDER_SECOND, name##_init, NULL)
+
+struct delayed_work {
+ struct work_struct work;
+ struct {
+ struct callout callout;
+ struct mtx mtx;
+ int expires;
+ } timer;
+};
+
+#define DECLARE_DELAYED_WORK(name, fn) \
+ struct delayed_work name; \
+ static void __linux_delayed_ ## name ## _init(void *arg) \
+ { \
+ linux_init_delayed_work(&name, fn); \
+ } \
+ SYSINIT(name, SI_SUB_LOCK, SI_ORDER_SECOND, \
+ __linux_delayed_ ## name##_init, NULL)
+
+static inline struct delayed_work *
+to_delayed_work(struct work_struct *work)
+{
+ return (container_of(work, struct delayed_work, work));
+}
+
+#define INIT_WORK(work, fn) \
+do { \
+ (work)->func = (fn); \
+ (work)->work_queue = NULL; \
+ atomic_set(&(work)->state, 0); \
+ TASK_INIT(&(work)->work_task, 0, linux_work_fn, (work)); \
+} while (0)
+
+#define INIT_RCU_WORK(_work, _fn) \
+ INIT_WORK(&(_work)->work, (_fn))
+
+#define INIT_WORK_ONSTACK(work, fn) \
+ INIT_WORK(work, fn)
+
+#define INIT_DELAYED_WORK(dwork, fn) \
+ linux_init_delayed_work(dwork, fn)
+
+#define INIT_DELAYED_WORK_ONSTACK(dwork, fn) \
+ linux_init_delayed_work(dwork, fn)
+
+#define INIT_DEFERRABLE_WORK(dwork, fn) \
+ INIT_DELAYED_WORK(dwork, fn)
+
+#define flush_scheduled_work() \
+ taskqueue_drain_all(system_wq->taskqueue)
+
+#define queue_work(wq, work) \
+ linux_queue_work_on(WORK_CPU_UNBOUND, wq, work)
+
+#define schedule_work(work) \
+ linux_queue_work_on(WORK_CPU_UNBOUND, system_wq, work)
+
+#define queue_delayed_work(wq, dwork, delay) \
+ linux_queue_delayed_work_on(WORK_CPU_UNBOUND, wq, dwork, delay)
+
+#define schedule_delayed_work_on(cpu, dwork, delay) \
+ linux_queue_delayed_work_on(cpu, system_wq, dwork, delay)
+
+#define queue_work_on(cpu, wq, work) \
+ linux_queue_work_on(cpu, wq, work)
+
+#define schedule_delayed_work(dwork, delay) \
+ linux_queue_delayed_work_on(WORK_CPU_UNBOUND, system_wq, dwork, delay)
+
+#define queue_delayed_work_on(cpu, wq, dwork, delay) \
+ linux_queue_delayed_work_on(cpu, wq, dwork, delay)
+
+#define create_singlethread_workqueue(name) \
+ linux_create_workqueue_common(name, 1)
+
+#define create_workqueue(name) \
+ linux_create_workqueue_common(name, mp_ncpus)
+
+#define alloc_ordered_workqueue(name, flags) \
+ linux_create_workqueue_common(name, 1)
+
+#define alloc_workqueue(name, flags, max_active) \
+ linux_create_workqueue_common(name, max_active)
+
+#define flush_workqueue(wq) \
+ taskqueue_drain_all((wq)->taskqueue)
+
+#define drain_workqueue(wq) do { \
+ atomic_inc(&(wq)->draining); \
+ taskqueue_drain_all((wq)->taskqueue); \
+ atomic_dec(&(wq)->draining); \
+} while (0)
+
+#define mod_delayed_work(wq, dwork, delay) ({ \
+ bool __retval; \
+ __retval = linux_cancel_delayed_work(dwork); \
+ linux_queue_delayed_work_on(WORK_CPU_UNBOUND, \
+ wq, dwork, delay); \
+ __retval; \
+})
+
+#define delayed_work_pending(dwork) \
+ linux_work_pending(&(dwork)->work)
+
+#define cancel_delayed_work(dwork) \
+ linux_cancel_delayed_work(dwork)
+
+#define cancel_work_sync(work) \
+ linux_cancel_work_sync(work)
+
+#define cancel_delayed_work_sync(dwork) \
+ linux_cancel_delayed_work_sync(dwork)
+
+#define flush_work(work) \
+ linux_flush_work(work)
+
+#define queue_rcu_work(wq, rwork) \
+ linux_queue_rcu_work(wq, rwork)
+
+#define flush_rcu_work(rwork) \
+ linux_flush_rcu_work(rwork)
+
+#define flush_delayed_work(dwork) \
+ linux_flush_delayed_work(dwork)
+
+#define work_pending(work) \
+ linux_work_pending(work)
+
+#define work_busy(work) \
+ linux_work_busy(work)
+
+#define destroy_work_on_stack(work) \
+ do { } while (0)
+
+#define destroy_delayed_work_on_stack(dwork) \
+ do { } while (0)
+
+#define destroy_workqueue(wq) \
+ linux_destroy_workqueue(wq)
+
+#define current_work() \
+ linux_current_work()
+
+/* prototypes */
+
+extern struct workqueue_struct *system_wq;
+extern struct workqueue_struct *system_long_wq;
+extern struct workqueue_struct *system_unbound_wq;
+extern struct workqueue_struct *system_highpri_wq;
+extern struct workqueue_struct *system_power_efficient_wq;
+
+extern void linux_init_delayed_work(struct delayed_work *, work_func_t);
+extern void linux_work_fn(void *, int);
+extern void linux_delayed_work_fn(void *, int);
+extern struct workqueue_struct *linux_create_workqueue_common(const char *, int);
+extern void linux_destroy_workqueue(struct workqueue_struct *);
+extern bool linux_queue_work_on(int cpu, struct workqueue_struct *, struct work_struct *);
+extern bool linux_queue_delayed_work_on(int cpu, struct workqueue_struct *,
+ struct delayed_work *, unsigned delay);
+extern bool linux_cancel_delayed_work(struct delayed_work *);
+extern bool linux_cancel_work_sync(struct work_struct *);
+extern bool linux_cancel_delayed_work_sync(struct delayed_work *);
+extern bool linux_flush_work(struct work_struct *);
+extern bool linux_flush_delayed_work(struct delayed_work *);
+extern bool linux_work_pending(struct work_struct *);
+extern bool linux_work_busy(struct work_struct *);
+extern struct work_struct *linux_current_work(void);
+extern bool linux_queue_rcu_work(struct workqueue_struct *wq, struct rcu_work *rwork);
+extern bool linux_flush_rcu_work(struct rcu_work *rwork);
+
+#endif /* _LINUX_WORKQUEUE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/ww_mutex.h b/sys/compat/linuxkpi/common/include/linux/ww_mutex.h
new file mode 100644
index 000000000000..49bec6628486
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/ww_mutex.h
@@ -0,0 +1,144 @@
+/*-
+ * Copyright (c) 2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_WW_MUTEX_H_
+#define _LINUX_WW_MUTEX_H_
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/condvar.h>
+#include <sys/kernel.h>
+
+#include <linux/mutex.h>
+
+struct ww_class {
+ const char *mutex_name;
+};
+
+struct ww_acquire_ctx {
+};
+
+struct ww_mutex {
+ struct mutex base;
+ struct cv condvar;
+ struct ww_acquire_ctx *ctx;
+};
+
+#define DEFINE_WW_CLASS(name) \
+ struct ww_class name = { \
+ .mutex_name = mutex_name(#name "_mutex") \
+ }
+
+#define DEFINE_WW_MUTEX(name, ww_class) \
+ struct ww_mutex name; \
+ static void name##_init(void *arg) \
+ { \
+ ww_mutex_init(&name, &ww_class); \
+ } \
+ SYSINIT(name, SI_SUB_LOCK, SI_ORDER_SECOND, name##_init, NULL)
+
+#define ww_mutex_is_locked(_m) \
+ sx_xlocked(&(_m)->base.sx)
+
+#define ww_mutex_lock_slow(_m, _x) \
+ ww_mutex_lock(_m, _x)
+
+#define ww_mutex_lock_slow_interruptible(_m, _x) \
+ ww_mutex_lock_interruptible(_m, _x)
+
+static inline int __must_check
+ww_mutex_trylock(struct ww_mutex *lock)
+{
+ return (mutex_trylock(&lock->base));
+}
+
+extern int linux_ww_mutex_lock_sub(struct ww_mutex *,
+ struct ww_acquire_ctx *, int catch_signal);
+
+static inline int
+ww_mutex_lock(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)
+{
+ if (MUTEX_SKIP())
+ return (0);
+ else if ((struct thread *)SX_OWNER(lock->base.sx.sx_lock) == curthread)
+ return (-EALREADY);
+ else
+ return (linux_ww_mutex_lock_sub(lock, ctx, 0));
+}
+
+static inline int
+ww_mutex_lock_interruptible(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)
+{
+ if (MUTEX_SKIP())
+ return (0);
+ else if ((struct thread *)SX_OWNER(lock->base.sx.sx_lock) == curthread)
+ return (-EALREADY);
+ else
+ return (linux_ww_mutex_lock_sub(lock, ctx, 1));
+}
+
+extern void linux_ww_mutex_unlock_sub(struct ww_mutex *);
+
+static inline void
+ww_mutex_unlock(struct ww_mutex *lock)
+{
+ if (MUTEX_SKIP())
+ return;
+ else
+ linux_ww_mutex_unlock_sub(lock);
+}
+
+static inline void
+ww_mutex_destroy(struct ww_mutex *lock)
+{
+ cv_destroy(&lock->condvar);
+ mutex_destroy(&lock->base);
+}
+
+static inline void
+ww_acquire_init(struct ww_acquire_ctx *ctx, struct ww_class *ww_class)
+{
+}
+
+static inline void
+ww_mutex_init(struct ww_mutex *lock, struct ww_class *ww_class)
+{
+ linux_mutex_init(&lock->base, ww_class->mutex_name, SX_NOWITNESS);
+ cv_init(&lock->condvar, "lkpi-ww");
+}
+
+static inline void
+ww_acquire_fini(struct ww_acquire_ctx *ctx)
+{
+}
+
+static inline void
+ww_acquire_done(struct ww_acquire_ctx *ctx)
+{
+}
+
+#endif /* _LINUX_WW_MUTEX_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/xarray.h b/sys/compat/linuxkpi/common/include/linux/xarray.h
new file mode 100644
index 000000000000..afe66c1f2b5f
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/xarray.h
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 2020 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_XARRAY_H_
+#define _LINUX_XARRAY_H_
+
+#include <linux/gfp.h>
+#include <linux/radix-tree.h>
+#include <linux/err.h>
+
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#define XA_LIMIT(min, max) \
+ ({ CTASSERT((min) == 0); (uint32_t)(max); })
+
+#define XA_FLAGS_ALLOC (1U << 0)
+#define XA_FLAGS_LOCK_IRQ (1U << 1)
+
+#define XA_ERROR(x) \
+ ERR_PTR(x)
+
+#define xa_limit_32b XA_LIMIT(0, 0xFFFFFFFF)
+
+#define XA_ASSERT_LOCKED(xa) mtx_assert(&(xa)->mtx, MA_OWNED)
+#define xa_lock(xa) mtx_lock(&(xa)->mtx)
+#define xa_unlock(xa) mtx_unlock(&(xa)->mtx)
+
+struct xarray {
+ struct radix_tree_root root;
+ struct mtx mtx; /* internal mutex */
+};
+
+/*
+ * Extensible arrays API implemented as a wrapper
+ * around the radix tree implementation.
+ */
+void *xa_erase(struct xarray *, uint32_t);
+void *xa_load(struct xarray *, uint32_t);
+int xa_alloc(struct xarray *, uint32_t *, void *, uint32_t, gfp_t);
+int xa_alloc_cyclic(struct xarray *, uint32_t *, void *, uint32_t, uint32_t *, gfp_t);
+int xa_insert(struct xarray *, uint32_t, void *, gfp_t);
+void *xa_store(struct xarray *, uint32_t, void *, gfp_t);
+void xa_init_flags(struct xarray *, uint32_t);
+bool xa_empty(struct xarray *);
+void xa_destroy(struct xarray *);
+void *xa_next(struct xarray *, unsigned long *, bool);
+
+#define xa_for_each(xa, index, entry) \
+ for ((entry) = NULL, (index) = 0; \
+ ((entry) = xa_next(xa, &index, (entry) != NULL)) != NULL; )
+
+/*
+ * Unlocked version of functions above.
+ */
+void *__xa_erase(struct xarray *, uint32_t);
+int __xa_alloc(struct xarray *, uint32_t *, void *, uint32_t, gfp_t);
+int __xa_alloc_cyclic(struct xarray *, uint32_t *, void *, uint32_t, uint32_t *, gfp_t);
+int __xa_insert(struct xarray *, uint32_t, void *, gfp_t);
+void *__xa_store(struct xarray *, uint32_t, void *, gfp_t);
+bool __xa_empty(struct xarray *);
+void *__xa_next(struct xarray *, unsigned long *, bool);
+
+static inline int
+xa_err(void *ptr)
+{
+ return (PTR_ERR_OR_ZERO(ptr));
+}
+
+static inline void
+xa_init(struct xarray *xa)
+{
+ xa_init_flags(xa, 0);
+}
+
+#endif /* _LINUX_XARRAY_H_ */
diff --git a/sys/compat/linuxkpi/common/include/net/if_inet6.h b/sys/compat/linuxkpi/common/include/net/if_inet6.h
new file mode 100644
index 000000000000..bb4df2615186
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/net/if_inet6.h
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _NET_IF_INET6_H_
+#define _NET_IF_INET6_H_
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include <asm/types.h>
+
+static inline void ipv6_eth_mc_map(const struct in6_addr *addr, char *buf)
+{
+/*
+ * +-------+-------+-------+-------+-------+-------+
+ * | 33 | 33 | DST13 | DST14 | DST15 | DST16 |
+ * +-------+-------+-------+-------+-------+-------+
+ */
+
+ buf[0]= 0x33;
+ buf[1]= 0x33;
+
+ memcpy(buf + 2, &addr->s6_addr32[3], sizeof(__u32));
+}
+
+#endif /* _NET_IF_INET6_H_ */
diff --git a/sys/compat/linuxkpi/common/include/net/ip.h b/sys/compat/linuxkpi/common/include/net/ip.h
new file mode 100644
index 000000000000..1cfc568db323
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/net/ip.h
@@ -0,0 +1,103 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_NET_IP_H_
+#define _LINUX_NET_IP_H_
+
+#include "opt_inet.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <net/if_types.h>
+#include <net/if.h>
+#include <net/if_var.h>
+
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+
+static inline void
+inet_get_local_port_range(struct vnet *vnet, int *low, int *high)
+{
+#ifdef INET
+ CURVNET_SET_QUIET(vnet);
+ *low = V_ipport_firstauto;
+ *high = V_ipport_lastauto;
+ CURVNET_RESTORE();
+#else
+ *low = IPPORT_EPHEMERALFIRST; /* 10000 */
+ *high = IPPORT_EPHEMERALLAST; /* 65535 */
+#endif
+}
+
+static inline void
+ip_eth_mc_map(uint32_t addr, char *buf)
+{
+
+ addr = ntohl(addr);
+
+ buf[0] = 0x01;
+ buf[1] = 0x00;
+ buf[2] = 0x5e;
+ buf[3] = (addr >> 16) & 0x7f;
+ buf[4] = (addr >> 8) & 0xff;
+ buf[5] = (addr & 0xff);
+}
+
+static inline void
+ip_ib_mc_map(uint32_t addr, const unsigned char *bcast, char *buf)
+{
+ unsigned char scope;
+
+ addr = ntohl(addr);
+ scope = bcast[5] & 0xF;
+ buf[0] = 0;
+ buf[1] = 0xff;
+ buf[2] = 0xff;
+ buf[3] = 0xff;
+ buf[4] = 0xff;
+ buf[5] = 0x10 | scope;
+ buf[6] = 0x40;
+ buf[7] = 0x1b;
+ buf[8] = bcast[8];
+ buf[9] = bcast[9];
+ buf[10] = 0;
+ buf[11] = 0;
+ buf[12] = 0;
+ buf[13] = 0;
+ buf[14] = 0;
+ buf[15] = 0;
+ buf[16] = (addr >> 24) & 0xff;
+ buf[17] = (addr >> 16) & 0xff;
+ buf[18] = (addr >> 8) & 0xff;
+ buf[19] = addr & 0xff;
+}
+
+#endif /* _LINUX_NET_IP_H_ */
diff --git a/sys/compat/linuxkpi/common/include/net/ipv6.h b/sys/compat/linuxkpi/common/include/net/ipv6.h
new file mode 100644
index 000000000000..3eb6051035af
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/net/ipv6.h
@@ -0,0 +1,113 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_NET_IPV6_H_
+#define _LINUX_NET_IPV6_H_
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <linux/types.h>
+
+#define IPV6_DEFAULT_HOPLIMIT 64
+
+#define ipv6_addr_loopback(addr) IN6_IS_ADDR_LOOPBACK(addr)
+#define ipv6_addr_any(addr) IN6_IS_ADDR_UNSPECIFIED(addr)
+
+#define ipv6_addr_copy(dst, src) \
+ memcpy((dst), (src), sizeof(struct in6_addr))
+
+static inline void
+ipv6_ib_mc_map(const struct in6_addr *addr, const unsigned char *broadcast,
+ char *buf)
+{
+ unsigned char scope;
+
+ scope = broadcast[5] & 0xF;
+ buf[0] = 0;
+ buf[1] = 0xff;
+ buf[2] = 0xff;
+ buf[3] = 0xff;
+ buf[4] = 0xff;
+ buf[5] = 0x10 | scope;
+ buf[6] = 0x60;
+ buf[7] = 0x1b;
+ buf[8] = broadcast[8];
+ buf[9] = broadcast[9];
+ memcpy(&buf[10], &addr->s6_addr[6], 10);
+}
+
+static inline void __ipv6_addr_set_half(__be32 *addr, __be32 wh, __be32 wl)
+{
+#if BITS_PER_LONG == 64
+#if defined(__BIG_ENDIAN)
+ if (__builtin_constant_p(wh) && __builtin_constant_p(wl)) {
+ *(__force u64 *)addr = ((__force u64)(wh) << 32 | (__force u64)(wl));
+ return;
+ }
+#elif defined(__LITTLE_ENDIAN)
+ if (__builtin_constant_p(wl) && __builtin_constant_p(wh)) {
+ *(__force u64 *)addr = ((__force u64)(wl) << 32 | (__force u64)(wh));
+ return;
+ }
+#endif
+#endif
+ addr[0] = wh;
+ addr[1] = wl;
+}
+
+static inline void ipv6_addr_set(struct in6_addr *addr,
+ __be32 w1, __be32 w2,
+ __be32 w3, __be32 w4)
+{
+ __ipv6_addr_set_half(&addr->s6_addr32[0], w1, w2);
+ __ipv6_addr_set_half(&addr->s6_addr32[2], w3, w4);
+}
+
+static inline void ipv6_addr_set_v4mapped(const __be32 addr,
+ struct in6_addr *v4mapped)
+{
+ ipv6_addr_set(v4mapped,
+ 0, 0,
+ htonl(0x0000FFFF),
+ addr);
+}
+
+static inline int ipv6_addr_v4mapped(const struct in6_addr *a)
+{
+ return ((a->s6_addr32[0] | a->s6_addr32[1] |
+ (a->s6_addr32[2] ^ htonl(0x0000ffff))) == 0);
+}
+
+static inline int ipv6_addr_cmp(const struct in6_addr *a1, const struct in6_addr *a2)
+{
+ return memcmp(a1, a2, sizeof(struct in6_addr));
+}
+
+#endif /* _LINUX_NET_IPV6_H_ */
diff --git a/sys/compat/linuxkpi/common/include/net/netevent.h b/sys/compat/linuxkpi/common/include/net/netevent.h
new file mode 100644
index 000000000000..3c6fba2f28d6
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/net/netevent.h
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_NET_NETEVENT_H_
+#define _LINUX_NET_NETEVENT_H_
+
+#include <sys/types.h>
+#include <sys/eventhandler.h>
+
+#include <linux/notifier.h>
+
+enum netevent_notif_type {
+ NETEVENT_NEIGH_UPDATE = 0,
+#if 0 /* Unsupported events. */
+ NETEVENT_PMTU_UPDATE,
+ NETEVENT_REDIRECT,
+#endif
+};
+
+struct llentry;
+
+static inline void
+_handle_arp_update_event(void *arg, struct llentry *lle, int evt __unused)
+{
+ struct notifier_block *nb;
+
+ nb = arg;
+ nb->notifier_call(nb, NETEVENT_NEIGH_UPDATE, lle);
+}
+
+static inline int
+register_netevent_notifier(struct notifier_block *nb)
+{
+ nb->tags[NETEVENT_NEIGH_UPDATE] = EVENTHANDLER_REGISTER(
+ lle_event, _handle_arp_update_event, nb, 0);
+ return (0);
+}
+
+static inline int
+unregister_netevent_notifier(struct notifier_block *nb)
+{
+
+ EVENTHANDLER_DEREGISTER(lle_event, nb->tags[NETEVENT_NEIGH_UPDATE]);
+
+ return (0);
+}
+
+#endif /* _LINUX_NET_NETEVENT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/net/tcp.h b/sys/compat/linuxkpi/common/include/net/tcp.h
new file mode 100644
index 000000000000..3f156196aaaf
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/net/tcp.h
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LINUX_NET_TCP_H_
+#define _LINUX_NET_TCP_H_
+
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/kref.h>
+
+#include <net/ip.h>
+
+#endif /* _LINUX_NET_TCP_H_ */
diff --git a/sys/compat/linuxkpi/common/src/linux_acpi.c b/sys/compat/linuxkpi/common/src/linux_acpi.c
new file mode 100644
index 000000000000..5eb60941abac
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_acpi.c
@@ -0,0 +1,243 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2018 Johannes Lundberg <johalun@FreeBSD.org>
+ * Copyright (c) 2020 Vladimir Kondratyev <wulf@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "opt_acpi.h"
+
+#include <sys/types.h>
+#include <sys/bus.h>
+#include <sys/eventhandler.h>
+#include <sys/kernel.h>
+
+#include <contrib/dev/acpica/include/acpi.h>
+#include <dev/acpica/acpivar.h>
+
+#include <linux/notifier.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/video.h>
+
+#define ACPI_AC_CLASS "ac_adapter"
+
+ACPI_MODULE_NAME("linux_acpi")
+
+enum {
+ LINUX_ACPI_ACAD,
+ LINUX_ACPI_VIDEO,
+ LINUX_ACPI_TAGS /* must be last */
+};
+_Static_assert(LINUX_ACPI_TAGS <= LINUX_NOTIFY_TAGS,
+ "Not enough space for tags in notifier_block structure");
+
+#ifdef DEV_ACPI
+
+static uint32_t linux_acpi_target_sleep_state = ACPI_STATE_S0;
+
+static eventhandler_tag resume_tag;
+static eventhandler_tag suspend_tag;
+
+ACPI_HANDLE
+bsd_acpi_get_handle(device_t bsddev)
+{
+ return (acpi_get_handle(bsddev));
+}
+
+bool
+acpi_check_dsm(ACPI_HANDLE handle, const char *uuid, int rev, uint64_t funcs)
+{
+
+ if (funcs == 0)
+ return (false);
+
+ /*
+ * From ACPI 6.3 spec 9.1.1:
+ * Bit 0 indicates whether there is support for any functions other
+ * than function 0 for the specified UUID and Revision ID. If set to
+ * zero, no functions are supported (other than function zero) for the
+ * specified UUID and Revision ID.
+ */
+ funcs |= 1 << 0;
+
+ return ((acpi_DSMQuery(handle, uuid, rev) & funcs) == funcs);
+}
+
+ACPI_OBJECT *
+acpi_evaluate_dsm_typed(ACPI_HANDLE handle, const char *uuid, int rev,
+ int func, ACPI_OBJECT *argv4, ACPI_OBJECT_TYPE type)
+{
+ ACPI_BUFFER buf;
+
+ return (ACPI_SUCCESS(acpi_EvaluateDSMTyped(handle, uuid, rev, func,
+ argv4, &buf, type)) ? (ACPI_OBJECT *)buf.Pointer : NULL);
+}
+
+static void
+linux_handle_power_suspend_event(void *arg __unused)
+{
+ /*
+ * Only support S3 for now.
+ * acpi_sleep_event isn't always called so we use power_suspend_early
+ * instead which means we don't know what state we're switching to.
+ * TODO: Make acpi_sleep_event consistent
+ */
+ linux_acpi_target_sleep_state = ACPI_STATE_S3;
+}
+
+static void
+linux_handle_power_resume_event(void *arg __unused)
+{
+ linux_acpi_target_sleep_state = ACPI_STATE_S0;
+}
+
+static void
+linux_handle_acpi_acad_event(void *arg, int data)
+{
+ struct notifier_block *nb = arg;
+ /*
+ * Event type information is lost ATM in FreeBSD ACPI event handler.
+ * Fortunately, drm-kmod do not distinct AC event types too, so we can
+ * use any type e.g. ACPI_NOTIFY_BUS_CHECK that suits notifier handler.
+ */
+ struct acpi_bus_event abe = {
+ .device_class = ACPI_AC_CLASS,
+ .type = ACPI_NOTIFY_BUS_CHECK,
+ .data = data,
+ };
+
+ nb->notifier_call(nb, 0, &abe);
+}
+
+static void
+linux_handle_acpi_video_event(void *arg, int type)
+{
+ struct notifier_block *nb = arg;
+ struct acpi_bus_event abe = {
+ .device_class = ACPI_VIDEO_CLASS,
+ .type = type,
+ .data = 0,
+ };
+
+ nb->notifier_call(nb, 0, &abe);
+}
+
+int
+register_acpi_notifier(struct notifier_block *nb)
+{
+ nb->tags[LINUX_ACPI_ACAD] = EVENTHANDLER_REGISTER(acpi_acad_event,
+ linux_handle_acpi_acad_event, nb, EVENTHANDLER_PRI_FIRST);
+ nb->tags[LINUX_ACPI_VIDEO] = EVENTHANDLER_REGISTER(acpi_video_event,
+ linux_handle_acpi_video_event, nb, EVENTHANDLER_PRI_FIRST);
+
+ return (0);
+}
+
+int
+unregister_acpi_notifier(struct notifier_block *nb)
+{
+ EVENTHANDLER_DEREGISTER(acpi_acad_event, nb->tags[LINUX_ACPI_ACAD]);
+ EVENTHANDLER_DEREGISTER(acpi_video_event, nb->tags[LINUX_ACPI_VIDEO]);
+
+ return (0);
+}
+
+uint32_t
+acpi_target_system_state(void)
+{
+ return (linux_acpi_target_sleep_state);
+}
+
+static void
+linux_register_acpi_event_handlers(void *arg __unused)
+{
+ /*
+ * XXX johalun: acpi_{sleep,wakeup}_event can't be trusted, use
+ * power_{suspend_early,resume} 'acpiconf -s 3' or 'zzz' will not
+ * generate acpi_sleep_event... Lid open or wake on button generates
+ * acpi_wakeup_event on one of my Dell laptops but not the other
+ * (but it does power on)... is this a general thing?
+ */
+ resume_tag = EVENTHANDLER_REGISTER(power_resume,
+ linux_handle_power_resume_event, NULL, EVENTHANDLER_PRI_FIRST);
+ suspend_tag = EVENTHANDLER_REGISTER(power_suspend_early,
+ linux_handle_power_suspend_event, NULL, EVENTHANDLER_PRI_FIRST);
+}
+
+static void
+linux_deregister_acpi_event_handlers(void *arg __unused)
+{
+ EVENTHANDLER_DEREGISTER(power_resume, resume_tag);
+ EVENTHANDLER_DEREGISTER(power_suspend_early, suspend_tag);
+}
+
+SYSINIT(linux_acpi_events, SI_SUB_DRIVERS, SI_ORDER_ANY,
+ linux_register_acpi_event_handlers, NULL);
+SYSUNINIT(linux_acpi_events, SI_SUB_DRIVERS, SI_ORDER_ANY,
+ linux_deregister_acpi_event_handlers, NULL);
+
+#else /* !DEV_ACPI */
+
+ACPI_HANDLE
+bsd_acpi_get_handle(device_t bsddev)
+{
+ return (NULL);
+}
+
+bool
+acpi_check_dsm(ACPI_HANDLE handle, const char *uuid, int rev, uint64_t funcs)
+{
+ return (false);
+}
+
+ACPI_OBJECT *
+acpi_evaluate_dsm_typed(ACPI_HANDLE handle, const char *uuid, int rev,
+ int func, ACPI_OBJECT *argv4, ACPI_OBJECT_TYPE type)
+{
+ return (NULL);
+}
+
+int
+register_acpi_notifier(struct notifier_block *nb)
+{
+ return (0);
+}
+
+int
+unregister_acpi_notifier(struct notifier_block *nb)
+{
+ return (0);
+}
+
+uint32_t
+acpi_target_system_state(void)
+{
+ return (ACPI_STATE_S0);
+}
+
+#endif /* !DEV_ACPI */
diff --git a/sys/compat/linuxkpi/common/src/linux_compat.c b/sys/compat/linuxkpi/common/src/linux_compat.c
new file mode 100644
index 000000000000..2ad936311204
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_compat.c
@@ -0,0 +1,2566 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2018 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_stack.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+#include <sys/proc.h>
+#include <sys/sglist.h>
+#include <sys/sleepqueue.h>
+#include <sys/refcount.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/bus.h>
+#include <sys/eventhandler.h>
+#include <sys/fcntl.h>
+#include <sys/file.h>
+#include <sys/filio.h>
+#include <sys/rwlock.h>
+#include <sys/mman.h>
+#include <sys/stack.h>
+#include <sys/user.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+
+#include <machine/stdarg.h>
+
+#if defined(__i386__) || defined(__amd64__)
+#include <machine/md_var.h>
+#endif
+
+#include <linux/kobject.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/cdev.h>
+#include <linux/file.h>
+#include <linux/sysfs.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+#include <linux/vmalloc.h>
+#include <linux/netdevice.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/uaccess.h>
+#include <linux/list.h>
+#include <linux/kthread.h>
+#include <linux/kernel.h>
+#include <linux/compat.h>
+#include <linux/poll.h>
+#include <linux/smp.h>
+#include <linux/wait_bit.h>
+
+#if defined(__i386__) || defined(__amd64__)
+#include <asm/smp.h>
+#endif
+
+SYSCTL_NODE(_compat, OID_AUTO, linuxkpi, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
+ "LinuxKPI parameters");
+
+int linuxkpi_debug;
+SYSCTL_INT(_compat_linuxkpi, OID_AUTO, debug, CTLFLAG_RWTUN,
+ &linuxkpi_debug, 0, "Set to enable pr_debug() prints. Clear to disable.");
+
+MALLOC_DEFINE(M_KMALLOC, "linux", "Linux kmalloc compat");
+
+#include <linux/rbtree.h>
+/* Undo Linux compat changes. */
+#undef RB_ROOT
+#undef file
+#undef cdev
+#define RB_ROOT(head) (head)->rbh_root
+
+static void linux_cdev_deref(struct linux_cdev *ldev);
+static struct vm_area_struct *linux_cdev_handle_find(void *handle);
+
+struct kobject linux_class_root;
+struct device linux_root_device;
+struct class linux_class_misc;
+struct list_head pci_drivers;
+struct list_head pci_devices;
+spinlock_t pci_lock;
+
+unsigned long linux_timer_hz_mask;
+
+wait_queue_head_t linux_bit_waitq;
+wait_queue_head_t linux_var_waitq;
+
+int
+panic_cmp(struct rb_node *one, struct rb_node *two)
+{
+ panic("no cmp");
+}
+
+RB_GENERATE(linux_root, rb_node, __entry, panic_cmp);
+
+int
+kobject_set_name_vargs(struct kobject *kobj, const char *fmt, va_list args)
+{
+ va_list tmp_va;
+ int len;
+ char *old;
+ char *name;
+ char dummy;
+
+ old = kobj->name;
+
+ if (old && fmt == NULL)
+ return (0);
+
+ /* compute length of string */
+ va_copy(tmp_va, args);
+ len = vsnprintf(&dummy, 0, fmt, tmp_va);
+ va_end(tmp_va);
+
+ /* account for zero termination */
+ len++;
+
+ /* check for error */
+ if (len < 1)
+ return (-EINVAL);
+
+ /* allocate memory for string */
+ name = kzalloc(len, GFP_KERNEL);
+ if (name == NULL)
+ return (-ENOMEM);
+ vsnprintf(name, len, fmt, args);
+ kobj->name = name;
+
+ /* free old string */
+ kfree(old);
+
+ /* filter new string */
+ for (; *name != '\0'; name++)
+ if (*name == '/')
+ *name = '!';
+ return (0);
+}
+
+int
+kobject_set_name(struct kobject *kobj, const char *fmt, ...)
+{
+ va_list args;
+ int error;
+
+ va_start(args, fmt);
+ error = kobject_set_name_vargs(kobj, fmt, args);
+ va_end(args);
+
+ return (error);
+}
+
+static int
+kobject_add_complete(struct kobject *kobj, struct kobject *parent)
+{
+ const struct kobj_type *t;
+ int error;
+
+ kobj->parent = parent;
+ error = sysfs_create_dir(kobj);
+ if (error == 0 && kobj->ktype && kobj->ktype->default_attrs) {
+ struct attribute **attr;
+ t = kobj->ktype;
+
+ for (attr = t->default_attrs; *attr != NULL; attr++) {
+ error = sysfs_create_file(kobj, *attr);
+ if (error)
+ break;
+ }
+ if (error)
+ sysfs_remove_dir(kobj);
+ }
+ return (error);
+}
+
+int
+kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...)
+{
+ va_list args;
+ int error;
+
+ va_start(args, fmt);
+ error = kobject_set_name_vargs(kobj, fmt, args);
+ va_end(args);
+ if (error)
+ return (error);
+
+ return kobject_add_complete(kobj, parent);
+}
+
+void
+linux_kobject_release(struct kref *kref)
+{
+ struct kobject *kobj;
+ char *name;
+
+ kobj = container_of(kref, struct kobject, kref);
+ sysfs_remove_dir(kobj);
+ name = kobj->name;
+ if (kobj->ktype && kobj->ktype->release)
+ kobj->ktype->release(kobj);
+ kfree(name);
+}
+
+static void
+linux_kobject_kfree(struct kobject *kobj)
+{
+ kfree(kobj);
+}
+
+static void
+linux_kobject_kfree_name(struct kobject *kobj)
+{
+ if (kobj) {
+ kfree(kobj->name);
+ }
+}
+
+const struct kobj_type linux_kfree_type = {
+ .release = linux_kobject_kfree
+};
+
+static void
+linux_device_release(struct device *dev)
+{
+ pr_debug("linux_device_release: %s\n", dev_name(dev));
+ kfree(dev);
+}
+
+static ssize_t
+linux_class_show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+ struct class_attribute *dattr;
+ ssize_t error;
+
+ dattr = container_of(attr, struct class_attribute, attr);
+ error = -EIO;
+ if (dattr->show)
+ error = dattr->show(container_of(kobj, struct class, kobj),
+ dattr, buf);
+ return (error);
+}
+
+static ssize_t
+linux_class_store(struct kobject *kobj, struct attribute *attr, const char *buf,
+ size_t count)
+{
+ struct class_attribute *dattr;
+ ssize_t error;
+
+ dattr = container_of(attr, struct class_attribute, attr);
+ error = -EIO;
+ if (dattr->store)
+ error = dattr->store(container_of(kobj, struct class, kobj),
+ dattr, buf, count);
+ return (error);
+}
+
+static void
+linux_class_release(struct kobject *kobj)
+{
+ struct class *class;
+
+ class = container_of(kobj, struct class, kobj);
+ if (class->class_release)
+ class->class_release(class);
+}
+
+static const struct sysfs_ops linux_class_sysfs = {
+ .show = linux_class_show,
+ .store = linux_class_store,
+};
+
+const struct kobj_type linux_class_ktype = {
+ .release = linux_class_release,
+ .sysfs_ops = &linux_class_sysfs
+};
+
+static void
+linux_dev_release(struct kobject *kobj)
+{
+ struct device *dev;
+
+ dev = container_of(kobj, struct device, kobj);
+ /* This is the precedence defined by linux. */
+ if (dev->release)
+ dev->release(dev);
+ else if (dev->class && dev->class->dev_release)
+ dev->class->dev_release(dev);
+}
+
+static ssize_t
+linux_dev_show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+ struct device_attribute *dattr;
+ ssize_t error;
+
+ dattr = container_of(attr, struct device_attribute, attr);
+ error = -EIO;
+ if (dattr->show)
+ error = dattr->show(container_of(kobj, struct device, kobj),
+ dattr, buf);
+ return (error);
+}
+
+static ssize_t
+linux_dev_store(struct kobject *kobj, struct attribute *attr, const char *buf,
+ size_t count)
+{
+ struct device_attribute *dattr;
+ ssize_t error;
+
+ dattr = container_of(attr, struct device_attribute, attr);
+ error = -EIO;
+ if (dattr->store)
+ error = dattr->store(container_of(kobj, struct device, kobj),
+ dattr, buf, count);
+ return (error);
+}
+
+static const struct sysfs_ops linux_dev_sysfs = {
+ .show = linux_dev_show,
+ .store = linux_dev_store,
+};
+
+const struct kobj_type linux_dev_ktype = {
+ .release = linux_dev_release,
+ .sysfs_ops = &linux_dev_sysfs
+};
+
+struct device *
+device_create(struct class *class, struct device *parent, dev_t devt,
+ void *drvdata, const char *fmt, ...)
+{
+ struct device *dev;
+ va_list args;
+
+ dev = kzalloc(sizeof(*dev), M_WAITOK);
+ dev->parent = parent;
+ dev->class = class;
+ dev->devt = devt;
+ dev->driver_data = drvdata;
+ dev->release = linux_device_release;
+ va_start(args, fmt);
+ kobject_set_name_vargs(&dev->kobj, fmt, args);
+ va_end(args);
+ device_register(dev);
+
+ return (dev);
+}
+
+int
+kobject_init_and_add(struct kobject *kobj, const struct kobj_type *ktype,
+ struct kobject *parent, const char *fmt, ...)
+{
+ va_list args;
+ int error;
+
+ kobject_init(kobj, ktype);
+ kobj->ktype = ktype;
+ kobj->parent = parent;
+ kobj->name = NULL;
+
+ va_start(args, fmt);
+ error = kobject_set_name_vargs(kobj, fmt, args);
+ va_end(args);
+ if (error)
+ return (error);
+ return kobject_add_complete(kobj, parent);
+}
+
+static void
+linux_kq_lock(void *arg)
+{
+ spinlock_t *s = arg;
+
+ spin_lock(s);
+}
+static void
+linux_kq_unlock(void *arg)
+{
+ spinlock_t *s = arg;
+
+ spin_unlock(s);
+}
+
+static void
+linux_kq_assert_lock(void *arg, int what)
+{
+#ifdef INVARIANTS
+ spinlock_t *s = arg;
+
+ if (what == LA_LOCKED)
+ mtx_assert(&s->m, MA_OWNED);
+ else
+ mtx_assert(&s->m, MA_NOTOWNED);
+#endif
+}
+
+static void
+linux_file_kqfilter_poll(struct linux_file *, int);
+
+struct linux_file *
+linux_file_alloc(void)
+{
+ struct linux_file *filp;
+
+ filp = kzalloc(sizeof(*filp), GFP_KERNEL);
+
+ /* set initial refcount */
+ filp->f_count = 1;
+
+ /* setup fields needed by kqueue support */
+ spin_lock_init(&filp->f_kqlock);
+ knlist_init(&filp->f_selinfo.si_note, &filp->f_kqlock,
+ linux_kq_lock, linux_kq_unlock, linux_kq_assert_lock);
+
+ return (filp);
+}
+
+void
+linux_file_free(struct linux_file *filp)
+{
+ if (filp->_file == NULL) {
+ if (filp->f_shmem != NULL)
+ vm_object_deallocate(filp->f_shmem);
+ kfree(filp);
+ } else {
+ /*
+ * The close method of the character device or file
+ * will free the linux_file structure:
+ */
+ _fdrop(filp->_file, curthread);
+ }
+}
+
+static int
+linux_cdev_pager_fault(vm_object_t vm_obj, vm_ooffset_t offset, int prot,
+ vm_page_t *mres)
+{
+ struct vm_area_struct *vmap;
+
+ vmap = linux_cdev_handle_find(vm_obj->handle);
+
+ MPASS(vmap != NULL);
+ MPASS(vmap->vm_private_data == vm_obj->handle);
+
+ if (likely(vmap->vm_ops != NULL && offset < vmap->vm_len)) {
+ vm_paddr_t paddr = IDX_TO_OFF(vmap->vm_pfn) + offset;
+ vm_page_t page;
+
+ if (((*mres)->flags & PG_FICTITIOUS) != 0) {
+ /*
+ * If the passed in result page is a fake
+ * page, update it with the new physical
+ * address.
+ */
+ page = *mres;
+ vm_page_updatefake(page, paddr, vm_obj->memattr);
+ } else {
+ /*
+ * Replace the passed in "mres" page with our
+ * own fake page and free up the all of the
+ * original pages.
+ */
+ VM_OBJECT_WUNLOCK(vm_obj);
+ page = vm_page_getfake(paddr, vm_obj->memattr);
+ VM_OBJECT_WLOCK(vm_obj);
+
+ vm_page_replace(page, vm_obj, (*mres)->pindex, *mres);
+ *mres = page;
+ }
+ vm_page_valid(page);
+ return (VM_PAGER_OK);
+ }
+ return (VM_PAGER_FAIL);
+}
+
+static int
+linux_cdev_pager_populate(vm_object_t vm_obj, vm_pindex_t pidx, int fault_type,
+ vm_prot_t max_prot, vm_pindex_t *first, vm_pindex_t *last)
+{
+ struct vm_area_struct *vmap;
+ int err;
+
+ /* get VM area structure */
+ vmap = linux_cdev_handle_find(vm_obj->handle);
+ MPASS(vmap != NULL);
+ MPASS(vmap->vm_private_data == vm_obj->handle);
+
+ VM_OBJECT_WUNLOCK(vm_obj);
+
+ linux_set_current(curthread);
+
+ down_write(&vmap->vm_mm->mmap_sem);
+ if (unlikely(vmap->vm_ops == NULL)) {
+ err = VM_FAULT_SIGBUS;
+ } else {
+ struct vm_fault vmf;
+
+ /* fill out VM fault structure */
+ vmf.virtual_address = (void *)(uintptr_t)IDX_TO_OFF(pidx);
+ vmf.flags = (fault_type & VM_PROT_WRITE) ? FAULT_FLAG_WRITE : 0;
+ vmf.pgoff = 0;
+ vmf.page = NULL;
+ vmf.vma = vmap;
+
+ vmap->vm_pfn_count = 0;
+ vmap->vm_pfn_pcount = &vmap->vm_pfn_count;
+ vmap->vm_obj = vm_obj;
+
+ err = vmap->vm_ops->fault(vmap, &vmf);
+
+ while (vmap->vm_pfn_count == 0 && err == VM_FAULT_NOPAGE) {
+ kern_yield(PRI_USER);
+ err = vmap->vm_ops->fault(vmap, &vmf);
+ }
+ }
+
+ /* translate return code */
+ switch (err) {
+ case VM_FAULT_OOM:
+ err = VM_PAGER_AGAIN;
+ break;
+ case VM_FAULT_SIGBUS:
+ err = VM_PAGER_BAD;
+ break;
+ case VM_FAULT_NOPAGE:
+ /*
+ * By contract the fault handler will return having
+ * busied all the pages itself. If pidx is already
+ * found in the object, it will simply xbusy the first
+ * page and return with vm_pfn_count set to 1.
+ */
+ *first = vmap->vm_pfn_first;
+ *last = *first + vmap->vm_pfn_count - 1;
+ err = VM_PAGER_OK;
+ break;
+ default:
+ err = VM_PAGER_ERROR;
+ break;
+ }
+ up_write(&vmap->vm_mm->mmap_sem);
+ VM_OBJECT_WLOCK(vm_obj);
+ return (err);
+}
+
+static struct rwlock linux_vma_lock;
+static TAILQ_HEAD(, vm_area_struct) linux_vma_head =
+ TAILQ_HEAD_INITIALIZER(linux_vma_head);
+
+static void
+linux_cdev_handle_free(struct vm_area_struct *vmap)
+{
+ /* Drop reference on vm_file */
+ if (vmap->vm_file != NULL)
+ fput(vmap->vm_file);
+
+ /* Drop reference on mm_struct */
+ mmput(vmap->vm_mm);
+
+ kfree(vmap);
+}
+
+static void
+linux_cdev_handle_remove(struct vm_area_struct *vmap)
+{
+ rw_wlock(&linux_vma_lock);
+ TAILQ_REMOVE(&linux_vma_head, vmap, vm_entry);
+ rw_wunlock(&linux_vma_lock);
+}
+
+static struct vm_area_struct *
+linux_cdev_handle_find(void *handle)
+{
+ struct vm_area_struct *vmap;
+
+ rw_rlock(&linux_vma_lock);
+ TAILQ_FOREACH(vmap, &linux_vma_head, vm_entry) {
+ if (vmap->vm_private_data == handle)
+ break;
+ }
+ rw_runlock(&linux_vma_lock);
+ return (vmap);
+}
+
+static int
+linux_cdev_pager_ctor(void *handle, vm_ooffset_t size, vm_prot_t prot,
+ vm_ooffset_t foff, struct ucred *cred, u_short *color)
+{
+
+ MPASS(linux_cdev_handle_find(handle) != NULL);
+ *color = 0;
+ return (0);
+}
+
+static void
+linux_cdev_pager_dtor(void *handle)
+{
+ const struct vm_operations_struct *vm_ops;
+ struct vm_area_struct *vmap;
+
+ vmap = linux_cdev_handle_find(handle);
+ MPASS(vmap != NULL);
+
+ /*
+ * Remove handle before calling close operation to prevent
+ * other threads from reusing the handle pointer.
+ */
+ linux_cdev_handle_remove(vmap);
+
+ down_write(&vmap->vm_mm->mmap_sem);
+ vm_ops = vmap->vm_ops;
+ if (likely(vm_ops != NULL))
+ vm_ops->close(vmap);
+ up_write(&vmap->vm_mm->mmap_sem);
+
+ linux_cdev_handle_free(vmap);
+}
+
+static struct cdev_pager_ops linux_cdev_pager_ops[2] = {
+ {
+ /* OBJT_MGTDEVICE */
+ .cdev_pg_populate = linux_cdev_pager_populate,
+ .cdev_pg_ctor = linux_cdev_pager_ctor,
+ .cdev_pg_dtor = linux_cdev_pager_dtor
+ },
+ {
+ /* OBJT_DEVICE */
+ .cdev_pg_fault = linux_cdev_pager_fault,
+ .cdev_pg_ctor = linux_cdev_pager_ctor,
+ .cdev_pg_dtor = linux_cdev_pager_dtor
+ },
+};
+
+int
+zap_vma_ptes(struct vm_area_struct *vma, unsigned long address,
+ unsigned long size)
+{
+ vm_object_t obj;
+ vm_page_t m;
+
+ obj = vma->vm_obj;
+ if (obj == NULL || (obj->flags & OBJ_UNMANAGED) != 0)
+ return (-ENOTSUP);
+ VM_OBJECT_RLOCK(obj);
+ for (m = vm_page_find_least(obj, OFF_TO_IDX(address));
+ m != NULL && m->pindex < OFF_TO_IDX(address + size);
+ m = TAILQ_NEXT(m, listq))
+ pmap_remove_all(m);
+ VM_OBJECT_RUNLOCK(obj);
+ return (0);
+}
+
+static struct file_operations dummy_ldev_ops = {
+ /* XXXKIB */
+};
+
+static struct linux_cdev dummy_ldev = {
+ .ops = &dummy_ldev_ops,
+};
+
+#define LDEV_SI_DTR 0x0001
+#define LDEV_SI_REF 0x0002
+
+static void
+linux_get_fop(struct linux_file *filp, const struct file_operations **fop,
+ struct linux_cdev **dev)
+{
+ struct linux_cdev *ldev;
+ u_int siref;
+
+ ldev = filp->f_cdev;
+ *fop = filp->f_op;
+ if (ldev != NULL) {
+ for (siref = ldev->siref;;) {
+ if ((siref & LDEV_SI_DTR) != 0) {
+ ldev = &dummy_ldev;
+ siref = ldev->siref;
+ *fop = ldev->ops;
+ MPASS((ldev->siref & LDEV_SI_DTR) == 0);
+ } else if (atomic_fcmpset_int(&ldev->siref, &siref,
+ siref + LDEV_SI_REF)) {
+ break;
+ }
+ }
+ }
+ *dev = ldev;
+}
+
+static void
+linux_drop_fop(struct linux_cdev *ldev)
+{
+
+ if (ldev == NULL)
+ return;
+ MPASS((ldev->siref & ~LDEV_SI_DTR) != 0);
+ atomic_subtract_int(&ldev->siref, LDEV_SI_REF);
+}
+
+#define OPW(fp,td,code) ({ \
+ struct file *__fpop; \
+ __typeof(code) __retval; \
+ \
+ __fpop = (td)->td_fpop; \
+ (td)->td_fpop = (fp); \
+ __retval = (code); \
+ (td)->td_fpop = __fpop; \
+ __retval; \
+})
+
+static int
+linux_dev_fdopen(struct cdev *dev, int fflags, struct thread *td,
+ struct file *file)
+{
+ struct linux_cdev *ldev;
+ struct linux_file *filp;
+ const struct file_operations *fop;
+ int error;
+
+ ldev = dev->si_drv1;
+
+ filp = linux_file_alloc();
+ filp->f_dentry = &filp->f_dentry_store;
+ filp->f_op = ldev->ops;
+ filp->f_mode = file->f_flag;
+ filp->f_flags = file->f_flag;
+ filp->f_vnode = file->f_vnode;
+ filp->_file = file;
+ refcount_acquire(&ldev->refs);
+ filp->f_cdev = ldev;
+
+ linux_set_current(td);
+ linux_get_fop(filp, &fop, &ldev);
+
+ if (fop->open != NULL) {
+ error = -fop->open(file->f_vnode, filp);
+ if (error != 0) {
+ linux_drop_fop(ldev);
+ linux_cdev_deref(filp->f_cdev);
+ kfree(filp);
+ return (error);
+ }
+ }
+
+ /* hold on to the vnode - used for fstat() */
+ vhold(filp->f_vnode);
+
+ /* release the file from devfs */
+ finit(file, filp->f_mode, DTYPE_DEV, filp, &linuxfileops);
+ linux_drop_fop(ldev);
+ return (ENXIO);
+}
+
+#define LINUX_IOCTL_MIN_PTR 0x10000UL
+#define LINUX_IOCTL_MAX_PTR (LINUX_IOCTL_MIN_PTR + IOCPARM_MAX)
+
+static inline int
+linux_remap_address(void **uaddr, size_t len)
+{
+ uintptr_t uaddr_val = (uintptr_t)(*uaddr);
+
+ if (unlikely(uaddr_val >= LINUX_IOCTL_MIN_PTR &&
+ uaddr_val < LINUX_IOCTL_MAX_PTR)) {
+ struct task_struct *pts = current;
+ if (pts == NULL) {
+ *uaddr = NULL;
+ return (1);
+ }
+
+ /* compute data offset */
+ uaddr_val -= LINUX_IOCTL_MIN_PTR;
+
+ /* check that length is within bounds */
+ if ((len > IOCPARM_MAX) ||
+ (uaddr_val + len) > pts->bsd_ioctl_len) {
+ *uaddr = NULL;
+ return (1);
+ }
+
+ /* re-add kernel buffer address */
+ uaddr_val += (uintptr_t)pts->bsd_ioctl_data;
+
+ /* update address location */
+ *uaddr = (void *)uaddr_val;
+ return (1);
+ }
+ return (0);
+}
+
+int
+linux_copyin(const void *uaddr, void *kaddr, size_t len)
+{
+ if (linux_remap_address(__DECONST(void **, &uaddr), len)) {
+ if (uaddr == NULL)
+ return (-EFAULT);
+ memcpy(kaddr, uaddr, len);
+ return (0);
+ }
+ return (-copyin(uaddr, kaddr, len));
+}
+
+int
+linux_copyout(const void *kaddr, void *uaddr, size_t len)
+{
+ if (linux_remap_address(&uaddr, len)) {
+ if (uaddr == NULL)
+ return (-EFAULT);
+ memcpy(uaddr, kaddr, len);
+ return (0);
+ }
+ return (-copyout(kaddr, uaddr, len));
+}
+
+size_t
+linux_clear_user(void *_uaddr, size_t _len)
+{
+ uint8_t *uaddr = _uaddr;
+ size_t len = _len;
+
+ /* make sure uaddr is aligned before going into the fast loop */
+ while (((uintptr_t)uaddr & 7) != 0 && len > 7) {
+ if (subyte(uaddr, 0))
+ return (_len);
+ uaddr++;
+ len--;
+ }
+
+ /* zero 8 bytes at a time */
+ while (len > 7) {
+#ifdef __LP64__
+ if (suword64(uaddr, 0))
+ return (_len);
+#else
+ if (suword32(uaddr, 0))
+ return (_len);
+ if (suword32(uaddr + 4, 0))
+ return (_len);
+#endif
+ uaddr += 8;
+ len -= 8;
+ }
+
+ /* zero fill end, if any */
+ while (len > 0) {
+ if (subyte(uaddr, 0))
+ return (_len);
+ uaddr++;
+ len--;
+ }
+ return (0);
+}
+
+int
+linux_access_ok(const void *uaddr, size_t len)
+{
+ uintptr_t saddr;
+ uintptr_t eaddr;
+
+ /* get start and end address */
+ saddr = (uintptr_t)uaddr;
+ eaddr = (uintptr_t)uaddr + len;
+
+ /* verify addresses are valid for userspace */
+ return ((saddr == eaddr) ||
+ (eaddr > saddr && eaddr <= VM_MAXUSER_ADDRESS));
+}
+
+/*
+ * This function should return either EINTR or ERESTART depending on
+ * the signal type sent to this thread:
+ */
+static int
+linux_get_error(struct task_struct *task, int error)
+{
+ /* check for signal type interrupt code */
+ if (error == EINTR || error == ERESTARTSYS || error == ERESTART) {
+ error = -linux_schedule_get_interrupt_value(task);
+ if (error == 0)
+ error = EINTR;
+ }
+ return (error);
+}
+
+static int
+linux_file_ioctl_sub(struct file *fp, struct linux_file *filp,
+ const struct file_operations *fop, u_long cmd, caddr_t data,
+ struct thread *td)
+{
+ struct task_struct *task = current;
+ unsigned size;
+ int error;
+
+ size = IOCPARM_LEN(cmd);
+ /* refer to logic in sys_ioctl() */
+ if (size > 0) {
+ /*
+ * Setup hint for linux_copyin() and linux_copyout().
+ *
+ * Background: Linux code expects a user-space address
+ * while FreeBSD supplies a kernel-space address.
+ */
+ task->bsd_ioctl_data = data;
+ task->bsd_ioctl_len = size;
+ data = (void *)LINUX_IOCTL_MIN_PTR;
+ } else {
+ /* fetch user-space pointer */
+ data = *(void **)data;
+ }
+#if defined(__amd64__)
+ if (td->td_proc->p_elf_machine == EM_386) {
+ /* try the compat IOCTL handler first */
+ if (fop->compat_ioctl != NULL) {
+ error = -OPW(fp, td, fop->compat_ioctl(filp,
+ cmd, (u_long)data));
+ } else {
+ error = ENOTTY;
+ }
+
+ /* fallback to the regular IOCTL handler, if any */
+ if (error == ENOTTY && fop->unlocked_ioctl != NULL) {
+ error = -OPW(fp, td, fop->unlocked_ioctl(filp,
+ cmd, (u_long)data));
+ }
+ } else
+#endif
+ {
+ if (fop->unlocked_ioctl != NULL) {
+ error = -OPW(fp, td, fop->unlocked_ioctl(filp,
+ cmd, (u_long)data));
+ } else {
+ error = ENOTTY;
+ }
+ }
+ if (size > 0) {
+ task->bsd_ioctl_data = NULL;
+ task->bsd_ioctl_len = 0;
+ }
+
+ if (error == EWOULDBLOCK) {
+ /* update kqfilter status, if any */
+ linux_file_kqfilter_poll(filp,
+ LINUX_KQ_FLAG_HAS_READ | LINUX_KQ_FLAG_HAS_WRITE);
+ } else {
+ error = linux_get_error(task, error);
+ }
+ return (error);
+}
+
+#define LINUX_POLL_TABLE_NORMAL ((poll_table *)1)
+
+/*
+ * This function atomically updates the poll wakeup state and returns
+ * the previous state at the time of update.
+ */
+static uint8_t
+linux_poll_wakeup_state(atomic_t *v, const uint8_t *pstate)
+{
+ int c, old;
+
+ c = v->counter;
+
+ while ((old = atomic_cmpxchg(v, c, pstate[c])) != c)
+ c = old;
+
+ return (c);
+}
+
+static int
+linux_poll_wakeup_callback(wait_queue_t *wq, unsigned int wq_state, int flags, void *key)
+{
+ static const uint8_t state[LINUX_FWQ_STATE_MAX] = {
+ [LINUX_FWQ_STATE_INIT] = LINUX_FWQ_STATE_INIT, /* NOP */
+ [LINUX_FWQ_STATE_NOT_READY] = LINUX_FWQ_STATE_NOT_READY, /* NOP */
+ [LINUX_FWQ_STATE_QUEUED] = LINUX_FWQ_STATE_READY,
+ [LINUX_FWQ_STATE_READY] = LINUX_FWQ_STATE_READY, /* NOP */
+ };
+ struct linux_file *filp = container_of(wq, struct linux_file, f_wait_queue.wq);
+
+ switch (linux_poll_wakeup_state(&filp->f_wait_queue.state, state)) {
+ case LINUX_FWQ_STATE_QUEUED:
+ linux_poll_wakeup(filp);
+ return (1);
+ default:
+ return (0);
+ }
+}
+
+void
+linux_poll_wait(struct linux_file *filp, wait_queue_head_t *wqh, poll_table *p)
+{
+ static const uint8_t state[LINUX_FWQ_STATE_MAX] = {
+ [LINUX_FWQ_STATE_INIT] = LINUX_FWQ_STATE_NOT_READY,
+ [LINUX_FWQ_STATE_NOT_READY] = LINUX_FWQ_STATE_NOT_READY, /* NOP */
+ [LINUX_FWQ_STATE_QUEUED] = LINUX_FWQ_STATE_QUEUED, /* NOP */
+ [LINUX_FWQ_STATE_READY] = LINUX_FWQ_STATE_QUEUED,
+ };
+
+ /* check if we are called inside the select system call */
+ if (p == LINUX_POLL_TABLE_NORMAL)
+ selrecord(curthread, &filp->f_selinfo);
+
+ switch (linux_poll_wakeup_state(&filp->f_wait_queue.state, state)) {
+ case LINUX_FWQ_STATE_INIT:
+ /* NOTE: file handles can only belong to one wait-queue */
+ filp->f_wait_queue.wqh = wqh;
+ filp->f_wait_queue.wq.func = &linux_poll_wakeup_callback;
+ add_wait_queue(wqh, &filp->f_wait_queue.wq);
+ atomic_set(&filp->f_wait_queue.state, LINUX_FWQ_STATE_QUEUED);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+linux_poll_wait_dequeue(struct linux_file *filp)
+{
+ static const uint8_t state[LINUX_FWQ_STATE_MAX] = {
+ [LINUX_FWQ_STATE_INIT] = LINUX_FWQ_STATE_INIT, /* NOP */
+ [LINUX_FWQ_STATE_NOT_READY] = LINUX_FWQ_STATE_INIT,
+ [LINUX_FWQ_STATE_QUEUED] = LINUX_FWQ_STATE_INIT,
+ [LINUX_FWQ_STATE_READY] = LINUX_FWQ_STATE_INIT,
+ };
+
+ seldrain(&filp->f_selinfo);
+
+ switch (linux_poll_wakeup_state(&filp->f_wait_queue.state, state)) {
+ case LINUX_FWQ_STATE_NOT_READY:
+ case LINUX_FWQ_STATE_QUEUED:
+ case LINUX_FWQ_STATE_READY:
+ remove_wait_queue(filp->f_wait_queue.wqh, &filp->f_wait_queue.wq);
+ break;
+ default:
+ break;
+ }
+}
+
+void
+linux_poll_wakeup(struct linux_file *filp)
+{
+ /* this function should be NULL-safe */
+ if (filp == NULL)
+ return;
+
+ selwakeup(&filp->f_selinfo);
+
+ spin_lock(&filp->f_kqlock);
+ filp->f_kqflags |= LINUX_KQ_FLAG_NEED_READ |
+ LINUX_KQ_FLAG_NEED_WRITE;
+
+ /* make sure the "knote" gets woken up */
+ KNOTE_LOCKED(&filp->f_selinfo.si_note, 1);
+ spin_unlock(&filp->f_kqlock);
+}
+
+static void
+linux_file_kqfilter_detach(struct knote *kn)
+{
+ struct linux_file *filp = kn->kn_hook;
+
+ spin_lock(&filp->f_kqlock);
+ knlist_remove(&filp->f_selinfo.si_note, kn, 1);
+ spin_unlock(&filp->f_kqlock);
+}
+
+static int
+linux_file_kqfilter_read_event(struct knote *kn, long hint)
+{
+ struct linux_file *filp = kn->kn_hook;
+
+ mtx_assert(&filp->f_kqlock.m, MA_OWNED);
+
+ return ((filp->f_kqflags & LINUX_KQ_FLAG_NEED_READ) ? 1 : 0);
+}
+
+static int
+linux_file_kqfilter_write_event(struct knote *kn, long hint)
+{
+ struct linux_file *filp = kn->kn_hook;
+
+ mtx_assert(&filp->f_kqlock.m, MA_OWNED);
+
+ return ((filp->f_kqflags & LINUX_KQ_FLAG_NEED_WRITE) ? 1 : 0);
+}
+
+static struct filterops linux_dev_kqfiltops_read = {
+ .f_isfd = 1,
+ .f_detach = linux_file_kqfilter_detach,
+ .f_event = linux_file_kqfilter_read_event,
+};
+
+static struct filterops linux_dev_kqfiltops_write = {
+ .f_isfd = 1,
+ .f_detach = linux_file_kqfilter_detach,
+ .f_event = linux_file_kqfilter_write_event,
+};
+
+static void
+linux_file_kqfilter_poll(struct linux_file *filp, int kqflags)
+{
+ struct thread *td;
+ const struct file_operations *fop;
+ struct linux_cdev *ldev;
+ int temp;
+
+ if ((filp->f_kqflags & kqflags) == 0)
+ return;
+
+ td = curthread;
+
+ linux_get_fop(filp, &fop, &ldev);
+ /* get the latest polling state */
+ temp = OPW(filp->_file, td, fop->poll(filp, NULL));
+ linux_drop_fop(ldev);
+
+ spin_lock(&filp->f_kqlock);
+ /* clear kqflags */
+ filp->f_kqflags &= ~(LINUX_KQ_FLAG_NEED_READ |
+ LINUX_KQ_FLAG_NEED_WRITE);
+ /* update kqflags */
+ if ((temp & (POLLIN | POLLOUT)) != 0) {
+ if ((temp & POLLIN) != 0)
+ filp->f_kqflags |= LINUX_KQ_FLAG_NEED_READ;
+ if ((temp & POLLOUT) != 0)
+ filp->f_kqflags |= LINUX_KQ_FLAG_NEED_WRITE;
+
+ /* make sure the "knote" gets woken up */
+ KNOTE_LOCKED(&filp->f_selinfo.si_note, 0);
+ }
+ spin_unlock(&filp->f_kqlock);
+}
+
+static int
+linux_file_kqfilter(struct file *file, struct knote *kn)
+{
+ struct linux_file *filp;
+ struct thread *td;
+ int error;
+
+ td = curthread;
+ filp = (struct linux_file *)file->f_data;
+ filp->f_flags = file->f_flag;
+ if (filp->f_op->poll == NULL)
+ return (EINVAL);
+
+ spin_lock(&filp->f_kqlock);
+ switch (kn->kn_filter) {
+ case EVFILT_READ:
+ filp->f_kqflags |= LINUX_KQ_FLAG_HAS_READ;
+ kn->kn_fop = &linux_dev_kqfiltops_read;
+ kn->kn_hook = filp;
+ knlist_add(&filp->f_selinfo.si_note, kn, 1);
+ error = 0;
+ break;
+ case EVFILT_WRITE:
+ filp->f_kqflags |= LINUX_KQ_FLAG_HAS_WRITE;
+ kn->kn_fop = &linux_dev_kqfiltops_write;
+ kn->kn_hook = filp;
+ knlist_add(&filp->f_selinfo.si_note, kn, 1);
+ error = 0;
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ spin_unlock(&filp->f_kqlock);
+
+ if (error == 0) {
+ linux_set_current(td);
+
+ /* update kqfilter status, if any */
+ linux_file_kqfilter_poll(filp,
+ LINUX_KQ_FLAG_HAS_READ | LINUX_KQ_FLAG_HAS_WRITE);
+ }
+ return (error);
+}
+
+static int
+linux_file_mmap_single(struct file *fp, const struct file_operations *fop,
+ vm_ooffset_t *offset, vm_size_t size, struct vm_object **object,
+ int nprot, struct thread *td)
+{
+ struct task_struct *task;
+ struct vm_area_struct *vmap;
+ struct mm_struct *mm;
+ struct linux_file *filp;
+ vm_memattr_t attr;
+ int error;
+
+ filp = (struct linux_file *)fp->f_data;
+ filp->f_flags = fp->f_flag;
+
+ if (fop->mmap == NULL)
+ return (EOPNOTSUPP);
+
+ linux_set_current(td);
+
+ /*
+ * The same VM object might be shared by multiple processes
+ * and the mm_struct is usually freed when a process exits.
+ *
+ * The atomic reference below makes sure the mm_struct is
+ * available as long as the vmap is in the linux_vma_head.
+ */
+ task = current;
+ mm = task->mm;
+ if (atomic_inc_not_zero(&mm->mm_users) == 0)
+ return (EINVAL);
+
+ vmap = kzalloc(sizeof(*vmap), GFP_KERNEL);
+ vmap->vm_start = 0;
+ vmap->vm_end = size;
+ vmap->vm_pgoff = *offset / PAGE_SIZE;
+ vmap->vm_pfn = 0;
+ vmap->vm_flags = vmap->vm_page_prot = (nprot & VM_PROT_ALL);
+ vmap->vm_ops = NULL;
+ vmap->vm_file = get_file(filp);
+ vmap->vm_mm = mm;
+
+ if (unlikely(down_write_killable(&vmap->vm_mm->mmap_sem))) {
+ error = linux_get_error(task, EINTR);
+ } else {
+ error = -OPW(fp, td, fop->mmap(filp, vmap));
+ error = linux_get_error(task, error);
+ up_write(&vmap->vm_mm->mmap_sem);
+ }
+
+ if (error != 0) {
+ linux_cdev_handle_free(vmap);
+ return (error);
+ }
+
+ attr = pgprot2cachemode(vmap->vm_page_prot);
+
+ if (vmap->vm_ops != NULL) {
+ struct vm_area_struct *ptr;
+ void *vm_private_data;
+ bool vm_no_fault;
+
+ if (vmap->vm_ops->open == NULL ||
+ vmap->vm_ops->close == NULL ||
+ vmap->vm_private_data == NULL) {
+ /* free allocated VM area struct */
+ linux_cdev_handle_free(vmap);
+ return (EINVAL);
+ }
+
+ vm_private_data = vmap->vm_private_data;
+
+ rw_wlock(&linux_vma_lock);
+ TAILQ_FOREACH(ptr, &linux_vma_head, vm_entry) {
+ if (ptr->vm_private_data == vm_private_data)
+ break;
+ }
+ /* check if there is an existing VM area struct */
+ if (ptr != NULL) {
+ /* check if the VM area structure is invalid */
+ if (ptr->vm_ops == NULL ||
+ ptr->vm_ops->open == NULL ||
+ ptr->vm_ops->close == NULL) {
+ error = ESTALE;
+ vm_no_fault = 1;
+ } else {
+ error = EEXIST;
+ vm_no_fault = (ptr->vm_ops->fault == NULL);
+ }
+ } else {
+ /* insert VM area structure into list */
+ TAILQ_INSERT_TAIL(&linux_vma_head, vmap, vm_entry);
+ error = 0;
+ vm_no_fault = (vmap->vm_ops->fault == NULL);
+ }
+ rw_wunlock(&linux_vma_lock);
+
+ if (error != 0) {
+ /* free allocated VM area struct */
+ linux_cdev_handle_free(vmap);
+ /* check for stale VM area struct */
+ if (error != EEXIST)
+ return (error);
+ }
+
+ /* check if there is no fault handler */
+ if (vm_no_fault) {
+ *object = cdev_pager_allocate(vm_private_data, OBJT_DEVICE,
+ &linux_cdev_pager_ops[1], size, nprot, *offset,
+ td->td_ucred);
+ } else {
+ *object = cdev_pager_allocate(vm_private_data, OBJT_MGTDEVICE,
+ &linux_cdev_pager_ops[0], size, nprot, *offset,
+ td->td_ucred);
+ }
+
+ /* check if allocating the VM object failed */
+ if (*object == NULL) {
+ if (error == 0) {
+ /* remove VM area struct from list */
+ linux_cdev_handle_remove(vmap);
+ /* free allocated VM area struct */
+ linux_cdev_handle_free(vmap);
+ }
+ return (EINVAL);
+ }
+ } else {
+ struct sglist *sg;
+
+ sg = sglist_alloc(1, M_WAITOK);
+ sglist_append_phys(sg,
+ (vm_paddr_t)vmap->vm_pfn << PAGE_SHIFT, vmap->vm_len);
+
+ *object = vm_pager_allocate(OBJT_SG, sg, vmap->vm_len,
+ nprot, 0, td->td_ucred);
+
+ linux_cdev_handle_free(vmap);
+
+ if (*object == NULL) {
+ sglist_free(sg);
+ return (EINVAL);
+ }
+ }
+
+ if (attr != VM_MEMATTR_DEFAULT) {
+ VM_OBJECT_WLOCK(*object);
+ vm_object_set_memattr(*object, attr);
+ VM_OBJECT_WUNLOCK(*object);
+ }
+ *offset = 0;
+ return (0);
+}
+
+struct cdevsw linuxcdevsw = {
+ .d_version = D_VERSION,
+ .d_fdopen = linux_dev_fdopen,
+ .d_name = "lkpidev",
+};
+
+static int
+linux_file_read(struct file *file, struct uio *uio, struct ucred *active_cred,
+ int flags, struct thread *td)
+{
+ struct linux_file *filp;
+ const struct file_operations *fop;
+ struct linux_cdev *ldev;
+ ssize_t bytes;
+ int error;
+
+ error = 0;
+ filp = (struct linux_file *)file->f_data;
+ filp->f_flags = file->f_flag;
+ /* XXX no support for I/O vectors currently */
+ if (uio->uio_iovcnt != 1)
+ return (EOPNOTSUPP);
+ if (uio->uio_resid > DEVFS_IOSIZE_MAX)
+ return (EINVAL);
+ linux_set_current(td);
+ linux_get_fop(filp, &fop, &ldev);
+ if (fop->read != NULL) {
+ bytes = OPW(file, td, fop->read(filp,
+ uio->uio_iov->iov_base,
+ uio->uio_iov->iov_len, &uio->uio_offset));
+ if (bytes >= 0) {
+ uio->uio_iov->iov_base =
+ ((uint8_t *)uio->uio_iov->iov_base) + bytes;
+ uio->uio_iov->iov_len -= bytes;
+ uio->uio_resid -= bytes;
+ } else {
+ error = linux_get_error(current, -bytes);
+ }
+ } else
+ error = ENXIO;
+
+ /* update kqfilter status, if any */
+ linux_file_kqfilter_poll(filp, LINUX_KQ_FLAG_HAS_READ);
+ linux_drop_fop(ldev);
+
+ return (error);
+}
+
+static int
+linux_file_write(struct file *file, struct uio *uio, struct ucred *active_cred,
+ int flags, struct thread *td)
+{
+ struct linux_file *filp;
+ const struct file_operations *fop;
+ struct linux_cdev *ldev;
+ ssize_t bytes;
+ int error;
+
+ filp = (struct linux_file *)file->f_data;
+ filp->f_flags = file->f_flag;
+ /* XXX no support for I/O vectors currently */
+ if (uio->uio_iovcnt != 1)
+ return (EOPNOTSUPP);
+ if (uio->uio_resid > DEVFS_IOSIZE_MAX)
+ return (EINVAL);
+ linux_set_current(td);
+ linux_get_fop(filp, &fop, &ldev);
+ if (fop->write != NULL) {
+ bytes = OPW(file, td, fop->write(filp,
+ uio->uio_iov->iov_base,
+ uio->uio_iov->iov_len, &uio->uio_offset));
+ if (bytes >= 0) {
+ uio->uio_iov->iov_base =
+ ((uint8_t *)uio->uio_iov->iov_base) + bytes;
+ uio->uio_iov->iov_len -= bytes;
+ uio->uio_resid -= bytes;
+ error = 0;
+ } else {
+ error = linux_get_error(current, -bytes);
+ }
+ } else
+ error = ENXIO;
+
+ /* update kqfilter status, if any */
+ linux_file_kqfilter_poll(filp, LINUX_KQ_FLAG_HAS_WRITE);
+
+ linux_drop_fop(ldev);
+
+ return (error);
+}
+
+static int
+linux_file_poll(struct file *file, int events, struct ucred *active_cred,
+ struct thread *td)
+{
+ struct linux_file *filp;
+ const struct file_operations *fop;
+ struct linux_cdev *ldev;
+ int revents;
+
+ filp = (struct linux_file *)file->f_data;
+ filp->f_flags = file->f_flag;
+ linux_set_current(td);
+ linux_get_fop(filp, &fop, &ldev);
+ if (fop->poll != NULL) {
+ revents = OPW(file, td, fop->poll(filp,
+ LINUX_POLL_TABLE_NORMAL)) & events;
+ } else {
+ revents = 0;
+ }
+ linux_drop_fop(ldev);
+ return (revents);
+}
+
+static int
+linux_file_close(struct file *file, struct thread *td)
+{
+ struct linux_file *filp;
+ int (*release)(struct inode *, struct linux_file *);
+ const struct file_operations *fop;
+ struct linux_cdev *ldev;
+ int error;
+
+ filp = (struct linux_file *)file->f_data;
+
+ KASSERT(file_count(filp) == 0,
+ ("File refcount(%d) is not zero", file_count(filp)));
+
+ if (td == NULL)
+ td = curthread;
+
+ error = 0;
+ filp->f_flags = file->f_flag;
+ linux_set_current(td);
+ linux_poll_wait_dequeue(filp);
+ linux_get_fop(filp, &fop, &ldev);
+ /*
+ * Always use the real release function, if any, to avoid
+ * leaking device resources:
+ */
+ release = filp->f_op->release;
+ if (release != NULL)
+ error = -OPW(file, td, release(filp->f_vnode, filp));
+ funsetown(&filp->f_sigio);
+ if (filp->f_vnode != NULL)
+ vdrop(filp->f_vnode);
+ linux_drop_fop(ldev);
+ if (filp->f_cdev != NULL)
+ linux_cdev_deref(filp->f_cdev);
+ kfree(filp);
+
+ return (error);
+}
+
+static int
+linux_file_ioctl(struct file *fp, u_long cmd, void *data, struct ucred *cred,
+ struct thread *td)
+{
+ struct linux_file *filp;
+ const struct file_operations *fop;
+ struct linux_cdev *ldev;
+ struct fiodgname_arg *fgn;
+ const char *p;
+ int error, i;
+
+ error = 0;
+ filp = (struct linux_file *)fp->f_data;
+ filp->f_flags = fp->f_flag;
+ linux_get_fop(filp, &fop, &ldev);
+
+ linux_set_current(td);
+ switch (cmd) {
+ case FIONBIO:
+ break;
+ case FIOASYNC:
+ if (fop->fasync == NULL)
+ break;
+ error = -OPW(fp, td, fop->fasync(0, filp, fp->f_flag & FASYNC));
+ break;
+ case FIOSETOWN:
+ error = fsetown(*(int *)data, &filp->f_sigio);
+ if (error == 0) {
+ if (fop->fasync == NULL)
+ break;
+ error = -OPW(fp, td, fop->fasync(0, filp,
+ fp->f_flag & FASYNC));
+ }
+ break;
+ case FIOGETOWN:
+ *(int *)data = fgetown(&filp->f_sigio);
+ break;
+ case FIODGNAME:
+#ifdef COMPAT_FREEBSD32
+ case FIODGNAME_32:
+#endif
+ if (filp->f_cdev == NULL || filp->f_cdev->cdev == NULL) {
+ error = ENXIO;
+ break;
+ }
+ fgn = data;
+ p = devtoname(filp->f_cdev->cdev);
+ i = strlen(p) + 1;
+ if (i > fgn->len) {
+ error = EINVAL;
+ break;
+ }
+ error = copyout(p, fiodgname_buf_get_ptr(fgn, cmd), i);
+ break;
+ default:
+ error = linux_file_ioctl_sub(fp, filp, fop, cmd, data, td);
+ break;
+ }
+ linux_drop_fop(ldev);
+ return (error);
+}
+
+static int
+linux_file_mmap_sub(struct thread *td, vm_size_t objsize, vm_prot_t prot,
+ vm_prot_t *maxprotp, int *flagsp, struct file *fp,
+ vm_ooffset_t *foff, const struct file_operations *fop, vm_object_t *objp)
+{
+ /*
+ * Character devices do not provide private mappings
+ * of any kind:
+ */
+ if ((*maxprotp & VM_PROT_WRITE) == 0 &&
+ (prot & VM_PROT_WRITE) != 0)
+ return (EACCES);
+ if ((*flagsp & (MAP_PRIVATE | MAP_COPY)) != 0)
+ return (EINVAL);
+
+ return (linux_file_mmap_single(fp, fop, foff, objsize, objp,
+ (int)prot, td));
+}
+
+static int
+linux_file_mmap(struct file *fp, vm_map_t map, vm_offset_t *addr, vm_size_t size,
+ vm_prot_t prot, vm_prot_t cap_maxprot, int flags, vm_ooffset_t foff,
+ struct thread *td)
+{
+ struct linux_file *filp;
+ const struct file_operations *fop;
+ struct linux_cdev *ldev;
+ struct mount *mp;
+ struct vnode *vp;
+ vm_object_t object;
+ vm_prot_t maxprot;
+ int error;
+
+ filp = (struct linux_file *)fp->f_data;
+
+ vp = filp->f_vnode;
+ if (vp == NULL)
+ return (EOPNOTSUPP);
+
+ /*
+ * Ensure that file and memory protections are
+ * compatible.
+ */
+ mp = vp->v_mount;
+ if (mp != NULL && (mp->mnt_flag & MNT_NOEXEC) != 0) {
+ maxprot = VM_PROT_NONE;
+ if ((prot & VM_PROT_EXECUTE) != 0)
+ return (EACCES);
+ } else
+ maxprot = VM_PROT_EXECUTE;
+ if ((fp->f_flag & FREAD) != 0)
+ maxprot |= VM_PROT_READ;
+ else if ((prot & VM_PROT_READ) != 0)
+ return (EACCES);
+
+ /*
+ * If we are sharing potential changes via MAP_SHARED and we
+ * are trying to get write permission although we opened it
+ * without asking for it, bail out.
+ *
+ * Note that most character devices always share mappings.
+ *
+ * Rely on linux_file_mmap_sub() to fail invalid MAP_PRIVATE
+ * requests rather than doing it here.
+ */
+ if ((flags & MAP_SHARED) != 0) {
+ if ((fp->f_flag & FWRITE) != 0)
+ maxprot |= VM_PROT_WRITE;
+ else if ((prot & VM_PROT_WRITE) != 0)
+ return (EACCES);
+ }
+ maxprot &= cap_maxprot;
+
+ linux_get_fop(filp, &fop, &ldev);
+ error = linux_file_mmap_sub(td, size, prot, &maxprot, &flags, fp,
+ &foff, fop, &object);
+ if (error != 0)
+ goto out;
+
+ error = vm_mmap_object(map, addr, size, prot, maxprot, flags, object,
+ foff, FALSE, td);
+ if (error != 0)
+ vm_object_deallocate(object);
+out:
+ linux_drop_fop(ldev);
+ return (error);
+}
+
+static int
+linux_file_stat(struct file *fp, struct stat *sb, struct ucred *active_cred,
+ struct thread *td)
+{
+ struct linux_file *filp;
+ struct vnode *vp;
+ int error;
+
+ filp = (struct linux_file *)fp->f_data;
+ if (filp->f_vnode == NULL)
+ return (EOPNOTSUPP);
+
+ vp = filp->f_vnode;
+
+ vn_lock(vp, LK_SHARED | LK_RETRY);
+ error = VOP_STAT(vp, sb, td->td_ucred, NOCRED, td);
+ VOP_UNLOCK(vp);
+
+ return (error);
+}
+
+static int
+linux_file_fill_kinfo(struct file *fp, struct kinfo_file *kif,
+ struct filedesc *fdp)
+{
+ struct linux_file *filp;
+ struct vnode *vp;
+ int error;
+
+ filp = fp->f_data;
+ vp = filp->f_vnode;
+ if (vp == NULL) {
+ error = 0;
+ kif->kf_type = KF_TYPE_DEV;
+ } else {
+ vref(vp);
+ FILEDESC_SUNLOCK(fdp);
+ error = vn_fill_kinfo_vnode(vp, kif);
+ vrele(vp);
+ kif->kf_type = KF_TYPE_VNODE;
+ FILEDESC_SLOCK(fdp);
+ }
+ return (error);
+}
+
+unsigned int
+linux_iminor(struct inode *inode)
+{
+ struct linux_cdev *ldev;
+
+ if (inode == NULL || inode->v_rdev == NULL ||
+ inode->v_rdev->si_devsw != &linuxcdevsw)
+ return (-1U);
+ ldev = inode->v_rdev->si_drv1;
+ if (ldev == NULL)
+ return (-1U);
+
+ return (minor(ldev->dev));
+}
+
+struct fileops linuxfileops = {
+ .fo_read = linux_file_read,
+ .fo_write = linux_file_write,
+ .fo_truncate = invfo_truncate,
+ .fo_kqfilter = linux_file_kqfilter,
+ .fo_stat = linux_file_stat,
+ .fo_fill_kinfo = linux_file_fill_kinfo,
+ .fo_poll = linux_file_poll,
+ .fo_close = linux_file_close,
+ .fo_ioctl = linux_file_ioctl,
+ .fo_mmap = linux_file_mmap,
+ .fo_chmod = invfo_chmod,
+ .fo_chown = invfo_chown,
+ .fo_sendfile = invfo_sendfile,
+ .fo_flags = DFLAG_PASSABLE,
+};
+
+/*
+ * Hash of vmmap addresses. This is infrequently accessed and does not
+ * need to be particularly large. This is done because we must store the
+ * caller's idea of the map size to properly unmap.
+ */
+struct vmmap {
+ LIST_ENTRY(vmmap) vm_next;
+ void *vm_addr;
+ unsigned long vm_size;
+};
+
+struct vmmaphd {
+ struct vmmap *lh_first;
+};
+#define VMMAP_HASH_SIZE 64
+#define VMMAP_HASH_MASK (VMMAP_HASH_SIZE - 1)
+#define VM_HASH(addr) ((uintptr_t)(addr) >> PAGE_SHIFT) & VMMAP_HASH_MASK
+static struct vmmaphd vmmaphead[VMMAP_HASH_SIZE];
+static struct mtx vmmaplock;
+
+static void
+vmmap_add(void *addr, unsigned long size)
+{
+ struct vmmap *vmmap;
+
+ vmmap = kmalloc(sizeof(*vmmap), GFP_KERNEL);
+ mtx_lock(&vmmaplock);
+ vmmap->vm_size = size;
+ vmmap->vm_addr = addr;
+ LIST_INSERT_HEAD(&vmmaphead[VM_HASH(addr)], vmmap, vm_next);
+ mtx_unlock(&vmmaplock);
+}
+
+static struct vmmap *
+vmmap_remove(void *addr)
+{
+ struct vmmap *vmmap;
+
+ mtx_lock(&vmmaplock);
+ LIST_FOREACH(vmmap, &vmmaphead[VM_HASH(addr)], vm_next)
+ if (vmmap->vm_addr == addr)
+ break;
+ if (vmmap)
+ LIST_REMOVE(vmmap, vm_next);
+ mtx_unlock(&vmmaplock);
+
+ return (vmmap);
+}
+
+#if defined(__i386__) || defined(__amd64__) || defined(__powerpc__) || defined(__aarch64__)
+void *
+_ioremap_attr(vm_paddr_t phys_addr, unsigned long size, int attr)
+{
+ void *addr;
+
+ addr = pmap_mapdev_attr(phys_addr, size, attr);
+ if (addr == NULL)
+ return (NULL);
+ vmmap_add(addr, size);
+
+ return (addr);
+}
+#endif
+
+void
+iounmap(void *addr)
+{
+ struct vmmap *vmmap;
+
+ vmmap = vmmap_remove(addr);
+ if (vmmap == NULL)
+ return;
+#if defined(__i386__) || defined(__amd64__) || defined(__powerpc__) || defined(__aarch64__)
+ pmap_unmapdev((vm_offset_t)addr, vmmap->vm_size);
+#endif
+ kfree(vmmap);
+}
+
+void *
+vmap(struct page **pages, unsigned int count, unsigned long flags, int prot)
+{
+ vm_offset_t off;
+ size_t size;
+
+ size = count * PAGE_SIZE;
+ off = kva_alloc(size);
+ if (off == 0)
+ return (NULL);
+ vmmap_add((void *)off, size);
+ pmap_qenter(off, pages, count);
+
+ return ((void *)off);
+}
+
+void
+vunmap(void *addr)
+{
+ struct vmmap *vmmap;
+
+ vmmap = vmmap_remove(addr);
+ if (vmmap == NULL)
+ return;
+ pmap_qremove((vm_offset_t)addr, vmmap->vm_size / PAGE_SIZE);
+ kva_free((vm_offset_t)addr, vmmap->vm_size);
+ kfree(vmmap);
+}
+
+static char *
+devm_kvasprintf(struct device *dev, gfp_t gfp, const char *fmt, va_list ap)
+{
+ unsigned int len;
+ char *p;
+ va_list aq;
+
+ va_copy(aq, ap);
+ len = vsnprintf(NULL, 0, fmt, aq);
+ va_end(aq);
+
+ if (dev != NULL)
+ p = devm_kmalloc(dev, len + 1, gfp);
+ else
+ p = kmalloc(len + 1, gfp);
+ if (p != NULL)
+ vsnprintf(p, len + 1, fmt, ap);
+
+ return (p);
+}
+
+char *
+kvasprintf(gfp_t gfp, const char *fmt, va_list ap)
+{
+
+ return (devm_kvasprintf(NULL, gfp, fmt, ap));
+}
+
+char *
+lkpi_devm_kasprintf(struct device *dev, gfp_t gfp, const char *fmt, ...)
+{
+ va_list ap;
+ char *p;
+
+ va_start(ap, fmt);
+ p = devm_kvasprintf(dev, gfp, fmt, ap);
+ va_end(ap);
+
+ return (p);
+}
+
+char *
+kasprintf(gfp_t gfp, const char *fmt, ...)
+{
+ va_list ap;
+ char *p;
+
+ va_start(ap, fmt);
+ p = kvasprintf(gfp, fmt, ap);
+ va_end(ap);
+
+ return (p);
+}
+
+static void
+linux_timer_callback_wrapper(void *context)
+{
+ struct timer_list *timer;
+
+ linux_set_current(curthread);
+
+ timer = context;
+ timer->function(timer->data);
+}
+
+int
+mod_timer(struct timer_list *timer, int expires)
+{
+ int ret;
+
+ timer->expires = expires;
+ ret = callout_reset(&timer->callout,
+ linux_timer_jiffies_until(expires),
+ &linux_timer_callback_wrapper, timer);
+
+ MPASS(ret == 0 || ret == 1);
+
+ return (ret == 1);
+}
+
+void
+add_timer(struct timer_list *timer)
+{
+
+ callout_reset(&timer->callout,
+ linux_timer_jiffies_until(timer->expires),
+ &linux_timer_callback_wrapper, timer);
+}
+
+void
+add_timer_on(struct timer_list *timer, int cpu)
+{
+
+ callout_reset_on(&timer->callout,
+ linux_timer_jiffies_until(timer->expires),
+ &linux_timer_callback_wrapper, timer, cpu);
+}
+
+int
+del_timer(struct timer_list *timer)
+{
+
+ if (callout_stop(&(timer)->callout) == -1)
+ return (0);
+ return (1);
+}
+
+int
+del_timer_sync(struct timer_list *timer)
+{
+
+ if (callout_drain(&(timer)->callout) == -1)
+ return (0);
+ return (1);
+}
+
+/* greatest common divisor, Euclid equation */
+static uint64_t
+lkpi_gcd_64(uint64_t a, uint64_t b)
+{
+ uint64_t an;
+ uint64_t bn;
+
+ while (b != 0) {
+ an = b;
+ bn = a % b;
+ a = an;
+ b = bn;
+ }
+ return (a);
+}
+
+uint64_t lkpi_nsec2hz_rem;
+uint64_t lkpi_nsec2hz_div = 1000000000ULL;
+uint64_t lkpi_nsec2hz_max;
+
+uint64_t lkpi_usec2hz_rem;
+uint64_t lkpi_usec2hz_div = 1000000ULL;
+uint64_t lkpi_usec2hz_max;
+
+uint64_t lkpi_msec2hz_rem;
+uint64_t lkpi_msec2hz_div = 1000ULL;
+uint64_t lkpi_msec2hz_max;
+
+static void
+linux_timer_init(void *arg)
+{
+ uint64_t gcd;
+
+ /*
+ * Compute an internal HZ value which can divide 2**32 to
+ * avoid timer rounding problems when the tick value wraps
+ * around 2**32:
+ */
+ linux_timer_hz_mask = 1;
+ while (linux_timer_hz_mask < (unsigned long)hz)
+ linux_timer_hz_mask *= 2;
+ linux_timer_hz_mask--;
+
+ /* compute some internal constants */
+
+ lkpi_nsec2hz_rem = hz;
+ lkpi_usec2hz_rem = hz;
+ lkpi_msec2hz_rem = hz;
+
+ gcd = lkpi_gcd_64(lkpi_nsec2hz_rem, lkpi_nsec2hz_div);
+ lkpi_nsec2hz_rem /= gcd;
+ lkpi_nsec2hz_div /= gcd;
+ lkpi_nsec2hz_max = -1ULL / lkpi_nsec2hz_rem;
+
+ gcd = lkpi_gcd_64(lkpi_usec2hz_rem, lkpi_usec2hz_div);
+ lkpi_usec2hz_rem /= gcd;
+ lkpi_usec2hz_div /= gcd;
+ lkpi_usec2hz_max = -1ULL / lkpi_usec2hz_rem;
+
+ gcd = lkpi_gcd_64(lkpi_msec2hz_rem, lkpi_msec2hz_div);
+ lkpi_msec2hz_rem /= gcd;
+ lkpi_msec2hz_div /= gcd;
+ lkpi_msec2hz_max = -1ULL / lkpi_msec2hz_rem;
+}
+SYSINIT(linux_timer, SI_SUB_DRIVERS, SI_ORDER_FIRST, linux_timer_init, NULL);
+
+void
+linux_complete_common(struct completion *c, int all)
+{
+ int wakeup_swapper;
+
+ sleepq_lock(c);
+ if (all) {
+ c->done = UINT_MAX;
+ wakeup_swapper = sleepq_broadcast(c, SLEEPQ_SLEEP, 0, 0);
+ } else {
+ if (c->done != UINT_MAX)
+ c->done++;
+ wakeup_swapper = sleepq_signal(c, SLEEPQ_SLEEP, 0, 0);
+ }
+ sleepq_release(c);
+ if (wakeup_swapper)
+ kick_proc0();
+}
+
+/*
+ * Indefinite wait for done != 0 with or without signals.
+ */
+int
+linux_wait_for_common(struct completion *c, int flags)
+{
+ struct task_struct *task;
+ int error;
+
+ if (SCHEDULER_STOPPED())
+ return (0);
+
+ task = current;
+
+ if (flags != 0)
+ flags = SLEEPQ_INTERRUPTIBLE | SLEEPQ_SLEEP;
+ else
+ flags = SLEEPQ_SLEEP;
+ error = 0;
+ for (;;) {
+ sleepq_lock(c);
+ if (c->done)
+ break;
+ sleepq_add(c, NULL, "completion", flags, 0);
+ if (flags & SLEEPQ_INTERRUPTIBLE) {
+ DROP_GIANT();
+ error = -sleepq_wait_sig(c, 0);
+ PICKUP_GIANT();
+ if (error != 0) {
+ linux_schedule_save_interrupt_value(task, error);
+ error = -ERESTARTSYS;
+ goto intr;
+ }
+ } else {
+ DROP_GIANT();
+ sleepq_wait(c, 0);
+ PICKUP_GIANT();
+ }
+ }
+ if (c->done != UINT_MAX)
+ c->done--;
+ sleepq_release(c);
+
+intr:
+ return (error);
+}
+
+/*
+ * Time limited wait for done != 0 with or without signals.
+ */
+int
+linux_wait_for_timeout_common(struct completion *c, int timeout, int flags)
+{
+ struct task_struct *task;
+ int end = jiffies + timeout;
+ int error;
+
+ if (SCHEDULER_STOPPED())
+ return (0);
+
+ task = current;
+
+ if (flags != 0)
+ flags = SLEEPQ_INTERRUPTIBLE | SLEEPQ_SLEEP;
+ else
+ flags = SLEEPQ_SLEEP;
+
+ for (;;) {
+ sleepq_lock(c);
+ if (c->done)
+ break;
+ sleepq_add(c, NULL, "completion", flags, 0);
+ sleepq_set_timeout(c, linux_timer_jiffies_until(end));
+
+ DROP_GIANT();
+ if (flags & SLEEPQ_INTERRUPTIBLE)
+ error = -sleepq_timedwait_sig(c, 0);
+ else
+ error = -sleepq_timedwait(c, 0);
+ PICKUP_GIANT();
+
+ if (error != 0) {
+ /* check for timeout */
+ if (error == -EWOULDBLOCK) {
+ error = 0; /* timeout */
+ } else {
+ /* signal happened */
+ linux_schedule_save_interrupt_value(task, error);
+ error = -ERESTARTSYS;
+ }
+ goto done;
+ }
+ }
+ if (c->done != UINT_MAX)
+ c->done--;
+ sleepq_release(c);
+
+ /* return how many jiffies are left */
+ error = linux_timer_jiffies_until(end);
+done:
+ return (error);
+}
+
+int
+linux_try_wait_for_completion(struct completion *c)
+{
+ int isdone;
+
+ sleepq_lock(c);
+ isdone = (c->done != 0);
+ if (c->done != 0 && c->done != UINT_MAX)
+ c->done--;
+ sleepq_release(c);
+ return (isdone);
+}
+
+int
+linux_completion_done(struct completion *c)
+{
+ int isdone;
+
+ sleepq_lock(c);
+ isdone = (c->done != 0);
+ sleepq_release(c);
+ return (isdone);
+}
+
+static void
+linux_cdev_deref(struct linux_cdev *ldev)
+{
+
+ if (refcount_release(&ldev->refs))
+ kfree(ldev);
+}
+
+static void
+linux_cdev_release(struct kobject *kobj)
+{
+ struct linux_cdev *cdev;
+ struct kobject *parent;
+
+ cdev = container_of(kobj, struct linux_cdev, kobj);
+ parent = kobj->parent;
+ linux_destroy_dev(cdev);
+ linux_cdev_deref(cdev);
+ kobject_put(parent);
+}
+
+static void
+linux_cdev_static_release(struct kobject *kobj)
+{
+ struct linux_cdev *cdev;
+ struct kobject *parent;
+
+ cdev = container_of(kobj, struct linux_cdev, kobj);
+ parent = kobj->parent;
+ linux_destroy_dev(cdev);
+ kobject_put(parent);
+}
+
+void
+linux_destroy_dev(struct linux_cdev *ldev)
+{
+
+ if (ldev->cdev == NULL)
+ return;
+
+ MPASS((ldev->siref & LDEV_SI_DTR) == 0);
+ atomic_set_int(&ldev->siref, LDEV_SI_DTR);
+ while ((atomic_load_int(&ldev->siref) & ~LDEV_SI_DTR) != 0)
+ pause("ldevdtr", hz / 4);
+
+ destroy_dev(ldev->cdev);
+ ldev->cdev = NULL;
+}
+
+const struct kobj_type linux_cdev_ktype = {
+ .release = linux_cdev_release,
+};
+
+const struct kobj_type linux_cdev_static_ktype = {
+ .release = linux_cdev_static_release,
+};
+
+static void
+linux_handle_ifnet_link_event(void *arg, struct ifnet *ifp, int linkstate)
+{
+ struct notifier_block *nb;
+
+ nb = arg;
+ if (linkstate == LINK_STATE_UP)
+ nb->notifier_call(nb, NETDEV_UP, ifp);
+ else
+ nb->notifier_call(nb, NETDEV_DOWN, ifp);
+}
+
+static void
+linux_handle_ifnet_arrival_event(void *arg, struct ifnet *ifp)
+{
+ struct notifier_block *nb;
+
+ nb = arg;
+ nb->notifier_call(nb, NETDEV_REGISTER, ifp);
+}
+
+static void
+linux_handle_ifnet_departure_event(void *arg, struct ifnet *ifp)
+{
+ struct notifier_block *nb;
+
+ nb = arg;
+ nb->notifier_call(nb, NETDEV_UNREGISTER, ifp);
+}
+
+static void
+linux_handle_iflladdr_event(void *arg, struct ifnet *ifp)
+{
+ struct notifier_block *nb;
+
+ nb = arg;
+ nb->notifier_call(nb, NETDEV_CHANGEADDR, ifp);
+}
+
+static void
+linux_handle_ifaddr_event(void *arg, struct ifnet *ifp)
+{
+ struct notifier_block *nb;
+
+ nb = arg;
+ nb->notifier_call(nb, NETDEV_CHANGEIFADDR, ifp);
+}
+
+int
+register_netdevice_notifier(struct notifier_block *nb)
+{
+
+ nb->tags[NETDEV_UP] = EVENTHANDLER_REGISTER(
+ ifnet_link_event, linux_handle_ifnet_link_event, nb, 0);
+ nb->tags[NETDEV_REGISTER] = EVENTHANDLER_REGISTER(
+ ifnet_arrival_event, linux_handle_ifnet_arrival_event, nb, 0);
+ nb->tags[NETDEV_UNREGISTER] = EVENTHANDLER_REGISTER(
+ ifnet_departure_event, linux_handle_ifnet_departure_event, nb, 0);
+ nb->tags[NETDEV_CHANGEADDR] = EVENTHANDLER_REGISTER(
+ iflladdr_event, linux_handle_iflladdr_event, nb, 0);
+
+ return (0);
+}
+
+int
+register_inetaddr_notifier(struct notifier_block *nb)
+{
+
+ nb->tags[NETDEV_CHANGEIFADDR] = EVENTHANDLER_REGISTER(
+ ifaddr_event, linux_handle_ifaddr_event, nb, 0);
+ return (0);
+}
+
+int
+unregister_netdevice_notifier(struct notifier_block *nb)
+{
+
+ EVENTHANDLER_DEREGISTER(ifnet_link_event,
+ nb->tags[NETDEV_UP]);
+ EVENTHANDLER_DEREGISTER(ifnet_arrival_event,
+ nb->tags[NETDEV_REGISTER]);
+ EVENTHANDLER_DEREGISTER(ifnet_departure_event,
+ nb->tags[NETDEV_UNREGISTER]);
+ EVENTHANDLER_DEREGISTER(iflladdr_event,
+ nb->tags[NETDEV_CHANGEADDR]);
+
+ return (0);
+}
+
+int
+unregister_inetaddr_notifier(struct notifier_block *nb)
+{
+
+ EVENTHANDLER_DEREGISTER(ifaddr_event,
+ nb->tags[NETDEV_CHANGEIFADDR]);
+
+ return (0);
+}
+
+struct list_sort_thunk {
+ int (*cmp)(void *, struct list_head *, struct list_head *);
+ void *priv;
+};
+
+static inline int
+linux_le_cmp(void *priv, const void *d1, const void *d2)
+{
+ struct list_head *le1, *le2;
+ struct list_sort_thunk *thunk;
+
+ thunk = priv;
+ le1 = *(__DECONST(struct list_head **, d1));
+ le2 = *(__DECONST(struct list_head **, d2));
+ return ((thunk->cmp)(thunk->priv, le1, le2));
+}
+
+void
+list_sort(void *priv, struct list_head *head, int (*cmp)(void *priv,
+ struct list_head *a, struct list_head *b))
+{
+ struct list_sort_thunk thunk;
+ struct list_head **ar, *le;
+ size_t count, i;
+
+ count = 0;
+ list_for_each(le, head)
+ count++;
+ ar = malloc(sizeof(struct list_head *) * count, M_KMALLOC, M_WAITOK);
+ i = 0;
+ list_for_each(le, head)
+ ar[i++] = le;
+ thunk.cmp = cmp;
+ thunk.priv = priv;
+ qsort_r(ar, count, sizeof(struct list_head *), &thunk, linux_le_cmp);
+ INIT_LIST_HEAD(head);
+ for (i = 0; i < count; i++)
+ list_add_tail(ar[i], head);
+ free(ar, M_KMALLOC);
+}
+
+void
+linux_irq_handler(void *ent)
+{
+ struct irq_ent *irqe;
+
+ linux_set_current(curthread);
+
+ irqe = ent;
+ irqe->handler(irqe->irq, irqe->arg);
+}
+
+#if defined(__i386__) || defined(__amd64__)
+int
+linux_wbinvd_on_all_cpus(void)
+{
+
+ pmap_invalidate_cache();
+ return (0);
+}
+#endif
+
+int
+linux_on_each_cpu(void callback(void *), void *data)
+{
+
+ smp_rendezvous(smp_no_rendezvous_barrier, callback,
+ smp_no_rendezvous_barrier, data);
+ return (0);
+}
+
+int
+linux_in_atomic(void)
+{
+
+ return ((curthread->td_pflags & TDP_NOFAULTING) != 0);
+}
+
+struct linux_cdev *
+linux_find_cdev(const char *name, unsigned major, unsigned minor)
+{
+ dev_t dev = MKDEV(major, minor);
+ struct cdev *cdev;
+
+ dev_lock();
+ LIST_FOREACH(cdev, &linuxcdevsw.d_devs, si_list) {
+ struct linux_cdev *ldev = cdev->si_drv1;
+ if (ldev->dev == dev &&
+ strcmp(kobject_name(&ldev->kobj), name) == 0) {
+ break;
+ }
+ }
+ dev_unlock();
+
+ return (cdev != NULL ? cdev->si_drv1 : NULL);
+}
+
+int
+__register_chrdev(unsigned int major, unsigned int baseminor,
+ unsigned int count, const char *name,
+ const struct file_operations *fops)
+{
+ struct linux_cdev *cdev;
+ int ret = 0;
+ int i;
+
+ for (i = baseminor; i < baseminor + count; i++) {
+ cdev = cdev_alloc();
+ cdev->ops = fops;
+ kobject_set_name(&cdev->kobj, name);
+
+ ret = cdev_add(cdev, makedev(major, i), 1);
+ if (ret != 0)
+ break;
+ }
+ return (ret);
+}
+
+int
+__register_chrdev_p(unsigned int major, unsigned int baseminor,
+ unsigned int count, const char *name,
+ const struct file_operations *fops, uid_t uid,
+ gid_t gid, int mode)
+{
+ struct linux_cdev *cdev;
+ int ret = 0;
+ int i;
+
+ for (i = baseminor; i < baseminor + count; i++) {
+ cdev = cdev_alloc();
+ cdev->ops = fops;
+ kobject_set_name(&cdev->kobj, name);
+
+ ret = cdev_add_ext(cdev, makedev(major, i), uid, gid, mode);
+ if (ret != 0)
+ break;
+ }
+ return (ret);
+}
+
+void
+__unregister_chrdev(unsigned int major, unsigned int baseminor,
+ unsigned int count, const char *name)
+{
+ struct linux_cdev *cdevp;
+ int i;
+
+ for (i = baseminor; i < baseminor + count; i++) {
+ cdevp = linux_find_cdev(name, major, i);
+ if (cdevp != NULL)
+ cdev_del(cdevp);
+ }
+}
+
+void
+linux_dump_stack(void)
+{
+#ifdef STACK
+ struct stack st;
+
+ stack_zero(&st);
+ stack_save(&st);
+ stack_print(&st);
+#endif
+}
+
+#if defined(__i386__) || defined(__amd64__)
+bool linux_cpu_has_clflush;
+#endif
+
+static void
+linux_compat_init(void *arg)
+{
+ struct sysctl_oid *rootoid;
+ int i;
+
+#if defined(__i386__) || defined(__amd64__)
+ linux_cpu_has_clflush = (cpu_feature & CPUID_CLFSH);
+#endif
+ rw_init(&linux_vma_lock, "lkpi-vma-lock");
+
+ rootoid = SYSCTL_ADD_ROOT_NODE(NULL,
+ OID_AUTO, "sys", CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, "sys");
+ kobject_init(&linux_class_root, &linux_class_ktype);
+ kobject_set_name(&linux_class_root, "class");
+ linux_class_root.oidp = SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(rootoid),
+ OID_AUTO, "class", CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, "class");
+ kobject_init(&linux_root_device.kobj, &linux_dev_ktype);
+ kobject_set_name(&linux_root_device.kobj, "device");
+ linux_root_device.kobj.oidp = SYSCTL_ADD_NODE(NULL,
+ SYSCTL_CHILDREN(rootoid), OID_AUTO, "device",
+ CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "device");
+ linux_root_device.bsddev = root_bus;
+ linux_class_misc.name = "misc";
+ class_register(&linux_class_misc);
+ INIT_LIST_HEAD(&pci_drivers);
+ INIT_LIST_HEAD(&pci_devices);
+ spin_lock_init(&pci_lock);
+ mtx_init(&vmmaplock, "IO Map lock", NULL, MTX_DEF);
+ for (i = 0; i < VMMAP_HASH_SIZE; i++)
+ LIST_INIT(&vmmaphead[i]);
+ init_waitqueue_head(&linux_bit_waitq);
+ init_waitqueue_head(&linux_var_waitq);
+}
+SYSINIT(linux_compat, SI_SUB_DRIVERS, SI_ORDER_SECOND, linux_compat_init, NULL);
+
+static void
+linux_compat_uninit(void *arg)
+{
+ linux_kobject_kfree_name(&linux_class_root);
+ linux_kobject_kfree_name(&linux_root_device.kobj);
+ linux_kobject_kfree_name(&linux_class_misc.kobj);
+
+ mtx_destroy(&vmmaplock);
+ spin_lock_destroy(&pci_lock);
+ rw_destroy(&linux_vma_lock);
+}
+SYSUNINIT(linux_compat, SI_SUB_DRIVERS, SI_ORDER_SECOND, linux_compat_uninit, NULL);
+
+/*
+ * NOTE: Linux frequently uses "unsigned long" for pointer to integer
+ * conversion and vice versa, where in FreeBSD "uintptr_t" would be
+ * used. Assert these types have the same size, else some parts of the
+ * LinuxKPI may not work like expected:
+ */
+CTASSERT(sizeof(unsigned long) == sizeof(uintptr_t));
diff --git a/sys/compat/linuxkpi/common/src/linux_current.c b/sys/compat/linuxkpi/common/src/linux_current.c
new file mode 100644
index 000000000000..611d10df3383
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_current.c
@@ -0,0 +1,263 @@
+/*-
+ * Copyright (c) 2017 Hans Petter Selasky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <linux/compat.h>
+#include <linux/completion.h>
+#include <linux/mm.h>
+#include <linux/kthread.h>
+
+#include <sys/kernel.h>
+#include <sys/eventhandler.h>
+#include <sys/malloc.h>
+
+static eventhandler_tag linuxkpi_thread_dtor_tag;
+
+static MALLOC_DEFINE(M_LINUX_CURRENT, "linuxcurrent", "LinuxKPI task structure");
+
+int
+linux_alloc_current(struct thread *td, int flags)
+{
+ struct proc *proc;
+ struct thread *td_other;
+ struct task_struct *ts;
+ struct task_struct *ts_other;
+ struct mm_struct *mm;
+ struct mm_struct *mm_other;
+
+ MPASS(td->td_lkpi_task == NULL);
+
+ ts = malloc(sizeof(*ts), M_LINUX_CURRENT, flags | M_ZERO);
+ if (ts == NULL)
+ return (ENOMEM);
+
+ mm = malloc(sizeof(*mm), M_LINUX_CURRENT, flags | M_ZERO);
+ if (mm == NULL) {
+ free(ts, M_LINUX_CURRENT);
+ return (ENOMEM);
+ }
+
+ /* setup new task structure */
+ atomic_set(&ts->kthread_flags, 0);
+ ts->task_thread = td;
+ ts->comm = td->td_name;
+ ts->pid = td->td_tid;
+ ts->group_leader = ts;
+ atomic_set(&ts->usage, 1);
+ atomic_set(&ts->state, TASK_RUNNING);
+ init_completion(&ts->parked);
+ init_completion(&ts->exited);
+
+ proc = td->td_proc;
+
+ /* check if another thread already has a mm_struct */
+ PROC_LOCK(proc);
+ FOREACH_THREAD_IN_PROC(proc, td_other) {
+ ts_other = td_other->td_lkpi_task;
+ if (ts_other == NULL)
+ continue;
+
+ mm_other = ts_other->mm;
+ if (mm_other == NULL)
+ continue;
+
+ /* try to share other mm_struct */
+ if (atomic_inc_not_zero(&mm_other->mm_users)) {
+ /* set mm_struct pointer */
+ ts->mm = mm_other;
+ break;
+ }
+ }
+
+ /* use allocated mm_struct as a fallback */
+ if (ts->mm == NULL) {
+ /* setup new mm_struct */
+ init_rwsem(&mm->mmap_sem);
+ atomic_set(&mm->mm_count, 1);
+ atomic_set(&mm->mm_users, 1);
+ /* set mm_struct pointer */
+ ts->mm = mm;
+ /* clear pointer to not free memory */
+ mm = NULL;
+ }
+
+ /* store pointer to task struct */
+ td->td_lkpi_task = ts;
+ PROC_UNLOCK(proc);
+
+ /* free mm_struct pointer, if any */
+ free(mm, M_LINUX_CURRENT);
+
+ return (0);
+}
+
+struct mm_struct *
+linux_get_task_mm(struct task_struct *task)
+{
+ struct mm_struct *mm;
+
+ mm = task->mm;
+ if (mm != NULL) {
+ atomic_inc(&mm->mm_users);
+ return (mm);
+ }
+ return (NULL);
+}
+
+void
+linux_mm_dtor(struct mm_struct *mm)
+{
+ free(mm, M_LINUX_CURRENT);
+}
+
+void
+linux_free_current(struct task_struct *ts)
+{
+ mmput(ts->mm);
+ free(ts, M_LINUX_CURRENT);
+}
+
+static void
+linuxkpi_thread_dtor(void *arg __unused, struct thread *td)
+{
+ struct task_struct *ts;
+
+ ts = td->td_lkpi_task;
+ if (ts == NULL)
+ return;
+
+ td->td_lkpi_task = NULL;
+ put_task_struct(ts);
+}
+
+static struct task_struct *
+linux_get_pid_task_int(pid_t pid, const bool do_get)
+{
+ struct thread *td;
+ struct proc *p;
+ struct task_struct *ts;
+
+ if (pid > PID_MAX) {
+ /* try to find corresponding thread */
+ td = tdfind(pid, -1);
+ if (td != NULL) {
+ ts = td->td_lkpi_task;
+ if (do_get && ts != NULL)
+ get_task_struct(ts);
+ PROC_UNLOCK(td->td_proc);
+ return (ts);
+ }
+ } else {
+ /* try to find corresponding procedure */
+ p = pfind(pid);
+ if (p != NULL) {
+ FOREACH_THREAD_IN_PROC(p, td) {
+ ts = td->td_lkpi_task;
+ if (ts != NULL) {
+ if (do_get)
+ get_task_struct(ts);
+ PROC_UNLOCK(p);
+ return (ts);
+ }
+ }
+ PROC_UNLOCK(p);
+ }
+ }
+ return (NULL);
+}
+
+struct task_struct *
+linux_pid_task(pid_t pid)
+{
+ return (linux_get_pid_task_int(pid, false));
+}
+
+struct task_struct *
+linux_get_pid_task(pid_t pid)
+{
+ return (linux_get_pid_task_int(pid, true));
+}
+
+bool
+linux_task_exiting(struct task_struct *task)
+{
+ struct thread *td;
+ struct proc *p;
+ bool ret;
+
+ ret = false;
+
+ /* try to find corresponding thread */
+ td = tdfind(task->pid, -1);
+ if (td != NULL) {
+ p = td->td_proc;
+ } else {
+ /* try to find corresponding procedure */
+ p = pfind(task->pid);
+ }
+
+ if (p != NULL) {
+ if ((p->p_flag & P_WEXIT) != 0)
+ ret = true;
+ PROC_UNLOCK(p);
+ }
+ return (ret);
+}
+
+static void
+linux_current_init(void *arg __unused)
+{
+ lkpi_alloc_current = linux_alloc_current;
+ linuxkpi_thread_dtor_tag = EVENTHANDLER_REGISTER(thread_dtor,
+ linuxkpi_thread_dtor, NULL, EVENTHANDLER_PRI_ANY);
+}
+SYSINIT(linux_current, SI_SUB_EVENTHANDLER, SI_ORDER_SECOND, linux_current_init, NULL);
+
+static void
+linux_current_uninit(void *arg __unused)
+{
+ struct proc *p;
+ struct task_struct *ts;
+ struct thread *td;
+
+ sx_slock(&allproc_lock);
+ FOREACH_PROC_IN_SYSTEM(p) {
+ PROC_LOCK(p);
+ FOREACH_THREAD_IN_PROC(p, td) {
+ if ((ts = td->td_lkpi_task) != NULL) {
+ td->td_lkpi_task = NULL;
+ put_task_struct(ts);
+ }
+ }
+ PROC_UNLOCK(p);
+ }
+ sx_sunlock(&allproc_lock);
+ EVENTHANDLER_DEREGISTER(thread_dtor, linuxkpi_thread_dtor_tag);
+ lkpi_alloc_current = linux_alloc_current_noop;
+}
+SYSUNINIT(linux_current, SI_SUB_EVENTHANDLER, SI_ORDER_SECOND, linux_current_uninit, NULL);
diff --git a/sys/compat/linuxkpi/common/src/linux_devres.c b/sys/compat/linuxkpi/common/src/linux_devres.c
new file mode 100644
index 000000000000..96ff3e486d1d
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_devres.c
@@ -0,0 +1,226 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020-2021 The FreeBSD Foundation
+ *
+ * This software was developed by Bj\xc3\xb6rn Zeeb under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+
+/*
+ * Linux devres KPI implementation.
+ */
+
+struct devres {
+ struct list_head entry;
+ void (*release)(struct device *, void *);
+
+ /* Must come last. */
+ uint8_t __drdata[0] __aligned(CACHE_LINE_SIZE);
+};
+
+void *
+lkpi_devres_alloc(void(*release)(struct device *, void *),
+ size_t size, gfp_t gfp)
+{
+ void *p;
+ struct devres *dr;
+ size_t total;
+
+ if (size == 0)
+ return (NULL);
+
+ total = sizeof(*dr) + size;
+ dr = kmalloc(total, gfp);
+ if (dr == NULL)
+ return (NULL);
+
+ INIT_LIST_HEAD(&dr->entry);
+ dr->release = release;
+ p = (void *)(dr+1);
+
+ return (p);
+}
+
+static void
+lkpi_devres_free_dr(struct devres *dr)
+{
+
+ /*
+ * We have no dev, so cannot lock. This means someone else has
+ * to do this prior to us if devres_add() had been called.
+ */
+ KASSERT(list_empty_careful(&dr->entry),
+ ("%s: dr %p still on devres_head\n", __func__, dr));
+ kfree(dr);
+}
+
+void
+lkpi_devres_free(void *p)
+{
+ struct devres *dr;
+
+ if (p == NULL)
+ return;
+
+ dr = container_of(p, struct devres, __drdata);
+ lkpi_devres_free_dr(dr);
+}
+
+void
+lkpi_devres_add(struct device *dev, void *p)
+{
+ struct devres *dr;
+
+ KASSERT(dev != NULL && p != NULL, ("%s: dev %p p %p\n",
+ __func__, dev, p));
+
+ dr = container_of(p, struct devres, __drdata);
+ spin_lock(&dev->devres_lock);
+ list_add(&dr->entry, &dev->devres_head);
+ spin_unlock(&dev->devres_lock);
+}
+
+static struct devres *
+lkpi_devres_find_dr(struct device *dev, void(*release)(struct device *, void *),
+ int (*match)(struct device *, void *, void *), void *mp)
+{
+ struct devres *dr, *next;
+ void *p;
+
+ KASSERT(dev != NULL, ("%s: dev %p\n", __func__, dev));
+ assert_spin_locked(&dev->devres_lock);
+
+ list_for_each_entry_safe(dr, next, &dev->devres_head, entry) {
+ if (dr->release != release)
+ continue;
+ p = (void *)(dr+1);
+ if (match != NULL && match(dev, p, mp) == false)
+ continue;
+ return (dr);
+ }
+
+ return (NULL);
+}
+
+void *
+lkpi_devres_find(struct device *dev, void(*release)(struct device *, void *),
+ int (*match)(struct device *, void *, void *), void *mp)
+{
+ struct devres *dr;
+
+ KASSERT(dev != NULL, ("%s: dev %p\n", __func__, dev));
+
+ spin_lock(&dev->devres_lock);
+ dr = lkpi_devres_find_dr(dev, release, match, mp);
+ spin_unlock(&dev->devres_lock);
+
+ if (dr == NULL)
+ return (NULL);
+
+ return ((void *)(dr + 1));
+}
+
+static void
+lkpi_devres_unlink_locked(struct device *dev, struct devres *dr)
+{
+ KASSERT(dev != NULL, ("%s: dev %p\n", __func__, dev));
+ KASSERT(dr != NULL, ("%s: dr %p\n", __func__, dr));
+ assert_spin_locked(&dev->devres_lock);
+
+ list_del_init(&dr->entry);
+}
+
+void
+lkpi_devres_unlink(struct device *dev, void *p)
+{
+ struct devres *dr;
+
+ KASSERT(dev != NULL && p != NULL, ("%s: dev %p p %p\n",
+ __func__, dev, p));
+
+ dr = container_of(p, struct devres, __drdata);
+ spin_lock(&dev->devres_lock);
+ lkpi_devres_unlink_locked(dev, dr);
+ spin_unlock(&dev->devres_lock);
+}
+
+/* This is called on device free. */
+void
+lkpi_devres_release_free_list(struct device *dev)
+{
+ struct devres *dr, *next;
+ void *p;
+
+ /* Free any resources allocated on the device. */
+ /* No need to lock anymore. */
+ list_for_each_entry_safe(dr, next, &dev->devres_head, entry) {
+ p = (void *)(dr+1);
+ if (dr->release != NULL)
+ dr->release(dev, p);
+ /* This should probably be a function of some kind. */
+ list_del_init(&dr->entry);
+ lkpi_devres_free(p);
+ }
+}
+
+int
+lkpi_devres_destroy(struct device *dev, void(*release)(struct device *, void *),
+ int (*match)(struct device *, void *, void *), void *mp)
+{
+ struct devres *dr;
+
+ spin_lock(&dev->devres_lock);
+ dr = lkpi_devres_find_dr(dev, release, match, mp);
+ if (dr != NULL)
+ lkpi_devres_unlink_locked(dev, dr);
+ spin_unlock(&dev->devres_lock);
+
+ if (dr == NULL)
+ return (-ENOENT);
+ lkpi_devres_free_dr(dr);
+
+ return (0);
+}
+
+/*
+ * Devres release function for k*malloc().
+ * While there is nothing to do here adding, e.g., tracing would be
+ * possible so we leave the empty function here.
+ * Also good for documentation as it is the simplest example.
+ */
+void
+lkpi_devm_kmalloc_release(struct device *dev __unused, void *p __unused)
+{
+
+ /* Nothing to do. Freed with the devres. */
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_dmi.c b/sys/compat/linuxkpi/common/src/linux_dmi.c
new file mode 100644
index 000000000000..c0bb9a9f50d6
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_dmi.c
@@ -0,0 +1,140 @@
+/*-
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Emmanuel Vadot under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+
+#include <linux/dmi.h>
+
+static char *dmi_data[DMI_STRING_MAX];
+
+static void
+linux_dmi_preload(void *arg)
+{
+
+ dmi_data[DMI_BIOS_VENDOR] = kern_getenv("smbios.bios.vendor");
+ dmi_data[DMI_BIOS_VERSION] = kern_getenv("smbios.bios.version");
+ dmi_data[DMI_BIOS_DATE] = kern_getenv("smbios.bios.reldate");
+ dmi_data[DMI_SYS_VENDOR] = kern_getenv("smbios.system.maker");
+ dmi_data[DMI_PRODUCT_NAME] = kern_getenv("smbios.system.product");
+ dmi_data[DMI_PRODUCT_VERSION] = kern_getenv("smbios.system.version");
+ dmi_data[DMI_PRODUCT_SERIAL] = kern_getenv("smbios.system.serial");
+ dmi_data[DMI_PRODUCT_UUID] = kern_getenv("smbios.system.uuid");
+ dmi_data[DMI_BOARD_VENDOR] = kern_getenv("smbios.planar.maker");
+ dmi_data[DMI_BOARD_NAME] = kern_getenv("smbios.planar.product");
+ dmi_data[DMI_BOARD_VERSION] = kern_getenv("smbios.planar.version");
+ dmi_data[DMI_BOARD_SERIAL] = kern_getenv("smbios.planar.serial");
+ dmi_data[DMI_BOARD_ASSET_TAG] = kern_getenv("smbios.planar.tag");
+ dmi_data[DMI_CHASSIS_VENDOR] = kern_getenv("smbios.chassis.maker");
+ dmi_data[DMI_CHASSIS_TYPE] = kern_getenv("smbios.chassis.type");
+ dmi_data[DMI_CHASSIS_VERSION] = kern_getenv("smbios.chassis.version");
+ dmi_data[DMI_CHASSIS_SERIAL] = kern_getenv("smbios.chassis.serial");
+ dmi_data[DMI_CHASSIS_ASSET_TAG] = kern_getenv("smbios.chassis.tag");
+}
+SYSINIT(linux_dmi_preload, SI_SUB_DRIVERS, SI_ORDER_ANY, linux_dmi_preload, NULL);
+
+/* Match a system against a field */
+bool
+linux_dmi_match(enum dmi_field f, const char *str)
+{
+
+ if (f < DMI_STRING_MAX &&
+ dmi_data[f] != NULL &&
+ strcmp(dmi_data[f], str) == 0)
+ return(true);
+ return (false);
+}
+
+/* Match a system against the struct, all matches must be ok */
+static bool
+linux_dmi_matches(const struct dmi_system_id *dsi)
+{
+ int i;
+
+ for (i = 0; i < nitems(dsi->matches); i++) {
+ if (dsi->matches[i].slot == DMI_NONE)
+ break;
+ if (dmi_match(dsi->matches[i].slot,
+ dsi->matches[i].substr) == false)
+ return (false);
+ }
+
+ return (true);
+}
+
+/* Return the string matching the field */
+const char *
+linux_dmi_get_system_info(int field)
+{
+
+ if (field < DMI_STRING_MAX)
+ return (dmi_data[field]);
+ return (NULL);
+}
+
+/*
+ * Match a system against the structs list
+ * If a match is found return the corresponding structure.
+ */
+const struct dmi_system_id *
+linux_dmi_first_match(const struct dmi_system_id *list)
+{
+ const struct dmi_system_id *dsi;
+
+ for (dsi = list; dsi->matches[0].slot != 0; dsi++) {
+ if (linux_dmi_matches(dsi))
+ return (dsi);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Match a system against the structs list
+ * For each match call the callback with the corresponding data
+ * Return the number of matches.
+ */
+int
+linux_dmi_check_system(const struct dmi_system_id *sysid)
+{
+ const struct dmi_system_id *dsi;
+ int matches = 0;
+
+ for (dsi = sysid; dsi->matches[0].slot != 0; dsi++) {
+ if (linux_dmi_matches(dsi)) {
+ matches++;
+ if (dsi->callback && dsi->callback(dsi))
+ break;
+ }
+ }
+
+ return (matches);
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_firmware.c b/sys/compat/linuxkpi/common/src/linux_firmware.c
new file mode 100644
index 000000000000..75147a311827
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_firmware.c
@@ -0,0 +1,178 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020-2021 The FreeBSD Foundation
+ *
+ * This software was developed by Björn Zeeb under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/malloc.h>
+#include <sys/firmware.h>
+
+#include <linux/types.h>
+#include <linux/device.h>
+
+#include <linux/firmware.h>
+#undef firmware
+
+MALLOC_DEFINE(M_LKPI_FW, "lkpifw", "LinuxKPI firmware");
+
+static int
+_linuxkpi_request_firmware(const char *fw_name, const struct linuxkpi_firmware **fw,
+ struct device *dev, gfp_t gfp __unused, bool enoentok, bool warn)
+{
+ const struct firmware *fbdfw;
+ struct linuxkpi_firmware *lfw;
+ const char *fwimg;
+ char *p;
+ uint32_t flags;
+
+ if (fw_name == NULL || fw == NULL || dev == NULL)
+ return (-EINVAL);
+
+ /* Set independent on "warn". To debug, bootverbose is avail. */
+ flags = FIRMWARE_GET_NOWARN;
+
+ KASSERT(gfp == GFP_KERNEL, ("%s: gfp %#x\n", __func__, gfp));
+ lfw = malloc(sizeof(*lfw), M_LKPI_FW, M_WAITOK | M_ZERO);
+
+ /*
+ * Linux can have a path in the firmware which is hard to replicate
+ * for auto-firmware-module-loading.
+ * On FreeBSD, depending on what people do, the firmware will either
+ * be called "fw", or "dir_fw", or "modname_dir_fw". The latter the
+ * driver author has to deal with herself (requesting the special name).
+ * We also optionally flatten '/'s and '.'s as some firmware modules do.
+ * We probe in the least-of-work order avoiding memory operations.
+ * It will be preferred to build the firmware .ko in a well matching
+ * way rather than adding more name-mangling-hacks here in the future
+ * (though we could if needed).
+ */
+ /* (1) Try any name removed of path. */
+ fwimg = strrchr(fw_name, '/');
+ if (fwimg != NULL)
+ fwimg++;
+ if (fwimg == NULL || *fwimg == '\0')
+ fwimg = fw_name;
+ fbdfw = firmware_get_flags(fwimg, flags);
+ /* (2) Try the original name if we have not yet. */
+ if (fbdfw == NULL && fwimg != fw_name) {
+ fwimg = fw_name;
+ fbdfw = firmware_get_flags(fwimg, flags);
+ }
+ /* (3) Flatten '/' and then '.' to '_' and try with adjusted name. */
+ if (fbdfw == NULL &&
+ (strchr(fw_name, '/') != NULL || strchr(fw_name, '.') != NULL)) {
+ fwimg = strdup(fw_name, M_LKPI_FW);
+ if (fwimg != NULL) {
+ while ((p = strchr(fwimg, '/')) != NULL)
+ *p = '_';
+ fbdfw = firmware_get_flags(fwimg, flags);
+ if (fbdfw == NULL) {
+ while ((p = strchr(fwimg, '.')) != NULL)
+ *p = '_';
+ fbdfw = firmware_get_flags(fwimg, flags);
+ }
+ free(__DECONST(void *, fwimg), M_LKPI_FW);
+ }
+ }
+ if (fbdfw == NULL) {
+ if (enoentok)
+ *fw = lfw;
+ else {
+ free(lfw, M_LKPI_FW);
+ *fw = NULL;
+ }
+ if (warn)
+ device_printf(dev->bsddev, "could not load firmware "
+ "image '%s'\n", fw_name);
+ return (-ENOENT);
+ }
+
+ device_printf(dev->bsddev,"successfully loaded firmware image '%s'\n",
+ fw_name);
+ lfw->fbdfw = fbdfw;
+ lfw->data = (const uint8_t *)fbdfw->data;
+ lfw->size = fbdfw->datasize;
+ *fw = lfw;
+ return (0);
+}
+
+int
+linuxkpi_request_firmware_nowait(struct module *mod __unused, bool _t __unused,
+ const char *fw_name, struct device *dev, gfp_t gfp, void *drv,
+ void(*cont)(const struct linuxkpi_firmware *, void *))
+{
+ const struct linuxkpi_firmware *lfw;
+ int error;
+
+ /*
+ * Linux seems to run the callback if it cannot find the firmware.
+ * The fact that this is "_nowait()" and has a callback seems to
+ * imply that this is run in a deferred conext which we currently
+ * do not do. Should it become necessary (a driver actually requiring
+ * it) we would need to implement it here.
+ */
+ error = _linuxkpi_request_firmware(fw_name, &lfw, dev, gfp, true, true);
+ if (error == -ENOENT)
+ error = 0;
+ if (error == 0)
+ cont(lfw, drv);
+
+ return (error);
+}
+
+int
+linuxkpi_request_firmware(const struct linuxkpi_firmware **fw,
+ const char *fw_name, struct device *dev)
+{
+
+ return (_linuxkpi_request_firmware(fw_name, fw, dev, GFP_KERNEL, false,
+ true));
+}
+
+int
+linuxkpi_firmware_request_nowarn(const struct linuxkpi_firmware **fw,
+ const char *fw_name, struct device *dev)
+{
+
+ return (_linuxkpi_request_firmware(fw_name, fw, dev, GFP_KERNEL, false,
+ false));
+}
+
+void
+linuxkpi_release_firmware(const struct linuxkpi_firmware *fw)
+{
+
+ if (fw == NULL)
+ return;
+
+ if (fw->fbdfw)
+ firmware_put(fw->fbdfw, FIRMWARE_UNLOAD);
+ free(__DECONST(void *, fw), M_LKPI_FW);
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_fpu.c b/sys/compat/linuxkpi/common/src/linux_fpu.c
new file mode 100644
index 000000000000..976e55e68ca1
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_fpu.c
@@ -0,0 +1,50 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020 Greg V <greg@unrelenting.technology>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+
+#include <machine/fpu.h>
+
+struct fpu_kern_ctx *__lkpi_fpu_ctx;
+unsigned int __lkpi_fpu_ctx_level = 0;
+
+static void
+linux_fpu_init(void *arg __unused)
+{
+ __lkpi_fpu_ctx = fpu_kern_alloc_ctx(0);
+}
+SYSINIT(linux_fpu, SI_SUB_EVENTHANDLER, SI_ORDER_SECOND, linux_fpu_init, NULL);
+
+static void
+linux_fpu_uninit(void *arg __unused)
+{
+ fpu_kern_free_ctx(__lkpi_fpu_ctx);
+}
+SYSUNINIT(linux_fpu, SI_SUB_EVENTHANDLER, SI_ORDER_SECOND, linux_fpu_uninit, NULL);
diff --git a/sys/compat/linuxkpi/common/src/linux_hrtimer.c b/sys/compat/linuxkpi/common/src/linux_hrtimer.c
new file mode 100644
index 000000000000..a56485512a14
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_hrtimer.c
@@ -0,0 +1,122 @@
+/*-
+ * Copyright (c) 2017 Mark Johnston <markj@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/time.h>
+
+#include <machine/cpu.h>
+
+#include <linux/hrtimer.h>
+
+static void
+hrtimer_call_handler(void *arg)
+{
+ struct hrtimer *hrtimer;
+ enum hrtimer_restart ret;
+
+ hrtimer = arg;
+ ret = hrtimer->function(hrtimer);
+
+ if (ret == HRTIMER_RESTART) {
+ callout_schedule_sbt(&hrtimer->callout,
+ nstosbt(hrtimer->expires), nstosbt(hrtimer->precision), 0);
+ } else {
+ callout_deactivate(&hrtimer->callout);
+ }
+}
+
+bool
+linux_hrtimer_active(struct hrtimer *hrtimer)
+{
+ bool ret;
+
+ mtx_lock(&hrtimer->mtx);
+ ret = callout_active(&hrtimer->callout);
+ mtx_unlock(&hrtimer->mtx);
+
+ return (ret);
+}
+
+/*
+ * Cancel active hrtimer.
+ * Return 1 if timer was active and cancellation succeeded, or 0 otherwise.
+ */
+int
+linux_hrtimer_cancel(struct hrtimer *hrtimer)
+{
+
+ return (callout_drain(&hrtimer->callout) > 0);
+}
+
+void
+linux_hrtimer_init(struct hrtimer *hrtimer)
+{
+
+ memset(hrtimer, 0, sizeof(*hrtimer));
+ mtx_init(&hrtimer->mtx, "hrtimer", NULL,
+ MTX_DEF | MTX_RECURSE | MTX_NOWITNESS);
+ callout_init_mtx(&hrtimer->callout, &hrtimer->mtx, 0);
+}
+
+void
+linux_hrtimer_set_expires(struct hrtimer *hrtimer, ktime_t time)
+{
+ hrtimer->expires = ktime_to_ns(time);
+}
+
+void
+linux_hrtimer_start(struct hrtimer *hrtimer, ktime_t time)
+{
+
+ linux_hrtimer_start_range_ns(hrtimer, time, 0);
+}
+
+void
+linux_hrtimer_start_range_ns(struct hrtimer *hrtimer, ktime_t time,
+ int64_t nsec)
+{
+
+ mtx_lock(&hrtimer->mtx);
+ hrtimer->precision = nsec;
+ callout_reset_sbt(&hrtimer->callout, nstosbt(ktime_to_ns(time)),
+ nstosbt(nsec), hrtimer_call_handler, hrtimer, 0);
+ mtx_unlock(&hrtimer->mtx);
+}
+
+void
+linux_hrtimer_forward_now(struct hrtimer *hrtimer, ktime_t interval)
+{
+
+ mtx_lock(&hrtimer->mtx);
+ callout_reset_sbt(&hrtimer->callout, nstosbt(ktime_to_ns(interval)),
+ nstosbt(hrtimer->precision), hrtimer_call_handler, hrtimer, 0);
+ mtx_unlock(&hrtimer->mtx);
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_idr.c b/sys/compat/linuxkpi/common/src/linux_idr.c
new file mode 100644
index 000000000000..b5007a89966b
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_idr.c
@@ -0,0 +1,809 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#include <machine/stdarg.h>
+
+#include <linux/bitmap.h>
+#include <linux/kobject.h>
+#include <linux/slab.h>
+#include <linux/idr.h>
+#include <linux/err.h>
+
+#define MAX_IDR_LEVEL ((MAX_IDR_SHIFT + IDR_BITS - 1) / IDR_BITS)
+#define MAX_IDR_FREE (MAX_IDR_LEVEL * 2)
+
+struct linux_idr_cache {
+ spinlock_t lock;
+ struct idr_layer *head;
+ unsigned count;
+};
+
+DPCPU_DEFINE_STATIC(struct linux_idr_cache, linux_idr_cache);
+
+/*
+ * IDR Implementation.
+ *
+ * This is quick and dirty and not as re-entrant as the linux version
+ * however it should be fairly fast. It is basically a radix tree with
+ * a builtin bitmap for allocation.
+ */
+static MALLOC_DEFINE(M_IDR, "idr", "Linux IDR compat");
+
+static struct idr_layer *
+idr_preload_dequeue_locked(struct linux_idr_cache *lic)
+{
+ struct idr_layer *retval;
+
+ /* check if wrong thread is trying to dequeue */
+ if (mtx_owned(&lic->lock.m) == 0)
+ return (NULL);
+
+ retval = lic->head;
+ if (likely(retval != NULL)) {
+ lic->head = retval->ary[0];
+ lic->count--;
+ retval->ary[0] = NULL;
+ }
+ return (retval);
+}
+
+static void
+idr_preload_init(void *arg)
+{
+ int cpu;
+
+ CPU_FOREACH(cpu) {
+ struct linux_idr_cache *lic =
+ DPCPU_ID_PTR(cpu, linux_idr_cache);
+
+ spin_lock_init(&lic->lock);
+ }
+}
+SYSINIT(idr_preload_init, SI_SUB_CPU, SI_ORDER_ANY, idr_preload_init, NULL);
+
+static void
+idr_preload_uninit(void *arg)
+{
+ int cpu;
+
+ CPU_FOREACH(cpu) {
+ struct idr_layer *cacheval;
+ struct linux_idr_cache *lic =
+ DPCPU_ID_PTR(cpu, linux_idr_cache);
+
+ while (1) {
+ spin_lock(&lic->lock);
+ cacheval = idr_preload_dequeue_locked(lic);
+ spin_unlock(&lic->lock);
+
+ if (cacheval == NULL)
+ break;
+ free(cacheval, M_IDR);
+ }
+ spin_lock_destroy(&lic->lock);
+ }
+}
+SYSUNINIT(idr_preload_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, idr_preload_uninit, NULL);
+
+void
+idr_preload(gfp_t gfp_mask)
+{
+ struct linux_idr_cache *lic;
+ struct idr_layer *cacheval;
+
+ sched_pin();
+
+ lic = &DPCPU_GET(linux_idr_cache);
+
+ /* fill up cache */
+ spin_lock(&lic->lock);
+ while (lic->count < MAX_IDR_FREE) {
+ spin_unlock(&lic->lock);
+ cacheval = malloc(sizeof(*cacheval), M_IDR, M_ZERO | gfp_mask);
+ spin_lock(&lic->lock);
+ if (cacheval == NULL)
+ break;
+ cacheval->ary[0] = lic->head;
+ lic->head = cacheval;
+ lic->count++;
+ }
+}
+
+void
+idr_preload_end(void)
+{
+ struct linux_idr_cache *lic;
+
+ lic = &DPCPU_GET(linux_idr_cache);
+ spin_unlock(&lic->lock);
+ sched_unpin();
+}
+
+static inline int
+idr_max(struct idr *idr)
+{
+ return (1 << (idr->layers * IDR_BITS)) - 1;
+}
+
+static inline int
+idr_pos(int id, int layer)
+{
+ return (id >> (IDR_BITS * layer)) & IDR_MASK;
+}
+
+void
+idr_init(struct idr *idr)
+{
+ bzero(idr, sizeof(*idr));
+ mtx_init(&idr->lock, "idr", NULL, MTX_DEF);
+}
+
+/* Only frees cached pages. */
+void
+idr_destroy(struct idr *idr)
+{
+ struct idr_layer *il, *iln;
+
+ idr_remove_all(idr);
+ mtx_lock(&idr->lock);
+ for (il = idr->free; il != NULL; il = iln) {
+ iln = il->ary[0];
+ free(il, M_IDR);
+ }
+ mtx_unlock(&idr->lock);
+ mtx_destroy(&idr->lock);
+}
+
+static void
+idr_remove_layer(struct idr_layer *il, int layer)
+{
+ int i;
+
+ if (il == NULL)
+ return;
+ if (layer == 0) {
+ free(il, M_IDR);
+ return;
+ }
+ for (i = 0; i < IDR_SIZE; i++)
+ if (il->ary[i])
+ idr_remove_layer(il->ary[i], layer - 1);
+}
+
+void
+idr_remove_all(struct idr *idr)
+{
+
+ mtx_lock(&idr->lock);
+ idr_remove_layer(idr->top, idr->layers - 1);
+ idr->top = NULL;
+ idr->layers = 0;
+ mtx_unlock(&idr->lock);
+}
+
+static void *
+idr_remove_locked(struct idr *idr, int id)
+{
+ struct idr_layer *il;
+ void *res;
+ int layer;
+ int idx;
+
+ id &= MAX_ID_MASK;
+ il = idr->top;
+ layer = idr->layers - 1;
+ if (il == NULL || id > idr_max(idr))
+ return (NULL);
+ /*
+ * Walk down the tree to this item setting bitmaps along the way
+ * as we know at least one item will be free along this path.
+ */
+ while (layer && il) {
+ idx = idr_pos(id, layer);
+ il->bitmap |= 1 << idx;
+ il = il->ary[idx];
+ layer--;
+ }
+ idx = id & IDR_MASK;
+ /*
+ * At this point we've set free space bitmaps up the whole tree.
+ * We could make this non-fatal and unwind but linux dumps a stack
+ * and a warning so I don't think it's necessary.
+ */
+ if (il == NULL || (il->bitmap & (1 << idx)) != 0)
+ panic("idr_remove: Item %d not allocated (%p, %p)\n",
+ id, idr, il);
+ res = il->ary[idx];
+ il->ary[idx] = NULL;
+ il->bitmap |= 1 << idx;
+
+ return (res);
+}
+
+void *
+idr_remove(struct idr *idr, int id)
+{
+ void *res;
+
+ mtx_lock(&idr->lock);
+ res = idr_remove_locked(idr, id);
+ mtx_unlock(&idr->lock);
+
+ return (res);
+}
+
+static inline struct idr_layer *
+idr_find_layer_locked(struct idr *idr, int id)
+{
+ struct idr_layer *il;
+ int layer;
+
+ id &= MAX_ID_MASK;
+ il = idr->top;
+ layer = idr->layers - 1;
+ if (il == NULL || id > idr_max(idr))
+ return (NULL);
+ while (layer && il) {
+ il = il->ary[idr_pos(id, layer)];
+ layer--;
+ }
+ return (il);
+}
+
+void *
+idr_replace(struct idr *idr, void *ptr, int id)
+{
+ struct idr_layer *il;
+ void *res;
+ int idx;
+
+ mtx_lock(&idr->lock);
+ il = idr_find_layer_locked(idr, id);
+ idx = id & IDR_MASK;
+
+ /* Replace still returns an error if the item was not allocated. */
+ if (il == NULL || (il->bitmap & (1 << idx))) {
+ res = ERR_PTR(-ENOENT);
+ } else {
+ res = il->ary[idx];
+ il->ary[idx] = ptr;
+ }
+ mtx_unlock(&idr->lock);
+ return (res);
+}
+
+static inline void *
+idr_find_locked(struct idr *idr, int id)
+{
+ struct idr_layer *il;
+ void *res;
+
+ mtx_assert(&idr->lock, MA_OWNED);
+ il = idr_find_layer_locked(idr, id);
+ if (il != NULL)
+ res = il->ary[id & IDR_MASK];
+ else
+ res = NULL;
+ return (res);
+}
+
+void *
+idr_find(struct idr *idr, int id)
+{
+ void *res;
+
+ mtx_lock(&idr->lock);
+ res = idr_find_locked(idr, id);
+ mtx_unlock(&idr->lock);
+ return (res);
+}
+
+void *
+idr_get_next(struct idr *idr, int *nextidp)
+{
+ void *res = NULL;
+ int id = *nextidp;
+
+ mtx_lock(&idr->lock);
+ for (; id <= idr_max(idr); id++) {
+ res = idr_find_locked(idr, id);
+ if (res == NULL)
+ continue;
+ *nextidp = id;
+ break;
+ }
+ mtx_unlock(&idr->lock);
+ return (res);
+}
+
+int
+idr_pre_get(struct idr *idr, gfp_t gfp_mask)
+{
+ struct idr_layer *il, *iln;
+ struct idr_layer *head;
+ int need;
+
+ mtx_lock(&idr->lock);
+ for (;;) {
+ need = idr->layers + 1;
+ for (il = idr->free; il != NULL; il = il->ary[0])
+ need--;
+ mtx_unlock(&idr->lock);
+ if (need <= 0)
+ break;
+ for (head = NULL; need; need--) {
+ iln = malloc(sizeof(*il), M_IDR, M_ZERO | gfp_mask);
+ if (iln == NULL)
+ break;
+ bitmap_fill(&iln->bitmap, IDR_SIZE);
+ if (head != NULL) {
+ il->ary[0] = iln;
+ il = iln;
+ } else
+ head = il = iln;
+ }
+ if (head == NULL)
+ return (0);
+ mtx_lock(&idr->lock);
+ il->ary[0] = idr->free;
+ idr->free = head;
+ }
+ return (1);
+}
+
+static struct idr_layer *
+idr_free_list_get(struct idr *idp)
+{
+ struct idr_layer *il;
+
+ if ((il = idp->free) != NULL) {
+ idp->free = il->ary[0];
+ il->ary[0] = NULL;
+ }
+ return (il);
+}
+
+static inline struct idr_layer *
+idr_get(struct idr *idp)
+{
+ struct idr_layer *il;
+
+ if ((il = idr_free_list_get(idp)) != NULL) {
+ MPASS(il->bitmap != 0);
+ } else if ((il = malloc(sizeof(*il), M_IDR, M_ZERO | M_NOWAIT)) != NULL) {
+ bitmap_fill(&il->bitmap, IDR_SIZE);
+ } else if ((il = idr_preload_dequeue_locked(&DPCPU_GET(linux_idr_cache))) != NULL) {
+ bitmap_fill(&il->bitmap, IDR_SIZE);
+ } else {
+ return (NULL);
+ }
+ return (il);
+}
+
+/*
+ * Could be implemented as get_new_above(idr, ptr, 0, idp) but written
+ * first for simplicity sake.
+ */
+static int
+idr_get_new_locked(struct idr *idr, void *ptr, int *idp)
+{
+ struct idr_layer *stack[MAX_LEVEL];
+ struct idr_layer *il;
+ int error;
+ int layer;
+ int idx;
+ int id;
+
+ mtx_assert(&idr->lock, MA_OWNED);
+
+ error = -EAGAIN;
+ /*
+ * Expand the tree until there is free space.
+ */
+ if (idr->top == NULL || idr->top->bitmap == 0) {
+ if (idr->layers == MAX_LEVEL + 1) {
+ error = -ENOSPC;
+ goto out;
+ }
+ il = idr_get(idr);
+ if (il == NULL)
+ goto out;
+ il->ary[0] = idr->top;
+ if (idr->top)
+ il->bitmap &= ~1;
+ idr->top = il;
+ idr->layers++;
+ }
+ il = idr->top;
+ id = 0;
+ /*
+ * Walk the tree following free bitmaps, record our path.
+ */
+ for (layer = idr->layers - 1;; layer--) {
+ stack[layer] = il;
+ idx = ffsl(il->bitmap);
+ if (idx == 0)
+ panic("idr_get_new: Invalid leaf state (%p, %p)\n",
+ idr, il);
+ idx--;
+ id |= idx << (layer * IDR_BITS);
+ if (layer == 0)
+ break;
+ if (il->ary[idx] == NULL) {
+ il->ary[idx] = idr_get(idr);
+ if (il->ary[idx] == NULL)
+ goto out;
+ }
+ il = il->ary[idx];
+ }
+ /*
+ * Allocate the leaf to the consumer.
+ */
+ il->bitmap &= ~(1 << idx);
+ il->ary[idx] = ptr;
+ *idp = id;
+ /*
+ * Clear bitmaps potentially up to the root.
+ */
+ while (il->bitmap == 0 && ++layer < idr->layers) {
+ il = stack[layer];
+ il->bitmap &= ~(1 << idr_pos(id, layer));
+ }
+ error = 0;
+out:
+#ifdef INVARIANTS
+ if (error == 0 && idr_find_locked(idr, id) != ptr) {
+ panic("idr_get_new: Failed for idr %p, id %d, ptr %p\n",
+ idr, id, ptr);
+ }
+#endif
+ return (error);
+}
+
+int
+idr_get_new(struct idr *idr, void *ptr, int *idp)
+{
+ int retval;
+
+ mtx_lock(&idr->lock);
+ retval = idr_get_new_locked(idr, ptr, idp);
+ mtx_unlock(&idr->lock);
+ return (retval);
+}
+
+static int
+idr_get_new_above_locked(struct idr *idr, void *ptr, int starting_id, int *idp)
+{
+ struct idr_layer *stack[MAX_LEVEL];
+ struct idr_layer *il;
+ int error;
+ int layer;
+ int idx, sidx;
+ int id;
+
+ mtx_assert(&idr->lock, MA_OWNED);
+
+ error = -EAGAIN;
+ /*
+ * Compute the layers required to support starting_id and the mask
+ * at the top layer.
+ */
+restart:
+ idx = starting_id;
+ layer = 0;
+ while (idx & ~IDR_MASK) {
+ layer++;
+ idx >>= IDR_BITS;
+ }
+ if (layer == MAX_LEVEL + 1) {
+ error = -ENOSPC;
+ goto out;
+ }
+ /*
+ * Expand the tree until there is free space at or beyond starting_id.
+ */
+ while (idr->layers <= layer ||
+ idr->top->bitmap < (1 << idr_pos(starting_id, idr->layers - 1))) {
+ if (idr->layers == MAX_LEVEL + 1) {
+ error = -ENOSPC;
+ goto out;
+ }
+ il = idr_get(idr);
+ if (il == NULL)
+ goto out;
+ il->ary[0] = idr->top;
+ if (idr->top && idr->top->bitmap == 0)
+ il->bitmap &= ~1;
+ idr->top = il;
+ idr->layers++;
+ }
+ il = idr->top;
+ id = 0;
+ /*
+ * Walk the tree following free bitmaps, record our path.
+ */
+ for (layer = idr->layers - 1;; layer--) {
+ stack[layer] = il;
+ sidx = idr_pos(starting_id, layer);
+ /* Returns index numbered from 0 or size if none exists. */
+ idx = find_next_bit(&il->bitmap, IDR_SIZE, sidx);
+ if (idx == IDR_SIZE && sidx == 0)
+ panic("idr_get_new: Invalid leaf state (%p, %p)\n",
+ idr, il);
+ /*
+ * We may have walked a path where there was a free bit but
+ * it was lower than what we wanted. Restart the search with
+ * a larger starting id. id contains the progress we made so
+ * far. Search the leaf one above this level. This may
+ * restart as many as MAX_LEVEL times but that is expected
+ * to be rare.
+ */
+ if (idx == IDR_SIZE) {
+ starting_id = id + (1 << ((layer + 1) * IDR_BITS));
+ goto restart;
+ }
+ if (idx > sidx)
+ starting_id = 0; /* Search the whole subtree. */
+ id |= idx << (layer * IDR_BITS);
+ if (layer == 0)
+ break;
+ if (il->ary[idx] == NULL) {
+ il->ary[idx] = idr_get(idr);
+ if (il->ary[idx] == NULL)
+ goto out;
+ }
+ il = il->ary[idx];
+ }
+ /*
+ * Allocate the leaf to the consumer.
+ */
+ il->bitmap &= ~(1 << idx);
+ il->ary[idx] = ptr;
+ *idp = id;
+ /*
+ * Clear bitmaps potentially up to the root.
+ */
+ while (il->bitmap == 0 && ++layer < idr->layers) {
+ il = stack[layer];
+ il->bitmap &= ~(1 << idr_pos(id, layer));
+ }
+ error = 0;
+out:
+#ifdef INVARIANTS
+ if (error == 0 && idr_find_locked(idr, id) != ptr) {
+ panic("idr_get_new_above: Failed for idr %p, id %d, ptr %p\n",
+ idr, id, ptr);
+ }
+#endif
+ return (error);
+}
+
+int
+idr_get_new_above(struct idr *idr, void *ptr, int starting_id, int *idp)
+{
+ int retval;
+
+ mtx_lock(&idr->lock);
+ retval = idr_get_new_above_locked(idr, ptr, starting_id, idp);
+ mtx_unlock(&idr->lock);
+ return (retval);
+}
+
+int
+ida_get_new_above(struct ida *ida, int starting_id, int *p_id)
+{
+ return (idr_get_new_above(&ida->idr, NULL, starting_id, p_id));
+}
+
+static int
+idr_alloc_locked(struct idr *idr, void *ptr, int start, int end)
+{
+ int max = end > 0 ? end - 1 : INT_MAX;
+ int error;
+ int id;
+
+ mtx_assert(&idr->lock, MA_OWNED);
+
+ if (unlikely(start < 0))
+ return (-EINVAL);
+ if (unlikely(max < start))
+ return (-ENOSPC);
+
+ if (start == 0)
+ error = idr_get_new_locked(idr, ptr, &id);
+ else
+ error = idr_get_new_above_locked(idr, ptr, start, &id);
+
+ if (unlikely(error < 0))
+ return (error);
+ if (unlikely(id > max)) {
+ idr_remove_locked(idr, id);
+ return (-ENOSPC);
+ }
+ return (id);
+}
+
+int
+idr_alloc(struct idr *idr, void *ptr, int start, int end, gfp_t gfp_mask)
+{
+ int retval;
+
+ mtx_lock(&idr->lock);
+ retval = idr_alloc_locked(idr, ptr, start, end);
+ mtx_unlock(&idr->lock);
+ return (retval);
+}
+
+int
+idr_alloc_cyclic(struct idr *idr, void *ptr, int start, int end, gfp_t gfp_mask)
+{
+ int retval;
+
+ mtx_lock(&idr->lock);
+ retval = idr_alloc_locked(idr, ptr, max(start, idr->next_cyclic_id), end);
+ if (unlikely(retval == -ENOSPC))
+ retval = idr_alloc_locked(idr, ptr, start, end);
+ if (likely(retval >= 0))
+ idr->next_cyclic_id = retval + 1;
+ mtx_unlock(&idr->lock);
+ return (retval);
+}
+
+static int
+idr_for_each_layer(struct idr_layer *il, int offset, int layer,
+ int (*f)(int id, void *p, void *data), void *data)
+{
+ int i, err;
+
+ if (il == NULL)
+ return (0);
+ if (layer == 0) {
+ for (i = 0; i < IDR_SIZE; i++) {
+ if (il->ary[i] == NULL)
+ continue;
+ err = f(i + offset, il->ary[i], data);
+ if (err)
+ return (err);
+ }
+ return (0);
+ }
+ for (i = 0; i < IDR_SIZE; i++) {
+ if (il->ary[i] == NULL)
+ continue;
+ err = idr_for_each_layer(il->ary[i],
+ (i + offset) * IDR_SIZE, layer - 1, f, data);
+ if (err)
+ return (err);
+ }
+ return (0);
+}
+
+/* NOTE: It is not allowed to modify the IDR tree while it is being iterated */
+int
+idr_for_each(struct idr *idp, int (*f)(int id, void *p, void *data), void *data)
+{
+ return (idr_for_each_layer(idp->top, 0, idp->layers - 1, f, data));
+}
+
+static int
+idr_has_entry(int id, void *p, void *data)
+{
+
+ return (1);
+}
+
+bool
+idr_is_empty(struct idr *idp)
+{
+
+ return (idr_for_each(idp, idr_has_entry, NULL) == 0);
+}
+
+int
+ida_pre_get(struct ida *ida, gfp_t flags)
+{
+ if (idr_pre_get(&ida->idr, flags) == 0)
+ return (0);
+
+ if (ida->free_bitmap == NULL) {
+ ida->free_bitmap =
+ malloc(sizeof(struct ida_bitmap), M_IDR, flags);
+ }
+ return (ida->free_bitmap != NULL);
+}
+
+int
+ida_simple_get(struct ida *ida, unsigned int start, unsigned int end,
+ gfp_t flags)
+{
+ int ret, id;
+ unsigned int max;
+
+ MPASS((int)start >= 0);
+ MPASS((int)end >= 0);
+
+ if (end == 0)
+ max = 0x80000000;
+ else {
+ MPASS(end > start);
+ max = end - 1;
+ }
+again:
+ if (!ida_pre_get(ida, flags))
+ return (-ENOMEM);
+
+ if ((ret = ida_get_new_above(ida, start, &id)) == 0) {
+ if (id > max) {
+ ida_remove(ida, id);
+ ret = -ENOSPC;
+ } else {
+ ret = id;
+ }
+ }
+ if (__predict_false(ret == -EAGAIN))
+ goto again;
+
+ return (ret);
+}
+
+void
+ida_simple_remove(struct ida *ida, unsigned int id)
+{
+ idr_remove(&ida->idr, id);
+}
+
+void
+ida_remove(struct ida *ida, int id)
+{
+ idr_remove(&ida->idr, id);
+}
+
+void
+ida_init(struct ida *ida)
+{
+ idr_init(&ida->idr);
+}
+
+void
+ida_destroy(struct ida *ida)
+{
+ idr_destroy(&ida->idr);
+ free(ida->free_bitmap, M_IDR);
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_kmod.c b/sys/compat/linuxkpi/common/src/linux_kmod.c
new file mode 100644
index 000000000000..7fd73f0a7f45
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_kmod.c
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2015 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/module.h>
+
+MODULE_VERSION(linuxkpi, 1);
+MODULE_DEPEND(linuxkpi, firmware, 1, 1, 1);
+MODULE_DEPEND(linuxkpi, backlight, 1, 1, 1);
+MODULE_DEPEND(linuxkpi, pci, 1, 1, 1);
diff --git a/sys/compat/linuxkpi/common/src/linux_kthread.c b/sys/compat/linuxkpi/common/src/linux_kthread.c
new file mode 100644
index 000000000000..26afe005ea59
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_kthread.c
@@ -0,0 +1,167 @@
+/*-
+ * Copyright (c) 2017 Hans Petter Selasky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <linux/compat.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+
+#include <sys/bus.h>
+#include <sys/interrupt.h>
+#include <sys/priority.h>
+
+enum {
+ KTHREAD_SHOULD_STOP_MASK = (1 << 0),
+ KTHREAD_SHOULD_PARK_MASK = (1 << 1),
+ KTHREAD_IS_PARKED_MASK = (1 << 2),
+};
+
+bool
+linux_kthread_should_stop_task(struct task_struct *task)
+{
+
+ return (atomic_read(&task->kthread_flags) & KTHREAD_SHOULD_STOP_MASK);
+}
+
+bool
+linux_kthread_should_stop(void)
+{
+
+ return (atomic_read(&current->kthread_flags) & KTHREAD_SHOULD_STOP_MASK);
+}
+
+int
+linux_kthread_stop(struct task_struct *task)
+{
+ int retval;
+
+ /*
+ * Assume task is still alive else caller should not call
+ * kthread_stop():
+ */
+ atomic_or(KTHREAD_SHOULD_STOP_MASK, &task->kthread_flags);
+ kthread_unpark(task);
+ wake_up_process(task);
+ wait_for_completion(&task->exited);
+
+ /*
+ * Get return code and free task structure:
+ */
+ retval = task->task_ret;
+ put_task_struct(task);
+
+ return (retval);
+}
+
+int
+linux_kthread_park(struct task_struct *task)
+{
+
+ atomic_or(KTHREAD_SHOULD_PARK_MASK, &task->kthread_flags);
+ wake_up_process(task);
+ wait_for_completion(&task->parked);
+ return (0);
+}
+
+void
+linux_kthread_parkme(void)
+{
+ struct task_struct *task;
+
+ task = current;
+ set_task_state(task, TASK_PARKED | TASK_UNINTERRUPTIBLE);
+ while (linux_kthread_should_park()) {
+ while ((atomic_fetch_or(KTHREAD_IS_PARKED_MASK,
+ &task->kthread_flags) & KTHREAD_IS_PARKED_MASK) == 0)
+ complete(&task->parked);
+ schedule();
+ set_task_state(task, TASK_PARKED | TASK_UNINTERRUPTIBLE);
+ }
+ atomic_andnot(KTHREAD_IS_PARKED_MASK, &task->kthread_flags);
+ set_task_state(task, TASK_RUNNING);
+}
+
+bool
+linux_kthread_should_park(void)
+{
+ struct task_struct *task;
+
+ task = current;
+ return (atomic_read(&task->kthread_flags) & KTHREAD_SHOULD_PARK_MASK);
+}
+
+void
+linux_kthread_unpark(struct task_struct *task)
+{
+
+ atomic_andnot(KTHREAD_SHOULD_PARK_MASK, &task->kthread_flags);
+ if ((atomic_fetch_andnot(KTHREAD_IS_PARKED_MASK, &task->kthread_flags) &
+ KTHREAD_IS_PARKED_MASK) != 0)
+ wake_up_state(task, TASK_PARKED);
+}
+
+struct task_struct *
+linux_kthread_setup_and_run(struct thread *td, linux_task_fn_t *task_fn, void *arg)
+{
+ struct task_struct *task;
+
+ linux_set_current(td);
+
+ task = td->td_lkpi_task;
+ task->task_fn = task_fn;
+ task->task_data = arg;
+
+ thread_lock(td);
+ /* make sure the scheduler priority is raised */
+ sched_prio(td, PI_SWI(SWI_NET));
+ /* put thread into run-queue */
+ sched_add(td, SRQ_BORING);
+
+ return (task);
+}
+
+void
+linux_kthread_fn(void *arg __unused)
+{
+ struct task_struct *task = current;
+
+ if (linux_kthread_should_stop_task(task) == 0)
+ task->task_ret = task->task_fn(task->task_data);
+
+ if (linux_kthread_should_stop_task(task) != 0) {
+ struct thread *td = curthread;
+
+ /* let kthread_stop() free data */
+ td->td_lkpi_task = NULL;
+
+ /* wakeup kthread_stop() */
+ complete(&task->exited);
+ }
+ kthread_exit();
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_lock.c b/sys/compat/linuxkpi/common/src/linux_lock.c
new file mode 100644
index 000000000000..b04a7738d036
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_lock.c
@@ -0,0 +1,173 @@
+/*-
+ * Copyright (c) 2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/queue.h>
+
+#include <linux/sched.h>
+#include <linux/ww_mutex.h>
+
+struct ww_mutex_thread {
+ TAILQ_ENTRY(ww_mutex_thread) entry;
+ struct thread *thread;
+ struct ww_mutex *lock;
+};
+
+static TAILQ_HEAD(, ww_mutex_thread) ww_mutex_head;
+static struct mtx ww_mutex_global;
+
+static void
+linux_ww_init(void *arg)
+{
+ TAILQ_INIT(&ww_mutex_head);
+ mtx_init(&ww_mutex_global, "lkpi-ww-mtx", NULL, MTX_DEF);
+}
+
+SYSINIT(ww_init, SI_SUB_LOCK, SI_ORDER_SECOND, linux_ww_init, NULL);
+
+static void
+linux_ww_uninit(void *arg)
+{
+ mtx_destroy(&ww_mutex_global);
+}
+
+SYSUNINIT(ww_uninit, SI_SUB_LOCK, SI_ORDER_SECOND, linux_ww_uninit, NULL);
+
+static inline void
+linux_ww_lock(void)
+{
+ mtx_lock(&ww_mutex_global);
+}
+
+static inline void
+linux_ww_unlock(void)
+{
+ mtx_unlock(&ww_mutex_global);
+}
+
+/* lock a mutex with deadlock avoidance */
+int
+linux_ww_mutex_lock_sub(struct ww_mutex *lock,
+ struct ww_acquire_ctx *ctx, int catch_signal)
+{
+ struct task_struct *task;
+ struct ww_mutex_thread entry;
+ struct ww_mutex_thread *other;
+ int retval = 0;
+
+ task = current;
+
+ linux_ww_lock();
+ if (unlikely(sx_try_xlock(&lock->base.sx) == 0)) {
+ entry.thread = curthread;
+ entry.lock = lock;
+ TAILQ_INSERT_TAIL(&ww_mutex_head, &entry, entry);
+
+ do {
+ struct thread *owner = (struct thread *)
+ SX_OWNER(lock->base.sx.sx_lock);
+
+ /* scan for deadlock */
+ TAILQ_FOREACH(other, &ww_mutex_head, entry) {
+ /* skip own thread */
+ if (other == &entry)
+ continue;
+ /*
+ * If another thread is owning our
+ * lock and is at the same time trying
+ * to acquire a lock this thread owns,
+ * that means deadlock.
+ */
+ if (other->thread == owner &&
+ (struct thread *)SX_OWNER(
+ other->lock->base.sx.sx_lock) == curthread) {
+ retval = -EDEADLK;
+ goto done;
+ }
+ }
+ if (catch_signal) {
+ retval = -cv_wait_sig(&lock->condvar, &ww_mutex_global);
+ if (retval != 0) {
+ linux_schedule_save_interrupt_value(task, retval);
+ retval = -EINTR;
+ goto done;
+ }
+ } else {
+ cv_wait(&lock->condvar, &ww_mutex_global);
+ }
+ } while (sx_try_xlock(&lock->base.sx) == 0);
+done:
+ TAILQ_REMOVE(&ww_mutex_head, &entry, entry);
+
+ /* if the lock is free, wakeup next lock waiter, if any */
+ if ((struct thread *)SX_OWNER(lock->base.sx.sx_lock) == NULL)
+ cv_signal(&lock->condvar);
+ }
+
+ if (retval == 0)
+ lock->ctx = ctx;
+ linux_ww_unlock();
+ return (retval);
+}
+
+void
+linux_ww_mutex_unlock_sub(struct ww_mutex *lock)
+{
+ /* protect ww_mutex ownership change */
+ linux_ww_lock();
+ lock->ctx = NULL;
+ sx_xunlock(&lock->base.sx);
+ /* wakeup a lock waiter, if any */
+ cv_signal(&lock->condvar);
+ linux_ww_unlock();
+}
+
+int
+linux_mutex_lock_interruptible(mutex_t *m)
+{
+ int error;
+
+ error = -sx_xlock_sig(&m->sx);
+ if (error != 0) {
+ linux_schedule_save_interrupt_value(current, error);
+ error = -EINTR;
+ }
+ return (error);
+}
+
+int
+linux_down_write_killable(struct rw_semaphore *rw)
+{
+ int error;
+
+ error = -sx_xlock_sig(&rw->sx);
+ if (error != 0) {
+ linux_schedule_save_interrupt_value(current, error);
+ error = -EINTR;
+ }
+ return (error);
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_page.c b/sys/compat/linuxkpi/common/src/linux_page.c
new file mode 100644
index 000000000000..ee41366c53a6
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_page.c
@@ -0,0 +1,277 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2016 Matthew Macy (mmacy@mattmacy.io)
+ * Copyright (c) 2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
+#include <sys/proc.h>
+#include <sys/sched.h>
+
+#include <machine/bus.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_param.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_object.h>
+#include <vm/vm_map.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pageout.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_radix.h>
+#include <vm/vm_reserv.h>
+#include <vm/vm_extern.h>
+
+#include <vm/uma.h>
+#include <vm/uma_int.h>
+
+#include <linux/gfp.h>
+#include <linux/mm.h>
+#include <linux/preempt.h>
+#include <linux/fs.h>
+#include <linux/shmem_fs.h>
+
+void
+si_meminfo(struct sysinfo *si)
+{
+ si->totalram = physmem;
+ si->totalhigh = 0;
+ si->mem_unit = PAGE_SIZE;
+}
+
+void *
+linux_page_address(struct page *page)
+{
+
+ if (page->object != kernel_object) {
+ return (PMAP_HAS_DMAP ?
+ ((void *)(uintptr_t)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(page))) :
+ NULL);
+ }
+ return ((void *)(uintptr_t)(VM_MIN_KERNEL_ADDRESS +
+ IDX_TO_OFF(page->pindex)));
+}
+
+vm_page_t
+linux_alloc_pages(gfp_t flags, unsigned int order)
+{
+ vm_page_t page;
+
+ if (PMAP_HAS_DMAP) {
+ unsigned long npages = 1UL << order;
+ int req = VM_ALLOC_NOOBJ | VM_ALLOC_WIRED | VM_ALLOC_NORMAL;
+
+ if ((flags & M_ZERO) != 0)
+ req |= VM_ALLOC_ZERO;
+ if (order == 0 && (flags & GFP_DMA32) == 0) {
+ page = vm_page_alloc(NULL, 0, req);
+ if (page == NULL)
+ return (NULL);
+ } else {
+ vm_paddr_t pmax = (flags & GFP_DMA32) ?
+ BUS_SPACE_MAXADDR_32BIT : BUS_SPACE_MAXADDR;
+ retry:
+ page = vm_page_alloc_contig(NULL, 0, req,
+ npages, 0, pmax, PAGE_SIZE, 0, VM_MEMATTR_DEFAULT);
+
+ if (page == NULL) {
+ if (flags & M_WAITOK) {
+ if (!vm_page_reclaim_contig(req,
+ npages, 0, pmax, PAGE_SIZE, 0)) {
+ vm_wait(NULL);
+ }
+ flags &= ~M_WAITOK;
+ goto retry;
+ }
+ return (NULL);
+ }
+ }
+ if (flags & M_ZERO) {
+ unsigned long x;
+
+ for (x = 0; x != npages; x++) {
+ vm_page_t pgo = page + x;
+
+ if ((pgo->flags & PG_ZERO) == 0)
+ pmap_zero_page(pgo);
+ }
+ }
+ } else {
+ vm_offset_t vaddr;
+
+ vaddr = linux_alloc_kmem(flags, order);
+ if (vaddr == 0)
+ return (NULL);
+
+ page = PHYS_TO_VM_PAGE(vtophys((void *)vaddr));
+
+ KASSERT(vaddr == (vm_offset_t)page_address(page),
+ ("Page address mismatch"));
+ }
+
+ return (page);
+}
+
+void
+linux_free_pages(vm_page_t page, unsigned int order)
+{
+ if (PMAP_HAS_DMAP) {
+ unsigned long npages = 1UL << order;
+ unsigned long x;
+
+ for (x = 0; x != npages; x++) {
+ vm_page_t pgo = page + x;
+
+ if (vm_page_unwire_noq(pgo))
+ vm_page_free(pgo);
+ }
+ } else {
+ vm_offset_t vaddr;
+
+ vaddr = (vm_offset_t)page_address(page);
+
+ linux_free_kmem(vaddr, order);
+ }
+}
+
+vm_offset_t
+linux_alloc_kmem(gfp_t flags, unsigned int order)
+{
+ size_t size = ((size_t)PAGE_SIZE) << order;
+ vm_offset_t addr;
+
+ if ((flags & GFP_DMA32) == 0) {
+ addr = kmem_malloc(size, flags & GFP_NATIVE_MASK);
+ } else {
+ addr = kmem_alloc_contig(size, flags & GFP_NATIVE_MASK, 0,
+ BUS_SPACE_MAXADDR_32BIT, PAGE_SIZE, 0, VM_MEMATTR_DEFAULT);
+ }
+ return (addr);
+}
+
+void
+linux_free_kmem(vm_offset_t addr, unsigned int order)
+{
+ size_t size = ((size_t)PAGE_SIZE) << order;
+
+ kmem_free(addr, size);
+}
+
+static int
+linux_get_user_pages_internal(vm_map_t map, unsigned long start, int nr_pages,
+ int write, struct page **pages)
+{
+ vm_prot_t prot;
+ size_t len;
+ int count;
+
+ prot = write ? (VM_PROT_READ | VM_PROT_WRITE) : VM_PROT_READ;
+ len = ptoa((vm_offset_t)nr_pages);
+ count = vm_fault_quick_hold_pages(map, start, len, prot, pages, nr_pages);
+ return (count == -1 ? -EFAULT : nr_pages);
+}
+
+int
+__get_user_pages_fast(unsigned long start, int nr_pages, int write,
+ struct page **pages)
+{
+ vm_map_t map;
+ vm_page_t *mp;
+ vm_offset_t va;
+ vm_offset_t end;
+ vm_prot_t prot;
+ int count;
+
+ if (nr_pages == 0 || in_interrupt())
+ return (0);
+
+ MPASS(pages != NULL);
+ map = &curthread->td_proc->p_vmspace->vm_map;
+ end = start + ptoa((vm_offset_t)nr_pages);
+ if (!vm_map_range_valid(map, start, end))
+ return (-EINVAL);
+ prot = write ? (VM_PROT_READ | VM_PROT_WRITE) : VM_PROT_READ;
+ for (count = 0, mp = pages, va = start; va < end;
+ mp++, va += PAGE_SIZE, count++) {
+ *mp = pmap_extract_and_hold(map->pmap, va, prot);
+ if (*mp == NULL)
+ break;
+
+ if ((prot & VM_PROT_WRITE) != 0 &&
+ (*mp)->dirty != VM_PAGE_BITS_ALL) {
+ /*
+ * Explicitly dirty the physical page. Otherwise, the
+ * caller's changes may go unnoticed because they are
+ * performed through an unmanaged mapping or by a DMA
+ * operation.
+ *
+ * The object lock is not held here.
+ * See vm_page_clear_dirty_mask().
+ */
+ vm_page_dirty(*mp);
+ }
+ }
+ return (count);
+}
+
+long
+get_user_pages_remote(struct task_struct *task, struct mm_struct *mm,
+ unsigned long start, unsigned long nr_pages, int gup_flags,
+ struct page **pages, struct vm_area_struct **vmas)
+{
+ vm_map_t map;
+
+ map = &task->task_thread->td_proc->p_vmspace->vm_map;
+ return (linux_get_user_pages_internal(map, start, nr_pages,
+ !!(gup_flags & FOLL_WRITE), pages));
+}
+
+long
+get_user_pages(unsigned long start, unsigned long nr_pages, int gup_flags,
+ struct page **pages, struct vm_area_struct **vmas)
+{
+ vm_map_t map;
+
+ map = &curthread->td_proc->p_vmspace->vm_map;
+ return (linux_get_user_pages_internal(map, start, nr_pages,
+ !!(gup_flags & FOLL_WRITE), pages));
+}
+
+int
+is_vmalloc_addr(const void *addr)
+{
+ return (vtoslab((vm_offset_t)addr & ~UMA_SLAB_MASK) != NULL);
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_pci.c b/sys/compat/linuxkpi/common/src/linux_pci.c
new file mode 100644
index 000000000000..075df3c2adf7
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_pci.c
@@ -0,0 +1,1107 @@
+/*-
+ * Copyright (c) 2015-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/fcntl.h>
+#include <sys/file.h>
+#include <sys/filio.h>
+#include <sys/pciio.h>
+#include <sys/pctrie.h>
+#include <sys/rwlock.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/stdarg.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pci_private.h>
+#include <dev/pci/pci_iov.h>
+#include <dev/backlight/backlight.h>
+
+#include <linux/kobject.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/cdev.h>
+#include <linux/file.h>
+#include <linux/sysfs.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+#include <linux/vmalloc.h>
+#include <linux/pci.h>
+#include <linux/compat.h>
+
+#include <linux/backlight.h>
+
+#include "backlight_if.h"
+#include "pcib_if.h"
+
+/* Undef the linux function macro defined in linux/pci.h */
+#undef pci_get_class
+
+static device_probe_t linux_pci_probe;
+static device_attach_t linux_pci_attach;
+static device_detach_t linux_pci_detach;
+static device_suspend_t linux_pci_suspend;
+static device_resume_t linux_pci_resume;
+static device_shutdown_t linux_pci_shutdown;
+static pci_iov_init_t linux_pci_iov_init;
+static pci_iov_uninit_t linux_pci_iov_uninit;
+static pci_iov_add_vf_t linux_pci_iov_add_vf;
+static int linux_backlight_get_status(device_t dev, struct backlight_props *props);
+static int linux_backlight_update_status(device_t dev, struct backlight_props *props);
+static int linux_backlight_get_info(device_t dev, struct backlight_info *info);
+
+static device_method_t pci_methods[] = {
+ DEVMETHOD(device_probe, linux_pci_probe),
+ DEVMETHOD(device_attach, linux_pci_attach),
+ DEVMETHOD(device_detach, linux_pci_detach),
+ DEVMETHOD(device_suspend, linux_pci_suspend),
+ DEVMETHOD(device_resume, linux_pci_resume),
+ DEVMETHOD(device_shutdown, linux_pci_shutdown),
+ DEVMETHOD(pci_iov_init, linux_pci_iov_init),
+ DEVMETHOD(pci_iov_uninit, linux_pci_iov_uninit),
+ DEVMETHOD(pci_iov_add_vf, linux_pci_iov_add_vf),
+
+ /* backlight interface */
+ DEVMETHOD(backlight_update_status, linux_backlight_update_status),
+ DEVMETHOD(backlight_get_status, linux_backlight_get_status),
+ DEVMETHOD(backlight_get_info, linux_backlight_get_info),
+ DEVMETHOD_END
+};
+
+struct linux_dma_priv {
+ uint64_t dma_mask;
+ struct mtx lock;
+ bus_dma_tag_t dmat;
+ struct pctrie ptree;
+};
+#define DMA_PRIV_LOCK(priv) mtx_lock(&(priv)->lock)
+#define DMA_PRIV_UNLOCK(priv) mtx_unlock(&(priv)->lock)
+
+static int
+linux_pdev_dma_init(struct pci_dev *pdev)
+{
+ struct linux_dma_priv *priv;
+ int error;
+
+ priv = malloc(sizeof(*priv), M_DEVBUF, M_WAITOK | M_ZERO);
+ pdev->dev.dma_priv = priv;
+
+ mtx_init(&priv->lock, "lkpi-priv-dma", NULL, MTX_DEF);
+
+ pctrie_init(&priv->ptree);
+
+ /* create a default DMA tag */
+ error = linux_dma_tag_init(&pdev->dev, DMA_BIT_MASK(64));
+ if (error) {
+ mtx_destroy(&priv->lock);
+ free(priv, M_DEVBUF);
+ pdev->dev.dma_priv = NULL;
+ }
+ return (error);
+}
+
+static int
+linux_pdev_dma_uninit(struct pci_dev *pdev)
+{
+ struct linux_dma_priv *priv;
+
+ priv = pdev->dev.dma_priv;
+ if (priv->dmat)
+ bus_dma_tag_destroy(priv->dmat);
+ mtx_destroy(&priv->lock);
+ free(priv, M_DEVBUF);
+ pdev->dev.dma_priv = NULL;
+ return (0);
+}
+
+int
+linux_dma_tag_init(struct device *dev, u64 dma_mask)
+{
+ struct linux_dma_priv *priv;
+ int error;
+
+ priv = dev->dma_priv;
+
+ if (priv->dmat) {
+ if (priv->dma_mask == dma_mask)
+ return (0);
+
+ bus_dma_tag_destroy(priv->dmat);
+ }
+
+ priv->dma_mask = dma_mask;
+
+ error = bus_dma_tag_create(bus_get_dma_tag(dev->bsddev),
+ 1, 0, /* alignment, boundary */
+ dma_mask, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filtfunc, filtfuncarg */
+ BUS_SPACE_MAXSIZE, /* maxsize */
+ 1, /* nsegments */
+ BUS_SPACE_MAXSIZE, /* maxsegsz */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockfuncarg */
+ &priv->dmat);
+ return (-error);
+}
+
+static struct pci_driver *
+linux_pci_find(device_t dev, const struct pci_device_id **idp)
+{
+ const struct pci_device_id *id;
+ struct pci_driver *pdrv;
+ uint16_t vendor;
+ uint16_t device;
+ uint16_t subvendor;
+ uint16_t subdevice;
+
+ vendor = pci_get_vendor(dev);
+ device = pci_get_device(dev);
+ subvendor = pci_get_subvendor(dev);
+ subdevice = pci_get_subdevice(dev);
+
+ spin_lock(&pci_lock);
+ list_for_each_entry(pdrv, &pci_drivers, links) {
+ for (id = pdrv->id_table; id->vendor != 0; id++) {
+ if (vendor == id->vendor &&
+ (PCI_ANY_ID == id->device || device == id->device) &&
+ (PCI_ANY_ID == id->subvendor || subvendor == id->subvendor) &&
+ (PCI_ANY_ID == id->subdevice || subdevice == id->subdevice)) {
+ *idp = id;
+ spin_unlock(&pci_lock);
+ return (pdrv);
+ }
+ }
+ }
+ spin_unlock(&pci_lock);
+ return (NULL);
+}
+
+static void
+lkpifill_pci_dev(device_t dev, struct pci_dev *pdev)
+{
+
+ pdev->devfn = PCI_DEVFN(pci_get_slot(dev), pci_get_function(dev));
+ pdev->vendor = pci_get_vendor(dev);
+ pdev->device = pci_get_device(dev);
+ pdev->subsystem_vendor = pci_get_subvendor(dev);
+ pdev->subsystem_device = pci_get_subdevice(dev);
+ pdev->class = pci_get_class(dev);
+ pdev->revision = pci_get_revid(dev);
+ pdev->bus = malloc(sizeof(*pdev->bus), M_DEVBUF, M_WAITOK | M_ZERO);
+ pdev->bus->self = pdev;
+ pdev->bus->number = pci_get_bus(dev);
+ pdev->bus->domain = pci_get_domain(dev);
+ pdev->dev.bsddev = dev;
+ pdev->dev.parent = &linux_root_device;
+ INIT_LIST_HEAD(&pdev->dev.irqents);
+ kobject_init(&pdev->dev.kobj, &linux_dev_ktype);
+ kobject_set_name(&pdev->dev.kobj, device_get_nameunit(dev));
+ kobject_add(&pdev->dev.kobj, &linux_root_device.kobj,
+ kobject_name(&pdev->dev.kobj));
+}
+
+static void
+lkpinew_pci_dev_release(struct device *dev)
+{
+ struct pci_dev *pdev;
+
+ pdev = to_pci_dev(dev);
+ free(pdev->bus, M_DEVBUF);
+ free(pdev, M_DEVBUF);
+}
+
+static struct pci_dev *
+lkpinew_pci_dev(device_t dev)
+{
+ struct pci_dev *pdev;
+
+ pdev = malloc(sizeof(*pdev), M_DEVBUF, M_WAITOK|M_ZERO);
+ lkpifill_pci_dev(dev, pdev);
+ pdev->dev.release = lkpinew_pci_dev_release;
+
+ return (pdev);
+}
+
+struct pci_dev *
+lkpi_pci_get_class(unsigned int class, struct pci_dev *from)
+{
+ device_t dev;
+ device_t devfrom = NULL;
+ struct pci_dev *pdev;
+
+ if (from != NULL)
+ devfrom = from->dev.bsddev;
+
+ dev = pci_find_class_from(class >> 16, (class >> 8) & 0xFF, devfrom);
+ if (dev == NULL)
+ return (NULL);
+
+ pdev = lkpinew_pci_dev(dev);
+ return (pdev);
+}
+
+struct pci_dev *
+lkpi_pci_get_domain_bus_and_slot(int domain, unsigned int bus,
+ unsigned int devfn)
+{
+ device_t dev;
+ struct pci_dev *pdev;
+
+ dev = pci_find_dbsf(domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+ if (dev == NULL)
+ return (NULL);
+
+ pdev = lkpinew_pci_dev(dev);
+ return (pdev);
+}
+
+static int
+linux_pci_probe(device_t dev)
+{
+ const struct pci_device_id *id;
+ struct pci_driver *pdrv;
+
+ if ((pdrv = linux_pci_find(dev, &id)) == NULL)
+ return (ENXIO);
+ if (device_get_driver(dev) != &pdrv->bsddriver)
+ return (ENXIO);
+ device_set_desc(dev, pdrv->name);
+ return (0);
+}
+
+static int
+linux_pci_attach(device_t dev)
+{
+ const struct pci_device_id *id;
+ struct pci_driver *pdrv;
+ struct pci_dev *pdev;
+
+ pdrv = linux_pci_find(dev, &id);
+ pdev = device_get_softc(dev);
+
+ MPASS(pdrv != NULL);
+ MPASS(pdev != NULL);
+
+ return (linux_pci_attach_device(dev, pdrv, id, pdev));
+}
+
+int
+linux_pci_attach_device(device_t dev, struct pci_driver *pdrv,
+ const struct pci_device_id *id, struct pci_dev *pdev)
+{
+ struct resource_list_entry *rle;
+ device_t parent;
+ uintptr_t rid;
+ int error;
+ bool isdrm;
+
+ linux_set_current(curthread);
+
+ parent = device_get_parent(dev);
+ isdrm = pdrv != NULL && pdrv->isdrm;
+
+ if (isdrm) {
+ struct pci_devinfo *dinfo;
+
+ dinfo = device_get_ivars(parent);
+ device_set_ivars(dev, dinfo);
+ }
+
+ lkpifill_pci_dev(dev, pdev);
+ if (isdrm)
+ PCI_GET_ID(device_get_parent(parent), parent, PCI_ID_RID, &rid);
+ else
+ PCI_GET_ID(parent, dev, PCI_ID_RID, &rid);
+ pdev->devfn = rid;
+ pdev->pdrv = pdrv;
+ rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 0);
+ if (rle != NULL)
+ pdev->dev.irq = rle->start;
+ else
+ pdev->dev.irq = LINUX_IRQ_INVALID;
+ pdev->irq = pdev->dev.irq;
+ error = linux_pdev_dma_init(pdev);
+ if (error)
+ goto out_dma_init;
+
+ TAILQ_INIT(&pdev->mmio);
+
+ spin_lock(&pci_lock);
+ list_add(&pdev->links, &pci_devices);
+ spin_unlock(&pci_lock);
+
+ if (pdrv != NULL) {
+ error = pdrv->probe(pdev, id);
+ if (error)
+ goto out_probe;
+ }
+ return (0);
+
+out_probe:
+ free(pdev->bus, M_DEVBUF);
+ linux_pdev_dma_uninit(pdev);
+out_dma_init:
+ spin_lock(&pci_lock);
+ list_del(&pdev->links);
+ spin_unlock(&pci_lock);
+ put_device(&pdev->dev);
+ return (-error);
+}
+
+static int
+linux_pci_detach(device_t dev)
+{
+ struct pci_dev *pdev;
+
+ pdev = device_get_softc(dev);
+
+ MPASS(pdev != NULL);
+
+ device_set_desc(dev, NULL);
+
+ return (linux_pci_detach_device(pdev));
+}
+
+int
+linux_pci_detach_device(struct pci_dev *pdev)
+{
+
+ linux_set_current(curthread);
+
+ if (pdev->pdrv != NULL)
+ pdev->pdrv->remove(pdev);
+
+ free(pdev->bus, M_DEVBUF);
+ linux_pdev_dma_uninit(pdev);
+
+ spin_lock(&pci_lock);
+ list_del(&pdev->links);
+ spin_unlock(&pci_lock);
+ put_device(&pdev->dev);
+
+ return (0);
+}
+
+static int
+linux_pci_suspend(device_t dev)
+{
+ const struct dev_pm_ops *pmops;
+ struct pm_message pm = { };
+ struct pci_dev *pdev;
+ int error;
+
+ error = 0;
+ linux_set_current(curthread);
+ pdev = device_get_softc(dev);
+ pmops = pdev->pdrv->driver.pm;
+
+ if (pdev->pdrv->suspend != NULL)
+ error = -pdev->pdrv->suspend(pdev, pm);
+ else if (pmops != NULL && pmops->suspend != NULL) {
+ error = -pmops->suspend(&pdev->dev);
+ if (error == 0 && pmops->suspend_late != NULL)
+ error = -pmops->suspend_late(&pdev->dev);
+ }
+ return (error);
+}
+
+static int
+linux_pci_resume(device_t dev)
+{
+ const struct dev_pm_ops *pmops;
+ struct pci_dev *pdev;
+ int error;
+
+ error = 0;
+ linux_set_current(curthread);
+ pdev = device_get_softc(dev);
+ pmops = pdev->pdrv->driver.pm;
+
+ if (pdev->pdrv->resume != NULL)
+ error = -pdev->pdrv->resume(pdev);
+ else if (pmops != NULL && pmops->resume != NULL) {
+ if (pmops->resume_early != NULL)
+ error = -pmops->resume_early(&pdev->dev);
+ if (error == 0 && pmops->resume != NULL)
+ error = -pmops->resume(&pdev->dev);
+ }
+ return (error);
+}
+
+static int
+linux_pci_shutdown(device_t dev)
+{
+ struct pci_dev *pdev;
+
+ linux_set_current(curthread);
+ pdev = device_get_softc(dev);
+ if (pdev->pdrv->shutdown != NULL)
+ pdev->pdrv->shutdown(pdev);
+ return (0);
+}
+
+static int
+linux_pci_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *pf_config)
+{
+ struct pci_dev *pdev;
+ int error;
+
+ linux_set_current(curthread);
+ pdev = device_get_softc(dev);
+ if (pdev->pdrv->bsd_iov_init != NULL)
+ error = pdev->pdrv->bsd_iov_init(dev, num_vfs, pf_config);
+ else
+ error = EINVAL;
+ return (error);
+}
+
+static void
+linux_pci_iov_uninit(device_t dev)
+{
+ struct pci_dev *pdev;
+
+ linux_set_current(curthread);
+ pdev = device_get_softc(dev);
+ if (pdev->pdrv->bsd_iov_uninit != NULL)
+ pdev->pdrv->bsd_iov_uninit(dev);
+}
+
+static int
+linux_pci_iov_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *vf_config)
+{
+ struct pci_dev *pdev;
+ int error;
+
+ linux_set_current(curthread);
+ pdev = device_get_softc(dev);
+ if (pdev->pdrv->bsd_iov_add_vf != NULL)
+ error = pdev->pdrv->bsd_iov_add_vf(dev, vfnum, vf_config);
+ else
+ error = EINVAL;
+ return (error);
+}
+
+static int
+_linux_pci_register_driver(struct pci_driver *pdrv, devclass_t dc)
+{
+ int error;
+
+ linux_set_current(curthread);
+ spin_lock(&pci_lock);
+ list_add(&pdrv->links, &pci_drivers);
+ spin_unlock(&pci_lock);
+ pdrv->bsddriver.name = pdrv->name;
+ pdrv->bsddriver.methods = pci_methods;
+ pdrv->bsddriver.size = sizeof(struct pci_dev);
+
+ mtx_lock(&Giant);
+ error = devclass_add_driver(dc, &pdrv->bsddriver,
+ BUS_PASS_DEFAULT, &pdrv->bsdclass);
+ mtx_unlock(&Giant);
+ return (-error);
+}
+
+int
+linux_pci_register_driver(struct pci_driver *pdrv)
+{
+ devclass_t dc;
+
+ dc = devclass_find("pci");
+ if (dc == NULL)
+ return (-ENXIO);
+ pdrv->isdrm = false;
+ return (_linux_pci_register_driver(pdrv, dc));
+}
+
+unsigned long
+pci_resource_start(struct pci_dev *pdev, int bar)
+{
+ struct resource_list_entry *rle;
+ rman_res_t newstart;
+ device_t dev;
+
+ if ((rle = linux_pci_get_bar(pdev, bar)) == NULL)
+ return (0);
+ dev = pdev->pdrv != NULL && pdev->pdrv->isdrm ?
+ device_get_parent(pdev->dev.bsddev) : pdev->dev.bsddev;
+ if (BUS_TRANSLATE_RESOURCE(dev, rle->type, rle->start, &newstart)) {
+ device_printf(pdev->dev.bsddev, "translate of %#jx failed\n",
+ (uintmax_t)rle->start);
+ return (0);
+ }
+ return (newstart);
+}
+
+unsigned long
+pci_resource_len(struct pci_dev *pdev, int bar)
+{
+ struct resource_list_entry *rle;
+
+ if ((rle = linux_pci_get_bar(pdev, bar)) == NULL)
+ return (0);
+ return (rle->count);
+}
+
+int
+linux_pci_register_drm_driver(struct pci_driver *pdrv)
+{
+ devclass_t dc;
+
+ dc = devclass_create("vgapci");
+ if (dc == NULL)
+ return (-ENXIO);
+ pdrv->isdrm = true;
+ pdrv->name = "drmn";
+ return (_linux_pci_register_driver(pdrv, dc));
+}
+
+void
+linux_pci_unregister_driver(struct pci_driver *pdrv)
+{
+ devclass_t bus;
+
+ bus = devclass_find("pci");
+
+ spin_lock(&pci_lock);
+ list_del(&pdrv->links);
+ spin_unlock(&pci_lock);
+ mtx_lock(&Giant);
+ if (bus != NULL)
+ devclass_delete_driver(bus, &pdrv->bsddriver);
+ mtx_unlock(&Giant);
+}
+
+void
+linux_pci_unregister_drm_driver(struct pci_driver *pdrv)
+{
+ devclass_t bus;
+
+ bus = devclass_find("vgapci");
+
+ spin_lock(&pci_lock);
+ list_del(&pdrv->links);
+ spin_unlock(&pci_lock);
+ mtx_lock(&Giant);
+ if (bus != NULL)
+ devclass_delete_driver(bus, &pdrv->bsddriver);
+ mtx_unlock(&Giant);
+}
+
+CTASSERT(sizeof(dma_addr_t) <= sizeof(uint64_t));
+
+struct linux_dma_obj {
+ void *vaddr;
+ uint64_t dma_addr;
+ bus_dmamap_t dmamap;
+};
+
+static uma_zone_t linux_dma_trie_zone;
+static uma_zone_t linux_dma_obj_zone;
+
+static void
+linux_dma_init(void *arg)
+{
+
+ linux_dma_trie_zone = uma_zcreate("linux_dma_pctrie",
+ pctrie_node_size(), NULL, NULL, pctrie_zone_init, NULL,
+ UMA_ALIGN_PTR, 0);
+ linux_dma_obj_zone = uma_zcreate("linux_dma_object",
+ sizeof(struct linux_dma_obj), NULL, NULL, NULL, NULL,
+ UMA_ALIGN_PTR, 0);
+
+}
+SYSINIT(linux_dma, SI_SUB_DRIVERS, SI_ORDER_THIRD, linux_dma_init, NULL);
+
+static void
+linux_dma_uninit(void *arg)
+{
+
+ uma_zdestroy(linux_dma_obj_zone);
+ uma_zdestroy(linux_dma_trie_zone);
+}
+SYSUNINIT(linux_dma, SI_SUB_DRIVERS, SI_ORDER_THIRD, linux_dma_uninit, NULL);
+
+static void *
+linux_dma_trie_alloc(struct pctrie *ptree)
+{
+
+ return (uma_zalloc(linux_dma_trie_zone, M_NOWAIT));
+}
+
+static void
+linux_dma_trie_free(struct pctrie *ptree, void *node)
+{
+
+ uma_zfree(linux_dma_trie_zone, node);
+}
+
+PCTRIE_DEFINE(LINUX_DMA, linux_dma_obj, dma_addr, linux_dma_trie_alloc,
+ linux_dma_trie_free);
+
+void *
+linux_dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag)
+{
+ struct linux_dma_priv *priv;
+ vm_paddr_t high;
+ size_t align;
+ void *mem;
+
+ if (dev == NULL || dev->dma_priv == NULL) {
+ *dma_handle = 0;
+ return (NULL);
+ }
+ priv = dev->dma_priv;
+ if (priv->dma_mask)
+ high = priv->dma_mask;
+ else if (flag & GFP_DMA32)
+ high = BUS_SPACE_MAXADDR_32BIT;
+ else
+ high = BUS_SPACE_MAXADDR;
+ align = PAGE_SIZE << get_order(size);
+ mem = (void *)kmem_alloc_contig(size, flag & GFP_NATIVE_MASK, 0, high,
+ align, 0, VM_MEMATTR_DEFAULT);
+ if (mem != NULL) {
+ *dma_handle = linux_dma_map_phys(dev, vtophys(mem), size);
+ if (*dma_handle == 0) {
+ kmem_free((vm_offset_t)mem, size);
+ mem = NULL;
+ }
+ } else {
+ *dma_handle = 0;
+ }
+ return (mem);
+}
+
+#if defined(__i386__) || defined(__amd64__) || defined(__aarch64__)
+dma_addr_t
+linux_dma_map_phys(struct device *dev, vm_paddr_t phys, size_t len)
+{
+ struct linux_dma_priv *priv;
+ struct linux_dma_obj *obj;
+ int error, nseg;
+ bus_dma_segment_t seg;
+
+ priv = dev->dma_priv;
+
+ /*
+ * If the resultant mapping will be entirely 1:1 with the
+ * physical address, short-circuit the remainder of the
+ * bus_dma API. This avoids tracking collisions in the pctrie
+ * with the additional benefit of reducing overhead.
+ */
+ if (bus_dma_id_mapped(priv->dmat, phys, len))
+ return (phys);
+
+ obj = uma_zalloc(linux_dma_obj_zone, M_NOWAIT);
+ if (obj == NULL) {
+ return (0);
+ }
+
+ DMA_PRIV_LOCK(priv);
+ if (bus_dmamap_create(priv->dmat, 0, &obj->dmamap) != 0) {
+ DMA_PRIV_UNLOCK(priv);
+ uma_zfree(linux_dma_obj_zone, obj);
+ return (0);
+ }
+
+ nseg = -1;
+ if (_bus_dmamap_load_phys(priv->dmat, obj->dmamap, phys, len,
+ BUS_DMA_NOWAIT, &seg, &nseg) != 0) {
+ bus_dmamap_destroy(priv->dmat, obj->dmamap);
+ DMA_PRIV_UNLOCK(priv);
+ uma_zfree(linux_dma_obj_zone, obj);
+ return (0);
+ }
+
+ KASSERT(++nseg == 1, ("More than one segment (nseg=%d)", nseg));
+ obj->dma_addr = seg.ds_addr;
+
+ error = LINUX_DMA_PCTRIE_INSERT(&priv->ptree, obj);
+ if (error != 0) {
+ bus_dmamap_unload(priv->dmat, obj->dmamap);
+ bus_dmamap_destroy(priv->dmat, obj->dmamap);
+ DMA_PRIV_UNLOCK(priv);
+ uma_zfree(linux_dma_obj_zone, obj);
+ return (0);
+ }
+ DMA_PRIV_UNLOCK(priv);
+ return (obj->dma_addr);
+}
+#else
+dma_addr_t
+linux_dma_map_phys(struct device *dev, vm_paddr_t phys, size_t len)
+{
+ return (phys);
+}
+#endif
+
+#if defined(__i386__) || defined(__amd64__) || defined(__aarch64__)
+void
+linux_dma_unmap(struct device *dev, dma_addr_t dma_addr, size_t len)
+{
+ struct linux_dma_priv *priv;
+ struct linux_dma_obj *obj;
+
+ priv = dev->dma_priv;
+
+ if (pctrie_is_empty(&priv->ptree))
+ return;
+
+ DMA_PRIV_LOCK(priv);
+ obj = LINUX_DMA_PCTRIE_LOOKUP(&priv->ptree, dma_addr);
+ if (obj == NULL) {
+ DMA_PRIV_UNLOCK(priv);
+ return;
+ }
+ LINUX_DMA_PCTRIE_REMOVE(&priv->ptree, dma_addr);
+ bus_dmamap_unload(priv->dmat, obj->dmamap);
+ bus_dmamap_destroy(priv->dmat, obj->dmamap);
+ DMA_PRIV_UNLOCK(priv);
+
+ uma_zfree(linux_dma_obj_zone, obj);
+}
+#else
+void
+linux_dma_unmap(struct device *dev, dma_addr_t dma_addr, size_t len)
+{
+}
+#endif
+
+int
+linux_dma_map_sg_attrs(struct device *dev, struct scatterlist *sgl, int nents,
+ enum dma_data_direction dir, struct dma_attrs *attrs)
+{
+ struct linux_dma_priv *priv;
+ struct scatterlist *sg;
+ int i, nseg;
+ bus_dma_segment_t seg;
+
+ priv = dev->dma_priv;
+
+ DMA_PRIV_LOCK(priv);
+
+ /* create common DMA map in the first S/G entry */
+ if (bus_dmamap_create(priv->dmat, 0, &sgl->dma_map) != 0) {
+ DMA_PRIV_UNLOCK(priv);
+ return (0);
+ }
+
+ /* load all S/G list entries */
+ for_each_sg(sgl, sg, nents, i) {
+ nseg = -1;
+ if (_bus_dmamap_load_phys(priv->dmat, sgl->dma_map,
+ sg_phys(sg), sg->length, BUS_DMA_NOWAIT,
+ &seg, &nseg) != 0) {
+ bus_dmamap_unload(priv->dmat, sgl->dma_map);
+ bus_dmamap_destroy(priv->dmat, sgl->dma_map);
+ DMA_PRIV_UNLOCK(priv);
+ return (0);
+ }
+ KASSERT(nseg == 0,
+ ("More than one segment (nseg=%d)", nseg + 1));
+
+ sg_dma_address(sg) = seg.ds_addr;
+ }
+ DMA_PRIV_UNLOCK(priv);
+
+ return (nents);
+}
+
+void
+linux_dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sgl,
+ int nents, enum dma_data_direction dir, struct dma_attrs *attrs)
+{
+ struct linux_dma_priv *priv;
+
+ priv = dev->dma_priv;
+
+ DMA_PRIV_LOCK(priv);
+ bus_dmamap_unload(priv->dmat, sgl->dma_map);
+ bus_dmamap_destroy(priv->dmat, sgl->dma_map);
+ DMA_PRIV_UNLOCK(priv);
+}
+
+struct dma_pool {
+ struct device *pool_device;
+ uma_zone_t pool_zone;
+ struct mtx pool_lock;
+ bus_dma_tag_t pool_dmat;
+ size_t pool_entry_size;
+ struct pctrie pool_ptree;
+};
+
+#define DMA_POOL_LOCK(pool) mtx_lock(&(pool)->pool_lock)
+#define DMA_POOL_UNLOCK(pool) mtx_unlock(&(pool)->pool_lock)
+
+static inline int
+dma_pool_obj_ctor(void *mem, int size, void *arg, int flags)
+{
+ struct linux_dma_obj *obj = mem;
+ struct dma_pool *pool = arg;
+ int error, nseg;
+ bus_dma_segment_t seg;
+
+ nseg = -1;
+ DMA_POOL_LOCK(pool);
+ error = _bus_dmamap_load_phys(pool->pool_dmat, obj->dmamap,
+ vtophys(obj->vaddr), pool->pool_entry_size, BUS_DMA_NOWAIT,
+ &seg, &nseg);
+ DMA_POOL_UNLOCK(pool);
+ if (error != 0) {
+ return (error);
+ }
+ KASSERT(++nseg == 1, ("More than one segment (nseg=%d)", nseg));
+ obj->dma_addr = seg.ds_addr;
+
+ return (0);
+}
+
+static void
+dma_pool_obj_dtor(void *mem, int size, void *arg)
+{
+ struct linux_dma_obj *obj = mem;
+ struct dma_pool *pool = arg;
+
+ DMA_POOL_LOCK(pool);
+ bus_dmamap_unload(pool->pool_dmat, obj->dmamap);
+ DMA_POOL_UNLOCK(pool);
+}
+
+static int
+dma_pool_obj_import(void *arg, void **store, int count, int domain __unused,
+ int flags)
+{
+ struct dma_pool *pool = arg;
+ struct linux_dma_priv *priv;
+ struct linux_dma_obj *obj;
+ int error, i;
+
+ priv = pool->pool_device->dma_priv;
+ for (i = 0; i < count; i++) {
+ obj = uma_zalloc(linux_dma_obj_zone, flags);
+ if (obj == NULL)
+ break;
+
+ error = bus_dmamem_alloc(pool->pool_dmat, &obj->vaddr,
+ BUS_DMA_NOWAIT, &obj->dmamap);
+ if (error!= 0) {
+ uma_zfree(linux_dma_obj_zone, obj);
+ break;
+ }
+
+ store[i] = obj;
+ }
+
+ return (i);
+}
+
+static void
+dma_pool_obj_release(void *arg, void **store, int count)
+{
+ struct dma_pool *pool = arg;
+ struct linux_dma_priv *priv;
+ struct linux_dma_obj *obj;
+ int i;
+
+ priv = pool->pool_device->dma_priv;
+ for (i = 0; i < count; i++) {
+ obj = store[i];
+ bus_dmamem_free(pool->pool_dmat, obj->vaddr, obj->dmamap);
+ uma_zfree(linux_dma_obj_zone, obj);
+ }
+}
+
+struct dma_pool *
+linux_dma_pool_create(char *name, struct device *dev, size_t size,
+ size_t align, size_t boundary)
+{
+ struct linux_dma_priv *priv;
+ struct dma_pool *pool;
+
+ priv = dev->dma_priv;
+
+ pool = kzalloc(sizeof(*pool), GFP_KERNEL);
+ pool->pool_device = dev;
+ pool->pool_entry_size = size;
+
+ if (bus_dma_tag_create(bus_get_dma_tag(dev->bsddev),
+ align, boundary, /* alignment, boundary */
+ priv->dma_mask, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filtfunc, filtfuncarg */
+ size, /* maxsize */
+ 1, /* nsegments */
+ size, /* maxsegsz */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockfuncarg */
+ &pool->pool_dmat)) {
+ kfree(pool);
+ return (NULL);
+ }
+
+ pool->pool_zone = uma_zcache_create(name, -1, dma_pool_obj_ctor,
+ dma_pool_obj_dtor, NULL, NULL, dma_pool_obj_import,
+ dma_pool_obj_release, pool, 0);
+
+ mtx_init(&pool->pool_lock, "lkpi-dma-pool", NULL, MTX_DEF);
+ pctrie_init(&pool->pool_ptree);
+
+ return (pool);
+}
+
+void
+linux_dma_pool_destroy(struct dma_pool *pool)
+{
+
+ uma_zdestroy(pool->pool_zone);
+ bus_dma_tag_destroy(pool->pool_dmat);
+ mtx_destroy(&pool->pool_lock);
+ kfree(pool);
+}
+
+void *
+linux_dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags,
+ dma_addr_t *handle)
+{
+ struct linux_dma_obj *obj;
+
+ obj = uma_zalloc_arg(pool->pool_zone, pool, mem_flags & GFP_NATIVE_MASK);
+ if (obj == NULL)
+ return (NULL);
+
+ DMA_POOL_LOCK(pool);
+ if (LINUX_DMA_PCTRIE_INSERT(&pool->pool_ptree, obj) != 0) {
+ DMA_POOL_UNLOCK(pool);
+ uma_zfree_arg(pool->pool_zone, obj, pool);
+ return (NULL);
+ }
+ DMA_POOL_UNLOCK(pool);
+
+ *handle = obj->dma_addr;
+ return (obj->vaddr);
+}
+
+void
+linux_dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t dma_addr)
+{
+ struct linux_dma_obj *obj;
+
+ DMA_POOL_LOCK(pool);
+ obj = LINUX_DMA_PCTRIE_LOOKUP(&pool->pool_ptree, dma_addr);
+ if (obj == NULL) {
+ DMA_POOL_UNLOCK(pool);
+ return;
+ }
+ LINUX_DMA_PCTRIE_REMOVE(&pool->pool_ptree, dma_addr);
+ DMA_POOL_UNLOCK(pool);
+
+ uma_zfree_arg(pool->pool_zone, obj, pool);
+}
+
+static int
+linux_backlight_get_status(device_t dev, struct backlight_props *props)
+{
+ struct pci_dev *pdev;
+
+ linux_set_current(curthread);
+ pdev = device_get_softc(dev);
+
+ props->brightness = pdev->dev.bd->props.brightness;
+ props->brightness = props->brightness * 100 / pdev->dev.bd->props.max_brightness;
+ props->nlevels = 0;
+
+ return (0);
+}
+
+static int
+linux_backlight_get_info(device_t dev, struct backlight_info *info)
+{
+ struct pci_dev *pdev;
+
+ linux_set_current(curthread);
+ pdev = device_get_softc(dev);
+
+ info->type = BACKLIGHT_TYPE_PANEL;
+ strlcpy(info->name, pdev->dev.bd->name, BACKLIGHTMAXNAMELENGTH);
+ return (0);
+}
+
+static int
+linux_backlight_update_status(device_t dev, struct backlight_props *props)
+{
+ struct pci_dev *pdev;
+
+ linux_set_current(curthread);
+ pdev = device_get_softc(dev);
+
+ pdev->dev.bd->props.brightness = pdev->dev.bd->props.max_brightness *
+ props->brightness / 100;
+ return (pdev->dev.bd->ops->update_status(pdev->dev.bd));
+}
+
+struct backlight_device *
+linux_backlight_device_register(const char *name, struct device *dev,
+ void *data, const struct backlight_ops *ops, struct backlight_properties *props)
+{
+
+ dev->bd = malloc(sizeof(*dev->bd), M_DEVBUF, M_WAITOK | M_ZERO);
+ dev->bd->ops = ops;
+ dev->bd->props.type = props->type;
+ dev->bd->props.max_brightness = props->max_brightness;
+ dev->bd->props.brightness = props->brightness;
+ dev->bd->props.power = props->power;
+ dev->bd->data = data;
+ dev->bd->dev = dev;
+ dev->bd->name = strdup(name, M_DEVBUF);
+
+ dev->backlight_dev = backlight_register(name, dev->bsddev);
+
+ return (dev->bd);
+}
+
+void
+linux_backlight_device_unregister(struct backlight_device *bd)
+{
+
+ backlight_destroy(bd->dev->backlight_dev);
+ free(bd->name, M_DEVBUF);
+ free(bd, M_DEVBUF);
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_radix.c b/sys/compat/linuxkpi/common/src/linux_radix.c
new file mode 100644
index 000000000000..abf217de7f98
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_radix.c
@@ -0,0 +1,385 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2020 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/radix-tree.h>
+#include <linux/err.h>
+
+static MALLOC_DEFINE(M_RADIX, "radix", "Linux radix compat");
+
+static inline unsigned long
+radix_max(struct radix_tree_root *root)
+{
+ return ((1UL << (root->height * RADIX_TREE_MAP_SHIFT)) - 1UL);
+}
+
+static inline int
+radix_pos(long id, int height)
+{
+ return (id >> (RADIX_TREE_MAP_SHIFT * height)) & RADIX_TREE_MAP_MASK;
+}
+
+static void
+radix_tree_clean_root_node(struct radix_tree_root *root)
+{
+ /* Check if the root node should be freed */
+ if (root->rnode->count == 0) {
+ free(root->rnode, M_RADIX);
+ root->rnode = NULL;
+ root->height = 0;
+ }
+}
+
+void *
+radix_tree_lookup(struct radix_tree_root *root, unsigned long index)
+{
+ struct radix_tree_node *node;
+ void *item;
+ int height;
+
+ item = NULL;
+ node = root->rnode;
+ height = root->height - 1;
+ if (index > radix_max(root))
+ goto out;
+ while (height && node)
+ node = node->slots[radix_pos(index, height--)];
+ if (node)
+ item = node->slots[radix_pos(index, 0)];
+
+out:
+ return (item);
+}
+
+bool
+radix_tree_iter_find(struct radix_tree_root *root, struct radix_tree_iter *iter,
+ void ***pppslot)
+{
+ struct radix_tree_node *node;
+ unsigned long index = iter->index;
+ int height;
+
+restart:
+ node = root->rnode;
+ if (node == NULL)
+ return (false);
+ height = root->height - 1;
+ if (height == -1 || index > radix_max(root))
+ return (false);
+ do {
+ unsigned long mask = RADIX_TREE_MAP_MASK << (RADIX_TREE_MAP_SHIFT * height);
+ unsigned long step = 1UL << (RADIX_TREE_MAP_SHIFT * height);
+ int pos = radix_pos(index, height);
+ struct radix_tree_node *next;
+
+ /* track last slot */
+ *pppslot = node->slots + pos;
+
+ next = node->slots[pos];
+ if (next == NULL) {
+ index += step;
+ index &= -step;
+ if ((index & mask) == 0)
+ goto restart;
+ } else {
+ node = next;
+ height--;
+ }
+ } while (height != -1);
+ iter->index = index;
+ return (true);
+}
+
+void *
+radix_tree_delete(struct radix_tree_root *root, unsigned long index)
+{
+ struct radix_tree_node *stack[RADIX_TREE_MAX_HEIGHT];
+ struct radix_tree_node *node;
+ void *item;
+ int height;
+ int idx;
+
+ item = NULL;
+ node = root->rnode;
+ height = root->height - 1;
+ if (index > radix_max(root))
+ goto out;
+ /*
+ * Find the node and record the path in stack.
+ */
+ while (height && node) {
+ stack[height] = node;
+ node = node->slots[radix_pos(index, height--)];
+ }
+ idx = radix_pos(index, 0);
+ if (node)
+ item = node->slots[idx];
+ /*
+ * If we removed something reduce the height of the tree.
+ */
+ if (item)
+ for (;;) {
+ node->slots[idx] = NULL;
+ node->count--;
+ if (node->count > 0)
+ break;
+ free(node, M_RADIX);
+ if (node == root->rnode) {
+ root->rnode = NULL;
+ root->height = 0;
+ break;
+ }
+ height++;
+ node = stack[height];
+ idx = radix_pos(index, height);
+ }
+out:
+ return (item);
+}
+
+void
+radix_tree_iter_delete(struct radix_tree_root *root,
+ struct radix_tree_iter *iter, void **slot)
+{
+ radix_tree_delete(root, iter->index);
+}
+
+int
+radix_tree_insert(struct radix_tree_root *root, unsigned long index, void *item)
+{
+ struct radix_tree_node *node;
+ struct radix_tree_node *temp[RADIX_TREE_MAX_HEIGHT - 1];
+ int height;
+ int idx;
+
+ /* bail out upon insertion of a NULL item */
+ if (item == NULL)
+ return (-EINVAL);
+
+ /* get root node, if any */
+ node = root->rnode;
+
+ /* allocate root node, if any */
+ if (node == NULL) {
+ node = malloc(sizeof(*node), M_RADIX, root->gfp_mask | M_ZERO);
+ if (node == NULL)
+ return (-ENOMEM);
+ root->rnode = node;
+ root->height++;
+ }
+
+ /* expand radix tree as needed */
+ while (radix_max(root) < index) {
+ /* check if the radix tree is getting too big */
+ if (root->height == RADIX_TREE_MAX_HEIGHT) {
+ radix_tree_clean_root_node(root);
+ return (-E2BIG);
+ }
+
+ /*
+ * If the root radix level is not empty, we need to
+ * allocate a new radix level:
+ */
+ if (node->count != 0) {
+ node = malloc(sizeof(*node), M_RADIX, root->gfp_mask | M_ZERO);
+ if (node == NULL) {
+ /*
+ * Freeing the already allocated radix
+ * levels, if any, will be handled by
+ * the radix_tree_delete() function.
+ * This code path can only happen when
+ * the tree is not empty.
+ */
+ return (-ENOMEM);
+ }
+ node->slots[0] = root->rnode;
+ node->count++;
+ root->rnode = node;
+ }
+ root->height++;
+ }
+
+ /* get radix tree height index */
+ height = root->height - 1;
+
+ /* walk down the tree until the first missing node, if any */
+ for ( ; height != 0; height--) {
+ idx = radix_pos(index, height);
+ if (node->slots[idx] == NULL)
+ break;
+ node = node->slots[idx];
+ }
+
+ /* allocate the missing radix levels, if any */
+ for (idx = 0; idx != height; idx++) {
+ temp[idx] = malloc(sizeof(*node), M_RADIX,
+ root->gfp_mask | M_ZERO);
+ if (temp[idx] == NULL) {
+ while (idx--)
+ free(temp[idx], M_RADIX);
+ radix_tree_clean_root_node(root);
+ return (-ENOMEM);
+ }
+ }
+
+ /* setup new radix levels, if any */
+ for ( ; height != 0; height--) {
+ idx = radix_pos(index, height);
+ node->slots[idx] = temp[height - 1];
+ node->count++;
+ node = node->slots[idx];
+ }
+
+ /*
+ * Insert and adjust count if the item does not already exist.
+ */
+ idx = radix_pos(index, 0);
+ if (node->slots[idx])
+ return (-EEXIST);
+ node->slots[idx] = item;
+ node->count++;
+
+ return (0);
+}
+
+int
+radix_tree_store(struct radix_tree_root *root, unsigned long index, void **ppitem)
+{
+ struct radix_tree_node *node;
+ struct radix_tree_node *temp[RADIX_TREE_MAX_HEIGHT - 1];
+ void *pitem;
+ int height;
+ int idx;
+
+ /*
+ * Inserting a NULL item means delete it. The old pointer is
+ * stored at the location pointed to by "ppitem".
+ */
+ if (*ppitem == NULL) {
+ *ppitem = radix_tree_delete(root, index);
+ return (0);
+ }
+
+ /* get root node, if any */
+ node = root->rnode;
+
+ /* allocate root node, if any */
+ if (node == NULL) {
+ node = malloc(sizeof(*node), M_RADIX, root->gfp_mask | M_ZERO);
+ if (node == NULL)
+ return (-ENOMEM);
+ root->rnode = node;
+ root->height++;
+ }
+
+ /* expand radix tree as needed */
+ while (radix_max(root) < index) {
+ /* check if the radix tree is getting too big */
+ if (root->height == RADIX_TREE_MAX_HEIGHT) {
+ radix_tree_clean_root_node(root);
+ return (-E2BIG);
+ }
+
+ /*
+ * If the root radix level is not empty, we need to
+ * allocate a new radix level:
+ */
+ if (node->count != 0) {
+ node = malloc(sizeof(*node), M_RADIX, root->gfp_mask | M_ZERO);
+ if (node == NULL) {
+ /*
+ * Freeing the already allocated radix
+ * levels, if any, will be handled by
+ * the radix_tree_delete() function.
+ * This code path can only happen when
+ * the tree is not empty.
+ */
+ return (-ENOMEM);
+ }
+ node->slots[0] = root->rnode;
+ node->count++;
+ root->rnode = node;
+ }
+ root->height++;
+ }
+
+ /* get radix tree height index */
+ height = root->height - 1;
+
+ /* walk down the tree until the first missing node, if any */
+ for ( ; height != 0; height--) {
+ idx = radix_pos(index, height);
+ if (node->slots[idx] == NULL)
+ break;
+ node = node->slots[idx];
+ }
+
+ /* allocate the missing radix levels, if any */
+ for (idx = 0; idx != height; idx++) {
+ temp[idx] = malloc(sizeof(*node), M_RADIX,
+ root->gfp_mask | M_ZERO);
+ if (temp[idx] == NULL) {
+ while (idx--)
+ free(temp[idx], M_RADIX);
+ radix_tree_clean_root_node(root);
+ return (-ENOMEM);
+ }
+ }
+
+ /* setup new radix levels, if any */
+ for ( ; height != 0; height--) {
+ idx = radix_pos(index, height);
+ node->slots[idx] = temp[height - 1];
+ node->count++;
+ node = node->slots[idx];
+ }
+
+ /*
+ * Insert and adjust count if the item does not already exist.
+ */
+ idx = radix_pos(index, 0);
+ /* swap */
+ pitem = node->slots[idx];
+ node->slots[idx] = *ppitem;
+ *ppitem = pitem;
+
+ if (pitem == NULL)
+ node->count++;
+ return (0);
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_rcu.c b/sys/compat/linuxkpi/common/src/linux_rcu.c
new file mode 100644
index 000000000000..86ec193aa4e4
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_rcu.c
@@ -0,0 +1,421 @@
+/*-
+ * Copyright (c) 2016 Matthew Macy (mmacy@mattmacy.io)
+ * Copyright (c) 2017-2020 Hans Petter Selasky (hselasky@freebsd.org)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/sched.h>
+#include <sys/smp.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/kdb.h>
+
+#include <ck_epoch.h>
+
+#include <linux/rcupdate.h>
+#include <linux/srcu.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/compat.h>
+
+/*
+ * By defining CONFIG_NO_RCU_SKIP LinuxKPI RCU locks and asserts will
+ * not be skipped during panic().
+ */
+#ifdef CONFIG_NO_RCU_SKIP
+#define RCU_SKIP(void) 0
+#else
+#define RCU_SKIP(void) unlikely(SCHEDULER_STOPPED() || kdb_active)
+#endif
+
+struct callback_head {
+ STAILQ_ENTRY(callback_head) entry;
+ rcu_callback_t func;
+};
+
+struct linux_epoch_head {
+ STAILQ_HEAD(, callback_head) cb_head;
+ struct mtx lock;
+ struct task task;
+} __aligned(CACHE_LINE_SIZE);
+
+struct linux_epoch_record {
+ ck_epoch_record_t epoch_record;
+ TAILQ_HEAD(, task_struct) ts_head;
+ int cpuid;
+ int type;
+} __aligned(CACHE_LINE_SIZE);
+
+/*
+ * Verify that "struct rcu_head" is big enough to hold "struct
+ * callback_head". This has been done to avoid having to add special
+ * compile flags for including ck_epoch.h to all clients of the
+ * LinuxKPI.
+ */
+CTASSERT(sizeof(struct rcu_head) == sizeof(struct callback_head));
+
+/*
+ * Verify that "epoch_record" is at beginning of "struct
+ * linux_epoch_record":
+ */
+CTASSERT(offsetof(struct linux_epoch_record, epoch_record) == 0);
+
+CTASSERT(TS_RCU_TYPE_MAX == RCU_TYPE_MAX);
+
+static ck_epoch_t linux_epoch[RCU_TYPE_MAX];
+static struct linux_epoch_head linux_epoch_head[RCU_TYPE_MAX];
+DPCPU_DEFINE_STATIC(struct linux_epoch_record, linux_epoch_record[RCU_TYPE_MAX]);
+
+static void linux_rcu_cleaner_func(void *, int);
+
+static void
+linux_rcu_runtime_init(void *arg __unused)
+{
+ struct linux_epoch_head *head;
+ int i;
+ int j;
+
+ for (j = 0; j != RCU_TYPE_MAX; j++) {
+ ck_epoch_init(&linux_epoch[j]);
+
+ head = &linux_epoch_head[j];
+
+ mtx_init(&head->lock, "LRCU-HEAD", NULL, MTX_DEF);
+ TASK_INIT(&head->task, 0, linux_rcu_cleaner_func, head);
+ STAILQ_INIT(&head->cb_head);
+
+ CPU_FOREACH(i) {
+ struct linux_epoch_record *record;
+
+ record = &DPCPU_ID_GET(i, linux_epoch_record[j]);
+
+ record->cpuid = i;
+ record->type = j;
+ ck_epoch_register(&linux_epoch[j],
+ &record->epoch_record, NULL);
+ TAILQ_INIT(&record->ts_head);
+ }
+ }
+}
+SYSINIT(linux_rcu_runtime, SI_SUB_CPU, SI_ORDER_ANY, linux_rcu_runtime_init, NULL);
+
+static void
+linux_rcu_runtime_uninit(void *arg __unused)
+{
+ struct linux_epoch_head *head;
+ int j;
+
+ for (j = 0; j != RCU_TYPE_MAX; j++) {
+ head = &linux_epoch_head[j];
+
+ mtx_destroy(&head->lock);
+ }
+}
+SYSUNINIT(linux_rcu_runtime, SI_SUB_LOCK, SI_ORDER_SECOND, linux_rcu_runtime_uninit, NULL);
+
+static void
+linux_rcu_cleaner_func(void *context, int pending __unused)
+{
+ struct linux_epoch_head *head;
+ struct callback_head *rcu;
+ STAILQ_HEAD(, callback_head) tmp_head;
+ uintptr_t offset;
+
+ linux_set_current(curthread);
+
+ head = context;
+
+ /* move current callbacks into own queue */
+ mtx_lock(&head->lock);
+ STAILQ_INIT(&tmp_head);
+ STAILQ_CONCAT(&tmp_head, &head->cb_head);
+ mtx_unlock(&head->lock);
+
+ /* synchronize */
+ linux_synchronize_rcu(head - linux_epoch_head);
+
+ /* dispatch all callbacks, if any */
+ while ((rcu = STAILQ_FIRST(&tmp_head)) != NULL) {
+ STAILQ_REMOVE_HEAD(&tmp_head, entry);
+
+ offset = (uintptr_t)rcu->func;
+
+ if (offset < LINUX_KFREE_RCU_OFFSET_MAX)
+ kfree((char *)rcu - offset);
+ else
+ rcu->func((struct rcu_head *)rcu);
+ }
+}
+
+void
+linux_rcu_read_lock(unsigned type)
+{
+ struct linux_epoch_record *record;
+ struct task_struct *ts;
+
+ MPASS(type < RCU_TYPE_MAX);
+
+ if (RCU_SKIP())
+ return;
+
+ /*
+ * Pin thread to current CPU so that the unlock code gets the
+ * same per-CPU epoch record:
+ */
+ sched_pin();
+
+ record = &DPCPU_GET(linux_epoch_record[type]);
+ ts = current;
+
+ /*
+ * Use a critical section to prevent recursion inside
+ * ck_epoch_begin(). Else this function supports recursion.
+ */
+ critical_enter();
+ ck_epoch_begin(&record->epoch_record, NULL);
+ ts->rcu_recurse[type]++;
+ if (ts->rcu_recurse[type] == 1)
+ TAILQ_INSERT_TAIL(&record->ts_head, ts, rcu_entry[type]);
+ critical_exit();
+}
+
+void
+linux_rcu_read_unlock(unsigned type)
+{
+ struct linux_epoch_record *record;
+ struct task_struct *ts;
+
+ MPASS(type < RCU_TYPE_MAX);
+
+ if (RCU_SKIP())
+ return;
+
+ record = &DPCPU_GET(linux_epoch_record[type]);
+ ts = current;
+
+ /*
+ * Use a critical section to prevent recursion inside
+ * ck_epoch_end(). Else this function supports recursion.
+ */
+ critical_enter();
+ ck_epoch_end(&record->epoch_record, NULL);
+ ts->rcu_recurse[type]--;
+ if (ts->rcu_recurse[type] == 0)
+ TAILQ_REMOVE(&record->ts_head, ts, rcu_entry[type]);
+ critical_exit();
+
+ sched_unpin();
+}
+
+static void
+linux_synchronize_rcu_cb(ck_epoch_t *epoch __unused, ck_epoch_record_t *epoch_record, void *arg __unused)
+{
+ struct linux_epoch_record *record =
+ container_of(epoch_record, struct linux_epoch_record, epoch_record);
+ struct thread *td = curthread;
+ struct task_struct *ts;
+
+ /* check if blocked on the current CPU */
+ if (record->cpuid == PCPU_GET(cpuid)) {
+ bool is_sleeping = 0;
+ u_char prio = 0;
+
+ /*
+ * Find the lowest priority or sleeping thread which
+ * is blocking synchronization on this CPU core. All
+ * the threads in the queue are CPU-pinned and cannot
+ * go anywhere while the current thread is locked.
+ */
+ TAILQ_FOREACH(ts, &record->ts_head, rcu_entry[record->type]) {
+ if (ts->task_thread->td_priority > prio)
+ prio = ts->task_thread->td_priority;
+ is_sleeping |= (ts->task_thread->td_inhibitors != 0);
+ }
+
+ if (is_sleeping) {
+ thread_unlock(td);
+ pause("W", 1);
+ thread_lock(td);
+ } else {
+ /* set new thread priority */
+ sched_prio(td, prio);
+ /* task switch */
+ mi_switch(SW_VOL | SWT_RELINQUISH);
+ /*
+ * It is important the thread lock is dropped
+ * while yielding to allow other threads to
+ * acquire the lock pointed to by
+ * TDQ_LOCKPTR(td). Currently mi_switch() will
+ * unlock the thread lock before
+ * returning. Else a deadlock like situation
+ * might happen.
+ */
+ thread_lock(td);
+ }
+ } else {
+ /*
+ * To avoid spinning move execution to the other CPU
+ * which is blocking synchronization. Set highest
+ * thread priority so that code gets run. The thread
+ * priority will be restored later.
+ */
+ sched_prio(td, 0);
+ sched_bind(td, record->cpuid);
+ }
+}
+
+void
+linux_synchronize_rcu(unsigned type)
+{
+ struct thread *td;
+ int was_bound;
+ int old_cpu;
+ int old_pinned;
+ u_char old_prio;
+
+ MPASS(type < RCU_TYPE_MAX);
+
+ if (RCU_SKIP())
+ return;
+
+ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
+ "linux_synchronize_rcu() can sleep");
+
+ td = curthread;
+ DROP_GIANT();
+
+ /*
+ * Synchronizing RCU might change the CPU core this function
+ * is running on. Save current values:
+ */
+ thread_lock(td);
+
+ old_cpu = PCPU_GET(cpuid);
+ old_pinned = td->td_pinned;
+ old_prio = td->td_priority;
+ was_bound = sched_is_bound(td);
+ sched_unbind(td);
+ td->td_pinned = 0;
+ sched_bind(td, old_cpu);
+
+ ck_epoch_synchronize_wait(&linux_epoch[type],
+ &linux_synchronize_rcu_cb, NULL);
+
+ /* restore CPU binding, if any */
+ if (was_bound != 0) {
+ sched_bind(td, old_cpu);
+ } else {
+ /* get thread back to initial CPU, if any */
+ if (old_pinned != 0)
+ sched_bind(td, old_cpu);
+ sched_unbind(td);
+ }
+ /* restore pinned after bind */
+ td->td_pinned = old_pinned;
+
+ /* restore thread priority */
+ sched_prio(td, old_prio);
+ thread_unlock(td);
+
+ PICKUP_GIANT();
+}
+
+void
+linux_rcu_barrier(unsigned type)
+{
+ struct linux_epoch_head *head;
+
+ MPASS(type < RCU_TYPE_MAX);
+
+ linux_synchronize_rcu(type);
+
+ head = &linux_epoch_head[type];
+
+ /* wait for callbacks to complete */
+ taskqueue_drain(taskqueue_fast, &head->task);
+}
+
+void
+linux_call_rcu(unsigned type, struct rcu_head *context, rcu_callback_t func)
+{
+ struct callback_head *rcu;
+ struct linux_epoch_head *head;
+
+ MPASS(type < RCU_TYPE_MAX);
+
+ rcu = (struct callback_head *)context;
+ head = &linux_epoch_head[type];
+
+ mtx_lock(&head->lock);
+ rcu->func = func;
+ STAILQ_INSERT_TAIL(&head->cb_head, rcu, entry);
+ taskqueue_enqueue(taskqueue_fast, &head->task);
+ mtx_unlock(&head->lock);
+}
+
+int
+init_srcu_struct(struct srcu_struct *srcu)
+{
+ return (0);
+}
+
+void
+cleanup_srcu_struct(struct srcu_struct *srcu)
+{
+}
+
+int
+srcu_read_lock(struct srcu_struct *srcu)
+{
+ linux_rcu_read_lock(RCU_TYPE_SLEEPABLE);
+ return (0);
+}
+
+void
+srcu_read_unlock(struct srcu_struct *srcu, int key __unused)
+{
+ linux_rcu_read_unlock(RCU_TYPE_SLEEPABLE);
+}
+
+void
+synchronize_srcu(struct srcu_struct *srcu)
+{
+ linux_synchronize_rcu(RCU_TYPE_SLEEPABLE);
+}
+
+void
+srcu_barrier(struct srcu_struct *srcu)
+{
+ linux_rcu_barrier(RCU_TYPE_SLEEPABLE);
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_schedule.c b/sys/compat/linuxkpi/common/src/linux_schedule.c
new file mode 100644
index 000000000000..656d8697d169
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_schedule.c
@@ -0,0 +1,432 @@
+/*-
+ * Copyright (c) 2017 Mark Johnston <markj@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conds
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conds, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conds and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/signalvar.h>
+#include <sys/sleepqueue.h>
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+
+static int
+linux_add_to_sleepqueue(void *wchan, struct task_struct *task,
+ const char *wmesg, int timeout, int state)
+{
+ int flags, ret;
+
+ MPASS((state & ~(TASK_PARKED | TASK_NORMAL)) == 0);
+
+ flags = SLEEPQ_SLEEP | ((state & TASK_INTERRUPTIBLE) != 0 ?
+ SLEEPQ_INTERRUPTIBLE : 0);
+
+ sleepq_add(wchan, NULL, wmesg, flags, 0);
+ if (timeout != 0)
+ sleepq_set_timeout(wchan, timeout);
+
+ DROP_GIANT();
+ if ((state & TASK_INTERRUPTIBLE) != 0) {
+ if (timeout == 0)
+ ret = -sleepq_wait_sig(wchan, 0);
+ else
+ ret = -sleepq_timedwait_sig(wchan, 0);
+ } else {
+ if (timeout == 0) {
+ sleepq_wait(wchan, 0);
+ ret = 0;
+ } else
+ ret = -sleepq_timedwait(wchan, 0);
+ }
+ PICKUP_GIANT();
+
+ /* filter return value */
+ if (ret != 0 && ret != -EWOULDBLOCK) {
+ linux_schedule_save_interrupt_value(task, ret);
+ ret = -ERESTARTSYS;
+ }
+ return (ret);
+}
+
+unsigned int
+linux_msleep_interruptible(unsigned int ms)
+{
+ int ret;
+
+ /* guard against invalid values */
+ if (ms == 0)
+ ms = 1;
+ ret = -pause_sbt("lnxsleep", mstosbt(ms), 0, C_HARDCLOCK | C_CATCH);
+
+ switch (ret) {
+ case -EWOULDBLOCK:
+ return (0);
+ default:
+ linux_schedule_save_interrupt_value(current, ret);
+ return (ms);
+ }
+}
+
+static int
+wake_up_task(struct task_struct *task, unsigned int state)
+{
+ int ret, wakeup_swapper;
+
+ ret = wakeup_swapper = 0;
+ sleepq_lock(task);
+ if ((atomic_read(&task->state) & state) != 0) {
+ set_task_state(task, TASK_WAKING);
+ wakeup_swapper = sleepq_signal(task, SLEEPQ_SLEEP, 0, 0);
+ ret = 1;
+ }
+ sleepq_release(task);
+ if (wakeup_swapper)
+ kick_proc0();
+ return (ret);
+}
+
+bool
+linux_signal_pending(struct task_struct *task)
+{
+ struct thread *td;
+ sigset_t pending;
+
+ td = task->task_thread;
+ PROC_LOCK(td->td_proc);
+ pending = td->td_siglist;
+ SIGSETOR(pending, td->td_proc->p_siglist);
+ SIGSETNAND(pending, td->td_sigmask);
+ PROC_UNLOCK(td->td_proc);
+ return (!SIGISEMPTY(pending));
+}
+
+bool
+linux_fatal_signal_pending(struct task_struct *task)
+{
+ struct thread *td;
+ bool ret;
+
+ td = task->task_thread;
+ PROC_LOCK(td->td_proc);
+ ret = SIGISMEMBER(td->td_siglist, SIGKILL) ||
+ SIGISMEMBER(td->td_proc->p_siglist, SIGKILL);
+ PROC_UNLOCK(td->td_proc);
+ return (ret);
+}
+
+bool
+linux_signal_pending_state(long state, struct task_struct *task)
+{
+
+ MPASS((state & ~TASK_NORMAL) == 0);
+
+ if ((state & TASK_INTERRUPTIBLE) == 0)
+ return (false);
+ return (linux_signal_pending(task));
+}
+
+void
+linux_send_sig(int signo, struct task_struct *task)
+{
+ struct thread *td;
+
+ td = task->task_thread;
+ PROC_LOCK(td->td_proc);
+ tdsignal(td, signo);
+ PROC_UNLOCK(td->td_proc);
+}
+
+int
+autoremove_wake_function(wait_queue_t *wq, unsigned int state, int flags,
+ void *key __unused)
+{
+ struct task_struct *task;
+ int ret;
+
+ task = wq->private;
+ if ((ret = wake_up_task(task, state)) != 0)
+ list_del_init(&wq->task_list);
+ return (ret);
+}
+
+int
+default_wake_function(wait_queue_t *wq, unsigned int state, int flags,
+ void *key __unused)
+{
+ return (wake_up_task(wq->private, state));
+}
+
+void
+linux_init_wait_entry(wait_queue_t *wq, int flags)
+{
+
+ memset(wq, 0, sizeof(*wq));
+ wq->flags = flags;
+ wq->private = current;
+ wq->func = autoremove_wake_function;
+ INIT_LIST_HEAD(&wq->task_list);
+}
+
+void
+linux_wake_up(wait_queue_head_t *wqh, unsigned int state, int nr, bool locked)
+{
+ wait_queue_t *pos, *next;
+
+ if (!locked)
+ spin_lock(&wqh->lock);
+ list_for_each_entry_safe(pos, next, &wqh->task_list, task_list) {
+ if (pos->func == NULL) {
+ if (wake_up_task(pos->private, state) != 0 && --nr == 0)
+ break;
+ } else {
+ if (pos->func(pos, state, 0, NULL) != 0 && --nr == 0)
+ break;
+ }
+ }
+ if (!locked)
+ spin_unlock(&wqh->lock);
+}
+
+void
+linux_prepare_to_wait(wait_queue_head_t *wqh, wait_queue_t *wq, int state)
+{
+
+ spin_lock(&wqh->lock);
+ if (list_empty(&wq->task_list))
+ __add_wait_queue(wqh, wq);
+ set_task_state(current, state);
+ spin_unlock(&wqh->lock);
+}
+
+void
+linux_finish_wait(wait_queue_head_t *wqh, wait_queue_t *wq)
+{
+
+ spin_lock(&wqh->lock);
+ set_task_state(current, TASK_RUNNING);
+ if (!list_empty(&wq->task_list)) {
+ __remove_wait_queue(wqh, wq);
+ INIT_LIST_HEAD(&wq->task_list);
+ }
+ spin_unlock(&wqh->lock);
+}
+
+bool
+linux_waitqueue_active(wait_queue_head_t *wqh)
+{
+ bool ret;
+
+ spin_lock(&wqh->lock);
+ ret = !list_empty(&wqh->task_list);
+ spin_unlock(&wqh->lock);
+ return (ret);
+}
+
+int
+linux_wait_event_common(wait_queue_head_t *wqh, wait_queue_t *wq, int timeout,
+ unsigned int state, spinlock_t *lock)
+{
+ struct task_struct *task;
+ int ret;
+
+ if (lock != NULL)
+ spin_unlock_irq(lock);
+
+ /* range check timeout */
+ if (timeout < 1)
+ timeout = 1;
+ else if (timeout == MAX_SCHEDULE_TIMEOUT)
+ timeout = 0;
+
+ task = current;
+
+ /*
+ * Our wait queue entry is on the stack - make sure it doesn't
+ * get swapped out while we sleep.
+ */
+ PHOLD(task->task_thread->td_proc);
+ sleepq_lock(task);
+ if (atomic_read(&task->state) != TASK_WAKING) {
+ ret = linux_add_to_sleepqueue(task, task, "wevent", timeout,
+ state);
+ } else {
+ sleepq_release(task);
+ ret = 0;
+ }
+ PRELE(task->task_thread->td_proc);
+
+ if (lock != NULL)
+ spin_lock_irq(lock);
+ return (ret);
+}
+
+int
+linux_schedule_timeout(int timeout)
+{
+ struct task_struct *task;
+ int ret;
+ int state;
+ int remainder;
+
+ task = current;
+
+ /* range check timeout */
+ if (timeout < 1)
+ timeout = 1;
+ else if (timeout == MAX_SCHEDULE_TIMEOUT)
+ timeout = 0;
+
+ remainder = ticks + timeout;
+
+ sleepq_lock(task);
+ state = atomic_read(&task->state);
+ if (state != TASK_WAKING) {
+ ret = linux_add_to_sleepqueue(task, task, "sched", timeout,
+ state);
+ } else {
+ sleepq_release(task);
+ ret = 0;
+ }
+ set_task_state(task, TASK_RUNNING);
+
+ if (timeout == 0)
+ return (MAX_SCHEDULE_TIMEOUT);
+
+ /* range check return value */
+ remainder -= ticks;
+
+ /* range check return value */
+ if (ret == -ERESTARTSYS && remainder < 1)
+ remainder = 1;
+ else if (remainder < 0)
+ remainder = 0;
+ else if (remainder > timeout)
+ remainder = timeout;
+ return (remainder);
+}
+
+static void
+wake_up_sleepers(void *wchan)
+{
+ int wakeup_swapper;
+
+ sleepq_lock(wchan);
+ wakeup_swapper = sleepq_signal(wchan, SLEEPQ_SLEEP, 0, 0);
+ sleepq_release(wchan);
+ if (wakeup_swapper)
+ kick_proc0();
+}
+
+#define bit_to_wchan(word, bit) ((void *)(((uintptr_t)(word) << 6) | (bit)))
+
+void
+linux_wake_up_bit(void *word, int bit)
+{
+
+ wake_up_sleepers(bit_to_wchan(word, bit));
+}
+
+int
+linux_wait_on_bit_timeout(unsigned long *word, int bit, unsigned int state,
+ int timeout)
+{
+ struct task_struct *task;
+ void *wchan;
+ int ret;
+
+ /* range check timeout */
+ if (timeout < 1)
+ timeout = 1;
+ else if (timeout == MAX_SCHEDULE_TIMEOUT)
+ timeout = 0;
+
+ task = current;
+ wchan = bit_to_wchan(word, bit);
+ for (;;) {
+ sleepq_lock(wchan);
+ if ((*word & (1 << bit)) == 0) {
+ sleepq_release(wchan);
+ ret = 0;
+ break;
+ }
+ set_task_state(task, state);
+ ret = linux_add_to_sleepqueue(wchan, task, "wbit", timeout,
+ state);
+ if (ret != 0)
+ break;
+ }
+ set_task_state(task, TASK_RUNNING);
+
+ return (ret);
+}
+
+void
+linux_wake_up_atomic_t(atomic_t *a)
+{
+
+ wake_up_sleepers(a);
+}
+
+int
+linux_wait_on_atomic_t(atomic_t *a, unsigned int state)
+{
+ struct task_struct *task;
+ void *wchan;
+ int ret;
+
+ task = current;
+ wchan = a;
+ for (;;) {
+ sleepq_lock(wchan);
+ if (atomic_read(a) == 0) {
+ sleepq_release(wchan);
+ ret = 0;
+ break;
+ }
+ set_task_state(task, state);
+ ret = linux_add_to_sleepqueue(wchan, task, "watomic", 0, state);
+ if (ret != 0)
+ break;
+ }
+ set_task_state(task, TASK_RUNNING);
+
+ return (ret);
+}
+
+bool
+linux_wake_up_state(struct task_struct *task, unsigned int state)
+{
+
+ return (wake_up_task(task, state) != 0);
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_seq_file.c b/sys/compat/linuxkpi/common/src/linux_seq_file.c
new file mode 100644
index 000000000000..6f4f1a368c4a
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_seq_file.c
@@ -0,0 +1,156 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2016-2018, Matthew Macy <mmacy@freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/param.h>
+#include <sys/sbuf.h>
+#include <sys/syslog.h>
+#include <sys/vnode.h>
+
+#include <linux/seq_file.h>
+#include <linux/file.h>
+
+#undef file
+MALLOC_DEFINE(M_LSEQ, "seq_file", "seq_file");
+
+ssize_t
+seq_read(struct linux_file *f, char *ubuf, size_t size, off_t *ppos)
+{
+ struct seq_file *m = f->private_data;
+ void *p;
+ int rc;
+ off_t pos = 0;
+
+ p = m->op->start(m, &pos);
+ rc = m->op->show(m, p);
+ if (rc)
+ return (rc);
+ return (size);
+}
+
+int
+seq_write(struct seq_file *seq, const void *data, size_t len)
+{
+
+ return (sbuf_bcpy(seq->buf, data, len));
+}
+
+/*
+ * This only needs to be a valid address for lkpi
+ * drivers it should never actually be called
+ */
+off_t
+seq_lseek(struct linux_file *file, off_t offset, int whence)
+{
+
+ panic("%s not supported\n", __FUNCTION__);
+ return (0);
+}
+
+static void *
+single_start(struct seq_file *p, off_t *pos)
+{
+
+ return ((void *)(uintptr_t)(*pos == 0));
+}
+
+static void *
+single_next(struct seq_file *p, void *v, off_t *pos)
+{
+
+ ++*pos;
+ return (NULL);
+}
+
+static void
+single_stop(struct seq_file *p, void *v)
+{
+}
+
+int
+seq_open(struct linux_file *f, const struct seq_operations *op)
+{
+ struct seq_file *p;
+
+ if (f->private_data != NULL)
+ log(LOG_WARNING, "%s private_data not NULL", __func__);
+
+ if ((p = malloc(sizeof(*p), M_LSEQ, M_NOWAIT|M_ZERO)) == NULL)
+ return (-ENOMEM);
+
+ f->private_data = p;
+ p->op = op;
+ p->file = f;
+ return (0);
+}
+
+int
+single_open(struct linux_file *f, int (*show)(struct seq_file *, void *), void *d)
+{
+ struct seq_operations *op;
+ int rc = -ENOMEM;
+
+ op = malloc(sizeof(*op), M_LSEQ, M_NOWAIT);
+ if (op) {
+ op->start = single_start;
+ op->next = single_next;
+ op->stop = single_stop;
+ op->show = show;
+ rc = seq_open(f, op);
+ if (rc)
+ free(op, M_LSEQ);
+ else
+ ((struct seq_file *)f->private_data)->private = d;
+ }
+ return (rc);
+}
+
+int
+seq_release(struct inode *inode __unused, struct linux_file *file)
+{
+ struct seq_file *m;
+
+ m = file->private_data;
+ free(m, M_LSEQ);
+ return (0);
+}
+
+int
+single_release(struct vnode *v, struct linux_file *f)
+{
+ const struct seq_operations *op = ((struct seq_file *)f->private_data)->op;
+ int rc;
+
+ rc = seq_release(v, f);
+ free(__DECONST(void *, op), M_LSEQ);
+ return (rc);
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_shmemfs.c b/sys/compat/linuxkpi/common/src/linux_shmemfs.c
new file mode 100644
index 000000000000..ead9cc9d9f40
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_shmemfs.c
@@ -0,0 +1,128 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2016 Matthew Macy (mmacy@mattmacy.io)
+ * Copyright (c) 2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/rwlock.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_object.h>
+#include <vm/vm_map.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/shmem_fs.h>
+
+struct page *
+linux_shmem_read_mapping_page_gfp(vm_object_t obj, int pindex, gfp_t gfp)
+{
+ vm_page_t page;
+ int rv;
+
+ if ((gfp & GFP_NOWAIT) != 0)
+ panic("GFP_NOWAIT is unimplemented");
+
+ VM_OBJECT_WLOCK(obj);
+ rv = vm_page_grab_valid(&page, obj, pindex, VM_ALLOC_NORMAL |
+ VM_ALLOC_NOBUSY | VM_ALLOC_WIRED);
+ VM_OBJECT_WUNLOCK(obj);
+ if (rv != VM_PAGER_OK)
+ return (ERR_PTR(-EINVAL));
+ return (page);
+}
+
+struct linux_file *
+linux_shmem_file_setup(const char *name, loff_t size, unsigned long flags)
+{
+ struct fileobj {
+ struct linux_file file __aligned(sizeof(void *));
+ struct vnode vnode __aligned(sizeof(void *));
+ };
+ struct fileobj *fileobj;
+ struct linux_file *filp;
+ struct vnode *vp;
+ int error;
+
+ fileobj = kzalloc(sizeof(*fileobj), GFP_KERNEL);
+ if (fileobj == NULL) {
+ error = -ENOMEM;
+ goto err_0;
+ }
+ filp = &fileobj->file;
+ vp = &fileobj->vnode;
+
+ filp->f_count = 1;
+ filp->f_vnode = vp;
+ filp->f_shmem = vm_pager_allocate(OBJT_DEFAULT, NULL, size,
+ VM_PROT_READ | VM_PROT_WRITE, 0, curthread->td_ucred);
+ if (filp->f_shmem == NULL) {
+ error = -ENOMEM;
+ goto err_1;
+ }
+ return (filp);
+err_1:
+ kfree(filp);
+err_0:
+ return (ERR_PTR(error));
+}
+
+static vm_ooffset_t
+linux_invalidate_mapping_pages_sub(vm_object_t obj, vm_pindex_t start,
+ vm_pindex_t end, int flags)
+{
+ int start_count, end_count;
+
+ VM_OBJECT_WLOCK(obj);
+ start_count = obj->resident_page_count;
+ vm_object_page_remove(obj, start, end, flags);
+ end_count = obj->resident_page_count;
+ VM_OBJECT_WUNLOCK(obj);
+ return (start_count - end_count);
+}
+
+unsigned long
+linux_invalidate_mapping_pages(vm_object_t obj, pgoff_t start, pgoff_t end)
+{
+
+ return (linux_invalidate_mapping_pages_sub(obj, start, end, OBJPR_CLEANONLY));
+}
+
+void
+linux_shmem_truncate_range(vm_object_t obj, loff_t lstart, loff_t lend)
+{
+ vm_pindex_t start = OFF_TO_IDX(lstart + PAGE_SIZE - 1);
+ vm_pindex_t end = OFF_TO_IDX(lend + 1);
+
+ (void) linux_invalidate_mapping_pages_sub(obj, start, end, 0);
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_shrinker.c b/sys/compat/linuxkpi/common/src/linux_shrinker.c
new file mode 100644
index 000000000000..0423f4e05804
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_shrinker.c
@@ -0,0 +1,125 @@
+/*-
+ * Copyright (c) 2020 Emmanuel Vadot <manu@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/eventhandler.h>
+#include <sys/mutex.h>
+
+#include <linux/shrinker.h>
+
+TAILQ_HEAD(, shrinker) lkpi_shrinkers = TAILQ_HEAD_INITIALIZER(lkpi_shrinkers);
+static struct mtx mtx_shrinker;
+
+int
+linuxkpi_register_shrinker(struct shrinker *s)
+{
+
+ KASSERT(s != NULL, ("NULL shrinker"));
+ KASSERT(s->count_objects != NULL, ("NULL shrinker"));
+ KASSERT(s->scan_objects != NULL, ("NULL shrinker"));
+ mtx_lock(&mtx_shrinker);
+ TAILQ_INSERT_TAIL(&lkpi_shrinkers, s, next);
+ mtx_unlock(&mtx_shrinker);
+ return (0);
+}
+
+void
+linuxkpi_unregister_shrinker(struct shrinker *s)
+{
+
+ mtx_lock(&mtx_shrinker);
+ TAILQ_REMOVE(&lkpi_shrinkers, s, next);
+ mtx_unlock(&mtx_shrinker);
+}
+
+#define SHRINKER_BATCH 512
+
+static void
+shrinker_shrink(struct shrinker *s)
+{
+ struct shrink_control sc;
+ unsigned long can_free;
+ unsigned long batch;
+ unsigned long scanned = 0;
+ unsigned long ret;
+
+ can_free = s->count_objects(s, &sc);
+ if (can_free <= 0)
+ return;
+
+ batch = s->batch ? s->batch : SHRINKER_BATCH;
+ while (scanned <= can_free) {
+ sc.nr_to_scan = batch;
+ ret = s->scan_objects(s, &sc);
+ if (ret == SHRINK_STOP)
+ break;
+ scanned += batch;
+ }
+}
+
+static void
+linuxkpi_vm_lowmem(void *arg __unused)
+{
+ struct shrinker *s;
+
+ mtx_lock(&mtx_shrinker);
+ TAILQ_FOREACH(s, &lkpi_shrinkers, next) {
+ shrinker_shrink(s);
+ }
+ mtx_unlock(&mtx_shrinker);
+}
+
+static eventhandler_tag lowmem_tag;
+
+static void
+linuxkpi_sysinit_shrinker(void *arg __unused)
+{
+
+ mtx_init(&mtx_shrinker, "lkpi-shrinker", NULL, MTX_DEF);
+ lowmem_tag = EVENTHANDLER_REGISTER(vm_lowmem, linuxkpi_vm_lowmem,
+ NULL, EVENTHANDLER_PRI_FIRST);
+}
+
+static void
+linuxkpi_sysuninit_shrinker(void *arg __unused)
+{
+
+ mtx_destroy(&mtx_shrinker);
+ EVENTHANDLER_DEREGISTER(vm_lowmem, lowmem_tag);
+}
+
+SYSINIT(linuxkpi_shrinker, SI_SUB_DRIVERS, SI_ORDER_ANY,
+ linuxkpi_sysinit_shrinker, NULL);
+SYSUNINIT(linuxkpi_shrinker, SI_SUB_DRIVERS, SI_ORDER_ANY,
+ linuxkpi_sysuninit_shrinker, NULL);
diff --git a/sys/compat/linuxkpi/common/src/linux_slab.c b/sys/compat/linuxkpi/common/src/linux_slab.c
new file mode 100644
index 000000000000..3304c34b1dee
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_slab.c
@@ -0,0 +1,155 @@
+/*-
+ * Copyright (c) 2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <linux/slab.h>
+#include <linux/rcupdate.h>
+#include <linux/kernel.h>
+#include <linux/irq_work.h>
+#include <linux/llist.h>
+
+#include <sys/param.h>
+#include <sys/taskqueue.h>
+
+struct linux_kmem_rcu {
+ struct rcu_head rcu_head;
+ struct linux_kmem_cache *cache;
+};
+
+#define LINUX_KMEM_TO_RCU(c, m) \
+ ((struct linux_kmem_rcu *)((char *)(m) + \
+ (c)->cache_size - sizeof(struct linux_kmem_rcu)))
+
+#define LINUX_RCU_TO_KMEM(r) \
+ ((void *)((char *)(r) + sizeof(struct linux_kmem_rcu) - \
+ (r)->cache->cache_size))
+
+static LLIST_HEAD(linux_kfree_async_list);
+
+static int
+linux_kmem_ctor(void *mem, int size, void *arg, int flags)
+{
+ struct linux_kmem_cache *c = arg;
+
+ if (unlikely(c->cache_flags & SLAB_TYPESAFE_BY_RCU)) {
+ struct linux_kmem_rcu *rcu = LINUX_KMEM_TO_RCU(c, mem);
+
+ /* duplicate cache pointer */
+ rcu->cache = c;
+ }
+
+ /* check for constructor */
+ if (likely(c->cache_ctor != NULL))
+ c->cache_ctor(mem);
+
+ return (0);
+}
+
+static void
+linux_kmem_cache_free_rcu_callback(struct rcu_head *head)
+{
+ struct linux_kmem_rcu *rcu =
+ container_of(head, struct linux_kmem_rcu, rcu_head);
+
+ uma_zfree(rcu->cache->cache_zone, LINUX_RCU_TO_KMEM(rcu));
+}
+
+struct linux_kmem_cache *
+linux_kmem_cache_create(const char *name, size_t size, size_t align,
+ unsigned flags, linux_kmem_ctor_t *ctor)
+{
+ struct linux_kmem_cache *c;
+
+ c = malloc(sizeof(*c), M_KMALLOC, M_WAITOK);
+
+ if (flags & SLAB_HWCACHE_ALIGN)
+ align = UMA_ALIGN_CACHE;
+ else if (align != 0)
+ align--;
+
+ if (flags & SLAB_TYPESAFE_BY_RCU) {
+ /* make room for RCU structure */
+ size = ALIGN(size, sizeof(void *));
+ size += sizeof(struct linux_kmem_rcu);
+
+ /* create cache_zone */
+ c->cache_zone = uma_zcreate(name, size,
+ linux_kmem_ctor, NULL, NULL, NULL,
+ align, UMA_ZONE_ZINIT);
+ } else {
+ /* create cache_zone */
+ c->cache_zone = uma_zcreate(name, size,
+ ctor ? linux_kmem_ctor : NULL, NULL,
+ NULL, NULL, align, 0);
+ }
+
+ c->cache_flags = flags;
+ c->cache_ctor = ctor;
+ c->cache_size = size;
+ return (c);
+}
+
+void
+linux_kmem_cache_free_rcu(struct linux_kmem_cache *c, void *m)
+{
+ struct linux_kmem_rcu *rcu = LINUX_KMEM_TO_RCU(c, m);
+
+ call_rcu(&rcu->rcu_head, linux_kmem_cache_free_rcu_callback);
+}
+
+void
+linux_kmem_cache_destroy(struct linux_kmem_cache *c)
+{
+ if (unlikely(c->cache_flags & SLAB_TYPESAFE_BY_RCU)) {
+ /* make sure all free callbacks have been called */
+ rcu_barrier();
+ }
+
+ uma_zdestroy(c->cache_zone);
+ free(c, M_KMALLOC);
+}
+
+static void
+linux_kfree_async_fn(void *context, int pending)
+{
+ struct llist_node *freed;
+
+ while((freed = llist_del_first(&linux_kfree_async_list)) != NULL)
+ kfree(freed);
+}
+static struct task linux_kfree_async_task =
+ TASK_INITIALIZER(0, linux_kfree_async_fn, &linux_kfree_async_task);
+
+void
+linux_kfree_async(void *addr)
+{
+ if (addr == NULL)
+ return;
+ llist_add(addr, &linux_kfree_async_list);
+ taskqueue_enqueue(linux_irq_work_tq, &linux_kfree_async_task);
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_tasklet.c b/sys/compat/linuxkpi/common/src/linux_tasklet.c
new file mode 100644
index 000000000000..5cac8ffd994c
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_tasklet.c
@@ -0,0 +1,253 @@
+/*-
+ * Copyright (c) 2017 Hans Petter Selasky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/malloc.h>
+#include <sys/gtaskqueue.h>
+#include <sys/proc.h>
+#include <sys/sched.h>
+
+#include <linux/compiler.h>
+#include <linux/interrupt.h>
+#include <linux/compat.h>
+
+#define TASKLET_ST_IDLE 0
+#define TASKLET_ST_BUSY 1
+#define TASKLET_ST_EXEC 2
+#define TASKLET_ST_LOOP 3
+
+#define TASKLET_ST_CMPSET(ts, old, new) \
+ atomic_cmpset_int((volatile u_int *)&(ts)->tasklet_state, old, new)
+
+#define TASKLET_ST_SET(ts, new) \
+ WRITE_ONCE(*(volatile u_int *)&(ts)->tasklet_state, new)
+
+#define TASKLET_ST_GET(ts) \
+ READ_ONCE(*(volatile u_int *)&(ts)->tasklet_state)
+
+struct tasklet_worker {
+ struct mtx mtx;
+ TAILQ_HEAD(tasklet_list, tasklet_struct) head;
+ struct grouptask gtask;
+} __aligned(CACHE_LINE_SIZE);
+
+#define TASKLET_WORKER_LOCK(tw) mtx_lock(&(tw)->mtx)
+#define TASKLET_WORKER_UNLOCK(tw) mtx_unlock(&(tw)->mtx)
+
+DPCPU_DEFINE_STATIC(struct tasklet_worker, tasklet_worker);
+
+static void
+tasklet_handler(void *arg)
+{
+ struct tasklet_worker *tw = (struct tasklet_worker *)arg;
+ struct tasklet_struct *ts;
+ struct tasklet_struct *last;
+
+ linux_set_current(curthread);
+
+ TASKLET_WORKER_LOCK(tw);
+ last = TAILQ_LAST(&tw->head, tasklet_list);
+ while (1) {
+ ts = TAILQ_FIRST(&tw->head);
+ if (ts == NULL)
+ break;
+ TAILQ_REMOVE(&tw->head, ts, entry);
+
+ if (!atomic_read(&ts->count)) {
+ TASKLET_WORKER_UNLOCK(tw);
+ do {
+ /* reset executing state */
+ TASKLET_ST_SET(ts, TASKLET_ST_EXEC);
+
+ ts->func(ts->data);
+
+ } while (TASKLET_ST_CMPSET(ts, TASKLET_ST_EXEC,
+ TASKLET_ST_IDLE) == 0);
+ TASKLET_WORKER_LOCK(tw);
+ } else {
+ TAILQ_INSERT_TAIL(&tw->head, ts, entry);
+ }
+ if (ts == last)
+ break;
+ }
+ TASKLET_WORKER_UNLOCK(tw);
+}
+
+static void
+tasklet_subsystem_init(void *arg __unused)
+{
+ struct tasklet_worker *tw;
+ char buf[32];
+ int i;
+
+ CPU_FOREACH(i) {
+ if (CPU_ABSENT(i))
+ continue;
+
+ tw = DPCPU_ID_PTR(i, tasklet_worker);
+
+ mtx_init(&tw->mtx, "linux_tasklet", NULL, MTX_DEF);
+ TAILQ_INIT(&tw->head);
+ GROUPTASK_INIT(&tw->gtask, 0, tasklet_handler, tw);
+ snprintf(buf, sizeof(buf), "softirq%d", i);
+ taskqgroup_attach_cpu(qgroup_softirq, &tw->gtask,
+ "tasklet", i, NULL, NULL, buf);
+ }
+}
+SYSINIT(linux_tasklet, SI_SUB_TASKQ, SI_ORDER_THIRD, tasklet_subsystem_init, NULL);
+
+static void
+tasklet_subsystem_uninit(void *arg __unused)
+{
+ struct tasklet_worker *tw;
+ int i;
+
+ CPU_FOREACH(i) {
+ if (CPU_ABSENT(i))
+ continue;
+
+ tw = DPCPU_ID_PTR(i, tasklet_worker);
+
+ taskqgroup_detach(qgroup_softirq, &tw->gtask);
+ mtx_destroy(&tw->mtx);
+ }
+}
+SYSUNINIT(linux_tasklet, SI_SUB_TASKQ, SI_ORDER_THIRD, tasklet_subsystem_uninit, NULL);
+
+void
+tasklet_init(struct tasklet_struct *ts,
+ tasklet_func_t *func, unsigned long data)
+{
+ ts->entry.tqe_prev = NULL;
+ ts->entry.tqe_next = NULL;
+ ts->func = func;
+ ts->data = data;
+ atomic_set_int(&ts->tasklet_state, TASKLET_ST_IDLE);
+ atomic_set(&ts->count, 0);
+}
+
+void
+local_bh_enable(void)
+{
+ sched_unpin();
+}
+
+void
+local_bh_disable(void)
+{
+ sched_pin();
+}
+
+void
+tasklet_schedule(struct tasklet_struct *ts)
+{
+
+ /* tasklet is paused */
+ if (atomic_read(&ts->count))
+ return;
+
+ if (TASKLET_ST_CMPSET(ts, TASKLET_ST_EXEC, TASKLET_ST_LOOP)) {
+ /* tasklet_handler() will loop */
+ } else if (TASKLET_ST_CMPSET(ts, TASKLET_ST_IDLE, TASKLET_ST_BUSY)) {
+ struct tasklet_worker *tw;
+
+ tw = &DPCPU_GET(tasklet_worker);
+
+ /* tasklet_handler() was not queued */
+ TASKLET_WORKER_LOCK(tw);
+ /* enqueue tasklet */
+ TAILQ_INSERT_TAIL(&tw->head, ts, entry);
+ /* schedule worker */
+ GROUPTASK_ENQUEUE(&tw->gtask);
+ TASKLET_WORKER_UNLOCK(tw);
+ } else {
+ /*
+ * tasklet_handler() is already executing
+ *
+ * If the state is neither EXEC nor IDLE, it is either
+ * LOOP or BUSY. If the state changed between the two
+ * CMPSET's above the only possible transitions by
+ * elimination are LOOP->EXEC and BUSY->EXEC. If a
+ * EXEC->LOOP transition was missed that is not a
+ * problem because the callback function is then
+ * already about to be called again.
+ */
+ }
+}
+
+void
+tasklet_kill(struct tasklet_struct *ts)
+{
+
+ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "tasklet_kill() can sleep");
+
+ /* wait until tasklet is no longer busy */
+ while (TASKLET_ST_GET(ts) != TASKLET_ST_IDLE)
+ pause("W", 1);
+}
+
+void
+tasklet_enable(struct tasklet_struct *ts)
+{
+
+ atomic_dec(&ts->count);
+}
+
+void
+tasklet_disable(struct tasklet_struct *ts)
+{
+
+ atomic_inc(&ts->count);
+ tasklet_unlock_wait(ts);
+}
+
+int
+tasklet_trylock(struct tasklet_struct *ts)
+{
+
+ return (TASKLET_ST_CMPSET(ts, TASKLET_ST_IDLE, TASKLET_ST_BUSY));
+}
+
+void
+tasklet_unlock(struct tasklet_struct *ts)
+{
+
+ TASKLET_ST_SET(ts, TASKLET_ST_IDLE);
+}
+
+void
+tasklet_unlock_wait(struct tasklet_struct *ts)
+{
+
+ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "tasklet_kill() can sleep");
+
+ /* wait until tasklet is no longer busy */
+ while (TASKLET_ST_GET(ts) != TASKLET_ST_IDLE)
+ pause("W", 1);
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_usb.c b/sys/compat/linuxkpi/common/src/linux_usb.c
new file mode 100644
index 000000000000..e93559f95264
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_usb.c
@@ -0,0 +1,1720 @@
+/* $FreeBSD$ */
+/*-
+ * Copyright (c) 2007 Luigi Rizzo - Universita` di Pisa. All rights reserved.
+ * Copyright (c) 2007 Hans Petter Selasky. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef USB_GLOBAL_INCLUDE_FILE
+#include USB_GLOBAL_INCLUDE_FILE
+#else
+#include <sys/stdint.h>
+#include <sys/stddef.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/sx.h>
+#include <sys/unistd.h>
+#include <sys/callout.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+
+#define USB_DEBUG_VAR usb_debug
+
+#include <dev/usb/usb_core.h>
+#include <linux/usb.h>
+#include <dev/usb/usb_process.h>
+#include <dev/usb/usb_device.h>
+#include <dev/usb/usb_util.h>
+#include <dev/usb/usb_busdma.h>
+#include <dev/usb/usb_transfer.h>
+#include <dev/usb/usb_hub.h>
+#include <dev/usb/usb_request.h>
+#include <dev/usb/usb_debug.h>
+#include <dev/usb/usb_dynamic.h>
+#endif /* USB_GLOBAL_INCLUDE_FILE */
+
+struct usb_linux_softc {
+ LIST_ENTRY(usb_linux_softc) sc_attached_list;
+
+ device_t sc_fbsd_dev;
+ struct usb_device *sc_fbsd_udev;
+ struct usb_interface *sc_ui;
+ struct usb_driver *sc_udrv;
+};
+
+/* prototypes */
+static device_probe_t usb_linux_probe;
+static device_attach_t usb_linux_attach;
+static device_detach_t usb_linux_detach;
+static device_suspend_t usb_linux_suspend;
+static device_resume_t usb_linux_resume;
+
+static usb_callback_t usb_linux_isoc_callback;
+static usb_callback_t usb_linux_non_isoc_callback;
+
+static usb_complete_t usb_linux_wait_complete;
+
+static uint16_t usb_max_isoc_frames(struct usb_device *);
+static int usb_start_wait_urb(struct urb *, usb_timeout_t, uint16_t *);
+static const struct usb_device_id *usb_linux_lookup_id(
+ const struct usb_device_id *, struct usb_attach_arg *);
+static struct usb_driver *usb_linux_get_usb_driver(struct usb_linux_softc *);
+static int usb_linux_create_usb_device(struct usb_device *, device_t);
+static void usb_linux_cleanup_interface(struct usb_device *,
+ struct usb_interface *);
+static void usb_linux_complete(struct usb_xfer *);
+static int usb_unlink_urb_sub(struct urb *, uint8_t);
+
+/*------------------------------------------------------------------------*
+ * FreeBSD USB interface
+ *------------------------------------------------------------------------*/
+
+static LIST_HEAD(, usb_linux_softc) usb_linux_attached_list;
+static LIST_HEAD(, usb_driver) usb_linux_driver_list;
+
+static device_method_t usb_linux_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, usb_linux_probe),
+ DEVMETHOD(device_attach, usb_linux_attach),
+ DEVMETHOD(device_detach, usb_linux_detach),
+ DEVMETHOD(device_suspend, usb_linux_suspend),
+ DEVMETHOD(device_resume, usb_linux_resume),
+
+ DEVMETHOD_END
+};
+
+static driver_t usb_linux_driver = {
+ .name = "usb_linux",
+ .methods = usb_linux_methods,
+ .size = sizeof(struct usb_linux_softc),
+};
+
+static devclass_t usb_linux_devclass;
+
+DRIVER_MODULE(usb_linux, uhub, usb_linux_driver, usb_linux_devclass, NULL, 0);
+MODULE_VERSION(usb_linux, 1);
+
+/*------------------------------------------------------------------------*
+ * usb_linux_lookup_id
+ *
+ * This functions takes an array of "struct usb_device_id" and tries
+ * to match the entries with the information in "struct usb_attach_arg".
+ * If it finds a match the matching entry will be returned.
+ * Else "NULL" will be returned.
+ *------------------------------------------------------------------------*/
+static const struct usb_device_id *
+usb_linux_lookup_id(const struct usb_device_id *id, struct usb_attach_arg *uaa)
+{
+ if (id == NULL) {
+ goto done;
+ }
+ /*
+ * Keep on matching array entries until we find one with
+ * "match_flags" equal to zero, which indicates the end of the
+ * array:
+ */
+ for (; id->match_flags; id++) {
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
+ (id->idVendor != uaa->info.idVendor)) {
+ continue;
+ }
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
+ (id->idProduct != uaa->info.idProduct)) {
+ continue;
+ }
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
+ (id->bcdDevice_lo > uaa->info.bcdDevice)) {
+ continue;
+ }
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
+ (id->bcdDevice_hi < uaa->info.bcdDevice)) {
+ continue;
+ }
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
+ (id->bDeviceClass != uaa->info.bDeviceClass)) {
+ continue;
+ }
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
+ (id->bDeviceSubClass != uaa->info.bDeviceSubClass)) {
+ continue;
+ }
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
+ (id->bDeviceProtocol != uaa->info.bDeviceProtocol)) {
+ continue;
+ }
+ if ((uaa->info.bDeviceClass == 0xFF) &&
+ !(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
+ (id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS |
+ USB_DEVICE_ID_MATCH_INT_SUBCLASS |
+ USB_DEVICE_ID_MATCH_INT_PROTOCOL))) {
+ continue;
+ }
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
+ (id->bInterfaceClass != uaa->info.bInterfaceClass)) {
+ continue;
+ }
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&
+ (id->bInterfaceSubClass != uaa->info.bInterfaceSubClass)) {
+ continue;
+ }
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&
+ (id->bInterfaceProtocol != uaa->info.bInterfaceProtocol)) {
+ continue;
+ }
+ /* we found a match! */
+ return (id);
+ }
+
+done:
+ return (NULL);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_linux_probe
+ *
+ * This function is the FreeBSD probe callback. It is called from the
+ * FreeBSD USB stack through the "device_probe_and_attach()" function.
+ *------------------------------------------------------------------------*/
+static int
+usb_linux_probe(device_t dev)
+{
+ struct usb_attach_arg *uaa = device_get_ivars(dev);
+ struct usb_driver *udrv;
+ int err = ENXIO;
+
+ if (uaa->usb_mode != USB_MODE_HOST) {
+ return (ENXIO);
+ }
+ mtx_lock(&Giant);
+ LIST_FOREACH(udrv, &usb_linux_driver_list, linux_driver_list) {
+ if (usb_linux_lookup_id(udrv->id_table, uaa)) {
+ err = 0;
+ break;
+ }
+ }
+ mtx_unlock(&Giant);
+
+ return (err);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_linux_get_usb_driver
+ *
+ * This function returns the pointer to the "struct usb_driver" where
+ * the Linux USB device driver "struct usb_device_id" match was found.
+ * We apply a lock before reading out the pointer to avoid races.
+ *------------------------------------------------------------------------*/
+static struct usb_driver *
+usb_linux_get_usb_driver(struct usb_linux_softc *sc)
+{
+ struct usb_driver *udrv;
+
+ mtx_lock(&Giant);
+ udrv = sc->sc_udrv;
+ mtx_unlock(&Giant);
+ return (udrv);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_linux_attach
+ *
+ * This function is the FreeBSD attach callback. It is called from the
+ * FreeBSD USB stack through the "device_probe_and_attach()" function.
+ * This function is called when "usb_linux_probe()" returns zero.
+ *------------------------------------------------------------------------*/
+static int
+usb_linux_attach(device_t dev)
+{
+ struct usb_attach_arg *uaa = device_get_ivars(dev);
+ struct usb_linux_softc *sc = device_get_softc(dev);
+ struct usb_driver *udrv;
+ const struct usb_device_id *id = NULL;
+
+ mtx_lock(&Giant);
+ LIST_FOREACH(udrv, &usb_linux_driver_list, linux_driver_list) {
+ id = usb_linux_lookup_id(udrv->id_table, uaa);
+ if (id)
+ break;
+ }
+ mtx_unlock(&Giant);
+
+ if (id == NULL) {
+ return (ENXIO);
+ }
+ if (usb_linux_create_usb_device(uaa->device, dev) != 0)
+ return (ENOMEM);
+ device_set_usb_desc(dev);
+
+ sc->sc_fbsd_udev = uaa->device;
+ sc->sc_fbsd_dev = dev;
+ sc->sc_udrv = udrv;
+ sc->sc_ui = usb_ifnum_to_if(uaa->device, uaa->info.bIfaceNum);
+ if (sc->sc_ui == NULL) {
+ return (EINVAL);
+ }
+ if (udrv->probe) {
+ if ((udrv->probe) (sc->sc_ui, id)) {
+ return (ENXIO);
+ }
+ }
+ mtx_lock(&Giant);
+ LIST_INSERT_HEAD(&usb_linux_attached_list, sc, sc_attached_list);
+ mtx_unlock(&Giant);
+
+ /* success */
+ return (0);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_linux_detach
+ *
+ * This function is the FreeBSD detach callback. It is called from the
+ * FreeBSD USB stack through the "device_detach()" function.
+ *------------------------------------------------------------------------*/
+static int
+usb_linux_detach(device_t dev)
+{
+ struct usb_linux_softc *sc = device_get_softc(dev);
+ struct usb_driver *udrv = NULL;
+
+ mtx_lock(&Giant);
+ if (sc->sc_attached_list.le_prev) {
+ LIST_REMOVE(sc, sc_attached_list);
+ sc->sc_attached_list.le_prev = NULL;
+ udrv = sc->sc_udrv;
+ sc->sc_udrv = NULL;
+ }
+ mtx_unlock(&Giant);
+
+ if (udrv && udrv->disconnect) {
+ (udrv->disconnect) (sc->sc_ui);
+ }
+ /*
+ * Make sure that we free all FreeBSD USB transfers belonging to
+ * this Linux "usb_interface", hence they will most likely not be
+ * needed any more.
+ */
+ usb_linux_cleanup_interface(sc->sc_fbsd_udev, sc->sc_ui);
+ return (0);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_linux_suspend
+ *
+ * This function is the FreeBSD suspend callback. Usually it does nothing.
+ *------------------------------------------------------------------------*/
+static int
+usb_linux_suspend(device_t dev)
+{
+ struct usb_linux_softc *sc = device_get_softc(dev);
+ struct usb_driver *udrv = usb_linux_get_usb_driver(sc);
+ int err;
+
+ if (udrv && udrv->suspend) {
+ err = (udrv->suspend) (sc->sc_ui, 0);
+ }
+ return (0);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_linux_resume
+ *
+ * This function is the FreeBSD resume callback. Usually it does nothing.
+ *------------------------------------------------------------------------*/
+static int
+usb_linux_resume(device_t dev)
+{
+ struct usb_linux_softc *sc = device_get_softc(dev);
+ struct usb_driver *udrv = usb_linux_get_usb_driver(sc);
+ int err;
+
+ if (udrv && udrv->resume) {
+ err = (udrv->resume) (sc->sc_ui);
+ }
+ return (0);
+}
+
+/*------------------------------------------------------------------------*
+ * Linux emulation layer
+ *------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------*
+ * usb_max_isoc_frames
+ *
+ * The following function returns the maximum number of isochronous
+ * frames that we support per URB. It is not part of the Linux USB API.
+ *------------------------------------------------------------------------*/
+static uint16_t
+usb_max_isoc_frames(struct usb_device *dev)
+{
+ ; /* indent fix */
+ switch (usbd_get_speed(dev)) {
+ case USB_SPEED_LOW:
+ case USB_SPEED_FULL:
+ return (USB_MAX_FULL_SPEED_ISOC_FRAMES);
+ default:
+ return (USB_MAX_HIGH_SPEED_ISOC_FRAMES);
+ }
+}
+
+/*------------------------------------------------------------------------*
+ * usb_submit_urb
+ *
+ * This function is used to queue an URB after that it has been
+ * initialized. If it returns non-zero, it means that the URB was not
+ * queued.
+ *------------------------------------------------------------------------*/
+int
+usb_submit_urb(struct urb *urb, uint16_t mem_flags)
+{
+ struct usb_host_endpoint *uhe;
+ uint8_t do_unlock;
+ int err;
+
+ if (urb == NULL)
+ return (-EINVAL);
+
+ do_unlock = mtx_owned(&Giant) ? 0 : 1;
+ if (do_unlock)
+ mtx_lock(&Giant);
+
+ if (urb->endpoint == NULL) {
+ err = -EINVAL;
+ goto done;
+ }
+
+ /*
+ * Check to see if the urb is in the process of being killed
+ * and stop a urb that is in the process of being killed from
+ * being re-submitted (e.g. from its completion callback
+ * function).
+ */
+ if (urb->kill_count != 0) {
+ err = -EPERM;
+ goto done;
+ }
+
+ uhe = urb->endpoint;
+
+ /*
+ * Check that we have got a FreeBSD USB transfer that will dequeue
+ * the URB structure and do the real transfer. If there are no USB
+ * transfers, then we return an error.
+ */
+ if (uhe->bsd_xfer[0] ||
+ uhe->bsd_xfer[1]) {
+ /* we are ready! */
+
+ TAILQ_INSERT_TAIL(&uhe->bsd_urb_list, urb, bsd_urb_list);
+
+ urb->status = -EINPROGRESS;
+
+ usbd_transfer_start(uhe->bsd_xfer[0]);
+ usbd_transfer_start(uhe->bsd_xfer[1]);
+ err = 0;
+ } else {
+ /* no pipes have been setup yet! */
+ urb->status = -EINVAL;
+ err = -EINVAL;
+ }
+done:
+ if (do_unlock)
+ mtx_unlock(&Giant);
+ return (err);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_unlink_urb
+ *
+ * This function is used to stop an URB after that it is been
+ * submitted, but before the "complete" callback has been called. On
+ *------------------------------------------------------------------------*/
+int
+usb_unlink_urb(struct urb *urb)
+{
+ return (usb_unlink_urb_sub(urb, 0));
+}
+
+static void
+usb_unlink_bsd(struct usb_xfer *xfer,
+ struct urb *urb, uint8_t drain)
+{
+ if (xfer == NULL)
+ return;
+ if (!usbd_transfer_pending(xfer))
+ return;
+ if (xfer->priv_fifo == (void *)urb) {
+ if (drain) {
+ mtx_unlock(&Giant);
+ usbd_transfer_drain(xfer);
+ mtx_lock(&Giant);
+ } else {
+ usbd_transfer_stop(xfer);
+ }
+ usbd_transfer_start(xfer);
+ }
+}
+
+static int
+usb_unlink_urb_sub(struct urb *urb, uint8_t drain)
+{
+ struct usb_host_endpoint *uhe;
+ uint16_t x;
+ uint8_t do_unlock;
+ int err;
+
+ if (urb == NULL)
+ return (-EINVAL);
+
+ do_unlock = mtx_owned(&Giant) ? 0 : 1;
+ if (do_unlock)
+ mtx_lock(&Giant);
+ if (drain)
+ urb->kill_count++;
+
+ if (urb->endpoint == NULL) {
+ err = -EINVAL;
+ goto done;
+ }
+ uhe = urb->endpoint;
+
+ if (urb->bsd_urb_list.tqe_prev) {
+ /* not started yet, just remove it from the queue */
+ TAILQ_REMOVE(&uhe->bsd_urb_list, urb, bsd_urb_list);
+ urb->bsd_urb_list.tqe_prev = NULL;
+ urb->status = -ECONNRESET;
+ urb->actual_length = 0;
+
+ for (x = 0; x < urb->number_of_packets; x++) {
+ urb->iso_frame_desc[x].actual_length = 0;
+ }
+
+ if (urb->complete) {
+ (urb->complete) (urb);
+ }
+ } else {
+ /*
+ * If the URB is not on the URB list, then check if one of
+ * the FreeBSD USB transfer are processing the current URB.
+ * If so, re-start that transfer, which will lead to the
+ * termination of that URB:
+ */
+ usb_unlink_bsd(uhe->bsd_xfer[0], urb, drain);
+ usb_unlink_bsd(uhe->bsd_xfer[1], urb, drain);
+ }
+ err = 0;
+done:
+ if (drain)
+ urb->kill_count--;
+ if (do_unlock)
+ mtx_unlock(&Giant);
+ return (err);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_clear_halt
+ *
+ * This function must always be used to clear the stall. Stall is when
+ * an USB endpoint returns a stall message to the USB host controller.
+ * Until the stall is cleared, no data can be transferred.
+ *------------------------------------------------------------------------*/
+int
+usb_clear_halt(struct usb_device *dev, struct usb_host_endpoint *uhe)
+{
+ struct usb_config cfg[1];
+ struct usb_endpoint *ep;
+ uint8_t type;
+ uint8_t addr;
+
+ if (uhe == NULL)
+ return (-EINVAL);
+
+ type = uhe->desc.bmAttributes & UE_XFERTYPE;
+ addr = uhe->desc.bEndpointAddress;
+
+ memset(cfg, 0, sizeof(cfg));
+
+ cfg[0].type = type;
+ cfg[0].endpoint = addr & UE_ADDR;
+ cfg[0].direction = addr & (UE_DIR_OUT | UE_DIR_IN);
+
+ ep = usbd_get_endpoint(dev, uhe->bsd_iface_index, cfg);
+ if (ep == NULL)
+ return (-EINVAL);
+
+ usbd_clear_data_toggle(dev, ep);
+
+ return (usb_control_msg(dev, &dev->ep0,
+ UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT,
+ UF_ENDPOINT_HALT, addr, NULL, 0, 1000));
+}
+
+/*------------------------------------------------------------------------*
+ * usb_start_wait_urb
+ *
+ * This is an internal function that is used to perform synchronous
+ * Linux USB transfers.
+ *------------------------------------------------------------------------*/
+static int
+usb_start_wait_urb(struct urb *urb, usb_timeout_t timeout, uint16_t *p_actlen)
+{
+ int err;
+ uint8_t do_unlock;
+
+ /* you must have a timeout! */
+ if (timeout == 0) {
+ timeout = 1;
+ }
+ urb->complete = &usb_linux_wait_complete;
+ urb->timeout = timeout;
+ urb->transfer_flags |= URB_WAIT_WAKEUP;
+ urb->transfer_flags &= ~URB_IS_SLEEPING;
+
+ do_unlock = mtx_owned(&Giant) ? 0 : 1;
+ if (do_unlock)
+ mtx_lock(&Giant);
+ err = usb_submit_urb(urb, 0);
+ if (err)
+ goto done;
+
+ /*
+ * the URB might have completed before we get here, so check that by
+ * using some flags!
+ */
+ while (urb->transfer_flags & URB_WAIT_WAKEUP) {
+ urb->transfer_flags |= URB_IS_SLEEPING;
+ cv_wait(&urb->cv_wait, &Giant);
+ urb->transfer_flags &= ~URB_IS_SLEEPING;
+ }
+
+ err = urb->status;
+
+done:
+ if (do_unlock)
+ mtx_unlock(&Giant);
+ if (p_actlen != NULL) {
+ if (err)
+ *p_actlen = 0;
+ else
+ *p_actlen = urb->actual_length;
+ }
+ return (err);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_control_msg
+ *
+ * The following function performs a control transfer sequence one any
+ * control, bulk or interrupt endpoint, specified by "uhe". A control
+ * transfer means that you transfer an 8-byte header first followed by
+ * a data-phase as indicated by the 8-byte header. The "timeout" is
+ * given in milliseconds.
+ *
+ * Return values:
+ * 0: Success
+ * < 0: Failure
+ * > 0: Actual length
+ *------------------------------------------------------------------------*/
+int
+usb_control_msg(struct usb_device *dev, struct usb_host_endpoint *uhe,
+ uint8_t request, uint8_t requesttype,
+ uint16_t value, uint16_t index, void *data,
+ uint16_t size, usb_timeout_t timeout)
+{
+ struct usb_device_request req;
+ struct urb *urb;
+ int err;
+ uint16_t actlen;
+ uint8_t type;
+ uint8_t addr;
+
+ req.bmRequestType = requesttype;
+ req.bRequest = request;
+ USETW(req.wValue, value);
+ USETW(req.wIndex, index);
+ USETW(req.wLength, size);
+
+ if (uhe == NULL) {
+ return (-EINVAL);
+ }
+ type = (uhe->desc.bmAttributes & UE_XFERTYPE);
+ addr = (uhe->desc.bEndpointAddress & UE_ADDR);
+
+ if (type != UE_CONTROL) {
+ return (-EINVAL);
+ }
+ if (addr == 0) {
+ /*
+ * The FreeBSD USB stack supports standard control
+ * transfers on control endpoint zero:
+ */
+ err = usbd_do_request_flags(dev,
+ NULL, &req, data, USB_SHORT_XFER_OK,
+ &actlen, timeout);
+ if (err) {
+ err = -EPIPE;
+ } else {
+ err = actlen;
+ }
+ return (err);
+ }
+ if (dev->flags.usb_mode != USB_MODE_HOST) {
+ /* not supported */
+ return (-EINVAL);
+ }
+ err = usb_setup_endpoint(dev, uhe, 1 /* dummy */ );
+
+ /*
+ * NOTE: we need to allocate real memory here so that we don't
+ * transfer data to/from the stack!
+ *
+ * 0xFFFF is a FreeBSD specific magic value.
+ */
+ urb = usb_alloc_urb(0xFFFF, size);
+
+ urb->dev = dev;
+ urb->endpoint = uhe;
+
+ memcpy(urb->setup_packet, &req, sizeof(req));
+
+ if (size && (!(req.bmRequestType & UT_READ))) {
+ /* move the data to a real buffer */
+ memcpy(USB_ADD_BYTES(urb->setup_packet, sizeof(req)),
+ data, size);
+ }
+ err = usb_start_wait_urb(urb, timeout, &actlen);
+
+ if (req.bmRequestType & UT_READ) {
+ if (actlen) {
+ bcopy(USB_ADD_BYTES(urb->setup_packet,
+ sizeof(req)), data, actlen);
+ }
+ }
+ usb_free_urb(urb);
+
+ if (err == 0) {
+ err = actlen;
+ }
+ return (err);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_set_interface
+ *
+ * The following function will select which alternate setting of an
+ * USB interface you plan to use. By default alternate setting with
+ * index zero is selected. Note that "iface_no" is not the interface
+ * index, but rather the value of "bInterfaceNumber".
+ *------------------------------------------------------------------------*/
+int
+usb_set_interface(struct usb_device *dev, uint8_t iface_no, uint8_t alt_index)
+{
+ struct usb_interface *p_ui = usb_ifnum_to_if(dev, iface_no);
+ int err;
+
+ if (p_ui == NULL)
+ return (-EINVAL);
+ if (alt_index >= p_ui->num_altsetting)
+ return (-EINVAL);
+ usb_linux_cleanup_interface(dev, p_ui);
+ err = -usbd_set_alt_interface_index(dev,
+ p_ui->bsd_iface_index, alt_index);
+ if (err == 0) {
+ p_ui->cur_altsetting = p_ui->altsetting + alt_index;
+ }
+ return (err);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_setup_endpoint
+ *
+ * The following function is an extension to the Linux USB API that
+ * allows you to set a maximum buffer size for a given USB endpoint.
+ * The maximum buffer size is per URB. If you don't call this function
+ * to set a maximum buffer size, the endpoint will not be functional.
+ * Note that for isochronous endpoints the maximum buffer size must be
+ * a non-zero dummy, hence this function will base the maximum buffer
+ * size on "wMaxPacketSize".
+ *------------------------------------------------------------------------*/
+int
+usb_setup_endpoint(struct usb_device *dev,
+ struct usb_host_endpoint *uhe, usb_size_t bufsize)
+{
+ struct usb_config cfg[2];
+ uint8_t type = uhe->desc.bmAttributes & UE_XFERTYPE;
+ uint8_t addr = uhe->desc.bEndpointAddress;
+
+ if (uhe->fbsd_buf_size == bufsize) {
+ /* optimize */
+ return (0);
+ }
+ usbd_transfer_unsetup(uhe->bsd_xfer, 2);
+
+ uhe->fbsd_buf_size = bufsize;
+
+ if (bufsize == 0) {
+ return (0);
+ }
+ memset(cfg, 0, sizeof(cfg));
+
+ if (type == UE_ISOCHRONOUS) {
+ /*
+ * Isochronous transfers are special in that they don't fit
+ * into the BULK/INTR/CONTROL transfer model.
+ */
+
+ cfg[0].type = type;
+ cfg[0].endpoint = addr & UE_ADDR;
+ cfg[0].direction = addr & (UE_DIR_OUT | UE_DIR_IN);
+ cfg[0].callback = &usb_linux_isoc_callback;
+ cfg[0].bufsize = 0; /* use wMaxPacketSize */
+ cfg[0].frames = usb_max_isoc_frames(dev);
+ cfg[0].flags.proxy_buffer = 1;
+#if 0
+ /*
+ * The Linux USB API allows non back-to-back
+ * isochronous frames which we do not support. If the
+ * isochronous frames are not back-to-back we need to
+ * do a copy, and then we need a buffer for
+ * that. Enable this at your own risk.
+ */
+ cfg[0].flags.ext_buffer = 1;
+#endif
+ cfg[0].flags.short_xfer_ok = 1;
+
+ bcopy(cfg, cfg + 1, sizeof(*cfg));
+
+ /* Allocate and setup two generic FreeBSD USB transfers */
+
+ if (usbd_transfer_setup(dev, &uhe->bsd_iface_index,
+ uhe->bsd_xfer, cfg, 2, uhe, &Giant)) {
+ return (-EINVAL);
+ }
+ } else {
+ if (bufsize > (1 << 22)) {
+ /* limit buffer size */
+ bufsize = (1 << 22);
+ }
+ /* Allocate and setup one generic FreeBSD USB transfer */
+
+ cfg[0].type = type;
+ cfg[0].endpoint = addr & UE_ADDR;
+ cfg[0].direction = addr & (UE_DIR_OUT | UE_DIR_IN);
+ cfg[0].callback = &usb_linux_non_isoc_callback;
+ cfg[0].bufsize = bufsize;
+ cfg[0].flags.ext_buffer = 1; /* enable zero-copy */
+ cfg[0].flags.proxy_buffer = 1;
+ cfg[0].flags.short_xfer_ok = 1;
+
+ if (usbd_transfer_setup(dev, &uhe->bsd_iface_index,
+ uhe->bsd_xfer, cfg, 1, uhe, &Giant)) {
+ return (-EINVAL);
+ }
+ }
+ return (0);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_linux_create_usb_device
+ *
+ * The following function is used to build up a per USB device
+ * structure tree, that mimics the Linux one. The root structure
+ * is returned by this function.
+ *------------------------------------------------------------------------*/
+static int
+usb_linux_create_usb_device(struct usb_device *udev, device_t dev)
+{
+ struct usb_config_descriptor *cd = usbd_get_config_descriptor(udev);
+ struct usb_descriptor *desc;
+ struct usb_interface_descriptor *id;
+ struct usb_endpoint_descriptor *ed;
+ struct usb_interface *p_ui = NULL;
+ struct usb_host_interface *p_uhi = NULL;
+ struct usb_host_endpoint *p_uhe = NULL;
+ usb_size_t size;
+ uint16_t niface_total;
+ uint16_t nedesc;
+ uint16_t iface_no_curr;
+ uint16_t iface_index;
+ uint8_t pass;
+ uint8_t iface_no;
+
+ /*
+ * We do two passes. One pass for computing necessary memory size
+ * and one pass to initialize all the allocated memory structures.
+ */
+ for (pass = 0; pass < 2; pass++) {
+ iface_no_curr = 0xFFFF;
+ niface_total = 0;
+ iface_index = 0;
+ nedesc = 0;
+ desc = NULL;
+
+ /*
+ * Iterate over all the USB descriptors. Use the USB config
+ * descriptor pointer provided by the FreeBSD USB stack.
+ */
+ while ((desc = usb_desc_foreach(cd, desc))) {
+ /*
+ * Build up a tree according to the descriptors we
+ * find:
+ */
+ switch (desc->bDescriptorType) {
+ case UDESC_DEVICE:
+ break;
+
+ case UDESC_ENDPOINT:
+ ed = (void *)desc;
+ if ((ed->bLength < sizeof(*ed)) ||
+ (iface_index == 0))
+ break;
+ if (p_uhe) {
+ bcopy(ed, &p_uhe->desc, sizeof(p_uhe->desc));
+ p_uhe->bsd_iface_index = iface_index - 1;
+ TAILQ_INIT(&p_uhe->bsd_urb_list);
+ p_uhe++;
+ }
+ if (p_uhi) {
+ (p_uhi - 1)->desc.bNumEndpoints++;
+ }
+ nedesc++;
+ break;
+
+ case UDESC_INTERFACE:
+ id = (void *)desc;
+ if (id->bLength < sizeof(*id))
+ break;
+ if (p_uhi) {
+ bcopy(id, &p_uhi->desc, sizeof(p_uhi->desc));
+ p_uhi->desc.bNumEndpoints = 0;
+ p_uhi->endpoint = p_uhe;
+ p_uhi->string = "";
+ p_uhi->bsd_iface_index = iface_index;
+ p_uhi++;
+ }
+ iface_no = id->bInterfaceNumber;
+ niface_total++;
+ if (iface_no_curr != iface_no) {
+ if (p_ui) {
+ p_ui->altsetting = p_uhi - 1;
+ p_ui->cur_altsetting = p_uhi - 1;
+ p_ui->bsd_iface_index = iface_index;
+ p_ui->linux_udev = udev;
+ p_ui++;
+ }
+ iface_no_curr = iface_no;
+ iface_index++;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (pass == 0) {
+ size = (sizeof(*p_uhe) * nedesc) +
+ (sizeof(*p_ui) * iface_index) +
+ (sizeof(*p_uhi) * niface_total);
+
+ p_uhe = malloc(size, M_USBDEV, M_WAITOK | M_ZERO);
+ p_ui = (void *)(p_uhe + nedesc);
+ p_uhi = (void *)(p_ui + iface_index);
+
+ udev->linux_iface_start = p_ui;
+ udev->linux_iface_end = p_ui + iface_index;
+ udev->linux_endpoint_start = p_uhe;
+ udev->linux_endpoint_end = p_uhe + nedesc;
+ udev->devnum = device_get_unit(dev);
+ bcopy(&udev->ddesc, &udev->descriptor,
+ sizeof(udev->descriptor));
+ bcopy(udev->ctrl_ep.edesc, &udev->ep0.desc,
+ sizeof(udev->ep0.desc));
+ }
+ }
+ return (0);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_alloc_urb
+ *
+ * This function should always be used when you allocate an URB for
+ * use with the USB Linux stack. In case of an isochronous transfer
+ * you must specifiy the maximum number of "iso_packets" which you
+ * plan to transfer per URB. This function is always blocking, and
+ * "mem_flags" are not regarded like on Linux.
+ *------------------------------------------------------------------------*/
+struct urb *
+usb_alloc_urb(uint16_t iso_packets, uint16_t mem_flags)
+{
+ struct urb *urb;
+ usb_size_t size;
+
+ if (iso_packets == 0xFFFF) {
+ /*
+ * FreeBSD specific magic value to ask for control transfer
+ * memory allocation:
+ */
+ size = sizeof(*urb) + sizeof(struct usb_device_request) + mem_flags;
+ } else {
+ size = sizeof(*urb) + (iso_packets * sizeof(urb->iso_frame_desc[0]));
+ }
+
+ urb = malloc(size, M_USBDEV, M_WAITOK | M_ZERO);
+
+ cv_init(&urb->cv_wait, "URBWAIT");
+ if (iso_packets == 0xFFFF) {
+ urb->setup_packet = (void *)(urb + 1);
+ urb->transfer_buffer = (void *)(urb->setup_packet +
+ sizeof(struct usb_device_request));
+ } else {
+ urb->number_of_packets = iso_packets;
+ }
+ return (urb);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_find_host_endpoint
+ *
+ * The following function will return the Linux USB host endpoint
+ * structure that matches the given endpoint type and endpoint
+ * value. If no match is found, NULL is returned. This function is not
+ * part of the Linux USB API and is only used internally.
+ *------------------------------------------------------------------------*/
+struct usb_host_endpoint *
+usb_find_host_endpoint(struct usb_device *dev, uint8_t type, uint8_t ep)
+{
+ struct usb_host_endpoint *uhe;
+ struct usb_host_endpoint *uhe_end;
+ struct usb_host_interface *uhi;
+ struct usb_interface *ui;
+ uint8_t ea;
+ uint8_t at;
+ uint8_t mask;
+
+ if (dev == NULL) {
+ return (NULL);
+ }
+ if (type == UE_CONTROL) {
+ mask = UE_ADDR;
+ } else {
+ mask = (UE_DIR_IN | UE_DIR_OUT | UE_ADDR);
+ }
+
+ ep &= mask;
+
+ /*
+ * Iterate over all the interfaces searching the selected alternate
+ * setting only, and all belonging endpoints.
+ */
+ for (ui = dev->linux_iface_start;
+ ui != dev->linux_iface_end;
+ ui++) {
+ uhi = ui->cur_altsetting;
+ if (uhi) {
+ uhe_end = uhi->endpoint + uhi->desc.bNumEndpoints;
+ for (uhe = uhi->endpoint;
+ uhe != uhe_end;
+ uhe++) {
+ ea = uhe->desc.bEndpointAddress;
+ at = uhe->desc.bmAttributes;
+
+ if (((ea & mask) == ep) &&
+ ((at & UE_XFERTYPE) == type)) {
+ return (uhe);
+ }
+ }
+ }
+ }
+
+ if ((type == UE_CONTROL) && ((ep & UE_ADDR) == 0)) {
+ return (&dev->ep0);
+ }
+ return (NULL);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_altnum_to_altsetting
+ *
+ * The following function returns a pointer to an alternate setting by
+ * index given a "usb_interface" pointer. If the alternate setting by
+ * index does not exist, NULL is returned. And alternate setting is a
+ * variant of an interface, but usually with slightly different
+ * characteristics.
+ *------------------------------------------------------------------------*/
+struct usb_host_interface *
+usb_altnum_to_altsetting(const struct usb_interface *intf, uint8_t alt_index)
+{
+ if (alt_index >= intf->num_altsetting) {
+ return (NULL);
+ }
+ return (intf->altsetting + alt_index);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_ifnum_to_if
+ *
+ * The following function searches up an USB interface by
+ * "bInterfaceNumber". If no match is found, NULL is returned.
+ *------------------------------------------------------------------------*/
+struct usb_interface *
+usb_ifnum_to_if(struct usb_device *dev, uint8_t iface_no)
+{
+ struct usb_interface *p_ui;
+
+ for (p_ui = dev->linux_iface_start;
+ p_ui != dev->linux_iface_end;
+ p_ui++) {
+ if ((p_ui->num_altsetting > 0) &&
+ (p_ui->altsetting->desc.bInterfaceNumber == iface_no)) {
+ return (p_ui);
+ }
+ }
+ return (NULL);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_buffer_alloc
+ *------------------------------------------------------------------------*/
+void *
+usb_buffer_alloc(struct usb_device *dev, usb_size_t size, uint16_t mem_flags, uint8_t *dma_addr)
+{
+ return (malloc(size, M_USBDEV, M_WAITOK | M_ZERO));
+}
+
+/*------------------------------------------------------------------------*
+ * usbd_get_intfdata
+ *------------------------------------------------------------------------*/
+void *
+usbd_get_intfdata(struct usb_interface *intf)
+{
+ return (intf->bsd_priv_sc);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_linux_register
+ *
+ * The following function is used by the "USB_DRIVER_EXPORT()" macro,
+ * and is used to register a Linux USB driver, so that its
+ * "usb_device_id" structures gets searched a probe time. This
+ * function is not part of the Linux USB API, and is for internal use
+ * only.
+ *------------------------------------------------------------------------*/
+void
+usb_linux_register(void *arg)
+{
+ struct usb_driver *drv = arg;
+
+ mtx_lock(&Giant);
+ LIST_INSERT_HEAD(&usb_linux_driver_list, drv, linux_driver_list);
+ mtx_unlock(&Giant);
+
+ usb_needs_explore_all();
+}
+
+/*------------------------------------------------------------------------*
+ * usb_linux_deregister
+ *
+ * The following function is used by the "USB_DRIVER_EXPORT()" macro,
+ * and is used to deregister a Linux USB driver. This function will
+ * ensure that all driver instances belonging to the Linux USB device
+ * driver in question, gets detached before the driver is
+ * unloaded. This function is not part of the Linux USB API, and is
+ * for internal use only.
+ *------------------------------------------------------------------------*/
+void
+usb_linux_deregister(void *arg)
+{
+ struct usb_driver *drv = arg;
+ struct usb_linux_softc *sc;
+
+repeat:
+ mtx_lock(&Giant);
+ LIST_FOREACH(sc, &usb_linux_attached_list, sc_attached_list) {
+ if (sc->sc_udrv == drv) {
+ mtx_unlock(&Giant);
+ device_detach(sc->sc_fbsd_dev);
+ goto repeat;
+ }
+ }
+ LIST_REMOVE(drv, linux_driver_list);
+ mtx_unlock(&Giant);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_linux_free_device
+ *
+ * The following function is only used by the FreeBSD USB stack, to
+ * cleanup and free memory after that a Linux USB device was attached.
+ *------------------------------------------------------------------------*/
+void
+usb_linux_free_device(struct usb_device *dev)
+{
+ struct usb_host_endpoint *uhe;
+ struct usb_host_endpoint *uhe_end;
+ int err;
+
+ uhe = dev->linux_endpoint_start;
+ uhe_end = dev->linux_endpoint_end;
+ while (uhe != uhe_end) {
+ err = usb_setup_endpoint(dev, uhe, 0);
+ uhe++;
+ }
+ err = usb_setup_endpoint(dev, &dev->ep0, 0);
+ free(dev->linux_endpoint_start, M_USBDEV);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_buffer_free
+ *------------------------------------------------------------------------*/
+void
+usb_buffer_free(struct usb_device *dev, usb_size_t size,
+ void *addr, uint8_t dma_addr)
+{
+ free(addr, M_USBDEV);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_free_urb
+ *------------------------------------------------------------------------*/
+void
+usb_free_urb(struct urb *urb)
+{
+ if (urb == NULL) {
+ return;
+ }
+ /* make sure that the current URB is not active */
+ usb_kill_urb(urb);
+
+ /* destroy condition variable */
+ cv_destroy(&urb->cv_wait);
+
+ /* just free it */
+ free(urb, M_USBDEV);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_init_urb
+ *
+ * The following function can be used to initialize a custom URB. It
+ * is not recommended to use this function. Use "usb_alloc_urb()"
+ * instead.
+ *------------------------------------------------------------------------*/
+void
+usb_init_urb(struct urb *urb)
+{
+ if (urb == NULL) {
+ return;
+ }
+ memset(urb, 0, sizeof(*urb));
+}
+
+/*------------------------------------------------------------------------*
+ * usb_kill_urb
+ *------------------------------------------------------------------------*/
+void
+usb_kill_urb(struct urb *urb)
+{
+ usb_unlink_urb_sub(urb, 1);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_set_intfdata
+ *
+ * The following function sets the per Linux USB interface private
+ * data pointer. It is used by most Linux USB device drivers.
+ *------------------------------------------------------------------------*/
+void
+usb_set_intfdata(struct usb_interface *intf, void *data)
+{
+ intf->bsd_priv_sc = data;
+}
+
+/*------------------------------------------------------------------------*
+ * usb_linux_cleanup_interface
+ *
+ * The following function will release all FreeBSD USB transfers
+ * associated with a Linux USB interface. It is for internal use only.
+ *------------------------------------------------------------------------*/
+static void
+usb_linux_cleanup_interface(struct usb_device *dev, struct usb_interface *iface)
+{
+ struct usb_host_interface *uhi;
+ struct usb_host_interface *uhi_end;
+ struct usb_host_endpoint *uhe;
+ struct usb_host_endpoint *uhe_end;
+ int err;
+
+ uhi = iface->altsetting;
+ uhi_end = iface->altsetting + iface->num_altsetting;
+ while (uhi != uhi_end) {
+ uhe = uhi->endpoint;
+ uhe_end = uhi->endpoint + uhi->desc.bNumEndpoints;
+ while (uhe != uhe_end) {
+ err = usb_setup_endpoint(dev, uhe, 0);
+ uhe++;
+ }
+ uhi++;
+ }
+}
+
+/*------------------------------------------------------------------------*
+ * usb_linux_wait_complete
+ *
+ * The following function is used by "usb_start_wait_urb()" to wake it
+ * up, when an USB transfer has finished.
+ *------------------------------------------------------------------------*/
+static void
+usb_linux_wait_complete(struct urb *urb)
+{
+ if (urb->transfer_flags & URB_IS_SLEEPING) {
+ cv_signal(&urb->cv_wait);
+ }
+ urb->transfer_flags &= ~URB_WAIT_WAKEUP;
+}
+
+/*------------------------------------------------------------------------*
+ * usb_linux_complete
+ *------------------------------------------------------------------------*/
+static void
+usb_linux_complete(struct usb_xfer *xfer)
+{
+ struct urb *urb;
+
+ urb = usbd_xfer_get_priv(xfer);
+ usbd_xfer_set_priv(xfer, NULL);
+ if (urb->complete) {
+ (urb->complete) (urb);
+ }
+}
+
+/*------------------------------------------------------------------------*
+ * usb_linux_isoc_callback
+ *
+ * The following is the FreeBSD isochronous USB callback. Isochronous
+ * frames are USB packets transferred 1000 or 8000 times per second,
+ * depending on whether a full- or high- speed USB transfer is
+ * used.
+ *------------------------------------------------------------------------*/
+static void
+usb_linux_isoc_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+ usb_frlength_t max_frame = xfer->max_frame_size;
+ usb_frlength_t offset;
+ usb_frcount_t x;
+ struct urb *urb = usbd_xfer_get_priv(xfer);
+ struct usb_host_endpoint *uhe = usbd_xfer_softc(xfer);
+ struct usb_iso_packet_descriptor *uipd;
+
+ DPRINTF("\n");
+
+ switch (USB_GET_STATE(xfer)) {
+ case USB_ST_TRANSFERRED:
+
+ if (urb->bsd_isread) {
+ /* copy in data with regard to the URB */
+
+ offset = 0;
+
+ for (x = 0; x < urb->number_of_packets; x++) {
+ uipd = urb->iso_frame_desc + x;
+ if (uipd->length > xfer->frlengths[x]) {
+ if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+ /* XXX should be EREMOTEIO */
+ uipd->status = -EPIPE;
+ } else {
+ uipd->status = 0;
+ }
+ } else {
+ uipd->status = 0;
+ }
+ uipd->actual_length = xfer->frlengths[x];
+ if (!xfer->flags.ext_buffer) {
+ usbd_copy_out(xfer->frbuffers, offset,
+ USB_ADD_BYTES(urb->transfer_buffer,
+ uipd->offset), uipd->actual_length);
+ }
+ offset += max_frame;
+ }
+ } else {
+ for (x = 0; x < urb->number_of_packets; x++) {
+ uipd = urb->iso_frame_desc + x;
+ uipd->actual_length = xfer->frlengths[x];
+ uipd->status = 0;
+ }
+ }
+
+ urb->actual_length = xfer->actlen;
+
+ /* check for short transfer */
+ if (xfer->actlen < xfer->sumlen) {
+ /* short transfer */
+ if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+ /* XXX should be EREMOTEIO */
+ urb->status = -EPIPE;
+ } else {
+ urb->status = 0;
+ }
+ } else {
+ /* success */
+ urb->status = 0;
+ }
+
+ /* call callback */
+ usb_linux_complete(xfer);
+
+ case USB_ST_SETUP:
+tr_setup:
+
+ if (xfer->priv_fifo == NULL) {
+ /* get next transfer */
+ urb = TAILQ_FIRST(&uhe->bsd_urb_list);
+ if (urb == NULL) {
+ /* nothing to do */
+ return;
+ }
+ TAILQ_REMOVE(&uhe->bsd_urb_list, urb, bsd_urb_list);
+ urb->bsd_urb_list.tqe_prev = NULL;
+
+ x = xfer->max_frame_count;
+ if (urb->number_of_packets > x) {
+ /* XXX simply truncate the transfer */
+ urb->number_of_packets = x;
+ }
+ } else {
+ DPRINTF("Already got a transfer\n");
+
+ /* already got a transfer (should not happen) */
+ urb = usbd_xfer_get_priv(xfer);
+ }
+
+ urb->bsd_isread = (uhe->desc.bEndpointAddress & UE_DIR_IN) ? 1 : 0;
+
+ if (xfer->flags.ext_buffer) {
+ /* set virtual address to load */
+ usbd_xfer_set_frame_data(xfer, 0, urb->transfer_buffer, 0);
+ }
+ if (!(urb->bsd_isread)) {
+ /* copy out data with regard to the URB */
+
+ offset = 0;
+
+ for (x = 0; x < urb->number_of_packets; x++) {
+ uipd = urb->iso_frame_desc + x;
+ usbd_xfer_set_frame_len(xfer, x, uipd->length);
+ if (!xfer->flags.ext_buffer) {
+ usbd_copy_in(xfer->frbuffers, offset,
+ USB_ADD_BYTES(urb->transfer_buffer,
+ uipd->offset), uipd->length);
+ }
+ offset += uipd->length;
+ }
+ } else {
+ /*
+ * compute the transfer length into the "offset"
+ * variable
+ */
+
+ offset = urb->number_of_packets * max_frame;
+
+ /* setup "frlengths" array */
+
+ for (x = 0; x < urb->number_of_packets; x++) {
+ uipd = urb->iso_frame_desc + x;
+ usbd_xfer_set_frame_len(xfer, x, max_frame);
+ }
+ }
+ usbd_xfer_set_priv(xfer, urb);
+ xfer->flags.force_short_xfer = 0;
+ xfer->timeout = urb->timeout;
+ xfer->nframes = urb->number_of_packets;
+ usbd_transfer_submit(xfer);
+ return;
+
+ default: /* Error */
+ if (xfer->error == USB_ERR_CANCELLED) {
+ urb->status = -ECONNRESET;
+ } else {
+ urb->status = -EPIPE; /* stalled */
+ }
+
+ /* Set zero for "actual_length" */
+ urb->actual_length = 0;
+
+ /* Set zero for "actual_length" */
+ for (x = 0; x < urb->number_of_packets; x++) {
+ urb->iso_frame_desc[x].actual_length = 0;
+ urb->iso_frame_desc[x].status = urb->status;
+ }
+
+ /* call callback */
+ usb_linux_complete(xfer);
+
+ if (xfer->error == USB_ERR_CANCELLED) {
+ /* we need to return in this case */
+ return;
+ }
+ goto tr_setup;
+ }
+}
+
+/*------------------------------------------------------------------------*
+ * usb_linux_non_isoc_callback
+ *
+ * The following is the FreeBSD BULK/INTERRUPT and CONTROL USB
+ * callback. It dequeues Linux USB stack compatible URB's, transforms
+ * the URB fields into a FreeBSD USB transfer, and defragments the USB
+ * transfer as required. When the transfer is complete the "complete"
+ * callback is called.
+ *------------------------------------------------------------------------*/
+static void
+usb_linux_non_isoc_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+ enum {
+ REQ_SIZE = sizeof(struct usb_device_request)
+ };
+ struct urb *urb = usbd_xfer_get_priv(xfer);
+ struct usb_host_endpoint *uhe = usbd_xfer_softc(xfer);
+ uint8_t *ptr;
+ usb_frlength_t max_bulk = usbd_xfer_max_len(xfer);
+ uint8_t data_frame = xfer->flags_int.control_xfr ? 1 : 0;
+
+ DPRINTF("\n");
+
+ switch (USB_GET_STATE(xfer)) {
+ case USB_ST_TRANSFERRED:
+
+ if (xfer->flags_int.control_xfr) {
+ /* don't transfer the setup packet again: */
+
+ usbd_xfer_set_frame_len(xfer, 0, 0);
+ }
+ if (urb->bsd_isread && (!xfer->flags.ext_buffer)) {
+ /* copy in data with regard to the URB */
+ usbd_copy_out(xfer->frbuffers + data_frame, 0,
+ urb->bsd_data_ptr, xfer->frlengths[data_frame]);
+ }
+ urb->bsd_length_rem -= xfer->frlengths[data_frame];
+ urb->bsd_data_ptr += xfer->frlengths[data_frame];
+ urb->actual_length += xfer->frlengths[data_frame];
+
+ /* check for short transfer */
+ if (xfer->actlen < xfer->sumlen) {
+ urb->bsd_length_rem = 0;
+
+ /* short transfer */
+ if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+ urb->status = -EPIPE;
+ } else {
+ urb->status = 0;
+ }
+ } else {
+ /* check remainder */
+ if (urb->bsd_length_rem > 0) {
+ goto setup_bulk;
+ }
+ /* success */
+ urb->status = 0;
+ }
+
+ /* call callback */
+ usb_linux_complete(xfer);
+
+ case USB_ST_SETUP:
+tr_setup:
+ /* get next transfer */
+ urb = TAILQ_FIRST(&uhe->bsd_urb_list);
+ if (urb == NULL) {
+ /* nothing to do */
+ return;
+ }
+ TAILQ_REMOVE(&uhe->bsd_urb_list, urb, bsd_urb_list);
+ urb->bsd_urb_list.tqe_prev = NULL;
+
+ usbd_xfer_set_priv(xfer, urb);
+ xfer->flags.force_short_xfer = 0;
+ xfer->timeout = urb->timeout;
+
+ if (xfer->flags_int.control_xfr) {
+ /*
+ * USB control transfers need special handling.
+ * First copy in the header, then copy in data!
+ */
+ if (!xfer->flags.ext_buffer) {
+ usbd_copy_in(xfer->frbuffers, 0,
+ urb->setup_packet, REQ_SIZE);
+ usbd_xfer_set_frame_len(xfer, 0, REQ_SIZE);
+ } else {
+ /* set virtual address to load */
+ usbd_xfer_set_frame_data(xfer, 0,
+ urb->setup_packet, REQ_SIZE);
+ }
+
+ ptr = urb->setup_packet;
+
+ /* setup data transfer direction and length */
+ urb->bsd_isread = (ptr[0] & UT_READ) ? 1 : 0;
+ urb->bsd_length_rem = ptr[6] | (ptr[7] << 8);
+
+ } else {
+ /* setup data transfer direction */
+
+ urb->bsd_length_rem = urb->transfer_buffer_length;
+ urb->bsd_isread = (uhe->desc.bEndpointAddress &
+ UE_DIR_IN) ? 1 : 0;
+ }
+
+ urb->bsd_data_ptr = urb->transfer_buffer;
+ urb->actual_length = 0;
+
+setup_bulk:
+ if (max_bulk > urb->bsd_length_rem) {
+ max_bulk = urb->bsd_length_rem;
+ }
+ /* check if we need to force a short transfer */
+
+ if ((max_bulk == urb->bsd_length_rem) &&
+ (urb->transfer_flags & URB_ZERO_PACKET) &&
+ (!xfer->flags_int.control_xfr)) {
+ xfer->flags.force_short_xfer = 1;
+ }
+ /* check if we need to copy in data */
+
+ if (xfer->flags.ext_buffer) {
+ /* set virtual address to load */
+ usbd_xfer_set_frame_data(xfer, data_frame,
+ urb->bsd_data_ptr, max_bulk);
+ } else if (!urb->bsd_isread) {
+ /* copy out data with regard to the URB */
+ usbd_copy_in(xfer->frbuffers + data_frame, 0,
+ urb->bsd_data_ptr, max_bulk);
+ usbd_xfer_set_frame_len(xfer, data_frame, max_bulk);
+ }
+ if (xfer->flags_int.control_xfr) {
+ if (max_bulk > 0) {
+ xfer->nframes = 2;
+ } else {
+ xfer->nframes = 1;
+ }
+ } else {
+ xfer->nframes = 1;
+ }
+ usbd_transfer_submit(xfer);
+ return;
+
+ default:
+ if (xfer->error == USB_ERR_CANCELLED) {
+ urb->status = -ECONNRESET;
+ } else {
+ urb->status = -EPIPE;
+ }
+
+ /* Set zero for "actual_length" */
+ urb->actual_length = 0;
+
+ /* call callback */
+ usb_linux_complete(xfer);
+
+ if (xfer->error == USB_ERR_CANCELLED) {
+ /* we need to return in this case */
+ return;
+ }
+ goto tr_setup;
+ }
+}
+
+/*------------------------------------------------------------------------*
+ * usb_fill_bulk_urb
+ *------------------------------------------------------------------------*/
+void
+usb_fill_bulk_urb(struct urb *urb, struct usb_device *udev,
+ struct usb_host_endpoint *uhe, void *buf,
+ int length, usb_complete_t callback, void *arg)
+{
+ urb->dev = udev;
+ urb->endpoint = uhe;
+ urb->transfer_buffer = buf;
+ urb->transfer_buffer_length = length;
+ urb->complete = callback;
+ urb->context = arg;
+}
+
+/*------------------------------------------------------------------------*
+ * usb_bulk_msg
+ *
+ * NOTE: This function can also be used for interrupt endpoints!
+ *
+ * Return values:
+ * 0: Success
+ * Else: Failure
+ *------------------------------------------------------------------------*/
+int
+usb_bulk_msg(struct usb_device *udev, struct usb_host_endpoint *uhe,
+ void *data, int len, uint16_t *pactlen, usb_timeout_t timeout)
+{
+ struct urb *urb;
+ int err;
+
+ if (uhe == NULL)
+ return (-EINVAL);
+ if (len < 0)
+ return (-EINVAL);
+
+ err = usb_setup_endpoint(udev, uhe, 4096 /* bytes */);
+ if (err)
+ return (err);
+
+ urb = usb_alloc_urb(0, 0);
+
+ usb_fill_bulk_urb(urb, udev, uhe, data, len,
+ usb_linux_wait_complete, NULL);
+
+ err = usb_start_wait_urb(urb, timeout, pactlen);
+
+ usb_free_urb(urb);
+
+ return (err);
+}
+MODULE_DEPEND(linuxkpi, usb, 1, 1, 1);
+
+static void
+usb_linux_init(void *arg)
+{
+ /* register our function */
+ usb_linux_free_device_p = &usb_linux_free_device;
+}
+SYSINIT(usb_linux_init, SI_SUB_LOCK, SI_ORDER_FIRST, usb_linux_init, NULL);
+SYSUNINIT(usb_linux_unload, SI_SUB_LOCK, SI_ORDER_ANY, usb_linux_unload, NULL);
diff --git a/sys/compat/linuxkpi/common/src/linux_work.c b/sys/compat/linuxkpi/common/src/linux_work.c
new file mode 100644
index 000000000000..f9cf62928760
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_work.c
@@ -0,0 +1,738 @@
+/*-
+ * Copyright (c) 2017-2019 Hans Petter Selasky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <linux/workqueue.h>
+#include <linux/wait.h>
+#include <linux/compat.h>
+#include <linux/spinlock.h>
+#include <linux/rcupdate.h>
+#include <linux/irq_work.h>
+
+#include <sys/kernel.h>
+
+/*
+ * Define all work struct states
+ */
+enum {
+ WORK_ST_IDLE, /* idle - not started */
+ WORK_ST_TIMER, /* timer is being started */
+ WORK_ST_TASK, /* taskqueue is being queued */
+ WORK_ST_EXEC, /* callback is being called */
+ WORK_ST_CANCEL, /* cancel is being requested */
+ WORK_ST_MAX,
+};
+
+/*
+ * Define global workqueues
+ */
+static struct workqueue_struct *linux_system_short_wq;
+static struct workqueue_struct *linux_system_long_wq;
+
+struct workqueue_struct *system_wq;
+struct workqueue_struct *system_long_wq;
+struct workqueue_struct *system_unbound_wq;
+struct workqueue_struct *system_highpri_wq;
+struct workqueue_struct *system_power_efficient_wq;
+
+struct taskqueue *linux_irq_work_tq;
+
+static int linux_default_wq_cpus = 4;
+
+static void linux_delayed_work_timer_fn(void *);
+
+/*
+ * This function atomically updates the work state and returns the
+ * previous state at the time of update.
+ */
+static uint8_t
+linux_update_state(atomic_t *v, const uint8_t *pstate)
+{
+ int c, old;
+
+ c = v->counter;
+
+ while ((old = atomic_cmpxchg(v, c, pstate[c])) != c)
+ c = old;
+
+ return (c);
+}
+
+/*
+ * A LinuxKPI task is allowed to free itself inside the callback function
+ * and cannot safely be referred after the callback function has
+ * completed. This function gives the linux_work_fn() function a hint,
+ * that the task is not going away and can have its state checked
+ * again. Without this extra hint LinuxKPI tasks cannot be serialized
+ * accross multiple worker threads.
+ */
+static bool
+linux_work_exec_unblock(struct work_struct *work)
+{
+ struct workqueue_struct *wq;
+ struct work_exec *exec;
+ bool retval = false;
+
+ wq = work->work_queue;
+ if (unlikely(wq == NULL))
+ goto done;
+
+ WQ_EXEC_LOCK(wq);
+ TAILQ_FOREACH(exec, &wq->exec_head, entry) {
+ if (exec->target == work) {
+ exec->target = NULL;
+ retval = true;
+ break;
+ }
+ }
+ WQ_EXEC_UNLOCK(wq);
+done:
+ return (retval);
+}
+
+static void
+linux_delayed_work_enqueue(struct delayed_work *dwork)
+{
+ struct taskqueue *tq;
+
+ tq = dwork->work.work_queue->taskqueue;
+ taskqueue_enqueue(tq, &dwork->work.work_task);
+}
+
+/*
+ * This function queues the given work structure on the given
+ * workqueue. It returns non-zero if the work was successfully
+ * [re-]queued. Else the work is already pending for completion.
+ */
+bool
+linux_queue_work_on(int cpu __unused, struct workqueue_struct *wq,
+ struct work_struct *work)
+{
+ static const uint8_t states[WORK_ST_MAX] __aligned(8) = {
+ [WORK_ST_IDLE] = WORK_ST_TASK, /* start queuing task */
+ [WORK_ST_TIMER] = WORK_ST_TIMER, /* NOP */
+ [WORK_ST_TASK] = WORK_ST_TASK, /* NOP */
+ [WORK_ST_EXEC] = WORK_ST_TASK, /* queue task another time */
+ [WORK_ST_CANCEL] = WORK_ST_TASK, /* start queuing task again */
+ };
+
+ if (atomic_read(&wq->draining) != 0)
+ return (!work_pending(work));
+
+ switch (linux_update_state(&work->state, states)) {
+ case WORK_ST_EXEC:
+ case WORK_ST_CANCEL:
+ if (linux_work_exec_unblock(work) != 0)
+ return (true);
+ /* FALLTHROUGH */
+ case WORK_ST_IDLE:
+ work->work_queue = wq;
+ taskqueue_enqueue(wq->taskqueue, &work->work_task);
+ return (true);
+ default:
+ return (false); /* already on a queue */
+ }
+}
+
+/*
+ * Callback func for linux_queue_rcu_work
+ */
+static void
+rcu_work_func(struct rcu_head *rcu)
+{
+ struct rcu_work *rwork;
+
+ rwork = container_of(rcu, struct rcu_work, rcu);
+ linux_queue_work_on(WORK_CPU_UNBOUND, rwork->wq, &rwork->work);
+}
+
+/*
+ * This function queue a work after a grace period
+ * If the work was already pending it returns false,
+ * if not it calls call_rcu and returns true.
+ */
+bool
+linux_queue_rcu_work(struct workqueue_struct *wq, struct rcu_work *rwork)
+{
+
+ if (!linux_work_pending(&rwork->work)) {
+ rwork->wq = wq;
+ linux_call_rcu(RCU_TYPE_REGULAR, &rwork->rcu, rcu_work_func);
+ return (true);
+ }
+ return (false);
+}
+
+/*
+ * This function waits for the last execution of a work and then
+ * flush the work.
+ * It returns true if the work was pending and we waited, it returns
+ * false otherwise.
+ */
+bool
+linux_flush_rcu_work(struct rcu_work *rwork)
+{
+
+ if (linux_work_pending(&rwork->work)) {
+ linux_rcu_barrier(RCU_TYPE_REGULAR);
+ linux_flush_work(&rwork->work);
+ return (true);
+ }
+ return (linux_flush_work(&rwork->work));
+}
+
+/*
+ * This function queues the given work structure on the given
+ * workqueue after a given delay in ticks. It returns non-zero if the
+ * work was successfully [re-]queued. Else the work is already pending
+ * for completion.
+ */
+bool
+linux_queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
+ struct delayed_work *dwork, unsigned delay)
+{
+ static const uint8_t states[WORK_ST_MAX] __aligned(8) = {
+ [WORK_ST_IDLE] = WORK_ST_TIMER, /* start timeout */
+ [WORK_ST_TIMER] = WORK_ST_TIMER, /* NOP */
+ [WORK_ST_TASK] = WORK_ST_TASK, /* NOP */
+ [WORK_ST_EXEC] = WORK_ST_TIMER, /* start timeout */
+ [WORK_ST_CANCEL] = WORK_ST_TIMER, /* start timeout */
+ };
+
+ if (atomic_read(&wq->draining) != 0)
+ return (!work_pending(&dwork->work));
+
+ switch (linux_update_state(&dwork->work.state, states)) {
+ case WORK_ST_EXEC:
+ case WORK_ST_CANCEL:
+ if (delay == 0 && linux_work_exec_unblock(&dwork->work) != 0) {
+ dwork->timer.expires = jiffies;
+ return (true);
+ }
+ /* FALLTHROUGH */
+ case WORK_ST_IDLE:
+ dwork->work.work_queue = wq;
+ dwork->timer.expires = jiffies + delay;
+
+ if (delay == 0) {
+ linux_delayed_work_enqueue(dwork);
+ } else if (unlikely(cpu != WORK_CPU_UNBOUND)) {
+ mtx_lock(&dwork->timer.mtx);
+ callout_reset_on(&dwork->timer.callout, delay,
+ &linux_delayed_work_timer_fn, dwork, cpu);
+ mtx_unlock(&dwork->timer.mtx);
+ } else {
+ mtx_lock(&dwork->timer.mtx);
+ callout_reset(&dwork->timer.callout, delay,
+ &linux_delayed_work_timer_fn, dwork);
+ mtx_unlock(&dwork->timer.mtx);
+ }
+ return (true);
+ default:
+ return (false); /* already on a queue */
+ }
+}
+
+void
+linux_work_fn(void *context, int pending)
+{
+ static const uint8_t states[WORK_ST_MAX] __aligned(8) = {
+ [WORK_ST_IDLE] = WORK_ST_IDLE, /* NOP */
+ [WORK_ST_TIMER] = WORK_ST_EXEC, /* delayed work w/o timeout */
+ [WORK_ST_TASK] = WORK_ST_EXEC, /* call callback */
+ [WORK_ST_EXEC] = WORK_ST_IDLE, /* complete callback */
+ [WORK_ST_CANCEL] = WORK_ST_EXEC, /* failed to cancel */
+ };
+ struct work_struct *work;
+ struct workqueue_struct *wq;
+ struct work_exec exec;
+ struct task_struct *task;
+
+ task = current;
+
+ /* setup local variables */
+ work = context;
+ wq = work->work_queue;
+
+ /* store target pointer */
+ exec.target = work;
+
+ /* insert executor into list */
+ WQ_EXEC_LOCK(wq);
+ TAILQ_INSERT_TAIL(&wq->exec_head, &exec, entry);
+ while (1) {
+ switch (linux_update_state(&work->state, states)) {
+ case WORK_ST_TIMER:
+ case WORK_ST_TASK:
+ case WORK_ST_CANCEL:
+ WQ_EXEC_UNLOCK(wq);
+
+ /* set current work structure */
+ task->work = work;
+
+ /* call work function */
+ work->func(work);
+
+ /* set current work structure */
+ task->work = NULL;
+
+ WQ_EXEC_LOCK(wq);
+ /* check if unblocked */
+ if (exec.target != work) {
+ /* reapply block */
+ exec.target = work;
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ goto done;
+ }
+ }
+done:
+ /* remove executor from list */
+ TAILQ_REMOVE(&wq->exec_head, &exec, entry);
+ WQ_EXEC_UNLOCK(wq);
+}
+
+void
+linux_delayed_work_fn(void *context, int pending)
+{
+ struct delayed_work *dwork = context;
+
+ /*
+ * Make sure the timer belonging to the delayed work gets
+ * drained before invoking the work function. Else the timer
+ * mutex may still be in use which can lead to use-after-free
+ * situations, because the work function might free the work
+ * structure before returning.
+ */
+ callout_drain(&dwork->timer.callout);
+
+ linux_work_fn(&dwork->work, pending);
+}
+
+static void
+linux_delayed_work_timer_fn(void *arg)
+{
+ static const uint8_t states[WORK_ST_MAX] __aligned(8) = {
+ [WORK_ST_IDLE] = WORK_ST_IDLE, /* NOP */
+ [WORK_ST_TIMER] = WORK_ST_TASK, /* start queueing task */
+ [WORK_ST_TASK] = WORK_ST_TASK, /* NOP */
+ [WORK_ST_EXEC] = WORK_ST_EXEC, /* NOP */
+ [WORK_ST_CANCEL] = WORK_ST_TASK, /* failed to cancel */
+ };
+ struct delayed_work *dwork = arg;
+
+ switch (linux_update_state(&dwork->work.state, states)) {
+ case WORK_ST_TIMER:
+ case WORK_ST_CANCEL:
+ linux_delayed_work_enqueue(dwork);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ * This function cancels the given work structure in a synchronous
+ * fashion. It returns non-zero if the work was successfully
+ * cancelled. Else the work was already cancelled.
+ */
+bool
+linux_cancel_work_sync(struct work_struct *work)
+{
+ static const uint8_t states[WORK_ST_MAX] __aligned(8) = {
+ [WORK_ST_IDLE] = WORK_ST_IDLE, /* NOP */
+ [WORK_ST_TIMER] = WORK_ST_TIMER, /* can't happen */
+ [WORK_ST_TASK] = WORK_ST_IDLE, /* cancel and drain */
+ [WORK_ST_EXEC] = WORK_ST_IDLE, /* too late, drain */
+ [WORK_ST_CANCEL] = WORK_ST_IDLE, /* cancel and drain */
+ };
+ struct taskqueue *tq;
+ bool retval = false;
+
+ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
+ "linux_cancel_work_sync() might sleep");
+retry:
+ switch (linux_update_state(&work->state, states)) {
+ case WORK_ST_IDLE:
+ case WORK_ST_TIMER:
+ return (retval);
+ case WORK_ST_EXEC:
+ tq = work->work_queue->taskqueue;
+ if (taskqueue_cancel(tq, &work->work_task, NULL) != 0)
+ taskqueue_drain(tq, &work->work_task);
+ goto retry; /* work may have restarted itself */
+ default:
+ tq = work->work_queue->taskqueue;
+ if (taskqueue_cancel(tq, &work->work_task, NULL) != 0)
+ taskqueue_drain(tq, &work->work_task);
+ retval = true;
+ goto retry;
+ }
+}
+
+/*
+ * This function atomically stops the timer and callback. The timer
+ * callback will not be called after this function returns. This
+ * functions returns true when the timeout was cancelled. Else the
+ * timeout was not started or has already been called.
+ */
+static inline bool
+linux_cancel_timer(struct delayed_work *dwork, bool drain)
+{
+ bool cancelled;
+
+ mtx_lock(&dwork->timer.mtx);
+ cancelled = (callout_stop(&dwork->timer.callout) == 1);
+ mtx_unlock(&dwork->timer.mtx);
+
+ /* check if we should drain */
+ if (drain)
+ callout_drain(&dwork->timer.callout);
+ return (cancelled);
+}
+
+/*
+ * This function cancels the given delayed work structure in a
+ * non-blocking fashion. It returns non-zero if the work was
+ * successfully cancelled. Else the work may still be busy or already
+ * cancelled.
+ */
+bool
+linux_cancel_delayed_work(struct delayed_work *dwork)
+{
+ static const uint8_t states[WORK_ST_MAX] __aligned(8) = {
+ [WORK_ST_IDLE] = WORK_ST_IDLE, /* NOP */
+ [WORK_ST_TIMER] = WORK_ST_CANCEL, /* try to cancel */
+ [WORK_ST_TASK] = WORK_ST_CANCEL, /* try to cancel */
+ [WORK_ST_EXEC] = WORK_ST_EXEC, /* NOP */
+ [WORK_ST_CANCEL] = WORK_ST_CANCEL, /* NOP */
+ };
+ struct taskqueue *tq;
+ bool cancelled;
+
+ mtx_lock(&dwork->timer.mtx);
+ switch (linux_update_state(&dwork->work.state, states)) {
+ case WORK_ST_TIMER:
+ case WORK_ST_CANCEL:
+ cancelled = (callout_stop(&dwork->timer.callout) == 1);
+ if (cancelled) {
+ atomic_cmpxchg(&dwork->work.state,
+ WORK_ST_CANCEL, WORK_ST_IDLE);
+ mtx_unlock(&dwork->timer.mtx);
+ return (true);
+ }
+ /* FALLTHROUGH */
+ case WORK_ST_TASK:
+ tq = dwork->work.work_queue->taskqueue;
+ if (taskqueue_cancel(tq, &dwork->work.work_task, NULL) == 0) {
+ atomic_cmpxchg(&dwork->work.state,
+ WORK_ST_CANCEL, WORK_ST_IDLE);
+ mtx_unlock(&dwork->timer.mtx);
+ return (true);
+ }
+ /* FALLTHROUGH */
+ default:
+ mtx_unlock(&dwork->timer.mtx);
+ return (false);
+ }
+}
+
+/*
+ * This function cancels the given work structure in a synchronous
+ * fashion. It returns non-zero if the work was successfully
+ * cancelled. Else the work was already cancelled.
+ */
+bool
+linux_cancel_delayed_work_sync(struct delayed_work *dwork)
+{
+ static const uint8_t states[WORK_ST_MAX] __aligned(8) = {
+ [WORK_ST_IDLE] = WORK_ST_IDLE, /* NOP */
+ [WORK_ST_TIMER] = WORK_ST_IDLE, /* cancel and drain */
+ [WORK_ST_TASK] = WORK_ST_IDLE, /* cancel and drain */
+ [WORK_ST_EXEC] = WORK_ST_IDLE, /* too late, drain */
+ [WORK_ST_CANCEL] = WORK_ST_IDLE, /* cancel and drain */
+ };
+ struct taskqueue *tq;
+ bool retval = false;
+ int ret, state;
+ bool cancelled;
+
+ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
+ "linux_cancel_delayed_work_sync() might sleep");
+ mtx_lock(&dwork->timer.mtx);
+
+ state = linux_update_state(&dwork->work.state, states);
+ switch (state) {
+ case WORK_ST_IDLE:
+ mtx_unlock(&dwork->timer.mtx);
+ return (retval);
+ case WORK_ST_TIMER:
+ case WORK_ST_CANCEL:
+ cancelled = (callout_stop(&dwork->timer.callout) == 1);
+
+ tq = dwork->work.work_queue->taskqueue;
+ ret = taskqueue_cancel(tq, &dwork->work.work_task, NULL);
+ mtx_unlock(&dwork->timer.mtx);
+
+ callout_drain(&dwork->timer.callout);
+ taskqueue_drain(tq, &dwork->work.work_task);
+ return (cancelled || (ret != 0));
+ default:
+ tq = dwork->work.work_queue->taskqueue;
+ ret = taskqueue_cancel(tq, &dwork->work.work_task, NULL);
+ mtx_unlock(&dwork->timer.mtx);
+ if (ret != 0)
+ taskqueue_drain(tq, &dwork->work.work_task);
+ return (ret != 0);
+ }
+}
+
+/*
+ * This function waits until the given work structure is completed.
+ * It returns non-zero if the work was successfully
+ * waited for. Else the work was not waited for.
+ */
+bool
+linux_flush_work(struct work_struct *work)
+{
+ struct taskqueue *tq;
+ bool retval;
+
+ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
+ "linux_flush_work() might sleep");
+
+ switch (atomic_read(&work->state)) {
+ case WORK_ST_IDLE:
+ return (false);
+ default:
+ tq = work->work_queue->taskqueue;
+ retval = taskqueue_poll_is_busy(tq, &work->work_task);
+ taskqueue_drain(tq, &work->work_task);
+ return (retval);
+ }
+}
+
+/*
+ * This function waits until the given delayed work structure is
+ * completed. It returns non-zero if the work was successfully waited
+ * for. Else the work was not waited for.
+ */
+bool
+linux_flush_delayed_work(struct delayed_work *dwork)
+{
+ struct taskqueue *tq;
+ bool retval;
+
+ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
+ "linux_flush_delayed_work() might sleep");
+
+ switch (atomic_read(&dwork->work.state)) {
+ case WORK_ST_IDLE:
+ return (false);
+ case WORK_ST_TIMER:
+ if (linux_cancel_timer(dwork, 1))
+ linux_delayed_work_enqueue(dwork);
+ /* FALLTHROUGH */
+ default:
+ tq = dwork->work.work_queue->taskqueue;
+ retval = taskqueue_poll_is_busy(tq, &dwork->work.work_task);
+ taskqueue_drain(tq, &dwork->work.work_task);
+ return (retval);
+ }
+}
+
+/*
+ * This function returns true if the given work is pending, and not
+ * yet executing:
+ */
+bool
+linux_work_pending(struct work_struct *work)
+{
+ switch (atomic_read(&work->state)) {
+ case WORK_ST_TIMER:
+ case WORK_ST_TASK:
+ case WORK_ST_CANCEL:
+ return (true);
+ default:
+ return (false);
+ }
+}
+
+/*
+ * This function returns true if the given work is busy.
+ */
+bool
+linux_work_busy(struct work_struct *work)
+{
+ struct taskqueue *tq;
+
+ switch (atomic_read(&work->state)) {
+ case WORK_ST_IDLE:
+ return (false);
+ case WORK_ST_EXEC:
+ tq = work->work_queue->taskqueue;
+ return (taskqueue_poll_is_busy(tq, &work->work_task));
+ default:
+ return (true);
+ }
+}
+
+struct workqueue_struct *
+linux_create_workqueue_common(const char *name, int cpus)
+{
+ struct workqueue_struct *wq;
+
+ /*
+ * If zero CPUs are specified use the default number of CPUs:
+ */
+ if (cpus == 0)
+ cpus = linux_default_wq_cpus;
+
+ wq = kmalloc(sizeof(*wq), M_WAITOK | M_ZERO);
+ wq->taskqueue = taskqueue_create(name, M_WAITOK,
+ taskqueue_thread_enqueue, &wq->taskqueue);
+ atomic_set(&wq->draining, 0);
+ taskqueue_start_threads(&wq->taskqueue, cpus, PWAIT, "%s", name);
+ TAILQ_INIT(&wq->exec_head);
+ mtx_init(&wq->exec_mtx, "linux_wq_exec", NULL, MTX_DEF);
+
+ return (wq);
+}
+
+void
+linux_destroy_workqueue(struct workqueue_struct *wq)
+{
+ atomic_inc(&wq->draining);
+ drain_workqueue(wq);
+ taskqueue_free(wq->taskqueue);
+ mtx_destroy(&wq->exec_mtx);
+ kfree(wq);
+}
+
+void
+linux_init_delayed_work(struct delayed_work *dwork, work_func_t func)
+{
+ memset(dwork, 0, sizeof(*dwork));
+ dwork->work.func = func;
+ TASK_INIT(&dwork->work.work_task, 0, linux_delayed_work_fn, dwork);
+ mtx_init(&dwork->timer.mtx, spin_lock_name("lkpi-dwork"), NULL,
+ MTX_DEF | MTX_NOWITNESS);
+ callout_init_mtx(&dwork->timer.callout, &dwork->timer.mtx, 0);
+}
+
+struct work_struct *
+linux_current_work(void)
+{
+ return (current->work);
+}
+
+static void
+linux_work_init(void *arg)
+{
+ int max_wq_cpus = mp_ncpus + 1;
+
+ /* avoid deadlock when there are too few threads */
+ if (max_wq_cpus < 4)
+ max_wq_cpus = 4;
+
+ /* set default number of CPUs */
+ linux_default_wq_cpus = max_wq_cpus;
+
+ linux_system_short_wq = alloc_workqueue("linuxkpi_short_wq", 0, max_wq_cpus);
+ linux_system_long_wq = alloc_workqueue("linuxkpi_long_wq", 0, max_wq_cpus);
+
+ /* populate the workqueue pointers */
+ system_long_wq = linux_system_long_wq;
+ system_wq = linux_system_short_wq;
+ system_power_efficient_wq = linux_system_short_wq;
+ system_unbound_wq = linux_system_short_wq;
+ system_highpri_wq = linux_system_short_wq;
+}
+SYSINIT(linux_work_init, SI_SUB_TASKQ, SI_ORDER_THIRD, linux_work_init, NULL);
+
+static void
+linux_work_uninit(void *arg)
+{
+ destroy_workqueue(linux_system_short_wq);
+ destroy_workqueue(linux_system_long_wq);
+
+ /* clear workqueue pointers */
+ system_long_wq = NULL;
+ system_wq = NULL;
+ system_power_efficient_wq = NULL;
+ system_unbound_wq = NULL;
+ system_highpri_wq = NULL;
+}
+SYSUNINIT(linux_work_uninit, SI_SUB_TASKQ, SI_ORDER_THIRD, linux_work_uninit, NULL);
+
+void
+linux_irq_work_fn(void *context, int pending)
+{
+ struct irq_work *irqw = context;
+
+ irqw->func(irqw);
+}
+
+static void
+linux_irq_work_init_fn(void *context, int pending)
+{
+ /*
+ * LinuxKPI performs lazy allocation of memory structures required by
+ * current on the first access to it. As some irq_work clients read
+ * it with spinlock taken, we have to preallocate td_lkpi_task before
+ * first call to irq_work_queue(). As irq_work uses a single thread,
+ * it is enough to read current once at SYSINIT stage.
+ */
+ if (current == NULL)
+ panic("irq_work taskqueue is not initialized");
+}
+static struct task linux_irq_work_init_task =
+ TASK_INITIALIZER(0, linux_irq_work_init_fn, &linux_irq_work_init_task);
+
+static void
+linux_irq_work_init(void *arg)
+{
+ linux_irq_work_tq = taskqueue_create_fast("linuxkpi_irq_wq",
+ M_WAITOK, taskqueue_thread_enqueue, &linux_irq_work_tq);
+ taskqueue_start_threads(&linux_irq_work_tq, 1, PWAIT,
+ "linuxkpi_irq_wq");
+ taskqueue_enqueue(linux_irq_work_tq, &linux_irq_work_init_task);
+}
+SYSINIT(linux_irq_work_init, SI_SUB_TASKQ, SI_ORDER_SECOND,
+ linux_irq_work_init, NULL);
+
+static void
+linux_irq_work_uninit(void *arg)
+{
+ taskqueue_drain_all(linux_irq_work_tq);
+ taskqueue_free(linux_irq_work_tq);
+}
+SYSUNINIT(linux_irq_work_uninit, SI_SUB_TASKQ, SI_ORDER_SECOND,
+ linux_irq_work_uninit, NULL);
diff --git a/sys/compat/linuxkpi/common/src/linux_xarray.c b/sys/compat/linuxkpi/common/src/linux_xarray.c
new file mode 100644
index 000000000000..52be490c100e
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_xarray.c
@@ -0,0 +1,391 @@
+/*-
+ * Copyright (c) 2020 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <linux/xarray.h>
+
+#include <vm/vm_pageout.h>
+
+/*
+ * This function removes the element at the given index and returns
+ * the pointer to the removed element, if any.
+ */
+void *
+__xa_erase(struct xarray *xa, uint32_t index)
+{
+ XA_ASSERT_LOCKED(xa);
+
+ return (radix_tree_delete(&xa->root, index));
+}
+
+void *
+xa_erase(struct xarray *xa, uint32_t index)
+{
+ void *retval;
+
+ xa_lock(xa);
+ retval = __xa_erase(xa, index);
+ xa_unlock(xa);
+
+ return (retval);
+}
+
+/*
+ * This function returns the element pointer at the given index. A
+ * value of NULL is returned if the element does not exist.
+ */
+void *
+xa_load(struct xarray *xa, uint32_t index)
+{
+ void *retval;
+
+ xa_lock(xa);
+ retval = radix_tree_lookup(&xa->root, index);
+ xa_unlock(xa);
+
+ return (retval);
+}
+
+/*
+ * This is an internal function used to sleep until more memory
+ * becomes available.
+ */
+static void
+xa_vm_wait_locked(struct xarray *xa)
+{
+ xa_unlock(xa);
+ vm_wait(NULL);
+ xa_lock(xa);
+}
+
+/*
+ * This function iterates the xarray until it finds a free slot where
+ * it can insert the element pointer to by "ptr". It starts at the
+ * index pointed to by "pindex" and updates this value at return. The
+ * "mask" argument defines the maximum index allowed, inclusivly, and
+ * must be a power of two minus one value. The "gfp" argument
+ * basically tells if we can wait for more memory to become available
+ * or not. This function returns zero upon success or a negative error
+ * code on failure. A typical error code is -ENOMEM which means either
+ * the xarray is full, or there was not enough internal memory
+ * available to complete the radix tree insertion.
+ */
+int
+__xa_alloc(struct xarray *xa, uint32_t *pindex, void *ptr, uint32_t mask, gfp_t gfp)
+{
+ int retval;
+
+ XA_ASSERT_LOCKED(xa);
+
+ /* mask cannot be zero */
+ MPASS(mask != 0);
+
+ /* mask can be any power of two value minus one */
+ MPASS((mask & (mask + 1)) == 0);
+
+ *pindex = 0;
+retry:
+ retval = radix_tree_insert(&xa->root, *pindex, ptr);
+
+ switch (retval) {
+ case -EEXIST:
+ if (likely(*pindex != mask)) {
+ (*pindex)++;
+ goto retry;
+ }
+ retval = -ENOMEM;
+ break;
+ case -ENOMEM:
+ if (likely(gfp & M_WAITOK)) {
+ xa_vm_wait_locked(xa);
+ goto retry;
+ }
+ break;
+ default:
+ break;
+ }
+ return (retval);
+}
+
+int
+xa_alloc(struct xarray *xa, uint32_t *pindex, void *ptr, uint32_t mask, gfp_t gfp)
+{
+ int retval;
+
+ xa_lock(xa);
+ retval = __xa_alloc(xa, pindex, ptr, mask, gfp);
+ xa_unlock(xa);
+
+ return (retval);
+}
+
+/*
+ * This function works the same like the "xa_alloc" function, except
+ * it wraps the next index value to zero when there are no entries
+ * left at the end of the xarray searching for a free slot from the
+ * beginning of the array. If the xarray is full -ENOMEM is returned.
+ */
+int
+__xa_alloc_cyclic(struct xarray *xa, uint32_t *pindex, void *ptr, uint32_t mask,
+ uint32_t *pnext_index, gfp_t gfp)
+{
+ int retval;
+ int timeout = 1;
+
+ XA_ASSERT_LOCKED(xa);
+
+ /* mask cannot be zero */
+ MPASS(mask != 0);
+
+ /* mask can be any power of two value minus one */
+ MPASS((mask & (mask + 1)) == 0);
+
+ *pnext_index = 0;
+retry:
+ retval = radix_tree_insert(&xa->root, *pnext_index, ptr);
+
+ switch (retval) {
+ case -EEXIST:
+ if (unlikely(*pnext_index == mask) && !timeout--) {
+ retval = -ENOMEM;
+ break;
+ }
+ (*pnext_index)++;
+ (*pnext_index) &= mask;
+ goto retry;
+ case -ENOMEM:
+ if (likely(gfp & M_WAITOK)) {
+ xa_vm_wait_locked(xa);
+ goto retry;
+ }
+ break;
+ default:
+ break;
+ }
+ *pindex = *pnext_index;
+
+ return (retval);
+}
+
+int
+xa_alloc_cyclic(struct xarray *xa, uint32_t *pindex, void *ptr, uint32_t mask,
+ uint32_t *pnext_index, gfp_t gfp)
+{
+ int retval;
+
+ xa_lock(xa);
+ retval = __xa_alloc_cyclic(xa, pindex, ptr, mask, pnext_index, gfp);
+ xa_unlock(xa);
+
+ return (retval);
+}
+
+/*
+ * This function tries to insert an element at the given index. The
+ * "gfp" argument basically decides of this function can sleep or not
+ * trying to allocate internal memory for its radix tree. The
+ * function returns an error code upon failure. Typical error codes
+ * are element exists (-EEXIST) or out of memory (-ENOMEM).
+ */
+int
+__xa_insert(struct xarray *xa, uint32_t index, void *ptr, gfp_t gfp)
+{
+ int retval;
+
+ XA_ASSERT_LOCKED(xa);
+retry:
+ retval = radix_tree_insert(&xa->root, index, ptr);
+
+ switch (retval) {
+ case -ENOMEM:
+ if (likely(gfp & M_WAITOK)) {
+ xa_vm_wait_locked(xa);
+ goto retry;
+ }
+ break;
+ default:
+ break;
+ }
+ return (retval);
+}
+
+int
+xa_insert(struct xarray *xa, uint32_t index, void *ptr, gfp_t gfp)
+{
+ int retval;
+
+ xa_lock(xa);
+ retval = __xa_insert(xa, index, ptr, gfp);
+ xa_unlock(xa);
+
+ return (retval);
+}
+
+/*
+ * This function updates the element at the given index and returns a
+ * pointer to the old element. The "gfp" argument basically decides of
+ * this function can sleep or not trying to allocate internal memory
+ * for its radix tree. The function returns an XA_ERROR() pointer code
+ * upon failure. Code using this function must always check if the
+ * return value is an XA_ERROR() code before using the returned value.
+ */
+void *
+__xa_store(struct xarray *xa, uint32_t index, void *ptr, gfp_t gfp)
+{
+ int retval;
+
+ XA_ASSERT_LOCKED(xa);
+retry:
+ retval = radix_tree_store(&xa->root, index, &ptr);
+
+ switch (retval) {
+ case 0:
+ break;
+ case -ENOMEM:
+ if (likely(gfp & M_WAITOK)) {
+ xa_vm_wait_locked(xa);
+ goto retry;
+ }
+ ptr = XA_ERROR(retval);
+ break;
+ default:
+ ptr = XA_ERROR(retval);
+ break;
+ }
+ return (ptr);
+}
+
+void *
+xa_store(struct xarray *xa, uint32_t index, void *ptr, gfp_t gfp)
+{
+ void *retval;
+
+ xa_lock(xa);
+ retval = __xa_store(xa, index, ptr, gfp);
+ xa_unlock(xa);
+
+ return (retval);
+}
+
+/*
+ * This function initialize an xarray structure.
+ */
+void
+xa_init_flags(struct xarray *xa, uint32_t flags)
+{
+ memset(xa, 0, sizeof(*xa));
+
+ mtx_init(&xa->mtx, "lkpi-xarray", NULL, MTX_DEF | MTX_RECURSE);
+ xa->root.gfp_mask = GFP_NOWAIT;
+}
+
+/*
+ * This function destroys an xarray structure and all its internal
+ * memory and locks.
+ */
+void
+xa_destroy(struct xarray *xa)
+{
+ struct radix_tree_iter iter;
+ void **ppslot;
+
+ radix_tree_for_each_slot(ppslot, &xa->root, &iter, 0)
+ radix_tree_iter_delete(&xa->root, &iter, ppslot);
+ mtx_destroy(&xa->mtx);
+}
+
+/*
+ * This function checks if an xarray is empty or not.
+ * It returns true if empty, else false.
+ */
+bool
+__xa_empty(struct xarray *xa)
+{
+ struct radix_tree_iter iter = {};
+ void **temp;
+
+ XA_ASSERT_LOCKED(xa);
+
+ return (!radix_tree_iter_find(&xa->root, &iter, &temp));
+}
+
+bool
+xa_empty(struct xarray *xa)
+{
+ bool retval;
+
+ xa_lock(xa);
+ retval = __xa_empty(xa);
+ xa_unlock(xa);
+
+ return (retval);
+}
+
+/*
+ * This function returns the next valid xarray entry based on the
+ * index given by "pindex". The valued pointed to by "pindex" is
+ * updated before return.
+ */
+void *
+__xa_next(struct xarray *xa, unsigned long *pindex, bool not_first)
+{
+ struct radix_tree_iter iter = { .index = *pindex };
+ void **ppslot;
+ void *retval;
+ bool found;
+
+ XA_ASSERT_LOCKED(xa);
+
+ if (not_first) {
+ /* advance to next index, if any */
+ iter.index++;
+ if (iter.index == 0)
+ return (NULL);
+ }
+
+ found = radix_tree_iter_find(&xa->root, &iter, &ppslot);
+ if (likely(found)) {
+ retval = *ppslot;
+ *pindex = iter.index;
+ } else {
+ retval = NULL;
+ }
+ return (retval);
+}
+
+void *
+xa_next(struct xarray *xa, unsigned long *pindex, bool not_first)
+{
+ void *retval;
+
+ xa_lock(xa);
+ retval = __xa_next(xa, pindex, not_first);
+ xa_unlock(xa);
+
+ return (retval);
+}
diff --git a/sys/compat/x86bios/x86bios.c b/sys/compat/x86bios/x86bios.c
new file mode 100644
index 000000000000..f6350b8f6388
--- /dev/null
+++ b/sys/compat/x86bios/x86bios.c
@@ -0,0 +1,864 @@
+/*-
+ * Copyright (c) 2009 Alex Keda <admin@lissyara.su>
+ * Copyright (c) 2009-2010 Jung-uk Kim <jkim@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_x86bios.h"
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/sysctl.h>
+
+#include <contrib/x86emu/x86emu.h>
+#include <contrib/x86emu/x86emu_regs.h>
+#include <compat/x86bios/x86bios.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#ifdef __amd64__
+#define X86BIOS_NATIVE_ARCH
+#endif
+#ifdef __i386__
+#define X86BIOS_NATIVE_VM86
+#endif
+
+#define X86BIOS_MEM_SIZE 0x00100000 /* 1M */
+
+#define X86BIOS_TRACE(h, n, r) do { \
+ printf(__STRING(h) \
+ " (ax=0x%04x bx=0x%04x cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n",\
+ (n), (r)->R_AX, (r)->R_BX, (r)->R_CX, (r)->R_DX, \
+ (r)->R_ES, (r)->R_DI); \
+} while (0)
+
+static struct mtx x86bios_lock;
+
+static SYSCTL_NODE(_debug, OID_AUTO, x86bios, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
+ "x86bios debugging");
+static int x86bios_trace_call;
+SYSCTL_INT(_debug_x86bios, OID_AUTO, call, CTLFLAG_RWTUN, &x86bios_trace_call, 0,
+ "Trace far function calls");
+static int x86bios_trace_int;
+SYSCTL_INT(_debug_x86bios, OID_AUTO, int, CTLFLAG_RWTUN, &x86bios_trace_int, 0,
+ "Trace software interrupt handlers");
+
+#ifdef X86BIOS_NATIVE_VM86
+
+#include <machine/vm86.h>
+#include <machine/vmparam.h>
+#include <machine/pc/bios.h>
+
+struct vm86context x86bios_vmc;
+
+static void
+x86bios_emu2vmf(struct x86emu_regs *regs, struct vm86frame *vmf)
+{
+
+ vmf->vmf_ds = regs->R_DS;
+ vmf->vmf_es = regs->R_ES;
+ vmf->vmf_ax = regs->R_AX;
+ vmf->vmf_bx = regs->R_BX;
+ vmf->vmf_cx = regs->R_CX;
+ vmf->vmf_dx = regs->R_DX;
+ vmf->vmf_bp = regs->R_BP;
+ vmf->vmf_si = regs->R_SI;
+ vmf->vmf_di = regs->R_DI;
+}
+
+static void
+x86bios_vmf2emu(struct vm86frame *vmf, struct x86emu_regs *regs)
+{
+
+ regs->R_DS = vmf->vmf_ds;
+ regs->R_ES = vmf->vmf_es;
+ regs->R_FLG = vmf->vmf_flags;
+ regs->R_AX = vmf->vmf_ax;
+ regs->R_BX = vmf->vmf_bx;
+ regs->R_CX = vmf->vmf_cx;
+ regs->R_DX = vmf->vmf_dx;
+ regs->R_BP = vmf->vmf_bp;
+ regs->R_SI = vmf->vmf_si;
+ regs->R_DI = vmf->vmf_di;
+}
+
+void *
+x86bios_alloc(uint32_t *offset, size_t size, int flags)
+{
+ void *vaddr;
+ u_int i;
+
+ if (offset == NULL || size == 0)
+ return (NULL);
+ vaddr = contigmalloc(size, M_DEVBUF, flags, 0, X86BIOS_MEM_SIZE,
+ PAGE_SIZE, 0);
+ if (vaddr != NULL) {
+ *offset = vtophys(vaddr);
+ mtx_lock(&x86bios_lock);
+ for (i = 0; i < atop(round_page(size)); i++)
+ vm86_addpage(&x86bios_vmc, atop(*offset) + i,
+ (vm_offset_t)vaddr + ptoa(i));
+ mtx_unlock(&x86bios_lock);
+ }
+
+ return (vaddr);
+}
+
+void
+x86bios_free(void *addr, size_t size)
+{
+ vm_paddr_t paddr;
+ int i, nfree;
+
+ if (addr == NULL || size == 0)
+ return;
+ paddr = vtophys(addr);
+ if (paddr >= X86BIOS_MEM_SIZE || (paddr & PAGE_MASK) != 0)
+ return;
+ mtx_lock(&x86bios_lock);
+ for (i = 0; i < x86bios_vmc.npages; i++)
+ if (x86bios_vmc.pmap[i].kva == (vm_offset_t)addr)
+ break;
+ if (i >= x86bios_vmc.npages) {
+ mtx_unlock(&x86bios_lock);
+ return;
+ }
+ nfree = atop(round_page(size));
+ bzero(x86bios_vmc.pmap + i, sizeof(*x86bios_vmc.pmap) * nfree);
+ if (i + nfree == x86bios_vmc.npages) {
+ x86bios_vmc.npages -= nfree;
+ while (--i >= 0 && x86bios_vmc.pmap[i].kva == 0)
+ x86bios_vmc.npages--;
+ }
+ mtx_unlock(&x86bios_lock);
+ contigfree(addr, size, M_DEVBUF);
+}
+
+void
+x86bios_init_regs(struct x86regs *regs)
+{
+
+ bzero(regs, sizeof(*regs));
+}
+
+void
+x86bios_call(struct x86regs *regs, uint16_t seg, uint16_t off)
+{
+ struct vm86frame vmf;
+
+ if (x86bios_trace_call)
+ X86BIOS_TRACE(Calling 0x%06x, (seg << 4) + off, regs);
+
+ bzero(&vmf, sizeof(vmf));
+ x86bios_emu2vmf((struct x86emu_regs *)regs, &vmf);
+ vmf.vmf_cs = seg;
+ vmf.vmf_ip = off;
+ mtx_lock(&x86bios_lock);
+ vm86_datacall(-1, &vmf, &x86bios_vmc);
+ mtx_unlock(&x86bios_lock);
+ x86bios_vmf2emu(&vmf, (struct x86emu_regs *)regs);
+
+ if (x86bios_trace_call)
+ X86BIOS_TRACE(Exiting 0x%06x, (seg << 4) + off, regs);
+}
+
+uint32_t
+x86bios_get_intr(int intno)
+{
+
+ return (readl(BIOS_PADDRTOVADDR(intno * 4)));
+}
+
+void
+x86bios_set_intr(int intno, uint32_t saddr)
+{
+
+ writel(BIOS_PADDRTOVADDR(intno * 4), saddr);
+}
+
+void
+x86bios_intr(struct x86regs *regs, int intno)
+{
+ struct vm86frame vmf;
+
+ if (x86bios_trace_int)
+ X86BIOS_TRACE(Calling INT 0x%02x, intno, regs);
+
+ bzero(&vmf, sizeof(vmf));
+ x86bios_emu2vmf((struct x86emu_regs *)regs, &vmf);
+ mtx_lock(&x86bios_lock);
+ vm86_datacall(intno, &vmf, &x86bios_vmc);
+ mtx_unlock(&x86bios_lock);
+ x86bios_vmf2emu(&vmf, (struct x86emu_regs *)regs);
+
+ if (x86bios_trace_int)
+ X86BIOS_TRACE(Exiting INT 0x%02x, intno, regs);
+}
+
+void *
+x86bios_offset(uint32_t offset)
+{
+ vm_offset_t addr;
+
+ addr = vm86_getaddr(&x86bios_vmc, X86BIOS_PHYSTOSEG(offset),
+ X86BIOS_PHYSTOOFF(offset));
+ if (addr == 0)
+ addr = BIOS_PADDRTOVADDR(offset);
+
+ return ((void *)addr);
+}
+
+static int
+x86bios_init(void)
+{
+
+ mtx_init(&x86bios_lock, "x86bios lock", NULL, MTX_DEF);
+ bzero(&x86bios_vmc, sizeof(x86bios_vmc));
+
+ return (0);
+}
+
+static int
+x86bios_uninit(void)
+{
+
+ mtx_destroy(&x86bios_lock);
+
+ return (0);
+}
+
+#else
+
+#include <machine/iodev.h>
+
+#define X86BIOS_PAGE_SIZE 0x00001000 /* 4K */
+
+#define X86BIOS_IVT_SIZE 0x00000500 /* 1K + 256 (BDA) */
+
+#define X86BIOS_IVT_BASE 0x00000000
+#define X86BIOS_RAM_BASE 0x00001000
+#define X86BIOS_ROM_BASE 0x000a0000
+
+#define X86BIOS_ROM_SIZE (X86BIOS_MEM_SIZE - x86bios_rom_phys)
+#define X86BIOS_SEG_SIZE X86BIOS_PAGE_SIZE
+
+#define X86BIOS_PAGES (X86BIOS_MEM_SIZE / X86BIOS_PAGE_SIZE)
+
+#define X86BIOS_R_SS _pad2
+#define X86BIOS_R_SP _pad3.I16_reg.x_reg
+
+static struct x86emu x86bios_emu;
+
+static void *x86bios_ivt;
+static void *x86bios_rom;
+static void *x86bios_seg;
+
+static vm_offset_t *x86bios_map;
+
+static vm_paddr_t x86bios_rom_phys;
+static vm_paddr_t x86bios_seg_phys;
+
+static int x86bios_fault;
+static uint32_t x86bios_fault_addr;
+static uint16_t x86bios_fault_cs;
+static uint16_t x86bios_fault_ip;
+
+static void
+x86bios_set_fault(struct x86emu *emu, uint32_t addr)
+{
+
+ x86bios_fault = 1;
+ x86bios_fault_addr = addr;
+ x86bios_fault_cs = emu->x86.R_CS;
+ x86bios_fault_ip = emu->x86.R_IP;
+ x86emu_halt_sys(emu);
+}
+
+static void *
+x86bios_get_pages(uint32_t offset, size_t size)
+{
+ vm_offset_t addr;
+
+ if (offset + size > X86BIOS_MEM_SIZE + X86BIOS_IVT_SIZE)
+ return (NULL);
+
+ if (offset >= X86BIOS_MEM_SIZE)
+ offset -= X86BIOS_MEM_SIZE;
+ addr = x86bios_map[offset / X86BIOS_PAGE_SIZE];
+ if (addr != 0)
+ addr += offset % X86BIOS_PAGE_SIZE;
+
+ return ((void *)addr);
+}
+
+static void
+x86bios_set_pages(vm_offset_t va, vm_paddr_t pa, size_t size)
+{
+ int i, j;
+
+ for (i = pa / X86BIOS_PAGE_SIZE, j = 0;
+ j < howmany(size, X86BIOS_PAGE_SIZE); i++, j++)
+ x86bios_map[i] = va + j * X86BIOS_PAGE_SIZE;
+}
+
+static uint8_t
+x86bios_emu_rdb(struct x86emu *emu, uint32_t addr)
+{
+ uint8_t *va;
+
+ va = x86bios_get_pages(addr, sizeof(*va));
+ if (va == NULL)
+ x86bios_set_fault(emu, addr);
+
+ return (*va);
+}
+
+static uint16_t
+x86bios_emu_rdw(struct x86emu *emu, uint32_t addr)
+{
+ uint16_t *va;
+
+ va = x86bios_get_pages(addr, sizeof(*va));
+ if (va == NULL)
+ x86bios_set_fault(emu, addr);
+
+#ifndef __NO_STRICT_ALIGNMENT
+ if ((addr & 1) != 0)
+ return (le16dec(va));
+ else
+#endif
+ return (le16toh(*va));
+}
+
+static uint32_t
+x86bios_emu_rdl(struct x86emu *emu, uint32_t addr)
+{
+ uint32_t *va;
+
+ va = x86bios_get_pages(addr, sizeof(*va));
+ if (va == NULL)
+ x86bios_set_fault(emu, addr);
+
+#ifndef __NO_STRICT_ALIGNMENT
+ if ((addr & 3) != 0)
+ return (le32dec(va));
+ else
+#endif
+ return (le32toh(*va));
+}
+
+static void
+x86bios_emu_wrb(struct x86emu *emu, uint32_t addr, uint8_t val)
+{
+ uint8_t *va;
+
+ va = x86bios_get_pages(addr, sizeof(*va));
+ if (va == NULL)
+ x86bios_set_fault(emu, addr);
+
+ *va = val;
+}
+
+static void
+x86bios_emu_wrw(struct x86emu *emu, uint32_t addr, uint16_t val)
+{
+ uint16_t *va;
+
+ va = x86bios_get_pages(addr, sizeof(*va));
+ if (va == NULL)
+ x86bios_set_fault(emu, addr);
+
+#ifndef __NO_STRICT_ALIGNMENT
+ if ((addr & 1) != 0)
+ le16enc(va, val);
+ else
+#endif
+ *va = htole16(val);
+}
+
+static void
+x86bios_emu_wrl(struct x86emu *emu, uint32_t addr, uint32_t val)
+{
+ uint32_t *va;
+
+ va = x86bios_get_pages(addr, sizeof(*va));
+ if (va == NULL)
+ x86bios_set_fault(emu, addr);
+
+#ifndef __NO_STRICT_ALIGNMENT
+ if ((addr & 3) != 0)
+ le32enc(va, val);
+ else
+#endif
+ *va = htole32(val);
+}
+
+static uint8_t
+x86bios_emu_inb(struct x86emu *emu, uint16_t port)
+{
+
+#ifndef X86BIOS_NATIVE_ARCH
+ if (port == 0xb2) /* APM scratch register */
+ return (0);
+ if (port >= 0x80 && port < 0x88) /* POST status register */
+ return (0);
+#endif
+
+ return (iodev_read_1(port));
+}
+
+static uint16_t
+x86bios_emu_inw(struct x86emu *emu, uint16_t port)
+{
+ uint16_t val;
+
+#ifndef X86BIOS_NATIVE_ARCH
+ if (port >= 0x80 && port < 0x88) /* POST status register */
+ return (0);
+
+ if ((port & 1) != 0) {
+ val = iodev_read_1(port);
+ val |= iodev_read_1(port + 1) << 8;
+ } else
+#endif
+ val = iodev_read_2(port);
+
+ return (val);
+}
+
+static uint32_t
+x86bios_emu_inl(struct x86emu *emu, uint16_t port)
+{
+ uint32_t val;
+
+#ifndef X86BIOS_NATIVE_ARCH
+ if (port >= 0x80 && port < 0x88) /* POST status register */
+ return (0);
+
+ if ((port & 1) != 0) {
+ val = iodev_read_1(port);
+ val |= iodev_read_2(port + 1) << 8;
+ val |= iodev_read_1(port + 3) << 24;
+ } else if ((port & 2) != 0) {
+ val = iodev_read_2(port);
+ val |= iodev_read_2(port + 2) << 16;
+ } else
+#endif
+ val = iodev_read_4(port);
+
+ return (val);
+}
+
+static void
+x86bios_emu_outb(struct x86emu *emu, uint16_t port, uint8_t val)
+{
+
+#ifndef X86BIOS_NATIVE_ARCH
+ if (port == 0xb2) /* APM scratch register */
+ return;
+ if (port >= 0x80 && port < 0x88) /* POST status register */
+ return;
+#endif
+
+ iodev_write_1(port, val);
+}
+
+static void
+x86bios_emu_outw(struct x86emu *emu, uint16_t port, uint16_t val)
+{
+
+#ifndef X86BIOS_NATIVE_ARCH
+ if (port >= 0x80 && port < 0x88) /* POST status register */
+ return;
+
+ if ((port & 1) != 0) {
+ iodev_write_1(port, val);
+ iodev_write_1(port + 1, val >> 8);
+ } else
+#endif
+ iodev_write_2(port, val);
+}
+
+static void
+x86bios_emu_outl(struct x86emu *emu, uint16_t port, uint32_t val)
+{
+
+#ifndef X86BIOS_NATIVE_ARCH
+ if (port >= 0x80 && port < 0x88) /* POST status register */
+ return;
+
+ if ((port & 1) != 0) {
+ iodev_write_1(port, val);
+ iodev_write_2(port + 1, val >> 8);
+ iodev_write_1(port + 3, val >> 24);
+ } else if ((port & 2) != 0) {
+ iodev_write_2(port, val);
+ iodev_write_2(port + 2, val >> 16);
+ } else
+#endif
+ iodev_write_4(port, val);
+}
+
+void *
+x86bios_alloc(uint32_t *offset, size_t size, int flags)
+{
+ void *vaddr;
+
+ if (offset == NULL || size == 0)
+ return (NULL);
+ vaddr = contigmalloc(size, M_DEVBUF, flags, X86BIOS_RAM_BASE,
+ x86bios_rom_phys, X86BIOS_PAGE_SIZE, 0);
+ if (vaddr != NULL) {
+ *offset = vtophys(vaddr);
+ mtx_lock(&x86bios_lock);
+ x86bios_set_pages((vm_offset_t)vaddr, *offset, size);
+ mtx_unlock(&x86bios_lock);
+ }
+
+ return (vaddr);
+}
+
+void
+x86bios_free(void *addr, size_t size)
+{
+ vm_paddr_t paddr;
+
+ if (addr == NULL || size == 0)
+ return;
+ paddr = vtophys(addr);
+ if (paddr < X86BIOS_RAM_BASE || paddr >= x86bios_rom_phys ||
+ paddr % X86BIOS_PAGE_SIZE != 0)
+ return;
+ mtx_lock(&x86bios_lock);
+ bzero(x86bios_map + paddr / X86BIOS_PAGE_SIZE,
+ sizeof(*x86bios_map) * howmany(size, X86BIOS_PAGE_SIZE));
+ mtx_unlock(&x86bios_lock);
+ contigfree(addr, size, M_DEVBUF);
+}
+
+void
+x86bios_init_regs(struct x86regs *regs)
+{
+
+ bzero(regs, sizeof(*regs));
+ regs->X86BIOS_R_SS = X86BIOS_PHYSTOSEG(x86bios_seg_phys);
+ regs->X86BIOS_R_SP = X86BIOS_PAGE_SIZE - 2;
+}
+
+void
+x86bios_call(struct x86regs *regs, uint16_t seg, uint16_t off)
+{
+
+ if (x86bios_trace_call)
+ X86BIOS_TRACE(Calling 0x%06x, (seg << 4) + off, regs);
+
+ mtx_lock(&x86bios_lock);
+ memcpy((struct x86regs *)&x86bios_emu.x86, regs, sizeof(*regs));
+ x86bios_fault = 0;
+ spinlock_enter();
+ x86emu_exec_call(&x86bios_emu, seg, off);
+ spinlock_exit();
+ memcpy(regs, &x86bios_emu.x86, sizeof(*regs));
+ mtx_unlock(&x86bios_lock);
+
+ if (x86bios_trace_call) {
+ X86BIOS_TRACE(Exiting 0x%06x, (seg << 4) + off, regs);
+ if (x86bios_fault)
+ printf("Page fault at 0x%06x from 0x%04x:0x%04x.\n",
+ x86bios_fault_addr, x86bios_fault_cs,
+ x86bios_fault_ip);
+ }
+}
+
+uint32_t
+x86bios_get_intr(int intno)
+{
+
+ return (le32toh(*((uint32_t *)x86bios_ivt + intno)));
+}
+
+void
+x86bios_set_intr(int intno, uint32_t saddr)
+{
+
+ *((uint32_t *)x86bios_ivt + intno) = htole32(saddr);
+}
+
+void
+x86bios_intr(struct x86regs *regs, int intno)
+{
+
+ if (intno < 0 || intno > 255)
+ return;
+
+ if (x86bios_trace_int)
+ X86BIOS_TRACE(Calling INT 0x%02x, intno, regs);
+
+ mtx_lock(&x86bios_lock);
+ memcpy((struct x86regs *)&x86bios_emu.x86, regs, sizeof(*regs));
+ x86bios_fault = 0;
+ spinlock_enter();
+ x86emu_exec_intr(&x86bios_emu, intno);
+ spinlock_exit();
+ memcpy(regs, &x86bios_emu.x86, sizeof(*regs));
+ mtx_unlock(&x86bios_lock);
+
+ if (x86bios_trace_int) {
+ X86BIOS_TRACE(Exiting INT 0x%02x, intno, regs);
+ if (x86bios_fault)
+ printf("Page fault at 0x%06x from 0x%04x:0x%04x.\n",
+ x86bios_fault_addr, x86bios_fault_cs,
+ x86bios_fault_ip);
+ }
+}
+
+void *
+x86bios_offset(uint32_t offset)
+{
+
+ return (x86bios_get_pages(offset, 1));
+}
+
+static __inline void
+x86bios_unmap_mem(void)
+{
+
+ if (x86bios_map != NULL) {
+ free(x86bios_map, M_DEVBUF);
+ x86bios_map = NULL;
+ }
+ if (x86bios_ivt != NULL) {
+#ifdef X86BIOS_NATIVE_ARCH
+ pmap_unmapbios((vm_offset_t)x86bios_ivt, X86BIOS_IVT_SIZE);
+#else
+ free(x86bios_ivt, M_DEVBUF);
+ x86bios_ivt = NULL;
+#endif
+ }
+ if (x86bios_rom != NULL)
+ pmap_unmapdev((vm_offset_t)x86bios_rom, X86BIOS_ROM_SIZE);
+ if (x86bios_seg != NULL) {
+ contigfree(x86bios_seg, X86BIOS_SEG_SIZE, M_DEVBUF);
+ x86bios_seg = NULL;
+ }
+}
+
+static __inline int
+x86bios_map_mem(void)
+{
+
+ x86bios_map = malloc(sizeof(*x86bios_map) * X86BIOS_PAGES, M_DEVBUF,
+ M_NOWAIT | M_ZERO);
+ if (x86bios_map == NULL)
+ goto fail;
+
+#ifdef X86BIOS_NATIVE_ARCH
+ x86bios_ivt = pmap_mapbios(X86BIOS_IVT_BASE, X86BIOS_IVT_SIZE);
+
+ /* Probe EBDA via BDA. */
+ x86bios_rom_phys = *(uint16_t *)((caddr_t)x86bios_ivt + 0x40e);
+ x86bios_rom_phys = x86bios_rom_phys << 4;
+ if (x86bios_rom_phys != 0 && x86bios_rom_phys < X86BIOS_ROM_BASE &&
+ X86BIOS_ROM_BASE - x86bios_rom_phys <= 128 * 1024)
+ x86bios_rom_phys =
+ rounddown(x86bios_rom_phys, X86BIOS_PAGE_SIZE);
+ else
+#else
+ x86bios_ivt = malloc(X86BIOS_IVT_SIZE, M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (x86bios_ivt == NULL)
+ goto fail;
+#endif
+
+ x86bios_rom_phys = X86BIOS_ROM_BASE;
+ x86bios_rom = pmap_mapdev(x86bios_rom_phys, X86BIOS_ROM_SIZE);
+ if (x86bios_rom == NULL)
+ goto fail;
+#ifdef X86BIOS_NATIVE_ARCH
+ /* Change attribute for EBDA. */
+ if (x86bios_rom_phys < X86BIOS_ROM_BASE &&
+ pmap_change_attr((vm_offset_t)x86bios_rom,
+ X86BIOS_ROM_BASE - x86bios_rom_phys, PAT_WRITE_BACK) != 0)
+ goto fail;
+#endif
+
+ x86bios_seg = contigmalloc(X86BIOS_SEG_SIZE, M_DEVBUF, M_NOWAIT,
+ X86BIOS_RAM_BASE, x86bios_rom_phys, X86BIOS_PAGE_SIZE, 0);
+ if (x86bios_seg == NULL)
+ goto fail;
+ x86bios_seg_phys = vtophys(x86bios_seg);
+
+ x86bios_set_pages((vm_offset_t)x86bios_ivt, X86BIOS_IVT_BASE,
+ X86BIOS_IVT_SIZE);
+ x86bios_set_pages((vm_offset_t)x86bios_rom, x86bios_rom_phys,
+ X86BIOS_ROM_SIZE);
+ x86bios_set_pages((vm_offset_t)x86bios_seg, x86bios_seg_phys,
+ X86BIOS_SEG_SIZE);
+
+ if (bootverbose) {
+ printf("x86bios: IVT 0x%06jx-0x%06jx at %p\n",
+ (vm_paddr_t)X86BIOS_IVT_BASE,
+ (vm_paddr_t)X86BIOS_IVT_SIZE + X86BIOS_IVT_BASE - 1,
+ x86bios_ivt);
+ printf("x86bios: SSEG 0x%06jx-0x%06jx at %p\n",
+ x86bios_seg_phys,
+ (vm_paddr_t)X86BIOS_SEG_SIZE + x86bios_seg_phys - 1,
+ x86bios_seg);
+ if (x86bios_rom_phys < X86BIOS_ROM_BASE)
+ printf("x86bios: EBDA 0x%06jx-0x%06jx at %p\n",
+ x86bios_rom_phys, (vm_paddr_t)X86BIOS_ROM_BASE - 1,
+ x86bios_rom);
+ printf("x86bios: ROM 0x%06jx-0x%06jx at %p\n",
+ (vm_paddr_t)X86BIOS_ROM_BASE,
+ (vm_paddr_t)X86BIOS_MEM_SIZE - X86BIOS_SEG_SIZE - 1,
+ (caddr_t)x86bios_rom + X86BIOS_ROM_BASE - x86bios_rom_phys);
+ }
+
+ return (0);
+
+fail:
+ x86bios_unmap_mem();
+
+ return (1);
+}
+
+static int
+x86bios_init(void)
+{
+
+ mtx_init(&x86bios_lock, "x86bios lock", NULL, MTX_DEF);
+
+ if (x86bios_map_mem() != 0)
+ return (ENOMEM);
+
+ bzero(&x86bios_emu, sizeof(x86bios_emu));
+
+ x86bios_emu.emu_rdb = x86bios_emu_rdb;
+ x86bios_emu.emu_rdw = x86bios_emu_rdw;
+ x86bios_emu.emu_rdl = x86bios_emu_rdl;
+ x86bios_emu.emu_wrb = x86bios_emu_wrb;
+ x86bios_emu.emu_wrw = x86bios_emu_wrw;
+ x86bios_emu.emu_wrl = x86bios_emu_wrl;
+
+ x86bios_emu.emu_inb = x86bios_emu_inb;
+ x86bios_emu.emu_inw = x86bios_emu_inw;
+ x86bios_emu.emu_inl = x86bios_emu_inl;
+ x86bios_emu.emu_outb = x86bios_emu_outb;
+ x86bios_emu.emu_outw = x86bios_emu_outw;
+ x86bios_emu.emu_outl = x86bios_emu_outl;
+
+ return (0);
+}
+
+static int
+x86bios_uninit(void)
+{
+
+ x86bios_unmap_mem();
+ mtx_destroy(&x86bios_lock);
+
+ return (0);
+}
+
+#endif
+
+void *
+x86bios_get_orm(uint32_t offset)
+{
+ uint8_t *p;
+
+ /* Does the shadow ROM contain BIOS POST code for x86? */
+ p = x86bios_offset(offset);
+ if (p == NULL || p[0] != 0x55 || p[1] != 0xaa ||
+ (p[3] != 0xe9 && p[3] != 0xeb))
+ return (NULL);
+
+ return (p);
+}
+
+int
+x86bios_match_device(uint32_t offset, device_t dev)
+{
+ uint8_t *p;
+ uint16_t device, vendor;
+ uint8_t class, progif, subclass;
+
+ /* Does the shadow ROM contain BIOS POST code for x86? */
+ p = x86bios_get_orm(offset);
+ if (p == NULL)
+ return (0);
+
+ /* Does it contain PCI data structure? */
+ p += le16toh(*(uint16_t *)(p + 0x18));
+ if (bcmp(p, "PCIR", 4) != 0 ||
+ le16toh(*(uint16_t *)(p + 0x0a)) < 0x18 || *(p + 0x14) != 0)
+ return (0);
+
+ /* Does it match the vendor, device, and classcode? */
+ vendor = le16toh(*(uint16_t *)(p + 0x04));
+ device = le16toh(*(uint16_t *)(p + 0x06));
+ progif = *(p + 0x0d);
+ subclass = *(p + 0x0e);
+ class = *(p + 0x0f);
+ if (vendor != pci_get_vendor(dev) || device != pci_get_device(dev) ||
+ class != pci_get_class(dev) || subclass != pci_get_subclass(dev) ||
+ progif != pci_get_progif(dev))
+ return (0);
+
+ return (1);
+}
+
+static int
+x86bios_modevent(module_t mod __unused, int type, void *data __unused)
+{
+
+ switch (type) {
+ case MOD_LOAD:
+ return (x86bios_init());
+ case MOD_UNLOAD:
+ return (x86bios_uninit());
+ default:
+ return (ENOTSUP);
+ }
+}
+
+static moduledata_t x86bios_mod = {
+ "x86bios",
+ x86bios_modevent,
+ NULL,
+};
+
+DECLARE_MODULE(x86bios, x86bios_mod, SI_SUB_CPU, SI_ORDER_ANY);
+MODULE_VERSION(x86bios, 1);
diff --git a/sys/compat/x86bios/x86bios.h b/sys/compat/x86bios/x86bios.h
new file mode 100644
index 000000000000..f12c800d8b33
--- /dev/null
+++ b/sys/compat/x86bios/x86bios.h
@@ -0,0 +1,157 @@
+/*-
+ * Copyright (c) 2009 Alex Keda <admin@lissyara.su>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/*
+ * x86 registers were borrowed from x86emu.h x86emu_regs.h
+ * for compatibility.
+ */
+
+#ifndef _X86BIOS_H_
+#define _X86BIOS_H_
+
+#include <sys/endian.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+
+#ifdef __BIG_ENDIAN__
+
+struct x86_register32 {
+ uint32_t e_reg;
+};
+
+struct x86_register16 {
+ uint16_t filler0;
+ uint16_t x_reg;
+};
+
+struct x86_register8 {
+ uint8_t filler0;
+ uint8_t filler1;
+ uint8_t h_reg;
+ uint8_t l_reg;
+};
+
+#else /* !__BIG_ENDIAN__ */
+
+struct x86_register32 {
+ uint32_t e_reg;
+};
+
+struct x86_register16 {
+ uint16_t x_reg;
+};
+
+struct x86_register8 {
+ uint8_t l_reg;
+ uint8_t h_reg;
+};
+
+#endif /* __BIG_ENDIAN__ */
+
+union x86_register {
+ struct x86_register32 I32_reg;
+ struct x86_register16 I16_reg;
+ struct x86_register8 I8_reg;
+};
+
+struct x86regs {
+ uint16_t _pad0; /* CS */
+ uint16_t _pad1; /* DS */
+ uint16_t register_es;
+ uint16_t register_fs;
+ uint16_t register_gs;
+ uint16_t _pad2; /* SS */
+ uint32_t register_flags;
+ union x86_register register_a;
+ union x86_register register_b;
+ union x86_register register_c;
+ union x86_register register_d;
+
+ union x86_register _pad3; /* SP */
+ union x86_register register_bp;
+ union x86_register register_si;
+ union x86_register register_di;
+};
+
+typedef struct x86regs x86regs_t;
+
+/* 8 bit registers */
+#define R_AH register_a.I8_reg.h_reg
+#define R_AL register_a.I8_reg.l_reg
+#define R_BH register_b.I8_reg.h_reg
+#define R_BL register_b.I8_reg.l_reg
+#define R_CH register_c.I8_reg.h_reg
+#define R_CL register_c.I8_reg.l_reg
+#define R_DH register_d.I8_reg.h_reg
+#define R_DL register_d.I8_reg.l_reg
+
+/* 16 bit registers */
+#define R_AX register_a.I16_reg.x_reg
+#define R_BX register_b.I16_reg.x_reg
+#define R_CX register_c.I16_reg.x_reg
+#define R_DX register_d.I16_reg.x_reg
+
+/* 32 bit extended registers */
+#define R_EAX register_a.I32_reg.e_reg
+#define R_EBX register_b.I32_reg.e_reg
+#define R_ECX register_c.I32_reg.e_reg
+#define R_EDX register_d.I32_reg.e_reg
+
+/* special registers */
+#define R_BP register_bp.I16_reg.x_reg
+#define R_SI register_si.I16_reg.x_reg
+#define R_DI register_di.I16_reg.x_reg
+#define R_FLG register_flags
+
+/* special registers */
+#define R_EBP register_bp.I32_reg.e_reg
+#define R_ESI register_si.I32_reg.e_reg
+#define R_EDI register_di.I32_reg.e_reg
+#define R_EFLG register_flags
+
+/* segment registers */
+#define R_ES register_es
+#define R_FS register_fs
+#define R_GS register_gs
+
+#define X86BIOS_PHYSTOSEG(x) (((x) >> 4) & 0xff00)
+#define X86BIOS_PHYSTOOFF(x) ((x) & 0x0fff)
+
+__BEGIN_DECLS
+void *x86bios_alloc(uint32_t *offset, size_t size, int flags);
+void x86bios_call(struct x86regs *regs, uint16_t seg, uint16_t off);
+void x86bios_free(void *addr, size_t size);
+uint32_t x86bios_get_intr(int intno);
+void *x86bios_get_orm(uint32_t offset);
+void x86bios_init_regs(struct x86regs *regs);
+void x86bios_intr(struct x86regs *regs, int intno);
+int x86bios_match_device(uint32_t offset, device_t dev);
+void *x86bios_offset(uint32_t offset);
+void x86bios_set_intr(int intno, uint32_t saddr);
+__END_DECLS
+
+#endif /* !_X86BIOS_H_ */