diff options
Diffstat (limited to 'sys/compat')
128 files changed, 71205 insertions, 0 deletions
diff --git a/sys/compat/freebsd32/Makefile b/sys/compat/freebsd32/Makefile new file mode 100644 index 0000000..34d3e81 --- /dev/null +++ b/sys/compat/freebsd32/Makefile @@ -0,0 +1,21 @@ +# Makefile for syscall tables +# +# $FreeBSD$ + +all: + @echo "make sysent only" + +sysent: freebsd32_sysent.c freebsd32_syscall.h freebsd32_proto.h freebsd32_systrace_args.c + +freebsd32_sysent.c freebsd32_syscalls.c freebsd32_syscall.h freebsd32_proto.h freebsd32_systrace_args.c : \ + ../../kern/makesyscalls.sh syscalls.master syscalls.conf + -mv -f freebsd32_sysent.c freebsd32_sysent.c.bak + -mv -f freebsd32_syscalls.c freebsd32_syscalls.c.bak + -mv -f freebsd32_syscall.h freebsd32_syscall.h.bak + -mv -f freebsd32_proto.h freebsd32_proto.h.bak + -mv -f freebsd32_systrace_args.c freebsd32_systrace_args.c.bak + sh ../../kern/makesyscalls.sh syscalls.master syscalls.conf + +clean: + rm -f freebsd32_sysent.c freebsd32_syscalls.c freebsd32_syscall.h freebsd32_proto.h + rm -f freebsd32_systrace_args.c diff --git a/sys/compat/freebsd32/freebsd32.h b/sys/compat/freebsd32/freebsd32.h new file mode 100644 index 0000000..a95b0e5 --- /dev/null +++ b/sys/compat/freebsd32/freebsd32.h @@ -0,0 +1,372 @@ +/*- + * 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/procfs.h> +#include <sys/socket.h> +#include <sys/user.h> + +#define PTRIN(v) (void *)(uintptr_t) (v) +#define PTROUT(v) (u_int32_t)(uintptr_t) (v) + +#define CP(src,dst,fld) do { (dst).fld = (src).fld; } while (0) +#define PTRIN_CP(src,dst,fld) \ + do { (dst).fld = PTRIN((src).fld); } while (0) +#define PTROUT_CP(src,dst,fld) \ + do { (dst).fld = PTROUT((src).fld); } while (0) + +/* + * Being a newer port, 32-bit FreeBSD/MIPS uses 64-bit time_t. + */ +#ifdef __mips__ +typedef int64_t time32_t; +#else +typedef int32_t time32_t; +#endif + +struct timeval32 { + time32_t tv_sec; + int32_t tv_usec; +}; +#define TV_CP(src,dst,fld) do { \ + CP((src).fld,(dst).fld,tv_sec); \ + CP((src).fld,(dst).fld,tv_usec); \ +} while (0) + +struct timespec32 { + time32_t tv_sec; + int32_t tv_nsec; +}; +#define TS_CP(src,dst,fld) do { \ + CP((src).fld,(dst).fld,tv_sec); \ + CP((src).fld,(dst).fld,tv_nsec); \ +} while (0) + +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; +}; + +#define FREEBSD4_MNAMELEN (88 - 2 * sizeof(int32_t)) /* size of on/from name bufs */ + +/* 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[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 kevent32 { + u_int32_t ident; /* identifier for this event */ + short filter; /* filter for event */ + u_short flags; + u_int fflags; + int32_t data; + u_int32_t udata; /* opaque user data identifier */ +}; + +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; +}; + +struct stat32 { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_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; + 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; + ino_t st_ino; + mode_t st_mode; + nlink_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; +}; + +/* + * Alternative layouts for <sys/procfs.h> + */ +struct prstatus32 { + int pr_version; + u_int pr_statussz; + u_int pr_gregsetsz; + u_int pr_fpregsetsz; + int pr_osreldate; + int pr_cursig; + pid_t pr_pid; + struct reg32 pr_reg; +}; + +struct prpsinfo32 { + int pr_version; + u_int pr_psinfosz; + char pr_fname[PRFNAMESZ+1]; + char pr_psargs[PRARGSZ+1]; +}; + +struct thrmisc32 { + char pr_tname[MAXCOMLEN+1]; + u_int _pad; +}; + +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; + dev_t ki_tdev; + 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; + u_char ki_lastcpu; + 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_sparestrings[50]; + int ki_spareints[KI_NSPARE_INT]; + 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 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]; +}; + +#endif /* !_COMPAT_FREEBSD32_FREEBSD32_H_ */ diff --git a/sys/compat/freebsd32/freebsd32_ioctl.c b/sys/compat/freebsd32/freebsd32_ioctl.c new file mode 100644 index 0000000..81f5c8e --- /dev/null +++ b/sys/compat/freebsd32/freebsd32_ioctl.c @@ -0,0 +1,404 @@ +/*- + * 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 "opt_compat.h" + +#include <sys/param.h> +#include <sys/capability.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/mdioctl.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 <compat/freebsd32/freebsd32.h> +#include <compat/freebsd32/freebsd32_ioctl.h> +#include <compat/freebsd32/freebsd32_proto.h> + +/* Cannot get exact size in 64-bit due to alignment issue of entire struct. */ +CTASSERT((sizeof(struct md_ioctl32)+4) == 436); +CTASSERT(sizeof(struct ioc_read_toc_entry32) == 8); +CTASSERT(sizeof(struct ioc_toc_header32) == 4); +CTASSERT(sizeof(struct mem_range_op32) == 12); +CTASSERT(sizeof(struct pci_conf_io32) == 36); +CTASSERT(sizeof(struct pci_match_conf32) == 44); +CTASSERT(sizeof(struct pci_conf32) == 44); + + +static int +freebsd32_ioctl_md(struct thread *td, struct freebsd32_ioctl_args *uap, + struct file *fp) +{ + struct md_ioctl mdv; + struct md_ioctl32 md32; + u_long com = 0; + int i, error; + + if (uap->com & IOC_IN) { + if ((error = copyin(uap->data, &md32, sizeof(md32)))) { + return (error); + } + CP(md32, mdv, md_version); + CP(md32, mdv, md_unit); + CP(md32, mdv, md_type); + PTRIN_CP(md32, mdv, md_file); + CP(md32, mdv, md_mediasize); + CP(md32, mdv, md_sectorsize); + CP(md32, mdv, md_options); + CP(md32, mdv, md_base); + CP(md32, mdv, md_fwheads); + CP(md32, mdv, md_fwsectors); + } else if (uap->com & IOC_OUT) { + /* + * Zero the buffer so the user always + * gets back something deterministic. + */ + bzero(&mdv, sizeof mdv); + } + + switch (uap->com) { + case MDIOCATTACH_32: + com = MDIOCATTACH; + break; + case MDIOCDETACH_32: + com = MDIOCDETACH; + break; + case MDIOCQUERY_32: + com = MDIOCQUERY; + break; + case MDIOCLIST_32: + com = MDIOCLIST; + break; + default: + panic("%s: unknown MDIOC %#x", __func__, uap->com); + } + error = fo_ioctl(fp, com, (caddr_t)&mdv, td->td_ucred, td); + if (error == 0 && (com & IOC_OUT)) { + CP(mdv, md32, md_version); + CP(mdv, md32, md_unit); + CP(mdv, md32, md_type); + PTROUT_CP(mdv, md32, md_file); + CP(mdv, md32, md_mediasize); + CP(mdv, md32, md_sectorsize); + CP(mdv, md32, md_options); + CP(mdv, md32, md_base); + CP(mdv, md32, md_fwheads); + CP(mdv, md32, md_fwsectors); + if (com == MDIOCLIST) { + /* + * Use MDNPAD, and not MDNPAD32. Padding is + * allocated and used by compat32 ABI. + */ + for (i = 0; i < MDNPAD; i++) + CP(mdv, md32, md_pad[i]); + } + error = copyout(&md32, uap->data, sizeof(md32)); + } + return error; +} + + +static int +freebsd32_ioctl_ioc_toc_header(struct thread *td, + struct freebsd32_ioctl_args *uap, struct file *fp) +{ + struct ioc_toc_header toch; + struct ioc_toc_header32 toch32; + int error; + + if ((error = copyin(uap->data, &toch32, sizeof(toch32)))) + return (error); + CP(toch32, toch, len); + CP(toch32, toch, starting_track); + CP(toch32, toch, ending_track); + error = fo_ioctl(fp, CDIOREADTOCHEADER, (caddr_t)&toch, + td->td_ucred, td); + return (error); +} + + +static int +freebsd32_ioctl_ioc_read_toc(struct thread *td, + struct freebsd32_ioctl_args *uap, struct file *fp) +{ + struct ioc_read_toc_entry toce; + struct ioc_read_toc_entry32 toce32; + int error; + + if ((error = copyin(uap->data, &toce32, sizeof(toce32)))) + return (error); + CP(toce32, toce, address_format); + CP(toce32, toce, starting_track); + CP(toce32, toce, data_len); + PTRIN_CP(toce32, toce, data); + + if ((error = fo_ioctl(fp, CDIOREADTOCENTRYS, (caddr_t)&toce, + td->td_ucred, td))) { + CP(toce, toce32, address_format); + CP(toce, toce32, starting_track); + CP(toce, toce32, data_len); + PTROUT_CP(toce, toce32, data); + error = copyout(&toce32, uap->data, sizeof(toce32)); + } + return error; +} + +static int +freebsd32_ioctl_fiodgname(struct thread *td, + struct freebsd32_ioctl_args *uap, struct file *fp) +{ + struct fiodgname_arg fgn; + struct fiodgname_arg32 fgn32; + int error; + + if ((error = copyin(uap->data, &fgn32, sizeof fgn32)) != 0) + return (error); + CP(fgn32, fgn, len); + PTRIN_CP(fgn32, fgn, buf); + error = fo_ioctl(fp, FIODGNAME, (caddr_t)&fgn, td->td_ucred, td); + return (error); +} + +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_pciocgetconf(struct thread *td, + struct freebsd32_ioctl_args *uap, struct file *fp) +{ + struct pci_conf_io pci; + struct pci_conf_io32 pci32; + struct pci_match_conf32 pmc32; + struct pci_match_conf32 *pmc32p; + struct pci_match_conf pmc; + struct pci_match_conf *pmcp; + struct pci_conf32 pc32; + struct pci_conf32 *pc32p; + struct pci_conf pc; + struct pci_conf *pcp; + u_int32_t i; + u_int32_t npat_to_convert; + u_int32_t nmatch_to_convert; + vm_offset_t addr; + int error; + + if ((error = copyin(uap->data, &pci32, sizeof(pci32))) != 0) + return (error); + + CP(pci32, pci, num_patterns); + CP(pci32, pci, offset); + CP(pci32, pci, generation); + + npat_to_convert = pci32.pat_buf_len / sizeof(struct pci_match_conf32); + pci.pat_buf_len = npat_to_convert * sizeof(struct pci_match_conf); + pci.patterns = NULL; + nmatch_to_convert = pci32.match_buf_len / sizeof(struct pci_conf32); + pci.match_buf_len = nmatch_to_convert * sizeof(struct pci_conf); + pci.matches = NULL; + + if ((error = copyout_map(td, &addr, pci.pat_buf_len)) != 0) + goto cleanup; + pci.patterns = (struct pci_match_conf *)addr; + if ((error = copyout_map(td, &addr, pci.match_buf_len)) != 0) + goto cleanup; + pci.matches = (struct pci_conf *)addr; + + npat_to_convert = min(npat_to_convert, pci.num_patterns); + + for (i = 0, pmc32p = (struct pci_match_conf32 *)PTRIN(pci32.patterns), + pmcp = pci.patterns; + i < npat_to_convert; i++, pmc32p++, pmcp++) { + if ((error = copyin(pmc32p, &pmc32, sizeof(pmc32))) != 0) + goto cleanup; + CP(pmc32,pmc,pc_sel); + strlcpy(pmc.pd_name, pmc32.pd_name, sizeof(pmc.pd_name)); + CP(pmc32,pmc,pd_unit); + CP(pmc32,pmc,pc_vendor); + CP(pmc32,pmc,pc_device); + CP(pmc32,pmc,pc_class); + CP(pmc32,pmc,flags); + if ((error = copyout(&pmc, pmcp, sizeof(pmc))) != 0) + goto cleanup; + } + + if ((error = fo_ioctl(fp, PCIOCGETCONF, (caddr_t)&pci, + td->td_ucred, td)) != 0) + goto cleanup; + + nmatch_to_convert = min(nmatch_to_convert, pci.num_matches); + + for (i = 0, pcp = pci.matches, + pc32p = (struct pci_conf32 *)PTRIN(pci32.matches); + i < nmatch_to_convert; i++, pcp++, pc32p++) { + if ((error = copyin(pcp, &pc, sizeof(pc))) != 0) + goto cleanup; + CP(pc,pc32,pc_sel); + CP(pc,pc32,pc_hdr); + CP(pc,pc32,pc_subvendor); + CP(pc,pc32,pc_subdevice); + CP(pc,pc32,pc_vendor); + CP(pc,pc32,pc_device); + CP(pc,pc32,pc_class); + CP(pc,pc32,pc_subclass); + CP(pc,pc32,pc_progif); + CP(pc,pc32,pc_revid); + strlcpy(pc32.pd_name, pc.pd_name, sizeof(pc32.pd_name)); + CP(pc,pc32,pd_unit); + if ((error = copyout(&pc32, pc32p, sizeof(pc32))) != 0) + goto cleanup; + } + + CP(pci, pci32, num_matches); + CP(pci, pci32, offset); + CP(pci, pci32, generation); + CP(pci, pci32, status); + + error = copyout(&pci32, uap->data, sizeof(pci32)); + +cleanup: + if (pci.patterns) + copyout_unmap(td, (vm_offset_t)pci.patterns, pci.pat_buf_len); + if (pci.matches) + copyout_unmap(td, (vm_offset_t)pci.matches, pci.match_buf_len); + + 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; + int error; + + if ((error = fget(td, uap->fd, CAP_IOCTL, &fp)) != 0) + return (error); + if ((fp->f_flag & (FREAD | FWRITE)) == 0) { + fdrop(fp, td); + return (EBADF); + } + + switch (uap->com) { + case MDIOCATTACH_32: /* FALLTHROUGH */ + case MDIOCDETACH_32: /* FALLTHROUGH */ + case MDIOCQUERY_32: /* FALLTHROUGH */ + case MDIOCLIST_32: + error = freebsd32_ioctl_md(td, uap, fp); + break; + + case CDIOREADTOCENTRYS_32: + error = freebsd32_ioctl_ioc_read_toc(td, uap, fp); + break; + + case CDIOREADTOCHEADER_32: + error = freebsd32_ioctl_ioc_toc_header(td, uap, fp); + break; + + case FIODGNAME_32: + error = freebsd32_ioctl_fiodgname(td, uap, fp); + break; + + case MEMRANGE_GET32: /* FALLTHROUGH */ + case MEMRANGE_SET32: + error = freebsd32_ioctl_memrange(td, uap, fp); + break; + + case PCIOCGETCONF_32: + error = freebsd32_ioctl_pciocgetconf(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 0000000..e0beb73 --- /dev/null +++ b/sys/compat/freebsd32/freebsd32_ioctl.h @@ -0,0 +1,126 @@ +/*- + * 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_ + +typedef __uint32_t caddr_t32; + +struct ioc_toc_header32 { + u_short len; + u_char starting_track; + u_char ending_track; +}; + +struct ioc_read_toc_entry32 { + u_char address_format; + u_char starting_track; + u_short data_len; + uint32_t data; /* struct cd_toc_entry* */ +}; + +#define MDNPAD32 MDNPAD - 1 +struct md_ioctl32 { + unsigned md_version; /* Structure layout version */ + unsigned md_unit; /* unit number */ + enum md_types md_type; /* type of disk */ + caddr_t32 md_file; /* pathname of file to mount */ + off_t md_mediasize; /* size of disk in bytes */ + unsigned md_sectorsize; /* sectorsize */ + unsigned md_options; /* options */ + u_int64_t md_base; /* base address */ + int md_fwheads; /* firmware heads */ + int md_fwsectors; /* firmware sectors */ + int md_pad[MDNPAD32]; /* padding for future ideas */ +}; + +struct fiodgname_arg32 { + int len; + caddr_t32 buf; +}; + +struct mem_range_op32 +{ + caddr_t32 mo_desc; + int mo_arg[2]; +}; + +struct pci_conf32 { + struct pcisel pc_sel; /* domain+bus+slot+function */ + u_int8_t pc_hdr; /* PCI header type */ + u_int16_t pc_subvendor; /* card vendor ID */ + u_int16_t pc_subdevice; /* card device ID, assigned by + card vendor */ + u_int16_t pc_vendor; /* chip vendor ID */ + u_int16_t pc_device; /* chip device ID, assigned by + chip vendor */ + u_int8_t pc_class; /* chip PCI class */ + u_int8_t pc_subclass; /* chip PCI subclass */ + u_int8_t pc_progif; /* chip PCI programming interface */ + u_int8_t pc_revid; /* chip revision ID */ + char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ + u_int32_t pd_unit; /* device unit number */ +}; + +struct pci_match_conf32 { + struct pcisel pc_sel; /* domain+bus+slot+function */ + char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ + u_int32_t pd_unit; /* Unit number */ + u_int16_t pc_vendor; /* PCI Vendor ID */ + u_int16_t pc_device; /* PCI Device ID */ + u_int8_t pc_class; /* PCI class */ + u_int32_t flags; /* Matching expression */ +}; + +struct pci_conf_io32 { + u_int32_t pat_buf_len; /* pattern buffer length */ + u_int32_t num_patterns; /* number of patterns */ + caddr_t32 patterns; /* struct pci_match_conf ptr */ + u_int32_t match_buf_len; /* match buffer length */ + u_int32_t num_matches; /* number of matches returned */ + caddr_t32 matches; /* struct pci_conf ptr */ + u_int32_t offset; /* offset into device list */ + u_int32_t generation; /* device list generation */ + u_int32_t status; /* request status */ +}; + +#define CDIOREADTOCENTRYS_32 _IOWR('c', 5, struct ioc_read_toc_entry32) +#define CDIOREADTOCHEADER_32 _IOR('c', 4, struct ioc_toc_header32) +#define MDIOCATTACH_32 _IOC(IOC_INOUT, 'm', 0, sizeof(struct md_ioctl32) + 4) +#define MDIOCDETACH_32 _IOC(IOC_INOUT, 'm', 1, sizeof(struct md_ioctl32) + 4) +#define MDIOCQUERY_32 _IOC(IOC_INOUT, 'm', 2, sizeof(struct md_ioctl32) + 4) +#define MDIOCLIST_32 _IOC(IOC_INOUT, 'm', 3, sizeof(struct md_ioctl32) + 4) +#define FIODGNAME_32 _IOW('f', 120, struct fiodgname_arg32) +#define MEMRANGE_GET32 _IOWR('m', 50, struct mem_range_op32) +#define MEMRANGE_SET32 _IOW('m', 51, struct mem_range_op32) +#define PCIOCGETCONF_32 _IOWR('p', 5, struct pci_conf_io32) + +#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 0000000..320a63f --- /dev/null +++ b/sys/compat/freebsd32/freebsd32_ipc.h @@ -0,0 +1,160 @@ +/*- + * 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; +}; + +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; +}; + +struct shmid_ds32 { + struct ipc_perm32 shm_perm; + int32_t shm_segsz; + pid_t shm_lpid; + pid_t shm_cpid; + int shm_nattch; + int32_t shm_atime; + int32_t shm_dtime; + int32_t shm_ctime; +}; + +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 0000000..dd8d4f7 --- /dev/null +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -0,0 +1,2900 @@ +/*- + * 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_compat.h" +#include "opt_inet.h" +#include "opt_inet6.h" + +#define __ELF_WORD_SIZE 32 + +#include <sys/param.h> +#include <sys/bus.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/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/unistd.h> +#include <sys/ucontext.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 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> + +#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_signal.h> +#include <compat/freebsd32/freebsd32_proto.h> + +FEATURE(compat_freebsd_32bit, "Compatible with 32-bit FreeBSD"); + +#ifndef __mips__ +CTASSERT(sizeof(struct timeval32) == 8); +CTASSERT(sizeof(struct timespec32) == 8); +CTASSERT(sizeof(struct itimerval32) == 16); +#endif +CTASSERT(sizeof(struct statfs32) == 256); +#ifndef __mips__ +CTASSERT(sizeof(struct rusage32) == 72); +#endif +CTASSERT(sizeof(struct sigaltstack32) == 12); +CTASSERT(sizeof(struct kevent32) == 20); +CTASSERT(sizeof(struct iovec32) == 8); +CTASSERT(sizeof(struct msghdr32) == 28); +#ifndef __mips__ +CTASSERT(sizeof(struct 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); + +#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 + +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; + int error; + + count = uap->bufsize / sizeof(struct statfs32); + size = count * sizeof(struct statfs); + error = kern_getfsstat(td, &buf, size, UIO_SYSSPACE, uap->flags); + if (size > 0) { + count = td->td_retval[0]; + sp = buf; + while (count > 0 && error == 0) { + copy_statfs(sp, &stat32); + error = copyout(&stat32, uap->buf, sizeof(stat32)); + sp++; + uap->buf++; + count--; + } + free(buf, M_TEMP); + } + return (error); +} +#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, char *fname, + enum uio_seg segflg, u_int32_t *argv, u_int32_t *envv) +{ + char *argp, *envp; + u_int32_t *p32, arg; + size_t length; + 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. + */ + if (fname != NULL) { + args->fname = args->buf; + error = (segflg == UIO_SYSSPACE) ? + copystr(fname, args->fname, PATH_MAX, &length) : + copyinstr(fname, args->fname, PATH_MAX, &length); + if (error != 0) + goto err_exit; + } else + length = 0; + + args->begin_argv = args->buf + length; + args->endp = args->begin_argv; + args->stringspace = ARG_MAX; + + /* + * 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 = copyinstr(argp, args->endp, args->stringspace, &length); + if (error) { + if (error == ENAMETOOLONG) + error = E2BIG; + goto err_exit; + } + args->stringspace -= length; + args->endp += length; + args->argc++; + } + + args->begin_envv = args->endp; + + /* + * 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 = copyinstr(envp, args->endp, args->stringspace, + &length); + if (error) { + if (error == ENAMETOOLONG) + error = E2BIG; + goto err_exit; + } + args->stringspace -= length; + args->endp += length; + args->envc++; + } + } + + 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; + int error; + + error = freebsd32_exec_copyin_args(&eargs, uap->fname, UIO_USERSPACE, + uap->argv, uap->envv); + if (error == 0) + error = kern_execve(td, &eargs, NULL); + return (error); +} + +int +freebsd32_fexecve(struct thread *td, struct freebsd32_fexecve_args *uap) +{ + struct image_args eargs; + int 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); + } + return (error); +} + +#ifdef __ia64__ +static int +freebsd32_mmap_partial(struct thread *td, vm_offset_t start, vm_offset_t end, + int prot, int fd, off_t pos) +{ + vm_map_t map; + vm_map_entry_t entry; + int rv; + + map = &td->td_proc->p_vmspace->vm_map; + if (fd != -1) + prot |= VM_PROT_WRITE; + + if (vm_map_lookup_entry(map, start, &entry)) { + if ((entry->protection & prot) != prot) { + rv = vm_map_protect(map, + trunc_page(start), + round_page(end), + entry->protection | prot, + FALSE); + if (rv != KERN_SUCCESS) + return (EINVAL); + } + } else { + vm_offset_t addr = trunc_page(start); + rv = vm_map_find(map, 0, 0, + &addr, PAGE_SIZE, FALSE, prot, + VM_PROT_ALL, 0); + if (rv != KERN_SUCCESS) + return (EINVAL); + } + + if (fd != -1) { + struct pread_args r; + r.fd = fd; + r.buf = (void *) start; + r.nbyte = end - start; + r.offset = pos; + return (sys_pread(td, &r)); + } else { + while (start < end) { + subyte((void *) start, 0); + start++; + } + return (0); + } +} +#endif + +int +freebsd32_mprotect(struct thread *td, struct freebsd32_mprotect_args *uap) +{ + struct mprotect_args ap; + + ap.addr = PTRIN(uap->addr); + ap.len = uap->len; + ap.prot = uap->prot; +#if defined(__amd64__) || defined(__ia64__) + if (i386_read_exec && (ap.prot & PROT_READ) != 0) + ap.prot |= PROT_EXEC; +#endif + return (sys_mprotect(td, &ap)); +} + +int +freebsd32_mmap(struct thread *td, struct freebsd32_mmap_args *uap) +{ + struct mmap_args ap; + vm_offset_t addr = (vm_offset_t) uap->addr; + vm_size_t len = uap->len; + int prot = uap->prot; + int flags = uap->flags; + int fd = uap->fd; + off_t pos = PAIR32TO64(off_t,uap->pos); +#ifdef __ia64__ + vm_size_t pageoff; + int error; + + /* + * Attempt to handle page size hassles. + */ + pageoff = (pos & PAGE_MASK); + if (flags & MAP_FIXED) { + vm_offset_t start, end; + start = addr; + end = addr + len; + + if (start != trunc_page(start)) { + error = freebsd32_mmap_partial(td, start, + round_page(start), prot, + fd, pos); + if (fd != -1) + pos += round_page(start) - start; + start = round_page(start); + } + if (end != round_page(end)) { + vm_offset_t t = trunc_page(end); + error = freebsd32_mmap_partial(td, t, end, + prot, fd, + pos + t - start); + end = trunc_page(end); + } + if (end > start && fd != -1 && (pos & PAGE_MASK)) { + /* + * We can't map this region at all. The specified + * address doesn't have the same alignment as the file + * position. Fake the mapping by simply reading the + * entire region into memory. First we need to make + * sure the region exists. + */ + vm_map_t map; + struct pread_args r; + int rv; + + prot |= VM_PROT_WRITE; + map = &td->td_proc->p_vmspace->vm_map; + rv = vm_map_remove(map, start, end); + if (rv != KERN_SUCCESS) + return (EINVAL); + rv = vm_map_find(map, 0, 0, + &start, end - start, FALSE, + prot, VM_PROT_ALL, 0); + if (rv != KERN_SUCCESS) + return (EINVAL); + r.fd = fd; + r.buf = (void *) start; + r.nbyte = end - start; + r.offset = pos; + error = sys_pread(td, &r); + if (error) + return (error); + + td->td_retval[0] = addr; + return (0); + } + if (end == start) { + /* + * After dealing with the ragged ends, there + * might be none left. + */ + td->td_retval[0] = addr; + return (0); + } + addr = start; + len = end - start; + } +#endif + +#if defined(__amd64__) || defined(__ia64__) + if (i386_read_exec && (prot & PROT_READ)) + prot |= PROT_EXEC; +#endif + + ap.addr = (void *) addr; + ap.len = len; + ap.prot = prot; + ap.flags = flags; + ap.fd = fd; + ap.pos = pos; + + return (sys_mmap(td, &ap)); +} + +#ifdef COMPAT_FREEBSD6 +int +freebsd6_freebsd32_mmap(struct thread *td, struct freebsd6_freebsd32_mmap_args *uap) +{ + struct freebsd32_mmap_args ap; + + ap.addr = uap->addr; + ap.len = uap->len; + ap.prot = uap->prot; + ap.flags = uap->flags; + ap.fd = uap->fd; + ap.pos1 = uap->pos1; + ap.pos2 = uap->pos2; + + return (freebsd32_mmap(td, &ap)); +} +#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]; + int i, error = 0; + + 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); + 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_kevent_copyin(void *arg, struct kevent *kevp, int count) +{ + struct freebsd32_kevent_args *uap; + struct kevent32 ks32[KQ_NEVENTS]; + int i, error = 0; + + 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); + CP(ks32[i], kevp[i], data); + PTRIN_CP(ks32[i], kevp[i], udata); + } +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 = { uap, + freebsd32_kevent_copyout, + freebsd32_kevent_copyin}; + 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; + error = kern_kevent(td, uap->fd, uap->nchanges, uap->nevents, + &k_ops, tsp); + return (error); +} + +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 = tz_minuteswest; + rtz.tz_dsttime = tz_dsttime; + 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) + return (error); + if (uap->rusage != NULL) { + freebsd32_rusage_out(&s, &s32); + error = copyout(&s32, uap->rusage, sizeof(s32)); + } + return (error); +} + +static 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 int +freebsd32_copy_msg_out(struct msghdr *msg, struct mbuf *control) +{ + struct cmsghdr *cm; + void *data; + socklen_t clen, datalen; + 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; + + m = control; + ctlbuf = msg->msg_control; + + while (m && len > 0) { + 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; + + /* Adjust message length */ + cm->cmsg_len = FREEBSD32_ALIGN(sizeof(struct cmsghdr)) + + datalen; + + + /* Copy cmsghdr */ + copylen = sizeof(struct cmsghdr); + if (len < copylen) { + msg->msg_flags |= MSG_CTRUNC; + copylen = len; + } + + error = copyout(cm,ctlbuf,copylen); + if (error) + goto exit; + + ctlbuf += FREEBSD32_ALIGN(copylen); + len -= FREEBSD32_ALIGN(copylen); + + if (len <= 0) + break; + + /* Copy data */ + copylen = datalen; + if (len < copylen) { + msg->msg_flags |= MSG_CTRUNC; + copylen = len; + } + + 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; + } + } + m = m->m_next; + } + + msg->msg_controllen = (len <= 0) ? maxlen : ctlbuf - (caddr_t)msg->msg_control; + +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) + m_freem(control); + + return (error); +} + + +static int +freebsd32_convert_msg_in(struct mbuf **controlp) +{ + struct mbuf *control = *controlp; + struct cmsghdr *cm = mtod(control, struct cmsghdr *); + void *data; + socklen_t clen = control->m_len, datalen; + int error; + + error = 0; + *controlp = NULL; + + while (cm != NULL) { + if (sizeof(struct cmsghdr) > clen || cm->cmsg_len > clen) { + error = EINVAL; + break; + } + + data = FREEBSD32_CMSG_DATA(cm); + datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data; + + *controlp = sbcreatecontrol(data, datalen, cm->cmsg_type, + cm->cmsg_level); + controlp = &(*controlp)->m_next; + + if (FREEBSD32_CMSG_SPACE(datalen) < clen) { + clen -= FREEBSD32_CMSG_SPACE(datalen); + cm = (struct cmsghdr *) + ((caddr_t)cm + FREEBSD32_CMSG_SPACE(datalen)); + } else { + clen = 0; + cm = NULL; + } + } + + m_freem(control); + 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 = sockargs(&control, msg.msg_control, + msg.msg_controllen, MT_CONTROL); + if (error) + goto out; + + error = freebsd32_convert_msg_in(&control); + if (error) + goto out; + } + + 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_utimes(td, 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_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 = δ + } 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 s; + int error; + + error = kern_statfs(td, uap->path, UIO_USERSPACE, &s); + if (error) + return (error); + copy_statfs(&s, &s32); + return (copyout(&s32, uap->buf, sizeof(s32))); +} +#endif + +#ifdef COMPAT_FREEBSD4 +int +freebsd4_freebsd32_fstatfs(struct thread *td, struct freebsd4_freebsd32_fstatfs_args *uap) +{ + struct statfs32 s32; + struct statfs s; + int error; + + error = kern_fstatfs(td, uap->fd, &s); + if (error) + return (error); + copy_statfs(&s, &s32); + return (copyout(&s32, uap->buf, sizeof(s32))); +} +#endif + +#ifdef COMPAT_FREEBSD4 +int +freebsd4_freebsd32_fhstatfs(struct thread *td, struct freebsd4_freebsd32_fhstatfs_args *uap) +{ + struct statfs32 s32; + struct statfs s; + fhandle_t fh; + int error; + + if ((error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t))) != 0) + return (error); + error = kern_fhstatfs(td, fh, &s); + if (error) + return (error); + copy_statfs(&s, &s32); + return (copyout(&s32, uap->buf, sizeof(s32))); +} +#endif + +int +freebsd32_pread(struct thread *td, struct freebsd32_pread_args *uap) +{ + struct pread_args ap; + + ap.fd = uap->fd; + ap.buf = uap->buf; + ap.nbyte = uap->nbyte; + ap.offset = PAIR32TO64(off_t,uap->offset); + return (sys_pread(td, &ap)); +} + +int +freebsd32_pwrite(struct thread *td, struct freebsd32_pwrite_args *uap) +{ + struct pwrite_args ap; + + ap.fd = uap->fd; + ap.buf = uap->buf; + ap.nbyte = uap->nbyte; + ap.offset = PAIR32TO64(off_t,uap->offset); + return (sys_pwrite(td, &ap)); +} + +#ifdef COMPAT_43 +int +ofreebsd32_lseek(struct thread *td, struct ofreebsd32_lseek_args *uap) +{ + struct lseek_args nuap; + + nuap.fd = uap->fd; + nuap.offset = uap->offset; + nuap.whence = uap->whence; + return (sys_lseek(td, &nuap)); +} +#endif + +int +freebsd32_lseek(struct thread *td, struct freebsd32_lseek_args *uap) +{ + int error; + struct lseek_args ap; + off_t pos; + + ap.fd = uap->fd; + ap.offset = PAIR32TO64(off_t,uap->offset); + ap.whence = uap->whence; + error = sys_lseek(td, &ap); + /* 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 +freebsd32_truncate(struct thread *td, struct freebsd32_truncate_args *uap) +{ + struct truncate_args ap; + + ap.path = uap->path; + ap.length = PAIR32TO64(off_t,uap->length); + return (sys_truncate(td, &ap)); +} + +int +freebsd32_ftruncate(struct thread *td, struct freebsd32_ftruncate_args *uap) +{ + struct ftruncate_args ap; + + ap.fd = uap->fd; + ap.length = PAIR32TO64(off_t,uap->length); + return (sys_ftruncate(td, &ap)); +} + +#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 + +int +freebsd32_getdirentries(struct thread *td, + struct freebsd32_getdirentries_args *uap) +{ + long base; + int32_t base32; + int error; + + error = kern_getdirentries(td, uap->fd, uap->buf, uap->count, &base, + NULL, UIO_USERSPACE); + if (error) + return (error); + if (uap->basep != NULL) { + base32 = base; + error = copyout(&base32, uap->basep, sizeof(int32_t)); + } + return (error); +} + +#ifdef COMPAT_FREEBSD6 +/* versions with the 'int pad' argument */ +int +freebsd6_freebsd32_pread(struct thread *td, struct freebsd6_freebsd32_pread_args *uap) +{ + struct pread_args ap; + + ap.fd = uap->fd; + ap.buf = uap->buf; + ap.nbyte = uap->nbyte; + ap.offset = PAIR32TO64(off_t,uap->offset); + return (sys_pread(td, &ap)); +} + +int +freebsd6_freebsd32_pwrite(struct thread *td, struct freebsd6_freebsd32_pwrite_args *uap) +{ + struct pwrite_args ap; + + ap.fd = uap->fd; + ap.buf = uap->buf; + ap.nbyte = uap->nbyte; + ap.offset = PAIR32TO64(off_t,uap->offset); + return (sys_pwrite(td, &ap)); +} + +int +freebsd6_freebsd32_lseek(struct thread *td, struct freebsd6_freebsd32_lseek_args *uap) +{ + int error; + struct lseek_args ap; + off_t pos; + + ap.fd = uap->fd; + ap.offset = PAIR32TO64(off_t,uap->offset); + ap.whence = uap->whence; + error = sys_lseek(td, &ap); + /* 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) +{ + struct truncate_args ap; + + ap.path = uap->path; + ap.length = PAIR32TO64(off_t,uap->length); + return (sys_truncate(td, &ap)); +} + +int +freebsd6_freebsd32_ftruncate(struct thread *td, struct freebsd6_freebsd32_ftruncate_args *uap) +{ + struct ftruncate_args ap; + + ap.fd = uap->fd; + ap.length = PAIR32TO64(off_t,uap->length); + return (sys_ftruncate(td, &ap)); +} +#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 sendfile_args ap; + struct sf_hdtr32 hdtr32; + struct sf_hdtr hdtr; + struct uio *hdr_uio, *trl_uio; + struct iovec32 *iov32; + int error; + + hdr_uio = trl_uio = NULL; + + ap.fd = uap->fd; + ap.s = uap->s; + ap.offset = PAIR32TO64(off_t,uap->offset); + ap.nbytes = uap->nbytes; + ap.hdtr = (struct sf_hdtr *)uap->hdtr; /* XXX not used */ + ap.sbytes = uap->sbytes; + ap.flags = uap->flags; + + 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; + } + if (hdtr.trailers != NULL) { + iov32 = PTRIN(hdtr32.trailers); + error = freebsd32_copyinuio(iov32, + hdtr32.trl_cnt, &trl_uio); + if (error) + goto out; + } + } + + error = kern_sendfile(td, &ap, hdr_uio, trl_uio, compat); +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); +} + +#ifdef COMPAT_43 +static void +copy_ostat(struct stat *in, struct ostat32 *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); + CP(*in, *out, st_size); + 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 + +int +freebsd32_stat(struct thread *td, struct freebsd32_stat_args *uap) +{ + struct stat sb; + struct stat32 sb32; + int error; + + error = kern_stat(td, uap->path, UIO_USERSPACE, &sb); + if (error) + return (error); + copy_stat(&sb, &sb32); + error = copyout(&sb32, uap->ub, sizeof (sb32)); + return (error); +} + +#ifdef COMPAT_43 +int +ofreebsd32_stat(struct thread *td, struct ofreebsd32_stat_args *uap) +{ + struct stat sb; + struct ostat32 sb32; + int error; + + error = kern_stat(td, uap->path, UIO_USERSPACE, &sb); + 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); + if (error) + return (error); + copy_stat(&ub, &ub32); + error = copyout(&ub32, uap->buf, sizeof(ub32)); + return (error); +} + +int +freebsd32_lstat(struct thread *td, struct freebsd32_lstat_args *uap) +{ + struct stat sb; + struct stat32 sb32; + int error; + + error = kern_lstat(td, uap->path, UIO_USERSPACE, &sb); + if (error) + return (error); + copy_stat(&sb, &sb32); + error = copyout(&sb32, uap->ub, sizeof (sb32)); + 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_lstat(td, uap->path, UIO_USERSPACE, &sb); + if (error) + return (error); + copy_ostat(&sb, &sb32); + error = copyout(&sb32, uap->ub, 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; + + 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) + oldlen = fuword32(uap->oldlenp); + else + oldlen = 0; + error = userland_sysctl(td, name, uap->namelen, + uap->old, &oldlen, 1, + uap->new, uap->newlen, &j, SCTL_MASK32); + if (error && error != ENOMEM) + return (error); + if (uap->oldlenp) + suword32(uap->oldlenp, j); + return (0); +} + +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 = j32_v0.ip_number; + 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) +{ + struct timespec32 rmt32, rqt32; + struct timespec rmt, rqt; + int error; + + error = copyin(uap->rqtp, &rqt32, sizeof(rqt32)); + if (error) + return (error); + + CP(rqt32, rqt, tv_sec); + CP(rqt32, rqt, tv_nsec); + + if (uap->rmtp && + !useracc((caddr_t)uap->rmtp, sizeof(rmt), VM_PROT_WRITE)) + return (EFAULT); + error = kern_nanosleep(td, &rqt, &rmt); + if (error && uap->rmtp) { + int error2; + + CP(rmt, rmt32, tv_sec); + CP(rmt, rmt32, tv_nsec); + + error2 = copyout(&rmt32, uap->rmtp, sizeof(rmt32)); + if (error2) + 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_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(¶m, sizeof(struct thr_param)); + bzero(¶m32, sizeof(struct thr_param32)); + error = copyin(uap->param, ¶m32, 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, ¶m)); +} + +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.sigval_int = src->si_value.sival_int; + dst->si_timerid = src->si_timerid; + dst->si_overrun = src->si_overrun; +} + +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) +{ + struct cpuset_setid_args ap; + + ap.which = uap->which; + ap.id = PAIR32TO64(id_t,uap->id); + ap.setid = uap->setid; + + return (sys_cpuset_setid(td, &ap)); +} + +int +freebsd32_cpuset_getid(struct thread *td, + struct freebsd32_cpuset_getid_args *uap) +{ + struct cpuset_getid_args ap; + + ap.level = uap->level; + ap.which = uap->which; + ap.id = PAIR32TO64(id_t,uap->id); + ap.setid = uap->setid; + + return (sys_cpuset_getid(td, &ap)); +} + +int +freebsd32_cpuset_getaffinity(struct thread *td, + struct freebsd32_cpuset_getaffinity_args *uap) +{ + struct cpuset_getaffinity_args ap; + + ap.level = uap->level; + ap.which = uap->which; + ap.id = PAIR32TO64(id_t,uap->id); + ap.cpusetsize = uap->cpusetsize; + ap.mask = uap->mask; + + return (sys_cpuset_getaffinity(td, &ap)); +} + +int +freebsd32_cpuset_setaffinity(struct thread *td, + struct freebsd32_cpuset_setaffinity_args *uap) +{ + struct cpuset_setaffinity_args ap; + + ap.level = uap->level; + ap.which = uap->which; + ap.id = PAIR32TO64(id_t,uap->id); + ap.cpusetsize = uap->cpusetsize; + ap.mask = uap->mask; + + return (sys_cpuset_setaffinity(td, &ap)); +} + +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_register(int *offset, struct sysent *new_sysent, + struct sysent *old_sysent) +{ + if (*offset == NO_SYSCALL) { + int i; + + for (i = 1; i < SYS_MAXSYSCALL; ++i) + if (freebsd32_sysent[i].sy_call == + (sy_call_t *)lkmnosys) + break; + if (i == SYS_MAXSYSCALL) + return (ENFILE); + *offset = i; + } else if (*offset < 0 || *offset >= SYS_MAXSYSCALL) + return (EINVAL); + else if (freebsd32_sysent[*offset].sy_call != (sy_call_t *)lkmnosys && + freebsd32_sysent[*offset].sy_call != (sy_call_t *)lkmressys) + return (EEXIST); + + *old_sysent = freebsd32_sysent[*offset]; + freebsd32_sysent[*offset] = *new_sysent; + return 0; +} + +int +syscall32_deregister(int *offset, struct sysent *old_sysent) +{ + + if (*offset) + freebsd32_sysent[*offset] = *old_sysent; + return 0; +} + +int +syscall32_module_handler(struct module *mod, int what, void *arg) +{ + struct syscall_module_data *data = (struct syscall_module_data*)arg; + modspecific_t ms; + int error; + + switch (what) { + case MOD_LOAD: + error = syscall32_register(data->offset, data->new_sysent, + &data->old_sysent); + if (error) { + /* Leave a mark so we know to safely unload below. */ + data->offset = NULL; + return error; + } + ms.intval = *data->offset; + MOD_XLOCK; + module_setspecific(mod, &ms); + MOD_XUNLOCK; + if (data->chainevh) + error = data->chainevh(mod, what, data->chainarg); + return (error); + case MOD_UNLOAD: + /* + * MOD_LOAD failed, so just return without calling the + * chained handler since we didn't pass along the MOD_LOAD + * event. + */ + if (data->offset == NULL) + return (0); + if (data->chainevh) { + error = data->chainevh(mod, what, data->chainarg); + if (error) + return (error); + } + error = syscall32_deregister(data->offset, &data->old_sysent); + return (error); + default: + error = EOPNOTSUPP; + if (data->chainevh) + error = data->chainevh(mod, what, data->chainarg); + return (error); + } +} + +int +syscall32_helper_register(struct syscall_helper_data *sd) +{ + struct syscall_helper_data *sd1; + int error; + + for (sd1 = sd; sd1->syscall_no != NO_SYSCALL; sd1++) { + error = syscall32_register(&sd1->syscall_no, &sd1->new_sysent, + &sd1->old_sysent); + if (error != 0) { + syscall32_helper_unregister(sd); + return (error); + } + sd1->registered = 1; + } + return (0); +} + +int +syscall32_helper_unregister(struct syscall_helper_data *sd) +{ + struct syscall_helper_data *sd1; + + for (sd1 = sd; sd1->registered != 0; sd1++) { + syscall32_deregister(&sd1->syscall_no, &sd1->old_sysent); + sd1->registered = 0; + } + return (0); +} + +register_t * +freebsd32_copyout_strings(struct image_params *imgp) +{ + int argc, envc, i; + u_int32_t *vectp; + char *stringp, *destp; + u_int32_t *stack_base; + struct freebsd32_ps_strings *arginfo; + char canary[sizeof(long) * 8]; + int32_t pagesizes32[MAXPAGESIZES]; + size_t execpath_len; + int 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; + if (imgp->proc->p_sysent->sv_sigcode_base == 0) + szsigcode = *(imgp->proc->p_sysent->sv_szsigcode); + else + szsigcode = 0; + destp = (caddr_t)arginfo - szsigcode - SPARE_USRSPACE - + roundup(execpath_len, sizeof(char *)) - + roundup(sizeof(canary), sizeof(char *)) - + roundup(sizeof(pagesizes32), sizeof(char *)) - + roundup((ARG_MAX - imgp->args->stringspace), sizeof(char *)); + + /* + * install sigcode + */ + if (szsigcode != 0) + copyout(imgp->proc->p_sysent->sv_sigcode, + ((caddr_t)arginfo - szsigcode), szsigcode); + + /* + * Copy the image path for the rtld. + */ + if (execpath_len != 0) { + imgp->execpathp = (uintptr_t)arginfo - szsigcode - execpath_len; + copyout(imgp->execpath, (void *)imgp->execpathp, + execpath_len); + } + + /* + * Prepare the canary for SSP. + */ + arc4rand(canary, sizeof(canary), 0); + imgp->canary = (uintptr_t)arginfo - szsigcode - execpath_len - + sizeof(canary); + copyout(canary, (void *)imgp->canary, sizeof(canary)); + imgp->canarylen = sizeof(canary); + + /* + * Prepare the pagesizes array. + */ + for (i = 0; i < MAXPAGESIZES; i++) + pagesizes32[i] = (uint32_t)pagesizes[i]; + imgp->pagesizes = (uintptr_t)arginfo - szsigcode - execpath_len - + roundup(sizeof(canary), sizeof(char *)) - sizeof(pagesizes32); + copyout(pagesizes32, (void *)imgp->pagesizes, sizeof(pagesizes32)); + imgp->pagesizeslen = sizeof(pagesizes32); + + /* + * If we have a valid auxargs ptr, prepare some room + * on the stack. + */ + if (imgp->auxargs) { + /* + * 'AT_COUNT*2' is size for the ELF Auxargs data. This is for + * lower compatibility. + */ + imgp->auxarg_size = (imgp->auxarg_size) ? imgp->auxarg_size + : (AT_COUNT * 2); + /* + * The '+ 2' is for the null pointers at the end of each of + * the arg and env vector sets,and imgp->auxarg_size is room + * for argument of Runtime loader. + */ + vectp = (u_int32_t *) (destp - (imgp->args->argc + + imgp->args->envc + 2 + imgp->auxarg_size + execpath_len) * + sizeof(u_int32_t)); + } else + /* + * The '+ 2' is for the null pointers at the end of each of + * the arg and env vector sets + */ + vectp = (u_int32_t *) + (destp - (imgp->args->argc + imgp->args->envc + 2) * sizeof(u_int32_t)); + + /* + * vectp also becomes our initial stack base + */ + stack_base = vectp; + + stringp = imgp->args->begin_argv; + argc = imgp->args->argc; + envc = imgp->args->envc; + /* + * Copy out strings - arguments and environment. + */ + copyout(stringp, destp, ARG_MAX - imgp->args->stringspace); + + /* + * Fill in "ps_strings" struct for ps, w, etc. + */ + suword32(&arginfo->ps_argvstr, (u_int32_t)(intptr_t)vectp); + suword32(&arginfo->ps_nargvstr, argc); + + /* + * Fill in argument portion of vector table. + */ + for (; argc > 0; --argc) { + suword32(vectp++, (u_int32_t)(intptr_t)destp); + while (*stringp++ != 0) + destp++; + destp++; + } + + /* a null vector table pointer separates the argp's from the envp's */ + suword32(vectp++, 0); + + suword32(&arginfo->ps_envstr, (u_int32_t)(intptr_t)vectp); + suword32(&arginfo->ps_nenvstr, envc); + + /* + * Fill in environment portion of vector table. + */ + for (; envc > 0; --envc) { + suword32(vectp++, (u_int32_t)(intptr_t)destp); + while (*stringp++ != 0) + destp++; + destp++; + } + + /* end of vector table is a null pointer */ + suword32(vectp, 0); + + return ((register_t *)stack_base); +} + +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); + + error = kern_kldstat(td, uap->fileid, &stat); + if (error != 0) + return (error); + + 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)); + return (copyout(&stat32, uap->stat, version)); +} + +int +freebsd32_posix_fallocate(struct thread *td, + struct freebsd32_posix_fallocate_args *uap) +{ + + return (kern_posix_fallocate(td, uap->fd, + PAIR32TO64(off_t, uap->offset), PAIR32TO64(off_t, uap->len))); +} + +int +freebsd32_posix_fadvise(struct thread *td, + struct freebsd32_posix_fadvise_args *uap) +{ + + return (kern_posix_fadvise(td, uap->fd, PAIR32TO64(off_t, uap->offset), + PAIR32TO64(off_t, uap->len), uap->advice)); +} diff --git a/sys/compat/freebsd32/freebsd32_proto.h b/sys/compat/freebsd32/freebsd32_proto.h new file mode 100644 index 0000000..f1f444c --- /dev/null +++ b/sys/compat/freebsd32/freebsd32_proto.h @@ -0,0 +1,1151 @@ +/* + * System call prototypes. + * + * DO NOT EDIT-- this file is automatically generated. + * $FreeBSD$ + * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 251526 2013-06-08 13:27:57Z glebius + */ + +#ifndef _FREEBSD32_SYSPROTO_H_ +#define _FREEBSD32_SYSPROTO_H_ + +#include <sys/signal.h> +#include <sys/acl.h> +#include <sys/cpuset.h> +#include <sys/_ffcounter.h> +#include <sys/_semaphore.h> +#include <sys/ucontext.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(__powerpc__) || defined(__mips__)) +#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_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_(uint32_t)]; uint32_t buf; char buf_r_[PADR_(uint32_t)]; + 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_(uint32_t)]; uint32_t from; char from_r_[PADR_(uint32_t)]; + char fromlenaddr_l_[PADL_(uint32_t)]; uint32_t fromlenaddr; char fromlenaddr_r_[PADR_(uint32_t)]; +}; +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_(char *)]; char * fname; char fname_r_[PADR_(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_(const void *)]; const void * addr; char addr_r_[PADR_(const 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_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_(char *)]; char * path; char path_r_[PADR_(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_stat_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char ub_l_[PADL_(struct stat32 *)]; struct stat32 * ub; char ub_r_[PADR_(struct stat32 *)]; +}; +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_lstat_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char ub_l_[PADL_(struct stat32 *)]; struct stat32 * ub; char ub_r_[PADR_(struct stat32 *)]; +}; +struct 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 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_(void *)]; void * new; char new_r_[PADR_(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_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_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 sigevent *)]; struct sigevent * sig; char sig_r_[PADR_(struct sigevent *)]; +}; +struct freebsd32_lutimes_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(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_cancel_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char aiocbp_l_[PADL_(struct aiocb32 *)]; struct aiocb32 * aiocbp; char aiocbp_r_[PADR_(struct aiocb32 *)]; +}; +struct freebsd32_aio_error_args { + char aiocbp_l_[PADL_(struct aiocb32 *)]; struct aiocb32 * aiocbp; char aiocbp_r_[PADR_(struct aiocb32 *)]; +}; +struct freebsd32_oaio_read_args { + char aiocbp_l_[PADL_(struct oaiocb32 *)]; struct oaiocb32 * aiocbp; char aiocbp_r_[PADR_(struct oaiocb32 *)]; +}; +struct freebsd32_oaio_write_args { + char aiocbp_l_[PADL_(struct oaiocb32 *)]; struct oaiocb32 * aiocbp; char aiocbp_r_[PADR_(struct oaiocb32 *)]; +}; +struct freebsd32_olio_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 *)]; +}; +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_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_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_umtx_lock_args { + char umtx_l_[PADL_(struct umtx *)]; struct umtx * umtx; char umtx_r_[PADR_(struct umtx *)]; +}; +struct freebsd32_umtx_unlock_args { + char umtx_l_[PADL_(struct umtx *)]; struct umtx * umtx; char umtx_r_[PADR_(struct umtx *)]; +}; +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_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_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_(caddr_t)]; caddr_t addr; char addr_r_[PADR_(caddr_t)]; + 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_(char *)]; char * path; char path_r_[PADR_(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_(caddr_t)]; caddr_t addr; char addr_r_[PADR_(caddr_t)]; + 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_(char *)]; char * path; char path_r_[PADR_(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_fstatat_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char buf_l_[PADL_(struct stat *)]; struct stat * buf; char buf_r_[PADR_(struct stat *)]; + char flag_l_[PADL_(int)]; int flag; char flag_r_[PADR_(int)]; +}; +struct freebsd32_futimesat_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(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_aio_mlock_args { + char aiocbp_l_[PADL_(struct aiocb32 *)]; struct aiocb32 * aiocbp; char aiocbp_r_[PADR_(struct aiocb32 *)]; +}; +#if !defined(PAD64_REQUIRED) && (defined(__powerpc__) || defined(__mips__)) +#define PAD64_REQUIRED +#endif +int freebsd32_wait4(struct thread *, struct freebsd32_wait4_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_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_stat(struct thread *, struct freebsd32_stat_args *); +int freebsd32_fstat(struct thread *, struct freebsd32_fstat_args *); +int freebsd32_lstat(struct thread *, struct freebsd32_lstat_args *); +int freebsd32_getdirentries(struct thread *, struct freebsd32_getdirentries_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_nanosleep(struct thread *, struct freebsd32_nanosleep_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_cancel(struct thread *, struct freebsd32_aio_cancel_args *); +int freebsd32_aio_error(struct thread *, struct freebsd32_aio_error_args *); +int freebsd32_oaio_read(struct thread *, struct freebsd32_oaio_read_args *); +int freebsd32_oaio_write(struct thread *, struct freebsd32_oaio_write_args *); +int freebsd32_olio_listio(struct thread *, struct freebsd32_olio_listio_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_kevent(struct thread *, struct freebsd32_kevent_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_umtx_lock(struct thread *, struct freebsd32_umtx_lock_args *); +int freebsd32_umtx_unlock(struct thread *, struct freebsd32_umtx_unlock_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_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_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_fstatat(struct thread *, struct freebsd32_fstatat_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_aio_mlock(struct thread *, struct freebsd32_aio_mlock_args *); + +#ifdef COMPAT_43 + +#if !defined(PAD64_REQUIRED) && (defined(__powerpc__) || defined(__mips__)) +#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_(char *)]; char * path; char path_r_[PADR_(char *)]; + char ub_l_[PADL_(struct ostat32 *)]; struct ostat32 * ub; char ub_r_[PADR_(struct ostat32 *)]; +}; +struct ofreebsd32_lstat_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(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 +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(__powerpc__) || defined(__mips__)) +#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 flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; +}; +struct freebsd4_freebsd32_statfs_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(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 +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(__powerpc__) || defined(__mips__)) +#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_(caddr_t)]; caddr_t addr; char addr_r_[PADR_(caddr_t)]; + 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_(char *)]; char * path; char path_r_[PADR_(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)]; +}; +#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 *); + +#endif /* COMPAT_FREEBSD6 */ + + +#ifdef COMPAT_FREEBSD7 + +#if !defined(PAD64_REQUIRED) && (defined(__powerpc__) || defined(__mips__)) +#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 +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 */ + +#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_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_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_NULL +#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_select AUE_SELECT +#define FREEBSD32_SYS_AUE_ofreebsd32_sigreturn AUE_NULL +#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_stat AUE_STAT +#define FREEBSD32_SYS_AUE_freebsd32_fstat AUE_FSTAT +#define FREEBSD32_SYS_AUE_freebsd32_lstat AUE_LSTAT +#define FREEBSD32_SYS_AUE_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_nanosleep AUE_NULL +#define FREEBSD32_SYS_AUE_freebsd32_aio_read AUE_NULL +#define FREEBSD32_SYS_AUE_freebsd32_aio_write AUE_NULL +#define FREEBSD32_SYS_AUE_freebsd32_lio_listio AUE_NULL +#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_freebsd32_modstat AUE_NULL +#define FREEBSD32_SYS_AUE_freebsd32_kldstat AUE_NULL +#define FREEBSD32_SYS_AUE_freebsd32_aio_return AUE_NULL +#define FREEBSD32_SYS_AUE_freebsd32_aio_suspend AUE_NULL +#define FREEBSD32_SYS_AUE_freebsd32_aio_cancel AUE_NULL +#define FREEBSD32_SYS_AUE_freebsd32_aio_error AUE_NULL +#define FREEBSD32_SYS_AUE_freebsd32_oaio_read AUE_NULL +#define FREEBSD32_SYS_AUE_freebsd32_oaio_write AUE_NULL +#define FREEBSD32_SYS_AUE_freebsd32_olio_listio 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_NULL +#define FREEBSD32_SYS_AUE_freebsd32_kevent AUE_NULL +#define FREEBSD32_SYS_AUE_freebsd32_nmount AUE_NMOUNT +#define FREEBSD32_SYS_AUE_freebsd32_sendfile AUE_SENDFILE +#define FREEBSD32_SYS_AUE_freebsd32_ksem_init AUE_NULL +#define FREEBSD32_SYS_AUE_freebsd32_ksem_open AUE_NULL +#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_umtx_lock AUE_NULL +#define FREEBSD32_SYS_AUE_freebsd32_umtx_unlock AUE_NULL +#define FREEBSD32_SYS_AUE_freebsd32_ksem_timedwait AUE_NULL +#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_NULL +#define FREEBSD32_SYS_AUE_freebsd32_kmq_open AUE_NULL +#define FREEBSD32_SYS_AUE_freebsd32_kmq_setattr AUE_NULL +#define FREEBSD32_SYS_AUE_freebsd32_kmq_timedreceive AUE_NULL +#define FREEBSD32_SYS_AUE_freebsd32_kmq_timedsend AUE_NULL +#define FREEBSD32_SYS_AUE_freebsd32_aio_fsync AUE_NULL +#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_freebsd32_fstatat AUE_FSTATAT +#define FREEBSD32_SYS_AUE_freebsd32_futimesat AUE_FUTIMESAT +#define FREEBSD32_SYS_AUE_freebsd32_jail_get AUE_NULL +#define FREEBSD32_SYS_AUE_freebsd32_jail_set AUE_NULL +#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_NULL +#define FREEBSD32_SYS_AUE_freebsd32_posix_fadvise AUE_NULL +#define FREEBSD32_SYS_AUE_freebsd32_wait6 AUE_WAIT6 +#define FREEBSD32_SYS_AUE_freebsd32_posix_fallocate AUE_NULL +#define FREEBSD32_SYS_AUE_freebsd32_posix_fadvise AUE_NULL +#define FREEBSD32_SYS_AUE_freebsd32_wait6 AUE_WAIT6 +#define FREEBSD32_SYS_AUE_freebsd32_aio_mlock AUE_NULL + +#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 0000000..d31a8ae --- /dev/null +++ b/sys/compat/freebsd32/freebsd32_signal.h @@ -0,0 +1,102 @@ +/*- + * 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 */ +}; + +union sigval32 { + int sival_int; + u_int32_t sival_ptr; + /* 6.0 compatibility */ + int sigval_int; + u_int32_t sigval_ptr; +}; + +struct siginfo32 { + int si_signo; /* signal number */ + int si_errno; /* errno association */ + int si_code; /* signal code */ + int32_t si_pid; /* sending process */ + u_int32_t si_uid; /* sender's ruid */ + int si_status; /* exit value */ + u_int32_t si_addr; /* faulting instruction */ + union sigval32 si_value; /* signal value */ + union { + struct { + int _trapno;/* machine specific trap code */ + } _fault; + struct { + int _timerid; + int _overrun; + } _timer; + struct { + int _mqd; + } _mesgq; + struct { + int _band; /* band event for SIGPOLL */ + } _poll; /* was this ever used ? */ + struct { + int __spare1__; + int __spare2__[7]; + } __spare__; + } _reason; +}; + +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; +}; + +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 0000000..8c36fee --- /dev/null +++ b/sys/compat/freebsd32/freebsd32_syscall.h @@ -0,0 +1,447 @@ +/* + * System call numbers. + * + * DO NOT EDIT-- this file is automatically generated. + * $FreeBSD$ + * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 251526 2013-06-08 13:27:57Z glebius + */ + +#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_mknod 14 +#define FREEBSD32_SYS_chmod 15 +#define FREEBSD32_SYS_chown 16 +#define FREEBSD32_SYS_break 17 +#define FREEBSD32_SYS_freebsd4_freebsd32_getfsstat 18 + /* 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_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_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_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_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 */ +#define FREEBSD32_SYS_freebsd4_freebsd32_statfs 157 +#define FREEBSD32_SYS_freebsd4_freebsd32_fstatfs 158 +#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 +#define FREEBSD32_SYS_freebsd6_freebsd32_pread 173 +#define FREEBSD32_SYS_freebsd6_freebsd32_pwrite 174 +#define FREEBSD32_SYS_ntp_adjtime 176 +#define FREEBSD32_SYS_setgid 181 +#define FREEBSD32_SYS_setegid 182 +#define FREEBSD32_SYS_seteuid 183 +#define FREEBSD32_SYS_freebsd32_stat 188 +#define FREEBSD32_SYS_freebsd32_fstat 189 +#define FREEBSD32_SYS_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_freebsd32_getdirentries 196 +#define FREEBSD32_SYS_freebsd6_freebsd32_mmap 197 +#define FREEBSD32_SYS___syscall 198 +#define FREEBSD32_SYS_freebsd6_freebsd32_lseek 199 +#define FREEBSD32_SYS_freebsd6_freebsd32_truncate 200 +#define FREEBSD32_SYS_freebsd6_freebsd32_ftruncate 201 +#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 +#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_nanosleep 240 +#define FREEBSD32_SYS_ffclock_getcounter 241 +#define FREEBSD32_SYS_ffclock_setestimate 242 +#define FREEBSD32_SYS_ffclock_getestimate 243 +#define FREEBSD32_SYS_clock_getcpuclockid2 247 +#define FREEBSD32_SYS_minherit 250 +#define FREEBSD32_SYS_rfork 251 +#define FREEBSD32_SYS_openbsd_poll 252 +#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_getdents 272 +#define FREEBSD32_SYS_lchmod 274 +#define FREEBSD32_SYS_netbsd_lchown 275 +#define FREEBSD32_SYS_freebsd32_lutimes 276 +#define FREEBSD32_SYS_netbsd_msync 277 +#define FREEBSD32_SYS_nstat 278 +#define FREEBSD32_SYS_nfstat 279 +#define FREEBSD32_SYS_nlstat 280 +#define FREEBSD32_SYS_freebsd32_preadv 289 +#define FREEBSD32_SYS_freebsd32_pwritev 290 +#define FREEBSD32_SYS_freebsd4_freebsd32_fhstatfs 297 +#define FREEBSD32_SYS_fhopen 298 +#define FREEBSD32_SYS_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_freebsd32_aio_cancel 316 +#define FREEBSD32_SYS_freebsd32_aio_error 317 +#define FREEBSD32_SYS_freebsd32_oaio_read 318 +#define FREEBSD32_SYS_freebsd32_oaio_write 319 +#define FREEBSD32_SYS_freebsd32_olio_listio 320 +#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_sched_rr_get_interval 334 +#define FREEBSD32_SYS_utrace 335 +#define FREEBSD32_SYS_freebsd4_freebsd32_sendfile 336 +#define FREEBSD32_SYS_kldsym 337 +#define FREEBSD32_SYS_freebsd32_jail 338 +#define FREEBSD32_SYS_sigprocmask 340 +#define FREEBSD32_SYS_sigsuspend 341 +#define FREEBSD32_SYS_freebsd4_freebsd32_sigaction 342 +#define FREEBSD32_SYS_sigpending 343 +#define FREEBSD32_SYS_freebsd4_freebsd32_sigreturn 344 +#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_freebsd32_kevent 363 +#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 +#define FREEBSD32_SYS_eaccess 376 +#define FREEBSD32_SYS_freebsd32_nmount 378 +#define FREEBSD32_SYS_kenv 390 +#define FREEBSD32_SYS_lchflags 391 +#define FREEBSD32_SYS_uuidgen 392 +#define FREEBSD32_SYS_freebsd32_sendfile 393 +#define FREEBSD32_SYS_getfsstat 395 +#define FREEBSD32_SYS_statfs 396 +#define FREEBSD32_SYS_fstatfs 397 +#define FREEBSD32_SYS_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_freebsd32_umtx_lock 434 +#define FREEBSD32_SYS_freebsd32_umtx_unlock 435 +#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 +#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_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_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_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_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_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_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 +#define FREEBSD32_SYS_cap_new 514 +#define FREEBSD32_SYS_cap_rights_get 515 +#define FREEBSD32_SYS_cap_enter 516 +#define FREEBSD32_SYS_cap_getmode 517 +#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_cap_ioctls_limit 534 +#define FREEBSD32_SYS_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_MAXSYSCALL 544 diff --git a/sys/compat/freebsd32/freebsd32_syscalls.c b/sys/compat/freebsd32/freebsd32_syscalls.c new file mode 100644 index 0000000..9b643f9 --- /dev/null +++ b/sys/compat/freebsd32/freebsd32_syscalls.c @@ -0,0 +1,576 @@ +/* + * System call names. + * + * DO NOT EDIT-- this file is automatically generated. + * $FreeBSD$ + * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 251526 2013-06-08 13:27:57Z glebius + */ + +const char *freebsd32_syscallnames[] = { +#if !defined(PAD64_REQUIRED) && (defined(__powerpc__) || defined(__mips__)) +#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 */ + "mknod", /* 14 = 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 */ + "ptrace", /* 26 = 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 */ + "pipe", /* 42 = 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 */ + "vadvise", /* 72 = 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 */ + "fcntl", /* 92 = 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 */ + "ntp_adjtime", /* 176 = ntp_adjtime */ + "#177", /* 177 = sfork */ + "#178", /* 178 = getdescriptor */ + "#179", /* 179 = setdescriptor */ + "#180", /* 180 = nosys */ + "setgid", /* 181 = setgid */ + "setegid", /* 182 = setegid */ + "seteuid", /* 183 = seteuid */ + "#184", /* 184 = lfs_bmapv */ + "#185", /* 185 = lfs_markv */ + "#186", /* 186 = lfs_segclean */ + "#187", /* 187 = lfs_segwait */ + "freebsd32_stat", /* 188 = freebsd32_stat */ + "freebsd32_fstat", /* 189 = freebsd32_fstat */ + "freebsd32_lstat", /* 190 = freebsd32_lstat */ + "pathconf", /* 191 = pathconf */ + "fpathconf", /* 192 = fpathconf */ + "#193", /* 193 = nosys */ + "getrlimit", /* 194 = getrlimit */ + "setrlimit", /* 195 = setrlimit */ + "freebsd32_getdirentries", /* 196 = 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 = newreboot */ + "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 */ + "#223", /* 223 = 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 */ + "#235", /* 235 = timer_create */ + "#236", /* 236 = timer_delete */ + "#237", /* 237 = timer_settime */ + "#238", /* 238 = timer_gettime */ + "#239", /* 239 = timer_getoverrun */ + "freebsd32_nanosleep", /* 240 = freebsd32_nanosleep */ + "ffclock_getcounter", /* 241 = ffclock_getcounter */ + "ffclock_setestimate", /* 242 = ffclock_setestimate */ + "ffclock_getestimate", /* 243 = ffclock_getestimate */ + "#244", /* 244 = nosys */ + "#245", /* 245 = nosys */ + "#246", /* 246 = nosys */ + "clock_getcpuclockid2", /* 247 = clock_getcpuclockid2 */ + "#248", /* 248 = ntp_gettime */ + "#249", /* 249 = nosys */ + "minherit", /* 250 = minherit */ + "rfork", /* 251 = rfork */ + "openbsd_poll", /* 252 = 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 */ + "getdents", /* 272 = getdents */ + "#273", /* 273 = nosys */ + "lchmod", /* 274 = lchmod */ + "netbsd_lchown", /* 275 = netbsd_lchown */ + "freebsd32_lutimes", /* 276 = freebsd32_lutimes */ + "netbsd_msync", /* 277 = netbsd_msync */ + "nstat", /* 278 = nstat */ + "nfstat", /* 279 = nfstat */ + "nlstat", /* 280 = 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 */ + "fhstat", /* 299 = 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 */ + "freebsd32_aio_cancel", /* 316 = freebsd32_aio_cancel */ + "freebsd32_aio_error", /* 317 = freebsd32_aio_error */ + "freebsd32_oaio_read", /* 318 = freebsd32_oaio_read */ + "freebsd32_oaio_write", /* 319 = freebsd32_oaio_write */ + "freebsd32_olio_listio", /* 320 = freebsd32_olio_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 */ + "sched_rr_get_interval", /* 334 = 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 */ + "freebsd32_kevent", /* 363 = freebsd32_kevent */ + "#364", /* 364 = __cap_get_proc */ + "#365", /* 365 = __cap_set_proc */ + "#366", /* 366 = __cap_get_fd */ + "#367", /* 367 = __cap_get_file */ + "#368", /* 368 = __cap_set_fd */ + "#369", /* 369 = __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 */ + "#375", /* 375 = nfsclnt */ + "eaccess", /* 376 = eaccess */ + "#377", /* 377 = afs_syscall */ + "freebsd32_nmount", /* 378 = freebsd32_nmount */ + "#379", /* 379 = kse_exit */ + "#380", /* 380 = kse_wakeup */ + "#381", /* 381 = kse_create */ + "#382", /* 382 = kse_thr_interrupt */ + "#383", /* 383 = 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 */ + "getfsstat", /* 395 = getfsstat */ + "statfs", /* 396 = statfs */ + "fstatfs", /* 397 = fstatfs */ + "fhstatfs", /* 398 = 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 */ + "freebsd32_umtx_lock", /* 434 = freebsd32_umtx_lock */ + "freebsd32_umtx_unlock", /* 435 = freebsd32_umtx_unlock */ + "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 */ + "#440", /* 440 = 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 */ + "sigqueue", /* 456 = 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 */ + "kmq_notify", /* 461 = 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 */ + "shm_open", /* 482 = 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 */ + "freebsd32_fstatat", /* 493 = freebsd32_fstatat */ + "freebsd32_futimesat", /* 494 = freebsd32_futimesat */ + "linkat", /* 495 = linkat */ + "mkdirat", /* 496 = mkdirat */ + "mkfifoat", /* 497 = mkfifoat */ + "mknodat", /* 498 = 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 */ + "closefrom", /* 509 = closefrom */ + "freebsd32_semctl", /* 510 = freebsd32_semctl */ + "freebsd32_msgctl", /* 511 = freebsd32_msgctl */ + "freebsd32_shmctl", /* 512 = freebsd32_shmctl */ + "lpathconf", /* 513 = lpathconf */ + "cap_new", /* 514 = cap_new */ + "cap_rights_get", /* 515 = cap_rights_get */ + "cap_enter", /* 516 = cap_enter */ + "cap_getmode", /* 517 = cap_getmode */ + "#518", /* 518 = pdfork */ + "#519", /* 519 = pdkill */ + "#520", /* 520 = pdgetpid */ + "#521", /* 521 = pdwait */ + "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 */ + "cap_ioctls_limit", /* 534 = cap_ioctls_limit */ + "cap_ioctls_get", /* 535 = 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 */ +}; diff --git a/sys/compat/freebsd32/freebsd32_sysent.c b/sys/compat/freebsd32/freebsd32_sysent.c new file mode 100644 index 0000000..d37e8e9 --- /dev/null +++ b/sys/compat/freebsd32/freebsd32_sysent.c @@ -0,0 +1,613 @@ +/* + * System call switch table. + * + * DO NOT EDIT-- this file is automatically generated. + * $FreeBSD$ + * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 251526 2013-06-08 13:27:57Z glebius + */ + +#include "opt_compat.h" + +#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) n, (sy_call_t *)__CONCAT(o,name) +#else +#define compat(n, name) 0, (sy_call_t *)nosys +#endif + +#ifdef COMPAT_FREEBSD4 +#define compat4(n, name) n, (sy_call_t *)__CONCAT(freebsd4_,name) +#else +#define compat4(n, name) 0, (sy_call_t *)nosys +#endif + +#ifdef COMPAT_FREEBSD6 +#define compat6(n, name) n, (sy_call_t *)__CONCAT(freebsd6_,name) +#else +#define compat6(n, name) 0, (sy_call_t *)nosys +#endif + +#ifdef COMPAT_FREEBSD7 +#define compat7(n, name) n, (sy_call_t *)__CONCAT(freebsd7_,name) +#else +#define compat7(n, name) 0, (sy_call_t *)nosys +#endif + +/* The casts are bogus but will do for now. */ +struct sysent freebsd32_sysent[] = { +#if !defined(PAD64_REQUIRED) && (defined(__powerpc__) || defined(__mips__)) +#define PAD64_REQUIRED +#endif + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 0 = syscall */ + { AS(sys_exit_args), (sy_call_t *)sys_sys_exit, AUE_EXIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 1 = exit */ + { 0, (sy_call_t *)sys_fork, AUE_FORK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 2 = fork */ + { AS(read_args), (sy_call_t *)sys_read, AUE_READ, NULL, 0, 0, 0, SY_THR_STATIC }, /* 3 = read */ + { AS(write_args), (sy_call_t *)sys_write, AUE_WRITE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 4 = write */ + { AS(open_args), (sy_call_t *)sys_open, AUE_OPEN_RWTC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 5 = open */ + { AS(close_args), (sy_call_t *)sys_close, AUE_CLOSE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 6 = close */ + { AS(freebsd32_wait4_args), (sy_call_t *)freebsd32_wait4, AUE_WAIT4, NULL, 0, 0, 0, SY_THR_STATIC }, /* 7 = freebsd32_wait4 */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 8 = obsolete old creat */ + { AS(link_args), (sy_call_t *)sys_link, AUE_LINK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 9 = link */ + { AS(unlink_args), (sy_call_t *)sys_unlink, AUE_UNLINK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 10 = unlink */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 11 = obsolete execv */ + { AS(chdir_args), (sy_call_t *)sys_chdir, AUE_CHDIR, NULL, 0, 0, 0, SY_THR_STATIC }, /* 12 = chdir */ + { AS(fchdir_args), (sy_call_t *)sys_fchdir, AUE_FCHDIR, NULL, 0, 0, 0, SY_THR_STATIC }, /* 13 = fchdir */ + { AS(mknod_args), (sy_call_t *)sys_mknod, AUE_MKNOD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 14 = mknod */ + { AS(chmod_args), (sy_call_t *)sys_chmod, AUE_CHMOD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 15 = chmod */ + { AS(chown_args), (sy_call_t *)sys_chown, AUE_CHOWN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 16 = chown */ + { AS(obreak_args), (sy_call_t *)sys_obreak, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 17 = break */ + { compat4(AS(freebsd4_freebsd32_getfsstat_args),freebsd32_getfsstat), AUE_GETFSSTAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 18 = freebsd4 freebsd32_getfsstat */ + { compat(AS(ofreebsd32_lseek_args),freebsd32_lseek), AUE_LSEEK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 19 = old freebsd32_lseek */ + { 0, (sy_call_t *)sys_getpid, AUE_GETPID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 20 = getpid */ + { AS(mount_args), (sy_call_t *)sys_mount, AUE_MOUNT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 21 = mount */ + { AS(unmount_args), (sy_call_t *)sys_unmount, AUE_UMOUNT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 22 = unmount */ + { AS(setuid_args), (sy_call_t *)sys_setuid, AUE_SETUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 23 = setuid */ + { 0, (sy_call_t *)sys_getuid, AUE_GETUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 24 = getuid */ + { 0, (sy_call_t *)sys_geteuid, AUE_GETEUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 25 = geteuid */ + { AS(ptrace_args), (sy_call_t *)sys_ptrace, AUE_PTRACE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 26 = ptrace */ + { AS(freebsd32_recvmsg_args), (sy_call_t *)freebsd32_recvmsg, AUE_RECVMSG, NULL, 0, 0, 0, SY_THR_STATIC }, /* 27 = freebsd32_recvmsg */ + { AS(freebsd32_sendmsg_args), (sy_call_t *)freebsd32_sendmsg, AUE_SENDMSG, NULL, 0, 0, 0, SY_THR_STATIC }, /* 28 = freebsd32_sendmsg */ + { AS(freebsd32_recvfrom_args), (sy_call_t *)freebsd32_recvfrom, AUE_RECVFROM, NULL, 0, 0, 0, SY_THR_STATIC }, /* 29 = freebsd32_recvfrom */ + { AS(accept_args), (sy_call_t *)sys_accept, AUE_ACCEPT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 30 = accept */ + { AS(getpeername_args), (sy_call_t *)sys_getpeername, AUE_GETPEERNAME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 31 = getpeername */ + { AS(getsockname_args), (sy_call_t *)sys_getsockname, AUE_GETSOCKNAME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 32 = getsockname */ + { AS(access_args), (sy_call_t *)sys_access, AUE_ACCESS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 33 = access */ + { AS(chflags_args), (sy_call_t *)sys_chflags, AUE_CHFLAGS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 34 = chflags */ + { AS(fchflags_args), (sy_call_t *)sys_fchflags, AUE_FCHFLAGS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 35 = fchflags */ + { 0, (sy_call_t *)sys_sync, AUE_SYNC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 36 = sync */ + { AS(kill_args), (sy_call_t *)sys_kill, AUE_KILL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 37 = kill */ + { compat(AS(ofreebsd32_stat_args),freebsd32_stat), AUE_STAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 38 = old freebsd32_stat */ + { 0, (sy_call_t *)sys_getppid, AUE_GETPPID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 39 = getppid */ + { compat(AS(ofreebsd32_lstat_args),freebsd32_lstat), AUE_LSTAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 40 = old freebsd32_lstat */ + { AS(dup_args), (sy_call_t *)sys_dup, AUE_DUP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 41 = dup */ + { 0, (sy_call_t *)sys_pipe, AUE_PIPE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 42 = pipe */ + { 0, (sy_call_t *)sys_getegid, AUE_GETEGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 43 = getegid */ + { AS(profil_args), (sy_call_t *)sys_profil, AUE_PROFILE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 44 = profil */ + { AS(ktrace_args), (sy_call_t *)sys_ktrace, AUE_KTRACE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 45 = ktrace */ + { compat(AS(ofreebsd32_sigaction_args),freebsd32_sigaction), AUE_SIGACTION, NULL, 0, 0, 0, SY_THR_STATIC }, /* 46 = old freebsd32_sigaction */ + { 0, (sy_call_t *)sys_getgid, AUE_GETGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 47 = getgid */ + { compat(AS(ofreebsd32_sigprocmask_args),freebsd32_sigprocmask), AUE_SIGPROCMASK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 48 = old freebsd32_sigprocmask */ + { AS(getlogin_args), (sy_call_t *)sys_getlogin, AUE_GETLOGIN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 49 = getlogin */ + { AS(setlogin_args), (sy_call_t *)sys_setlogin, AUE_SETLOGIN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 50 = setlogin */ + { AS(acct_args), (sy_call_t *)sys_acct, AUE_ACCT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 51 = acct */ + { compat(0,freebsd32_sigpending), AUE_SIGPENDING, NULL, 0, 0, 0, SY_THR_STATIC }, /* 52 = old freebsd32_sigpending */ + { AS(freebsd32_sigaltstack_args), (sy_call_t *)freebsd32_sigaltstack, AUE_SIGALTSTACK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 53 = freebsd32_sigaltstack */ + { AS(freebsd32_ioctl_args), (sy_call_t *)freebsd32_ioctl, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 54 = freebsd32_ioctl */ + { AS(reboot_args), (sy_call_t *)sys_reboot, AUE_REBOOT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 55 = reboot */ + { AS(revoke_args), (sy_call_t *)sys_revoke, AUE_REVOKE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 56 = revoke */ + { AS(symlink_args), (sy_call_t *)sys_symlink, AUE_SYMLINK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 57 = symlink */ + { AS(readlink_args), (sy_call_t *)sys_readlink, AUE_READLINK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 58 = readlink */ + { AS(freebsd32_execve_args), (sy_call_t *)freebsd32_execve, AUE_EXECVE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 59 = freebsd32_execve */ + { AS(umask_args), (sy_call_t *)sys_umask, AUE_UMASK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 60 = umask */ + { AS(chroot_args), (sy_call_t *)sys_chroot, AUE_CHROOT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 61 = chroot */ + { compat(AS(ofreebsd32_fstat_args),freebsd32_fstat), AUE_FSTAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 62 = old freebsd32_fstat */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 63 = obsolete ogetkerninfo */ + { compat(AS(ofreebsd32_getpagesize_args),freebsd32_getpagesize), AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 64 = old freebsd32_getpagesize */ + { AS(msync_args), (sy_call_t *)sys_msync, AUE_MSYNC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 65 = msync */ + { 0, (sy_call_t *)sys_vfork, AUE_VFORK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 66 = vfork */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 67 = obsolete vread */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 68 = obsolete vwrite */ + { AS(sbrk_args), (sy_call_t *)sys_sbrk, AUE_SBRK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 69 = sbrk */ + { AS(sstk_args), (sy_call_t *)sys_sstk, AUE_SSTK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 70 = sstk */ + { compat(AS(ommap_args),mmap), AUE_MMAP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 71 = old mmap */ + { AS(ovadvise_args), (sy_call_t *)sys_ovadvise, AUE_O_VADVISE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 72 = vadvise */ + { AS(munmap_args), (sy_call_t *)sys_munmap, AUE_MUNMAP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 73 = munmap */ + { AS(freebsd32_mprotect_args), (sy_call_t *)freebsd32_mprotect, AUE_MPROTECT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 74 = freebsd32_mprotect */ + { AS(madvise_args), (sy_call_t *)sys_madvise, AUE_MADVISE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 75 = madvise */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 76 = obsolete vhangup */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 77 = obsolete vlimit */ + { AS(mincore_args), (sy_call_t *)sys_mincore, AUE_MINCORE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 78 = mincore */ + { AS(getgroups_args), (sy_call_t *)sys_getgroups, AUE_GETGROUPS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 79 = getgroups */ + { AS(setgroups_args), (sy_call_t *)sys_setgroups, AUE_SETGROUPS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 80 = setgroups */ + { 0, (sy_call_t *)sys_getpgrp, AUE_GETPGRP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 81 = getpgrp */ + { AS(setpgid_args), (sy_call_t *)sys_setpgid, AUE_SETPGRP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 82 = setpgid */ + { AS(freebsd32_setitimer_args), (sy_call_t *)freebsd32_setitimer, AUE_SETITIMER, NULL, 0, 0, 0, SY_THR_STATIC }, /* 83 = freebsd32_setitimer */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 84 = obsolete owait */ + { AS(swapon_args), (sy_call_t *)sys_swapon, AUE_SWAPON, NULL, 0, 0, 0, SY_THR_STATIC }, /* 85 = swapon */ + { AS(freebsd32_getitimer_args), (sy_call_t *)freebsd32_getitimer, AUE_GETITIMER, NULL, 0, 0, 0, SY_THR_STATIC }, /* 86 = freebsd32_getitimer */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 87 = obsolete ogethostname */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 88 = obsolete osethostname */ + { 0, (sy_call_t *)sys_getdtablesize, AUE_GETDTABLESIZE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 89 = getdtablesize */ + { AS(dup2_args), (sy_call_t *)sys_dup2, AUE_DUP2, NULL, 0, 0, 0, SY_THR_STATIC }, /* 90 = dup2 */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 91 = getdopt */ + { AS(fcntl_args), (sy_call_t *)sys_fcntl, AUE_FCNTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 92 = fcntl */ + { AS(freebsd32_select_args), (sy_call_t *)freebsd32_select, AUE_SELECT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 93 = freebsd32_select */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 94 = setdopt */ + { AS(fsync_args), (sy_call_t *)sys_fsync, AUE_FSYNC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 95 = fsync */ + { AS(setpriority_args), (sy_call_t *)sys_setpriority, AUE_SETPRIORITY, NULL, 0, 0, 0, SY_THR_STATIC }, /* 96 = setpriority */ + { AS(socket_args), (sy_call_t *)sys_socket, AUE_SOCKET, NULL, 0, 0, 0, SY_THR_STATIC }, /* 97 = socket */ + { AS(connect_args), (sy_call_t *)sys_connect, AUE_CONNECT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 98 = connect */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 99 = obsolete oaccept */ + { AS(getpriority_args), (sy_call_t *)sys_getpriority, AUE_GETPRIORITY, NULL, 0, 0, 0, SY_THR_STATIC }, /* 100 = getpriority */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 101 = obsolete osend */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 102 = obsolete orecv */ + { compat(AS(ofreebsd32_sigreturn_args),freebsd32_sigreturn), AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 103 = old freebsd32_sigreturn */ + { AS(bind_args), (sy_call_t *)sys_bind, AUE_BIND, NULL, 0, 0, 0, SY_THR_STATIC }, /* 104 = bind */ + { AS(setsockopt_args), (sy_call_t *)sys_setsockopt, AUE_SETSOCKOPT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 105 = setsockopt */ + { AS(listen_args), (sy_call_t *)sys_listen, AUE_LISTEN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 106 = listen */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 107 = obsolete vtimes */ + { compat(AS(ofreebsd32_sigvec_args),freebsd32_sigvec), AUE_O_SIGVEC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 108 = old freebsd32_sigvec */ + { compat(AS(ofreebsd32_sigblock_args),freebsd32_sigblock), AUE_O_SIGBLOCK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 109 = old freebsd32_sigblock */ + { compat(AS(ofreebsd32_sigsetmask_args),freebsd32_sigsetmask), AUE_O_SIGSETMASK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 110 = old freebsd32_sigsetmask */ + { compat(AS(ofreebsd32_sigsuspend_args),freebsd32_sigsuspend), AUE_SIGSUSPEND, NULL, 0, 0, 0, SY_THR_STATIC }, /* 111 = old freebsd32_sigsuspend */ + { compat(AS(ofreebsd32_sigstack_args),freebsd32_sigstack), AUE_O_SIGSTACK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 112 = old freebsd32_sigstack */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 113 = obsolete orecvmsg */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 114 = obsolete osendmsg */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 115 = obsolete vtrace */ + { AS(freebsd32_gettimeofday_args), (sy_call_t *)freebsd32_gettimeofday, AUE_GETTIMEOFDAY, NULL, 0, 0, 0, SY_THR_STATIC }, /* 116 = freebsd32_gettimeofday */ + { AS(freebsd32_getrusage_args), (sy_call_t *)freebsd32_getrusage, AUE_GETRUSAGE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 117 = freebsd32_getrusage */ + { AS(getsockopt_args), (sy_call_t *)sys_getsockopt, AUE_GETSOCKOPT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 118 = getsockopt */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 119 = resuba */ + { AS(freebsd32_readv_args), (sy_call_t *)freebsd32_readv, AUE_READV, NULL, 0, 0, 0, SY_THR_STATIC }, /* 120 = freebsd32_readv */ + { AS(freebsd32_writev_args), (sy_call_t *)freebsd32_writev, AUE_WRITEV, NULL, 0, 0, 0, SY_THR_STATIC }, /* 121 = freebsd32_writev */ + { AS(freebsd32_settimeofday_args), (sy_call_t *)freebsd32_settimeofday, AUE_SETTIMEOFDAY, NULL, 0, 0, 0, SY_THR_STATIC }, /* 122 = freebsd32_settimeofday */ + { AS(fchown_args), (sy_call_t *)sys_fchown, AUE_FCHOWN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 123 = fchown */ + { AS(fchmod_args), (sy_call_t *)sys_fchmod, AUE_FCHMOD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 124 = fchmod */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 125 = obsolete orecvfrom */ + { AS(setreuid_args), (sy_call_t *)sys_setreuid, AUE_SETREUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 126 = setreuid */ + { AS(setregid_args), (sy_call_t *)sys_setregid, AUE_SETREGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 127 = setregid */ + { AS(rename_args), (sy_call_t *)sys_rename, AUE_RENAME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 128 = rename */ + { compat(AS(otruncate_args),truncate), AUE_TRUNCATE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 129 = old truncate */ + { compat(AS(oftruncate_args),ftruncate), AUE_FTRUNCATE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 130 = old ftruncate */ + { AS(flock_args), (sy_call_t *)sys_flock, AUE_FLOCK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 131 = flock */ + { AS(mkfifo_args), (sy_call_t *)sys_mkfifo, AUE_MKFIFO, NULL, 0, 0, 0, SY_THR_STATIC }, /* 132 = mkfifo */ + { AS(sendto_args), (sy_call_t *)sys_sendto, AUE_SENDTO, NULL, 0, 0, 0, SY_THR_STATIC }, /* 133 = sendto */ + { AS(shutdown_args), (sy_call_t *)sys_shutdown, AUE_SHUTDOWN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 134 = shutdown */ + { AS(socketpair_args), (sy_call_t *)sys_socketpair, AUE_SOCKETPAIR, NULL, 0, 0, 0, SY_THR_STATIC }, /* 135 = socketpair */ + { AS(mkdir_args), (sy_call_t *)sys_mkdir, AUE_MKDIR, NULL, 0, 0, 0, SY_THR_STATIC }, /* 136 = mkdir */ + { AS(rmdir_args), (sy_call_t *)sys_rmdir, AUE_RMDIR, NULL, 0, 0, 0, SY_THR_STATIC }, /* 137 = rmdir */ + { AS(freebsd32_utimes_args), (sy_call_t *)freebsd32_utimes, AUE_UTIMES, NULL, 0, 0, 0, SY_THR_STATIC }, /* 138 = freebsd32_utimes */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 139 = obsolete 4.2 sigreturn */ + { AS(freebsd32_adjtime_args), (sy_call_t *)freebsd32_adjtime, AUE_ADJTIME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 140 = freebsd32_adjtime */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 141 = obsolete ogetpeername */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 142 = obsolete ogethostid */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 143 = obsolete sethostid */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 144 = obsolete getrlimit */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 145 = obsolete setrlimit */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 146 = obsolete killpg */ + { 0, (sy_call_t *)sys_setsid, AUE_SETSID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 147 = setsid */ + { AS(quotactl_args), (sy_call_t *)sys_quotactl, AUE_QUOTACTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 148 = quotactl */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 149 = obsolete oquota */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 150 = obsolete ogetsockname */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 151 = sem_lock */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 152 = sem_wakeup */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 153 = asyncdaemon */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 154 = nlm_syscall */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 155 = nfssvc */ + { compat(AS(ofreebsd32_getdirentries_args),freebsd32_getdirentries), AUE_GETDIRENTRIES, NULL, 0, 0, 0, SY_THR_STATIC }, /* 156 = old freebsd32_getdirentries */ + { compat4(AS(freebsd4_freebsd32_statfs_args),freebsd32_statfs), AUE_STATFS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 157 = freebsd4 freebsd32_statfs */ + { compat4(AS(freebsd4_freebsd32_fstatfs_args),freebsd32_fstatfs), AUE_FSTATFS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 158 = freebsd4 freebsd32_fstatfs */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 159 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 160 = lgetfh */ + { AS(getfh_args), (sy_call_t *)sys_getfh, AUE_NFS_GETFH, NULL, 0, 0, 0, SY_THR_STATIC }, /* 161 = getfh */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 162 = obsolete getdomainname */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 163 = obsolete setdomainname */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 164 = obsolete uname */ + { AS(freebsd32_sysarch_args), (sy_call_t *)freebsd32_sysarch, AUE_SYSARCH, NULL, 0, 0, 0, SY_THR_STATIC }, /* 165 = freebsd32_sysarch */ + { AS(rtprio_args), (sy_call_t *)sys_rtprio, AUE_RTPRIO, NULL, 0, 0, 0, SY_THR_STATIC }, /* 166 = rtprio */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 167 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 168 = nosys */ + { AS(freebsd32_semsys_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 169 = freebsd32_semsys */ + { AS(freebsd32_msgsys_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 170 = freebsd32_msgsys */ + { AS(freebsd32_shmsys_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 171 = freebsd32_shmsys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 172 = nosys */ + { compat6(AS(freebsd6_freebsd32_pread_args),freebsd32_pread), AUE_PREAD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 173 = freebsd6 freebsd32_pread */ + { compat6(AS(freebsd6_freebsd32_pwrite_args),freebsd32_pwrite), AUE_PWRITE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 174 = freebsd6 freebsd32_pwrite */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 175 = nosys */ + { AS(ntp_adjtime_args), (sy_call_t *)sys_ntp_adjtime, AUE_NTP_ADJTIME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 176 = ntp_adjtime */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 177 = sfork */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 178 = getdescriptor */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 179 = setdescriptor */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 180 = nosys */ + { AS(setgid_args), (sy_call_t *)sys_setgid, AUE_SETGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 181 = setgid */ + { AS(setegid_args), (sy_call_t *)sys_setegid, AUE_SETEGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 182 = setegid */ + { AS(seteuid_args), (sy_call_t *)sys_seteuid, AUE_SETEUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 183 = seteuid */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 184 = lfs_bmapv */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 185 = lfs_markv */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 186 = lfs_segclean */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 187 = lfs_segwait */ + { AS(freebsd32_stat_args), (sy_call_t *)freebsd32_stat, AUE_STAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 188 = freebsd32_stat */ + { AS(freebsd32_fstat_args), (sy_call_t *)freebsd32_fstat, AUE_FSTAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 189 = freebsd32_fstat */ + { AS(freebsd32_lstat_args), (sy_call_t *)freebsd32_lstat, AUE_LSTAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 190 = freebsd32_lstat */ + { AS(pathconf_args), (sy_call_t *)sys_pathconf, AUE_PATHCONF, NULL, 0, 0, 0, SY_THR_STATIC }, /* 191 = pathconf */ + { AS(fpathconf_args), (sy_call_t *)sys_fpathconf, AUE_FPATHCONF, NULL, 0, 0, 0, SY_THR_STATIC }, /* 192 = fpathconf */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 193 = nosys */ + { AS(__getrlimit_args), (sy_call_t *)sys_getrlimit, AUE_GETRLIMIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 194 = getrlimit */ + { AS(__setrlimit_args), (sy_call_t *)sys_setrlimit, AUE_SETRLIMIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 195 = setrlimit */ + { AS(freebsd32_getdirentries_args), (sy_call_t *)freebsd32_getdirentries, AUE_GETDIRENTRIES, NULL, 0, 0, 0, SY_THR_STATIC }, /* 196 = freebsd32_getdirentries */ + { compat6(AS(freebsd6_freebsd32_mmap_args),freebsd32_mmap), AUE_MMAP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 197 = freebsd6 freebsd32_mmap */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 198 = __syscall */ + { compat6(AS(freebsd6_freebsd32_lseek_args),freebsd32_lseek), AUE_LSEEK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 199 = freebsd6 freebsd32_lseek */ + { compat6(AS(freebsd6_freebsd32_truncate_args),freebsd32_truncate), AUE_TRUNCATE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 200 = freebsd6 freebsd32_truncate */ + { compat6(AS(freebsd6_freebsd32_ftruncate_args),freebsd32_ftruncate), AUE_FTRUNCATE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 201 = freebsd6 freebsd32_ftruncate */ + { AS(freebsd32_sysctl_args), (sy_call_t *)freebsd32_sysctl, AUE_SYSCTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 202 = freebsd32_sysctl */ + { AS(mlock_args), (sy_call_t *)sys_mlock, AUE_MLOCK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 203 = mlock */ + { AS(munlock_args), (sy_call_t *)sys_munlock, AUE_MUNLOCK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 204 = munlock */ + { AS(undelete_args), (sy_call_t *)sys_undelete, AUE_UNDELETE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 205 = undelete */ + { AS(freebsd32_futimes_args), (sy_call_t *)freebsd32_futimes, AUE_FUTIMES, NULL, 0, 0, 0, SY_THR_STATIC }, /* 206 = freebsd32_futimes */ + { AS(getpgid_args), (sy_call_t *)sys_getpgid, AUE_GETPGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 207 = getpgid */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 208 = newreboot */ + { AS(poll_args), (sy_call_t *)sys_poll, AUE_POLL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 209 = poll */ + { AS(nosys_args), (sy_call_t *)lkmnosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 210 = lkmnosys */ + { AS(nosys_args), (sy_call_t *)lkmnosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 211 = lkmnosys */ + { AS(nosys_args), (sy_call_t *)lkmnosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 212 = lkmnosys */ + { AS(nosys_args), (sy_call_t *)lkmnosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 213 = lkmnosys */ + { AS(nosys_args), (sy_call_t *)lkmnosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 214 = lkmnosys */ + { AS(nosys_args), (sy_call_t *)lkmnosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 215 = lkmnosys */ + { AS(nosys_args), (sy_call_t *)lkmnosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 216 = lkmnosys */ + { AS(nosys_args), (sy_call_t *)lkmnosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 217 = lkmnosys */ + { AS(nosys_args), (sy_call_t *)lkmnosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 218 = lkmnosys */ + { AS(nosys_args), (sy_call_t *)lkmnosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 219 = lkmnosys */ + { 0, (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 220 = freebsd7 freebsd32_semctl */ + { AS(semget_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 221 = semget */ + { AS(semop_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 222 = semop */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 223 = semconfig */ + { 0, (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 224 = freebsd7 freebsd32_msgctl */ + { AS(msgget_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 225 = msgget */ + { AS(freebsd32_msgsnd_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 226 = freebsd32_msgsnd */ + { AS(freebsd32_msgrcv_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 227 = freebsd32_msgrcv */ + { AS(shmat_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 228 = shmat */ + { 0, (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 229 = freebsd7 freebsd32_shmctl */ + { AS(shmdt_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 230 = shmdt */ + { AS(shmget_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 231 = shmget */ + { AS(freebsd32_clock_gettime_args), (sy_call_t *)freebsd32_clock_gettime, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 232 = freebsd32_clock_gettime */ + { AS(freebsd32_clock_settime_args), (sy_call_t *)freebsd32_clock_settime, AUE_CLOCK_SETTIME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 233 = freebsd32_clock_settime */ + { AS(freebsd32_clock_getres_args), (sy_call_t *)freebsd32_clock_getres, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 234 = freebsd32_clock_getres */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 235 = timer_create */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 236 = timer_delete */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 237 = timer_settime */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 238 = timer_gettime */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 239 = timer_getoverrun */ + { AS(freebsd32_nanosleep_args), (sy_call_t *)freebsd32_nanosleep, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 240 = freebsd32_nanosleep */ + { AS(ffclock_getcounter_args), (sy_call_t *)sys_ffclock_getcounter, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 241 = ffclock_getcounter */ + { AS(ffclock_setestimate_args), (sy_call_t *)sys_ffclock_setestimate, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 242 = ffclock_setestimate */ + { AS(ffclock_getestimate_args), (sy_call_t *)sys_ffclock_getestimate, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 243 = ffclock_getestimate */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 244 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 245 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 246 = nosys */ + { AS(clock_getcpuclockid2_args), (sy_call_t *)sys_clock_getcpuclockid2, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 247 = clock_getcpuclockid2 */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 248 = ntp_gettime */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 249 = nosys */ + { AS(minherit_args), (sy_call_t *)sys_minherit, AUE_MINHERIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 250 = minherit */ + { AS(rfork_args), (sy_call_t *)sys_rfork, AUE_RFORK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 251 = rfork */ + { AS(openbsd_poll_args), (sy_call_t *)sys_openbsd_poll, AUE_POLL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 252 = openbsd_poll */ + { 0, (sy_call_t *)sys_issetugid, AUE_ISSETUGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 253 = issetugid */ + { AS(lchown_args), (sy_call_t *)sys_lchown, AUE_LCHOWN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 254 = lchown */ + { AS(freebsd32_aio_read_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 255 = freebsd32_aio_read */ + { AS(freebsd32_aio_write_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 256 = freebsd32_aio_write */ + { AS(freebsd32_lio_listio_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 257 = freebsd32_lio_listio */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 258 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 259 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 260 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 261 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 262 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 263 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 264 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 265 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 266 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 267 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 268 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 269 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 270 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 271 = nosys */ + { AS(getdents_args), (sy_call_t *)sys_getdents, AUE_O_GETDENTS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 272 = getdents */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 273 = nosys */ + { AS(lchmod_args), (sy_call_t *)sys_lchmod, AUE_LCHMOD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 274 = lchmod */ + { AS(lchown_args), (sy_call_t *)sys_lchown, AUE_LCHOWN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 275 = netbsd_lchown */ + { AS(freebsd32_lutimes_args), (sy_call_t *)freebsd32_lutimes, AUE_LUTIMES, NULL, 0, 0, 0, SY_THR_STATIC }, /* 276 = freebsd32_lutimes */ + { AS(msync_args), (sy_call_t *)sys_msync, AUE_MSYNC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 277 = netbsd_msync */ + { AS(nstat_args), (sy_call_t *)sys_nstat, AUE_STAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 278 = nstat */ + { AS(nfstat_args), (sy_call_t *)sys_nfstat, AUE_FSTAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 279 = nfstat */ + { AS(nlstat_args), (sy_call_t *)sys_nlstat, AUE_LSTAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 280 = nlstat */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 281 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 282 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 283 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 284 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 285 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 286 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 287 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 288 = nosys */ + { AS(freebsd32_preadv_args), (sy_call_t *)freebsd32_preadv, AUE_PREADV, NULL, 0, 0, 0, SY_THR_STATIC }, /* 289 = freebsd32_preadv */ + { AS(freebsd32_pwritev_args), (sy_call_t *)freebsd32_pwritev, AUE_PWRITEV, NULL, 0, 0, 0, SY_THR_STATIC }, /* 290 = freebsd32_pwritev */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 291 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 292 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 293 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 294 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 295 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 296 = nosys */ + { compat4(AS(freebsd4_freebsd32_fhstatfs_args),freebsd32_fhstatfs), AUE_FHSTATFS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 297 = freebsd4 freebsd32_fhstatfs */ + { AS(fhopen_args), (sy_call_t *)sys_fhopen, AUE_FHOPEN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 298 = fhopen */ + { AS(fhstat_args), (sy_call_t *)sys_fhstat, AUE_FHSTAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 299 = fhstat */ + { AS(modnext_args), (sy_call_t *)sys_modnext, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 300 = modnext */ + { AS(freebsd32_modstat_args), (sy_call_t *)freebsd32_modstat, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 301 = freebsd32_modstat */ + { AS(modfnext_args), (sy_call_t *)sys_modfnext, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 302 = modfnext */ + { AS(modfind_args), (sy_call_t *)sys_modfind, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 303 = modfind */ + { AS(kldload_args), (sy_call_t *)sys_kldload, AUE_MODLOAD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 304 = kldload */ + { AS(kldunload_args), (sy_call_t *)sys_kldunload, AUE_MODUNLOAD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 305 = kldunload */ + { AS(kldfind_args), (sy_call_t *)sys_kldfind, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 306 = kldfind */ + { AS(kldnext_args), (sy_call_t *)sys_kldnext, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 307 = kldnext */ + { AS(freebsd32_kldstat_args), (sy_call_t *)freebsd32_kldstat, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 308 = freebsd32_kldstat */ + { AS(kldfirstmod_args), (sy_call_t *)sys_kldfirstmod, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 309 = kldfirstmod */ + { AS(getsid_args), (sy_call_t *)sys_getsid, AUE_GETSID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 310 = getsid */ + { AS(setresuid_args), (sy_call_t *)sys_setresuid, AUE_SETRESUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 311 = setresuid */ + { AS(setresgid_args), (sy_call_t *)sys_setresgid, AUE_SETRESGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 312 = setresgid */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 313 = obsolete signanosleep */ + { AS(freebsd32_aio_return_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 314 = freebsd32_aio_return */ + { AS(freebsd32_aio_suspend_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 315 = freebsd32_aio_suspend */ + { AS(freebsd32_aio_cancel_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 316 = freebsd32_aio_cancel */ + { AS(freebsd32_aio_error_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 317 = freebsd32_aio_error */ + { AS(freebsd32_oaio_read_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 318 = freebsd32_oaio_read */ + { AS(freebsd32_oaio_write_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 319 = freebsd32_oaio_write */ + { AS(freebsd32_olio_listio_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 320 = freebsd32_olio_listio */ + { 0, (sy_call_t *)sys_yield, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 321 = yield */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 322 = obsolete thr_sleep */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 323 = obsolete thr_wakeup */ + { AS(mlockall_args), (sy_call_t *)sys_mlockall, AUE_MLOCKALL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 324 = mlockall */ + { 0, (sy_call_t *)sys_munlockall, AUE_MUNLOCKALL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 325 = munlockall */ + { AS(__getcwd_args), (sy_call_t *)sys___getcwd, AUE_GETCWD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 326 = __getcwd */ + { AS(sched_setparam_args), (sy_call_t *)sys_sched_setparam, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 327 = sched_setparam */ + { AS(sched_getparam_args), (sy_call_t *)sys_sched_getparam, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 328 = sched_getparam */ + { AS(sched_setscheduler_args), (sy_call_t *)sys_sched_setscheduler, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 329 = sched_setscheduler */ + { AS(sched_getscheduler_args), (sy_call_t *)sys_sched_getscheduler, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 330 = sched_getscheduler */ + { 0, (sy_call_t *)sys_sched_yield, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 331 = sched_yield */ + { AS(sched_get_priority_max_args), (sy_call_t *)sys_sched_get_priority_max, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 332 = sched_get_priority_max */ + { AS(sched_get_priority_min_args), (sy_call_t *)sys_sched_get_priority_min, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 333 = sched_get_priority_min */ + { AS(sched_rr_get_interval_args), (sy_call_t *)sys_sched_rr_get_interval, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 334 = sched_rr_get_interval */ + { AS(utrace_args), (sy_call_t *)sys_utrace, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 335 = utrace */ + { compat4(AS(freebsd4_freebsd32_sendfile_args),freebsd32_sendfile), AUE_SENDFILE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 336 = freebsd4 freebsd32_sendfile */ + { AS(kldsym_args), (sy_call_t *)sys_kldsym, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 337 = kldsym */ + { AS(freebsd32_jail_args), (sy_call_t *)freebsd32_jail, AUE_JAIL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 338 = freebsd32_jail */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 339 = pioctl */ + { AS(sigprocmask_args), (sy_call_t *)sys_sigprocmask, AUE_SIGPROCMASK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 340 = sigprocmask */ + { AS(sigsuspend_args), (sy_call_t *)sys_sigsuspend, AUE_SIGSUSPEND, NULL, 0, 0, 0, SY_THR_STATIC }, /* 341 = sigsuspend */ + { compat4(AS(freebsd4_freebsd32_sigaction_args),freebsd32_sigaction), AUE_SIGACTION, NULL, 0, 0, 0, SY_THR_STATIC }, /* 342 = freebsd4 freebsd32_sigaction */ + { AS(sigpending_args), (sy_call_t *)sys_sigpending, AUE_SIGPENDING, NULL, 0, 0, 0, SY_THR_STATIC }, /* 343 = sigpending */ + { compat4(AS(freebsd4_freebsd32_sigreturn_args),freebsd32_sigreturn), AUE_SIGRETURN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 344 = freebsd4 freebsd32_sigreturn */ + { AS(freebsd32_sigtimedwait_args), (sy_call_t *)freebsd32_sigtimedwait, AUE_SIGWAIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 345 = freebsd32_sigtimedwait */ + { AS(freebsd32_sigwaitinfo_args), (sy_call_t *)freebsd32_sigwaitinfo, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 346 = freebsd32_sigwaitinfo */ + { AS(__acl_get_file_args), (sy_call_t *)sys___acl_get_file, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 347 = __acl_get_file */ + { AS(__acl_set_file_args), (sy_call_t *)sys___acl_set_file, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 348 = __acl_set_file */ + { AS(__acl_get_fd_args), (sy_call_t *)sys___acl_get_fd, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 349 = __acl_get_fd */ + { AS(__acl_set_fd_args), (sy_call_t *)sys___acl_set_fd, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 350 = __acl_set_fd */ + { AS(__acl_delete_file_args), (sy_call_t *)sys___acl_delete_file, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 351 = __acl_delete_file */ + { AS(__acl_delete_fd_args), (sy_call_t *)sys___acl_delete_fd, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 352 = __acl_delete_fd */ + { AS(__acl_aclcheck_file_args), (sy_call_t *)sys___acl_aclcheck_file, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 353 = __acl_aclcheck_file */ + { AS(__acl_aclcheck_fd_args), (sy_call_t *)sys___acl_aclcheck_fd, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 354 = __acl_aclcheck_fd */ + { AS(extattrctl_args), (sy_call_t *)sys_extattrctl, AUE_EXTATTRCTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 355 = extattrctl */ + { AS(extattr_set_file_args), (sy_call_t *)sys_extattr_set_file, AUE_EXTATTR_SET_FILE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 356 = extattr_set_file */ + { AS(extattr_get_file_args), (sy_call_t *)sys_extattr_get_file, AUE_EXTATTR_GET_FILE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 357 = extattr_get_file */ + { AS(extattr_delete_file_args), (sy_call_t *)sys_extattr_delete_file, AUE_EXTATTR_DELETE_FILE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 358 = extattr_delete_file */ + { AS(freebsd32_aio_waitcomplete_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 359 = freebsd32_aio_waitcomplete */ + { AS(getresuid_args), (sy_call_t *)sys_getresuid, AUE_GETRESUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 360 = getresuid */ + { AS(getresgid_args), (sy_call_t *)sys_getresgid, AUE_GETRESGID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 361 = getresgid */ + { 0, (sy_call_t *)sys_kqueue, AUE_KQUEUE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 362 = kqueue */ + { AS(freebsd32_kevent_args), (sy_call_t *)freebsd32_kevent, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 363 = freebsd32_kevent */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 364 = __cap_get_proc */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 365 = __cap_set_proc */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 366 = __cap_get_fd */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 367 = __cap_get_file */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 368 = __cap_set_fd */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 369 = __cap_set_file */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 370 = nosys */ + { AS(extattr_set_fd_args), (sy_call_t *)sys_extattr_set_fd, AUE_EXTATTR_SET_FD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 371 = extattr_set_fd */ + { AS(extattr_get_fd_args), (sy_call_t *)sys_extattr_get_fd, AUE_EXTATTR_GET_FD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 372 = extattr_get_fd */ + { AS(extattr_delete_fd_args), (sy_call_t *)sys_extattr_delete_fd, AUE_EXTATTR_DELETE_FD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 373 = extattr_delete_fd */ + { AS(__setugid_args), (sy_call_t *)sys___setugid, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 374 = __setugid */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 375 = nfsclnt */ + { AS(eaccess_args), (sy_call_t *)sys_eaccess, AUE_EACCESS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 376 = eaccess */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 377 = afs_syscall */ + { AS(freebsd32_nmount_args), (sy_call_t *)freebsd32_nmount, AUE_NMOUNT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 378 = freebsd32_nmount */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 379 = kse_exit */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 380 = kse_wakeup */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 381 = kse_create */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 382 = kse_thr_interrupt */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 383 = kse_release */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 384 = __mac_get_proc */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 385 = __mac_set_proc */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 386 = __mac_get_fd */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 387 = __mac_get_file */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 388 = __mac_set_fd */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 389 = __mac_set_file */ + { AS(kenv_args), (sy_call_t *)sys_kenv, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 390 = kenv */ + { AS(lchflags_args), (sy_call_t *)sys_lchflags, AUE_LCHFLAGS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 391 = lchflags */ + { AS(uuidgen_args), (sy_call_t *)sys_uuidgen, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 392 = uuidgen */ + { AS(freebsd32_sendfile_args), (sy_call_t *)freebsd32_sendfile, AUE_SENDFILE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 393 = freebsd32_sendfile */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 394 = mac_syscall */ + { AS(getfsstat_args), (sy_call_t *)sys_getfsstat, AUE_GETFSSTAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 395 = getfsstat */ + { AS(statfs_args), (sy_call_t *)sys_statfs, AUE_STATFS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 396 = statfs */ + { AS(fstatfs_args), (sy_call_t *)sys_fstatfs, AUE_FSTATFS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 397 = fstatfs */ + { AS(fhstatfs_args), (sy_call_t *)sys_fhstatfs, AUE_FHSTATFS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 398 = fhstatfs */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 399 = nosys */ + { AS(ksem_close_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 400 = ksem_close */ + { AS(ksem_post_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 401 = ksem_post */ + { AS(ksem_wait_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 402 = ksem_wait */ + { AS(ksem_trywait_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 403 = ksem_trywait */ + { AS(freebsd32_ksem_init_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 404 = freebsd32_ksem_init */ + { AS(freebsd32_ksem_open_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 405 = freebsd32_ksem_open */ + { AS(ksem_unlink_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 406 = ksem_unlink */ + { AS(ksem_getvalue_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 407 = ksem_getvalue */ + { AS(ksem_destroy_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 408 = ksem_destroy */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 409 = __mac_get_pid */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 410 = __mac_get_link */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 411 = __mac_set_link */ + { AS(extattr_set_link_args), (sy_call_t *)sys_extattr_set_link, AUE_EXTATTR_SET_LINK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 412 = extattr_set_link */ + { AS(extattr_get_link_args), (sy_call_t *)sys_extattr_get_link, AUE_EXTATTR_GET_LINK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 413 = extattr_get_link */ + { AS(extattr_delete_link_args), (sy_call_t *)sys_extattr_delete_link, AUE_EXTATTR_DELETE_LINK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 414 = extattr_delete_link */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 415 = __mac_execve */ + { AS(freebsd32_sigaction_args), (sy_call_t *)freebsd32_sigaction, AUE_SIGACTION, NULL, 0, 0, 0, SY_THR_STATIC }, /* 416 = freebsd32_sigaction */ + { AS(freebsd32_sigreturn_args), (sy_call_t *)freebsd32_sigreturn, AUE_SIGRETURN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 417 = freebsd32_sigreturn */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 418 = __xstat */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 419 = __xfstat */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 420 = __xlstat */ + { AS(freebsd32_getcontext_args), (sy_call_t *)freebsd32_getcontext, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 421 = freebsd32_getcontext */ + { AS(freebsd32_setcontext_args), (sy_call_t *)freebsd32_setcontext, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 422 = freebsd32_setcontext */ + { AS(freebsd32_swapcontext_args), (sy_call_t *)freebsd32_swapcontext, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 423 = freebsd32_swapcontext */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 424 = swapoff */ + { AS(__acl_get_link_args), (sy_call_t *)sys___acl_get_link, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 425 = __acl_get_link */ + { AS(__acl_set_link_args), (sy_call_t *)sys___acl_set_link, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 426 = __acl_set_link */ + { AS(__acl_delete_link_args), (sy_call_t *)sys___acl_delete_link, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 427 = __acl_delete_link */ + { AS(__acl_aclcheck_link_args), (sy_call_t *)sys___acl_aclcheck_link, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 428 = __acl_aclcheck_link */ + { AS(sigwait_args), (sy_call_t *)sys_sigwait, AUE_SIGWAIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 429 = sigwait */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 430 = thr_create; */ + { AS(thr_exit_args), (sy_call_t *)sys_thr_exit, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 431 = thr_exit */ + { AS(thr_self_args), (sy_call_t *)sys_thr_self, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 432 = thr_self */ + { AS(thr_kill_args), (sy_call_t *)sys_thr_kill, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 433 = thr_kill */ + { AS(freebsd32_umtx_lock_args), (sy_call_t *)freebsd32_umtx_lock, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 434 = freebsd32_umtx_lock */ + { AS(freebsd32_umtx_unlock_args), (sy_call_t *)freebsd32_umtx_unlock, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 435 = freebsd32_umtx_unlock */ + { AS(jail_attach_args), (sy_call_t *)sys_jail_attach, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 436 = jail_attach */ + { AS(extattr_list_fd_args), (sy_call_t *)sys_extattr_list_fd, AUE_EXTATTR_LIST_FD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 437 = extattr_list_fd */ + { AS(extattr_list_file_args), (sy_call_t *)sys_extattr_list_file, AUE_EXTATTR_LIST_FILE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 438 = extattr_list_file */ + { AS(extattr_list_link_args), (sy_call_t *)sys_extattr_list_link, AUE_EXTATTR_LIST_LINK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 439 = extattr_list_link */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 440 = kse_switchin */ + { AS(freebsd32_ksem_timedwait_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 441 = freebsd32_ksem_timedwait */ + { AS(freebsd32_thr_suspend_args), (sy_call_t *)freebsd32_thr_suspend, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 442 = freebsd32_thr_suspend */ + { AS(thr_wake_args), (sy_call_t *)sys_thr_wake, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 443 = thr_wake */ + { AS(kldunloadf_args), (sy_call_t *)sys_kldunloadf, AUE_MODUNLOAD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 444 = kldunloadf */ + { AS(audit_args), (sy_call_t *)sys_audit, AUE_AUDIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 445 = audit */ + { AS(auditon_args), (sy_call_t *)sys_auditon, AUE_AUDITON, NULL, 0, 0, 0, SY_THR_STATIC }, /* 446 = auditon */ + { AS(getauid_args), (sy_call_t *)sys_getauid, AUE_GETAUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 447 = getauid */ + { AS(setauid_args), (sy_call_t *)sys_setauid, AUE_SETAUID, NULL, 0, 0, 0, SY_THR_STATIC }, /* 448 = setauid */ + { AS(getaudit_args), (sy_call_t *)sys_getaudit, AUE_GETAUDIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 449 = getaudit */ + { AS(setaudit_args), (sy_call_t *)sys_setaudit, AUE_SETAUDIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 450 = setaudit */ + { AS(getaudit_addr_args), (sy_call_t *)sys_getaudit_addr, AUE_GETAUDIT_ADDR, NULL, 0, 0, 0, SY_THR_STATIC }, /* 451 = getaudit_addr */ + { AS(setaudit_addr_args), (sy_call_t *)sys_setaudit_addr, AUE_SETAUDIT_ADDR, NULL, 0, 0, 0, SY_THR_STATIC }, /* 452 = setaudit_addr */ + { AS(auditctl_args), (sy_call_t *)sys_auditctl, AUE_AUDITCTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 453 = auditctl */ + { AS(freebsd32_umtx_op_args), (sy_call_t *)freebsd32_umtx_op, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 454 = freebsd32_umtx_op */ + { AS(freebsd32_thr_new_args), (sy_call_t *)freebsd32_thr_new, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 455 = freebsd32_thr_new */ + { AS(sigqueue_args), (sy_call_t *)sys_sigqueue, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 456 = sigqueue */ + { AS(freebsd32_kmq_open_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 457 = freebsd32_kmq_open */ + { AS(freebsd32_kmq_setattr_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 458 = freebsd32_kmq_setattr */ + { AS(freebsd32_kmq_timedreceive_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 459 = freebsd32_kmq_timedreceive */ + { AS(freebsd32_kmq_timedsend_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 460 = freebsd32_kmq_timedsend */ + { AS(kmq_notify_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 461 = kmq_notify */ + { AS(kmq_unlink_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 462 = kmq_unlink */ + { AS(abort2_args), (sy_call_t *)sys_abort2, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 463 = abort2 */ + { AS(thr_set_name_args), (sy_call_t *)sys_thr_set_name, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 464 = thr_set_name */ + { AS(freebsd32_aio_fsync_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 465 = freebsd32_aio_fsync */ + { AS(rtprio_thread_args), (sy_call_t *)sys_rtprio_thread, AUE_RTPRIO, NULL, 0, 0, 0, SY_THR_STATIC }, /* 466 = rtprio_thread */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 467 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 468 = nosys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 469 = __getpath_fromfd */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 470 = __getpath_fromaddr */ + { AS(sctp_peeloff_args), (sy_call_t *)sys_sctp_peeloff, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 471 = sctp_peeloff */ + { AS(sctp_generic_sendmsg_args), (sy_call_t *)sys_sctp_generic_sendmsg, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 472 = sctp_generic_sendmsg */ + { AS(sctp_generic_sendmsg_iov_args), (sy_call_t *)sys_sctp_generic_sendmsg_iov, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 473 = sctp_generic_sendmsg_iov */ + { AS(sctp_generic_recvmsg_args), (sy_call_t *)sys_sctp_generic_recvmsg, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 474 = sctp_generic_recvmsg */ +#ifdef PAD64_REQUIRED + { AS(freebsd32_pread_args), (sy_call_t *)freebsd32_pread, AUE_PREAD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 475 = freebsd32_pread */ + { AS(freebsd32_pwrite_args), (sy_call_t *)freebsd32_pwrite, AUE_PWRITE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 476 = freebsd32_pwrite */ + { AS(freebsd32_mmap_args), (sy_call_t *)freebsd32_mmap, AUE_MMAP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 477 = freebsd32_mmap */ + { AS(freebsd32_lseek_args), (sy_call_t *)freebsd32_lseek, AUE_LSEEK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 478 = freebsd32_lseek */ + { AS(freebsd32_truncate_args), (sy_call_t *)freebsd32_truncate, AUE_TRUNCATE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 479 = freebsd32_truncate */ + { AS(freebsd32_ftruncate_args), (sy_call_t *)freebsd32_ftruncate, AUE_FTRUNCATE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 480 = freebsd32_ftruncate */ +#else + { AS(freebsd32_pread_args), (sy_call_t *)freebsd32_pread, AUE_PREAD, NULL, 0, 0, 0, SY_THR_STATIC }, /* 475 = freebsd32_pread */ + { AS(freebsd32_pwrite_args), (sy_call_t *)freebsd32_pwrite, AUE_PWRITE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 476 = freebsd32_pwrite */ + { AS(freebsd32_mmap_args), (sy_call_t *)freebsd32_mmap, AUE_MMAP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 477 = freebsd32_mmap */ + { AS(freebsd32_lseek_args), (sy_call_t *)freebsd32_lseek, AUE_LSEEK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 478 = freebsd32_lseek */ + { AS(freebsd32_truncate_args), (sy_call_t *)freebsd32_truncate, AUE_TRUNCATE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 479 = freebsd32_truncate */ + { AS(freebsd32_ftruncate_args), (sy_call_t *)freebsd32_ftruncate, AUE_FTRUNCATE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 480 = freebsd32_ftruncate */ +#endif + { AS(thr_kill2_args), (sy_call_t *)sys_thr_kill2, AUE_KILL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 481 = thr_kill2 */ + { AS(shm_open_args), (sy_call_t *)sys_shm_open, AUE_SHMOPEN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 482 = shm_open */ + { AS(shm_unlink_args), (sy_call_t *)sys_shm_unlink, AUE_SHMUNLINK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 483 = shm_unlink */ + { AS(cpuset_args), (sy_call_t *)sys_cpuset, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 484 = cpuset */ +#ifdef PAD64_REQUIRED + { AS(freebsd32_cpuset_setid_args), (sy_call_t *)freebsd32_cpuset_setid, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 485 = freebsd32_cpuset_setid */ +#else + { AS(freebsd32_cpuset_setid_args), (sy_call_t *)freebsd32_cpuset_setid, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 485 = freebsd32_cpuset_setid */ +#endif + { AS(freebsd32_cpuset_getid_args), (sy_call_t *)freebsd32_cpuset_getid, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 486 = freebsd32_cpuset_getid */ + { AS(freebsd32_cpuset_getaffinity_args), (sy_call_t *)freebsd32_cpuset_getaffinity, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 487 = freebsd32_cpuset_getaffinity */ + { AS(freebsd32_cpuset_setaffinity_args), (sy_call_t *)freebsd32_cpuset_setaffinity, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 488 = freebsd32_cpuset_setaffinity */ + { AS(faccessat_args), (sy_call_t *)sys_faccessat, AUE_FACCESSAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 489 = faccessat */ + { AS(fchmodat_args), (sy_call_t *)sys_fchmodat, AUE_FCHMODAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 490 = fchmodat */ + { AS(fchownat_args), (sy_call_t *)sys_fchownat, AUE_FCHOWNAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 491 = fchownat */ + { AS(freebsd32_fexecve_args), (sy_call_t *)freebsd32_fexecve, AUE_FEXECVE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 492 = freebsd32_fexecve */ + { AS(freebsd32_fstatat_args), (sy_call_t *)freebsd32_fstatat, AUE_FSTATAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 493 = freebsd32_fstatat */ + { AS(freebsd32_futimesat_args), (sy_call_t *)freebsd32_futimesat, AUE_FUTIMESAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 494 = freebsd32_futimesat */ + { AS(linkat_args), (sy_call_t *)sys_linkat, AUE_LINKAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 495 = linkat */ + { AS(mkdirat_args), (sy_call_t *)sys_mkdirat, AUE_MKDIRAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 496 = mkdirat */ + { AS(mkfifoat_args), (sy_call_t *)sys_mkfifoat, AUE_MKFIFOAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 497 = mkfifoat */ + { AS(mknodat_args), (sy_call_t *)sys_mknodat, AUE_MKNODAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 498 = mknodat */ + { AS(openat_args), (sy_call_t *)sys_openat, AUE_OPENAT_RWTC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 499 = openat */ + { AS(readlinkat_args), (sy_call_t *)sys_readlinkat, AUE_READLINKAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 500 = readlinkat */ + { AS(renameat_args), (sy_call_t *)sys_renameat, AUE_RENAMEAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 501 = renameat */ + { AS(symlinkat_args), (sy_call_t *)sys_symlinkat, AUE_SYMLINKAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 502 = symlinkat */ + { AS(unlinkat_args), (sy_call_t *)sys_unlinkat, AUE_UNLINKAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 503 = unlinkat */ + { AS(posix_openpt_args), (sy_call_t *)sys_posix_openpt, AUE_POSIX_OPENPT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 504 = posix_openpt */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 505 = gssd_syscall */ + { AS(freebsd32_jail_get_args), (sy_call_t *)freebsd32_jail_get, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 506 = freebsd32_jail_get */ + { AS(freebsd32_jail_set_args), (sy_call_t *)freebsd32_jail_set, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 507 = freebsd32_jail_set */ + { AS(jail_remove_args), (sy_call_t *)sys_jail_remove, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 508 = jail_remove */ + { AS(closefrom_args), (sy_call_t *)sys_closefrom, AUE_CLOSEFROM, NULL, 0, 0, 0, SY_THR_STATIC }, /* 509 = closefrom */ + { AS(freebsd32_semctl_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 510 = freebsd32_semctl */ + { AS(freebsd32_msgctl_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 511 = freebsd32_msgctl */ + { AS(freebsd32_shmctl_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 512 = freebsd32_shmctl */ + { AS(lpathconf_args), (sy_call_t *)sys_lpathconf, AUE_LPATHCONF, NULL, 0, 0, 0, SY_THR_STATIC }, /* 513 = lpathconf */ + { AS(cap_new_args), (sy_call_t *)sys_cap_new, AUE_CAP_NEW, NULL, 0, 0, 0, SY_THR_STATIC }, /* 514 = cap_new */ + { AS(cap_rights_get_args), (sy_call_t *)sys_cap_rights_get, AUE_CAP_RIGHTS_GET, NULL, 0, 0, 0, SY_THR_STATIC }, /* 515 = cap_rights_get */ + { 0, (sy_call_t *)sys_cap_enter, AUE_CAP_ENTER, NULL, 0, 0, 0, SY_THR_STATIC }, /* 516 = cap_enter */ + { AS(cap_getmode_args), (sy_call_t *)sys_cap_getmode, AUE_CAP_GETMODE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 517 = cap_getmode */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 518 = pdfork */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 519 = pdkill */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 520 = pdgetpid */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 521 = pdwait */ + { AS(freebsd32_pselect_args), (sy_call_t *)freebsd32_pselect, AUE_SELECT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 522 = freebsd32_pselect */ + { AS(getloginclass_args), (sy_call_t *)sys_getloginclass, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 523 = getloginclass */ + { AS(setloginclass_args), (sy_call_t *)sys_setloginclass, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 524 = setloginclass */ + { AS(rctl_get_racct_args), (sy_call_t *)sys_rctl_get_racct, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 525 = rctl_get_racct */ + { AS(rctl_get_rules_args), (sy_call_t *)sys_rctl_get_rules, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 526 = rctl_get_rules */ + { AS(rctl_get_limits_args), (sy_call_t *)sys_rctl_get_limits, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 527 = rctl_get_limits */ + { AS(rctl_add_rule_args), (sy_call_t *)sys_rctl_add_rule, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 528 = rctl_add_rule */ + { AS(rctl_remove_rule_args), (sy_call_t *)sys_rctl_remove_rule, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 529 = rctl_remove_rule */ +#ifdef PAD64_REQUIRED + { AS(freebsd32_posix_fallocate_args), (sy_call_t *)freebsd32_posix_fallocate, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 530 = freebsd32_posix_fallocate */ + { AS(freebsd32_posix_fadvise_args), (sy_call_t *)freebsd32_posix_fadvise, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 531 = freebsd32_posix_fadvise */ + { AS(freebsd32_wait6_args), (sy_call_t *)freebsd32_wait6, AUE_WAIT6, NULL, 0, 0, 0, SY_THR_STATIC }, /* 532 = freebsd32_wait6 */ +#else + { AS(freebsd32_posix_fallocate_args), (sy_call_t *)freebsd32_posix_fallocate, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 530 = freebsd32_posix_fallocate */ + { AS(freebsd32_posix_fadvise_args), (sy_call_t *)freebsd32_posix_fadvise, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 531 = freebsd32_posix_fadvise */ + { AS(freebsd32_wait6_args), (sy_call_t *)freebsd32_wait6, AUE_WAIT6, NULL, 0, 0, 0, SY_THR_STATIC }, /* 532 = freebsd32_wait6 */ +#endif + { AS(cap_rights_limit_args), (sy_call_t *)sys_cap_rights_limit, AUE_CAP_RIGHTS_LIMIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 533 = cap_rights_limit */ + { AS(cap_ioctls_limit_args), (sy_call_t *)sys_cap_ioctls_limit, AUE_CAP_IOCTLS_LIMIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 534 = cap_ioctls_limit */ + { AS(cap_ioctls_get_args), (sy_call_t *)sys_cap_ioctls_get, AUE_CAP_IOCTLS_GET, NULL, 0, 0, 0, SY_THR_STATIC }, /* 535 = cap_ioctls_get */ + { AS(cap_fcntls_limit_args), (sy_call_t *)sys_cap_fcntls_limit, AUE_CAP_FCNTLS_LIMIT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 536 = cap_fcntls_limit */ + { AS(cap_fcntls_get_args), (sy_call_t *)sys_cap_fcntls_get, AUE_CAP_FCNTLS_GET, NULL, 0, 0, 0, SY_THR_STATIC }, /* 537 = cap_fcntls_get */ + { AS(bindat_args), (sy_call_t *)sys_bindat, AUE_BINDAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 538 = bindat */ + { AS(connectat_args), (sy_call_t *)sys_connectat, AUE_CONNECTAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 539 = connectat */ + { AS(chflagsat_args), (sy_call_t *)sys_chflagsat, AUE_CHFLAGSAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 540 = chflagsat */ + { AS(accept4_args), (sy_call_t *)sys_accept4, AUE_ACCEPT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 541 = accept4 */ + { AS(pipe2_args), (sy_call_t *)sys_pipe2, AUE_PIPE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 542 = pipe2 */ + { AS(freebsd32_aio_mlock_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 543 = freebsd32_aio_mlock */ +}; diff --git a/sys/compat/freebsd32/freebsd32_systrace_args.c b/sys/compat/freebsd32/freebsd32_systrace_args.c new file mode 100644 index 0000000..7417f0e --- /dev/null +++ b/sys/compat/freebsd32/freebsd32_systrace_args.c @@ -0,0 +1,10486 @@ +/* + * 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(__powerpc__) || defined(__mips__)) +#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; /* char * */ + iarg[1] = p->flags; /* int */ + iarg[2] = p->mode; /* int */ + *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; /* char * */ + uarg[1] = (intptr_t) p->link; /* char * */ + *n_args = 2; + break; + } + /* unlink */ + case 10: { + struct unlink_args *p = params; + uarg[0] = (intptr_t) p->path; /* char * */ + *n_args = 1; + break; + } + /* chdir */ + case 12: { + struct chdir_args *p = params; + uarg[0] = (intptr_t) p->path; /* char * */ + *n_args = 1; + break; + } + /* fchdir */ + case 13: { + struct fchdir_args *p = params; + iarg[0] = p->fd; /* int */ + *n_args = 1; + break; + } + /* mknod */ + case 14: { + struct mknod_args *p = params; + uarg[0] = (intptr_t) p->path; /* char * */ + iarg[1] = p->mode; /* int */ + iarg[2] = p->dev; /* int */ + *n_args = 3; + break; + } + /* chmod */ + case 15: { + struct chmod_args *p = params; + uarg[0] = (intptr_t) p->path; /* char * */ + iarg[1] = p->mode; /* int */ + *n_args = 2; + break; + } + /* chown */ + case 16: { + struct chown_args *p = params; + uarg[0] = (intptr_t) p->path; /* char * */ + iarg[1] = p->uid; /* int */ + iarg[2] = p->gid; /* int */ + *n_args = 3; + break; + } + /* obreak */ + case 17: { + struct obreak_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; /* char * */ + uarg[1] = (intptr_t) p->path; /* char * */ + iarg[2] = p->flags; /* int */ + uarg[3] = (intptr_t) p->data; /* caddr_t */ + *n_args = 4; + break; + } + /* unmount */ + case 22: { + struct unmount_args *p = params; + uarg[0] = (intptr_t) p->path; /* 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; + } + /* ptrace */ + case 26: { + struct 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] = p->buf; /* uint32_t */ + uarg[2] = p->len; /* uint32_t */ + iarg[3] = p->flags; /* int */ + uarg[4] = p->from; /* uint32_t */ + 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; /* caddr_t */ + 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; /* caddr_t */ + 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; /* caddr_t */ + 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; /* 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; + } + /* pipe */ + case 42: { + *n_args = 0; + break; + } + /* getegid */ + case 43: { + *n_args = 0; + break; + } + /* profil */ + case 44: { + struct profil_args *p = params; + uarg[0] = (intptr_t) p->samples; /* caddr_t */ + 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; /* char * */ + *n_args = 1; + break; + } + /* acct */ + case 51: { + struct acct_args *p = params; + uarg[0] = (intptr_t) p->path; /* 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; /* char * */ + *n_args = 1; + break; + } + /* symlink */ + case 57: { + struct symlink_args *p = params; + uarg[0] = (intptr_t) p->path; /* char * */ + uarg[1] = (intptr_t) p->link; /* char * */ + *n_args = 2; + break; + } + /* readlink */ + case 58: { + struct readlink_args *p = params; + uarg[0] = (intptr_t) p->path; /* 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; /* 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; /* int */ + *n_args = 1; + break; + } + /* chroot */ + case 61: { + struct chroot_args *p = params; + uarg[0] = (intptr_t) p->path; /* 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; + } + /* ovadvise */ + case 72: { + struct ovadvise_args *p = params; + iarg[0] = p->anom; /* 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; /* const 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; /* 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; + } + /* fcntl */ + case 92: { + struct fcntl_args *p = params; + iarg[0] = p->fd; /* int */ + iarg[1] = p->cmd; /* int */ + iarg[2] = p->arg; /* long */ + *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; /* caddr_t */ + 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; /* caddr_t */ + 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; /* caddr_t */ + 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; /* caddr_t */ + 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; /* int */ + *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; /* char * */ + uarg[1] = (intptr_t) p->to; /* 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; /* char * */ + iarg[1] = p->mode; /* int */ + *n_args = 2; + break; + } + /* sendto */ + case 133: { + struct sendto_args *p = params; + iarg[0] = p->s; /* int */ + uarg[1] = (intptr_t) p->buf; /* caddr_t */ + uarg[2] = p->len; /* size_t */ + iarg[3] = p->flags; /* int */ + uarg[4] = (intptr_t) p->to; /* caddr_t */ + 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; /* char * */ + iarg[1] = p->mode; /* int */ + *n_args = 2; + break; + } + /* rmdir */ + case 137: { + struct rmdir_args *p = params; + uarg[0] = (intptr_t) p->path; /* char * */ + *n_args = 1; + break; + } + /* freebsd32_utimes */ + case 138: { + struct freebsd32_utimes_args *p = params; + uarg[0] = (intptr_t) p->path; /* 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; /* char * */ + iarg[1] = p->cmd; /* int */ + iarg[2] = p->uid; /* int */ + uarg[3] = (intptr_t) p->arg; /* caddr_t */ + *n_args = 4; + break; + } + /* getfh */ + case 161: { + struct getfh_args *p = params; + uarg[0] = (intptr_t) p->fname; /* 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; + } + /* ntp_adjtime */ + case 176: { + struct ntp_adjtime_args *p = params; + uarg[0] = (intptr_t) p->tp; /* struct timex * */ + *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; + } + /* freebsd32_stat */ + case 188: { + struct freebsd32_stat_args *p = params; + uarg[0] = (intptr_t) p->path; /* char * */ + uarg[1] = (intptr_t) p->ub; /* struct stat32 * */ + *n_args = 2; + break; + } + /* freebsd32_fstat */ + case 189: { + struct freebsd32_fstat_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->ub; /* struct stat32 * */ + *n_args = 2; + break; + } + /* freebsd32_lstat */ + case 190: { + struct freebsd32_lstat_args *p = params; + uarg[0] = (intptr_t) p->path; /* char * */ + uarg[1] = (intptr_t) p->ub; /* struct stat32 * */ + *n_args = 2; + break; + } + /* pathconf */ + case 191: { + struct pathconf_args *p = params; + uarg[0] = (intptr_t) p->path; /* 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; + } + /* freebsd32_getdirentries */ + case 196: { + struct freebsd32_getdirentries_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->buf; /* char * */ + uarg[2] = p->count; /* u_int */ + uarg[3] = (intptr_t) p->basep; /* int32_t * */ + *n_args = 4; + 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; /* 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; /* 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_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; + } + /* clock_getcpuclockid2 */ + case 247: { + struct clock_getcpuclockid2_args *p = params; + iarg[0] = p->id; /* id_t */ + iarg[1] = p->which; /* int */ + uarg[2] = (intptr_t) p->clock_id; /* clockid_t * */ + *n_args = 3; + 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; + } + /* openbsd_poll */ + case 252: { + struct openbsd_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; + } + /* issetugid */ + case 253: { + *n_args = 0; + break; + } + /* lchown */ + case 254: { + struct lchown_args *p = params; + uarg[0] = (intptr_t) p->path; /* 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 sigevent * */ + *n_args = 4; + break; + } + /* getdents */ + case 272: { + struct getdents_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->buf; /* char * */ + uarg[2] = p->count; /* size_t */ + *n_args = 3; + break; + } + /* lchmod */ + case 274: { + struct lchmod_args *p = params; + uarg[0] = (intptr_t) p->path; /* char * */ + iarg[1] = p->mode; /* mode_t */ + *n_args = 2; + break; + } + /* lchown */ + case 275: { + struct lchown_args *p = params; + uarg[0] = (intptr_t) p->path; /* char * */ + uarg[1] = p->uid; /* uid_t */ + iarg[2] = p->gid; /* gid_t */ + *n_args = 3; + break; + } + /* freebsd32_lutimes */ + case 276: { + struct freebsd32_lutimes_args *p = params; + uarg[0] = (intptr_t) p->path; /* char * */ + uarg[1] = (intptr_t) p->tptr; /* struct timeval32 * */ + *n_args = 2; + break; + } + /* msync */ + case 277: { + 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; + } + /* nstat */ + case 278: { + struct nstat_args *p = params; + uarg[0] = (intptr_t) p->path; /* char * */ + uarg[1] = (intptr_t) p->ub; /* struct nstat * */ + *n_args = 2; + break; + } + /* nfstat */ + case 279: { + struct nfstat_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->sb; /* struct nstat * */ + *n_args = 2; + break; + } + /* nlstat */ + case 280: { + struct nlstat_args *p = params; + uarg[0] = (intptr_t) p->path; /* char * */ + uarg[1] = (intptr_t) p->ub; /* struct nstat * */ + *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; + } + /* fhstat */ + case 299: { + struct fhstat_args *p = params; + uarg[0] = (intptr_t) p->u_fhp; /* const struct fhandle * */ + uarg[1] = (intptr_t) p->sb; /* struct stat * */ + *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; + } + /* freebsd32_aio_cancel */ + case 316: { + struct freebsd32_aio_cancel_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->aiocbp; /* struct aiocb32 * */ + *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; + } + /* freebsd32_oaio_read */ + case 318: { + struct freebsd32_oaio_read_args *p = params; + uarg[0] = (intptr_t) p->aiocbp; /* struct oaiocb32 * */ + *n_args = 1; + break; + } + /* freebsd32_oaio_write */ + case 319: { + struct freebsd32_oaio_write_args *p = params; + uarg[0] = (intptr_t) p->aiocbp; /* struct oaiocb32 * */ + *n_args = 1; + break; + } + /* freebsd32_olio_listio */ + case 320: { + struct freebsd32_olio_listio_args *p = params; + iarg[0] = p->mode; /* int */ + uarg[1] = (intptr_t) p->acb_list; /* struct oaiocb32 *const * */ + iarg[2] = p->nent; /* int */ + uarg[3] = (intptr_t) p->sig; /* struct osigevent32 * */ + *n_args = 4; + 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; /* u_char * */ + uarg[1] = p->buflen; /* u_int */ + *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; + } + /* sched_rr_get_interval */ + case 334: { + struct sched_rr_get_interval_args *p = params; + iarg[0] = p->pid; /* pid_t */ + uarg[1] = (intptr_t) p->interval; /* struct timespec * */ + *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; + } + /* freebsd32_kevent */ + case 363: { + 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; + } + /* 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; /* 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; + } + /* getfsstat */ + case 395: { + struct getfsstat_args *p = params; + uarg[0] = (intptr_t) p->buf; /* struct statfs * */ + iarg[1] = p->bufsize; /* long */ + iarg[2] = p->flags; /* int */ + *n_args = 3; + break; + } + /* statfs */ + case 396: { + struct statfs_args *p = params; + uarg[0] = (intptr_t) p->path; /* char * */ + uarg[1] = (intptr_t) p->buf; /* struct statfs * */ + *n_args = 2; + break; + } + /* fstatfs */ + case 397: { + struct fstatfs_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->buf; /* struct statfs * */ + *n_args = 2; + break; + } + /* fhstatfs */ + case 398: { + struct fhstatfs_args *p = params; + uarg[0] = (intptr_t) p->u_fhp; /* const struct fhandle * */ + uarg[1] = (intptr_t) p->buf; /* struct statfs * */ + *n_args = 2; + 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; + } + /* freebsd32_umtx_lock */ + case 434: { + struct freebsd32_umtx_lock_args *p = params; + uarg[0] = (intptr_t) p->umtx; /* struct umtx * */ + *n_args = 1; + break; + } + /* freebsd32_umtx_unlock */ + case 435: { + struct freebsd32_umtx_unlock_args *p = params; + uarg[0] = (intptr_t) p->umtx; /* struct umtx * */ + *n_args = 1; + 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; /* 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; + } + /* sigqueue */ + case 456: { + struct sigqueue_args *p = params; + iarg[0] = p->pid; /* pid_t */ + iarg[1] = p->signum; /* int */ + uarg[2] = (intptr_t) p->value; /* void * */ + *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; + } + /* kmq_notify */ + case 461: { + struct kmq_notify_args *p = params; + iarg[0] = p->mqd; /* int */ + uarg[1] = (intptr_t) p->sigev; /* const struct sigevent * */ + *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; /* caddr_t */ + iarg[2] = p->mlen; /* int */ + uarg[3] = (intptr_t) p->to; /* caddr_t */ + 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; /* caddr_t */ + 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; /* caddr_t */ + 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; /* 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; /* caddr_t */ + 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; /* 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_open */ + case 482: { + struct shm_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; + } + /* 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; /* 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; /* 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_fstatat */ + case 493: { + struct freebsd32_fstatat_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->path; /* char * */ + uarg[2] = (intptr_t) p->buf; /* struct stat * */ + iarg[3] = p->flag; /* int */ + *n_args = 4; + break; + } + /* freebsd32_futimesat */ + case 494: { + struct freebsd32_futimesat_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->path; /* 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; /* char * */ + iarg[2] = p->fd2; /* int */ + uarg[3] = (intptr_t) p->path2; /* 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; /* 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; /* char * */ + iarg[2] = p->mode; /* mode_t */ + *n_args = 3; + break; + } + /* mknodat */ + case 498: { + struct mknodat_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->path; /* char * */ + iarg[2] = p->mode; /* mode_t */ + iarg[3] = p->dev; /* dev_t */ + *n_args = 4; + break; + } + /* openat */ + case 499: { + struct openat_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->path; /* 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; /* 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; /* 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; /* char * */ + iarg[1] = p->fd; /* int */ + uarg[2] = (intptr_t) p->path2; /* char * */ + *n_args = 3; + break; + } + /* unlinkat */ + case 503: { + struct unlinkat_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->path; /* 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; + } + /* closefrom */ + case 509: { + struct closefrom_args *p = params; + iarg[0] = p->lowfd; /* 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; /* char * */ + iarg[1] = p->name; /* int */ + *n_args = 2; + break; + } + /* cap_new */ + case 514: { + struct cap_new_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = p->rights; /* uint64_t */ + *n_args = 2; + break; + } + /* cap_rights_get */ + case 515: { + struct cap_rights_get_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->rightsp; /* uint64_t * */ + *n_args = 2; + 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; + } + /* 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] = p->rights; /* uint64_t */ + *n_args = 2; + break; + } + /* cap_ioctls_limit */ + case 534: { + struct cap_ioctls_limit_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->cmds; /* const u_long * */ + uarg[2] = p->ncmds; /* size_t */ + *n_args = 3; + break; + } + /* cap_ioctls_get */ + case 535: { + struct cap_ioctls_get_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->cmds; /* u_long * */ + 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; /* caddr_t */ + 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; /* caddr_t */ + 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 *__restrict */ + uarg[2] = (intptr_t) p->anamelen; /* __socklen_t *__restrict */ + 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; + } + 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(__powerpc__) || defined(__mips__)) +#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 = "void *"; + break; + case 2: + p = "size_t"; + break; + default: + break; + }; + break; + /* write */ + case 4: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "const void *"; + break; + case 2: + p = "size_t"; + break; + default: + break; + }; + break; + /* open */ + case 5: + switch(ndx) { + case 0: + p = "char *"; + break; + case 1: + p = "int"; + break; + case 2: + p = "int"; + 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 = "int *"; + break; + case 2: + p = "int"; + break; + case 3: + p = "struct rusage32 *"; + break; + default: + break; + }; + break; + /* link */ + case 9: + switch(ndx) { + case 0: + p = "char *"; + break; + case 1: + p = "char *"; + break; + default: + break; + }; + break; + /* unlink */ + case 10: + switch(ndx) { + case 0: + p = "char *"; + break; + default: + break; + }; + break; + /* chdir */ + case 12: + switch(ndx) { + case 0: + p = "char *"; + break; + default: + break; + }; + break; + /* fchdir */ + case 13: + switch(ndx) { + case 0: + p = "int"; + break; + default: + break; + }; + break; + /* mknod */ + case 14: + switch(ndx) { + case 0: + p = "char *"; + break; + case 1: + p = "int"; + break; + case 2: + p = "int"; + break; + default: + break; + }; + break; + /* chmod */ + case 15: + switch(ndx) { + case 0: + p = "char *"; + break; + case 1: + p = "int"; + break; + default: + break; + }; + break; + /* chown */ + case 16: + switch(ndx) { + case 0: + p = "char *"; + break; + case 1: + p = "int"; + break; + case 2: + p = "int"; + break; + default: + break; + }; + break; + /* obreak */ + case 17: + switch(ndx) { + case 0: + p = "char *"; + break; + default: + break; + }; + break; + /* getpid */ + case 20: + break; + /* mount */ + case 21: + switch(ndx) { + case 0: + p = "char *"; + break; + case 1: + p = "char *"; + break; + case 2: + p = "int"; + break; + case 3: + p = "caddr_t"; + break; + default: + break; + }; + break; + /* unmount */ + case 22: + switch(ndx) { + case 0: + p = "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; + /* 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 = "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 = "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 = "uint32_t"; + break; + case 2: + p = "uint32_t"; + break; + case 3: + p = "int"; + break; + case 4: + p = "uint32_t"; + break; + case 5: + p = "uint32_t"; + break; + default: + break; + }; + break; + /* accept */ + case 30: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "caddr_t"; + break; + case 2: + p = "int *"; + break; + default: + break; + }; + break; + /* getpeername */ + case 31: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "caddr_t"; + break; + case 2: + p = "int *"; + break; + default: + break; + }; + break; + /* getsockname */ + case 32: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "caddr_t"; + break; + case 2: + p = "int *"; + break; + default: + break; + }; + break; + /* access */ + case 33: + switch(ndx) { + case 0: + p = "char *"; + break; + case 1: + p = "int"; + break; + default: + break; + }; + break; + /* chflags */ + case 34: + switch(ndx) { + case 0: + p = "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; + /* pipe */ + case 42: + break; + /* getegid */ + case 43: + break; + /* profil */ + case 44: + switch(ndx) { + case 0: + p = "caddr_t"; + 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 = "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 = "char *"; + break; + case 1: + p = "u_int"; + break; + default: + break; + }; + break; + /* setlogin */ + case 50: + switch(ndx) { + case 0: + p = "char *"; + break; + default: + break; + }; + break; + /* acct */ + case 51: + switch(ndx) { + case 0: + p = "char *"; + break; + default: + break; + }; + break; + /* freebsd32_sigaltstack */ + case 53: + switch(ndx) { + case 0: + p = "struct sigaltstack32 *"; + break; + case 1: + p = "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 = "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 = "char *"; + break; + default: + break; + }; + break; + /* symlink */ + case 57: + switch(ndx) { + case 0: + p = "char *"; + break; + case 1: + p = "char *"; + break; + default: + break; + }; + break; + /* readlink */ + case 58: + switch(ndx) { + case 0: + p = "char *"; + break; + case 1: + p = "char *"; + break; + case 2: + p = "size_t"; + break; + default: + break; + }; + break; + /* freebsd32_execve */ + case 59: + switch(ndx) { + case 0: + p = "char *"; + break; + case 1: + p = "uint32_t *"; + break; + case 2: + p = "uint32_t *"; + break; + default: + break; + }; + break; + /* umask */ + case 60: + switch(ndx) { + case 0: + p = "int"; + break; + default: + break; + }; + break; + /* chroot */ + case 61: + switch(ndx) { + case 0: + p = "char *"; + break; + default: + break; + }; + break; + /* msync */ + case 65: + switch(ndx) { + case 0: + p = "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; + /* ovadvise */ + case 72: + switch(ndx) { + case 0: + p = "int"; + break; + default: + break; + }; + break; + /* munmap */ + case 73: + switch(ndx) { + case 0: + p = "void *"; + break; + case 1: + p = "size_t"; + break; + default: + break; + }; + break; + /* freebsd32_mprotect */ + case 74: + switch(ndx) { + case 0: + p = "const void *"; + break; + case 1: + p = "size_t"; + break; + case 2: + p = "int"; + break; + default: + break; + }; + break; + /* madvise */ + case 75: + switch(ndx) { + case 0: + p = "void *"; + break; + case 1: + p = "size_t"; + break; + case 2: + p = "int"; + break; + default: + break; + }; + break; + /* mincore */ + case 78: + switch(ndx) { + case 0: + p = "const void *"; + break; + case 1: + p = "size_t"; + break; + case 2: + p = "char *"; + break; + default: + break; + }; + break; + /* getgroups */ + case 79: + switch(ndx) { + case 0: + p = "u_int"; + break; + case 1: + p = "gid_t *"; + break; + default: + break; + }; + break; + /* setgroups */ + case 80: + switch(ndx) { + case 0: + p = "u_int"; + break; + case 1: + p = "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 = "struct itimerval32 *"; + break; + case 2: + p = "struct itimerval32 *"; + break; + default: + break; + }; + break; + /* swapon */ + case 85: + switch(ndx) { + case 0: + p = "char *"; + break; + default: + break; + }; + break; + /* freebsd32_getitimer */ + case 86: + switch(ndx) { + case 0: + p = "u_int"; + break; + case 1: + p = "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; + /* fcntl */ + case 92: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "int"; + break; + case 2: + p = "long"; + break; + default: + break; + }; + break; + /* freebsd32_select */ + case 93: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "fd_set *"; + break; + case 2: + p = "fd_set *"; + break; + case 3: + p = "fd_set *"; + break; + case 4: + p = "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 = "caddr_t"; + 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 = "caddr_t"; + 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 = "caddr_t"; + 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 = "struct timeval32 *"; + break; + case 1: + p = "struct timezone *"; + break; + default: + break; + }; + break; + /* freebsd32_getrusage */ + case 117: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "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 = "caddr_t"; + break; + case 4: + p = "int *"; + break; + default: + break; + }; + break; + /* freebsd32_readv */ + case 120: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "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 = "struct iovec32 *"; + break; + case 2: + p = "u_int"; + break; + default: + break; + }; + break; + /* freebsd32_settimeofday */ + case 122: + switch(ndx) { + case 0: + p = "struct timeval32 *"; + break; + case 1: + p = "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 = "int"; + 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 = "char *"; + break; + case 1: + p = "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 = "char *"; + break; + case 1: + p = "int"; + break; + default: + break; + }; + break; + /* sendto */ + case 133: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "caddr_t"; + break; + case 2: + p = "size_t"; + break; + case 3: + p = "int"; + break; + case 4: + p = "caddr_t"; + 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 = "int *"; + break; + default: + break; + }; + break; + /* mkdir */ + case 136: + switch(ndx) { + case 0: + p = "char *"; + break; + case 1: + p = "int"; + break; + default: + break; + }; + break; + /* rmdir */ + case 137: + switch(ndx) { + case 0: + p = "char *"; + break; + default: + break; + }; + break; + /* freebsd32_utimes */ + case 138: + switch(ndx) { + case 0: + p = "char *"; + break; + case 1: + p = "struct timeval32 *"; + break; + default: + break; + }; + break; + /* freebsd32_adjtime */ + case 140: + switch(ndx) { + case 0: + p = "struct timeval32 *"; + break; + case 1: + p = "struct timeval32 *"; + break; + default: + break; + }; + break; + /* setsid */ + case 147: + break; + /* quotactl */ + case 148: + switch(ndx) { + case 0: + p = "char *"; + break; + case 1: + p = "int"; + break; + case 2: + p = "int"; + break; + case 3: + p = "caddr_t"; + break; + default: + break; + }; + break; + /* getfh */ + case 161: + switch(ndx) { + case 0: + p = "char *"; + break; + case 1: + p = "struct fhandle *"; + break; + default: + break; + }; + break; + /* freebsd32_sysarch */ + case 165: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "char *"; + break; + default: + break; + }; + break; + /* rtprio */ + case 166: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "pid_t"; + break; + case 2: + p = "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; + /* ntp_adjtime */ + case 176: + switch(ndx) { + case 0: + p = "struct timex *"; + 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; + /* freebsd32_stat */ + case 188: + switch(ndx) { + case 0: + p = "char *"; + break; + case 1: + p = "struct stat32 *"; + break; + default: + break; + }; + break; + /* freebsd32_fstat */ + case 189: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "struct stat32 *"; + break; + default: + break; + }; + break; + /* freebsd32_lstat */ + case 190: + switch(ndx) { + case 0: + p = "char *"; + break; + case 1: + p = "struct stat32 *"; + break; + default: + break; + }; + break; + /* pathconf */ + case 191: + switch(ndx) { + case 0: + p = "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 = "struct rlimit *"; + break; + default: + break; + }; + break; + /* setrlimit */ + case 195: + switch(ndx) { + case 0: + p = "u_int"; + break; + case 1: + p = "struct rlimit *"; + break; + default: + break; + }; + break; + /* freebsd32_getdirentries */ + case 196: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "char *"; + break; + case 2: + p = "u_int"; + break; + case 3: + p = "int32_t *"; + break; + default: + break; + }; + break; + /* nosys */ + case 198: + break; + /* freebsd32_sysctl */ + case 202: + switch(ndx) { + case 0: + p = "int *"; + break; + case 1: + p = "u_int"; + break; + case 2: + p = "void *"; + break; + case 3: + p = "uint32_t *"; + break; + case 4: + p = "void *"; + break; + case 5: + p = "uint32_t"; + break; + default: + break; + }; + break; + /* mlock */ + case 203: + switch(ndx) { + case 0: + p = "const void *"; + break; + case 1: + p = "size_t"; + break; + default: + break; + }; + break; + /* munlock */ + case 204: + switch(ndx) { + case 0: + p = "const void *"; + break; + case 1: + p = "size_t"; + break; + default: + break; + }; + break; + /* undelete */ + case 205: + switch(ndx) { + case 0: + p = "char *"; + break; + default: + break; + }; + break; + /* freebsd32_futimes */ + case 206: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "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 = "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 = "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 = "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 = "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 = "void *"; + break; + case 2: + p = "int"; + break; + default: + break; + }; + break; + /* shmdt */ + case 230: + switch(ndx) { + case 0: + p = "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 = "struct timespec32 *"; + break; + default: + break; + }; + break; + /* freebsd32_clock_settime */ + case 233: + switch(ndx) { + case 0: + p = "clockid_t"; + break; + case 1: + p = "const struct timespec32 *"; + break; + default: + break; + }; + break; + /* freebsd32_clock_getres */ + case 234: + switch(ndx) { + case 0: + p = "clockid_t"; + break; + case 1: + p = "struct timespec32 *"; + break; + default: + break; + }; + break; + /* freebsd32_nanosleep */ + case 240: + switch(ndx) { + case 0: + p = "const struct timespec32 *"; + break; + case 1: + p = "struct timespec32 *"; + break; + default: + break; + }; + break; + /* ffclock_getcounter */ + case 241: + switch(ndx) { + case 0: + p = "ffcounter *"; + break; + default: + break; + }; + break; + /* ffclock_setestimate */ + case 242: + switch(ndx) { + case 0: + p = "struct ffclock_estimate *"; + break; + default: + break; + }; + break; + /* ffclock_getestimate */ + case 243: + switch(ndx) { + case 0: + p = "struct ffclock_estimate *"; + break; + default: + break; + }; + break; + /* clock_getcpuclockid2 */ + case 247: + switch(ndx) { + case 0: + p = "id_t"; + break; + case 1: + p = "int"; + break; + case 2: + p = "clockid_t *"; + break; + default: + break; + }; + break; + /* minherit */ + case 250: + switch(ndx) { + case 0: + p = "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; + /* openbsd_poll */ + case 252: + switch(ndx) { + case 0: + p = "struct pollfd *"; + break; + case 1: + p = "u_int"; + break; + case 2: + p = "int"; + break; + default: + break; + }; + break; + /* issetugid */ + case 253: + break; + /* lchown */ + case 254: + switch(ndx) { + case 0: + p = "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 = "struct aiocb32 *"; + break; + default: + break; + }; + break; + /* freebsd32_aio_write */ + case 256: + switch(ndx) { + case 0: + p = "struct aiocb32 *"; + break; + default: + break; + }; + break; + /* freebsd32_lio_listio */ + case 257: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "struct aiocb32 *const *"; + break; + case 2: + p = "int"; + break; + case 3: + p = "struct sigevent *"; + break; + default: + break; + }; + break; + /* getdents */ + case 272: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "char *"; + break; + case 2: + p = "size_t"; + break; + default: + break; + }; + break; + /* lchmod */ + case 274: + switch(ndx) { + case 0: + p = "char *"; + break; + case 1: + p = "mode_t"; + break; + default: + break; + }; + break; + /* lchown */ + case 275: + switch(ndx) { + case 0: + p = "char *"; + break; + case 1: + p = "uid_t"; + break; + case 2: + p = "gid_t"; + break; + default: + break; + }; + break; + /* freebsd32_lutimes */ + case 276: + switch(ndx) { + case 0: + p = "char *"; + break; + case 1: + p = "struct timeval32 *"; + break; + default: + break; + }; + break; + /* msync */ + case 277: + switch(ndx) { + case 0: + p = "void *"; + break; + case 1: + p = "size_t"; + break; + case 2: + p = "int"; + break; + default: + break; + }; + break; + /* nstat */ + case 278: + switch(ndx) { + case 0: + p = "char *"; + break; + case 1: + p = "struct nstat *"; + break; + default: + break; + }; + break; + /* nfstat */ + case 279: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "struct nstat *"; + break; + default: + break; + }; + break; + /* nlstat */ + case 280: + switch(ndx) { + case 0: + p = "char *"; + break; + case 1: + p = "struct nstat *"; + break; + default: + break; + }; + break; + /* freebsd32_preadv */ + case 289: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "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 = "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 = "const struct fhandle *"; + break; + case 1: + p = "int"; + break; + default: + break; + }; + break; + /* fhstat */ + case 299: + switch(ndx) { + case 0: + p = "const struct fhandle *"; + break; + case 1: + p = "struct stat *"; + 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 = "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 = "const char *"; + break; + default: + break; + }; + break; + /* kldload */ + case 304: + switch(ndx) { + case 0: + p = "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 = "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 = "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 = "struct aiocb32 *"; + break; + default: + break; + }; + break; + /* freebsd32_aio_suspend */ + case 315: + switch(ndx) { + case 0: + p = "struct aiocb32 *const *"; + break; + case 1: + p = "int"; + break; + case 2: + p = "const struct timespec32 *"; + break; + default: + break; + }; + break; + /* freebsd32_aio_cancel */ + case 316: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "struct aiocb32 *"; + break; + default: + break; + }; + break; + /* freebsd32_aio_error */ + case 317: + switch(ndx) { + case 0: + p = "struct aiocb32 *"; + break; + default: + break; + }; + break; + /* freebsd32_oaio_read */ + case 318: + switch(ndx) { + case 0: + p = "struct oaiocb32 *"; + break; + default: + break; + }; + break; + /* freebsd32_oaio_write */ + case 319: + switch(ndx) { + case 0: + p = "struct oaiocb32 *"; + break; + default: + break; + }; + break; + /* freebsd32_olio_listio */ + case 320: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "struct oaiocb32 *const *"; + break; + case 2: + p = "int"; + break; + case 3: + p = "struct osigevent32 *"; + 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 = "u_char *"; + break; + case 1: + p = "u_int"; + break; + default: + break; + }; + break; + /* sched_setparam */ + case 327: + switch(ndx) { + case 0: + p = "pid_t"; + break; + case 1: + p = "const struct sched_param *"; + break; + default: + break; + }; + break; + /* sched_getparam */ + case 328: + switch(ndx) { + case 0: + p = "pid_t"; + break; + case 1: + p = "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 = "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; + /* sched_rr_get_interval */ + case 334: + switch(ndx) { + case 0: + p = "pid_t"; + break; + case 1: + p = "struct timespec *"; + break; + default: + break; + }; + break; + /* utrace */ + case 335: + switch(ndx) { + case 0: + p = "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 = "void *"; + break; + default: + break; + }; + break; + /* freebsd32_jail */ + case 338: + switch(ndx) { + case 0: + p = "struct jail32 *"; + break; + default: + break; + }; + break; + /* sigprocmask */ + case 340: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "const sigset_t *"; + break; + case 2: + p = "sigset_t *"; + break; + default: + break; + }; + break; + /* sigsuspend */ + case 341: + switch(ndx) { + case 0: + p = "const sigset_t *"; + break; + default: + break; + }; + break; + /* sigpending */ + case 343: + switch(ndx) { + case 0: + p = "sigset_t *"; + break; + default: + break; + }; + break; + /* freebsd32_sigtimedwait */ + case 345: + switch(ndx) { + case 0: + p = "const sigset_t *"; + break; + case 1: + p = "siginfo_t *"; + break; + case 2: + p = "const struct timespec *"; + break; + default: + break; + }; + break; + /* freebsd32_sigwaitinfo */ + case 346: + switch(ndx) { + case 0: + p = "const sigset_t *"; + break; + case 1: + p = "siginfo_t *"; + break; + default: + break; + }; + break; + /* __acl_get_file */ + case 347: + switch(ndx) { + case 0: + p = "const char *"; + break; + case 1: + p = "acl_type_t"; + break; + case 2: + p = "struct acl *"; + break; + default: + break; + }; + break; + /* __acl_set_file */ + case 348: + switch(ndx) { + case 0: + p = "const char *"; + break; + case 1: + p = "acl_type_t"; + break; + case 2: + p = "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 = "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 = "struct acl *"; + break; + default: + break; + }; + break; + /* __acl_delete_file */ + case 351: + switch(ndx) { + case 0: + p = "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 = "const char *"; + break; + case 1: + p = "acl_type_t"; + break; + case 2: + p = "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 = "struct acl *"; + break; + default: + break; + }; + break; + /* extattrctl */ + case 355: + switch(ndx) { + case 0: + p = "const char *"; + break; + case 1: + p = "int"; + break; + case 2: + p = "const char *"; + break; + case 3: + p = "int"; + break; + case 4: + p = "const char *"; + break; + default: + break; + }; + break; + /* extattr_set_file */ + case 356: + switch(ndx) { + case 0: + p = "const char *"; + break; + case 1: + p = "int"; + break; + case 2: + p = "const char *"; + break; + case 3: + p = "void *"; + break; + case 4: + p = "size_t"; + break; + default: + break; + }; + break; + /* extattr_get_file */ + case 357: + switch(ndx) { + case 0: + p = "const char *"; + break; + case 1: + p = "int"; + break; + case 2: + p = "const char *"; + break; + case 3: + p = "void *"; + break; + case 4: + p = "size_t"; + break; + default: + break; + }; + break; + /* extattr_delete_file */ + case 358: + switch(ndx) { + case 0: + p = "const char *"; + break; + case 1: + p = "int"; + break; + case 2: + p = "const char *"; + break; + default: + break; + }; + break; + /* freebsd32_aio_waitcomplete */ + case 359: + switch(ndx) { + case 0: + p = "struct aiocb32 **"; + break; + case 1: + p = "struct timespec32 *"; + break; + default: + break; + }; + break; + /* getresuid */ + case 360: + switch(ndx) { + case 0: + p = "uid_t *"; + break; + case 1: + p = "uid_t *"; + break; + case 2: + p = "uid_t *"; + break; + default: + break; + }; + break; + /* getresgid */ + case 361: + switch(ndx) { + case 0: + p = "gid_t *"; + break; + case 1: + p = "gid_t *"; + break; + case 2: + p = "gid_t *"; + break; + default: + break; + }; + break; + /* kqueue */ + case 362: + break; + /* freebsd32_kevent */ + case 363: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "const struct kevent32 *"; + break; + case 2: + p = "int"; + break; + case 3: + p = "struct kevent32 *"; + break; + case 4: + p = "int"; + break; + case 5: + p = "const struct timespec32 *"; + break; + default: + break; + }; + break; + /* extattr_set_fd */ + case 371: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "int"; + break; + case 2: + p = "const char *"; + break; + case 3: + p = "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 = "const char *"; + break; + case 3: + p = "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 = "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 = "char *"; + break; + case 1: + p = "int"; + break; + default: + break; + }; + break; + /* freebsd32_nmount */ + case 378: + switch(ndx) { + case 0: + p = "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 = "const char *"; + break; + case 2: + p = "char *"; + break; + case 3: + p = "int"; + break; + default: + break; + }; + break; + /* lchflags */ + case 391: + switch(ndx) { + case 0: + p = "const char *"; + break; + case 1: + p = "u_long"; + break; + default: + break; + }; + break; + /* uuidgen */ + case 392: + switch(ndx) { + case 0: + p = "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 = "struct sf_hdtr32 *"; + break; + case 6: + p = "off_t *"; + break; + case 7: + p = "int"; + break; + default: + break; + }; + break; + /* getfsstat */ + case 395: + switch(ndx) { + case 0: + p = "struct statfs *"; + break; + case 1: + p = "long"; + break; + case 2: + p = "int"; + break; + default: + break; + }; + break; + /* statfs */ + case 396: + switch(ndx) { + case 0: + p = "char *"; + break; + case 1: + p = "struct statfs *"; + break; + default: + break; + }; + break; + /* fstatfs */ + case 397: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "struct statfs *"; + break; + default: + break; + }; + break; + /* fhstatfs */ + case 398: + switch(ndx) { + case 0: + p = "const struct fhandle *"; + break; + case 1: + p = "struct statfs *"; + 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 = "semid_t *"; + break; + case 1: + p = "unsigned int"; + break; + default: + break; + }; + break; + /* freebsd32_ksem_open */ + case 405: + switch(ndx) { + case 0: + p = "semid_t *"; + break; + case 1: + p = "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 = "const char *"; + break; + default: + break; + }; + break; + /* ksem_getvalue */ + case 407: + switch(ndx) { + case 0: + p = "semid_t"; + break; + case 1: + p = "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 = "const char *"; + break; + case 1: + p = "int"; + break; + case 2: + p = "const char *"; + break; + case 3: + p = "void *"; + break; + case 4: + p = "size_t"; + break; + default: + break; + }; + break; + /* extattr_get_link */ + case 413: + switch(ndx) { + case 0: + p = "const char *"; + break; + case 1: + p = "int"; + break; + case 2: + p = "const char *"; + break; + case 3: + p = "void *"; + break; + case 4: + p = "size_t"; + break; + default: + break; + }; + break; + /* extattr_delete_link */ + case 414: + switch(ndx) { + case 0: + p = "const char *"; + break; + case 1: + p = "int"; + break; + case 2: + p = "const char *"; + break; + default: + break; + }; + break; + /* freebsd32_sigaction */ + case 416: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "struct sigaction32 *"; + break; + case 2: + p = "struct sigaction32 *"; + break; + default: + break; + }; + break; + /* freebsd32_sigreturn */ + case 417: + switch(ndx) { + case 0: + p = "const struct freebsd32_ucontext *"; + break; + default: + break; + }; + break; + /* freebsd32_getcontext */ + case 421: + switch(ndx) { + case 0: + p = "struct freebsd32_ucontext *"; + break; + default: + break; + }; + break; + /* freebsd32_setcontext */ + case 422: + switch(ndx) { + case 0: + p = "const struct freebsd32_ucontext *"; + break; + default: + break; + }; + break; + /* freebsd32_swapcontext */ + case 423: + switch(ndx) { + case 0: + p = "struct freebsd32_ucontext *"; + break; + case 1: + p = "const struct freebsd32_ucontext *"; + break; + default: + break; + }; + break; + /* __acl_get_link */ + case 425: + switch(ndx) { + case 0: + p = "const char *"; + break; + case 1: + p = "acl_type_t"; + break; + case 2: + p = "struct acl *"; + break; + default: + break; + }; + break; + /* __acl_set_link */ + case 426: + switch(ndx) { + case 0: + p = "const char *"; + break; + case 1: + p = "acl_type_t"; + break; + case 2: + p = "struct acl *"; + break; + default: + break; + }; + break; + /* __acl_delete_link */ + case 427: + switch(ndx) { + case 0: + p = "const char *"; + break; + case 1: + p = "acl_type_t"; + break; + default: + break; + }; + break; + /* __acl_aclcheck_link */ + case 428: + switch(ndx) { + case 0: + p = "const char *"; + break; + case 1: + p = "acl_type_t"; + break; + case 2: + p = "struct acl *"; + break; + default: + break; + }; + break; + /* sigwait */ + case 429: + switch(ndx) { + case 0: + p = "const sigset_t *"; + break; + case 1: + p = "int *"; + break; + default: + break; + }; + break; + /* thr_exit */ + case 431: + switch(ndx) { + case 0: + p = "long *"; + break; + default: + break; + }; + break; + /* thr_self */ + case 432: + switch(ndx) { + case 0: + p = "long *"; + break; + default: + break; + }; + break; + /* thr_kill */ + case 433: + switch(ndx) { + case 0: + p = "long"; + break; + case 1: + p = "int"; + break; + default: + break; + }; + break; + /* freebsd32_umtx_lock */ + case 434: + switch(ndx) { + case 0: + p = "struct umtx *"; + break; + default: + break; + }; + break; + /* freebsd32_umtx_unlock */ + case 435: + switch(ndx) { + case 0: + p = "struct umtx *"; + 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 = "void *"; + break; + case 3: + p = "size_t"; + break; + default: + break; + }; + break; + /* extattr_list_file */ + case 438: + switch(ndx) { + case 0: + p = "const char *"; + break; + case 1: + p = "int"; + break; + case 2: + p = "void *"; + break; + case 3: + p = "size_t"; + break; + default: + break; + }; + break; + /* extattr_list_link */ + case 439: + switch(ndx) { + case 0: + p = "const char *"; + break; + case 1: + p = "int"; + break; + case 2: + p = "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 = "const struct timespec32 *"; + break; + default: + break; + }; + break; + /* freebsd32_thr_suspend */ + case 442: + switch(ndx) { + case 0: + p = "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 = "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 = "void *"; + break; + case 2: + p = "u_int"; + break; + default: + break; + }; + break; + /* getauid */ + case 447: + switch(ndx) { + case 0: + p = "uid_t *"; + break; + default: + break; + }; + break; + /* setauid */ + case 448: + switch(ndx) { + case 0: + p = "uid_t *"; + break; + default: + break; + }; + break; + /* getaudit */ + case 449: + switch(ndx) { + case 0: + p = "struct auditinfo *"; + break; + default: + break; + }; + break; + /* setaudit */ + case 450: + switch(ndx) { + case 0: + p = "struct auditinfo *"; + break; + default: + break; + }; + break; + /* getaudit_addr */ + case 451: + switch(ndx) { + case 0: + p = "struct auditinfo_addr *"; + break; + case 1: + p = "u_int"; + break; + default: + break; + }; + break; + /* setaudit_addr */ + case 452: + switch(ndx) { + case 0: + p = "struct auditinfo_addr *"; + break; + case 1: + p = "u_int"; + break; + default: + break; + }; + break; + /* auditctl */ + case 453: + switch(ndx) { + case 0: + p = "char *"; + break; + default: + break; + }; + break; + /* freebsd32_umtx_op */ + case 454: + switch(ndx) { + case 0: + p = "void *"; + break; + case 1: + p = "int"; + break; + case 2: + p = "u_long"; + break; + case 3: + p = "void *"; + break; + case 4: + p = "void *"; + break; + default: + break; + }; + break; + /* freebsd32_thr_new */ + case 455: + switch(ndx) { + case 0: + p = "struct thr_param32 *"; + break; + case 1: + p = "int"; + break; + default: + break; + }; + break; + /* sigqueue */ + case 456: + switch(ndx) { + case 0: + p = "pid_t"; + break; + case 1: + p = "int"; + break; + case 2: + p = "void *"; + break; + default: + break; + }; + break; + /* freebsd32_kmq_open */ + case 457: + switch(ndx) { + case 0: + p = "const char *"; + break; + case 1: + p = "int"; + break; + case 2: + p = "mode_t"; + break; + case 3: + p = "const struct mq_attr32 *"; + break; + default: + break; + }; + break; + /* freebsd32_kmq_setattr */ + case 458: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "const struct mq_attr32 *"; + break; + case 2: + p = "struct mq_attr32 *"; + break; + default: + break; + }; + break; + /* freebsd32_kmq_timedreceive */ + case 459: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "char *"; + break; + case 2: + p = "size_t"; + break; + case 3: + p = "unsigned *"; + break; + case 4: + p = "const struct timespec32 *"; + break; + default: + break; + }; + break; + /* freebsd32_kmq_timedsend */ + case 460: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "const char *"; + break; + case 2: + p = "size_t"; + break; + case 3: + p = "unsigned"; + break; + case 4: + p = "const struct timespec32 *"; + break; + default: + break; + }; + break; + /* kmq_notify */ + case 461: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "const struct sigevent *"; + break; + default: + break; + }; + break; + /* kmq_unlink */ + case 462: + switch(ndx) { + case 0: + p = "const char *"; + break; + default: + break; + }; + break; + /* abort2 */ + case 463: + switch(ndx) { + case 0: + p = "const char *"; + break; + case 1: + p = "int"; + break; + case 2: + p = "void **"; + break; + default: + break; + }; + break; + /* thr_set_name */ + case 464: + switch(ndx) { + case 0: + p = "long"; + break; + case 1: + p = "const char *"; + break; + default: + break; + }; + break; + /* freebsd32_aio_fsync */ + case 465: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "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 = "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 = "caddr_t"; + break; + case 2: + p = "int"; + break; + case 3: + p = "caddr_t"; + break; + case 4: + p = "__socklen_t"; + break; + case 5: + p = "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 = "struct iovec *"; + break; + case 2: + p = "int"; + break; + case 3: + p = "caddr_t"; + break; + case 4: + p = "__socklen_t"; + break; + case 5: + p = "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 = "struct iovec *"; + break; + case 2: + p = "int"; + break; + case 3: + p = "struct sockaddr *"; + break; + case 4: + p = "__socklen_t *"; + break; + case 5: + p = "struct sctp_sndrcvinfo *"; + break; + case 6: + p = "int *"; + break; + default: + break; + }; + break; +#ifdef PAD64_REQUIRED + /* freebsd32_pread */ + case 475: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "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 = "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 = "caddr_t"; + 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 = "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 = "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 = "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 = "caddr_t"; + 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 = "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_open */ + case 482: + switch(ndx) { + case 0: + p = "const char *"; + break; + case 1: + p = "int"; + break; + case 2: + p = "mode_t"; + break; + default: + break; + }; + break; + /* shm_unlink */ + case 483: + switch(ndx) { + case 0: + p = "const char *"; + break; + default: + break; + }; + break; + /* cpuset */ + case 484: + switch(ndx) { + case 0: + p = "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 = "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 = "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 = "const cpuset_t *"; + break; + default: + break; + }; + break; + /* faccessat */ + case 489: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "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 = "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 = "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 = "uint32_t *"; + break; + case 2: + p = "uint32_t *"; + break; + default: + break; + }; + break; + /* freebsd32_fstatat */ + case 493: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "char *"; + break; + case 2: + p = "struct stat *"; + break; + case 3: + p = "int"; + break; + default: + break; + }; + break; + /* freebsd32_futimesat */ + case 494: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "char *"; + break; + case 2: + p = "struct timeval *"; + break; + default: + break; + }; + break; + /* linkat */ + case 495: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "char *"; + break; + case 2: + p = "int"; + break; + case 3: + p = "char *"; + break; + case 4: + p = "int"; + break; + default: + break; + }; + break; + /* mkdirat */ + case 496: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "char *"; + break; + case 2: + p = "mode_t"; + break; + default: + break; + }; + break; + /* mkfifoat */ + case 497: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "char *"; + break; + case 2: + p = "mode_t"; + break; + default: + break; + }; + break; + /* mknodat */ + case 498: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "char *"; + break; + case 2: + p = "mode_t"; + break; + case 3: + p = "dev_t"; + break; + default: + break; + }; + break; + /* openat */ + case 499: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "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 = "char *"; + break; + case 2: + p = "char *"; + break; + case 3: + p = "size_t"; + break; + default: + break; + }; + break; + /* renameat */ + case 501: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "char *"; + break; + case 2: + p = "int"; + break; + case 3: + p = "const char *"; + break; + default: + break; + }; + break; + /* symlinkat */ + case 502: + switch(ndx) { + case 0: + p = "char *"; + break; + case 1: + p = "int"; + break; + case 2: + p = "char *"; + break; + default: + break; + }; + break; + /* unlinkat */ + case 503: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "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 = "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 = "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; + /* closefrom */ + case 509: + 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 = "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 = "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 = "struct shmid_ds32 *"; + break; + default: + break; + }; + break; + /* lpathconf */ + case 513: + switch(ndx) { + case 0: + p = "char *"; + break; + case 1: + p = "int"; + break; + default: + break; + }; + break; + /* cap_new */ + case 514: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "uint64_t"; + break; + default: + break; + }; + break; + /* cap_rights_get */ + case 515: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "uint64_t *"; + break; + default: + break; + }; + break; + /* cap_enter */ + case 516: + break; + /* cap_getmode */ + case 517: + switch(ndx) { + case 0: + p = "u_int *"; + break; + default: + break; + }; + break; + /* freebsd32_pselect */ + case 522: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "fd_set *"; + break; + case 2: + p = "fd_set *"; + break; + case 3: + p = "fd_set *"; + break; + case 4: + p = "const struct timespec32 *"; + break; + case 5: + p = "const sigset_t *"; + break; + default: + break; + }; + break; + /* getloginclass */ + case 523: + switch(ndx) { + case 0: + p = "char *"; + break; + case 1: + p = "size_t"; + break; + default: + break; + }; + break; + /* setloginclass */ + case 524: + switch(ndx) { + case 0: + p = "const char *"; + break; + default: + break; + }; + break; + /* rctl_get_racct */ + case 525: + switch(ndx) { + case 0: + p = "const void *"; + break; + case 1: + p = "size_t"; + break; + case 2: + p = "void *"; + break; + case 3: + p = "size_t"; + break; + default: + break; + }; + break; + /* rctl_get_rules */ + case 526: + switch(ndx) { + case 0: + p = "const void *"; + break; + case 1: + p = "size_t"; + break; + case 2: + p = "void *"; + break; + case 3: + p = "size_t"; + break; + default: + break; + }; + break; + /* rctl_get_limits */ + case 527: + switch(ndx) { + case 0: + p = "const void *"; + break; + case 1: + p = "size_t"; + break; + case 2: + p = "void *"; + break; + case 3: + p = "size_t"; + break; + default: + break; + }; + break; + /* rctl_add_rule */ + case 528: + switch(ndx) { + case 0: + p = "const void *"; + break; + case 1: + p = "size_t"; + break; + case 2: + p = "void *"; + break; + case 3: + p = "size_t"; + break; + default: + break; + }; + break; + /* rctl_remove_rule */ + case 529: + switch(ndx) { + case 0: + p = "const void *"; + break; + case 1: + p = "size_t"; + break; + case 2: + p = "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 = "int *"; + break; + case 5: + p = "int"; + break; + case 6: + p = "struct wrusage32 *"; + break; + case 7: + p = "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 = "int *"; + break; + case 4: + p = "int"; + break; + case 5: + p = "struct wrusage32 *"; + break; + case 6: + p = "siginfo_t *"; + break; + default: + break; + }; + break; +#endif + /* cap_rights_limit */ + case 533: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "uint64_t"; + break; + default: + break; + }; + break; + /* cap_ioctls_limit */ + case 534: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "const u_long *"; + break; + case 2: + p = "size_t"; + break; + default: + break; + }; + break; + /* cap_ioctls_get */ + case 535: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "u_long *"; + 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 = "uint32_t *"; + break; + default: + break; + }; + break; + /* bindat */ + case 538: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "int"; + break; + case 2: + p = "caddr_t"; + 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 = "caddr_t"; + break; + case 3: + p = "int"; + break; + default: + break; + }; + break; + /* chflagsat */ + case 540: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "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 = "struct sockaddr *__restrict"; + break; + case 2: + p = "__socklen_t *__restrict"; + break; + case 3: + p = "int"; + break; + default: + break; + }; + break; + /* pipe2 */ + case 542: + switch(ndx) { + case 0: + p = "int *"; + break; + case 1: + p = "int"; + break; + default: + break; + }; + break; + /* freebsd32_aio_mlock */ + case 543: + switch(ndx) { + case 0: + p = "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(__powerpc__) || defined(__mips__)) +#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; + /* mknod */ + case 14: + 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; + /* obreak */ + case 17: + if (ndx == 0 || ndx == 1) + p = "int"; + 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: + /* 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; + /* pipe */ + case 42: + /* 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; + /* ovadvise */ + case 72: + 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; + /* 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; + /* 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; + /* freebsd32_stat */ + case 188: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* freebsd32_fstat */ + case 189: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* freebsd32_lstat */ + case 190: + 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; + /* freebsd32_getdirentries */ + case 196: + 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 = "int"; + 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_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; + /* 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; + /* openbsd_poll */ + case 252: + 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; + /* getdents */ + case 272: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* lchmod */ + case 274: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* lchown */ + case 275: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* freebsd32_lutimes */ + case 276: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* msync */ + case 277: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* nstat */ + case 278: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* nfstat */ + case 279: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* nlstat */ + case 280: + 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; + /* fhstat */ + case 299: + 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; + /* freebsd32_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; + /* freebsd32_oaio_read */ + case 318: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* freebsd32_oaio_write */ + case 319: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* freebsd32_olio_listio */ + case 320: + 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; + /* 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: + /* freebsd32_kevent */ + case 363: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* 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; + /* getfsstat */ + case 395: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* statfs */ + case 396: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* fstatfs */ + case 397: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* fhstatfs */ + case 398: + 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; + /* freebsd32_umtx_lock */ + case 434: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* freebsd32_umtx_unlock */ + case 435: + 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; + /* 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; + /* 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 = "caddr_t"; + 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 = "caddr_t"; + 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_open */ + case 482: + 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_fstatat */ + case 493: + 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; + /* mknodat */ + case 498: + 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 = "int"; + 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; + /* closefrom */ + case 509: + 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_new */ + case 514: + 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; + /* 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; + /* cap_ioctls_limit */ + case 534: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* 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; + 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 0000000..9282275 --- /dev/null +++ b/sys/compat/freebsd32/freebsd32_util.h @@ -0,0 +1,118 @@ +/*- + * 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__) || defined(__ia64__) +#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(syscallname) { \ + .new_sysent = { \ + .sy_narg = (sizeof(struct syscallname ## _args ) \ + / sizeof(register_t)), \ + .sy_call = (sy_call_t *)& syscallname, \ + }, \ + .syscall_no = FREEBSD32_SYS_##syscallname \ +} + +#define SYSCALL32_INIT_HELPER_COMPAT(syscallname) { \ + .new_sysent = { \ + .sy_narg = (sizeof(struct syscallname ## _args ) \ + / sizeof(register_t)), \ + .sy_call = (sy_call_t *)& sys_ ## syscallname, \ + }, \ + .syscall_no = FREEBSD32_SYS_##syscallname \ +} + +int syscall32_register(int *offset, struct sysent *new_sysent, + struct sysent *old_sysent); +int syscall32_deregister(int *offset, struct sysent *old_sysent); +int syscall32_module_handler(struct module *mod, int what, void *arg); +int syscall32_helper_register(struct syscall_helper_data *sd); +int syscall32_helper_unregister(struct syscall_helper_data *sd); + +struct iovec32; +struct rusage32; +register_t *freebsd32_copyout_strings(struct image_params *imgp); +int freebsd32_copyiniov(struct iovec32 *iovp, u_int iovcnt, + struct iovec **iov, int error); +void freebsd32_rusage_out(const struct rusage *s, struct rusage32 *s32); + +struct image_args; +int freebsd32_exec_copyin_args(struct image_args *args, 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 0000000..3715400 --- /dev/null +++ b/sys/compat/freebsd32/syscalls.conf @@ -0,0 +1,11 @@ +# $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" diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master new file mode 100644 index 0000000..bcca754 --- /dev/null +++ b/sys/compat/freebsd32/syscalls.master @@ -0,0 +1,1048 @@ + $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, 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 psuedo-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 COMPAT4 #ifdef (FreeBSD 4 compat) +; COMPAT6 included on COMPAT6 #ifdef (FreeBSD 6 compat) +; COMPAT7 included on COMPAT7 #ifdef (FreeBSD 7 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(__powerpc__) || defined(__mips__)) +#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(char *path, int flags, \ + int 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(char *path, char *link); } +10 AUE_UNLINK NOPROTO { int unlink(char *path); } +11 AUE_NULL OBSOL execv +12 AUE_CHDIR NOPROTO { int chdir(char *path); } +13 AUE_FCHDIR NOPROTO { int fchdir(int fd); } +14 AUE_MKNOD NOPROTO { int mknod(char *path, int mode, int dev); } +15 AUE_CHMOD NOPROTO { int chmod(char *path, int mode); } +16 AUE_CHOWN NOPROTO { int chown(char *path, int uid, int gid); } +17 AUE_NULL NOPROTO { int obreak(char *nsize); } break \ + obreak_args int +18 AUE_GETFSSTAT COMPAT4 { int freebsd32_getfsstat( \ + struct statfs32 *buf, long bufsize, \ + int flags); } +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(char *type, char *path, \ + int flags, caddr_t data); } +22 AUE_UMOUNT NOPROTO { int unmount(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 NOPROTO { int 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, uint32_t buf, \ + uint32_t len, int flags, uint32_t from, \ + uint32_t fromlenaddr); } +30 AUE_ACCEPT NOPROTO { int accept(int s, caddr_t name, \ + int *anamelen); } +31 AUE_GETPEERNAME NOPROTO { int getpeername(int fdes, caddr_t asa, \ + int *alen); } +32 AUE_GETSOCKNAME NOPROTO { int getsockname(int fdes, caddr_t asa, \ + int *alen); } +33 AUE_ACCESS NOPROTO { int access(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(char *path, \ + struct ostat32 *ub); } +39 AUE_GETPPID NOPROTO { pid_t getppid(void); } +40 AUE_LSTAT COMPAT { int freebsd32_lstat(char *path, \ + struct ostat *ub); } +41 AUE_DUP NOPROTO { int dup(u_int fd); } +42 AUE_PIPE NOPROTO { int pipe(void); } +43 AUE_GETEGID NOPROTO { gid_t getegid(void); } +44 AUE_PROFILE NOPROTO { int profil(caddr_t 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(char *namebuf); } +51 AUE_ACCT NOPROTO { int acct(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_NULL 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(char *path); } +57 AUE_SYMLINK NOPROTO { int symlink(char *path, char *link); } +58 AUE_READLINK NOPROTO { ssize_t readlink(char *path, char *buf, \ + size_t count); } +59 AUE_EXECVE STD { int freebsd32_execve(char *fname, \ + uint32_t *argv, uint32_t *envv); } +60 AUE_UMASK NOPROTO { int umask(int newmask); } umask \ + umask_args int +61 AUE_CHROOT NOPROTO { int chroot(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 { int mmap(void *addr, int len, \ + int prot, int flags, int fd, int pos); } +72 AUE_O_VADVISE NOPROTO { int ovadvise(int anom); } vadvise \ + ovadvise_args int +73 AUE_MUNMAP NOPROTO { int munmap(void *addr, size_t len); } +74 AUE_MPROTECT STD { int freebsd32_mprotect(const 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(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 NOPROTO { int fcntl(int fd, int cmd, long 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, caddr_t 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_NULL COMPAT { int freebsd32_sigreturn( \ + struct ia32_sigcontext3 *sigcntxp); } +104 AUE_BIND NOPROTO { int bind(int s, caddr_t name, \ + int namelen); } +105 AUE_SETSOCKOPT NOPROTO { int setsockopt(int s, int level, \ + int name, caddr_t 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, caddr_t 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, int 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(char *from, char *to); } +129 AUE_TRUNCATE COMPAT|NOPROTO { int truncate(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(char *path, int mode); } +133 AUE_SENDTO NOPROTO { int sendto(int s, caddr_t buf, \ + size_t len, int flags, caddr_t 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(char *path, int mode); } +137 AUE_RMDIR NOPROTO { int rmdir(char *path); } +138 AUE_UTIMES STD { int freebsd32_utimes(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(char *path, int cmd, int uid, \ + caddr_t 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(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(char *fname, \ + struct fhandle *fhp); } +162 AUE_NULL OBSOL getdomainname +163 AUE_NULL 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 NOPROTO { int ntp_adjtime(struct timex *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 UNIMPL lfs_bmapv +185 AUE_NULL UNIMPL lfs_markv +186 AUE_NULL UNIMPL lfs_segclean +187 AUE_NULL UNIMPL lfs_segwait +188 AUE_STAT STD { int freebsd32_stat(char *path, \ + struct stat32 *ub); } +189 AUE_FSTAT STD { int freebsd32_fstat(int fd, \ + struct stat32 *ub); } +190 AUE_LSTAT STD { int freebsd32_lstat(char *path, \ + struct stat32 *ub); } +191 AUE_PATHCONF NOPROTO { int pathconf(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 STD { int freebsd32_getdirentries(int fd, \ + char *buf, u_int count, int32_t *basep); } +197 AUE_MMAP COMPAT6 { caddr_t freebsd32_mmap(caddr_t 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(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, 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(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 newreboot (NetBSD) +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 + +; +; The following were introduced with NetBSD/4.4Lite-2 +; They are initialized by their respective modules/sysinits +; XXX PROBLEM!! +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 UNIMPL 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 { int 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 UNIMPL timer_create +236 AUE_NULL UNIMPL timer_delete +237 AUE_NULL UNIMPL timer_settime +238 AUE_NULL UNIMPL timer_gettime +239 AUE_NULL UNIMPL timer_getoverrun +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 UNIMPL nosys +245 AUE_NULL UNIMPL nosys +246 AUE_NULL UNIMPL nosys +247 AUE_NULL NOPROTO { int clock_getcpuclockid2(id_t id,\ + int which, clockid_t *clock_id); } +248 AUE_NULL UNIMPL ntp_gettime +249 AUE_NULL UNIMPL nosys +; syscall numbers initially used in OpenBSD +250 AUE_MINHERIT NOPROTO { int minherit(void *addr, size_t len, \ + int inherit); } +251 AUE_RFORK NOPROTO { int rfork(int flags); } +252 AUE_POLL NOPROTO { int openbsd_poll(struct pollfd *fds, \ + u_int nfds, int timeout); } +253 AUE_ISSETUGID NOPROTO { int issetugid(void); } +254 AUE_LCHOWN NOPROTO { int lchown(char *path, int uid, int gid); } +255 AUE_NULL NOSTD { int freebsd32_aio_read( \ + struct aiocb32 *aiocbp); } +256 AUE_NULL NOSTD { int freebsd32_aio_write( \ + struct aiocb32 *aiocbp); } +257 AUE_NULL NOSTD { int freebsd32_lio_listio(int mode, \ + struct aiocb32 * const *acb_list, \ + int nent, struct sigevent *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 NOPROTO { int getdents(int fd, char *buf, \ + size_t count); } +273 AUE_NULL UNIMPL nosys +274 AUE_LCHMOD NOPROTO { int lchmod(char *path, mode_t mode); } +275 AUE_LCHOWN NOPROTO { int lchown(char *path, uid_t uid, \ + gid_t gid); } netbsd_lchown \ + lchown_args int +276 AUE_LUTIMES STD { int freebsd32_lutimes(char *path, \ + struct timeval32 *tptr); } +277 AUE_MSYNC NOPROTO { int msync(void *addr, size_t len, \ + int flags); } netbsd_msync msync_args int +278 AUE_STAT NOPROTO { int nstat(char *path, struct nstat *ub); } +279 AUE_FSTAT NOPROTO { int nfstat(int fd, struct nstat *sb); } +280 AUE_LSTAT NOPROTO { int nlstat(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 and 290 from NetBSD (OpenBSD: 267 and 268) +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 +; XXX 297 is 300 in NetBSD +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 NOPROTO { int fhstat(const struct fhandle *u_fhp, \ + struct stat *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_NULL NOSTD { int freebsd32_aio_return( \ + struct aiocb32 *aiocbp); } +315 AUE_NULL NOSTD { int freebsd32_aio_suspend( \ + struct aiocb32 * const * aiocbp, int nent, \ + const struct timespec32 *timeout); } +316 AUE_NULL NOSTD { int freebsd32_aio_cancel(int fd, \ + struct aiocb32 *aiocbp); } +317 AUE_NULL NOSTD { int freebsd32_aio_error( \ + struct aiocb32 *aiocbp); } +318 AUE_NULL NOSTD { int freebsd32_oaio_read( \ + struct oaiocb32 *aiocbp); } +319 AUE_NULL NOSTD { int freebsd32_oaio_write( \ + struct oaiocb32 *aiocbp); } +320 AUE_NULL NOSTD { int freebsd32_olio_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(u_char *buf, u_int 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 NOPROTO { int sched_rr_get_interval (pid_t pid, \ + struct timespec *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_NULL NOPROTO { int __acl_get_file(const char *path, \ + acl_type_t type, struct acl *aclp); } +348 AUE_NULL NOPROTO { int __acl_set_file(const char *path, \ + acl_type_t type, struct acl *aclp); } +349 AUE_NULL NOPROTO { int __acl_get_fd(int filedes, \ + acl_type_t type, struct acl *aclp); } +350 AUE_NULL NOPROTO { int __acl_set_fd(int filedes, \ + acl_type_t type, struct acl *aclp); } +351 AUE_NULL NOPROTO { int __acl_delete_file(const char *path, \ + acl_type_t type); } +352 AUE_NULL NOPROTO { int __acl_delete_fd(int filedes, \ + acl_type_t type); } +353 AUE_NULL NOPROTO { int __acl_aclcheck_file(const char *path, \ + acl_type_t type, struct acl *aclp); } +354 AUE_NULL 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_NULL NOSTD { 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_NULL STD { int freebsd32_kevent(int fd, \ + const struct kevent32 *changelist, \ + int nchanges, \ + struct kevent32 *eventlist, int nevents, \ + const struct timespec32 *timeout); } +364 AUE_NULL UNIMPL __cap_get_proc +365 AUE_NULL UNIMPL __cap_set_proc +366 AUE_NULL UNIMPL __cap_get_fd +367 AUE_NULL UNIMPL __cap_get_file +368 AUE_NULL UNIMPL __cap_set_fd +369 AUE_NULL UNIMPL __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_NULL NOPROTO { int __setugid(int flag); } +375 AUE_NULL UNIMPL nfsclnt +376 AUE_EACCESS NOPROTO { int eaccess(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 UNIMPL kse_exit +380 AUE_NULL UNIMPL kse_wakeup +381 AUE_NULL UNIMPL kse_create +382 AUE_NULL UNIMPL kse_thr_interrupt +383 AUE_NULL UNIMPL 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 NOPROTO { int getfsstat(struct statfs *buf, \ + long bufsize, int flags); } +396 AUE_STATFS NOPROTO { int statfs(char *path, \ + struct statfs *buf); } +397 AUE_FSTATFS NOPROTO { int fstatfs(int fd, struct statfs *buf); } +398 AUE_FHSTATFS NOPROTO { int fhstatfs(const struct fhandle *u_fhp, \ + struct statfs *buf); } +399 AUE_NULL UNIMPL nosys +400 AUE_NULL NOSTD|NOPROTO { int ksem_close(semid_t id); } +401 AUE_NULL NOSTD|NOPROTO { int ksem_post(semid_t id); } +402 AUE_NULL NOSTD|NOPROTO { int ksem_wait(semid_t id); } +403 AUE_NULL NOSTD|NOPROTO { int ksem_trywait(semid_t id); } +404 AUE_NULL NOSTD { int freebsd32_ksem_init(semid_t *idp, \ + unsigned int value); } +405 AUE_NULL NOSTD { int freebsd32_ksem_open(semid_t *idp, \ + const char *name, int oflag, \ + mode_t mode, unsigned int value); } +406 AUE_NULL NOSTD|NOPROTO { int ksem_unlink(const char *name); } +407 AUE_NULL NOSTD|NOPROTO { int ksem_getvalue(semid_t id, \ + int *val); } +408 AUE_NULL 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_NULL NOPROTO { int __acl_get_link(const char *path, \ + acl_type_t type, struct acl *aclp); } +426 AUE_NULL NOPROTO { int __acl_set_link(const char *path, \ + acl_type_t type, struct acl *aclp); } +427 AUE_NULL NOPROTO { int __acl_delete_link(const char *path, \ + acl_type_t type); } +428 AUE_NULL 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_NULL UNIMPL thr_create; +431 AUE_NULL NOPROTO { void thr_exit(long *state); } +432 AUE_NULL NOPROTO { int thr_self(long *id); } +433 AUE_NULL NOPROTO { int thr_kill(long id, int sig); } +434 AUE_NULL STD { int freebsd32_umtx_lock(struct umtx *umtx); } +435 AUE_NULL STD { int freebsd32_umtx_unlock(struct umtx *umtx); } +436 AUE_NULL 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 UNIMPL kse_switchin +441 AUE_NULL 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(char *path); } +454 AUE_NULL STD { int freebsd32_umtx_op(void *obj, int op,\ + u_long val, void *uaddr, \ + void *uaddr2); } +455 AUE_NULL STD { int freebsd32_thr_new( \ + struct thr_param32 *param, \ + int param_size); } +456 AUE_NULL NOPROTO { int sigqueue(pid_t pid, int signum, \ + void *value); } +457 AUE_NULL NOSTD { int freebsd32_kmq_open( \ + const char *path, int flags, mode_t mode, \ + const struct mq_attr32 *attr); } +458 AUE_NULL NOSTD { int freebsd32_kmq_setattr(int mqd, \ + const struct mq_attr32 *attr, \ + struct mq_attr32 *oattr); } +459 AUE_NULL NOSTD { int freebsd32_kmq_timedreceive(int mqd, \ + char *msg_ptr, size_t msg_len, \ + unsigned *msg_prio, \ + const struct timespec32 *abs_timeout); } +460 AUE_NULL 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_NULL NOPROTO|NOSTD { int kmq_notify(int mqd, \ + const struct sigevent *sigev); } +462 AUE_NULL 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_NULL NOSTD { 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_NULL NOPROTO { int sctp_peeloff(int sd, uint32_t name); } +472 AUE_NULL NOPROTO { int sctp_generic_sendmsg(int sd, caddr_t msg, int mlen, \ + caddr_t to, __socklen_t tolen, \ + struct sctp_sndrcvinfo *sinfo, int flags); } +473 AUE_NULL NOPROTO { int sctp_generic_sendmsg_iov(int sd, struct iovec *iov, int iovlen, \ + caddr_t to, __socklen_t tolen, \ + struct sctp_sndrcvinfo *sinfo, int flags); } +474 AUE_NULL NOPROTO { 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 { caddr_t freebsd32_mmap(caddr_t 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(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 { caddr_t freebsd32_mmap(caddr_t 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(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_KILL NOPROTO { int thr_kill2(pid_t pid, long id, int sig); } +482 AUE_SHMOPEN 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, 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, 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 STD { int freebsd32_fstatat(int fd, char *path, \ + struct stat *buf, int flag); } +494 AUE_FUTIMESAT STD { int freebsd32_futimesat(int fd, char *path, \ + struct timeval *times); } +495 AUE_LINKAT NOPROTO { int linkat(int fd1, char *path1, int fd2, \ + char *path2, int flag); } +496 AUE_MKDIRAT NOPROTO { int mkdirat(int fd, char *path, \ + mode_t mode); } +497 AUE_MKFIFOAT NOPROTO { int mkfifoat(int fd, char *path, \ + mode_t mode); } +498 AUE_MKNODAT NOPROTO { int mknodat(int fd, char *path, \ + mode_t mode, dev_t dev); } +499 AUE_OPENAT_RWTC NOPROTO { int openat(int fd, char *path, int flag, \ + mode_t mode); } +500 AUE_READLINKAT NOPROTO { int readlinkat(int fd, char *path, char *buf, \ + size_t bufsize); } +501 AUE_RENAMEAT NOPROTO { int renameat(int oldfd, char *old, int newfd, \ + const char *new); } +502 AUE_SYMLINKAT NOPROTO { int symlinkat(char *path1, int fd, \ + char *path2); } +503 AUE_UNLINKAT NOPROTO { int unlinkat(int fd, 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_NULL STD { int freebsd32_jail_get(struct iovec32 *iovp, \ + unsigned int iovcnt, int flags); } +507 AUE_NULL STD { int freebsd32_jail_set(struct iovec32 *iovp, \ + unsigned int iovcnt, int flags); } +508 AUE_NULL NOPROTO { int jail_remove(int jid); } +509 AUE_CLOSEFROM 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(char *path, int name); } +514 AUE_CAP_NEW NOPROTO { int cap_new(int fd, uint64_t rights); } +515 AUE_CAP_RIGHTS_GET NOPROTO { int cap_rights_get(int fd, \ + uint64_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 UNIMPL pdfork +519 AUE_PDKILL UNIMPL pdkill +520 AUE_PDGETPID UNIMPL pdgetpid +521 AUE_PDWAIT UNIMPL pdwait +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_NULL NOPROTO { int getloginclass(char *namebuf, \ + size_t namelen); } +524 AUE_NULL 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_NULL STD { int freebsd32_posix_fallocate(int fd, \ + int pad, \ + uint32_t offset1, uint32_t offset2,\ + uint32_t len1, uint32_t len2); } +531 AUE_NULL 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_NULL STD { int freebsd32_posix_fallocate(int fd,\ + uint32_t offset1, uint32_t offset2,\ + uint32_t len1, uint32_t len2); } +531 AUE_NULL 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, \ + uint64_t rights); } +534 AUE_CAP_IOCTLS_LIMIT NOPROTO { int cap_ioctls_limit(int fd, \ + const u_long *cmds, size_t ncmds); } +535 AUE_CAP_IOCTLS_GET NOPROTO { ssize_t cap_ioctls_get(int fd, \ + u_long *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, caddr_t name, \ + int namelen); } +539 AUE_CONNECTAT NOPROTO { int connectat(int fd, int s, caddr_t 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 * __restrict name, \ + __socklen_t * __restrict anamelen, \ + int flags); } +542 AUE_PIPE NOPROTO { int pipe2(int *fildes, int flags); } +543 AUE_NULL NOSTD { int freebsd32_aio_mlock( \ + struct aiocb32 *aiocbp); } diff --git a/sys/compat/ia32/ia32_genassym.c b/sys/compat/ia32/ia32_genassym.c new file mode 100644 index 0000000..5462a8b --- /dev/null +++ b/sys/compat/ia32/ia32_genassym.c @@ -0,0 +1,29 @@ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_compat.h" + +#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 0000000..78cb82a --- /dev/null +++ b/sys/compat/ia32/ia32_signal.h @@ -0,0 +1,208 @@ +/*- + * 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 + +#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, + u_long 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 0000000..a8e52e8 --- /dev/null +++ b/sys/compat/ia32/ia32_sysvec.c @@ -0,0 +1,228 @@ +/*- + * 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$"); + +#include "opt_compat.h" + +#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/pioctl.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, 0, "ia32 mode"); + +static u_long ia32_maxdsiz = IA32_MAXDSIZ; +SYSCTL_ULONG(_compat_ia32, OID_AUTO, maxdsiz, CTLFLAG_RW, &ia32_maxdsiz, 0, ""); +TUNABLE_ULONG("compat.ia32.maxdsiz", &ia32_maxdsiz); +u_long ia32_maxssiz = IA32_MAXSSIZ; +SYSCTL_ULONG(_compat_ia32, OID_AUTO, maxssiz, CTLFLAG_RW, &ia32_maxssiz, 0, ""); +TUNABLE_ULONG("compat.ia32.maxssiz", &ia32_maxssiz); +static u_long ia32_maxvmem = IA32_MAXVMEM; +SYSCTL_ULONG(_compat_ia32, OID_AUTO, maxvmem, CTLFLAG_RW, &ia32_maxvmem, 0, ""); +TUNABLE_ULONG("compat.ia32.maxvmem", &ia32_maxvmem); + +struct sysentvec ia32_freebsd_sysvec = { + .sv_size = FREEBSD32_SYS_MAXSYSCALL, + .sv_table = freebsd32_sysent, + .sv_mask = 0, + .sv_sigsize = 0, + .sv_sigtbl = NULL, + .sv_errsize = 0, + .sv_errtbl = NULL, + .sv_transtrap = NULL, + .sv_fixup = elf32_freebsd_fixup, + .sv_sendsig = ia32_sendsig, + .sv_sigcode = ia32_sigcode, + .sv_szsigcode = &sz_ia32_sigcode, + .sv_prepsyscall = NULL, + .sv_name = "FreeBSD ELF32", + .sv_coredump = elf32_coredump, + .sv_imgact_try = NULL, + .sv_minsigstksz = MINSIGSTKSZ, + .sv_pagesize = IA32_PAGE_SIZE, + .sv_minuser = FREEBSD32_MINUSER, + .sv_maxuser = FREEBSD32_MAXUSER, + .sv_usrstack = FREEBSD32_USRSTACK, + .sv_psstrings = FREEBSD32_PS_STRINGS, + .sv_stackprot = VM_PROT_ALL, + .sv_copyout_strings = freebsd32_copyout_strings, + .sv_setregs = ia32_setregs, + .sv_fixlimit = ia32_fixlimit, + .sv_maxssiz = &ia32_maxssiz, + .sv_flags = SV_ABI_FREEBSD | SV_IA32 | SV_ILP32 | +#ifdef __amd64__ + SV_SHP +#else + 0 +#endif + , + .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, +}; +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 __unused, void *dst __unused, + size_t *off __unused) +{ +} + +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 0000000..fe87b72 --- /dev/null +++ b/sys/compat/ia32/ia32_util.h @@ -0,0 +1,64 @@ +/*- + * 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> + +#ifdef __ia64__ +#define FREEBSD32_MAXUSER ((1ul << 32) - IA32_PAGE_SIZE * 2) +#define FREEBSD32_MINUSER 0 +#define FREEBSD32_SHAREDPAGE 0 +#define FREEBSD32_USRSTACK FREEBSD32_MAXUSER +#else /* __ia64__ */ +#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 +#endif /* __ia64 */ + +#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, struct syscall_args *sa); +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/linprocfs/linprocfs.c b/sys/compat/linprocfs/linprocfs.c new file mode 100644 index 0000000..28b683a --- /dev/null +++ b/sys/compat/linprocfs/linprocfs.c @@ -0,0 +1,1456 @@ +/*- + * 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 "opt_compat.h" + +#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/linker.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/mount.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/sbuf.h> +#include <sys/sem.h> +#include <sys/smp.h> +#include <sys/socket.h> +#include <sys/sysctl.h> +#include <sys/systm.h> +#include <sys/time.h> +#include <sys/tty.h> +#include <sys/user.h> +#include <sys/vmmeter.h> +#include <sys/vnode.h> +#include <sys/bus.h> + +#include <net/if.h> +#include <net/vnet.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__ */ + +#ifdef COMPAT_FREEBSD32 +#include <compat/freebsd32/freebsd32_util.h> +#endif + +#include <compat/linux/linux_ioctl.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 memused; /* used memory in bytes */ + unsigned long memfree; /* free memory in bytes */ + unsigned long memshared; /* shared memory ??? */ + unsigned long buffers, cached; /* buffer / cache memory ??? */ + 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 */ + vm_object_t object; + int i, j; + + memtotal = physmem * PAGE_SIZE; + /* + * The correct thing here would be: + * + memfree = cnt.v_free_count * PAGE_SIZE; + memused = memtotal - memfree; + * + * but it might mislead linux binaries into thinking there + * is very little memory left, so we cheat and tell them that + * all memory that isn't wired down is free. + */ + memused = cnt.v_wire_count * PAGE_SIZE; + memfree = memtotal - memused; + swap_pager_status(&i, &j); + swaptotal = (unsigned long long)i * PAGE_SIZE; + swapused = (unsigned long long)j * PAGE_SIZE; + swapfree = swaptotal - swapused; + memshared = 0; + mtx_lock(&vm_object_list_mtx); + TAILQ_FOREACH(object, &vm_object_list, object_list) + if (object->shadow_count > 1) + memshared += object->resident_page_count; + mtx_unlock(&vm_object_list_mtx); + memshared *= PAGE_SIZE; + /* + * We'd love to be able to write: + * + buffers = bufspace; + * + * but bufspace is internal to vfs_bio.c and we don't feel + * like unstaticizing it just for linprocfs's sake. + */ + buffers = 0; + cached = cnt.v_cache_count * PAGE_SIZE; + + sbuf_printf(sb, + " total: used: free: shared: buffers: cached:\n" + "Mem: %lu %lu %lu %lu %lu %lu\n" + "Swap: %llu %llu %llu\n" + "MemTotal: %9lu kB\n" + "MemFree: %9lu kB\n" + "MemShared:%9lu kB\n" + "Buffers: %9lu kB\n" + "Cached: %9lu kB\n" + "SwapTotal:%9llu kB\n" + "SwapFree: %9llu kB\n", + memtotal, memused, memfree, memshared, buffers, cached, + swaptotal, swapused, swapfree, + B2K(memtotal), B2K(memfree), + B2K(memshared), 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; + int class, fqmhz, fqkhz; + int i; + + /* + * We default the flags to include all non-conflicting flags, + * and the Intel versions of conflicting flags. + */ + static char *flags[] = { + "fpu", "vme", "de", "pse", "tsc", + "msr", "pae", "mce", "cx8", "apic", + "sep", "sep", "mtrr", "pge", "mca", + "cmov", "pat", "pse36", "pn", "b19", + "b20", "b21", "mmxext", "mmx", "fxsr", + "xmm", "sse2", "b27", "b28", "b29", + "3dnowext", "3dnow" + }; + + switch (cpu_class) { +#ifdef __i386__ + case CPUCLASS_286: + class = 2; + break; + case CPUCLASS_386: + class = 3; + break; + case CPUCLASS_486: + class = 4; + break; + case CPUCLASS_586: + class = 5; + break; + case CPUCLASS_686: + class = 6; + break; + default: + class = 0; + break; +#else /* __amd64__ */ + default: + class = 15; + break; +#endif + } + + 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"); + for (i = 0; i < mp_ncpus; ++i) { + 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\n", + i, cpu_vendor, CPUID_TO_FAMILY(cpu_id), + CPUID_TO_MODEL(cpu_id), model, cpu_id & CPUID_STEPPING); + /* XXX per-cpu vendor / class / model / id? */ + } + + sbuf_cat(sb, "flags\t\t:"); + +#ifdef __i386__ + switch (cpu_vendor_id) { + case CPU_VENDOR_AMD: + if (class < 6) + flags[16] = "fcmov"; + break; + case CPU_VENDOR_CYRIX: + flags[24] = "cxmmx"; + break; + } +#endif + + for (i = 0; i < 32; i++) + if (cpu_feature & (1 << i)) + sbuf_printf(sb, " %s", flags[i]); + sbuf_cat(sb, "\n"); + freq = atomic_load_acq_64(&tsc_freq); + if (freq != 0) { + fqmhz = (freq + 4999) / 1000000; + fqkhz = ((freq + 4999) / 10000) % 100; + sbuf_printf(sb, + "cpu MHz\t\t: %d.%02d\n" + "bogomips\t: %d.%02d\n", + fqmhz, fqkhz, fqmhz, fqkhz); + } + + return (0); +} +#endif /* __i386__ || __amd64__ */ + +/* + * Filler function for proc/mtab + * + * This file 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; + struct mount *mp; + const char *lep; + char *dlep, *flep, *mntto, *mntfrom, *fstype; + size_t lep_len; + int error; + + /* resolve symlinks etc. in the emulation tree prefix */ + 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(td, nd.ni_vp, &dlep, &flep) == 0) + lep = dlep; + vrele(nd.ni_vp); + } + lep_len = strlen(lep); + + mtx_lock(&mountlist_mtx); + error = 0; + TAILQ_FOREACH(mp, &mountlist, mnt_list) { + /* determine device name */ + mntfrom = mp->mnt_stat.f_mntfromname; + + /* determine mount point */ + mntto = mp->mnt_stat.f_mntonname; + if (strncmp(mntto, lep, lep_len) == 0 && + mntto[lep_len] == '/') + mntto += lep_len; + + /* determine fs type */ + fstype = mp->mnt_stat.f_fstypename; + if (strcmp(fstype, pn->pn_info->pi_name) == 0) + mntfrom = fstype = "proc"; + else if (strcmp(fstype, "procfs") == 0) + continue; + + if (strcmp(fstype, "linsysfs") == 0) { + sbuf_printf(sb, "/sys %s sysfs %s", mntto, + mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); + } else { + /* For Linux msdosfs is called vfat */ + if (strcmp(fstype, "msdosfs") == 0) + fstype = "vfat"; + sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype, + mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); + } +#define ADD_OPTION(opt, name) \ + if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(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 + /* a real Linux mtab will also show NFS options */ + sbuf_printf(sb, " 0 0\n"); + } + mtx_unlock(&mountlist_mtx); + 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; + struct nameidata nd; + const char *lep; + char *dlep, *flep; + size_t lep_len; + int error; + int major, minor; + + /* resolve symlinks etc. in the emulation tree prefix */ + 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(td, nd.ni_vp, &dlep, &flep) == 0) + lep = dlep; + vrele(nd.ni_vp); + } + lep_len = strlen(lep); + + g_topology_lock(); + error = 0; + 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(); + + free(flep, M_TEMP); + return (error); +} + + +/* + * Filler function for proc/stat + */ +static int +linprocfs_dostat(PFS_FILL_ARGS) +{ + struct pcpu *pcpu; + long cp_time[CPUSTATES]; + long *cp; + int i; + + read_cpu_time(cp_time); + sbuf_printf(sb, "cpu %ld %ld %ld %ld\n", + T2J(cp_time[CP_USER]), + T2J(cp_time[CP_NICE]), + T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), + T2J(cp_time[CP_IDLE])); + CPU_FOREACH(i) { + pcpu = pcpu_find(i); + cp = pcpu->pc_cp_time; + sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i, + T2J(cp[CP_USER]), + T2J(cp[CP_NICE]), + T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/), + T2J(cp[CP_IDLE])); + } + sbuf_printf(sb, + "disk 0 0 0 0\n" + "page %u %u\n" + "swap %u %u\n" + "intr %u\n" + "ctxt %u\n" + "btime %lld\n", + cnt.v_vnodepgsin, + cnt.v_vnodepgsout, + cnt.v_swappgsin, + cnt.v_swappgsout, + cnt.v_intr, + cnt.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"); + mtx_lock(&Giant); + 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); + } + mtx_unlock(&Giant); + 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); +} + +/* + * Filler function for proc/pid/stat + */ +static int +linprocfs_doprocstat(PFS_FILL_ARGS) +{ + struct kinfo_proc kp; + char state; + static int ratelimit = 0; + vm_offset_t startcode, startdata; + + PROC_LOCK(p); + fill_kinfo_proc(p, &kp); + 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", kp.ki_tdev); + 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; + + PROC_LOCK(p); + fill_kinfo_proc(p, &kp); + PROC_UNLOCK(p); + + /* + * 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; + int i; + + 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); + sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ + sbuf_printf(sb, "State:\t%s\n", state); + + /* + * Credentials + */ + sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); + sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? + p->p_pptr->p_pid : 0); + 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 + * + * We support up to 128 signals, while Linux supports 32, + * but we only define 32 (the same 32 as Linux, to boot), so + * just show the lower 32 bits of each mask. XXX hack. + * + * NB: on certain platforms (Sparc at least) Linux actually + * supports 64 signals, but this code is a long way from + * running on anything but i386, so ignore that for now. + */ + PROC_LOCK(p); + sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); + /* + * I can't seem to find out where the signal mask is in + * relation to struct proc, so SigBlk is left unimplemented. + */ + sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ + ps = p->p_sigacts; + mtx_lock(&ps->ps_mtx); + sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]); + sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]); + mtx_unlock(&ps->ps_mtx); + PROC_UNLOCK(p); + + /* + * 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) +{ + char *fullpath = "unknown"; + char *freepath = NULL; + + vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath); + sbuf_printf(sb, "%s", fullpath); + if (freepath) + free(freepath, M_TEMP); + return (0); +} + +/* + * Filler function for proc/pid/root + */ +static int +linprocfs_doprocroot(PFS_FILL_ARGS) +{ + struct vnode *rvp; + char *fullpath = "unknown"; + char *freepath = NULL; + + rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir; + vn_fullpath(td, rvp, &fullpath, &freepath); + sbuf_printf(sb, "%s", fullpath); + if (freepath) + free(freepath, M_TEMP); + 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) +{ + int ret; + + PROC_LOCK(p); + if ((ret = p_candebug(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_flag & P_SYSTEM) != 0) { + PROC_UNLOCK(p); + return (0); + } + + PROC_UNLOCK(p); + + ret = proc_getenvv(td, p, sb); + return (ret); +} + +/* + * 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 = 0; + vm_prot_t e_prot; + unsigned int last_timestamp; + char *name = "", *freename = NULL; + ino_t ino; + int ref_count, shadow_count, flags; + int error; + struct vnode *vp; + struct vattr vat; + + 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); + map = &vm->vm_map; + vm_map_lock_read(map); + for (entry = map->header.next; entry != &map->header; + entry = entry->next) { + 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; + for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) { + VM_OBJECT_RLOCK(tobj); + if (lobj != obj) + VM_OBJECT_RUNLOCK(lobj); + lobj = tobj; + } + last_timestamp = map->timestamp; + vm_map_unlock_read(map); + ino = 0; + if (lobj) { + off = IDX_TO_OFF(lobj->size); + if (lobj->type == OBJT_VNODE) { + vp = lobj->handle; + if (vp) + vref(vp); + } + else + vp = NULL; + 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) { + vn_fullpath(td, vp, &name, &freename); + vn_lock(vp, LK_SHARED | LK_RETRY); + VOP_GETATTR(vp, &vat, td->td_ucred); + ino = vat.va_fileid; + vput(vp); + } + } else { + flags = 0; + ref_count = 0; + shadow_count = 0; + } + + /* + * format: + * start, end, access, offset, major, minor, inode, name. + */ + error = sbuf_printf(sb, + "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n", + (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":"-", + "p", + (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/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(); + TAILQ_FOREACH(ifp, &V_ifnet, if_link) { + linux_ifname(ifp, ifname, sizeof ifname); + sbuf_printf(sb, "%6.6s: ", ifname); + sbuf_printf(sb, "%7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", + ifp->if_ibytes, /* rx_bytes */ + ifp->if_ipackets, /* rx_packets */ + ifp->if_ierrors, /* rx_errors */ + ifp->if_iqdrops, /* rx_dropped + + * rx_missed_errors */ + 0UL, /* rx_fifo_errors */ + 0UL, /* rx_length_errors + + * rx_over_errors + + * rx_crc_errors + + * rx_frame_errors */ + 0UL, /* rx_compressed */ + ifp->if_imcasts); /* multicast, XXX-BZ rx only? */ + sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", + ifp->if_obytes, /* tx_bytes */ + ifp->if_opackets, /* tx_packets */ + ifp->if_oerrors, /* tx_errors */ + 0UL, /* tx_dropped */ + 0UL, /* tx_fifo_errors */ + ifp->if_collisions, /* 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/msgmni + */ +static int +linprocfs_domsgmni(PFS_FILL_ARGS) +{ + + sbuf_printf(sb, "%d\n", msginfo.msgmni); + 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/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); +} + +extern struct cdevsw *cdevsw[]; + +/* + * 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; + + mtx_lock(&Giant); + 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); + } + mtx_unlock(&Giant); + return(0); +} + +#if 0 +/* + * Filler function for proc/modules + */ +static int +linprocfs_domodules(PFS_FILL_ARGS) +{ + 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); + } + return (0); +} +#endif + +/* + * 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); +} + +/* + * Constructor + */ +static int +linprocfs_init(PFS_INIT_ARGS) +{ + struct pfs_node *root; + struct pfs_node *dir; + + 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); +#if 0 + pfs_create_file(root, "modules", &linprocfs_domodules, + NULL, NULL, NULL, PFS_RD); +#endif + 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/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, NULL, 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_create_file(dir, "mem", &procfs_doprocmem, + &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW); + 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); + + /* /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/... */ + dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0); + /* /proc/sys/kernel/... */ + dir = pfs_create_dir(dir, "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, "msgmni", &linprocfs_domsgmni, + 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); + + return (0); +} + +/* + * Destructor + */ +static int +linprocfs_uninit(PFS_INIT_ARGS) +{ + + /* nothing to do, pseudofs will GC */ + return (0); +} + +PSEUDOFS(linprocfs, 1, 0); +MODULE_DEPEND(linprocfs, linux, 1, 1, 1); +MODULE_DEPEND(linprocfs, procfs, 1, 1, 1); +MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1); +MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1); diff --git a/sys/compat/linsysfs/linsysfs.c b/sys/compat/linsysfs/linsysfs.c new file mode 100644 index 0000000..45f44af --- /dev/null +++ b/sys/compat/linsysfs/linsysfs.c @@ -0,0 +1,284 @@ +/*- + * 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/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 "opt_compat.h" +#ifdef COMPAT_LINUX32 /* XXX */ +#include <machine/../linux32/linux.h> +#else +#include <machine/../linux/linux.h> +#endif +#include <compat/linux/linux_ioctl.h> +#include <compat/linux/linux_mib.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); +} + +/* + * 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); +} + +#define PCI_DEV "pci" +static int +linsysfs_run_bus(device_t dev, struct pfs_node *dir, struct pfs_node *scsi, char *path, + char *prefix) +{ + struct scsi_host_queue *scsi_host; + struct pfs_node *sub_dir; + int i, nchildren; + device_t *children, parent; + devclass_t devclass; + const char *name = NULL; + struct pci_devinfo *dinfo; + char *device, *host, *new_path = path; + + 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); + + 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); + } + } + } + + device_get_children(dev, &children, &nchildren); + for (i = 0; i < nchildren; i++) { + if (children[i]) + linsysfs_run_bus(children[i], dir, scsi, new_path, prefix); + } + if (new_path != path) + free(new_path, M_TEMP); + + return (1); +} + +/* + * Constructor + */ +static int +linsysfs_init(PFS_INIT_ARGS) +{ + struct pfs_node *root; + struct pfs_node *dir; + struct pfs_node *pci; + struct pfs_node *scsi; + devclass_t devclass; + device_t dev; + + TAILQ_INIT(&scsi_host_q); + + root = pi->pi_root; + + /* /sys/class/... */ + scsi = pfs_create_dir(root, "class", NULL, NULL, NULL, 0); + scsi = pfs_create_dir(scsi, "scsi_host", NULL, NULL, NULL, 0); + + /* /sys/device */ + dir = pfs_create_dir(root, "devices", NULL, NULL, NULL, 0); + + /* /sys/device/pci0000:00 */ + 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, "/pci0000:00", "0000"); + 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, 0); +MODULE_DEPEND(linsysfs, linux, 1, 1, 1); diff --git a/sys/compat/linux/check_error.d b/sys/compat/linux/check_error.d new file mode 100644 index 0000000..9e3c00a --- /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:proc_exit:child_clear_tid_error, +linuxulator*:emul:proc_exit: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 0000000..2bdef68 --- /dev/null +++ b/sys/compat/linux/check_internal_locks.d @@ -0,0 +1,132 @@ +#!/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["emul_lock"] = 0; + check["emul_shared_rlock"] = 0; + check["emul_shared_wlock"] = 0; + check["futex_mtx"] = 0; +} + +linuxulator*:locks:emul_lock:locked, +linuxulator*:locks:emul_shared_wlock:locked, +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:emul_lock:locked, +linuxulator*:locks:emul_shared_rlock:locked, +linuxulator*:locks:emul_shared_wlock:locked, +linuxulator*:locks:futex_mtx:locked +{ + ++check[probefunc]; + @stats[probefunc] = count(); + + ts[probefunc] = timestamp; + spec[probefunc] = speculation(); +} + +linuxulator*:locks:emul_lock:unlock, +linuxulator*:locks:emul_shared_rlock:unlock, +linuxulator*:locks:emul_shared_wlock:unlock, +linuxulator*:locks:futex_mtx:unlock +/check[probefunc] == 0/ +{ + printf("ERROR: unlock attemt 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:emul_lock:unlock, +linuxulator*:locks:emul_shared_rlock:unlock, +linuxulator*:locks:emul_shared_wlock:unlock, +linuxulator*:locks:futex_mtx:unlock +{ + discard(spec[probefunc]); + spec[probefunc] = 0; + --check[probefunc]; +} + +/* Timeout handling */ + +tick-10s +/spec["emul_lock"] != 0 && timestamp - ts["emul_lock"] >= 9999999000/ +{ + commit(spec["emul_lock"]); + spec["emul_lock"] = 0; +} + +tick-10s +/spec["emul_shared_wlock"] != 0 && timestamp - ts["emul_shared_wlock"] >= 9999999000/ +{ + commit(spec["emul_shared_wlock"]); + spec["emul_shared_wlock"] = 0; +} + +tick-10s +/spec["emul_shared_rlock"] != 0 && timestamp - ts["emul_shared_rlock"] >= 9999999000/ +{ + commit(spec["emul_shared_rlock"]); + spec["emul_shared_rlock"] = 0; +} + +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_dtrace.h b/sys/compat/linux/linux_dtrace.h new file mode 100644 index 0000000..b6a2b33 --- /dev/null +++ b/sys/compat/linux/linux_dtrace.h @@ -0,0 +1,95 @@ +/*- + * 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, 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, 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, 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, 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, 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, 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_PROBE_ARGTYPE(a, b, c, d, e, f) SDT_PROBE_ARGTYPE(a, b,\ + c, d, e, f) +#define LIN_SDT_PROBE_ARGTYPE(a, b, c, d, e) _LIN_SDT_PROBE_ARGTYPE( \ + LINUX_DTRACE, a, b, c, d, e) + +#define LIN_SDT_PROBE0(a, b, c) SDT_PROBE1(LINUX_DTRACE, a, b, \ + c, 0) +#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_PROBE(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_emul.c b/sys/compat/linux/linux_emul.c new file mode 100644 index 0000000..61156ba --- /dev/null +++ b/sys/compat/linux/linux_emul.c @@ -0,0 +1,474 @@ +/*- + * 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 + * 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 "opt_kdtrace.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/imgact.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/mutex.h> +#include <sys/sdt.h> +#include <sys/sx.h> +#include <sys/proc.h> +#include <sys/syscallsubr.h> +#include <sys/sysent.h> +#include <sys/sysproto.h> +#include <sys/unistd.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_misc.h> + +/** + * 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(LINUX_DTRACE); + +/** + * Special DTrace module "locks", it covers some linuxulator internal + * locks. + */ +LIN_SDT_PROBE_DEFINE1(locks, emul_lock, locked, "struct mtx *"); +LIN_SDT_PROBE_DEFINE1(locks, emul_lock, unlock, "struct mtx *"); +LIN_SDT_PROBE_DEFINE1(locks, emul_shared_rlock, locked, "struct sx *"); +LIN_SDT_PROBE_DEFINE1(locks, emul_shared_rlock, unlock, "struct sx *"); +LIN_SDT_PROBE_DEFINE1(locks, emul_shared_wlock, locked, "struct sx *"); +LIN_SDT_PROBE_DEFINE1(locks, emul_shared_wlock, unlock, "struct sx *"); + +/** + * DTrace probes in this module. + */ +LIN_SDT_PROBE_DEFINE2(emul, em_find, entry, "struct proc *", "int"); +LIN_SDT_PROBE_DEFINE0(emul, em_find, return); +LIN_SDT_PROBE_DEFINE3(emul, proc_init, entry, "struct thread *", "pid_t", + "int"); +LIN_SDT_PROBE_DEFINE0(emul, proc_init, create_thread); +LIN_SDT_PROBE_DEFINE0(emul, proc_init, fork); +LIN_SDT_PROBE_DEFINE0(emul, proc_init, exec); +LIN_SDT_PROBE_DEFINE0(emul, proc_init, return); +LIN_SDT_PROBE_DEFINE1(emul, proc_exit, entry, "struct proc *"); +LIN_SDT_PROBE_DEFINE0(emul, proc_exit, futex_failed); +LIN_SDT_PROBE_DEFINE3(emul, proc_exit, reparent, "pid_t", "pid_t", + "struct proc *"); +LIN_SDT_PROBE_DEFINE1(emul, proc_exit, child_clear_tid_error, "int"); +LIN_SDT_PROBE_DEFINE0(emul, proc_exit, return); +LIN_SDT_PROBE_DEFINE2(emul, proc_exec, entry, "struct proc *", + "struct image_params *"); +LIN_SDT_PROBE_DEFINE0(emul, proc_exec, return); +LIN_SDT_PROBE_DEFINE0(emul, linux_schedtail, entry); +LIN_SDT_PROBE_DEFINE1(emul, linux_schedtail, copyout_error, "int"); +LIN_SDT_PROBE_DEFINE0(emul, linux_schedtail, return); +LIN_SDT_PROBE_DEFINE1(emul, linux_set_tid_address, entry, "int *"); +LIN_SDT_PROBE_DEFINE0(emul, linux_set_tid_address, return); +LIN_SDT_PROBE_DEFINE2(emul, linux_kill_threads, entry, "struct thread *", + "int"); +LIN_SDT_PROBE_DEFINE1(emul, linux_kill_threads, kill, "pid_t"); +LIN_SDT_PROBE_DEFINE0(emul, linux_kill_threads, return); + +struct sx emul_shared_lock; +struct mtx emul_lock; + +/* this returns locked reference to the emuldata entry (if found) */ +struct linux_emuldata * +em_find(struct proc *p, int locked) +{ + struct linux_emuldata *em; + + LIN_SDT_PROBE2(emul, em_find, entry, p, locked); + + if (locked == EMUL_DOLOCK) + EMUL_LOCK(&emul_lock); + + em = p->p_emuldata; + + if (em == NULL && locked == EMUL_DOLOCK) + EMUL_UNLOCK(&emul_lock); + + LIN_SDT_PROBE1(emul, em_find, return, em); + return (em); +} + +int +linux_proc_init(struct thread *td, pid_t child, int flags) +{ + struct linux_emuldata *em, *p_em; + struct proc *p; + + LIN_SDT_PROBE3(emul, proc_init, entry, td, child, flags); + + if (child != 0) { + /* fork or create a thread */ + em = malloc(sizeof *em, M_LINUX, M_WAITOK | M_ZERO); + em->pid = child; + em->pdeath_signal = 0; + em->flags = 0; + em->robust_futexes = NULL; + if (flags & LINUX_CLONE_THREAD) { + /* handled later in the code */ + LIN_SDT_PROBE0(emul, proc_init, create_thread); + } else { + struct linux_emuldata_shared *s; + + LIN_SDT_PROBE0(emul, proc_init, fork); + + s = malloc(sizeof *s, M_LINUX, M_WAITOK | M_ZERO); + s->refs = 1; + s->group_pid = child; + + LIST_INIT(&s->threads); + em->shared = s; + } + } else { + /* exec */ + LIN_SDT_PROBE0(emul, proc_init, exec); + + /* lookup the old one */ + em = em_find(td->td_proc, EMUL_DOLOCK); + KASSERT(em != NULL, ("proc_init: emuldata not found in exec case.\n")); + } + + em->child_clear_tid = NULL; + em->child_set_tid = NULL; + + /* + * allocate the shared struct only in clone()/fork cases in the case + * of clone() td = calling proc and child = pid of the newly created + * proc + */ + if (child != 0) { + if (flags & LINUX_CLONE_THREAD) { + /* lookup the parent */ + /* + * we dont have to lock the p_em because + * its waiting for us in linux_clone so + * there is no chance of it changing the + * p_em->shared address + */ + p_em = em_find(td->td_proc, EMUL_DONTLOCK); + KASSERT(p_em != NULL, ("proc_init: parent emuldata not found for CLONE_THREAD\n")); + em->shared = p_em->shared; + EMUL_SHARED_WLOCK(&emul_shared_lock); + em->shared->refs++; + EMUL_SHARED_WUNLOCK(&emul_shared_lock); + } else { + /* + * handled earlier to avoid malloc(M_WAITOK) with + * rwlock held + */ + } + + EMUL_SHARED_WLOCK(&emul_shared_lock); + LIST_INSERT_HEAD(&em->shared->threads, em, threads); + EMUL_SHARED_WUNLOCK(&emul_shared_lock); + + p = pfind(child); + KASSERT(p != NULL, ("process not found in proc_init\n")); + p->p_emuldata = em; + PROC_UNLOCK(p); + } else + EMUL_UNLOCK(&emul_lock); + + LIN_SDT_PROBE0(emul, proc_init, return); + return (0); +} + +void +linux_proc_exit(void *arg __unused, struct proc *p) +{ + struct linux_emuldata *em; + int error, shared_flags, shared_xstat; + struct thread *td = FIRST_THREAD_IN_PROC(p); + int *child_clear_tid; + struct proc *q, *nq; + + if (__predict_true(p->p_sysent != &elf_linux_sysvec)) + return; + + LIN_SDT_PROBE1(emul, proc_exit, entry, p); + + release_futexes(p); + + /* find the emuldata */ + em = em_find(p, EMUL_DOLOCK); + + KASSERT(em != NULL, ("proc_exit: emuldata not found.\n")); + + /* reparent all procs that are not a thread leader to initproc */ + if (em->shared->group_pid != p->p_pid) { + LIN_SDT_PROBE3(emul, proc_exit, reparent, + em->shared->group_pid, p->p_pid, p); + + child_clear_tid = em->child_clear_tid; + EMUL_UNLOCK(&emul_lock); + sx_xlock(&proctree_lock); + wakeup(initproc); + PROC_LOCK(p); + proc_reparent(p, initproc); + p->p_sigparent = SIGCHLD; + PROC_UNLOCK(p); + sx_xunlock(&proctree_lock); + } else { + child_clear_tid = em->child_clear_tid; + EMUL_UNLOCK(&emul_lock); + } + + EMUL_SHARED_WLOCK(&emul_shared_lock); + shared_flags = em->shared->flags; + shared_xstat = em->shared->xstat; + LIST_REMOVE(em, threads); + + em->shared->refs--; + if (em->shared->refs == 0) { + EMUL_SHARED_WUNLOCK(&emul_shared_lock); + free(em->shared, M_LINUX); + } else + EMUL_SHARED_WUNLOCK(&emul_shared_lock); + + if ((shared_flags & EMUL_SHARED_HASXSTAT) != 0) + p->p_xstat = shared_xstat; + + if (child_clear_tid != NULL) { + struct linux_sys_futex_args cup; + int null = 0; + + error = copyout(&null, child_clear_tid, sizeof(null)); + if (error) { + LIN_SDT_PROBE1(emul, proc_exit, + child_clear_tid_error, error); + + free(em, M_LINUX); + + LIN_SDT_PROBE0(emul, proc_exit, return); + return; + } + + /* futexes stuff */ + cup.uaddr = child_clear_tid; + cup.op = LINUX_FUTEX_WAKE; + cup.val = 0x7fffffff; /* Awake everyone */ + cup.timeout = NULL; + cup.uaddr2 = NULL; + cup.val3 = 0; + error = linux_sys_futex(FIRST_THREAD_IN_PROC(p), &cup); + /* + * this cannot happen at the moment and if this happens it + * probably means there is a user space bug + */ + if (error) { + LIN_SDT_PROBE0(emul, proc_exit, futex_failed); + printf(LMSG("futex stuff in proc_exit failed.\n")); + } + } + + /* clean the stuff up */ + free(em, M_LINUX); + + /* this is a little weird but rewritten from exit1() */ + sx_xlock(&proctree_lock); + q = LIST_FIRST(&p->p_children); + for (; q != NULL; q = nq) { + nq = LIST_NEXT(q, p_sibling); + if (q->p_flag & P_WEXIT) + continue; + if (__predict_false(q->p_sysent != &elf_linux_sysvec)) + continue; + em = em_find(q, EMUL_DOLOCK); + KASSERT(em != NULL, ("linux_reparent: emuldata not found: %i\n", q->p_pid)); + PROC_LOCK(q); + if ((q->p_flag & P_WEXIT) == 0 && em->pdeath_signal != 0) { + kern_psignal(q, em->pdeath_signal); + } + PROC_UNLOCK(q); + EMUL_UNLOCK(&emul_lock); + } + sx_xunlock(&proctree_lock); + + LIN_SDT_PROBE0(emul, proc_exit, return); +} + +/* + * This is used in a case of transition from FreeBSD binary execing to linux binary + * in this case we create linux emuldata proc entry with the pid of the currently running + * process. + */ +void +linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp) +{ + if (__predict_false(imgp->sysent == &elf_linux_sysvec)) { + LIN_SDT_PROBE2(emul, proc_exec, entry, p, imgp); + } + if (__predict_false(imgp->sysent == &elf_linux_sysvec + && p->p_sysent != &elf_linux_sysvec)) + linux_proc_init(FIRST_THREAD_IN_PROC(p), p->p_pid, 0); + if (__predict_false((p->p_sysent->sv_flags & SV_ABI_MASK) == + SV_ABI_LINUX)) + /* Kill threads regardless of imgp->sysent value */ + linux_kill_threads(FIRST_THREAD_IN_PROC(p), SIGKILL); + if (__predict_false(imgp->sysent != &elf_linux_sysvec + && p->p_sysent == &elf_linux_sysvec)) { + struct linux_emuldata *em; + + /* + * XXX:There's a race because here we assign p->p_emuldata NULL + * but the process is still counted as linux one for a short + * time so some other process might reference it and try to + * access its p->p_emuldata and panicing on a NULL reference. + */ + em = em_find(p, EMUL_DONTLOCK); + + KASSERT(em != NULL, ("proc_exec: emuldata not found.\n")); + + EMUL_SHARED_WLOCK(&emul_shared_lock); + LIST_REMOVE(em, threads); + + PROC_LOCK(p); + p->p_emuldata = NULL; + PROC_UNLOCK(p); + + em->shared->refs--; + if (em->shared->refs == 0) { + EMUL_SHARED_WUNLOCK(&emul_shared_lock); + free(em->shared, M_LINUX); + } else + EMUL_SHARED_WUNLOCK(&emul_shared_lock); + + free(em, M_LINUX); + } + + if (__predict_false(imgp->sysent == &elf_linux_sysvec)) { + LIN_SDT_PROBE0(emul, proc_exec, return); + } +} + +void +linux_schedtail(struct thread *td) +{ + struct linux_emuldata *em; + struct proc *p; + int error = 0; + int *child_set_tid; + + p = td->td_proc; + + LIN_SDT_PROBE1(emul, linux_schedtail, entry, p); + + /* find the emuldata */ + em = em_find(p, EMUL_DOLOCK); + + KASSERT(em != NULL, ("linux_schedtail: emuldata not found.\n")); + child_set_tid = em->child_set_tid; + EMUL_UNLOCK(&emul_lock); + + if (child_set_tid != NULL) { + error = copyout(&p->p_pid, (int *)child_set_tid, + sizeof(p->p_pid)); + + if (error != 0) { + LIN_SDT_PROBE1(emul, linux_schedtail, copyout_error, + error); + } + } + + LIN_SDT_PROBE0(emul, linux_schedtail, return); + + return; +} + +int +linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args) +{ + struct linux_emuldata *em; + + LIN_SDT_PROBE1(emul, linux_set_tid_address, entry, args->tidptr); + + /* find the emuldata */ + em = em_find(td->td_proc, EMUL_DOLOCK); + + KASSERT(em != NULL, ("set_tid_address: emuldata not found.\n")); + + em->child_clear_tid = args->tidptr; + td->td_retval[0] = td->td_proc->p_pid; + + EMUL_UNLOCK(&emul_lock); + + LIN_SDT_PROBE0(emul, linux_set_tid_address, return); + return 0; +} + +void +linux_kill_threads(struct thread *td, int sig) +{ + struct linux_emuldata *em, *td_em, *tmp_em; + struct proc *sp; + + LIN_SDT_PROBE2(emul, linux_kill_threads, entry, td, sig); + + td_em = em_find(td->td_proc, EMUL_DONTLOCK); + + KASSERT(td_em != NULL, ("linux_kill_threads: emuldata not found.\n")); + + EMUL_SHARED_RLOCK(&emul_shared_lock); + LIST_FOREACH_SAFE(em, &td_em->shared->threads, threads, tmp_em) { + if (em->pid == td_em->pid) + continue; + + sp = pfind(em->pid); + if ((sp->p_flag & P_WEXIT) == 0) + kern_psignal(sp, sig); + PROC_UNLOCK(sp); + + LIN_SDT_PROBE1(emul, linux_kill_threads, kill, em->pid); + } + EMUL_SHARED_RUNLOCK(&emul_shared_lock); + + LIN_SDT_PROBE0(emul, linux_kill_threads, return); +} diff --git a/sys/compat/linux/linux_emul.h b/sys/compat/linux/linux_emul.h new file mode 100644 index 0000000..f409a34 --- /dev/null +++ b/sys/compat/linux/linux_emul.h @@ -0,0 +1,121 @@ +/*- + * 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 + * 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_EMUL_H_ +#define _LINUX_EMUL_H_ + +#define EMUL_SHARED_HASXSTAT 0x01 + +struct linux_emuldata_shared { + int refs; + int flags; + int xstat; + pid_t group_pid; + + LIST_HEAD(, linux_emuldata) threads; /* head of list of linux threads */ +}; + +/* + * modeled after similar structure in NetBSD + * this will be extended as we need more functionality + */ +struct linux_emuldata { + pid_t pid; + + 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 */ + + struct linux_emuldata_shared *shared; + + int pdeath_signal; /* parent death signal */ + int flags; /* different emuldata flags */ + + struct linux_robust_list_head *robust_futexes; + + LIST_ENTRY(linux_emuldata) threads; /* list of linux threads */ +}; + +struct linux_emuldata *em_find(struct proc *, int locked); + +/* + * DTrace probes for locks should be fired after locking and before releasing + * to prevent races (to provide data/function stability in dtrace, see the + * output of "dtrace -v ..." and the corresponding dtrace docs). + */ +#define EMUL_LOCK(l) do { \ + mtx_lock(l); \ + LIN_SDT_PROBE1(locks, emul_lock, \ + locked, l); \ + } while (0) +#define EMUL_UNLOCK(l) do { \ + LIN_SDT_PROBE1(locks, emul_lock, \ + unlock, l); \ + mtx_unlock(l); \ + } while (0) + +#define EMUL_SHARED_RLOCK(l) do { \ + sx_slock(l); \ + LIN_SDT_PROBE1(locks, emul_shared_rlock, \ + locked, l); \ + } while (0) +#define EMUL_SHARED_RUNLOCK(l) do { \ + LIN_SDT_PROBE1(locks, emul_shared_rlock, \ + unlock, l); \ + sx_sunlock(l); \ + } while (0) +#define EMUL_SHARED_WLOCK(l) do { \ + sx_xlock(l); \ + LIN_SDT_PROBE1(locks, emul_shared_wlock, \ + locked, l); \ + } while (0) +#define EMUL_SHARED_WUNLOCK(l) do { \ + LIN_SDT_PROBE1(locks, emul_shared_wlock, \ + unlock, l); \ + sx_xunlock(l); \ + } while (0) + +/* for em_find use */ +#define EMUL_DOLOCK 1 +#define EMUL_DONTLOCK 0 + +/* emuldata flags */ +#define LINUX_XDEPR_REQUEUEOP 0x00000001 /* uses deprecated + futex REQUEUE op*/ + +int linux_proc_init(struct thread *, pid_t, int); +void linux_proc_exit(void *, struct proc *); +void linux_schedtail(struct thread *); +void linux_proc_exec(void *, struct proc *, struct image_params *); +void linux_kill_threads(struct thread *, int); + +extern struct sx emul_shared_lock; +extern struct mtx emul_lock; + +#endif /* !_LINUX_EMUL_H_ */ diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c new file mode 100644 index 0000000..49c3fdf --- /dev/null +++ b/sys/compat/linux/linux_file.c @@ -0,0 +1,1617 @@ +/*- + * 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/systm.h> +#include <sys/capability.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/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> + +#include <security/mac/mac_framework.h> + +#include <ufs/ufs/extattr.h> +#include <ufs/ufs/quota.h> +#include <ufs/ufs/ufsmount.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> +#include <compat/linux/linux_file.h> + +int +linux_creat(struct thread *td, struct linux_creat_args *args) +{ + char *path; + int error; + + LCONVPATHEXIST(td, args->path, &path); + +#ifdef DEBUG + if (ldebug(creat)) + printf(ARGS(creat, "%s, %d"), path, args->mode); +#endif + error = kern_open(td, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC, + args->mode); + LFREEPATH(path); + return (error); +} + + +static int +linux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mode) +{ + struct proc *p = td->td_proc; + struct file *fp; + int fd; + int bsd_flags, error; + + 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_NONBLOCK) + bsd_flags |= O_NONBLOCK; + if (l_flags & LINUX_FASYNC) + 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. */ + + error = kern_openat(td, dirfd, path, UIO_SYSSPACE, bsd_flags, mode); + + if (!error) { + fd = td->td_retval[0]; + /* + * XXX In between kern_open() and fget(), another process + * having the same filedesc could use that fd without + * checking below. + */ + error = fget(td, fd, CAP_IOCTL, &fp); + if (!error) { + sx_slock(&proctree_lock); + PROC_LOCK(p); + if (!(bsd_flags & O_NOCTTY) && + SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { + PROC_UNLOCK(p); + sx_unlock(&proctree_lock); + /* XXXPJD: Verify if TIOCSCTTY is allowed. */ + if (fp->f_type == DTYPE_VNODE) + (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, + td->td_ucred, td); + } else { + PROC_UNLOCK(p); + sx_sunlock(&proctree_lock); + } + fdrop(fp, td); + /* + * XXX as above, fdrop()/kern_close() pair is racy. + */ + if (error) + kern_close(td, fd); + } + } + +#ifdef DEBUG + if (ldebug(open)) + printf(LMSG("open returns error %d"), error); +#endif + LFREEPATH(path); + return (error); +} + +int +linux_openat(struct thread *td, struct linux_openat_args *args) +{ + char *path; + int dfd; + + dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; + if (args->flags & LINUX_O_CREAT) + LCONVPATH_AT(td, args->filename, &path, 1, dfd); + else + LCONVPATH_AT(td, args->filename, &path, 0, dfd); +#ifdef DEBUG + if (ldebug(openat)) + printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd, + path, args->flags, args->mode); +#endif + return (linux_common_open(td, dfd, path, args->flags, args->mode)); +} + +int +linux_open(struct thread *td, struct linux_open_args *args) +{ + char *path; + + if (args->flags & LINUX_O_CREAT) + LCONVPATHCREAT(td, args->path, &path); + else + LCONVPATHEXIST(td, args->path, &path); + +#ifdef DEBUG + if (ldebug(open)) + printf(ARGS(open, "%s, 0x%x, 0x%x"), + path, args->flags, args->mode); +#endif + + return (linux_common_open(td, AT_FDCWD, path, args->flags, args->mode)); +} + +int +linux_lseek(struct thread *td, struct linux_lseek_args *args) +{ + + struct lseek_args /* { + int fd; + int pad; + off_t offset; + int whence; + } */ tmp_args; + int error; + +#ifdef DEBUG + if (ldebug(lseek)) + printf(ARGS(lseek, "%d, %ld, %d"), + args->fdes, (long)args->off, args->whence); +#endif + tmp_args.fd = args->fdes; + tmp_args.offset = (off_t)args->off; + tmp_args.whence = args->whence; + error = sys_lseek(td, &tmp_args); + return error; +} + +int +linux_llseek(struct thread *td, struct linux_llseek_args *args) +{ + struct lseek_args bsd_args; + int error; + off_t off; + +#ifdef DEBUG + if (ldebug(llseek)) + printf(ARGS(llseek, "%d, %d:%d, %d"), + args->fd, args->ohigh, args->olow, args->whence); +#endif + off = (args->olow) | (((off_t) args->ohigh) << 32); + + bsd_args.fd = args->fd; + bsd_args.offset = off; + bsd_args.whence = args->whence; + + if ((error = sys_lseek(td, &bsd_args))) + return error; + + if ((error = copyout(td->td_retval, args->res, sizeof (off_t)))) + return error; + + td->td_retval[0] = 0; + return 0; +} + +int +linux_readdir(struct thread *td, struct linux_readdir_args *args) +{ + struct linux_getdents_args lda; + + lda.fd = args->fd; + lda.dent = args->dent; + lda.count = 1; + return linux_getdents(td, &lda); +} + +/* + * 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. We use this to common the code, with the exception of + * accessing struct dirent. Note that linux_readdir(2) is implemented + * by means of linux_getdents(2). In this case we never operate on + * struct dirent64 and thus don't need to handle it... + */ + +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)) + +#define LINUX_MAXRECLEN max(LINUX_RECLEN(LINUX_NAME_MAX), \ + LINUX_RECLEN64(LINUX_NAME_MAX)) +#define LINUX_DIRBLKSIZ 512 + +static int +getdents_common(struct thread *td, struct linux_getdents64_args *args, + int is64bit) +{ + struct dirent *bdp; + struct vnode *vp; + caddr_t inp, buf; /* BSD-format */ + int len, reclen; /* BSD-format */ + caddr_t outp; /* Linux-format */ + int resid, linuxreclen=0; /* Linux-format */ + caddr_t lbuf; /* Linux-format */ + struct file *fp; + struct uio auio; + struct iovec aiov; + off_t off; + struct l_dirent *linux_dirent; + struct l_dirent64 *linux_dirent64; + int buflen, error, eofflag, nbytes, justone; + u_long *cookies = NULL, *cookiep; + int ncookies; + + nbytes = args->count; + if (nbytes == 1) { + /* readdir(2) case. Always struct dirent. */ + if (is64bit) + return (EINVAL); + nbytes = sizeof(*linux_dirent); + justone = 1; + } else + justone = 0; + + if ((error = getvnode(td->td_proc->p_fd, args->fd, CAP_READ, &fp)) != 0) + return (error); + + if ((fp->f_flag & FREAD) == 0) { + fdrop(fp, td); + return (EBADF); + } + + off = foffset_lock(fp, 0); + vp = fp->f_vnode; + if (vp->v_type != VDIR) { + foffset_unlock(fp, off, 0); + fdrop(fp, td); + return (EINVAL); + } + + + buflen = max(LINUX_DIRBLKSIZ, nbytes); + buflen = min(buflen, MAXBSIZE); + buf = malloc(buflen, M_TEMP, M_WAITOK); + lbuf = malloc(LINUX_MAXRECLEN, M_TEMP, M_WAITOK | M_ZERO); + vn_lock(vp, LK_SHARED | LK_RETRY); + + aiov.iov_base = buf; + aiov.iov_len = buflen; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_td = td; + auio.uio_resid = buflen; + auio.uio_offset = off; + +#ifdef MAC + /* + * Do directory search MAC check using non-cached credentials. + */ + if ((error = mac_vnode_check_readdir(td->td_ucred, vp))) + goto out; +#endif /* MAC */ + if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, + &cookies))) + goto out; + + inp = buf; + outp = (caddr_t)args->dirent; + resid = nbytes; + if ((len = buflen - auio.uio_resid) <= 0) + goto eof; + + cookiep = cookies; + + if (cookies) { + /* + * When using cookies, the vfs has the option of reading from + * a different offset than that supplied (UFS truncates the + * offset to a block boundary to make sure that it never reads + * partway through a directory entry, even if the directory + * has been compacted). + */ + while (len > 0 && ncookies > 0 && *cookiep <= off) { + bdp = (struct dirent *) inp; + len -= bdp->d_reclen; + inp += bdp->d_reclen; + cookiep++; + ncookies--; + } + } + + while (len > 0) { + if (cookiep && ncookies == 0) + break; + bdp = (struct dirent *) inp; + reclen = bdp->d_reclen; + if (reclen & 3) { + error = EFAULT; + goto out; + } + + if (bdp->d_fileno == 0) { + inp += reclen; + if (cookiep) { + off = *cookiep++; + ncookies--; + } else + off += reclen; + + len -= reclen; + continue; + } + + linuxreclen = (is64bit) + ? LINUX_RECLEN64(bdp->d_namlen) + : LINUX_RECLEN(bdp->d_namlen); + + if (reclen > len || resid < linuxreclen) { + outp++; + break; + } + + if (justone) { + /* readdir(2) case. */ + linux_dirent = (struct l_dirent*)lbuf; + linux_dirent->d_ino = bdp->d_fileno; + linux_dirent->d_off = (l_off_t)linuxreclen; + linux_dirent->d_reclen = (l_ushort)bdp->d_namlen; + strlcpy(linux_dirent->d_name, bdp->d_name, + linuxreclen - offsetof(struct l_dirent, d_name)); + error = copyout(linux_dirent, outp, linuxreclen); + } + if (is64bit) { + linux_dirent64 = (struct l_dirent64*)lbuf; + linux_dirent64->d_ino = bdp->d_fileno; + linux_dirent64->d_off = (cookiep) + ? (l_off_t)*cookiep + : (l_off_t)(off + reclen); + linux_dirent64->d_reclen = (l_ushort)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); + } else if (!justone) { + linux_dirent = (struct l_dirent*)lbuf; + linux_dirent->d_ino = bdp->d_fileno; + linux_dirent->d_off = (cookiep) + ? (l_off_t)*cookiep + : (l_off_t)(off + reclen); + linux_dirent->d_reclen = (l_ushort)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) + goto out; + + inp += reclen; + if (cookiep) { + off = *cookiep++; + ncookies--; + } else + off += reclen; + + outp += linuxreclen; + resid -= linuxreclen; + len -= reclen; + if (justone) + break; + } + + if (outp == (caddr_t)args->dirent) { + nbytes = resid; + goto eof; + } + + if (justone) + nbytes = resid + linuxreclen; + +eof: + td->td_retval[0] = nbytes - resid; + +out: + free(cookies, M_TEMP); + + VOP_UNLOCK(vp, 0); + foffset_unlock(fp, off, 0); + fdrop(fp, td); + free(buf, M_TEMP); + free(lbuf, M_TEMP); + return (error); +} + +int +linux_getdents(struct thread *td, struct linux_getdents_args *args) +{ + +#ifdef DEBUG + if (ldebug(getdents)) + printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count); +#endif + + return (getdents_common(td, (struct linux_getdents64_args*)args, 0)); +} + +int +linux_getdents64(struct thread *td, struct linux_getdents64_args *args) +{ + +#ifdef DEBUG + if (ldebug(getdents64)) + printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count); +#endif + + return (getdents_common(td, args, 1)); +} + +/* + * These exist mainly for hooks for doing /compat/linux translation. + */ + +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); + + LCONVPATHEXIST(td, args->path, &path); + +#ifdef DEBUG + if (ldebug(access)) + printf(ARGS(access, "%s, %d"), path, args->amode); +#endif + error = kern_access(td, path, UIO_SYSSPACE, args->amode); + LFREEPATH(path); + + return (error); +} + +int +linux_faccessat(struct thread *td, struct linux_faccessat_args *args) +{ + char *path; + int error, dfd, flag; + + if (args->flag & ~LINUX_AT_EACCESS) + return (EINVAL); + /* 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; + LCONVPATHEXIST_AT(td, args->filename, &path, dfd); + +#ifdef DEBUG + if (ldebug(access)) + printf(ARGS(access, "%s, %d"), path, args->amode); +#endif + + flag = (args->flag & LINUX_AT_EACCESS) == 0 ? 0 : AT_EACCESS; + error = kern_accessat(td, dfd, path, UIO_SYSSPACE, flag, args->amode); + LFREEPATH(path); + + return (error); +} + +int +linux_unlink(struct thread *td, struct linux_unlink_args *args) +{ + char *path; + int error; + struct stat st; + + LCONVPATHEXIST(td, args->path, &path); + +#ifdef DEBUG + if (ldebug(unlink)) + printf(ARGS(unlink, "%s"), path); +#endif + + error = kern_unlink(td, path, UIO_SYSSPACE); + if (error == EPERM) + /* Introduce POSIX noncompliant behaviour of Linux */ + if (kern_stat(td, path, UIO_SYSSPACE, &st) == 0) + if (S_ISDIR(st.st_mode)) + error = EISDIR; + LFREEPATH(path); + return (error); +} + +int +linux_unlinkat(struct thread *td, struct linux_unlinkat_args *args) +{ + char *path; + int error, dfd; + struct stat st; + + if (args->flag & ~LINUX_AT_REMOVEDIR) + return (EINVAL); + + dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; + LCONVPATHEXIST_AT(td, args->pathname, &path, dfd); + +#ifdef DEBUG + if (ldebug(unlinkat)) + printf(ARGS(unlinkat, "%s"), path); +#endif + + if (args->flag & LINUX_AT_REMOVEDIR) + error = kern_rmdirat(td, dfd, path, UIO_SYSSPACE); + else + error = kern_unlinkat(td, dfd, path, UIO_SYSSPACE, 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) == 0 && S_ISDIR(st.st_mode)) + error = EISDIR; + } + LFREEPATH(path); + return (error); +} +int +linux_chdir(struct thread *td, struct linux_chdir_args *args) +{ + char *path; + int error; + + LCONVPATHEXIST(td, args->path, &path); + +#ifdef DEBUG + if (ldebug(chdir)) + printf(ARGS(chdir, "%s"), path); +#endif + error = kern_chdir(td, path, UIO_SYSSPACE); + LFREEPATH(path); + return (error); +} + +int +linux_chmod(struct thread *td, struct linux_chmod_args *args) +{ + char *path; + int error; + + LCONVPATHEXIST(td, args->path, &path); + +#ifdef DEBUG + if (ldebug(chmod)) + printf(ARGS(chmod, "%s, %d"), path, args->mode); +#endif + error = kern_chmod(td, path, UIO_SYSSPACE, args->mode); + LFREEPATH(path); + return (error); +} + +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; + LCONVPATHEXIST_AT(td, args->filename, &path, dfd); + +#ifdef DEBUG + if (ldebug(fchmodat)) + printf(ARGS(fchmodat, "%s, %d"), path, args->mode); +#endif + + error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0); + LFREEPATH(path); + return (error); +} + +int +linux_mkdir(struct thread *td, struct linux_mkdir_args *args) +{ + char *path; + int error; + + LCONVPATHCREAT(td, args->path, &path); + +#ifdef DEBUG + if (ldebug(mkdir)) + printf(ARGS(mkdir, "%s, %d"), path, args->mode); +#endif + error = kern_mkdir(td, path, UIO_SYSSPACE, args->mode); + LFREEPATH(path); + return (error); +} + +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; + LCONVPATHCREAT_AT(td, args->pathname, &path, dfd); + +#ifdef DEBUG + if (ldebug(mkdirat)) + printf(ARGS(mkdirat, "%s, %d"), path, args->mode); +#endif + error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode); + LFREEPATH(path); + return (error); +} + +int +linux_rmdir(struct thread *td, struct linux_rmdir_args *args) +{ + char *path; + int error; + + LCONVPATHEXIST(td, args->path, &path); + +#ifdef DEBUG + if (ldebug(rmdir)) + printf(ARGS(rmdir, "%s"), path); +#endif + error = kern_rmdir(td, path, UIO_SYSSPACE); + LFREEPATH(path); + return (error); +} + +int +linux_rename(struct thread *td, struct linux_rename_args *args) +{ + char *from, *to; + int error; + + 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); + } + +#ifdef DEBUG + if (ldebug(rename)) + printf(ARGS(rename, "%s, %s"), from, to); +#endif + error = kern_rename(td, from, to, UIO_SYSSPACE); + LFREEPATH(from); + LFREEPATH(to); + return (error); +} + +int +linux_renameat(struct thread *td, struct linux_renameat_args *args) +{ + char *from, *to; + int error, olddfd, newdfd; + + olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; + newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; + 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); + } + +#ifdef DEBUG + if (ldebug(renameat)) + printf(ARGS(renameat, "%s, %s"), from, to); +#endif + error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE); + LFREEPATH(from); + LFREEPATH(to); + return (error); +} + +int +linux_symlink(struct thread *td, struct linux_symlink_args *args) +{ + char *path, *to; + int error; + + 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); + } + +#ifdef DEBUG + if (ldebug(symlink)) + printf(ARGS(symlink, "%s, %s"), path, to); +#endif + error = kern_symlink(td, path, to, UIO_SYSSPACE); + LFREEPATH(path); + LFREEPATH(to); + return (error); +} + +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; + LCONVPATHEXIST_AT(td, args->oldname, &path, dfd); + /* 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); + } + +#ifdef DEBUG + if (ldebug(symlinkat)) + printf(ARGS(symlinkat, "%s, %s"), path, to); +#endif + + error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE); + LFREEPATH(path); + LFREEPATH(to); + return (error); +} + +int +linux_readlink(struct thread *td, struct linux_readlink_args *args) +{ + char *name; + int error; + + LCONVPATHEXIST(td, args->name, &name); + +#ifdef DEBUG + if (ldebug(readlink)) + printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf, + args->count); +#endif + error = kern_readlink(td, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE, + args->count); + LFREEPATH(name); + return (error); +} + +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; + LCONVPATHEXIST_AT(td, args->path, &name, dfd); + +#ifdef DEBUG + if (ldebug(readlinkat)) + printf(ARGS(readlinkat, "%s, %p, %d"), name, (void *)args->buf, + args->bufsiz); +#endif + + 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; + + LCONVPATHEXIST(td, args->path, &path); + +#ifdef DEBUG + if (ldebug(truncate)) + printf(ARGS(truncate, "%s, %ld"), path, (long)args->length); +#endif + + error = kern_truncate(td, path, UIO_SYSSPACE, args->length); + LFREEPATH(path); + return (error); +} + +int +linux_truncate64(struct thread *td, struct linux_truncate64_args *args) +{ + char *path; + int error; + + LCONVPATHEXIST(td, args->path, &path); + +#ifdef DEBUG + if (ldebug(truncate64)) + printf(ARGS(truncate64, "%s, %jd"), path, args->length); +#endif + + error = kern_truncate(td, path, UIO_SYSSPACE, args->length); + LFREEPATH(path); + return (error); +} +int +linux_ftruncate(struct thread *td, struct linux_ftruncate_args *args) +{ + struct ftruncate_args /* { + int fd; + int pad; + off_t length; + } */ nuap; + + nuap.fd = args->fd; + nuap.length = args->length; + return (sys_ftruncate(td, &nuap)); +} + +int +linux_link(struct thread *td, struct linux_link_args *args) +{ + char *path, *to; + int error; + + 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); + } + +#ifdef DEBUG + if (ldebug(link)) + printf(ARGS(link, "%s, %s"), path, to); +#endif + error = kern_link(td, path, to, UIO_SYSSPACE); + LFREEPATH(path); + LFREEPATH(to); + return (error); +} + +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; + 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); + } + +#ifdef DEBUG + if (ldebug(linkat)) + printf(ARGS(linkat, "%i, %s, %i, %s, %i"), args->olddfd, path, + args->newdfd, to, args->flag); +#endif + + follow = (args->flag & LINUX_AT_SYMLINK_FOLLOW) == 0 ? NOFOLLOW : + FOLLOW; + error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, follow); + LFREEPATH(path); + LFREEPATH(to); + return (error); +} + +int +linux_fdatasync(td, uap) + struct thread *td; + struct linux_fdatasync_args *uap; +{ + struct fsync_args bsd; + + bsd.fd = uap->fd; + return sys_fsync(td, &bsd); +} + +int +linux_pread(td, uap) + struct thread *td; + struct linux_pread_args *uap; +{ + struct pread_args bsd; + struct vnode *vp; + int error; + + bsd.fd = uap->fd; + bsd.buf = uap->buf; + bsd.nbyte = uap->nbyte; + bsd.offset = uap->offset; + + error = sys_pread(td, &bsd); + + if (error == 0) { + /* This seems to violate POSIX but linux does it */ + if ((error = fgetvp(td, uap->fd, CAP_PREAD, &vp)) != 0) + return (error); + if (vp->v_type == VDIR) { + vrele(vp); + return (EISDIR); + } + vrele(vp); + } + + return (error); +} + +int +linux_pwrite(td, uap) + struct thread *td; + struct linux_pwrite_args *uap; +{ + struct pwrite_args bsd; + + bsd.fd = uap->fd; + bsd.buf = uap->buf; + bsd.nbyte = uap->nbyte; + bsd.offset = uap->offset; + return sys_pwrite(td, &bsd); +} + +int +linux_mount(struct thread *td, struct linux_mount_args *args) +{ + struct ufs_args ufs; + char fstypename[MFSNAMELEN]; + char mntonname[MNAMELEN], mntfromname[MNAMELEN]; + int error; + int fsflags; + void *fsdata; + + error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1, + NULL); + if (error) + return (error); + error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL); + if (error) + return (error); + error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL); + if (error) + return (error); + +#ifdef DEBUG + if (ldebug(mount)) + printf(ARGS(mount, "%s, %s, %s"), + fstypename, mntfromname, mntonname); +#endif + + if (strcmp(fstypename, "ext2") == 0) { + strcpy(fstypename, "ext2fs"); + fsdata = &ufs; + ufs.fspec = mntfromname; +#define DEFAULT_ROOTID -2 + ufs.export.ex_root = DEFAULT_ROOTID; + ufs.export.ex_flags = + args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0; + } else if (strcmp(fstypename, "proc") == 0) { + strcpy(fstypename, "linprocfs"); + fsdata = NULL; + } else if (strcmp(fstypename, "vfat") == 0) { + strcpy(fstypename, "msdosfs"); + fsdata = NULL; + } else { + return (ENODEV); + } + + fsflags = 0; + + if ((args->rwflag & 0xffff0000) == 0xc0ed0000) { + /* + * 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; + } + + if (strcmp(fstypename, "linprocfs") == 0) { + error = kernel_vmount(fsflags, + "fstype", fstypename, + "fspath", mntonname, + NULL); + } else if (strcmp(fstypename, "msdosfs") == 0) { + error = kernel_vmount(fsflags, + "fstype", fstypename, + "fspath", mntonname, + "from", mntfromname, + NULL); + } else + error = EOPNOTSUPP; + return (error); +} + +int +linux_oldumount(struct thread *td, struct linux_oldumount_args *args) +{ + struct linux_umount_args args2; + + args2.path = args->path; + args2.flags = 0; + return (linux_umount(td, &args2)); +} + +int +linux_umount(struct thread *td, struct linux_umount_args *args) +{ + struct unmount_args bsd; + + bsd.path = args->path; + bsd.flags = args->flags; /* XXX correct? */ + return (sys_unmount(td, &bsd)); +} + +/* + * 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_fcntl64_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_FASYNC; +#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_FASYNC) + 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, &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)); + } + + return (EINVAL); +} + +int +linux_fcntl(struct thread *td, struct linux_fcntl_args *args) +{ + struct linux_fcntl64_args args64; + +#ifdef DEBUG + if (ldebug(fcntl)) + printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd); +#endif + + args64.fd = args->fd; + args64.cmd = args->cmd; + args64.arg = args->arg; + return (fcntl_common(td, &args64)); +} + +#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; + int error; + +#ifdef DEBUG + if (ldebug(fcntl64)) + printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd); +#endif + + 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)); + } + + return (fcntl_common(td, args)); +} +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ + +int +linux_chown(struct thread *td, struct linux_chown_args *args) +{ + char *path; + int error; + + LCONVPATHEXIST(td, args->path, &path); + +#ifdef DEBUG + if (ldebug(chown)) + printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid); +#endif + error = kern_chown(td, path, UIO_SYSSPACE, args->uid, args->gid); + LFREEPATH(path); + return (error); +} + +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; + LCONVPATHEXIST_AT(td, args->filename, &path, dfd); + +#ifdef DEBUG + if (ldebug(fchownat)) + printf(ARGS(fchownat, "%s, %d, %d"), path, args->uid, args->gid); +#endif + + flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 : + AT_SYMLINK_NOFOLLOW; + error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid, + flag); + LFREEPATH(path); + return (error); +} + +int +linux_lchown(struct thread *td, struct linux_lchown_args *args) +{ + char *path; + int error; + + LCONVPATHEXIST(td, args->path, &path); + +#ifdef DEBUG + if (ldebug(lchown)) + printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid); +#endif + error = kern_lchown(td, path, UIO_SYSSPACE, args->uid, args->gid); + LFREEPATH(path); + return (error); +} + +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) +{ + int advice; + + advice = convert_fadvice(args->advice); + if (advice == -1) + return (EINVAL); + return (kern_posix_fadvise(td, args->fd, args->offset, args->len, + advice)); +} + +int +linux_fadvise64_64(struct thread *td, struct linux_fadvise64_64_args *args) +{ + int advice; + + advice = convert_fadvice(args->advice); + if (advice == -1) + return (EINVAL); + return (kern_posix_fadvise(td, args->fd, args->offset, args->len, + advice)); +} + +int +linux_pipe(struct thread *td, struct linux_pipe_args *args) +{ + int fildes[2]; + int error; + +#ifdef DEBUG + if (ldebug(pipe)) + printf(ARGS(pipe, "*")); +#endif + + error = kern_pipe2(td, fildes, 0); + if (error) + return (error); + + /* XXX: Close descriptors on error. */ + return (copyout(fildes, args->pipefds, sizeof(fildes))); +} + +int +linux_pipe2(struct thread *td, struct linux_pipe2_args *args) +{ + int fildes[2]; + int error, flags; + +#ifdef DEBUG + if (ldebug(pipe2)) + printf(ARGS(pipe2, "*, %d"), args->flags); +#endif + + 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_pipe2(td, fildes, flags); + if (error) + return (error); + + /* XXX: Close descriptors on error. */ + return (copyout(fildes, args->pipefds, sizeof(fildes))); +} diff --git a/sys/compat/linux/linux_file.h b/sys/compat/linux/linux_file.h new file mode 100644 index 0000000..2d3106f --- /dev/null +++ b/sys/compat/linux/linux_file.h @@ -0,0 +1,57 @@ +/*- + * 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 + +/* + * 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 + +#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 0000000..2103636 --- /dev/null +++ b/sys/compat/linux/linux_fork.c @@ -0,0 +1,300 @@ +/*- + * 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 "opt_kdtrace.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/imgact.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/proc.h> +#include <sys/sched.h> +#include <sys/sdt.h> +#include <sys/sx.h> +#include <sys/unistd.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_signal.h> +#include <compat/linux/linux_emul.h> +#include <compat/linux/linux_misc.h> + +/* DTrace init */ +LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); + +/* Linuxulator-global DTrace probes */ +LIN_SDT_PROBE_DECLARE(locks, emul_lock, locked); +LIN_SDT_PROBE_DECLARE(locks, emul_lock, unlock); + + +int +linux_fork(struct thread *td, struct linux_fork_args *args) +{ + int error; + struct proc *p2; + struct thread *td2; + +#ifdef DEBUG + if (ldebug(fork)) + printf(ARGS(fork, "")); +#endif + + if ((error = fork1(td, RFFDG | RFPROC | RFSTOPPED, 0, &p2, NULL, 0)) + != 0) + return (error); + + td->td_retval[0] = p2->p_pid; + td->td_retval[1] = 0; + + error = linux_proc_init(td, td->td_retval[0], 0); + if (error) + return (error); + + td2 = FIRST_THREAD_IN_PROC(p2); + + /* + * Make this runnable after we are finished with it. + */ + thread_lock(td2); + TD_SET_CAN_RUN(td2); + sched_add(td2, SRQ_BORING); + thread_unlock(td2); + + return (0); +} + +int +linux_vfork(struct thread *td, struct linux_vfork_args *args) +{ + int error; + struct proc *p2; + struct thread *td2; + +#ifdef DEBUG + if (ldebug(vfork)) + printf(ARGS(vfork, "")); +#endif + + /* Exclude RFPPWAIT */ + if ((error = fork1(td, RFFDG | RFPROC | RFMEM | RFSTOPPED, 0, &p2, + NULL, 0)) != 0) + return (error); + + td->td_retval[0] = p2->p_pid; + + error = linux_proc_init(td, td->td_retval[0], 0); + if (error) + return (error); + + PROC_LOCK(p2); + p2->p_flag |= P_PPWAIT; + PROC_UNLOCK(p2); + + td2 = FIRST_THREAD_IN_PROC(p2); + + /* + * Make this runnable after we are finished with it. + */ + thread_lock(td2); + TD_SET_CAN_RUN(td2); + sched_add(td2, SRQ_BORING); + thread_unlock(td2); + + /* wait for the children to exit, ie. emulate vfork */ + PROC_LOCK(p2); + while (p2->p_flag & P_PPWAIT) + cv_wait(&p2->p_pwait, &p2->p_mtx); + PROC_UNLOCK(p2); + + return (0); +} + +int +linux_clone(struct thread *td, struct linux_clone_args *args) +{ + int error, ff = RFPROC | RFSTOPPED; + struct proc *p2; + struct thread *td2; + int exit_signal; + struct linux_emuldata *em; + +#ifdef DEBUG + if (ldebug(clone)) { + printf(ARGS(clone, "flags %x, stack %p, parent tid: %p, " + "child tid: %p"), (unsigned)args->flags, + args->stack, args->parent_tidptr, args->child_tidptr); + } +#endif + + exit_signal = args->flags & 0x000000ff; + if (LINUX_SIG_VALID(exit_signal)) { + if (exit_signal <= LINUX_SIGTBLSZ) + exit_signal = + linux_to_bsd_signal[_SIG_IDX(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; + /* + * XXX: In Linux, sharing of fs info (chroot/cwd/umask) + * and open files is independant. In FreeBSD, its in one + * structure but in reality it does not cause any problems + * because both of these flags are usually set together. + */ + if (!(args->flags & (LINUX_CLONE_FILES | LINUX_CLONE_FS))) + ff |= RFFDG; + + /* + * Attempt to detect when linux_clone(2) is used for creating + * kernel threads. Unfortunately despite the existence of the + * CLONE_THREAD flag, version of linuxthreads package used in + * most popular distros as of beginning of 2005 doesn't make + * any use of it. Therefore, this detection relies on + * empirical observation that linuxthreads sets certain + * combination of flags, so that we can make more or less + * precise detection and notify the FreeBSD kernel that several + * processes are in fact part of the same threading group, so + * that special treatment is necessary for signal delivery + * between those processes and fd locking. + */ + if ((args->flags & 0xffffff00) == LINUX_THREADING_FLAGS) + ff |= RFTHREAD; + + if (args->flags & LINUX_CLONE_PARENT_SETTID) + if (args->parent_tidptr == NULL) + return (EINVAL); + + error = fork1(td, ff, 0, &p2, NULL, 0); + if (error) + return (error); + + if (args->flags & (LINUX_CLONE_PARENT | LINUX_CLONE_THREAD)) { + sx_xlock(&proctree_lock); + PROC_LOCK(p2); + proc_reparent(p2, td->td_proc->p_pptr); + PROC_UNLOCK(p2); + sx_xunlock(&proctree_lock); + } + + /* create the emuldata */ + error = linux_proc_init(td, p2->p_pid, args->flags); + /* reference it - no need to check this */ + em = em_find(p2, EMUL_DOLOCK); + KASSERT(em != NULL, ("clone: emuldata not found.")); + /* and adjust it */ + + if (args->flags & LINUX_CLONE_THREAD) { +#ifdef notyet + PROC_LOCK(p2); + p2->p_pgrp = td->td_proc->p_pgrp; + PROC_UNLOCK(p2); +#endif + exit_signal = 0; + } + + 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; + + EMUL_UNLOCK(&emul_lock); + + if (args->flags & LINUX_CLONE_PARENT_SETTID) { + error = copyout(&p2->p_pid, args->parent_tidptr, + sizeof(p2->p_pid)); + if (error) + printf(LMSG("copyout failed!")); + } + + PROC_LOCK(p2); + p2->p_sigparent = exit_signal; + PROC_UNLOCK(p2); + td2 = FIRST_THREAD_IN_PROC(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. + */ + if (args->stack) + linux_set_upcall_kse(td2, PTROUT(args->stack)); + + if (args->flags & LINUX_CLONE_SETTLS) + linux_set_cloned_tls(td2, args->tls); + +#ifdef DEBUG + if (ldebug(clone)) + printf(LMSG("clone: successful rfork to %d, " + "stack %p sig = %d"), (int)p2->p_pid, args->stack, + exit_signal); +#endif + if (args->flags & LINUX_CLONE_VFORK) { + PROC_LOCK(p2); + p2->p_flag |= P_PPWAIT; + PROC_UNLOCK(p2); + } + + /* + * Make this runnable after we are finished with it. + */ + thread_lock(td2); + TD_SET_CAN_RUN(td2); + sched_add(td2, SRQ_BORING); + thread_unlock(td2); + + td->td_retval[0] = p2->p_pid; + td->td_retval[1] = 0; + + if (args->flags & LINUX_CLONE_VFORK) { + /* wait for the children to exit, ie. emulate vfork */ + PROC_LOCK(p2); + while (p2->p_flag & P_PPWAIT) + cv_wait(&p2->p_pwait, &p2->p_mtx); + PROC_UNLOCK(p2); + } + + return (0); +} diff --git a/sys/compat/linux/linux_futex.c b/sys/compat/linux/linux_futex.c new file mode 100644 index 0000000..c1531d0 --- /dev/null +++ b/sys/compat/linux/linux_futex.c @@ -0,0 +1,1228 @@ +/* $NetBSD: linux_futex.c,v 1.7 2006/07/24 19:01:49 manu Exp $ */ + +/*- + * 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 "opt_kdtrace.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/sx.h> +#include <sys/umtx.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_util.h> + +/* DTrace init */ +LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); + +/* Linuxulator-global DTrace probes */ +LIN_SDT_PROBE_DECLARE(locks, emul_lock, locked); +LIN_SDT_PROBE_DECLARE(locks, emul_lock, unlock); + +/** + * 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 **", "int"); +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 *", "uin32_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 l_timespec *", "uint32_t"); +LIN_SDT_PROBE_DEFINE1(futex, futex_wait, copyin_error, "int"); +LIN_SDT_PROBE_DEFINE1(futex, futex_wait, itimerfix_error, "int"); +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 proc *", + "uint32_t *", "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 **", "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_DEFINE1(futex, release_futexes, entry, "struct proc *"); +LIN_SDT_PROBE_DEFINE1(futex, release_futexes, copyin_error, "int"); +LIN_SDT_PROBE_DEFINE0(futex, release_futexes, return); + +static MALLOC_DEFINE(M_FUTEX, "futex", "Linux futexes"); +static MALLOC_DEFINE(M_FUTEX_WP, "futex wp", "Linux futexes wp"); + +struct futex; + +struct waiting_proc { + uint32_t wp_flags; + struct futex *wp_futex; + TAILQ_ENTRY(waiting_proc) wp_list; +}; + +struct futex { + struct sx 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; +}; + +struct futex_list futex_list; + +#define FUTEX_LOCK(f) sx_xlock(&(f)->f_lck) +#define FUTEX_UNLOCK(f) sx_xunlock(&(f)->f_lck) +#define FUTEX_INIT(f) do { \ + sx_init_flags(&(f)->f_lck, "ftlk", \ + SX_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); \ + sx_destroy(&(f)->f_lck); \ + } while (0) +#define FUTEX_ASSERT_LOCKED(f) sx_assert(&(f)->f_lck, SA_XLOCKED) + +struct mtx futex_mtx; /* protects the futex list */ +#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 */ + +/* 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. + */ + +/* support.s */ +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); + +static void +futex_put(struct futex *f, struct waiting_proc *wp) +{ + LIN_SDT_PROBE2(futex, futex_put, entry, f, wp); + + FUTEX_ASSERT_LOCKED(f); + 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; + 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); + FUTEXES_UNLOCK; + FUTEX_UNLOCK(f); + + 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) { + 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); + + 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. + */ + 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 int +futex_sleep(struct futex *f, struct waiting_proc *wp, int timeout) +{ + int error; + + FUTEX_ASSERT_LOCKED(f); + LIN_SDT_PROBE3(futex, futex_sleep, entry, f, wp, timeout); + LINUX_CTR4(sys_futex, "futex_sleep enter uaddr %p wp %p timo %d ref %d", + f->f_uaddr, wp, timeout, f->f_refcount); + error = sx_sleep(wp, &f->f_lck, PCATCH, "futex", timeout); + 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 l_timespec *ts, + uint32_t bitset) +{ + struct l_timespec timeout; + struct timeval tv; + int timeout_hz; + int error; + + LIN_SDT_PROBE4(futex, futex_wait, entry, f, wp, ts, bitset); + + if (bitset == 0) { + LIN_SDT_PROBE1(futex, futex_wait, return, EINVAL); + return (EINVAL); + } + + f->f_bitset = bitset; + + if (ts != NULL) { + error = copyin(ts, &timeout, sizeof(timeout)); + if (error) { + LIN_SDT_PROBE1(futex, futex_wait, copyin_error, error); + LIN_SDT_PROBE1(futex, futex_wait, return, error); + return (error); + } + TIMESPEC_TO_TIMEVAL(&tv, &timeout); + error = itimerfix(&tv); + if (error) { + LIN_SDT_PROBE1(futex, futex_wait, itimerfix_error, + error); + LIN_SDT_PROBE1(futex, futex_wait, return, error); + return (error); + } + timeout_hz = tvtohz(&tv); + } else + timeout_hz = 0; + + error = futex_sleep(f, wp, timeout_hz); + 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, val; + struct linux_emuldata *em; + struct waiting_proc *wp; + struct futex *f, *f2; + int error; + uint32_t flags; + + 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 %d val3 %d", + args->uaddr, args->val, args->val3); + + 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(args->uaddr, &val, sizeof(val)); + if (error) { + LIN_SDT_PROBE1(futex, linux_sys_futex, copyin_error, + error); + LINUX_CTR1(sys_futex, "WAIT copyin failed %d", + error); + futex_put(f, wp); + + 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_CTR4(sys_futex, + "WAIT uaddr %p val %d != uval %d val3 %d", + args->uaddr, args->val, val, args->val3); + futex_put(f, wp); + + LIN_SDT_PROBE1(futex, linux_sys_futex, return, + EWOULDBLOCK); + return (EWOULDBLOCK); + } + + error = futex_wait(f, wp, args->timeout, 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 val % d val3 %d", + 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 " + "val %d val3 %d uaddr2 %p val2 %d", + args->uaddr, args->val, args->val3, args->uaddr2, + (int)(unsigned long)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); + } + + error = futex_get(args->uaddr, NULL, &f, flags); + 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); + if (error) { + futex_put(f, NULL); + + LIN_SDT_PROBE1(futex, linux_sys_futex, return, error); + return (error); + } + error = copyin(args->uaddr, &val, sizeof(val)); + if (error) { + LIN_SDT_PROBE1(futex, linux_sys_futex, copyin_error, + error); + LINUX_CTR1(sys_futex, "CMP_REQUEUE copyin failed %d", + error); + futex_put(f2, NULL); + futex_put(f, NULL); + + 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 %d != uval %d", + 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 op %d val %x uaddr2 %p val3 %x", + args->uaddr, args->op, args->val, + args->uaddr2, args->val3); + + error = futex_get(args->uaddr, NULL, &f, flags); + if (error) { + LIN_SDT_PROBE1(futex, linux_sys_futex, return, error); + return (error); + } + + if (args->uaddr != args->uaddr2) + error = futex_get(args->uaddr2, NULL, &f2, flags); + if (error) { + futex_put(f, NULL); + + LIN_SDT_PROBE1(futex, linux_sys_futex, return, error); + return (error); + } + + /* + * This function returns positive number as results and + * negative as errors + */ + op_ret = futex_atomic_op(td, args->val3, args->uaddr2); + + if (op_ret < 0) { + /* XXX: We don't handle the EFAULT yet. */ + if (op_ret != -EFAULT) { + if (f2 != NULL) + futex_put(f2, NULL); + futex_put(f, NULL); + + LIN_SDT_PROBE1(futex, linux_sys_futex, return, + -op_ret); + return (-op_ret); + } else { + LIN_SDT_PROBE0(futex, linux_sys_futex, + unhandled_efault); + } + if (f2 != NULL) + futex_put(f2, NULL); + futex_put(f, NULL); + + LIN_SDT_PROBE1(futex, linux_sys_futex, return, EFAULT); + return (EFAULT); + } + + 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 */ + linux_msg(td, + "linux_sys_futex: " + "op LINUX_FUTEX_LOCK_PI not implemented\n"); + 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 */ + linux_msg(td, + "linux_sys_futex: " + "op LINUX_FUTEX_UNLOCK_PI not implemented\n"); + 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 */ + linux_msg(td, + "linux_sys_futex: " + "op LINUX_FUTEX_TRYLOCK_PI not implemented\n"); + 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. + */ + em = em_find(td->td_proc, EMUL_DONTLOCK); + if ((em->flags & LINUX_XDEPR_REQUEUEOP) == 0) { + linux_msg(td, + "linux_sys_futex: " + "unsupported futex_requeue op\n"); + em->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 */ + linux_msg(td, + "linux_sys_futex: " + "op FUTEX_WAIT_REQUEUE_PI not implemented\n"); + 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 */ + linux_msg(td, + "linux_sys_futex: " + "op LINUX_FUTEX_CMP_REQUEUE_PI not implemented\n"); + 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, + "linux_sys_futex: unknown op %d\n", 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->td_proc, EMUL_DOLOCK); + em->robust_futexes = args->head; + EMUL_UNLOCK(&emul_lock); + + 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); + int error = 0; + + LIN_SDT_PROBE2(futex, linux_get_robust_list, entry, td, args); + + if (!args->pid) { + em = em_find(td->td_proc, EMUL_DONTLOCK); + head = em->robust_futexes; + } else { + struct proc *p; + + p = pfind(args->pid); + if (p == NULL) { + LIN_SDT_PROBE1(futex, linux_get_robust_list, return, + ESRCH); + return (ESRCH); + } + + em = em_find(p, EMUL_DONTLOCK); + /* XXX: ptrace? */ + if (priv_check(td, PRIV_CRED_SETUID) || + priv_check(td, PRIV_CRED_SETEUID) || + p_candebug(td, p)) { + PROC_UNLOCK(p); + + LIN_SDT_PROBE1(futex, linux_get_robust_list, return, + EPERM); + return (EPERM); + } + head = em->robust_futexes; + + PROC_UNLOCK(p); + } + + 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(struct linux_robust_list_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 proc *p, uint32_t *uaddr, int pi) +{ + uint32_t uval, nval, mval; + struct futex *f; + int error; + + LIN_SDT_PROBE3(futex, handle_futex_death, entry, p, 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) == p->p_pid) { + 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, 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 proc *p) +{ + struct linux_robust_list_head *head = NULL; + struct linux_robust_list *entry, *next_entry, *pending; + unsigned int limit = 2048, pi, next_pi, pip; + struct linux_emuldata *em; + l_long futex_offset; + int rc, error; + + LIN_SDT_PROBE1(futex, release_futexes, entry, p); + + em = em_find(p, EMUL_DONTLOCK); + 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(p, + (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(p, (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 0000000..0990daa --- /dev/null +++ b/sys/compat/linux/linux_futex.h @@ -0,0 +1,81 @@ +/* $NetBSD: linux_futex.h,v 1.2 2005/12/11 12:20:19 christos Exp $ */ + +/*- + * 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 + +extern LIST_HEAD(futex_list, futex) futex_list; +extern struct mtx futex_mtx; + +#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 + +void release_futexes(struct proc *); + +#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 0000000..cad5a22 --- /dev/null +++ b/sys/compat/linux/linux_getcwd.c @@ -0,0 +1,469 @@ +/* $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 $ */ +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Bill Sommerfeld. + * + * 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/namei.h> +#include <sys/filedesc.h> +#include <sys/kernel.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/syscallsubr.h> +#include <sys/vnode.h> +#include <sys/mount.h> +#include <sys/proc.h> +#include <sys/uio.h> +#include <sys/malloc.h> +#include <sys/dirent.h> +#include <ufs/ufs/dir.h> /* XXX only for DIRBLKSIZ */ + +#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 <security/mac/mac_framework.h> + +static int +linux_getcwd_scandir(struct vnode **, struct vnode **, + char **, char *, struct thread *); +static int +linux_getcwd_common(struct vnode *, struct vnode *, + char **, char *, int, int, struct thread *); + +#define DIRENT_MINSIZE (sizeof(struct dirent) - (MAXNAMLEN+1) + 4) + +/* + * Vnode variable naming conventions in this file: + * + * rvp: the current root we're aiming towards. + * lvp, *lvpp: the "lower" vnode + * uvp, *uvpp: the "upper" vnode. + * + * Since all the vnodes we're dealing with are directories, and the + * lookups are going *up* in the filesystem rather than *down*, the + * usual "pvp" (parent) or "dvp" (directory) naming conventions are + * too confusing. + */ + +/* + * XXX Will infinite loop in certain cases if a directory read reliably + * returns EINVAL on last block. + * XXX is EINVAL the right thing to return if a directory is malformed? + */ + +/* + * XXX Untested vs. mount -o union; probably does the wrong thing. + */ + +/* + * Find parent vnode of *lvpp, return in *uvpp + * + * If we care about the name, scan it looking for name of directory + * entry pointing at lvp. + * + * Place the name in the buffer which starts at bufp, immediately + * before *bpp, and move bpp backwards to point at the start of it. + * + * On entry, *lvpp is a locked vnode reference; on exit, it is vput and NULL'ed + * On exit, *uvpp is either NULL or is a locked vnode reference. + */ +static int +linux_getcwd_scandir(lvpp, uvpp, bpp, bufp, td) + struct vnode **lvpp; + struct vnode **uvpp; + char **bpp; + char *bufp; + struct thread *td; +{ + int error = 0; + int eofflag; + off_t off; + int tries; + struct uio uio; + struct iovec iov; + char *dirbuf = NULL; + int dirbuflen; + ino_t fileno; + struct vattr va; + struct vnode *uvp = NULL; + struct vnode *lvp = *lvpp; + struct componentname cn; + int len, reclen; + tries = 0; + + /* + * If we want the filename, get some info we need while the + * current directory is still locked. + */ + if (bufp != NULL) { + error = VOP_GETATTR(lvp, &va, td->td_ucred); + if (error) { + vput(lvp); + *lvpp = NULL; + *uvpp = NULL; + return error; + } + } + + /* + * Ok, we have to do it the hard way.. + * Next, get parent vnode using lookup of .. + */ + cn.cn_nameiop = LOOKUP; + cn.cn_flags = ISLASTCN | ISDOTDOT | RDONLY; + cn.cn_thread = td; + cn.cn_cred = td->td_ucred; + cn.cn_pnbuf = NULL; + cn.cn_nameptr = ".."; + cn.cn_namelen = 2; + cn.cn_consume = 0; + cn.cn_lkflags = LK_SHARED; + + /* + * At this point, lvp is locked and will be unlocked by the lookup. + * On successful return, *uvpp will be locked + */ +#ifdef MAC + error = mac_vnode_check_lookup(td->td_ucred, lvp, &cn); + if (error == 0) +#endif + error = VOP_LOOKUP(lvp, uvpp, &cn); + if (error) { + vput(lvp); + *lvpp = NULL; + *uvpp = NULL; + return error; + } + uvp = *uvpp; + + /* If we don't care about the pathname, we're done */ + if (bufp == NULL) { + vput(lvp); + *lvpp = NULL; + return 0; + } + + fileno = va.va_fileid; + + dirbuflen = DIRBLKSIZ; + if (dirbuflen < va.va_blocksize) + dirbuflen = va.va_blocksize; + dirbuf = (char *)malloc(dirbuflen, M_TEMP, M_WAITOK); + +#if 0 +unionread: +#endif + off = 0; + do { + /* call VOP_READDIR of parent */ + iov.iov_base = dirbuf; + iov.iov_len = dirbuflen; + + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_offset = off; + uio.uio_resid = dirbuflen; + uio.uio_segflg = UIO_SYSSPACE; + uio.uio_rw = UIO_READ; + uio.uio_td = td; + + eofflag = 0; + +#ifdef MAC + error = mac_vnode_check_readdir(td->td_ucred, uvp); + if (error == 0) +#endif /* MAC */ + error = VOP_READDIR(uvp, &uio, td->td_ucred, &eofflag, + 0, 0); + + off = uio.uio_offset; + + /* + * Try again if NFS tosses its cookies. + * XXX this can still loop forever if the directory is busted + * such that the second or subsequent page of it always + * returns EINVAL + */ + if ((error == EINVAL) && (tries < 3)) { + off = 0; + tries++; + continue; /* once more, with feeling */ + } + + if (!error) { + char *cpos; + struct dirent *dp; + + cpos = dirbuf; + tries = 0; + + /* scan directory page looking for matching vnode */ + for (len = (dirbuflen - uio.uio_resid); len > 0; len -= reclen) { + dp = (struct dirent *) cpos; + reclen = dp->d_reclen; + + /* check for malformed directory.. */ + if (reclen < DIRENT_MINSIZE) { + error = EINVAL; + goto out; + } + /* + * XXX should perhaps do VOP_LOOKUP to + * check that we got back to the right place, + * but getting the locking games for that + * right would be heinous. + */ + if ((dp->d_type != DT_WHT) && + (dp->d_fileno == fileno)) { + char *bp = *bpp; + bp -= dp->d_namlen; + + if (bp <= bufp) { + error = ERANGE; + goto out; + } + bcopy(dp->d_name, bp, dp->d_namlen); + error = 0; + *bpp = bp; + goto out; + } + cpos += reclen; + } + } + } while (!eofflag); + error = ENOENT; + +out: + vput(lvp); + *lvpp = NULL; + free(dirbuf, M_TEMP); + return error; +} + + +/* + * common routine shared by sys___getcwd() and linux_vn_isunder() + */ + +#define GETCWD_CHECK_ACCESS 0x0001 + +static int +linux_getcwd_common (lvp, rvp, bpp, bufp, limit, flags, td) + struct vnode *lvp; + struct vnode *rvp; + char **bpp; + char *bufp; + int limit; + int flags; + struct thread *td; +{ + struct filedesc *fdp = td->td_proc->p_fd; + struct vnode *uvp = NULL; + char *bp = NULL; + int error; + accmode_t accmode = VEXEC; + + if (rvp == NULL) { + rvp = fdp->fd_rdir; + if (rvp == NULL) + rvp = rootvnode; + } + + VREF(rvp); + VREF(lvp); + + /* + * Error handling invariant: + * Before a `goto out': + * lvp is either NULL, or locked and held. + * uvp is either NULL, or locked and held. + */ + + error = vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY); + if (error != 0) + panic("vn_lock LK_RETRY returned error %d", error); + if (bufp) + bp = *bpp; + /* + * this loop will terminate when one of the following happens: + * - we hit the root + * - getdirentries or lookup fails + * - we run out of space in the buffer. + */ + if (lvp == rvp) { + if (bp) + *(--bp) = '/'; + goto out; + } + do { + if (lvp->v_type != VDIR) { + error = ENOTDIR; + goto out; + } + + /* + * access check here is optional, depending on + * whether or not caller cares. + */ + if (flags & GETCWD_CHECK_ACCESS) { + error = VOP_ACCESS(lvp, accmode, td->td_ucred, td); + if (error) + goto out; + accmode = VEXEC|VREAD; + } + + /* + * step up if we're a covered vnode.. + */ + while (lvp->v_vflag & VV_ROOT) { + struct vnode *tvp; + + if (lvp == rvp) + goto out; + + tvp = lvp; + lvp = lvp->v_mount->mnt_vnodecovered; + vput(tvp); + /* + * hodie natus est radici frater + */ + if (lvp == NULL) { + error = ENOENT; + goto out; + } + VREF(lvp); + error = vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY); + if (error != 0) + panic("vn_lock LK_RETRY returned %d", error); + } + error = linux_getcwd_scandir(&lvp, &uvp, &bp, bufp, td); + if (error) + goto out; +#ifdef DIAGNOSTIC + if (lvp != NULL) + panic("getcwd: oops, forgot to null lvp"); + if (bufp && (bp <= bufp)) { + panic("getcwd: oops, went back too far"); + } +#endif + if (bp) + *(--bp) = '/'; + lvp = uvp; + uvp = NULL; + limit--; + } while ((lvp != rvp) && (limit > 0)); + +out: + if (bpp) + *bpp = bp; + if (uvp) + vput(uvp); + if (lvp) + vput(lvp); + vrele(rvp); + return error; +} + + +/* + * Find pathname of process's current directory. + * + * Use vfs vnode-to-name reverse cache; if that fails, fall back + * to reading directory contents. + */ + +int +linux_getcwd(struct thread *td, struct linux_getcwd_args *args) +{ + caddr_t bp, bend, path; + int error, len, lenused; + +#ifdef DEBUG + if (ldebug(getcwd)) + printf(ARGS(getcwd, "%p, %ld"), args->buf, (long)args->bufsize); +#endif + + len = args->bufsize; + + if (len > MAXPATHLEN*4) + len = MAXPATHLEN*4; + else if (len < 2) + return ERANGE; + + path = (char *)malloc(len, M_TEMP, M_WAITOK); + + error = kern___getcwd(td, path, UIO_SYSSPACE, len); + if (!error) { + lenused = strlen(path) + 1; + if (lenused <= args->bufsize) { + td->td_retval[0] = lenused; + error = copyout(path, args->buf, lenused); + } + else + error = ERANGE; + } else { + bp = &path[len]; + bend = bp; + *(--bp) = '\0'; + + /* + * 5th argument here is "max number of vnodes to traverse". + * Since each entry takes up at least 2 bytes in the output buffer, + * limit it to N/2 vnodes for an N byte buffer. + */ + + mtx_lock(&Giant); + error = linux_getcwd_common (td->td_proc->p_fd->fd_cdir, NULL, + &bp, path, len/2, GETCWD_CHECK_ACCESS, td); + mtx_unlock(&Giant); + + if (error) + goto out; + lenused = bend - bp; + td->td_retval[0] = lenused; + /* put the result into user buffer */ + error = copyout(bp, args->buf, lenused); + } +out: + free(path, 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 0000000..192b9fd --- /dev/null +++ b/sys/compat/linux/linux_ioctl.c @@ -0,0 +1,3532 @@ +/*- + * 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 "opt_compat.h" + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sysproto.h> +#include <sys/capability.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/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_dl.h> +#include <net/if_types.h> +#include <net/vnet.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_ioctl.h> +#include <compat/linux/linux_mib.h> +#include <compat/linux/linux_socket.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> + +CTASSERT(LINUX_IFNAMSIZ == IFNAMSIZ); + +FEATURE(linuxulator_v4l, "V4L ioctl wrapper support in the linuxulator"); +FEATURE(linuxulator_v4l2, "V4L2 ioctl wrapper support in the linuxulator"); + +static linux_ioctl_function_t linux_ioctl_cdrom; +static linux_ioctl_function_t linux_ioctl_vfat; +static linux_ioctl_function_t linux_ioctl_console; +static linux_ioctl_function_t linux_ioctl_hdio; +static linux_ioctl_function_t linux_ioctl_disk; +static linux_ioctl_function_t linux_ioctl_socket; +static linux_ioctl_function_t linux_ioctl_sound; +static linux_ioctl_function_t linux_ioctl_termio; +static linux_ioctl_function_t linux_ioctl_private; +static linux_ioctl_function_t linux_ioctl_drm; +static linux_ioctl_function_t linux_ioctl_sg; +static linux_ioctl_function_t linux_ioctl_v4l; +static linux_ioctl_function_t linux_ioctl_v4l2; +static linux_ioctl_function_t linux_ioctl_special; +static linux_ioctl_function_t linux_ioctl_fbsd_usb; + +static struct linux_ioctl_handler cdrom_handler = +{ linux_ioctl_cdrom, LINUX_IOCTL_CDROM_MIN, LINUX_IOCTL_CDROM_MAX }; +static struct linux_ioctl_handler vfat_handler = +{ linux_ioctl_vfat, LINUX_IOCTL_VFAT_MIN, LINUX_IOCTL_VFAT_MAX }; +static struct linux_ioctl_handler console_handler = +{ linux_ioctl_console, LINUX_IOCTL_CONSOLE_MIN, LINUX_IOCTL_CONSOLE_MAX }; +static struct linux_ioctl_handler hdio_handler = +{ linux_ioctl_hdio, LINUX_IOCTL_HDIO_MIN, LINUX_IOCTL_HDIO_MAX }; +static struct linux_ioctl_handler disk_handler = +{ linux_ioctl_disk, LINUX_IOCTL_DISK_MIN, LINUX_IOCTL_DISK_MAX }; +static struct linux_ioctl_handler socket_handler = +{ linux_ioctl_socket, LINUX_IOCTL_SOCKET_MIN, LINUX_IOCTL_SOCKET_MAX }; +static struct linux_ioctl_handler sound_handler = +{ linux_ioctl_sound, LINUX_IOCTL_SOUND_MIN, LINUX_IOCTL_SOUND_MAX }; +static struct linux_ioctl_handler termio_handler = +{ linux_ioctl_termio, LINUX_IOCTL_TERMIO_MIN, LINUX_IOCTL_TERMIO_MAX }; +static struct linux_ioctl_handler private_handler = +{ linux_ioctl_private, LINUX_IOCTL_PRIVATE_MIN, LINUX_IOCTL_PRIVATE_MAX }; +static struct linux_ioctl_handler drm_handler = +{ linux_ioctl_drm, LINUX_IOCTL_DRM_MIN, LINUX_IOCTL_DRM_MAX }; +static struct linux_ioctl_handler sg_handler = +{ linux_ioctl_sg, LINUX_IOCTL_SG_MIN, LINUX_IOCTL_SG_MAX }; +static struct linux_ioctl_handler video_handler = +{ linux_ioctl_v4l, LINUX_IOCTL_VIDEO_MIN, LINUX_IOCTL_VIDEO_MAX }; +static struct linux_ioctl_handler video2_handler = +{ linux_ioctl_v4l2, LINUX_IOCTL_VIDEO2_MIN, LINUX_IOCTL_VIDEO2_MAX }; +static struct linux_ioctl_handler fbsd_usb = +{ linux_ioctl_fbsd_usb, FBSD_LUSB_MIN, FBSD_LUSB_MAX }; + +DATA_SET(linux_ioctl_handler_set, cdrom_handler); +DATA_SET(linux_ioctl_handler_set, vfat_handler); +DATA_SET(linux_ioctl_handler_set, console_handler); +DATA_SET(linux_ioctl_handler_set, hdio_handler); +DATA_SET(linux_ioctl_handler_set, disk_handler); +DATA_SET(linux_ioctl_handler_set, socket_handler); +DATA_SET(linux_ioctl_handler_set, sound_handler); +DATA_SET(linux_ioctl_handler_set, termio_handler); +DATA_SET(linux_ioctl_handler_set, private_handler); +DATA_SET(linux_ioctl_handler_set, drm_handler); +DATA_SET(linux_ioctl_handler_set, sg_handler); +DATA_SET(linux_ioctl_handler_set, video_handler); +DATA_SET(linux_ioctl_handler_set, video2_handler); +DATA_SET(linux_ioctl_handler_set, fbsd_usb); + +struct handler_element +{ + TAILQ_ENTRY(handler_element) list; + int (*func)(struct thread *, struct linux_ioctl_args *); + int low, high, span; +}; + +static TAILQ_HEAD(, handler_element) handlers = + TAILQ_HEAD_INITIALIZER(handlers); +static struct sx linux_ioctl_sx; +SX_SYSINIT(linux_ioctl, &linux_ioctl_sx, "linux ioctl handlers"); + +/* + * 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; + + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 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)§orsize, 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 defined(DEBUG) + linux_msg(td, "HDIO_GET_GEO: mediasize %jd, c/h/s %d/%d/%d, " + "bpc %jd", + (intmax_t)mediasize, fwcylinders, fwheads, fwsectors, + (intmax_t)bytespercyl); +#endif + 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; + + 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, + "ioctl fd=%d, cmd=0x%x ('%c',%d) is not implemented", + args->fd, (int)(args->cmd & 0xffff), + (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; + off_t mediasize; + + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + return (error); + switch (args->cmd & 0xffff) { + case LINUX_BLKGETSIZE: + error = fo_ioctl(fp, DIOCGSECTORSIZE, + (caddr_t)§orsize, 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(§orsize, (void *)args->arg, + sizeof(sectorsize))); + break; + } + 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; + +#ifdef DEBUG + if (ldebug(ioctl)) { + printf("LINUX: BSD termios structure (input):\n"); + printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n", + bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag, + bios->c_ispeed, bios->c_ospeed); + printf("c_cc "); + for (i=0; i<NCCS; i++) + printf("%02x ", bios->c_cc[i]); + printf("\n"); + } +#endif + + 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]; + + 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; + +#ifdef DEBUG + if (ldebug(ioctl)) { + printf("LINUX: LINUX termios structure (output):\n"); + printf("i=%08x o=%08x c=%08x l=%08x line=%d\n", + lios->c_iflag, lios->c_oflag, lios->c_cflag, + lios->c_lflag, (int)lios->c_line); + printf("c_cc "); + for (i=0; i<LINUX_NCCS; i++) + printf("%02x ", lios->c_cc[i]); + printf("\n"); + } +#endif +} + +static void +linux_to_bsd_termios(struct linux_termios *lios, struct termios *bios) +{ + int i; + +#ifdef DEBUG + if (ldebug(ioctl)) { + printf("LINUX: LINUX termios structure (input):\n"); + printf("i=%08x o=%08x c=%08x l=%08x line=%d\n", + lios->c_iflag, lios->c_oflag, lios->c_cflag, + lios->c_lflag, (int)lios->c_line); + printf("c_cc "); + for (i=0; i<LINUX_NCCS; i++) + printf("%02x ", lios->c_cc[i]); + printf("\n"); + } +#endif + + 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]; + + 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); + +#ifdef DEBUG + if (ldebug(ioctl)) { + printf("LINUX: BSD termios structure (output):\n"); + printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n", + bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag, + bios->c_ispeed, bios->c_ospeed); + printf("c_cc "); + for (i=0; i<NCCS; i++) + printf("%02x ", bios->c_cc[i]); + printf("\n"); + } +#endif +} + +static void +bsd_to_linux_termio(struct termios *bios, struct linux_termio *lio) +{ + struct linux_termios lios; + + 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; + + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 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; + 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) + return (error); + 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; + + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 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(<h, (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, <e, 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, <e.cdte_addr); + error = copyout(<e, (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; + + bsdsc.address_format = CD_LBA_FORMAT; + bsdsc.data_format = CD_CURRENT_POSITION; + bsdsc.track = 0; + bsdsc.data_len = sizeof(bsdinfo); + bsdsc.data = &bsdinfo; + error = fo_ioctl(fp, CDIOCREADSUBCHANNEL_SYSSPACE, + (caddr_t)&bsdsc, td->td_ucred, td); + if (error) + break; + error = copyin((void *)args->arg, &sc, sizeof(sc)); + 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: + case LINUX_SCSI_GET_IDLUN: + error = linux_ioctl_sg(td, args); + 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_mixer_info { + char id[16]; + char name[32]; + int modify_counter; + int fillers[10]; +}; + +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_INFO: { + /* Key on encoded length */ + switch ((args->cmd >> 16) & 0x1fff) { + case 0x005c: { /* SOUND_MIXER_INFO */ + struct linux_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); + } + 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 + */ + +#define ISSIGVALID(sig) ((sig) > 0 && (sig) < NSIG) + +static int +linux_ioctl_console(struct thread *td, struct linux_ioctl_args *args) +{ + struct file *fp; + int error; + + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 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 (!ISSIGVALID(mode.frsig) && ISSIGVALID(mode.acqsig)) + mode.frsig = mode.acqsig; + 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); +} + +/* + * Criteria for interface name translation + */ +#define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER) + +/* + * Interface function used by linprocfs (at the time of writing). It's not + * used by the Linuxulator itself. + */ +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; + TAILQ_FOREACH(ifscan, &V_ifnet, if_link) { + if (ifscan == ifp) + return (snprintf(buffer, buflen, "eth%d", ethno)); + if (IFP_IS_ETH(ifscan)) + ethno++; + } + + return (0); +} + +/* + * 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. + */ + +static struct ifnet * +ifname_linux_to_bsd(struct thread *td, const char *lxname, char *bsdname) +{ + struct ifnet *ifp; + int len, unit; + char *ep; + int is_eth, index; + + for (len = 0; len < LINUX_IFNAMSIZ; ++len) + if (!isalpha(lxname[len])) + break; + if (len == 0 || len == LINUX_IFNAMSIZ) + return (NULL); + unit = (int)strtoul(lxname + len, &ep, 10); + if (ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ) + return (NULL); + index = 0; + is_eth = (len == 3 && !strncmp(lxname, "eth", len)) ? 1 : 0; + CURVNET_SET(TD_TO_VNET(td)); + IFNET_RLOCK(); + TAILQ_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; + } + IFNET_RUNLOCK(); + CURVNET_RESTORE(); + if (ifp != NULL) + strlcpy(bsdname, ifp->if_xname, IFNAMSIZ); + return (ifp); +} + +/* + * 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(); + TAILQ_FOREACH(ifp, &V_ifnet, if_link) { + TAILQ_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(); + TAILQ_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 */ + TAILQ_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; + + flags = (ifp->if_flags | ifp->if_drv_flags) & 0xffff; + /* these flags have no Linux equivalent */ + flags &= ~(IFF_SMART|IFF_DRV_OACTIVE|IFF_SIMPLEX| + IFF_LINK0|IFF_LINK1|IFF_LINK2); + /* Linux' multicast flag is in a different bit */ + if (flags & IFF_MULTICAST) { + flags &= ~IFF_MULTICAST; + flags |= 0x1000; + } + + return (copyout(&flags, &ifr->ifr_flags, sizeof(flags))); +} + +#define ARPHRD_ETHER 1 +#define ARPHRD_LOOPBACK 772 + +static int +linux_gifhwaddr(struct ifnet *ifp, struct l_ifreq *ifr) +{ + struct ifaddr *ifa; + struct sockaddr_dl *sdl; + struct l_sockaddr lsa; + + if (ifp->if_type == IFT_LOOP) { + bzero(&lsa, sizeof(lsa)); + lsa.sa_family = ARPHRD_LOOPBACK; + return (copyout(&lsa, &ifr->ifr_hwaddr, sizeof(lsa))); + } + + if (ifp->if_type != IFT_ETHER) + return (ENOENT); + + TAILQ_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 = ARPHRD_ETHER; + bcopy(LLADDR(sdl), lsa.sa_data, LINUX_IFHWADDRLEN); + return (copyout(&lsa, &ifr->ifr_hwaddr, sizeof(lsa))); + } + } + + return (ENOENT); +} + + + /* +* 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; + + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 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_SIOCGIFCONF: + case LINUX_SIOCGPGRP: + case LINUX_SIOCSPGRP: + case LINUX_SIOCGIFCOUNT: + /* these ioctls don't take an interface name */ +#ifdef DEBUG + printf("%s(): ioctl %d\n", __func__, + args->cmd & 0xffff); +#endif + 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); +#ifdef DEBUG + printf("%s(): ioctl %d on %.*s\n", __func__, + args->cmd & 0xffff, LINUX_IFNAMSIZ, lifname); +#endif + 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); +#ifdef DEBUG + printf("%s(): %s translated to %s\n", __func__, + lifname, ifname); +#endif + 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_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); + +#ifdef DEBUG + printf("%s(): returning %d\n", __func__, error); +#endif + 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; + + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 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); +} + +static int +linux_ioctl_sg(struct thread *td, struct linux_ioctl_args *args) +{ + struct file *fp; + u_long cmd; + int error; + + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) { + printf("sg_linux_ioctl: fget returned %d\n", error); + return (error); + } + cmd = args->cmd; + + error = (fo_ioctl(fp, cmd, (caddr_t)args->arg, td->td_ucred, td)); + fdrop(fp, td); + return (error); +} + +/* + * 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) +{ + 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 == 0) { + 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: + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 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: + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 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: + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 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: + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 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: + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 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: + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 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: + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 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; + memcpy(&vstd->name, &lvstd->name, sizeof(*lvstd) - offsetof(struct l_v4l2_standard, name)); + 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; + memcpy(&lvstd->name, &vstd->name, sizeof(*lvstd) - offsetof(struct l_v4l2_standard, name)); + 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); + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + 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); + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + 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); + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 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); + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) + 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; + default: + error = ENOIOCTL; + } + if (error != ENOIOCTL) + error = sys_ioctl(td, (struct ioctl_args *)args); + return (error); +} + +/* + * main ioctl syscall function + */ + +int +linux_ioctl(struct thread *td, struct linux_ioctl_args *args) +{ + struct file *fp; + struct handler_element *he; + int error, cmd; + +#ifdef DEBUG + if (ldebug(ioctl)) + printf(ARGS(ioctl, "%d, %04lx, *"), args->fd, + (unsigned long)args->cmd); +#endif + + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 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); + TAILQ_FOREACH(he, &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); + + linux_msg(td, "ioctl fd=%d, cmd=0x%x ('%c',%d) is not implemented", + args->fd, (int)(args->cmd & 0xffff), + (int)(args->cmd & 0xff00) >> 8, (int)(args->cmd & 0xff)); + + return (EINVAL); +} + +int +linux_ioctl_register_handler(struct linux_ioctl_handler *h) +{ + struct 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, &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(&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, &handlers, list) { + if (cur->span > he->span) { + TAILQ_INSERT_BEFORE(cur, he, list); + sx_xunlock(&linux_ioctl_sx); + return (0); + } + } + TAILQ_INSERT_TAIL(&handlers, he, list); + sx_xunlock(&linux_ioctl_sx); + + return (0); +} + +int +linux_ioctl_unregister_handler(struct linux_ioctl_handler *h) +{ + struct handler_element *he; + + if (h == NULL || h->func == NULL) + return (EINVAL); + + sx_xlock(&linux_ioctl_sx); + TAILQ_FOREACH(he, &handlers, list) { + if (he->func == h->func) { + TAILQ_REMOVE(&handlers, he, list); + sx_xunlock(&linux_ioctl_sx); + free(he, M_LINUX); + return (0); + } + } + sx_xunlock(&linux_ioctl_sx); + + return (EINVAL); +} diff --git a/sys/compat/linux/linux_ioctl.h b/sys/compat/linux/linux_ioctl.h new file mode 100644 index 0000000..aa7650b --- /dev/null +++ b/sys/compat/linux/linux_ioctl.h @@ -0,0 +1,767 @@ +/*- + * 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 + * 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_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_IOCTL_DISK_MIN LINUX_BLKROSET +#define LINUX_IOCTL_DISK_MAX LINUX_BLKSSZGET + +/* + * 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_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_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_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 + +/* + * This doesn't really belong here, but I can't think of a better + * place to put it. + */ +struct ifnet; +int linux_ifname(struct ifnet *, char *, size_t); + +/* + * 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 + +/* + * 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_MAX 0xffff +#define FBSD_LUSB_MIN 0xffe0 + +/* + * 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; +}; + +int linux_ioctl_register_handler(struct linux_ioctl_handler *h); +int linux_ioctl_unregister_handler(struct linux_ioctl_handler *h); + +#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 0000000..1237edc --- /dev/null +++ b/sys/compat/linux/linux_ipc.c @@ -0,0 +1,899 @@ +/*- + * 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 <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 "opt_compat.h" + +#ifdef COMPAT_LINUX32 +#include <machine/../linux32/linux.h> +#include <machine/../linux32/linux32_proto.h> +#include <machine/../linux32/linux32_ipc64.h> +#else +#include <machine/../linux/linux.h> +#include <machine/../linux/linux_proto.h> +#include <machine/../linux/linux_ipc64.h> +#endif +#include <compat/linux/linux_ipc.h> +#include <compat/linux/linux_util.h> + +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_shminfo *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 ; +} + +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; +}; + +static void +linux_to_bsd_ipc_perm(struct l_ipc_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_ipc_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; + 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 */ +} +#if defined(__amd64__) && defined(COMPAT_LINUX32) +__packed +#endif +; + +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; +} +#if defined(__amd64__) && defined(COMPAT_LINUX32) +__packed +#endif +; + +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_semid_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; + bsp->sem_base = PTRIN(lsp->sem_base); +} + +static void +bsd_to_linux_semid_ds(struct semid_ds *bsp, struct l_semid_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; + lsp->sem_base = PTROUT(bsp->sem_base); +} + +static void +linux_to_bsd_shmid_ds(struct l_shmid_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_shmid_ds *lsp) +{ + + bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->shm_perm); + if (bsp->shm_segsz > INT_MAX) + lsp->shm_segsz = INT_MAX; + else + lsp->shm_segsz = bsp->shm_segsz; + lsp->shm_lpid = bsp->shm_lpid; + lsp->shm_cpid = bsp->shm_cpid; + if (bsp->shm_nattch > SHRT_MAX) + lsp->shm_nattch = SHRT_MAX; + else + lsp->shm_nattch = bsp->shm_nattch; + lsp->shm_atime = bsp->shm_atime; + lsp->shm_dtime = bsp->shm_dtime; + lsp->shm_ctime = bsp->shm_ctime; + lsp->private3 = 0; +} + +static void +linux_to_bsd_msqid_ds(struct l_msqid_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_msqid_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 void +linux_ipc_perm_to_ipc64_perm(struct l_ipc_perm *in, struct l_ipc64_perm *out) +{ + + /* XXX: do we really need to do something here? */ + 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; +} + +static int +linux_msqid_pullup(l_int ver, struct l_msqid_ds *linux_msqid, caddr_t uaddr) +{ + struct l_msqid64_ds linux_msqid64; + int error; + + if (ver == LINUX_IPC_64) { + error = copyin(uaddr, &linux_msqid64, sizeof(linux_msqid64)); + if (error != 0) + return (error); + + bzero(linux_msqid, sizeof(*linux_msqid)); + + linux_msqid->msg_perm.uid = linux_msqid64.msg_perm.uid; + linux_msqid->msg_perm.gid = linux_msqid64.msg_perm.gid; + linux_msqid->msg_perm.mode = linux_msqid64.msg_perm.mode; + + if (linux_msqid64.msg_qbytes > USHRT_MAX) + linux_msqid->msg_lqbytes = linux_msqid64.msg_qbytes; + else + linux_msqid->msg_qbytes = linux_msqid64.msg_qbytes; + } else + error = copyin(uaddr, linux_msqid, sizeof(*linux_msqid)); + + return (error); +} + +static int +linux_msqid_pushdown(l_int ver, struct l_msqid_ds *linux_msqid, caddr_t uaddr) +{ + struct l_msqid64_ds linux_msqid64; + + if (ver == LINUX_IPC_64) { + bzero(&linux_msqid64, sizeof(linux_msqid64)); + + linux_ipc_perm_to_ipc64_perm(&linux_msqid->msg_perm, + &linux_msqid64.msg_perm); + + linux_msqid64.msg_stime = linux_msqid->msg_stime; + linux_msqid64.msg_rtime = linux_msqid->msg_rtime; + linux_msqid64.msg_ctime = linux_msqid->msg_ctime; + + if (linux_msqid->msg_cbytes == 0) + linux_msqid64.msg_cbytes = linux_msqid->msg_lcbytes; + else + linux_msqid64.msg_cbytes = linux_msqid->msg_cbytes; + + linux_msqid64.msg_qnum = linux_msqid->msg_qnum; + + if (linux_msqid->msg_qbytes == 0) + linux_msqid64.msg_qbytes = linux_msqid->msg_lqbytes; + else + linux_msqid64.msg_qbytes = linux_msqid->msg_qbytes; + + linux_msqid64.msg_lspid = linux_msqid->msg_lspid; + linux_msqid64.msg_lrpid = linux_msqid->msg_lrpid; + + return (copyout(&linux_msqid64, uaddr, sizeof(linux_msqid64))); + } else + return (copyout(linux_msqid, uaddr, sizeof(*linux_msqid))); +} + +static int +linux_semid_pullup(l_int ver, struct l_semid_ds *linux_semid, caddr_t uaddr) +{ + struct l_semid64_ds linux_semid64; + int error; + + if (ver == LINUX_IPC_64) { + error = copyin(uaddr, &linux_semid64, sizeof(linux_semid64)); + if (error != 0) + return (error); + + bzero(linux_semid, sizeof(*linux_semid)); + + linux_semid->sem_perm.uid = linux_semid64.sem_perm.uid; + linux_semid->sem_perm.gid = linux_semid64.sem_perm.gid; + linux_semid->sem_perm.mode = linux_semid64.sem_perm.mode; + } else + error = copyin(uaddr, linux_semid, sizeof(*linux_semid)); + + return (error); +} + +static int +linux_semid_pushdown(l_int ver, struct l_semid_ds *linux_semid, caddr_t uaddr) +{ + struct l_semid64_ds linux_semid64; + + if (ver == LINUX_IPC_64) { + bzero(&linux_semid64, sizeof(linux_semid64)); + + linux_ipc_perm_to_ipc64_perm(&linux_semid->sem_perm, + &linux_semid64.sem_perm); + + linux_semid64.sem_otime = linux_semid->sem_otime; + linux_semid64.sem_ctime = linux_semid->sem_ctime; + linux_semid64.sem_nsems = linux_semid->sem_nsems; + + return (copyout(&linux_semid64, uaddr, sizeof(linux_semid64))); + } else + return (copyout(linux_semid, uaddr, sizeof(*linux_semid))); +} + +static int +linux_shmid_pullup(l_int ver, struct l_shmid_ds *linux_shmid, caddr_t uaddr) +{ + struct l_shmid64_ds linux_shmid64; + int error; + + if (ver == LINUX_IPC_64) { + error = copyin(uaddr, &linux_shmid64, sizeof(linux_shmid64)); + if (error != 0) + return (error); + + bzero(linux_shmid, sizeof(*linux_shmid)); + + linux_shmid->shm_perm.uid = linux_shmid64.shm_perm.uid; + linux_shmid->shm_perm.gid = linux_shmid64.shm_perm.gid; + linux_shmid->shm_perm.mode = linux_shmid64.shm_perm.mode; + } else + error = copyin(uaddr, linux_shmid, sizeof(*linux_shmid)); + + return (error); +} + +static int +linux_shmid_pushdown(l_int ver, struct l_shmid_ds *linux_shmid, caddr_t uaddr) +{ + struct l_shmid64_ds linux_shmid64; + + /* + * XXX: This is backwards and loses information in shm_nattch + * and shm_segsz. We should probably either expose the BSD + * shmid structure directly and convert it to either the + * non-64 or 64 variant directly or the code should always + * convert to the 64 variant and then truncate values into the + * non-64 variant if needed since the 64 variant has more + * precision. + */ + if (ver == LINUX_IPC_64) { + bzero(&linux_shmid64, sizeof(linux_shmid64)); + + linux_ipc_perm_to_ipc64_perm(&linux_shmid->shm_perm, + &linux_shmid64.shm_perm); + + linux_shmid64.shm_segsz = linux_shmid->shm_segsz; + linux_shmid64.shm_atime = linux_shmid->shm_atime; + linux_shmid64.shm_dtime = linux_shmid->shm_dtime; + linux_shmid64.shm_ctime = linux_shmid->shm_ctime; + linux_shmid64.shm_cpid = linux_shmid->shm_cpid; + linux_shmid64.shm_lpid = linux_shmid->shm_lpid; + linux_shmid64.shm_nattch = linux_shmid->shm_nattch; + + return (copyout(&linux_shmid64, uaddr, sizeof(linux_shmid64))); + } else + return (copyout(linux_shmid, uaddr, sizeof(*linux_shmid))); +} + +static int +linux_shminfo_pushdown(l_int ver, struct l_shminfo *linux_shminfo, + caddr_t uaddr) +{ + struct l_shminfo64 linux_shminfo64; + + if (ver == LINUX_IPC_64) { + bzero(&linux_shminfo64, sizeof(linux_shminfo64)); + + linux_shminfo64.shmmax = linux_shminfo->shmmax; + linux_shminfo64.shmmin = linux_shminfo->shmmin; + linux_shminfo64.shmmni = linux_shminfo->shmmni; + linux_shminfo64.shmseg = linux_shminfo->shmseg; + linux_shminfo64.shmall = linux_shminfo->shmall; + + return (copyout(&linux_shminfo64, uaddr, + sizeof(linux_shminfo64))); + } else + 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; + + 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_semid_ds linux_semid; + struct l_seminfo linux_seminfo; + struct semid_ds semid; + union semun semun; + register_t rval; + int cmd, error; + + 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_semid, PTRIN(args->arg.buf)); + if (error) + return (error); + linux_to_bsd_semid_ds(&linux_semid, &semid); + semun.buf = &semid; + return (kern_semctl(td, args->semid, args->semnum, cmd, &semun, + td->td_retval)); + case LINUX_IPC_STAT: + case LINUX_SEM_STAT: + if ((args->cmd & ~LINUX_IPC_64) == LINUX_IPC_STAT) + cmd = IPC_STAT; + else + cmd = SEM_STAT; + semun.buf = &semid; + error = kern_semctl(td, args->semid, args->semnum, cmd, &semun, + &rval); + if (error) + return (error); + bsd_to_linux_semid_ds(&semid, &linux_semid); + error = linux_semid_pushdown(args->cmd & LINUX_IPC_64, + &linux_semid, PTRIN(args->arg.buf)); + if (error == 0) + td->td_retval[0] = (cmd == SEM_STAT) ? rval : 0; + 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) + return (error); + td->td_retval[0] = seminfo.semmni; + return (0); /* No need for __semctl call */ + case LINUX_GETALL: + cmd = GETALL; + semun.val = args->arg.val; + break; + case LINUX_SETALL: + cmd = SETALL; + semun.val = args->arg.val; + 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_msqid_ds linux_msqid; + struct msqid_ds bsd_msqid; + + bsd_cmd = args->cmd & ~LINUX_IPC_64; + switch (bsd_cmd) { + case LINUX_IPC_INFO: + case LINUX_MSG_INFO: { + struct l_msginfo 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_msqid, PTRIN(args->buf)); + if (error) + return (error); + linux_to_bsd_msqid_ds(&linux_msqid, &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 != EINVAL) + return (error); + + if (bsd_cmd == LINUX_IPC_STAT) { + bsd_to_linux_msqid_ds(&bsd_msqid, &linux_msqid); + return (linux_msqid_pushdown(args->cmd & LINUX_IPC_64, + &linux_msqid, 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; + int error; +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) + l_uintptr_t addr; +#endif + + bsd_args.shmid = args->shmid; + bsd_args.shmaddr = PTRIN(args->shmaddr); + bsd_args.shmflg = args->shmflg; + if ((error = sys_shmat(td, &bsd_args))) + return (error); +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) + addr = td->td_retval[0]; + if ((error = copyout(&addr, PTRIN(args->raddr), sizeof(addr)))) + return (error); + td->td_retval[0] = 0; +#endif + return (0); +} + +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_shmid_ds linux_shmid; + struct l_shminfo linux_shminfo; + struct l_shm_info linux_shm_info; + struct shmid_ds bsd_shmid; + int error; + + 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) + return (error); + + bsd_to_linux_shminfo(&bsd_shminfo, &linux_shminfo); + + return (linux_shminfo_pushdown(args->cmd & LINUX_IPC_64, + &linux_shminfo, 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) + 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) + return (error); + + bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid); + + return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64, + &linux_shmid, 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) + return (error); + + bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid); + + return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64, + &linux_shmid, PTRIN(args->buf))); + + case LINUX_IPC_SET: + error = linux_shmid_pullup(args->cmd & LINUX_IPC_64, + &linux_shmid, PTRIN(args->buf)); + if (error) + return (error); + + linux_to_bsd_shmid_ds(&linux_shmid, &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_shmid, PTRIN(args->buf)); + if (error) + return (error); + linux_to_bsd_shmid_ds(&linux_shmid, &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 0000000..f1531ba --- /dev/null +++ b/sys/compat/linux/linux_ipc.h @@ -0,0 +1,182 @@ +/*- + * 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. + * 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_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__) + +struct linux_msgctl_args +{ + l_int msqid; + l_int cmd; + struct l_msqid_ds *buf; +}; + +struct linux_msgget_args +{ + l_key_t key; + l_int msgflg; +}; + +struct linux_msgrcv_args +{ + l_int msqid; + struct l_msgbuf *msgp; + l_size_t msgsz; + l_long msgtyp; + l_int msgflg; +}; + +struct linux_msgsnd_args +{ + l_int msqid; + struct l_msgbuf *msgp; + l_size_t msgsz; + l_int msgflg; +}; + +struct linux_semctl_args +{ + l_int semid; + l_int semnum; + l_int cmd; + union l_semun arg; +}; + +struct linux_semget_args +{ + l_key_t key; + l_int nsems; + l_int semflg; +}; + +struct linux_semop_args +{ + l_int semid; + struct l_sembuf *tsops; + l_uint nsops; +}; + +struct linux_shmat_args +{ + l_int shmid; + char *shmaddr; + l_int shmflg; + l_ulong *raddr; +}; + +struct linux_shmctl_args +{ + l_int shmid; + l_int cmd; + struct l_shmid_ds *buf; +}; + +struct linux_shmdt_args +{ + char *shmaddr; +}; + +struct linux_shmget_args +{ + l_key_t key; + l_size_t size; + l_int shmflg; +}; + +int linux_msgctl(struct thread *, struct linux_msgctl_args *); +int linux_msgget(struct thread *, struct linux_msgget_args *); +int linux_msgrcv(struct thread *, struct linux_msgrcv_args *); +int linux_msgsnd(struct thread *, struct linux_msgsnd_args *); + +int linux_semctl(struct thread *, struct linux_semctl_args *); +int linux_semget(struct thread *, struct linux_semget_args *); +int linux_semop(struct thread *, struct linux_semop_args *); + +int linux_shmat(struct thread *, struct linux_shmat_args *); +int linux_shmctl(struct thread *, struct linux_shmctl_args *); +int linux_shmdt(struct thread *, struct linux_shmdt_args *); +int linux_shmget(struct thread *, struct linux_shmget_args *); + +#endif /* __i386__ || __amd64__ */ + +#endif /* _LINUX_IPC_H_ */ diff --git a/sys/compat/linux/linux_mib.c b/sys/compat/linux/linux_mib.c new file mode 100644 index 0000000..323a38f --- /dev/null +++ b/sys/compat/linux/linux_mib.c @@ -0,0 +1,858 @@ +/*- + * 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 + * 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 "opt_kdtrace.h" + +#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/mutex.h> +#include <sys/sx.h> + +#ifdef COMPAT_LINUX32 +#include <machine/../linux32/linux.h> +#else +#include <machine/../linux/linux.h> +#endif +#include <compat/linux/linux_dtrace.h> +#include <compat/linux/linux_mib.h> +#include <compat/linux/linux_misc.h> + +/* DTrace init */ +LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); + +/** + * DTrace probes in this module. + */ +LIN_SDT_PROBE_DEFINE0(mib, linux_sysctl_osname, entry); +LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_osname, sysctl_string_error, "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_osname, return, "int"); + +LIN_SDT_PROBE_DEFINE0(mib, linux_sysctl_osrelease, entry); +LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_osrelease, sysctl_string_error, "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_osrelease, return, "int"); +LIN_SDT_PROBE_DEFINE0(mib, linux_sysctl_oss_version, entry); +LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_oss_version, sysctl_string_error, + "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_oss_version, return, "int"); +LIN_SDT_PROBE_DEFINE2(mib, linux_map_osrel, entry, "char *", "int *"); +LIN_SDT_PROBE_DEFINE1(mib, linux_map_osrel, return, "int"); +LIN_SDT_PROBE_DEFINE2(mib, linux_get_prison, entry, "struct prison *", + "struct prison **"); +LIN_SDT_PROBE_DEFINE1(mib, linux_get_prison, return, "struct linux_prison *"); +LIN_SDT_PROBE_DEFINE2(mib, linux_alloc_prison, entry, "struct prison *", + "struct linux_prison **"); +LIN_SDT_PROBE_DEFINE1(mib, linux_alloc_prison, return, "int"); +LIN_SDT_PROBE_DEFINE2(mib, linux_prison_create, entry, "void *", "void *"); +LIN_SDT_PROBE_DEFINE1(mib, linux_prison_create, vfs_copyopt_error, "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_prison_create, return, "int"); +LIN_SDT_PROBE_DEFINE2(mib, linux_prison_check, entry, "void *", "void *"); +LIN_SDT_PROBE_DEFINE1(mib, linux_prison_check, vfs_copyopt_error, "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_prison_check, vfs_getopt_error, "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_prison_check, return, "int"); +LIN_SDT_PROBE_DEFINE2(mib, linux_prison_set, entry, "void *", "void *"); +LIN_SDT_PROBE_DEFINE1(mib, linux_prison_set, vfs_copyopt_error, "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_prison_set, vfs_getopt_error, "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_prison_set, return, "int"); +LIN_SDT_PROBE_DEFINE2(mib, linux_prison_get, entry, "void *", "void *"); +LIN_SDT_PROBE_DEFINE1(mib, linux_prison_get, vfs_setopt_error, "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_prison_get, vfs_setopts_error, "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_prison_get, return, "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_prison_destructor, entry, "void *"); +LIN_SDT_PROBE_DEFINE0(mib, linux_prison_destructor, return); +LIN_SDT_PROBE_DEFINE0(mib, linux_osd_jail_register, entry); +LIN_SDT_PROBE_DEFINE0(mib, linux_osd_jail_register, return); +LIN_SDT_PROBE_DEFINE0(mib, linux_osd_jail_deregister, entry); +LIN_SDT_PROBE_DEFINE0(mib, linux_osd_jail_deregister, return); +LIN_SDT_PROBE_DEFINE2(mib, linux_get_osname, entry, "struct thread *", + "char *"); +LIN_SDT_PROBE_DEFINE0(mib, linux_get_osname, return); +LIN_SDT_PROBE_DEFINE2(mib, linux_set_osname, entry, "struct thread *", + "char *"); +LIN_SDT_PROBE_DEFINE1(mib, linux_set_osname, return, "int"); +LIN_SDT_PROBE_DEFINE2(mib, linux_get_osrelease, entry, "struct thread *", + "char *"); +LIN_SDT_PROBE_DEFINE0(mib, linux_get_osrelease, return); +LIN_SDT_PROBE_DEFINE1(mib, linux_kernver, entry, "struct thread *"); +LIN_SDT_PROBE_DEFINE1(mib, linux_kernver, return, "int"); +LIN_SDT_PROBE_DEFINE2(mib, linux_set_osrelease, entry, "struct thread *", + "char *"); +LIN_SDT_PROBE_DEFINE1(mib, linux_set_osrelease, return, "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_get_oss_version, entry, "struct thread *"); +LIN_SDT_PROBE_DEFINE1(mib, linux_get_oss_version, return, "int"); + +LIN_SDT_PROBE_DEFINE2(mib, linux_set_oss_version, entry, "struct thread *", + "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_set_oss_version, return, "int"); + +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 = "2.6.16", + .pr_oss_version = 0x030600, + .pr_osrel = 2006016 +}; + +static unsigned linux_osd_jail_slot; + +static SYSCTL_NODE(_compat, OID_AUTO, linux, CTLFLAG_RW, 0, + "Linux mode"); + +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; + + LIN_SDT_PROBE0(mib, linux_sysctl_osname, entry); + + linux_get_osname(req->td, osname); + error = sysctl_handle_string(oidp, osname, LINUX_MAX_UTSNAME, req); + if (error != 0 || req->newptr == NULL) { + LIN_SDT_PROBE1(mib, linux_sysctl_osname, sysctl_string_error, + error); + LIN_SDT_PROBE1(mib, linux_sysctl_osname, return, error); + return (error); + } + error = linux_set_osname(req->td, osname); + + LIN_SDT_PROBE1(mib, linux_sysctl_osname, return, error); + 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; + + LIN_SDT_PROBE0(mib, linux_sysctl_osrelease, entry); + + linux_get_osrelease(req->td, osrelease); + error = sysctl_handle_string(oidp, osrelease, LINUX_MAX_UTSNAME, req); + if (error != 0 || req->newptr == NULL) { + LIN_SDT_PROBE1(mib, linux_sysctl_osrelease, sysctl_string_error, + error); + LIN_SDT_PROBE1(mib, linux_sysctl_osrelease, return, error); + return (error); + } + error = linux_set_osrelease(req->td, osrelease); + + LIN_SDT_PROBE1(mib, linux_sysctl_osrelease, return, error); + 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; + + LIN_SDT_PROBE0(mib, linux_sysctl_oss_version, entry); + + oss_version = linux_get_oss_version(req->td); + error = sysctl_handle_int(oidp, &oss_version, 0, req); + if (error != 0 || req->newptr == NULL) { + LIN_SDT_PROBE1(mib, linux_sysctl_oss_version, + sysctl_string_error, error); + LIN_SDT_PROBE1(mib, linux_sysctl_oss_version, return, error); + return (error); + } + error = linux_set_oss_version(req->td, oss_version); + + LIN_SDT_PROBE1(mib, linux_sysctl_oss_version, return, error); + 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; + + LIN_SDT_PROBE2(mib, linux_map_osrel, entry, osrelease, osrel); + + len = strlen(osrelease); + eosrelease = osrelease + len; + v0 = strtol(osrelease, &sep, 10); + if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.') { + LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL); + return (EINVAL); + } + osrelease = sep + 1; + v1 = strtol(osrelease, &sep, 10); + if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.') { + LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL); + return (EINVAL); + } + osrelease = sep + 1; + v2 = strtol(osrelease, &sep, 10); + if (osrelease == sep || sep != eosrelease) { + LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL); + return (EINVAL); + } + + v = v0 * 1000000 + v1 * 1000 + v2; + if (v < 1000000) { + LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL); + return (EINVAL); + } + + *osrel = v; + + LIN_SDT_PROBE1(mib, linux_map_osrel, return, 0); + 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; + + LIN_SDT_PROBE2(mib, linux_get_prison, entry, spr, prp); + + if (!linux_osd_jail_slot) + /* In case osd_register failed. */ + spr = &prison0; + 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; + + LIN_SDT_PROBE1(mib, linux_get_prison, return, lpr); + 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 int +linux_alloc_prison(struct prison *pr, struct linux_prison **lprp) +{ + struct prison *ppr; + struct linux_prison *lpr, *nlpr; + int error; + + LIN_SDT_PROBE2(mib, linux_alloc_prison, entry, pr, lprp); + + /* If this prison already has Linux info, return that. */ + error = 0; + 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); + lpr = linux_find_prison(pr, &ppr); + if (ppr == pr) { + free(nlpr, M_PRISON); + goto done; + } + /* Inherit the initial values from the ancestor. */ + mtx_lock(&pr->pr_mtx); + error = osd_jail_set(pr, linux_osd_jail_slot, nlpr); + if (error == 0) { + bcopy(lpr, nlpr, sizeof(*lpr)); + lpr = nlpr; + } else { + free(nlpr, M_PRISON); + lpr = NULL; + } + mtx_unlock(&ppr->pr_mtx); + done: + if (lprp != NULL) + *lprp = lpr; + else + mtx_unlock(&pr->pr_mtx); + + LIN_SDT_PROBE1(mib, linux_alloc_prison, return, error); + return (error); +} + +/* + * 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, error; + + LIN_SDT_PROBE2(mib, linux_prison_create, entry, obj, data); + + error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)); + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_create, vfs_copyopt_error, + error); + } else if (jsys == JAIL_SYS_INHERIT) { + LIN_SDT_PROBE1(mib, linux_prison_create, return, 0); + return (0); + } + /* + * Inherit a prison's initial values from its parent + * (different from JAIL_SYS_INHERIT which also inherits changes). + */ + error = linux_alloc_prison(pr, NULL); + + LIN_SDT_PROBE1(mib, linux_prison_create, return, error); + return (error); +} + +static int +linux_prison_check(void *obj __unused, void *data) +{ + struct vfsoptlist *opts = data; + char *osname, *osrelease; + int error, jsys, len, osrel, oss_version; + + LIN_SDT_PROBE2(mib, linux_prison_check, entry, obj, data); + + /* Check that the parameters are correct. */ + error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)); + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_check, vfs_copyopt_error, + error); + } + if (error != ENOENT) { + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_check, return, error); + return (error); + } + if (jsys != JAIL_SYS_NEW && jsys != JAIL_SYS_INHERIT) { + LIN_SDT_PROBE1(mib, linux_prison_check, return, EINVAL); + return (EINVAL); + } + } + error = vfs_getopt(opts, "linux.osname", (void **)&osname, &len); + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_check, vfs_getopt_error, + error); + } + if (error != ENOENT) { + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_check, return, error); + return (error); + } + if (len == 0 || osname[len - 1] != '\0') { + LIN_SDT_PROBE1(mib, linux_prison_check, return, EINVAL); + return (EINVAL); + } + if (len > LINUX_MAX_UTSNAME) { + vfs_opterror(opts, "linux.osname too long"); + LIN_SDT_PROBE1(mib, linux_prison_check, return, + ENAMETOOLONG); + return (ENAMETOOLONG); + } + } + error = vfs_getopt(opts, "linux.osrelease", (void **)&osrelease, &len); + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_check, vfs_getopt_error, + error); + } + if (error != ENOENT) { + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_check, return, error); + return (error); + } + if (len == 0 || osrelease[len - 1] != '\0') { + LIN_SDT_PROBE1(mib, linux_prison_check, return, EINVAL); + return (EINVAL); + } + if (len > LINUX_MAX_UTSNAME) { + vfs_opterror(opts, "linux.osrelease too long"); + LIN_SDT_PROBE1(mib, linux_prison_check, return, + ENAMETOOLONG); + return (ENAMETOOLONG); + } + error = linux_map_osrel(osrelease, &osrel); + if (error != 0) { + vfs_opterror(opts, "linux.osrelease format error"); + LIN_SDT_PROBE1(mib, linux_prison_check, return, error); + return (error); + } + } + error = vfs_copyopt(opts, "linux.oss_version", &oss_version, + sizeof(oss_version)); + if (error != 0) + LIN_SDT_PROBE1(mib, linux_prison_check, vfs_copyopt_error, error); + + if (error == ENOENT) + error = 0; + LIN_SDT_PROBE1(mib, linux_prison_check, return, error); + 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; + + LIN_SDT_PROBE2(mib, linux_prison_set, entry, obj, data); + + /* Set the parameters, which should be correct. */ + error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)); + if (error != 0) + LIN_SDT_PROBE1(mib, linux_prison_set, vfs_copyopt_error, error); + if (error == ENOENT) + jsys = -1; + error = vfs_getopt(opts, "linux.osname", (void **)&osname, &len); + if (error != 0) + LIN_SDT_PROBE1(mib, linux_prison_set, vfs_getopt_error, error); + if (error == ENOENT) + osname = NULL; + else + jsys = JAIL_SYS_NEW; + error = vfs_getopt(opts, "linux.osrelease", (void **)&osrelease, &len); + if (error != 0) + LIN_SDT_PROBE1(mib, linux_prison_set, vfs_getopt_error, error); + if (error == ENOENT) + osrelease = NULL; + else + jsys = JAIL_SYS_NEW; + error = vfs_copyopt(opts, "linux.oss_version", &oss_version, + sizeof(oss_version)); + if (error != 0) + LIN_SDT_PROBE1(mib, linux_prison_set, vfs_copyopt_error, error); + 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. + */ + error = linux_alloc_prison(pr, &lpr); + if (error) { + mtx_unlock(&pr->pr_mtx); + LIN_SDT_PROBE1(mib, linux_prison_set, return, error); + return (error); + } + if (osrelease) { + error = linux_map_osrel(osrelease, &lpr->pr_osrel); + if (error) { + mtx_unlock(&pr->pr_mtx); + LIN_SDT_PROBE1(mib, linux_prison_set, return, + error); + return (error); + } + 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); + } + + LIN_SDT_PROBE1(mib, linux_prison_set, return, 0); + 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; + + LIN_SDT_PROBE2(mib, linux_prison_get, entry, obj, data); + + /* 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) { + LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopt_error, error); + if (error != ENOENT) + goto done; + } + if (i) { + error = vfs_setopts(opts, "linux.osname", lpr->pr_osname); + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error, + error); + if (error != ENOENT) + goto done; + } + error = vfs_setopts(opts, "linux.osrelease", lpr->pr_osrelease); + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error, + error); + if (error != ENOENT) + goto done; + } + error = vfs_setopt(opts, "linux.oss_version", + &lpr->pr_oss_version, sizeof(lpr->pr_oss_version)); + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopt_error, + error); + if(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) { + LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error, + error); + if(error != ENOENT) + goto done; + } + error = vfs_setopts(opts, "linux.osrelease", ""); + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error, + error); + if(error != ENOENT) + goto done; + } + error = vfs_setopt(opts, "linux.oss_version", &version0, + sizeof(lpr->pr_oss_version)); + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopt_error, + error); + if(error != ENOENT) + goto done; + } + } + error = 0; + + done: + mtx_unlock(&ppr->pr_mtx); + + LIN_SDT_PROBE1(mib, linux_prison_get, return, error); + return (error); +} + +static void +linux_prison_destructor(void *data) +{ + + LIN_SDT_PROBE1(mib, linux_prison_destructor, entry, data); + free(data, M_PRISON); + LIN_SDT_PROBE0(mib, linux_prison_destructor, return); +} + +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 + }; + + LIN_SDT_PROBE0(mib, linux_osd_jail_register, entry); + + linux_osd_jail_slot = + osd_jail_register(linux_prison_destructor, methods); + if (linux_osd_jail_slot > 0) { + /* Copy the system linux info to any current prisons. */ + sx_xlock(&allprison_lock); + TAILQ_FOREACH(pr, &allprison, pr_list) + (void)linux_alloc_prison(pr, NULL); + sx_xunlock(&allprison_lock); + } + + LIN_SDT_PROBE0(mib, linux_osd_jail_register, return); +} + +void +linux_osd_jail_deregister(void) +{ + + LIN_SDT_PROBE0(mib, linux_osd_jail_register, entry); + + if (linux_osd_jail_slot) + osd_jail_deregister(linux_osd_jail_slot); + + LIN_SDT_PROBE0(mib, linux_osd_jail_register, return); +} + +void +linux_get_osname(struct thread *td, char *dst) +{ + struct prison *pr; + struct linux_prison *lpr; + + LIN_SDT_PROBE2(mib, linux_get_osname, entry, td, dst); + + lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); + bcopy(lpr->pr_osname, dst, LINUX_MAX_UTSNAME); + mtx_unlock(&pr->pr_mtx); + + LIN_SDT_PROBE0(mib, linux_get_osname, return); +} + +static int +linux_set_osname(struct thread *td, char *osname) +{ + struct prison *pr; + struct linux_prison *lpr; + + LIN_SDT_PROBE2(mib, linux_set_osname, entry, td, osname); + + lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); + strlcpy(lpr->pr_osname, osname, LINUX_MAX_UTSNAME); + mtx_unlock(&pr->pr_mtx); + + LIN_SDT_PROBE1(mib, linux_set_osname, return, 0); + return (0); +} + +void +linux_get_osrelease(struct thread *td, char *dst) +{ + struct prison *pr; + struct linux_prison *lpr; + + LIN_SDT_PROBE2(mib, linux_get_osrelease, entry, td, dst); + + lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); + bcopy(lpr->pr_osrelease, dst, LINUX_MAX_UTSNAME); + mtx_unlock(&pr->pr_mtx); + + LIN_SDT_PROBE0(mib, linux_get_osrelease, return); +} + +int +linux_kernver(struct thread *td) +{ + struct prison *pr; + struct linux_prison *lpr; + int osrel; + + LIN_SDT_PROBE1(mib, linux_kernver, entry, td); + + lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); + osrel = lpr->pr_osrel; + mtx_unlock(&pr->pr_mtx); + + LIN_SDT_PROBE1(mib, linux_kernver, return, osrel); + return (osrel); +} + +static int +linux_set_osrelease(struct thread *td, char *osrelease) +{ + struct prison *pr; + struct linux_prison *lpr; + int error; + + LIN_SDT_PROBE2(mib, linux_set_osrelease, entry, td, osrelease); + + 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); + + LIN_SDT_PROBE1(mib, linux_set_osrelease, return, error); + return (error); +} + +int +linux_get_oss_version(struct thread *td) +{ + struct prison *pr; + struct linux_prison *lpr; + int version; + + LIN_SDT_PROBE1(mib, linux_get_oss_version, entry, td); + + lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); + version = lpr->pr_oss_version; + mtx_unlock(&pr->pr_mtx); + + LIN_SDT_PROBE1(mib, linux_get_oss_version, return, version); + return (version); +} + +static int +linux_set_oss_version(struct thread *td, int oss_version) +{ + struct prison *pr; + struct linux_prison *lpr; + + LIN_SDT_PROBE2(mib, linux_set_oss_version, entry, td, oss_version); + + lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); + lpr->pr_oss_version = oss_version; + mtx_unlock(&pr->pr_mtx); + + LIN_SDT_PROBE1(mib, linux_set_oss_version, return, 0); + return (0); +} + +#if defined(DEBUG) || defined(KTR) +/* XXX: can be removed when every ldebug(...) and KTR stuff are removed. */ + +u_char linux_debug_map[howmany(LINUX_SYS_MAXSYSCALL, sizeof(u_char))]; + +static int +linux_debug(int syscall, int toggle, int global) +{ + + if (global) { + char c = toggle ? 0 : 0xff; + + memset(linux_debug_map, c, sizeof(linux_debug_map)); + return (0); + } + if (syscall < 0 || syscall >= LINUX_SYS_MAXSYSCALL) + return (EINVAL); + if (toggle) + clrbit(linux_debug_map, syscall); + else + setbit(linux_debug_map, syscall); + return (0); +} + +/* + * Usage: sysctl linux.debug=<syscall_nr>.<0/1> + * + * E.g.: sysctl linux.debug=21.0 + * + * As a special case, syscall "all" will apply to all syscalls globally. + */ +#define LINUX_MAX_DEBUGSTR 16 +static int +linux_sysctl_debug(SYSCTL_HANDLER_ARGS) +{ + char value[LINUX_MAX_DEBUGSTR], *p; + int error, sysc, toggle; + int global = 0; + + value[0] = '\0'; + error = sysctl_handle_string(oidp, value, LINUX_MAX_DEBUGSTR, req); + if (error || req->newptr == NULL) + return (error); + for (p = value; *p != '\0' && *p != '.'; p++); + if (*p == '\0') + return (EINVAL); + *p++ = '\0'; + sysc = strtol(value, NULL, 0); + toggle = strtol(p, NULL, 0); + if (strcmp(value, "all") == 0) + global = 1; + error = linux_debug(sysc, toggle, global); + return (error); +} + +SYSCTL_PROC(_compat_linux, OID_AUTO, debug, + CTLTYPE_STRING | CTLFLAG_RW, + 0, 0, linux_sysctl_debug, "A", + "Linux debugging control"); + +#endif /* DEBUG || KTR */ diff --git a/sys/compat/linux/linux_mib.h b/sys/compat/linux/linux_mib.h new file mode 100644 index 0000000..e8eedf9 --- /dev/null +++ b/sys/compat/linux/linux_mib.h @@ -0,0 +1,50 @@ +/*- + * 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 + * 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_MIB_H_ +#define _LINUX_MIB_H_ + +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_KERNVER_2004000 2004000 +#define LINUX_KERNVER_2006000 2006000 + +#define linux_use26(t) (linux_kernver(t) >= LINUX_KERNVER_2006000) + +#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 0000000..7587272 --- /dev/null +++ b/sys/compat/linux/linux_misc.c @@ -0,0 +1,1927 @@ +/*- + * 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 "opt_kdtrace.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/mutex.h> +#include <sys/namei.h> +#include <sys/priv.h> +#include <sys/proc.h> +#include <sys/reboot.h> +#include <sys/racct.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 <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/vm_object.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_util.h> +#include <compat/linux/linux_sysproto.h> +#include <compat/linux/linux_emul.h> +#include <compat/linux/linux_misc.h> + +/* DTrace init */ +LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); + +/* Linuxulator-global DTrace probes */ +LIN_SDT_PROBE_DECLARE(locks, emul_lock, locked); +LIN_SDT_PROBE_DECLARE(locks, emul_lock, unlock); +LIN_SDT_PROBE_DECLARE(locks, emul_shared_rlock, locked); +LIN_SDT_PROBE_DECLARE(locks, emul_shared_rlock, unlock); +LIN_SDT_PROBE_DECLARE(locks, emul_shared_wlock, locked); +LIN_SDT_PROBE_DECLARE(locks, emul_shared_wlock, unlock); + +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 totalbig; + l_ulong freebig; + l_uint mem_unit; + char _f[20-2*sizeof(l_long)-sizeof(l_int)]; /* padding */ +}; +int +linux_sysinfo(struct thread *td, struct linux_sysinfo_args *args) +{ + struct l_sysinfo sysinfo; + vm_object_t object; + int i, j; + struct timespec ts; + + 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 = sysinfo.totalram - cnt.v_wire_count * PAGE_SIZE; + + sysinfo.sharedram = 0; + mtx_lock(&vm_object_list_mtx); + TAILQ_FOREACH(object, &vm_object_list, object_list) + if (object->shadow_count > 1) + sysinfo.sharedram += object->resident_page_count; + mtx_unlock(&vm_object_list_mtx); + + sysinfo.sharedram *= PAGE_SIZE; + sysinfo.bufferram = 0; + + swap_pager_status(&i, &j); + sysinfo.totalswap = i * PAGE_SIZE; + sysinfo.freeswap = (i - j) * PAGE_SIZE; + + sysinfo.procs = nprocs; + + /* The following are only present in newer Linux kernels. */ + sysinfo.totalbig = 0; + sysinfo.freebig = 0; + sysinfo.mem_unit = 1; + + return (copyout(&sysinfo, args->info, sizeof(sysinfo))); +} + +int +linux_alarm(struct thread *td, struct linux_alarm_args *args) +{ + struct itimerval it, old_it; + u_int secs; + int error; + +#ifdef DEBUG + if (ldebug(alarm)) + printf(ARGS(alarm, "%u"), args->secs); +#endif + + secs = args->secs; + + if (secs > INT_MAX) + secs = INT_MAX; + + it.it_value.tv_sec = (long) secs; + it.it_value.tv_usec = 0; + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = 0; + error = kern_setitimer(td, ITIMER_REAL, &it, &old_it); + if (error) + return (error); + if (timevalisset(&old_it.it_value)) { + if (old_it.it_value.tv_usec != 0) + old_it.it_value.tv_sec++; + td->td_retval[0] = old_it.it_value.tv_sec; + } + return (0); +} + +int +linux_brk(struct thread *td, struct linux_brk_args *args) +{ + struct vmspace *vm = td->td_proc->p_vmspace; + vm_offset_t new, old; + struct obreak_args /* { + char * nsize; + } */ tmp; + +#ifdef DEBUG + if (ldebug(brk)) + printf(ARGS(brk, "%p"), (void *)(uintptr_t)args->dsend); +#endif + old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize); + new = (vm_offset_t)args->dsend; + tmp.nsize = (char *)new; + if (((caddr_t)new > vm->vm_daddr) && !sys_obreak(td, &tmp)) + td->td_retval[0] = (long)new; + else + td->td_retval[0] = (long)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; + struct vattr attr; + vm_offset_t vmaddr; + unsigned long file_offset; + unsigned long bss_size; + char *library; + ssize_t aresid; + int error, locked, writecount; + + LCONVPATHEXIST(td, args->library, &library); + +#ifdef DEBUG + if (ldebug(uselib)) + printf(ARGS(uselib, "%s"), library); +#endif + + a_out = NULL; + locked = 0; + vp = NULL; + + 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 = 1; + + /* Writable? */ + error = VOP_GET_WRITECOUNT(vp, &writecount); + if (error != 0) + goto cleanup; + if (writecount != 0) { + error = ETXTBSY; + goto cleanup; + } + + /* 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; + + /* 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(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. + * XXX: Note that if any of the VM operations fail below we don't + * clear this flag. + */ + VOP_SET_TEXT(vp); + + /* + * Lock no longer needed + */ + locked = 0; + VOP_UNLOCK(vp, 0); + + /* + * 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) { +#ifdef DEBUG + printf("uselib: Non page aligned binary %lu\n", file_offset); +#endif + /* 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, FALSE, 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 { +#ifdef DEBUG + printf("uselib: Page aligned binary %lu\n", file_offset); +#endif + /* + * 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. + */ + error = vm_mmap(&td->td_proc->p_vmspace->vm_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; + } +#ifdef DEBUG + printf("mem=%08lx = %08lx %08lx\n", (long)vmaddr, ((long *)vmaddr)[0], + ((long *)vmaddr)[1]); +#endif + 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, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0); + if (error) + goto cleanup; + } + +cleanup: + /* Unlock vnode if needed */ + if (locked) + VOP_UNLOCK(vp, 0); + + /* Release the temporary mapping. */ + if (a_out) + kmem_free_wakeup(exec_map, (vm_offset_t)a_out, PAGE_SIZE); + + return (error); +} + +#endif /* __i386__ */ + +int +linux_select(struct thread *td, struct linux_select_args *args) +{ + l_timeval ltv; + struct timeval tv0, tv1, utv, *tvp; + int error; + +#ifdef DEBUG + if (ldebug(select)) + printf(ARGS(select, "%d, %p, %p, %p, %p"), args->nfds, + (void *)args->readfds, (void *)args->writefds, + (void *)args->exceptfds, (void *)args->timeout); +#endif + + /* + * Store current time for computation of the amount of + * time left. + */ + if (args->timeout) { + if ((error = copyin(args->timeout, <v, sizeof(ltv)))) + goto select_out; + utv.tv_sec = ltv.tv_sec; + utv.tv_usec = ltv.tv_usec; +#ifdef DEBUG + if (ldebug(select)) + printf(LMSG("incoming timeout (%jd/%ld)"), + (intmax_t)utv.tv_sec, utv.tv_usec); +#endif + + 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, sizeof(l_int) * 8); + +#ifdef DEBUG + if (ldebug(select)) + printf(LMSG("real select returns %d"), error); +#endif + 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); +#ifdef DEBUG + if (ldebug(select)) + printf(LMSG("outgoing timeout (%jd/%ld)"), + (intmax_t)utv.tv_sec, utv.tv_usec); +#endif + ltv.tv_sec = utv.tv_sec; + ltv.tv_usec = utv.tv_usec; + if ((error = copyout(<v, args->timeout, sizeof(ltv)))) + goto select_out; + } + +select_out: +#ifdef DEBUG + if (ldebug(select)) + printf(LMSG("select_out -> %d"), error); +#endif + return (error); +} + +int +linux_mremap(struct thread *td, struct linux_mremap_args *args) +{ + struct munmap_args /* { + void *addr; + size_t len; + } */ bsd_args; + int error = 0; + +#ifdef DEBUG + if (ldebug(mremap)) + printf(ARGS(mremap, "%p, %08lx, %08lx, %08lx"), + (void *)(uintptr_t)args->addr, + (unsigned long)args->old_len, + (unsigned long)args->new_len, + (unsigned long)args->flags); +#endif + + 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) { + bsd_args.addr = + (caddr_t)((uintptr_t)args->addr + args->new_len); + bsd_args.len = args->old_len - args->new_len; + error = sys_munmap(td, &bsd_args); + } + + 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) +{ + struct msync_args bsd_args; + + bsd_args.addr = (caddr_t)(uintptr_t)args->addr; + bsd_args.len = (uintptr_t)args->len; + bsd_args.flags = args->fl & ~LINUX_MS_SYNC; + + return (sys_msync(td, &bsd_args)); +} + +int +linux_time(struct thread *td, struct linux_time_args *args) +{ + struct timeval tv; + l_time_t tm; + int error; + +#ifdef DEBUG + if (ldebug(time)) + printf(ARGS(time, "*")); +#endif + + 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); +} + +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; + +#ifdef DEBUG + if (ldebug(times)) + printf(ARGS(times, "*")); +#endif + + if (args->buf != NULL) { + p = td->td_proc; + PROC_LOCK(p); + PROC_SLOCK(p); + calcru(p, &utime, &stime); + PROC_SUNLOCK(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; + +#ifdef DEBUG + if (ldebug(newuname)) + printf(ARGS(newuname, "*")); +#endif + + 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; + } + strlcpy(utsname.machine, linux_platform, LINUX_MAX_UTSNAME); + + return (copyout(&utsname, args->buf, sizeof(utsname))); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +struct l_utimbuf { + l_time_t l_actime; + l_time_t l_modtime; +}; + +int +linux_utime(struct thread *td, struct linux_utime_args *args) +{ + struct timeval tv[2], *tvp; + struct l_utimbuf lut; + char *fname; + int error; + + LCONVPATHEXIST(td, args->fname, &fname); + +#ifdef DEBUG + if (ldebug(utime)) + printf(ARGS(utime, "%s, *"), fname); +#endif + + if (args->times) { + if ((error = copyin(args->times, &lut, sizeof lut))) { + 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; + + error = kern_utimes(td, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE); + LFREEPATH(fname); + return (error); +} + +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; + + LCONVPATHEXIST(td, args->fname, &fname); + +#ifdef DEBUG + if (ldebug(utimes)) + printf(ARGS(utimes, "%s, *"), fname); +#endif + + 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; + } + + error = kern_utimes(td, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE); + LFREEPATH(fname); + return (error); +} + +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; + + dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; + LCONVPATHEXIST_AT(td, args->filename, &fname, dfd); + +#ifdef DEBUG + if (ldebug(futimesat)) + printf(ARGS(futimesat, "%s, *"), fname); +#endif + + if (args->utimes != NULL) { + if ((error = copyin(args->utimes, 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; + } + + error = kern_utimesat(td, dfd, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE); + LFREEPATH(fname); + return (error); +} +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ + +int +linux_common_wait(struct thread *td, int pid, int *status, + int options, struct rusage *ru) +{ + int error, tmpstat; + + error = kern_wait(td, pid, &tmpstat, options, ru); + if (error) + return (error); + + if (status) { + tmpstat &= 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); + error = copyout(&tmpstat, status, sizeof(int)); + } + + return (error); +} + +int +linux_waitpid(struct thread *td, struct linux_waitpid_args *args) +{ + int options; + +#ifdef DEBUG + if (ldebug(waitpid)) + printf(ARGS(waitpid, "%d, %p, %d"), + args->pid, (void *)args->status, args->options); +#endif + /* + * this is necessary because the test in kern_wait doesn't work + * because we mess with the options here + */ + if (args->options & ~(WUNTRACED | WNOHANG | WCONTINUED | __WCLONE)) + return (EINVAL); + + options = (args->options & (WNOHANG | WUNTRACED)); + /* WLINUXCLONE should be equal to __WCLONE, but we make sure */ + if (args->options & __WCLONE) + options |= WLINUXCLONE; + + return (linux_common_wait(td, args->pid, args->status, options, NULL)); +} + + +int +linux_mknod(struct thread *td, struct linux_mknod_args *args) +{ + char *path; + int error; + + LCONVPATHCREAT(td, args->path, &path); + +#ifdef DEBUG + if (ldebug(mknod)) + printf(ARGS(mknod, "%s, %d, %d"), path, args->mode, args->dev); +#endif + + switch (args->mode & S_IFMT) { + case S_IFIFO: + case S_IFSOCK: + error = kern_mkfifo(td, path, UIO_SYSSPACE, args->mode); + break; + + case S_IFCHR: + case S_IFBLK: + error = kern_mknod(td, path, UIO_SYSSPACE, args->mode, + args->dev); + break; + + case S_IFDIR: + error = EPERM; + break; + + case 0: + args->mode |= S_IFREG; + /* FALLTHROUGH */ + case S_IFREG: + error = kern_open(td, path, UIO_SYSSPACE, + O_WRONLY | O_CREAT | O_TRUNC, args->mode); + if (error == 0) + kern_close(td, td->td_retval[0]); + break; + + default: + error = EINVAL; + break; + } + LFREEPATH(path); + return (error); +} + +int +linux_mknodat(struct thread *td, struct linux_mknodat_args *args) +{ + char *path; + int error, dfd; + + dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; + LCONVPATHCREAT_AT(td, args->filename, &path, dfd); + +#ifdef DEBUG + if (ldebug(mknodat)) + printf(ARGS(mknodat, "%s, %d, %d"), path, args->mode, args->dev); +#endif + + switch (args->mode & S_IFMT) { + case S_IFIFO: + case S_IFSOCK: + error = kern_mkfifoat(td, dfd, path, UIO_SYSSPACE, args->mode); + break; + + case S_IFCHR: + case S_IFBLK: + error = kern_mknodat(td, dfd, path, UIO_SYSSPACE, 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, UIO_SYSSPACE, + O_WRONLY | O_CREAT | O_TRUNC, args->mode); + if (error == 0) + kern_close(td, td->td_retval[0]); + break; + + default: + error = EINVAL; + break; + } + 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) +{ +#ifdef DEBUG + if (ldebug(personality)) + printf(ARGS(personality, "%lu"), (unsigned long)args->per); +#endif + if (args->per != 0) + return (EINVAL); + + /* Yes Jim, it's still a Linux... */ + td->td_retval[0] = 0; + 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; + +#ifdef DEBUG + if (ldebug(setitimer)) + printf(ARGS(setitimer, "%p, %p"), + (void *)uap->itv, (void *)uap->oitv); +#endif + + 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); +#ifdef DEBUG + if (ldebug(setitimer)) { + printf("setitimer: value: sec: %jd, usec: %ld\n", + (intmax_t)aitv.it_value.tv_sec, aitv.it_value.tv_usec); + printf("setitimer: interval: sec: %jd, usec: %ld\n", + (intmax_t)aitv.it_interval.tv_sec, aitv.it_interval.tv_usec); + } +#endif + 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; + +#ifdef DEBUG + if (ldebug(getitimer)) + printf(ARGS(getitimer, "%p"), (void *)uap->itv); +#endif + error = kern_getitimer(td, uap->which, &aitv); + if (error != 0) + return (error); + B2L_ITIMERVAL(&ls, &aitv); + return (copyout(&ls, uap->itv, sizeof(ls))); +} + +int +linux_nice(struct thread *td, struct linux_nice_args *args) +{ + struct setpriority_args bsd_args; + + bsd_args.which = PRIO_PROCESS; + bsd_args.who = 0; /* current process */ + bsd_args.prio = args->inc; + return (sys_setpriority(td, &bsd_args)); +} + +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_TEMP, M_WAITOK); + error = copyin(args->grouplist, linux_gidset, ngrp * sizeof(l_gid_t)); + if (error) + goto out; + 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)) != 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); + p->p_ucred = newcred; + PROC_UNLOCK(p); + crfree(oldcred); + error = 0; +out: + free(linux_gidset, M_TEMP); + 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_TEMP, 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_TEMP); + if (error) + return (error); + + td->td_retval[0] = ngrp; + return (0); +} + +int +linux_setrlimit(struct thread *td, struct linux_setrlimit_args *args) +{ + struct rlimit bsd_rlim; + struct l_rlimit rlim; + u_int which; + int error; + +#ifdef DEBUG + if (ldebug(setrlimit)) + printf(ARGS(setrlimit, "%d, %p"), + args->resource, (void *)args->rlim); +#endif + + 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)); +} + +int +linux_old_getrlimit(struct thread *td, struct linux_old_getrlimit_args *args) +{ + struct l_rlimit rlim; + struct proc *p = td->td_proc; + struct rlimit bsd_rlim; + u_int which; + +#ifdef DEBUG + if (ldebug(old_getrlimit)) + printf(ARGS(old_getrlimit, "%d, %p"), + args->resource, (void *)args->rlim); +#endif + + if (args->resource >= LINUX_RLIM_NLIMITS) + return (EINVAL); + + which = linux_to_bsd_resource[args->resource]; + if (which == -1) + return (EINVAL); + + PROC_LOCK(p); + lim_rlimit(p, which, &bsd_rlim); + PROC_UNLOCK(p); + +#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))); +} + +int +linux_getrlimit(struct thread *td, struct linux_getrlimit_args *args) +{ + struct l_rlimit rlim; + struct proc *p = td->td_proc; + struct rlimit bsd_rlim; + u_int which; + +#ifdef DEBUG + if (ldebug(getrlimit)) + printf(ARGS(getrlimit, "%d, %p"), + args->resource, (void *)args->rlim); +#endif + + if (args->resource >= LINUX_RLIM_NLIMITS) + return (EINVAL); + + which = linux_to_bsd_resource[args->resource]; + if (which == -1) + return (EINVAL); + + PROC_LOCK(p); + lim_rlimit(p, which, &bsd_rlim); + PROC_UNLOCK(p); + + 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_setscheduler_args bsd; + +#ifdef DEBUG + if (ldebug(sched_setscheduler)) + printf(ARGS(sched_setscheduler, "%d, %d, %p"), + args->pid, args->policy, (const void *)args->param); +#endif + + 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); + } + + bsd.pid = args->pid; + bsd.param = (struct sched_param *)args->param; + return (sys_sched_setscheduler(td, &bsd)); +} + +int +linux_sched_getscheduler(struct thread *td, + struct linux_sched_getscheduler_args *args) +{ + struct sched_getscheduler_args bsd; + int error; + +#ifdef DEBUG + if (ldebug(sched_getscheduler)) + printf(ARGS(sched_getscheduler, "%d"), args->pid); +#endif + + bsd.pid = args->pid; + error = sys_sched_getscheduler(td, &bsd); + + switch (td->td_retval[0]) { + 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; + +#ifdef DEBUG + if (ldebug(sched_get_priority_max)) + printf(ARGS(sched_get_priority_max, "%d"), args->policy); +#endif + + 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; + +#ifdef DEBUG + if (ldebug(sched_get_priority_min)) + printf(ARGS(sched_get_priority_min, "%d"), args->policy); +#endif + + 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; + +#ifdef DEBUG + if (ldebug(reboot)) + printf(ARGS(reboot, "0x%x"), args->cmd); +#endif + + 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)); +} + + +/* + * The FreeBSD native getpid(2), getgid(2) and getuid(2) also modify + * td->td_retval[1] when COMPAT_43 is defined. This clobbers registers that + * are assumed to be preserved. The following lightweight syscalls fixes + * this. See also linux_getgid16() and linux_getuid16() in linux_uid16.c + * + * linux_getpid() - MP SAFE + * linux_getgid() - MP SAFE + * linux_getuid() - MP SAFE + */ + +int +linux_getpid(struct thread *td, struct linux_getpid_args *args) +{ + struct linux_emuldata *em; + +#ifdef DEBUG + if (ldebug(getpid)) + printf(ARGS(getpid, "")); +#endif + + if (linux_use26(td)) { + em = em_find(td->td_proc, EMUL_DONTLOCK); + KASSERT(em != NULL, ("getpid: emuldata not found.\n")); + td->td_retval[0] = em->shared->group_pid; + } else { + td->td_retval[0] = td->td_proc->p_pid; + } + + return (0); +} + +int +linux_gettid(struct thread *td, struct linux_gettid_args *args) +{ + +#ifdef DEBUG + if (ldebug(gettid)) + printf(ARGS(gettid, "")); +#endif + + td->td_retval[0] = td->td_proc->p_pid; + return (0); +} + + +int +linux_getppid(struct thread *td, struct linux_getppid_args *args) +{ + struct linux_emuldata *em; + struct proc *p, *pp; + +#ifdef DEBUG + if (ldebug(getppid)) + printf(ARGS(getppid, "")); +#endif + + if (!linux_use26(td)) { + PROC_LOCK(td->td_proc); + td->td_retval[0] = td->td_proc->p_pptr->p_pid; + PROC_UNLOCK(td->td_proc); + return (0); + } + + em = em_find(td->td_proc, EMUL_DONTLOCK); + + KASSERT(em != NULL, ("getppid: process emuldata not found.\n")); + + /* find the group leader */ + p = pfind(em->shared->group_pid); + + if (p == NULL) { +#ifdef DEBUG + printf(LMSG("parent process not found.\n")); +#endif + return (0); + } + + pp = p->p_pptr; /* switch to parent */ + PROC_LOCK(pp); + PROC_UNLOCK(p); + + /* if its also linux process */ + if (pp->p_sysent == &elf_linux_sysvec) { + em = em_find(pp, EMUL_DONTLOCK); + KASSERT(em != NULL, ("getppid: parent emuldata not found.\n")); + + td->td_retval[0] = em->shared->group_pid; + } else + td->td_retval[0] = pp->p_pid; + + PROC_UNLOCK(pp); + + return (0); +} + +int +linux_getgid(struct thread *td, struct linux_getgid_args *args) +{ + +#ifdef DEBUG + if (ldebug(getgid)) + printf(ARGS(getgid, "")); +#endif + + td->td_retval[0] = td->td_ucred->cr_rgid; + return (0); +} + +int +linux_getuid(struct thread *td, struct linux_getuid_args *args) +{ + +#ifdef DEBUG + if (ldebug(getuid)) + printf(ARGS(getuid, "")); +#endif + + td->td_retval[0] = td->td_ucred->cr_ruid; + return (0); +} + + +int +linux_getsid(struct thread *td, struct linux_getsid_args *args) +{ + struct getsid_args bsd; + +#ifdef DEBUG + if (ldebug(getsid)) + printf(ARGS(getsid, "%i"), args->pid); +#endif + + bsd.pid = args->pid; + return (sys_getsid(td, &bsd)); +} + +int +linux_nosys(struct thread *td, struct nosys_args *ignore) +{ + + return (ENOSYS); +} + +int +linux_getpriority(struct thread *td, struct linux_getpriority_args *args) +{ + struct getpriority_args bsd_args; + int error; + +#ifdef DEBUG + if (ldebug(getpriority)) + printf(ARGS(getpriority, "%i, %i"), args->which, args->who); +#endif + + bsd_args.which = args->which; + bsd_args.who = args->who; + error = sys_getpriority(td, &bsd_args); + 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]; + +#ifdef DEBUG + if (ldebug(sethostname)) + printf(ARGS(sethostname, "*, %i"), args->len); +#endif + + 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]; + +#ifdef DEBUG + if (ldebug(setdomainname)) + printf(ARGS(setdomainname, "*, %i"), args->len); +#endif + + 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) +{ + struct linux_emuldata *em; + +#ifdef DEBUG + if (ldebug(exit_group)) + printf(ARGS(exit_group, "%i"), args->error_code); +#endif + + em = em_find(td->td_proc, EMUL_DONTLOCK); + if (em->shared->refs > 1) { + EMUL_SHARED_WLOCK(&emul_shared_lock); + em->shared->flags |= EMUL_SHARED_HASXSTAT; + em->shared->xstat = W_EXITCODE(args->error_code, 0); + EMUL_SHARED_WUNLOCK(&emul_shared_lock); + if (linux_use26(td)) + linux_kill_threads(td, SIGKILL); + } + + /* + * 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, W_EXITCODE(args->error_code, 0)); + + return (0); +} + +#define _LINUX_CAPABILITY_VERSION 0x19980330 + +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 *args) +{ + struct l_user_cap_header luch; + struct l_user_cap_data lucd; + int error; + + if (args->hdrp == NULL) + return (EFAULT); + + error = copyin(args->hdrp, &luch, sizeof(luch)); + if (error != 0) + return (error); + + if (luch.version != _LINUX_CAPABILITY_VERSION) { + luch.version = _LINUX_CAPABILITY_VERSION; + error = copyout(&luch, args->hdrp, sizeof(luch)); + if (error) + return (error); + return (EINVAL); + } + + if (luch.pid) + return (EPERM); + + if (args->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. + */ + bzero (&lucd, sizeof(lucd)); + error = copyout(&lucd, args->datap, sizeof(lucd)); + } + + return (error); +} + +int +linux_capset(struct thread *td, struct linux_capset_args *args) +{ + struct l_user_cap_header luch; + struct l_user_cap_data lucd; + int error; + + if (args->hdrp == NULL || args->datap == NULL) + return (EFAULT); + + error = copyin(args->hdrp, &luch, sizeof(luch)); + if (error != 0) + return (error); + + if (luch.version != _LINUX_CAPABILITY_VERSION) { + luch.version = _LINUX_CAPABILITY_VERSION; + error = copyout(&luch, args->hdrp, sizeof(luch)); + if (error) + return (error); + return (EINVAL); + } + + if (luch.pid) + return (EPERM); + + error = copyin(args->datap, &lucd, sizeof(lucd)); + if (error != 0) + return (error); + + /* We currently don't support setting any capabilities. */ + if (lucd.effective || lucd.permitted || lucd.inheritable) { + linux_msg(td, + "capset effective=0x%x, permitted=0x%x, " + "inheritable=0x%x is not implemented", + (int)lucd.effective, (int)lucd.permitted, + (int)lucd.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]; + struct linux_emuldata *em; + int pdeath_signal; + +#ifdef DEBUG + if (ldebug(prctl)) + printf(ARGS(prctl, "%d, %d, %d, %d, %d"), args->option, + args->arg2, args->arg3, args->arg4, args->arg5); +#endif + + switch (args->option) { + case LINUX_PR_SET_PDEATHSIG: + if (!LINUX_SIG_VALID(args->arg2)) + return (EINVAL); + em = em_find(p, EMUL_DOLOCK); + KASSERT(em != NULL, ("prctl: emuldata not found.\n")); + em->pdeath_signal = args->arg2; + EMUL_UNLOCK(&emul_lock); + break; + case LINUX_PR_GET_PDEATHSIG: + em = em_find(p, EMUL_DOLOCK); + KASSERT(em != NULL, ("prctl: emuldata not found.\n")); + pdeath_signal = em->pdeath_signal; + EMUL_UNLOCK(&emul_lock); + error = copyout(&pdeath_signal, + (void *)(register_t)args->arg2, + sizeof(pdeath_signal)); + break; + 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; + default: + error = EINVAL; + break; + } + + return (error); +} + +/* + * Get affinity of a process. + */ +int +linux_sched_getaffinity(struct thread *td, + struct linux_sched_getaffinity_args *args) +{ + int error; + struct cpuset_getaffinity_args cga; + +#ifdef DEBUG + if (ldebug(sched_getaffinity)) + printf(ARGS(sched_getaffinity, "%d, %d, *"), args->pid, + args->len); +#endif + if (args->len < sizeof(cpuset_t)) + return (EINVAL); + + cga.level = CPU_LEVEL_WHICH; + cga.which = CPU_WHICH_PID; + cga.id = args->pid; + cga.cpusetsize = sizeof(cpuset_t); + cga.mask = (cpuset_t *) args->user_mask_ptr; + + if ((error = sys_cpuset_getaffinity(td, &cga)) == 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 cpuset_setaffinity_args csa; + +#ifdef DEBUG + if (ldebug(sched_setaffinity)) + printf(ARGS(sched_setaffinity, "%d, %d, *"), args->pid, + args->len); +#endif + if (args->len < sizeof(cpuset_t)) + return (EINVAL); + + csa.level = CPU_LEVEL_WHICH; + csa.which = CPU_WHICH_PID; + csa.id = args->pid; + csa.cpusetsize = sizeof(cpuset_t); + csa.mask = (cpuset_t *) args->user_mask_ptr; + + return (sys_cpuset_setaffinity(td, &csa)); +} diff --git a/sys/compat/linux/linux_misc.h b/sys/compat/linux/linux_misc.h new file mode 100644 index 0000000..154d78f --- /dev/null +++ b/sys/compat/linux/linux_misc.h @@ -0,0 +1,125 @@ +/*- + * 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 + * 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_MISC_H_ +#define _LINUX_MISC_H_ + +/* + * 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_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_MAX_COMM_LEN 16 /* Maximum length of the process name. */ + +#define LINUX_MREMAP_MAYMOVE 1 +#define LINUX_MREMAP_FIXED 2 + +extern const char *linux_platform; + +/* + * 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_EXECFN 31 /* filename of program */ + +/* 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_VFORK 0x00004000 +#define LINUX_CLONE_PARENT 0x00008000 +#define LINUX_CLONE_THREAD 0x00010000 +#define LINUX_CLONE_SETTLS 0x00080000 +#define LINUX_CLONE_PARENT_SETTID 0x00100000 +#define LINUX_CLONE_CHILD_CLEARTID 0x00200000 +#define LINUX_CLONE_CHILD_SETTID 0x01000000 + +#define LINUX_THREADING_FLAGS \ + (LINUX_CLONE_VM | LINUX_CLONE_FS | LINUX_CLONE_FILES | \ + LINUX_CLONE_SIGHAND | LINUX_CLONE_THREAD) + +/* Scheduling policies */ +#define LINUX_SCHED_OTHER 0 +#define LINUX_SCHED_FIFO 1 +#define LINUX_SCHED_RR 2 + +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_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_REALTIME_HR 4 +#define LINUX_CLOCK_MONOTONIC_HR 5 + +extern int stclohz; + +#define __WCLONE 0x80000000 + +int linux_common_wait(struct thread *td, int pid, int *status, + int options, struct rusage *ru); +int linux_set_upcall_kse(struct thread *td, register_t stack); +int linux_set_cloned_tls(struct thread *td, void *desc); + +#endif /* _LINUX_MISC_H_ */ diff --git a/sys/compat/linux/linux_signal.c b/sys/compat/linux/linux_signal.c new file mode 100644 index 0000000..1c778f9 --- /dev/null +++ b/sys/compat/linux/linux_signal.c @@ -0,0 +1,656 @@ +/*- + * 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 <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> + +void +linux_to_bsd_sigset(l_sigset_t *lss, sigset_t *bss) +{ + int b, l; + + SIGEMPTYSET(*bss); + bss->__bits[0] = lss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1); + bss->__bits[1] = lss->__bits[1]; + for (l = 1; l <= LINUX_SIGTBLSZ; l++) { + if (LINUX_SIGISMEMBER(*lss, l)) { + b = linux_to_bsd_signal[_SIG_IDX(l)]; + if (b) + SIGADDSET(*bss, b); + } + } +} + +void +bsd_to_linux_sigset(sigset_t *bss, l_sigset_t *lss) +{ + int b, l; + + LINUX_SIGEMPTYSET(*lss); + lss->__bits[0] = bss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1); + lss->__bits[1] = bss->__bits[1]; + for (b = 1; b <= LINUX_SIGTBLSZ; b++) { + if (SIGISMEMBER(*bss, b)) { + l = bsd_to_linux_signal[_SIG_IDX(b)]; + if (l) + LINUX_SIGADDSET(*lss, l); + } + } +} + +static void +linux_to_bsd_sigaction(l_sigaction_t *lsa, struct sigaction *bsa) +{ + + linux_to_bsd_sigset(&lsa->lsa_mask, &bsa->sa_mask); + bsa->sa_handler = PTRIN(lsa->lsa_handler); + bsa->sa_flags = 0; + if (lsa->lsa_flags & LINUX_SA_NOCLDSTOP) + bsa->sa_flags |= SA_NOCLDSTOP; + if (lsa->lsa_flags & LINUX_SA_NOCLDWAIT) + bsa->sa_flags |= SA_NOCLDWAIT; + if (lsa->lsa_flags & LINUX_SA_SIGINFO) + bsa->sa_flags |= SA_SIGINFO; + if (lsa->lsa_flags & LINUX_SA_ONSTACK) + bsa->sa_flags |= SA_ONSTACK; + if (lsa->lsa_flags & LINUX_SA_RESTART) + bsa->sa_flags |= SA_RESTART; + if (lsa->lsa_flags & LINUX_SA_ONESHOT) + bsa->sa_flags |= SA_RESETHAND; + if (lsa->lsa_flags & LINUX_SA_NOMASK) + bsa->sa_flags |= SA_NODEFER; +} + +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; + + if (linux_sig <= LINUX_SIGTBLSZ) + sig = linux_to_bsd_signal[_SIG_IDX(linux_sig)]; + else + sig = 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); +} + + +int +linux_signal(struct thread *td, struct linux_signal_args *args) +{ + l_sigaction_t nsa, osa; + int error; + +#ifdef DEBUG + if (ldebug(signal)) + printf(ARGS(signal, "%d, %p"), + args->sig, (void *)(uintptr_t)args->handler); +#endif + + 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); +} + +int +linux_rt_sigaction(struct thread *td, struct linux_rt_sigaction_args *args) +{ + l_sigaction_t nsa, osa; + int error; + +#ifdef DEBUG + if (ldebug(rt_sigaction)) + printf(ARGS(rt_sigaction, "%ld, %p, %p, %ld"), + (long)args->sig, (void *)args->act, + (void *)args->oact, (long)args->sigsetsize); +#endif + + 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); +} + +int +linux_sigprocmask(struct thread *td, struct linux_sigprocmask_args *args) +{ + l_osigset_t mask; + l_sigset_t set, oset; + int error; + +#ifdef DEBUG + if (ldebug(sigprocmask)) + printf(ARGS(sigprocmask, "%d, *, *"), args->how); +#endif + + if (args->mask != NULL) { + error = copyin(args->mask, &mask, sizeof(l_osigset_t)); + if (error) + return (error); + LINUX_SIGEMPTYSET(set); + set.__bits[0] = mask; + } + + error = linux_do_sigprocmask(td, args->how, + args->mask ? &set : NULL, + args->omask ? &oset : NULL); + + if (args->omask != NULL && !error) { + mask = oset.__bits[0]; + error = copyout(&mask, args->omask, sizeof(l_osigset_t)); + } + + return (error); +} + +int +linux_rt_sigprocmask(struct thread *td, struct linux_rt_sigprocmask_args *args) +{ + l_sigset_t set, oset; + int error; + +#ifdef DEBUG + if (ldebug(rt_sigprocmask)) + printf(ARGS(rt_sigprocmask, "%d, %p, %p, %ld"), + args->how, (void *)args->mask, + (void *)args->omask, (long)args->sigsetsize); +#endif + + 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); +} + +int +linux_sgetmask(struct thread *td, struct linux_sgetmask_args *args) +{ + struct proc *p = td->td_proc; + l_sigset_t mask; + +#ifdef DEBUG + if (ldebug(sgetmask)) + printf(ARGS(sgetmask, "")); +#endif + + PROC_LOCK(p); + bsd_to_linux_sigset(&td->td_sigmask, &mask); + PROC_UNLOCK(p); + td->td_retval[0] = mask.__bits[0]; + 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; + +#ifdef DEBUG + if (ldebug(ssetmask)) + printf(ARGS(ssetmask, "%08lx"), (unsigned long)args->mask); +#endif + + PROC_LOCK(p); + bsd_to_linux_sigset(&td->td_sigmask, &lset); + td->td_retval[0] = lset.__bits[0]; + LINUX_SIGEMPTYSET(lset); + lset.__bits[0] = args->mask; + linux_to_bsd_sigset(&lset, &bset); + td->td_sigmask = bset; + SIG_CANTMASK(td->td_sigmask); + signotify(td); + PROC_UNLOCK(p); + return (0); +} + +/* + * MPSAFE + */ +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; + +#ifdef DEBUG + if (ldebug(sigpending)) + printf(ARGS(sigpending, "*")); +#endif + + 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.__bits[0]; + return (copyout(&mask, args->mask, sizeof(mask))); +} + +/* + * 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 */ + +#ifdef DEBUG + if (ldebug(rt_sigpending)) + printf(ARGS(rt_sigpending, "*")); +#endif + + 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; + +#ifdef DEBUG + if (ldebug(rt_sigtimedwait)) + printf(ARGS(rt_sigtimedwait, "*")); +#endif + 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, <v, sizeof(ltv)))) + return (error); +#ifdef DEBUG + if (ldebug(rt_sigtimedwait)) + printf(LMSG("linux_rt_sigtimedwait: " + "incoming timeout (%d/%d)\n"), + ltv.tv_sec, ltv.tv_usec); +#endif + 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); +#ifdef DEBUG + if (ldebug(rt_sigtimedwait)) + printf(LMSG("linux_rt_sigtimedwait: " + "converted timeout (%jd/%ld)\n"), + (intmax_t)tv.tv_sec, tv.tv_usec); +#endif + } + TIMEVAL_TO_TIMESPEC(&tv, &ts); + tsa = &ts; + } + error = kern_sigtimedwait(td, bset, &info, tsa); +#ifdef DEBUG + if (ldebug(rt_sigtimedwait)) + printf(LMSG("linux_rt_sigtimedwait: " + "sigtimedwait returning (%d)\n"), error); +#endif + 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) +{ + struct kill_args /* { + int pid; + int signum; + } */ tmp; + +#ifdef DEBUG + if (ldebug(kill)) + printf(ARGS(kill, "%d, %d"), args->pid, args->signum); +#endif + + /* + * 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 && args->signum <= LINUX_SIGTBLSZ) + tmp.signum = linux_to_bsd_signal[_SIG_IDX(args->signum)]; + else + tmp.signum = args->signum; + + tmp.pid = args->pid; + return (sys_kill(td, &tmp)); +} + +static int +linux_do_tkill(struct thread *td, l_int tgid, l_int pid, l_int signum) +{ + struct proc *proc = td->td_proc; + struct linux_emuldata *em; + struct proc *p; + ksiginfo_t ksi; + int error; + + AUDIT_ARG_SIGNUM(signum); + AUDIT_ARG_PID(pid); + + /* + * Allow signal 0 as a means to check for privileges + */ + if (!LINUX_SIG_VALID(signum) && signum != 0) + return (EINVAL); + + if (signum > 0 && signum <= LINUX_SIGTBLSZ) + signum = linux_to_bsd_signal[_SIG_IDX(signum)]; + + if ((p = pfind(pid)) == NULL) { + if ((p = zpfind(pid)) == NULL) + return (ESRCH); + } + + AUDIT_ARG_PROCESS(p); + error = p_cansignal(td, p, signum); + if (error != 0 || signum == 0) + goto out; + + error = ESRCH; + em = em_find(p, EMUL_DONTLOCK); + + if (em == NULL) { +#ifdef DEBUG + printf("emuldata not found in do_tkill.\n"); +#endif + goto out; + } + if (tgid > 0 && em->shared->group_pid != tgid) + goto out; + + ksiginfo_init(&ksi); + ksi.ksi_signo = signum; + ksi.ksi_code = LINUX_SI_TKILL; + ksi.ksi_errno = 0; + ksi.ksi_pid = proc->p_pid; + ksi.ksi_uid = proc->p_ucred->cr_ruid; + + error = pksignal(p, ksi.ksi_signo, &ksi); + +out: + PROC_UNLOCK(p); + return (error); +} + +int +linux_tgkill(struct thread *td, struct linux_tgkill_args *args) +{ + +#ifdef DEBUG + if (ldebug(tgkill)) + printf(ARGS(tgkill, "%d, %d, %d"), args->tgid, args->pid, args->sig); +#endif + if (args->pid <= 0 || args->tgid <=0) + return (EINVAL); + + return (linux_do_tkill(td, args->tgid, args->pid, args->sig)); +} + +int +linux_tkill(struct thread *td, struct linux_tkill_args *args) +{ +#ifdef DEBUG + if (ldebug(tkill)) + printf(ARGS(tkill, "%i, %i"), args->tid, args->sig); +#endif + if (args->tid <= 0) + return (EINVAL); + + return (linux_do_tkill(td, 0, args->tid, args->sig)); +} + +void +ksiginfo_to_lsiginfo(ksiginfo_t *ksi, l_siginfo_t *lsi, l_int sig) +{ + + lsi->lsi_signo = sig; + lsi->lsi_code = ksi->ksi_code; + + switch (sig) { + case LINUX_SIGPOLL: + /* XXX si_fd? */ + lsi->lsi_band = ksi->ksi_band; + break; + case LINUX_SIGCHLD: + lsi->lsi_pid = ksi->ksi_pid; + lsi->lsi_uid = ksi->ksi_uid; + lsi->lsi_status = ksi->ksi_status; + break; + case LINUX_SIGBUS: + case LINUX_SIGILL: + case LINUX_SIGFPE: + case LINUX_SIGSEGV: + lsi->lsi_addr = PTROUT(ksi->ksi_addr); + break; + default: + /* XXX SI_TIMER etc... */ + lsi->lsi_pid = ksi->ksi_pid; + lsi->lsi_uid = ksi->ksi_uid; + break; + } + if (sig >= LINUX_SIGRTMIN) { + lsi->lsi_int = ksi->ksi_info.si_value.sival_int; + lsi->lsi_ptr = PTROUT(ksi->ksi_info.si_value.sival_ptr); + } +} diff --git a/sys/compat/linux/linux_signal.h b/sys/compat/linux/linux_signal.h new file mode 100644 index 0000000..426cf43 --- /dev/null +++ b/sys/compat/linux/linux_signal.h @@ -0,0 +1,49 @@ +/*- + * 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. + * 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_SIGNAL_H_ +#define _LINUX_SIGNAL_H_ + +#define LINUX_SI_TKILL -6; + +extern int bsd_to_linux_signal[]; +extern int linux_to_bsd_signal[]; + +void linux_to_bsd_sigset(l_sigset_t *, sigset_t *); +void bsd_to_linux_sigset(sigset_t *, l_sigset_t *); +int linux_do_sigaction(struct thread *, int, l_sigaction_t *, l_sigaction_t *); +void ksiginfo_to_lsiginfo(ksiginfo_t *ksi, l_siginfo_t *lsi, l_int sig); + +#define LINUX_SIG_VALID(sig) ((sig) <= LINUX_NSIG && (sig) > 0) + +#define BSD_TO_LINUX_SIGNAL(sig) \ + (((sig) <= LINUX_SIGTBLSZ) ? bsd_to_linux_signal[_SIG_IDX(sig)] : 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 0000000..36b23ac --- /dev/null +++ b/sys/compat/linux/linux_socket.c @@ -0,0 +1,1709 @@ +/*- + * 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 + * 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$"); + +/* 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/capability.h> +#include <sys/fcntl.h> +#include <sys/file.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/syslog.h> +#include <sys/un.h> + +#include <net/if.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> +#include <netinet6/in6_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_socket.h> +#include <compat/linux/linux_util.h> + +static int linux_to_bsd_domain(int); + +/* + * Reads a linux sockaddr and does any necessary translation. + * Linux sockaddrs don't have a length field, only a family. + * Copy the osockaddr structure pointed to by osa to kernel, adjust + * family and convert to sockaddr. + */ +static int +linux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int salen) +{ + struct sockaddr *sa; + struct osockaddr *kosa; +#ifdef INET6 + struct sockaddr_in6 *sin6; + int oldv6size; +#endif + char *name; + int bdom, error, hdrlen, namelen; + + if (salen < 2 || salen > UCHAR_MAX || !osa) + return (EINVAL); + +#ifdef INET6 + oldv6size = 0; + /* + * 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 = 1; + } +#endif + + kosa = malloc(salen, M_SONAME, M_WAITOK); + + if ((error = copyin(osa, kosa, salen))) + 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 { + log(LOG_DEBUG, + "obsolete pre-RFC2553 sockaddr_in6 rejected\n"); + 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; + return (0); + +out: + free(kosa, M_SONAME); + return (error); +} + +static 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); +} + +static 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); +} + +static int +linux_to_bsd_sockopt_level(int level) +{ + + switch (level) { + case LINUX_SOL_SOCKET: + return (SOL_SOCKET); + } + return (level); +} + +static int +bsd_to_linux_sockopt_level(int level) +{ + + switch (level) { + case SOL_SOCKET: + return (LINUX_SOL_SOCKET); + } + return (level); +} + +static int +linux_to_bsd_ip_sockopt(int opt) +{ + + switch (opt) { + case LINUX_IP_TOS: + return (IP_TOS); + case LINUX_IP_TTL: + return (IP_TTL); + case LINUX_IP_OPTIONS: + return (IP_OPTIONS); + 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_HDRINCL: + return (IP_HDRINCL); + } + 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: + return (SO_SNDBUF); + case LINUX_SO_RCVBUF: + 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_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); + } + 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_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 0 /* not handled */ + if (flags & LINUX_MSG_PROXY) + ; + if (flags & LINUX_MSG_FIN) + ; + if (flags & LINUX_MSG_SYN) + ; + if (flags & LINUX_MSG_CONFIRM) + ; + if (flags & LINUX_MSG_RST) + ; + if (flags & LINUX_MSG_ERRQUEUE) + ; +#endif + return ret_flags; +} + +/* +* If bsd_to_linux_sockaddr() or linux_to_bsd_sockaddr() faults, then the +* native syscall will fault. Thus, we don't really need to check the +* return values for these functions. +*/ + +static int +bsd_to_linux_sockaddr(struct sockaddr *arg) +{ + struct sockaddr sa; + size_t sa_len = sizeof(struct sockaddr); + int error; + + if ((error = copyin(arg, &sa, sa_len))) + return (error); + + *(u_short *)&sa = sa.sa_family; + + error = copyout(&sa, arg, sa_len); + + return (error); +} + +static int +linux_to_bsd_sockaddr(struct sockaddr *arg, int len) +{ + struct sockaddr sa; + size_t sa_len = sizeof(struct sockaddr); + int error; + + if ((error = copyin(arg, &sa, sa_len))) + return (error); + + sa.sa_family = *(sa_family_t *)&sa; + sa.sa_len = len; + + error = copyout(&sa, arg, sa_len); + + return (error); +} + + +static int +linux_sa_put(struct osockaddr *osa) +{ + struct osockaddr sa; + int error, bdom; + + /* + * Only read/write the osockaddr family part, the rest is + * not changed. + */ + error = copyin(osa, &sa, sizeof(sa.sa_family)); + if (error) + return (error); + + bdom = bsd_to_linux_domain(sa.sa_family); + if (bdom == -1) + return (EINVAL); + + sa.sa_family = bdom; + error = copyout(&sa, osa, sizeof(sa.sa_family)); + if (error) + return (error); + + return (0); +} + +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); + } + 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(struct thread *td, int s, int flags) +{ + int error; + + if (flags & LINUX_SOCK_NONBLOCK) { + error = kern_fcntl(td, s, F_SETFL, O_NONBLOCK); + if (error) + return (error); + } + if (flags & LINUX_SOCK_CLOEXEC) { + error = kern_fcntl(td, s, F_SETFD, FD_CLOEXEC); + if (error) + return (error); + } + return (0); +} + +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; + + if (mp->msg_name != NULL) { + error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen); + if (error) + 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, size_val; + + size_val = sizeof(optval); + error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL, + &optval, UIO_SYSSPACE, &size_val); + if (error) + return (error); + + return (optval == 0); +} + +struct linux_sendto_args { + int s; + l_uintptr_t msg; + int len; + int flags; + l_uintptr_t to; + int tolen; +}; + +/* + * 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_TEMP, 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_TEMP); + return (error); +} + +struct linux_socket_args { + int domain; + int type; + int protocol; +}; + +static int +linux_socket(struct thread *td, struct linux_socket_args *args) +{ + struct socket_args /* { + int domain; + int type; + int protocol; + } */ bsd_args; + int retval_socket, socket_flags; + + bsd_args.protocol = args->protocol; + socket_flags = args->type & ~LINUX_SOCK_TYPE_MASK; + if (socket_flags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK)) + return (EINVAL); + bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK; + if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX) + return (EINVAL); + bsd_args.domain = linux_to_bsd_domain(args->domain); + if (bsd_args.domain == -1) + return (EAFNOSUPPORT); + + retval_socket = sys_socket(td, &bsd_args); + if (retval_socket) + return (retval_socket); + + retval_socket = linux_set_socket_flags(td, td->td_retval[0], + socket_flags); + if (retval_socket) { + (void)kern_close(td, td->td_retval[0]); + goto out; + } + + if (bsd_args.type == SOCK_RAW + && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0) + && bsd_args.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 (bsd_args.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 + +out: + return (retval_socket); +} + +struct linux_bind_args { + int s; + l_uintptr_t name; + int namelen; +}; + +static int +linux_bind(struct thread *td, struct linux_bind_args *args) +{ + struct sockaddr *sa; + int error; + + error = linux_getsockaddr(&sa, PTRIN(args->name), + args->namelen); + if (error) + return (error); + + error = kern_bind(td, args->s, sa); + free(sa, M_SONAME); + if (error == EADDRNOTAVAIL && args->namelen != sizeof(struct sockaddr_in)) + return (EINVAL); + return (error); +} + +struct linux_connect_args { + int s; + l_uintptr_t name; + int namelen; +}; +int linux_connect(struct thread *, struct linux_connect_args *); + +int +linux_connect(struct thread *td, struct linux_connect_args *args) +{ + struct socket *so; + struct sockaddr *sa; + u_int fflag; + int error; + + error = linux_getsockaddr(&sa, (struct osockaddr *)PTRIN(args->name), + args->namelen); + if (error) + return (error); + + error = kern_connect(td, 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. + * + * XXXRW: Instead of using fgetsock(), check that it is a + * socket and use the file descriptor reference instead of + * creating a new one. + */ + error = fgetsock(td, args->s, CAP_CONNECT, &so, &fflag); + if (error == 0) { + error = EISCONN; + if (fflag & FNONBLOCK) { + SOCK_LOCK(so); + if (so->so_emuldata == 0) + error = so->so_error; + so->so_emuldata = (void *)1; + SOCK_UNLOCK(so); + } + fputsock(so); + } + return (error); +} + +struct linux_listen_args { + int s; + int backlog; +}; + +static int +linux_listen(struct thread *td, struct linux_listen_args *args) +{ + struct listen_args /* { + int s; + int backlog; + } */ bsd_args; + + bsd_args.s = args->s; + bsd_args.backlog = args->backlog; + return (sys_listen(td, &bsd_args)); +} + +static int +linux_accept_common(struct thread *td, int s, l_uintptr_t addr, + l_uintptr_t namelen, int flags) +{ + struct accept_args /* { + int s; + struct sockaddr * __restrict name; + socklen_t * __restrict anamelen; + } */ bsd_args; + int error; + + if (flags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK)) + return (EINVAL); + + bsd_args.s = s; + /* XXX: */ + bsd_args.name = (struct sockaddr * __restrict)PTRIN(addr); + bsd_args.anamelen = PTRIN(namelen);/* XXX */ + error = sys_accept(td, &bsd_args); + bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.name); + if (error) { + if (error == EFAULT && namelen != sizeof(struct sockaddr_in)) + return (EINVAL); + return (error); + } + + /* + * linux appears not to copy flags from the parent socket to the + * accepted one, so we must clear the flags in the new descriptor + * and apply the requested flags. + */ + error = kern_fcntl(td, td->td_retval[0], F_SETFL, 0); + if (error) + goto out; + error = linux_set_socket_flags(td, td->td_retval[0], flags); + if (error) + goto out; + if (addr) + error = linux_sa_put(PTRIN(addr)); + +out: + if (error) { + (void)kern_close(td, td->td_retval[0]); + td->td_retval[0] = 0; + } + return (error); +} + +struct linux_accept_args { + int s; + l_uintptr_t addr; + l_uintptr_t namelen; +}; + +static int +linux_accept(struct thread *td, struct linux_accept_args *args) +{ + + return (linux_accept_common(td, args->s, args->addr, + args->namelen, 0)); +} + +struct linux_accept4_args { + int s; + l_uintptr_t addr; + l_uintptr_t namelen; + int flags; +}; + +static int +linux_accept4(struct thread *td, struct linux_accept4_args *args) +{ + + return (linux_accept_common(td, args->s, args->addr, + args->namelen, args->flags)); +} + +struct linux_getsockname_args { + int s; + l_uintptr_t addr; + l_uintptr_t namelen; +}; + +static int +linux_getsockname(struct thread *td, struct linux_getsockname_args *args) +{ + struct getsockname_args /* { + int fdes; + struct sockaddr * __restrict asa; + socklen_t * __restrict alen; + } */ bsd_args; + int error; + + bsd_args.fdes = args->s; + /* XXX: */ + bsd_args.asa = (struct sockaddr * __restrict)PTRIN(args->addr); + bsd_args.alen = PTRIN(args->namelen); /* XXX */ + error = sys_getsockname(td, &bsd_args); + bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa); + if (error) + return (error); + error = linux_sa_put(PTRIN(args->addr)); + if (error) + return (error); + return (0); +} + +struct linux_getpeername_args { + int s; + l_uintptr_t addr; + l_uintptr_t namelen; +}; + +static int +linux_getpeername(struct thread *td, struct linux_getpeername_args *args) +{ + struct getpeername_args /* { + int fdes; + caddr_t asa; + int *alen; + } */ bsd_args; + int error; + + bsd_args.fdes = args->s; + bsd_args.asa = (struct sockaddr *)PTRIN(args->addr); + bsd_args.alen = (int *)PTRIN(args->namelen); + error = sys_getpeername(td, &bsd_args); + bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa); + if (error) + return (error); + error = linux_sa_put(PTRIN(args->addr)); + if (error) + return (error); + return (0); +} + +struct linux_socketpair_args { + int domain; + int type; + int protocol; + l_uintptr_t rsv; +}; + +static int +linux_socketpair(struct thread *td, struct linux_socketpair_args *args) +{ + struct socketpair_args /* { + int domain; + int type; + int protocol; + int *rsv; + } */ bsd_args; + int error, socket_flags; + int sv[2]; + + bsd_args.domain = linux_to_bsd_domain(args->domain); + if (bsd_args.domain != PF_LOCAL) + return (EAFNOSUPPORT); + + socket_flags = args->type & ~LINUX_SOCK_TYPE_MASK; + if (socket_flags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK)) + return (EINVAL); + bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK; + if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX) + return (EINVAL); + + 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); + else + bsd_args.protocol = 0; + bsd_args.rsv = (int *)PTRIN(args->rsv); + error = kern_socketpair(td, bsd_args.domain, bsd_args.type, + bsd_args.protocol, sv); + if (error) + return (error); + error = linux_set_socket_flags(td, sv[0], socket_flags); + if (error) + goto out; + error = linux_set_socket_flags(td, sv[1], socket_flags); + if (error) + goto out; + + error = copyout(sv, bsd_args.rsv, 2 * sizeof(int)); + +out: + if (error) { + (void)kern_close(td, sv[0]); + (void)kern_close(td, sv[1]); + } + return (error); +} + +struct linux_send_args { + int s; + l_uintptr_t msg; + int len; + int 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; + + bsd_args.s = args->s; + bsd_args.buf = (caddr_t)PTRIN(args->msg); + bsd_args.len = args->len; + bsd_args.flags = args->flags; + bsd_args.to = NULL; + bsd_args.tolen = 0; + return sys_sendto(td, &bsd_args); +} + +struct linux_recv_args { + int s; + l_uintptr_t msg; + int len; + int 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)); +} + +static int +linux_sendto(struct thread *td, struct linux_sendto_args *args) +{ + struct msghdr msg; + struct iovec aiov; + int error; + + 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; + error = linux_sendit(td, args->s, &msg, args->flags, NULL, + UIO_USERSPACE); + return (error); +} + +struct linux_recvfrom_args { + int s; + l_uintptr_t buf; + int len; + int flags; + l_uintptr_t from; + l_uintptr_t fromlen; +}; + +static int +linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args) +{ + struct recvfrom_args /* { + int s; + caddr_t buf; + size_t len; + int flags; + struct sockaddr * __restrict from; + socklen_t * __restrict fromlenaddr; + } */ bsd_args; + size_t len; + int error; + + if ((error = copyin(PTRIN(args->fromlen), &len, sizeof(size_t)))) + return (error); + + bsd_args.s = args->s; + bsd_args.buf = PTRIN(args->buf); + bsd_args.len = args->len; + bsd_args.flags = linux_to_bsd_msg_flags(args->flags); + /* XXX: */ + bsd_args.from = (struct sockaddr * __restrict)PTRIN(args->from); + bsd_args.fromlenaddr = PTRIN(args->fromlen);/* XXX */ + + linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.from, len); + error = sys_recvfrom(td, &bsd_args); + bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.from); + + if (error) + return (error); + if (args->from) { + error = linux_sa_put((struct osockaddr *) + PTRIN(args->from)); + if (error) + return (error); + } + return (0); +} + +struct linux_sendmsg_args { + int s; + l_uintptr_t msg; + int flags; +}; + +static int +linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args) +{ + struct cmsghdr *cmsg; + struct cmsgcred cmcred; + struct mbuf *control; + struct msghdr msg; + struct l_cmsghdr linux_cmsg; + struct l_cmsghdr *ptr_cmsg; + struct l_msghdr linux_msg; + struct iovec *iov; + socklen_t datalen; + struct sockaddr *sa; + sa_family_t sa_family; + void *data; + int error; + + error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg)); + if (error) + 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_msg.msg_control) != NULL && linux_msg.msg_controllen == 0) + linux_msg.msg_control = PTROUT(NULL); + + error = linux_to_bsd_msghdr(&msg, &linux_msg); + if (error) + 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) + return (error); + + control = NULL; + cmsg = NULL; + + if ((ptr_cmsg = LINUX_CMSG_FIRSTHDR(&linux_msg)) != NULL) { + error = kern_getsockname(td, args->s, &sa, &datalen); + if (error) + goto bad; + sa_family = sa->sa_family; + free(sa, M_SONAME); + + error = ENOBUFS; + cmsg = malloc(CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO); + control = m_get(M_WAITOK, MT_CONTROL); + if (control == NULL) + goto bad; + + do { + error = copyin(ptr_cmsg, &linux_cmsg, + sizeof(struct l_cmsghdr)); + if (error) + goto bad; + + error = EINVAL; + if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr)) + goto bad; + + /* + * Now we support only SCM_RIGHTS and SCM_CRED, + * so return EINVAL in any other cmsg_type + */ + 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) + 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) + continue; + + data = LINUX_CMSG_DATA(ptr_cmsg); + datalen = linux_cmsg.cmsg_len - L_CMSG_HDRSZ; + + switch (cmsg->cmsg_type) + { + case SCM_RIGHTS: + break; + + case SCM_CREDS: + data = &cmcred; + datalen = sizeof(cmcred); + + /* + * The lower levels will fill in the structure + */ + bzero(data, datalen); + break; + } + + cmsg->cmsg_len = CMSG_LEN(datalen); + + error = ENOBUFS; + if (!m_append(control, CMSG_HDRSZ, (c_caddr_t)cmsg)) + goto bad; + if (!m_append(control, datalen, (c_caddr_t)data)) + goto bad; + } while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&linux_msg, ptr_cmsg))); + + if (m_length(control, NULL) == 0) { + m_freem(control); + control = NULL; + } + } + + msg.msg_iov = iov; + msg.msg_flags = 0; + error = linux_sendit(td, args->s, &msg, args->flags, control, + UIO_USERSPACE); + +bad: + free(iov, M_IOV); + if (cmsg) + free(cmsg, M_TEMP); + return (error); +} + +struct linux_recvmsg_args { + int s; + l_uintptr_t msg; + int flags; +}; + +static int +linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args) +{ + struct cmsghdr *cm; + struct cmsgcred *cmcred; + struct msghdr msg; + struct l_cmsghdr *linux_cmsg = NULL; + struct l_ucred linux_ucred; + socklen_t datalen, outlen; + struct l_msghdr linux_msg; + struct iovec *iov, *uiov; + struct mbuf *control = NULL; + struct mbuf **controlp; + caddr_t outbuf; + void *data; + int error, i, fd, fds, *fdp; + + error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg)); + if (error) + return (error); + + error = linux_to_bsd_msghdr(&msg, &linux_msg); + if (error) + 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) + return (error); + + if (msg.msg_name) { + error = linux_to_bsd_sockaddr((struct sockaddr *)msg.msg_name, + msg.msg_namelen); + if (error) + goto bad; + } + + uiov = msg.msg_iov; + msg.msg_iov = iov; + controlp = (msg.msg_control != NULL) ? &control : NULL; + error = kern_recvit(td, args->s, &msg, UIO_USERSPACE, controlp); + msg.msg_iov = uiov; + if (error) + goto bad; + + error = bsd_to_linux_msghdr(&msg, &linux_msg); + if (error) + goto bad; + + if (linux_msg.msg_name) { + error = bsd_to_linux_sockaddr((struct sockaddr *) + PTRIN(linux_msg.msg_name)); + if (error) + goto bad; + } + if (linux_msg.msg_name && linux_msg.msg_namelen > 2) { + error = linux_sa_put(PTRIN(linux_msg.msg_name)); + if (error) + goto bad; + } + + outbuf = PTRIN(linux_msg.msg_control); + outlen = 0; + + if (control) { + linux_cmsg = malloc(L_CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO); + + msg.msg_control = mtod(control, struct cmsghdr *); + msg.msg_controllen = control->m_len; + + cm = CMSG_FIRSTHDR(&msg); + + 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) + { + 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 (args->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; + } + + if (outlen + LINUX_CMSG_LEN(datalen) > + linux_msg.msg_controllen) { + if (outlen == 0) { + error = EMSGSIZE; + goto bad; + } else { + linux_msg.msg_flags |= + LINUX_MSG_CTRUNC; + goto out; + } + } + + linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen); + + error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ); + if (error) + goto bad; + outbuf += L_CMSG_HDRSZ; + + error = copyout(data, outbuf, datalen); + if (error) + goto bad; + + outbuf += LINUX_CMSG_ALIGN(datalen); + outlen += LINUX_CMSG_LEN(datalen); + + cm = CMSG_NXTHDR(&msg, cm); + } + } + +out: + linux_msg.msg_controllen = outlen; + error = copyout(&linux_msg, PTRIN(args->msg), sizeof(linux_msg)); + +bad: + free(iov, M_IOV); + m_freem(control); + free(linux_cmsg, M_TEMP); + + return (error); +} + +struct linux_shutdown_args { + int s; + int how; +}; + +static int +linux_shutdown(struct thread *td, struct linux_shutdown_args *args) +{ + struct shutdown_args /* { + int s; + int how; + } */ bsd_args; + + bsd_args.s = args->s; + bsd_args.how = args->how; + return (sys_shutdown(td, &bsd_args)); +} + +struct linux_setsockopt_args { + int s; + int level; + int optname; + l_uintptr_t optval; + int optlen; +}; + +static int +linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args) +{ + struct setsockopt_args /* { + int s; + int level; + int name; + caddr_t val; + int valsize; + } */ bsd_args; + l_timeval linux_tv; + struct timeval tv; + int error, name; + + bsd_args.s = args->s; + bsd_args.level = linux_to_bsd_sockopt_level(args->level); + switch (bsd_args.level) { + case SOL_SOCKET: + name = linux_to_bsd_so_sockopt(args->optname); + switch (name) { + case SO_RCVTIMEO: + /* FALLTHROUGH */ + case SO_SNDTIMEO: + error = copyin(PTRIN(args->optval), &linux_tv, + sizeof(linux_tv)); + if (error) + return (error); + tv.tv_sec = linux_tv.tv_sec; + tv.tv_usec = linux_tv.tv_usec; + return (kern_setsockopt(td, args->s, bsd_args.level, + name, &tv, UIO_SYSSPACE, sizeof(tv))); + /* NOTREACHED */ + break; + default: + break; + } + break; + case IPPROTO_IP: + name = linux_to_bsd_ip_sockopt(args->optname); + break; + case IPPROTO_TCP: + name = linux_to_bsd_tcp_sockopt(args->optname); + break; + default: + name = -1; + break; + } + if (name == -1) + return (ENOPROTOOPT); + + bsd_args.name = name; + bsd_args.val = PTRIN(args->optval); + bsd_args.valsize = args->optlen; + + if (name == IPV6_NEXTHOP) { + linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.val, + bsd_args.valsize); + error = sys_setsockopt(td, &bsd_args); + bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val); + } else + error = sys_setsockopt(td, &bsd_args); + + return (error); +} + +struct linux_getsockopt_args { + int s; + int level; + int optname; + l_uintptr_t optval; + l_uintptr_t optlen; +}; + +static int +linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args) +{ + struct getsockopt_args /* { + int s; + int level; + int name; + caddr_t val; + int *avalsize; + } */ bsd_args; + l_timeval linux_tv; + struct timeval tv; + socklen_t tv_len, xulen; + struct xucred xu; + struct l_ucred lxu; + int error, name; + + bsd_args.s = args->s; + bsd_args.level = linux_to_bsd_sockopt_level(args->level); + switch (bsd_args.level) { + case SOL_SOCKET: + name = linux_to_bsd_so_sockopt(args->optname); + switch (name) { + case SO_RCVTIMEO: + /* FALLTHROUGH */ + case SO_SNDTIMEO: + tv_len = sizeof(tv); + error = kern_getsockopt(td, args->s, bsd_args.level, + name, &tv, UIO_SYSSPACE, &tv_len); + if (error) + 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 */ + break; + case LOCAL_PEERCRED: + if (args->optlen != sizeof(lxu)) + return (EINVAL); + xulen = sizeof(xu); + error = kern_getsockopt(td, args->s, bsd_args.level, + name, &xu, UIO_SYSSPACE, &xulen); + if (error) + return (error); + /* + * XXX Use 0 for pid as the FreeBSD does not cache peer pid. + */ + lxu.pid = 0; + lxu.uid = xu.cr_uid; + lxu.gid = xu.cr_gid; + return (copyout(&lxu, PTRIN(args->optval), sizeof(lxu))); + /* NOTREACHED */ + break; + default: + break; + } + break; + case IPPROTO_IP: + name = linux_to_bsd_ip_sockopt(args->optname); + break; + case IPPROTO_TCP: + name = linux_to_bsd_tcp_sockopt(args->optname); + break; + default: + name = -1; + break; + } + if (name == -1) + return (EINVAL); + + bsd_args.name = name; + bsd_args.val = PTRIN(args->optval); + bsd_args.avalsize = PTRIN(args->optlen); + + if (name == IPV6_NEXTHOP) { + error = sys_getsockopt(td, &bsd_args); + bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val); + } else + error = sys_getsockopt(td, &bsd_args); + + return (error); +} + +/* Argument list sizes for linux_socketcall */ + +#define LINUX_AL(x) ((x) * sizeof(l_ulong)) + +static const unsigned char lxs_args[] = { + LINUX_AL(0) /* unused*/, LINUX_AL(3) /* socket */, + LINUX_AL(3) /* bind */, LINUX_AL(3) /* connect */, + LINUX_AL(2) /* listen */, LINUX_AL(3) /* accept */, + LINUX_AL(3) /* getsockname */, LINUX_AL(3) /* getpeername */, + LINUX_AL(4) /* socketpair */, LINUX_AL(4) /* send */, + LINUX_AL(4) /* recv */, LINUX_AL(6) /* sendto */, + LINUX_AL(6) /* recvfrom */, LINUX_AL(2) /* shutdown */, + LINUX_AL(5) /* setsockopt */, LINUX_AL(5) /* getsockopt */, + LINUX_AL(3) /* sendmsg */, LINUX_AL(3) /* recvmsg */, + LINUX_AL(4) /* accept4 */ +}; + +#define LINUX_AL_SIZE sizeof(lxs_args) / sizeof(lxs_args[0]) - 1 + +int +linux_socketcall(struct thread *td, struct linux_socketcall_args *args) +{ + l_ulong a[6]; + void *arg; + int error; + + if (args->what < LINUX_SOCKET || args->what > LINUX_AL_SIZE) + return (EINVAL); + error = copyin(PTRIN(args->args), a, lxs_args[args->what]); + if (error) + return (error); + + arg = a; + 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)); + } + + uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what); + return (ENOSYS); +} diff --git a/sys/compat/linux/linux_socket.h b/sys/compat/linux/linux_socket.h new file mode 100644 index 0000000..e6efadb --- /dev/null +++ b/sys/compat/linux/linux_socket.h @@ -0,0 +1,159 @@ +/*- + * 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_CMSG_CLOEXEC 0x40000000 + +/* Socket-level control message types */ + +#define LINUX_SCM_RIGHTS 0x01 +#define LINUX_SCM_CREDENTIALS 0x02 + +/* Ancilliary 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 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 + +/* 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; +}; + +/* 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 + +/* 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_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_TCP_NODELAY 1 +#define LINUX_TCP_MAXSEG 2 +#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 0000000..2e05c85 --- /dev/null +++ b/sys/compat/linux/linux_stats.c @@ -0,0 +1,627 @@ +/*- + * 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/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> + +#define LINUX_SHMFS_MAGIC 0x01021994 + +static void +translate_vnhook_major_minor(struct vnode *vp, struct stat *sb) +{ + int major, minor; + + if (vp->v_type == VCHR && vp->v_rdev != NULL && + linux_driver_get_major_minor(devtoname(vp->v_rdev), + &major, &minor) == 0) { + sb->st_rdev = (major << 8 | minor); + } +} + +static int +linux_kern_statat(struct thread *td, int flag, int fd, char *path, + enum uio_seg pathseg, struct stat *sbp) +{ + + return (kern_statat_vnhook(td, flag, fd, path, pathseg, sbp, + translate_vnhook_major_minor)); +} + +static int +linux_kern_stat(struct thread *td, 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, char *path, enum uio_seg pathseg, + struct stat *sbp) +{ + + return (linux_kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, path, + pathseg, sbp)); +} + +/* + * XXX: This was removed from newstat_copyout(), and almost identical + * XXX: code was in stat64_copyout(). findcdev() needs to be replaced + * XXX: with something that does lookup and locking properly. + * XXX: When somebody fixes this: please try to avoid duplicating it. + */ +#if 0 +static void +disk_foo(struct somestat *tbuf) +{ + struct cdevsw *cdevsw; + struct cdev *dev; + + /* Lie about disk drives which are character devices + * in FreeBSD but block devices under Linux. + */ + if (S_ISCHR(tbuf.st_mode) && + (dev = findcdev(buf->st_rdev)) != NULL) { + cdevsw = dev_refthread(dev); + if (cdevsw != NULL) { + if (cdevsw->d_flags & D_DISK) { + tbuf.st_mode &= ~S_IFMT; + tbuf.st_mode |= S_IFBLK; + + /* XXX this may not be quite right */ + /* Map major number to 0 */ + tbuf.st_dev = minor(buf->st_dev) & 0xf; + tbuf.st_rdev = buf->st_rdev & 0xff; + } + dev_relthread(dev); + } + } + +} +#endif + +static void +translate_fd_major_minor(struct thread *td, int fd, struct stat *buf) +{ + struct file *fp; + struct vnode *vp; + int major, minor; + + /* + * No capability rights required here. + */ + if ((!S_ISCHR(buf->st_mode) && !S_ISBLK(buf->st_mode)) || + fget(td, fd, 0, &fp) != 0) + return; + vp = fp->f_vnode; + if (vp != NULL && vp->v_rdev != NULL && + linux_driver_get_major_minor(devtoname(vp->v_rdev), + &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); +} + +static int +newstat_copyout(struct stat *buf, void *ubuf) +{ + struct l_newstat tbuf; + + bzero(&tbuf, sizeof(tbuf)); + tbuf.st_dev = minor(buf->st_dev) | (major(buf->st_dev) << 8); + 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))); +} + +int +linux_newstat(struct thread *td, struct linux_newstat_args *args) +{ + struct stat buf; + char *path; + int error; + + LCONVPATHEXIST(td, args->path, &path); + +#ifdef DEBUG + if (ldebug(newstat)) + printf(ARGS(newstat, "%s, *"), path); +#endif + + 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; + + LCONVPATHEXIST(td, args->path, &path); + +#ifdef DEBUG + if (ldebug(newlstat)) + printf(ARGS(newlstat, "%s, *"), path); +#endif + + error = linux_kern_lstat(td, path, UIO_SYSSPACE, &sb); + LFREEPATH(path); + if (error) + return (error); + return (newstat_copyout(&sb, args->buf)); +} + +int +linux_newfstat(struct thread *td, struct linux_newfstat_args *args) +{ + struct stat buf; + int error; + +#ifdef DEBUG + if (ldebug(newfstat)) + printf(ARGS(newfstat, "%d, *"), args->fd); +#endif + + 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); +} + +static int +stat_copyout(struct stat *buf, void *ubuf) +{ + struct l_stat lbuf; + + bzero(&lbuf, sizeof(lbuf)); + lbuf.st_dev = 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; + if (buf->st_size < (quad_t)1 << 32) + lbuf.st_size = buf->st_size; + else + lbuf.st_size = -2; + 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; + + LCONVPATHEXIST(td, args->path, &path); + +#ifdef DEBUG + if (ldebug(stat)) + printf(ARGS(stat, "%s, *"), path); +#endif + error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf); + if (error) { + LFREEPATH(path); + return (error); + } + LFREEPATH(path); + return(stat_copyout(&buf, args->up)); +} + +int +linux_lstat(struct thread *td, struct linux_lstat_args *args) +{ + struct stat buf; + char *path; + int error; + + LCONVPATHEXIST(td, args->path, &path); + +#ifdef DEBUG + if (ldebug(lstat)) + printf(ARGS(lstat, "%s, *"), path); +#endif + error = linux_kern_lstat(td, path, UIO_SYSSPACE, &buf); + if (error) { + LFREEPATH(path); + return (error); + } + LFREEPATH(path); + return(stat_copyout(&buf, args->up)); +} + +/* XXX - All fields of type l_int are defined as l_long on i386 */ +struct l_statfs { + l_int f_type; + l_int f_bsize; + l_int f_blocks; + l_int f_bfree; + l_int f_bavail; + l_int f_files; + l_int f_ffree; + l_fsid_t f_fsid; + l_int f_namelen; + l_int f_spare[6]; +}; + +#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_DEVFS_SUPER_MAGIC 0x1373L + +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}, + {"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}, + {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 void +bsd_to_linux_statfs(struct statfs *bsd_statfs, struct l_statfs *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; +} + +int +linux_statfs(struct thread *td, struct linux_statfs_args *args) +{ + struct l_statfs linux_statfs; + struct statfs bsd_statfs; + char *path; + int error, dev_shm; + + LCONVPATHEXIST(td, args->path, &path); + +#ifdef DEBUG + if (ldebug(statfs)) + printf(ARGS(statfs, "%s, *"), path); +#endif + dev_shm = 0; + error = kern_statfs(td, path, UIO_SYSSPACE, &bsd_statfs); + if (strncmp(path, "/dev/shm", sizeof("/dev/shm") - 1) == 0) + dev_shm = (path[8] == '\0' + || (path[8] == '/' && path[9] == '\0')); + LFREEPATH(path); + if (error) + return (error); + bsd_to_linux_statfs(&bsd_statfs, &linux_statfs); + if (dev_shm) + linux_statfs.f_type = LINUX_SHMFS_MAGIC; + return copyout(&linux_statfs, args->buf, sizeof(linux_statfs)); +} + +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; +} + +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; + + LCONVPATHEXIST(td, args->path, &path); + +#ifdef DEBUG + if (ldebug(statfs64)) + printf(ARGS(statfs64, "%s, *"), path); +#endif + error = kern_statfs(td, path, UIO_SYSSPACE, &bsd_statfs); + LFREEPATH(path); + if (error) + return (error); + bsd_to_linux_statfs64(&bsd_statfs, &linux_statfs); + return copyout(&linux_statfs, args->buf, sizeof(linux_statfs)); +} + +int +linux_fstatfs(struct thread *td, struct linux_fstatfs_args *args) +{ + struct l_statfs linux_statfs; + struct statfs bsd_statfs; + int error; + +#ifdef DEBUG + if (ldebug(fstatfs)) + printf(ARGS(fstatfs, "%d, *"), args->fd); +#endif + error = kern_fstatfs(td, args->fd, &bsd_statfs); + if (error) + return error; + bsd_to_linux_statfs(&bsd_statfs, &linux_statfs); + 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]; +}; + +int +linux_ustat(struct thread *td, struct linux_ustat_args *args) +{ +#ifdef DEBUG + if (ldebug(ustat)) + printf(ARGS(ustat, "%d, *"), args->dev); +#endif + + return (EOPNOTSUPP); +} + +#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 = minor(buf->st_dev) | (major(buf->st_dev) << 8); + 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; + + LCONVPATHEXIST(td, args->filename, &filename); + +#ifdef DEBUG + if (ldebug(stat64)) + printf(ARGS(stat64, "%s, *"), filename); +#endif + + 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; + + LCONVPATHEXIST(td, args->filename, &filename); + +#ifdef DEBUG + if (ldebug(lstat64)) + printf(ARGS(lstat64, "%s, *"), args->filename); +#endif + + 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; + +#ifdef DEBUG + if (ldebug(fstat64)) + printf(ARGS(fstat64, "%d, *"), args->fd); +#endif + + 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; + LCONVPATHEXIST_AT(td, args->pathname, &path, dfd); + +#ifdef DEBUG + if (ldebug(fstatat64)) + printf(ARGS(fstatat64, "%i, %s, %i"), args->dfd, path, args->flag); +#endif + + error = linux_kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf); + if (!error) + error = stat64_copyout(&buf, args->statbuf); + LFREEPATH(path); + + return (error); +} + +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ diff --git a/sys/compat/linux/linux_sysctl.c b/sys/compat/linux/linux_sysctl.c new file mode 100644 index 0000000..decd8f8 --- /dev/null +++ b/sys/compat/linux/linux_sysctl.c @@ -0,0 +1,194 @@ +/*- + * 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 + * 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 "opt_kdtrace.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"); + +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_TEMP, 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_TEMP); + 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_TEMP); + 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_TEMP); + + LIN_SDT_PROBE1(sysctl, linux_sysctl, return, ENOTDIR); + return (ENOTDIR); +} diff --git a/sys/compat/linux/linux_sysproto.h b/sys/compat/linux/linux_sysproto.h new file mode 100644 index 0000000..69f1577 --- /dev/null +++ b/sys/compat/linux/linux_sysproto.h @@ -0,0 +1,36 @@ +/*- + * 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 0000000..e03af00 --- /dev/null +++ b/sys/compat/linux/linux_time.c @@ -0,0 +1,417 @@ +/* $NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $ */ + +/*- + * 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 "opt_kdtrace.h" + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/ucred.h> +#include <sys/mount.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> + +/* 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, nanosleep_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, nanosleep_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"); + +static void native_to_linux_timespec(struct l_timespec *, + struct timespec *); +static int linux_to_native_timespec(struct timespec *, + struct l_timespec *); +static int linux_to_native_clockid(clockid_t *, clockid_t); + +static void +native_to_linux_timespec(struct l_timespec *ltp, struct timespec *ntp) +{ + + LIN_SDT_PROBE2(time, native_to_linux_timespec, entry, ltp, ntp); + + ltp->tv_sec = ntp->tv_sec; + ltp->tv_nsec = ntp->tv_nsec; + + LIN_SDT_PROBE0(time, native_to_linux_timespec, return); +} + +static 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 > (l_long)999999999L) { + 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); +} + +static int +linux_to_native_clockid(clockid_t *n, clockid_t l) +{ + + LIN_SDT_PROBE2(time, linux_to_native_clockid, entry, n, l); + + switch (l) { + case LINUX_CLOCK_REALTIME: + *n = CLOCK_REALTIME; + break; + case LINUX_CLOCK_MONOTONIC: + *n = CLOCK_MONOTONIC; + break; + case LINUX_CLOCK_PROCESS_CPUTIME_ID: + case LINUX_CLOCK_THREAD_CPUTIME_ID: + case LINUX_CLOCK_REALTIME_HR: + case LINUX_CLOCK_MONOTONIC_HR: + LIN_SDT_PROBE1(time, linux_to_native_clockid, + unsupported_clockid, l); + LIN_SDT_PROBE1(time, linux_to_native_clockid, return, EINVAL); + return (EINVAL); + break; + default: + LIN_SDT_PROBE1(time, linux_to_native_clockid, + unknown_clockid, l); + LIN_SDT_PROBE1(time, linux_to_native_clockid, return, EINVAL); + return (EINVAL); + break; + } + + LIN_SDT_PROBE1(time, linux_to_native_clockid, return, 0); + return (0); +} + +int +linux_clock_gettime(struct thread *td, struct linux_clock_gettime_args *args) +{ + struct l_timespec lts; + int error; + clockid_t nwhich = 0; /* XXX: GCC */ + struct timespec tp; + + LIN_SDT_PROBE2(time, linux_clock_gettime, entry, args->which, args->tp); + + error = linux_to_native_clockid(&nwhich, args->which); + if (error != 0) { + LIN_SDT_PROBE1(time, linux_clock_gettime, conversion_error, + error); + LIN_SDT_PROBE1(time, linux_clock_gettime, return, error); + return (error); + } + error = kern_clock_gettime(td, nwhich, &tp); + if (error != 0) { + LIN_SDT_PROBE1(time, linux_clock_gettime, gettime_error, error); + LIN_SDT_PROBE1(time, linux_clock_gettime, return, error); + return (error); + } + native_to_linux_timespec(<s, &tp); + + error = copyout(<s, 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 = 0; /* XXX: GCC */ + + LIN_SDT_PROBE2(time, linux_clock_settime, entry, args->which, args->tp); + + error = linux_to_native_clockid(&nwhich, args->which); + 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 = copyin(args->tp, <s, 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, <s); + 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 timespec ts; + struct l_timespec lts; + int error; + clockid_t nwhich = 0; /* XXX: GCC */ + + LIN_SDT_PROBE2(time, linux_clock_getres, entry, args->which, args->tp); + + if (args->tp == NULL) { + LIN_SDT_PROBE0(time, linux_clock_getres, nullcall); + LIN_SDT_PROBE1(time, linux_clock_getres, return, 0); + return (0); + } + + error = linux_to_native_clockid(&nwhich, args->which); + if (error != 0) { + LIN_SDT_PROBE1(time, linux_clock_getres, conversion_error, + error); + LIN_SDT_PROBE1(time, linux_clock_getres, return, error); + return (error); + } + 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); + } + native_to_linux_timespec(<s, &ts); + + error = copyout(<s, 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; + + 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 != 0) { + LIN_SDT_PROBE1(time, linux_nanosleep, nanosleep_error, error); + LIN_SDT_PROBE1(time, linux_nanosleep, return, error); + return (error); + } + + if (args->rmtp != NULL) { + native_to_linux_timespec(&lrmts, rmtp); + error = copyout(&lrmts, args->rmtp, sizeof(lrmts)); + if (error != 0) { + LIN_SDT_PROBE1(time, linux_nanosleep, copyout_error, + error); + LIN_SDT_PROBE1(time, linux_nanosleep, return, error); + return (error); + } + } + + LIN_SDT_PROBE1(time, linux_nanosleep, return, 0); + return (0); +} + +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; + + LIN_SDT_PROBE4(time, linux_clock_nanosleep, entry, args->which, + args->flags, args->rqtp, args->rmtp); + + if (args->flags != 0) { + /* XXX deal with TIMER_ABSTIME */ + LIN_SDT_PROBE1(time, linux_clock_nanosleep, unsupported_flags, + args->flags); + LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, EINVAL); + return (EINVAL); /* XXX deal with TIMER_ABSTIME */ + } + + if (args->which != LINUX_CLOCK_REALTIME) { + LIN_SDT_PROBE1(time, linux_clock_nanosleep, unsupported_clockid, + args->which); + LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, EINVAL); + return (EINVAL); + } + + 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_nanosleep(td, &rqts, rmtp); + if (error != 0) { + LIN_SDT_PROBE1(time, linux_clock_nanosleep, nanosleep_error, + error); + LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error); + return (error); + } + + if (args->rmtp != NULL) { + native_to_linux_timespec(&lrmts, rmtp); + error = copyout(&lrmts, args->rmtp, sizeof lrmts ); + if (error != 0) { + LIN_SDT_PROBE1(time, linux_clock_nanosleep, + copyout_error, error); + LIN_SDT_PROBE1(time, linux_nanosleep, return, error); + return (error); + } + } + + LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, 0); + return (0); +} diff --git a/sys/compat/linux/linux_uid16.c b/sys/compat/linux/linux_uid16.c new file mode 100644 index 0000000..b66fb5c --- /dev/null +++ b/sys/compat/linux/linux_uid16.c @@ -0,0 +1,441 @@ +/*- + * 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 "opt_kdtrace.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_git16_t", "l_git16_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; + + 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_chown(td, path, UIO_SYSSPACE, CAST_NOCHG(args->uid), + CAST_NOCHG(args->gid)); + 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; + + 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_lchown(td, path, UIO_SYSSPACE, CAST_NOCHG(args->uid), + CAST_NOCHG(args->gid)); + 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_TEMP, 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_TEMP); + 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)) != 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); + p->p_ucred = newcred; + PROC_UNLOCK(p); + crfree(oldcred); + error = 0; +out: + free(linux_gidset, M_TEMP); + + 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_TEMP, 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_TEMP); + 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); +} + +/* + * The FreeBSD native getgid(2) and getuid(2) also modify td->td_retval[1] + * when COMPAT_43 is defined. This clobbers registers that are assumed to + * be preserved. The following lightweight syscalls fixes this. See also + * linux_getpid(2), linux_getgid(2) and linux_getuid(2) in linux_misc.c + * + * linux_getgid16() - MP SAFE + * linux_getuid16() - MP SAFE + */ + +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 0000000..76c210c --- /dev/null +++ b/sys/compat/linux/linux_util.c @@ -0,0 +1,333 @@ +/*- + * 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 "opt_compat.h" +#include "opt_kdtrace.h" + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/fcntl.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/systm.h> +#include <sys/vnode.h> + +#include <machine/stdarg.h> + +#include <compat/linux/linux_util.h> +#ifdef COMPAT_LINUX32 +#include <machine/../linux32/linux.h> +#else +#include <machine/../linux/linux.h> +#endif + +#include <compat/linux/linux_dtrace.h> + +const char linux_emul_path[] = "/compat/linux"; + +/* DTrace init */ +LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); + +/** + * DTrace probes in this module. + */ +LIN_SDT_PROBE_DEFINE5(util, linux_emul_convpath, entry, "const char *", + "enum uio_seg", "char **", "int", "int"); +LIN_SDT_PROBE_DEFINE1(util, linux_emul_convpath, return, "int"); +LIN_SDT_PROBE_DEFINE1(util, linux_msg, entry, "const char *"); +LIN_SDT_PROBE_DEFINE0(util, linux_msg, return); +LIN_SDT_PROBE_DEFINE2(util, linux_driver_get_name_dev, entry, "device_t", + "const char *"); +LIN_SDT_PROBE_DEFINE0(util, linux_driver_get_name_dev, nullcall); +LIN_SDT_PROBE_DEFINE1(util, linux_driver_get_name_dev, return, "char *"); +LIN_SDT_PROBE_DEFINE3(util, linux_driver_get_major_minor, entry, "char *", + "int *", "int *"); +LIN_SDT_PROBE_DEFINE0(util, linux_driver_get_major_minor, nullcall); +LIN_SDT_PROBE_DEFINE1(util, linux_driver_get_major_minor, notfound, "char *"); +LIN_SDT_PROBE_DEFINE3(util, linux_driver_get_major_minor, return, "int", + "int", "int"); +LIN_SDT_PROBE_DEFINE0(util, linux_get_char_devices, entry); +LIN_SDT_PROBE_DEFINE1(util, linux_get_char_devices, return, "char *"); +LIN_SDT_PROBE_DEFINE1(util, linux_free_get_char_devices, entry, "char *"); +LIN_SDT_PROBE_DEFINE0(util, linux_free_get_char_devices, return); +LIN_SDT_PROBE_DEFINE1(util, linux_device_register_handler, entry, + "struct linux_device_handler *"); +LIN_SDT_PROBE_DEFINE1(util, linux_device_register_handler, return, "int"); +LIN_SDT_PROBE_DEFINE1(util, linux_device_unregister_handler, entry, + "struct linux_device_handler *"); +LIN_SDT_PROBE_DEFINE1(util, linux_device_unregister_handler, return, "int"); + +/* + * 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; + + LIN_SDT_PROBE5(util, linux_emul_convpath, entry, path, pathseg, pbuf, + cflag, dfd); + + retval = kern_alternate_path(td, linux_emul_path, path, pathseg, pbuf, + cflag, dfd); + + LIN_SDT_PROBE1(util, linux_emul_convpath, return, retval); + return (retval); +} + +void +linux_msg(const struct thread *td, const char *fmt, ...) +{ + va_list ap; + struct proc *p; + + LIN_SDT_PROBE1(util, linux_msg, entry, fmt); + + p = td->td_proc; + printf("linux: pid %d (%s): ", (int)p->p_pid, p->p_comm); + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + printf("\n"); + + LIN_SDT_PROBE0(util, linux_msg, return); +} + +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); + + LIN_SDT_PROBE2(util, linux_driver_get_name_dev, entry, dev, + device_name); + + if (device_name == NULL) { + LIN_SDT_PROBE0(util, linux_driver_get_name_dev, nullcall); + LIN_SDT_PROBE1(util, linux_driver_get_name_dev, return, NULL); + return NULL; + } + TAILQ_FOREACH(de, &devices, list) { + if (strcmp(device_name, de->entry.bsd_driver_name) == 0) { + LIN_SDT_PROBE1(util, linux_driver_get_name_dev, return, + de->entry.linux_driver_name); + return (de->entry.linux_driver_name); + } + } + + LIN_SDT_PROBE1(util, linux_driver_get_name_dev, return, NULL); + return NULL; +} + +int +linux_driver_get_major_minor(const char *node, int *major, int *minor) +{ + struct device_element *de; + + LIN_SDT_PROBE3(util, linux_driver_get_major_minor, entry, node, major, + minor); + + if (node == NULL || major == NULL || minor == NULL) { + LIN_SDT_PROBE0(util, linux_driver_get_major_minor, nullcall); + LIN_SDT_PROBE3(util, linux_driver_get_major_minor, return, 1, + 0, 0); + return 1; + } + + if (strlen(node) > strlen("pts/") && + strncmp(node, "pts/", strlen("pts/")) == 0) { + unsigned long devno; + + /* + * 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 + strlen("pts/"), NULL, 10); + *major = 136 + (devno / 256); + *minor = devno % 256; + + LIN_SDT_PROBE3(util, linux_driver_get_major_minor, return, 0, + *major, *minor); + 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; + + LIN_SDT_PROBE3(util, linux_driver_get_major_minor, + return, 0, *major, *minor); + return 0; + } + } + + LIN_SDT_PROBE1(util, linux_driver_get_major_minor, notfound, node); + LIN_SDT_PROBE3(util, linux_driver_get_major_minor, return, 1, 0, 0); + return 1; +} + +char * +linux_get_char_devices() +{ + struct device_element *de; + char *temp, *string, *last; + char formated[256]; + int current_size = 0, string_size = 1024; + + LIN_SDT_PROBE0(util, linux_get_char_devices, entry); + + 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); + } + } + + LIN_SDT_PROBE1(util, linux_get_char_devices, return, string); + return string; +} + +void +linux_free_get_char_devices(char *string) +{ + + LIN_SDT_PROBE1(util, linux_get_char_devices, entry, string); + + free(string, M_LINUX); + + LIN_SDT_PROBE0(util, linux_get_char_devices, return); +} + +static int linux_major_starting = 200; + +int +linux_device_register_handler(struct linux_device_handler *d) +{ + struct device_element *de; + + LIN_SDT_PROBE1(util, linux_device_register_handler, entry, d); + + if (d == NULL) { + LIN_SDT_PROBE1(util, linux_device_register_handler, return, + EINVAL); + 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); + + LIN_SDT_PROBE1(util, linux_device_register_handler, return, 0); + return (0); +} + +int +linux_device_unregister_handler(struct linux_device_handler *d) +{ + struct device_element *de; + + LIN_SDT_PROBE1(util, linux_device_unregister_handler, entry, d); + + if (d == NULL) { + LIN_SDT_PROBE1(util, linux_device_unregister_handler, return, + EINVAL); + return (EINVAL); + } + + TAILQ_FOREACH(de, &devices, list) { + if (bcmp(d, &de->entry, sizeof(*d)) == 0) { + TAILQ_REMOVE(&devices, de, list); + free(de, M_LINUX); + + LIN_SDT_PROBE1(util, linux_device_unregister_handler, + return, 0); + return (0); + } + } + + LIN_SDT_PROBE1(util, linux_device_unregister_handler, return, EINVAL); + return (EINVAL); +} diff --git a/sys/compat/linux/linux_util.h b/sys/compat/linux/linux_util.h new file mode 100644 index 0000000..6be0392 --- /dev/null +++ b/sys/compat/linux/linux_util.h @@ -0,0 +1,141 @@ +/*- + * 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 <machine/vmparam.h> +#include <sys/exec.h> +#include <sys/sysent.h> +#include <sys/syslog.h> +#include <sys/cdefs.h> +#include <sys/uio.h> + +extern const char linux_emul_path[]; + +int linux_emul_convpath(struct thread *, const char *, enum uio_seg, char **, int, int); + +#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 + +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); +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 { \ + if (ldebug(f)) \ + 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 + +#endif /* !_LINUX_UTIL_H_ */ diff --git a/sys/compat/linux/linux_videodev2_compat.h b/sys/compat/linux/linux_videodev2_compat.h new file mode 100644 index 0000000..0d9a3a3 --- /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 0000000..98034bc --- /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 0000000..d0b6f73 --- /dev/null +++ b/sys/compat/linux/stats_timing.d @@ -0,0 +1,94 @@ +#!/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 + * - timing statistics for the emul_lock + * - 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 0000000..bd9dac6 --- /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 attemt 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/ndis/cfg_var.h b/sys/compat/ndis/cfg_var.h new file mode 100644 index 0000000..1fb44ce --- /dev/null +++ b/sys/compat/ndis/cfg_var.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.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, 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 Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD + * 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 _CFG_VAR_H_ +#define _CFG_VAR_H_ + +struct ndis_cfg { + char *nc_cfgkey; + char *nc_cfgdesc; + char nc_val[256]; + int nc_idx; +}; + +typedef struct ndis_cfg ndis_cfg; + +#endif /* _CFG_VAR_H_ */ diff --git a/sys/compat/ndis/hal_var.h b/sys/compat/ndis/hal_var.h new file mode 100644 index 0000000..699b01c --- /dev/null +++ b/sys/compat/ndis/hal_var.h @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.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, 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 Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD + * 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 _HAL_VAR_H_ +#define _HAL_VAR_H_ + +#define NDIS_BUS_SPACE_IO X86_BUS_SPACE_IO +#define NDIS_BUS_SPACE_MEM X86_BUS_SPACE_MEM + +extern image_patch_table hal_functbl[]; + +__BEGIN_DECLS +extern int hal_libinit(void); +extern int hal_libfini(void); +extern uint8_t KfAcquireSpinLock(kspin_lock *); +extern void KfReleaseSpinLock(kspin_lock *, uint8_t); +extern uint8_t KfRaiseIrql(uint8_t); +extern void KfLowerIrql(uint8_t); +extern uint8_t KeGetCurrentIrql(void); +__END_DECLS + +#endif /* _HAL_VAR_H_ */ diff --git a/sys/compat/ndis/kern_ndis.c b/sys/compat/ndis/kern_ndis.c new file mode 100644 index 0000000..71b4b80 --- /dev/null +++ b/sys/compat/ndis/kern_ndis.c @@ -0,0 +1,1433 @@ +/*- + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.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, 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 Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD + * 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/unistd.h> +#include <sys/types.h> +#include <sys/errno.h> +#include <sys/callout.h> +#include <sys/socket.h> +#include <sys/queue.h> +#include <sys/sysctl.h> +#include <sys/proc.h> +#include <sys/malloc.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/conf.h> + +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/kthread.h> +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/bus.h> +#include <sys/rman.h> + +#include <net/if.h> +#include <net/if_arp.h> +#include <net/ethernet.h> +#include <net/if_dl.h> +#include <net/if_media.h> + +#include <net80211/ieee80211_var.h> +#include <net80211/ieee80211_ioctl.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> + +#include <compat/ndis/pe_var.h> +#include <compat/ndis/cfg_var.h> +#include <compat/ndis/resource_var.h> +#include <compat/ndis/ntoskrnl_var.h> +#include <compat/ndis/ndis_var.h> +#include <compat/ndis/hal_var.h> +#include <compat/ndis/usbd_var.h> +#include <dev/if_ndis/if_ndisvar.h> + +#define NDIS_DUMMY_PATH "\\\\some\\bogus\\path" + +static void ndis_status_func(ndis_handle, ndis_status, void *, uint32_t); +static void ndis_statusdone_func(ndis_handle); +static void ndis_setdone_func(ndis_handle, ndis_status); +static void ndis_getdone_func(ndis_handle, ndis_status); +static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t); +static void ndis_sendrsrcavail_func(ndis_handle); +static void ndis_intrsetup(kdpc *, device_object *, + irp *, struct ndis_softc *); +static void ndis_return(device_object *, void *); + +static image_patch_table kernndis_functbl[] = { + IMPORT_SFUNC(ndis_status_func, 4), + IMPORT_SFUNC(ndis_statusdone_func, 1), + IMPORT_SFUNC(ndis_setdone_func, 2), + IMPORT_SFUNC(ndis_getdone_func, 2), + IMPORT_SFUNC(ndis_resetdone_func, 3), + IMPORT_SFUNC(ndis_sendrsrcavail_func, 1), + IMPORT_SFUNC(ndis_intrsetup, 4), + IMPORT_SFUNC(ndis_return, 1), + + { NULL, NULL, NULL } +}; + +static struct nd_head ndis_devhead; + +/* + * This allows us to export our symbols to other modules. + * Note that we call ourselves 'ndisapi' to avoid a namespace + * collision with if_ndis.ko, which internally calls itself + * 'ndis.' + * + * Note: some of the subsystems depend on each other, so the + * order in which they're started is important. The order of + * importance is: + * + * HAL - spinlocks and IRQL manipulation + * ntoskrnl - DPC and workitem threads, object waiting + * windrv - driver/device registration + * + * The HAL should also be the last thing shut down, since + * the ntoskrnl subsystem will use spinlocks right up until + * the DPC and workitem threads are terminated. + */ + +static int +ndis_modevent(module_t mod, int cmd, void *arg) +{ + int error = 0; + image_patch_table *patch; + + switch (cmd) { + case MOD_LOAD: + /* Initialize subsystems */ + hal_libinit(); + ntoskrnl_libinit(); + windrv_libinit(); + ndis_libinit(); + usbd_libinit(); + + patch = kernndis_functbl; + while (patch->ipt_func != NULL) { + windrv_wrap((funcptr)patch->ipt_func, + (funcptr *)&patch->ipt_wrap, + patch->ipt_argcnt, patch->ipt_ftype); + patch++; + } + + TAILQ_INIT(&ndis_devhead); + break; + case MOD_SHUTDOWN: + if (TAILQ_FIRST(&ndis_devhead) == NULL) { + /* Shut down subsystems */ + ndis_libfini(); + usbd_libfini(); + windrv_libfini(); + ntoskrnl_libfini(); + hal_libfini(); + + patch = kernndis_functbl; + while (patch->ipt_func != NULL) { + windrv_unwrap(patch->ipt_wrap); + patch++; + } + } + break; + case MOD_UNLOAD: + /* Shut down subsystems */ + ndis_libfini(); + usbd_libfini(); + windrv_libfini(); + ntoskrnl_libfini(); + hal_libfini(); + + patch = kernndis_functbl; + while (patch->ipt_func != NULL) { + windrv_unwrap(patch->ipt_wrap); + patch++; + } + + break; + default: + error = EINVAL; + break; + } + + return (error); +} +DEV_MODULE(ndisapi, ndis_modevent, NULL); +MODULE_VERSION(ndisapi, 1); + +static void +ndis_sendrsrcavail_func(adapter) + ndis_handle adapter; +{ +} + +static void +ndis_status_func(adapter, status, sbuf, slen) + ndis_handle adapter; + ndis_status status; + void *sbuf; + uint32_t slen; +{ + ndis_miniport_block *block; + struct ndis_softc *sc; + struct ifnet *ifp; + + block = adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + ifp = sc->ifp; + if (ifp->if_flags & IFF_DEBUG) + device_printf(sc->ndis_dev, "status: %x\n", status); +} + +static void +ndis_statusdone_func(adapter) + ndis_handle adapter; +{ + ndis_miniport_block *block; + struct ndis_softc *sc; + struct ifnet *ifp; + + block = adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + ifp = sc->ifp; + if (ifp->if_flags & IFF_DEBUG) + device_printf(sc->ndis_dev, "status complete\n"); +} + +static void +ndis_setdone_func(adapter, status) + ndis_handle adapter; + ndis_status status; +{ + ndis_miniport_block *block; + block = adapter; + + block->nmb_setstat = status; + KeSetEvent(&block->nmb_setevent, IO_NO_INCREMENT, FALSE); +} + +static void +ndis_getdone_func(adapter, status) + ndis_handle adapter; + ndis_status status; +{ + ndis_miniport_block *block; + block = adapter; + + block->nmb_getstat = status; + KeSetEvent(&block->nmb_getevent, IO_NO_INCREMENT, FALSE); +} + +static void +ndis_resetdone_func(ndis_handle adapter, ndis_status status, + uint8_t addressingreset) +{ + ndis_miniport_block *block; + struct ndis_softc *sc; + struct ifnet *ifp; + + block = adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + ifp = sc->ifp; + + if (ifp->if_flags & IFF_DEBUG) + device_printf(sc->ndis_dev, "reset done...\n"); + KeSetEvent(&block->nmb_resetevent, IO_NO_INCREMENT, FALSE); +} + +int +ndis_create_sysctls(arg) + void *arg; +{ + struct ndis_softc *sc; + ndis_cfg *vals; + char buf[256]; + struct sysctl_oid *oidp; + struct sysctl_ctx_entry *e; + + if (arg == NULL) + return (EINVAL); + + sc = arg; + vals = sc->ndis_regvals; + + TAILQ_INIT(&sc->ndis_cfglist_head); + + /* Add the driver-specific registry keys. */ + + while(1) { + if (vals->nc_cfgkey == NULL) + break; + + if (vals->nc_idx != sc->ndis_devidx) { + vals++; + continue; + } + + /* See if we already have a sysctl with this name */ + + oidp = NULL; + TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) { + oidp = e->entry; + if (strcasecmp(oidp->oid_name, vals->nc_cfgkey) == 0) + break; + oidp = NULL; + } + + if (oidp != NULL) { + vals++; + continue; + } + + ndis_add_sysctl(sc, vals->nc_cfgkey, vals->nc_cfgdesc, + vals->nc_val, CTLFLAG_RW); + vals++; + } + + /* Now add a couple of builtin keys. */ + + /* + * Environment can be either Windows (0) or WindowsNT (1). + * We qualify as the latter. + */ + ndis_add_sysctl(sc, "Environment", + "Windows environment", "1", CTLFLAG_RD); + + /* NDIS version should be 5.1. */ + ndis_add_sysctl(sc, "NdisVersion", + "NDIS API Version", "0x00050001", CTLFLAG_RD); + + /* + * Some miniport drivers rely on the existence of the SlotNumber, + * NetCfgInstanceId and DriverDesc keys. + */ + ndis_add_sysctl(sc, "SlotNumber", "Slot Numer", "01", CTLFLAG_RD); + ndis_add_sysctl(sc, "NetCfgInstanceId", "NetCfgInstanceId", + "{12345678-1234-5678-CAFE0-123456789ABC}", CTLFLAG_RD); + ndis_add_sysctl(sc, "DriverDesc", "Driver Description", + "NDIS Network Adapter", CTLFLAG_RD); + + /* Bus type (PCI, PCMCIA, etc...) */ + sprintf(buf, "%d", (int)sc->ndis_iftype); + ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD); + + if (sc->ndis_res_io != NULL) { + sprintf(buf, "0x%lx", rman_get_start(sc->ndis_res_io)); + ndis_add_sysctl(sc, "IOBaseAddress", + "Base I/O Address", buf, CTLFLAG_RD); + } + + if (sc->ndis_irq != NULL) { + sprintf(buf, "%lu", rman_get_start(sc->ndis_irq)); + ndis_add_sysctl(sc, "InterruptNumber", + "Interrupt Number", buf, CTLFLAG_RD); + } + + return (0); +} + +int +ndis_add_sysctl(arg, key, desc, val, flag) + void *arg; + char *key; + char *desc; + char *val; + int flag; +{ + struct ndis_softc *sc; + struct ndis_cfglist *cfg; + char descstr[256]; + + sc = arg; + + cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO); + + if (cfg == NULL) { + printf("failed for %s\n", key); + return (ENOMEM); + } + + cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF); + if (desc == NULL) { + snprintf(descstr, sizeof(descstr), "%s (dynamic)", key); + cfg->ndis_cfg.nc_cfgdesc = strdup(descstr, M_DEVBUF); + } else + cfg->ndis_cfg.nc_cfgdesc = strdup(desc, M_DEVBUF); + strcpy(cfg->ndis_cfg.nc_val, val); + + TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link); + + cfg->ndis_oid = + SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)), + OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag, + cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val), + cfg->ndis_cfg.nc_cfgdesc); + + return (0); +} + +/* + * Somewhere, somebody decided "hey, let's automatically create + * a sysctl tree for each device instance as it's created -- it'll + * make life so much easier!" Lies. Why must they turn the kernel + * into a house of lies? + */ + +int +ndis_flush_sysctls(arg) + void *arg; +{ + struct ndis_softc *sc; + struct ndis_cfglist *cfg; + struct sysctl_ctx_list *clist; + + sc = arg; + + clist = device_get_sysctl_ctx(sc->ndis_dev); + + while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) { + cfg = TAILQ_FIRST(&sc->ndis_cfglist_head); + TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link); + sysctl_ctx_entry_del(clist, cfg->ndis_oid); + sysctl_remove_oid(cfg->ndis_oid, 1, 0); + free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF); + free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF); + free(cfg, M_DEVBUF); + } + + return (0); +} + +void * +ndis_get_routine_address(functbl, name) + struct image_patch_table *functbl; + char *name; +{ + int i; + + for (i = 0; functbl[i].ipt_name != NULL; i++) + if (strcmp(name, functbl[i].ipt_name) == 0) + return (functbl[i].ipt_wrap); + return (NULL); +} + +static void +ndis_return(dobj, arg) + device_object *dobj; + void *arg; +{ + ndis_miniport_block *block; + ndis_miniport_characteristics *ch; + ndis_return_handler returnfunc; + ndis_handle adapter; + ndis_packet *p; + uint8_t irql; + list_entry *l; + + block = arg; + ch = IoGetDriverObjectExtension(dobj->do_drvobj, (void *)1); + + p = arg; + adapter = block->nmb_miniportadapterctx; + + if (adapter == NULL) + return; + + returnfunc = ch->nmc_return_packet_func; + + KeAcquireSpinLock(&block->nmb_returnlock, &irql); + while (!IsListEmpty(&block->nmb_returnlist)) { + l = RemoveHeadList((&block->nmb_returnlist)); + p = CONTAINING_RECORD(l, ndis_packet, np_list); + InitializeListHead((&p->np_list)); + KeReleaseSpinLock(&block->nmb_returnlock, irql); + MSCALL2(returnfunc, adapter, p); + KeAcquireSpinLock(&block->nmb_returnlock, &irql); + } + KeReleaseSpinLock(&block->nmb_returnlock, irql); +} + +void +ndis_return_packet(buf, arg) + void *buf; /* not used */ + void *arg; +{ + ndis_packet *p; + ndis_miniport_block *block; + + if (arg == NULL) + return; + + p = arg; + + /* Decrement refcount. */ + p->np_refcnt--; + + /* Release packet when refcount hits zero, otherwise return. */ + if (p->np_refcnt) + return; + + block = ((struct ndis_softc *)p->np_softc)->ndis_block; + + KeAcquireSpinLockAtDpcLevel(&block->nmb_returnlock); + InitializeListHead((&p->np_list)); + InsertHeadList((&block->nmb_returnlist), (&p->np_list)); + KeReleaseSpinLockFromDpcLevel(&block->nmb_returnlock); + + IoQueueWorkItem(block->nmb_returnitem, + (io_workitem_func)kernndis_functbl[7].ipt_wrap, + WORKQUEUE_CRITICAL, block); +} + +void +ndis_free_bufs(b0) + ndis_buffer *b0; +{ + ndis_buffer *next; + + if (b0 == NULL) + return; + + while(b0 != NULL) { + next = b0->mdl_next; + IoFreeMdl(b0); + b0 = next; + } +} + +void +ndis_free_packet(p) + ndis_packet *p; +{ + if (p == NULL) + return; + + ndis_free_bufs(p->np_private.npp_head); + NdisFreePacket(p); +} + +int +ndis_convert_res(arg) + void *arg; +{ + struct ndis_softc *sc; + ndis_resource_list *rl = NULL; + cm_partial_resource_desc *prd = NULL; + ndis_miniport_block *block; + device_t dev; + struct resource_list *brl; + struct resource_list_entry *brle; + int error = 0; + + sc = arg; + block = sc->ndis_block; + dev = sc->ndis_dev; + + rl = malloc(sizeof(ndis_resource_list) + + (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)), + M_DEVBUF, M_NOWAIT|M_ZERO); + + if (rl == NULL) + return (ENOMEM); + + rl->cprl_version = 5; + rl->cprl_revision = 1; + rl->cprl_count = sc->ndis_rescnt; + prd = rl->cprl_partial_descs; + + brl = BUS_GET_RESOURCE_LIST(dev, dev); + + if (brl != NULL) { + + STAILQ_FOREACH(brle, brl, link) { + switch (brle->type) { + case SYS_RES_IOPORT: + prd->cprd_type = CmResourceTypePort; + prd->cprd_flags = CM_RESOURCE_PORT_IO; + prd->cprd_sharedisp = + CmResourceShareDeviceExclusive; + prd->u.cprd_port.cprd_start.np_quad = + brle->start; + prd->u.cprd_port.cprd_len = brle->count; + break; + case SYS_RES_MEMORY: + prd->cprd_type = CmResourceTypeMemory; + prd->cprd_flags = + CM_RESOURCE_MEMORY_READ_WRITE; + prd->cprd_sharedisp = + CmResourceShareDeviceExclusive; + prd->u.cprd_mem.cprd_start.np_quad = + brle->start; + prd->u.cprd_mem.cprd_len = brle->count; + break; + case SYS_RES_IRQ: + prd->cprd_type = CmResourceTypeInterrupt; + prd->cprd_flags = 0; + /* + * Always mark interrupt resources as + * shared, since in our implementation, + * they will be. + */ + prd->cprd_sharedisp = + CmResourceShareShared; + prd->u.cprd_intr.cprd_level = brle->start; + prd->u.cprd_intr.cprd_vector = brle->start; + prd->u.cprd_intr.cprd_affinity = 0; + break; + default: + break; + } + prd++; + } + } + + block->nmb_rlist = rl; + + return (error); +} + +/* + * Map an NDIS packet to an mbuf list. When an NDIS driver receives a + * packet, it will hand it to us in the form of an ndis_packet, + * which we need to convert to an mbuf that is then handed off + * to the stack. Note: we configure the mbuf list so that it uses + * the memory regions specified by the ndis_buffer structures in + * the ndis_packet as external storage. In most cases, this will + * point to a memory region allocated by the driver (either by + * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect + * the driver to handle free()ing this region for is, so we set up + * a dummy no-op free handler for it. + */ + +int +ndis_ptom(m0, p) + struct mbuf **m0; + ndis_packet *p; +{ + struct mbuf *m = NULL, *prev = NULL; + ndis_buffer *buf; + ndis_packet_private *priv; + uint32_t totlen = 0; + struct ifnet *ifp; + struct ether_header *eh; + int diff; + + if (p == NULL || m0 == NULL) + return (EINVAL); + + priv = &p->np_private; + buf = priv->npp_head; + p->np_refcnt = 0; + + for (buf = priv->npp_head; buf != NULL; buf = buf->mdl_next) { + if (buf == priv->npp_head) + m = m_gethdr(M_NOWAIT, MT_DATA); + else + m = m_get(M_NOWAIT, MT_DATA); + if (m == NULL) { + m_freem(*m0); + *m0 = NULL; + return (ENOBUFS); + } + m->m_len = MmGetMdlByteCount(buf); + m->m_data = MmGetMdlVirtualAddress(buf); + MEXTADD(m, m->m_data, m->m_len, ndis_return_packet, + m->m_data, p, 0, EXT_NDIS); + p->np_refcnt++; + + totlen += m->m_len; + if (m->m_flags & M_PKTHDR) + *m0 = m; + else + prev->m_next = m; + prev = m; + } + + /* + * This is a hack to deal with the Marvell 8335 driver + * which, when associated with an AP in WPA-PSK mode, + * seems to overpad its frames by 8 bytes. I don't know + * that the extra 8 bytes are for, and they're not there + * in open mode, so for now clamp the frame size at 1514 + * until I can figure out how to deal with this properly, + * otherwise if_ethersubr() will spank us by discarding + * the 'oversize' frames. + */ + + eh = mtod((*m0), struct ether_header *); + ifp = ((struct ndis_softc *)p->np_softc)->ifp; + if (totlen > ETHER_MAX_FRAME(ifp, eh->ether_type, FALSE)) { + diff = totlen - ETHER_MAX_FRAME(ifp, eh->ether_type, FALSE); + totlen -= diff; + m->m_len -= diff; + } + (*m0)->m_pkthdr.len = totlen; + + return (0); +} + +/* + * Create an NDIS packet from an mbuf chain. + * This is used mainly when transmitting packets, where we need + * to turn an mbuf off an interface's send queue and transform it + * into an NDIS packet which will be fed into the NDIS driver's + * send routine. + * + * NDIS packets consist of two parts: an ndis_packet structure, + * which is vaguely analagous to the pkthdr portion of an mbuf, + * and one or more ndis_buffer structures, which define the + * actual memory segments in which the packet data resides. + * We need to allocate one ndis_buffer for each mbuf in a chain, + * plus one ndis_packet as the header. + */ + +int +ndis_mtop(m0, p) + struct mbuf *m0; + ndis_packet **p; +{ + struct mbuf *m; + ndis_buffer *buf = NULL, *prev = NULL; + ndis_packet_private *priv; + + if (p == NULL || *p == NULL || m0 == NULL) + return (EINVAL); + + priv = &(*p)->np_private; + priv->npp_totlen = m0->m_pkthdr.len; + + for (m = m0; m != NULL; m = m->m_next) { + if (m->m_len == 0) + continue; + buf = IoAllocateMdl(m->m_data, m->m_len, FALSE, FALSE, NULL); + if (buf == NULL) { + ndis_free_packet(*p); + *p = NULL; + return (ENOMEM); + } + MmBuildMdlForNonPagedPool(buf); + + if (priv->npp_head == NULL) + priv->npp_head = buf; + else + prev->mdl_next = buf; + prev = buf; + } + + priv->npp_tail = buf; + + return (0); +} + +int +ndis_get_supported_oids(arg, oids, oidcnt) + void *arg; + ndis_oid **oids; + int *oidcnt; +{ + int len, rval; + ndis_oid *o; + + if (arg == NULL || oids == NULL || oidcnt == NULL) + return (EINVAL); + len = 0; + ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len); + + o = malloc(len, M_DEVBUF, M_NOWAIT); + if (o == NULL) + return (ENOMEM); + + rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len); + + if (rval) { + free(o, M_DEVBUF); + return (rval); + } + + *oids = o; + *oidcnt = len / 4; + + return (0); +} + +int +ndis_set_info(arg, oid, buf, buflen) + void *arg; + ndis_oid oid; + void *buf; + int *buflen; +{ + struct ndis_softc *sc; + ndis_status rval; + ndis_handle adapter; + ndis_setinfo_handler setfunc; + uint32_t byteswritten = 0, bytesneeded = 0; + uint8_t irql; + uint64_t duetime; + + /* + * According to the NDIS spec, MiniportQueryInformation() + * and MiniportSetInformation() requests are handled serially: + * once one request has been issued, we must wait for it to + * finish before allowing another request to proceed. + */ + + sc = arg; + + KeResetEvent(&sc->ndis_block->nmb_setevent); + + KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); + + if (sc->ndis_block->nmb_pendingreq != NULL) { + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); + panic("ndis_set_info() called while other request pending"); + } else + sc->ndis_block->nmb_pendingreq = (ndis_request *)sc; + + setfunc = sc->ndis_chars->nmc_setinfo_func; + adapter = sc->ndis_block->nmb_miniportadapterctx; + + if (adapter == NULL || setfunc == NULL || + sc->ndis_block->nmb_devicectx == NULL) { + sc->ndis_block->nmb_pendingreq = NULL; + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); + return (ENXIO); + } + + rval = MSCALL6(setfunc, adapter, oid, buf, *buflen, + &byteswritten, &bytesneeded); + + sc->ndis_block->nmb_pendingreq = NULL; + + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); + + if (rval == NDIS_STATUS_PENDING) { + /* Wait up to 5 seconds. */ + duetime = (5 * 1000000) * -10; + KeWaitForSingleObject(&sc->ndis_block->nmb_setevent, + 0, 0, FALSE, &duetime); + rval = sc->ndis_block->nmb_setstat; + } + + if (byteswritten) + *buflen = byteswritten; + if (bytesneeded) + *buflen = bytesneeded; + + if (rval == NDIS_STATUS_INVALID_LENGTH) + return (ENOSPC); + + if (rval == NDIS_STATUS_INVALID_OID) + return (EINVAL); + + if (rval == NDIS_STATUS_NOT_SUPPORTED || + rval == NDIS_STATUS_NOT_ACCEPTED) + return (ENOTSUP); + + if (rval != NDIS_STATUS_SUCCESS) + return (ENODEV); + + return (0); +} + +typedef void (*ndis_senddone_func)(ndis_handle, ndis_packet *, ndis_status); + +int +ndis_send_packets(arg, packets, cnt) + void *arg; + ndis_packet **packets; + int cnt; +{ + struct ndis_softc *sc; + ndis_handle adapter; + ndis_sendmulti_handler sendfunc; + ndis_senddone_func senddonefunc; + int i; + ndis_packet *p; + uint8_t irql = 0; + + sc = arg; + adapter = sc->ndis_block->nmb_miniportadapterctx; + if (adapter == NULL) + return (ENXIO); + sendfunc = sc->ndis_chars->nmc_sendmulti_func; + senddonefunc = sc->ndis_block->nmb_senddone_func; + + if (NDIS_SERIALIZED(sc->ndis_block)) + KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); + + MSCALL3(sendfunc, adapter, packets, cnt); + + for (i = 0; i < cnt; i++) { + p = packets[i]; + /* + * Either the driver already handed the packet to + * ndis_txeof() due to a failure, or it wants to keep + * it and release it asynchronously later. Skip to the + * next one. + */ + if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING) + continue; + MSCALL3(senddonefunc, sc->ndis_block, p, p->np_oob.npo_status); + } + + if (NDIS_SERIALIZED(sc->ndis_block)) + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); + + return (0); +} + +int +ndis_send_packet(arg, packet) + void *arg; + ndis_packet *packet; +{ + struct ndis_softc *sc; + ndis_handle adapter; + ndis_status status; + ndis_sendsingle_handler sendfunc; + ndis_senddone_func senddonefunc; + uint8_t irql = 0; + + sc = arg; + adapter = sc->ndis_block->nmb_miniportadapterctx; + if (adapter == NULL) + return (ENXIO); + sendfunc = sc->ndis_chars->nmc_sendsingle_func; + senddonefunc = sc->ndis_block->nmb_senddone_func; + + if (NDIS_SERIALIZED(sc->ndis_block)) + KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); + status = MSCALL3(sendfunc, adapter, packet, + packet->np_private.npp_flags); + + if (status == NDIS_STATUS_PENDING) { + if (NDIS_SERIALIZED(sc->ndis_block)) + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); + return (0); + } + + MSCALL3(senddonefunc, sc->ndis_block, packet, status); + + if (NDIS_SERIALIZED(sc->ndis_block)) + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); + + return (0); +} + +int +ndis_init_dma(arg) + void *arg; +{ + struct ndis_softc *sc; + int i, error; + + sc = arg; + + sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts, + M_DEVBUF, M_NOWAIT|M_ZERO); + + if (sc->ndis_tmaps == NULL) + return (ENOMEM); + + for (i = 0; i < sc->ndis_maxpkts; i++) { + error = bus_dmamap_create(sc->ndis_ttag, 0, + &sc->ndis_tmaps[i]); + if (error) { + free(sc->ndis_tmaps, M_DEVBUF); + return (ENODEV); + } + } + + return (0); +} + +int +ndis_destroy_dma(arg) + void *arg; +{ + struct ndis_softc *sc; + struct mbuf *m; + ndis_packet *p = NULL; + int i; + + sc = arg; + + for (i = 0; i < sc->ndis_maxpkts; i++) { + if (sc->ndis_txarray[i] != NULL) { + p = sc->ndis_txarray[i]; + m = (struct mbuf *)p->np_rsvd[1]; + if (m != NULL) + m_freem(m); + ndis_free_packet(sc->ndis_txarray[i]); + } + bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]); + } + + free(sc->ndis_tmaps, M_DEVBUF); + + bus_dma_tag_destroy(sc->ndis_ttag); + + return (0); +} + +int +ndis_reset_nic(arg) + void *arg; +{ + struct ndis_softc *sc; + ndis_handle adapter; + ndis_reset_handler resetfunc; + uint8_t addressing_reset; + int rval; + uint8_t irql = 0; + + sc = arg; + + NDIS_LOCK(sc); + adapter = sc->ndis_block->nmb_miniportadapterctx; + resetfunc = sc->ndis_chars->nmc_reset_func; + + if (adapter == NULL || resetfunc == NULL || + sc->ndis_block->nmb_devicectx == NULL) { + NDIS_UNLOCK(sc); + return (EIO); + } + + NDIS_UNLOCK(sc); + + KeResetEvent(&sc->ndis_block->nmb_resetevent); + + if (NDIS_SERIALIZED(sc->ndis_block)) + KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); + + rval = MSCALL2(resetfunc, &addressing_reset, adapter); + + if (NDIS_SERIALIZED(sc->ndis_block)) + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); + + if (rval == NDIS_STATUS_PENDING) + KeWaitForSingleObject(&sc->ndis_block->nmb_resetevent, + 0, 0, FALSE, NULL); + + return (0); +} + +int +ndis_halt_nic(arg) + void *arg; +{ + struct ndis_softc *sc; + ndis_handle adapter; + ndis_halt_handler haltfunc; + ndis_miniport_block *block; + int empty = 0; + uint8_t irql; + + sc = arg; + block = sc->ndis_block; + + if (!cold) + KeFlushQueuedDpcs(); + + /* + * Wait for all packets to be returned. + */ + + while (1) { + KeAcquireSpinLock(&block->nmb_returnlock, &irql); + empty = IsListEmpty(&block->nmb_returnlist); + KeReleaseSpinLock(&block->nmb_returnlock, irql); + if (empty) + break; + NdisMSleep(1000); + } + + NDIS_LOCK(sc); + adapter = sc->ndis_block->nmb_miniportadapterctx; + if (adapter == NULL) { + NDIS_UNLOCK(sc); + return (EIO); + } + + sc->ndis_block->nmb_devicectx = NULL; + + /* + * The adapter context is only valid after the init + * handler has been called, and is invalid once the + * halt handler has been called. + */ + + haltfunc = sc->ndis_chars->nmc_halt_func; + NDIS_UNLOCK(sc); + + MSCALL1(haltfunc, adapter); + + NDIS_LOCK(sc); + sc->ndis_block->nmb_miniportadapterctx = NULL; + NDIS_UNLOCK(sc); + + return (0); +} + +int +ndis_shutdown_nic(arg) + void *arg; +{ + struct ndis_softc *sc; + ndis_handle adapter; + ndis_shutdown_handler shutdownfunc; + + sc = arg; + NDIS_LOCK(sc); + adapter = sc->ndis_block->nmb_miniportadapterctx; + shutdownfunc = sc->ndis_chars->nmc_shutdown_handler; + NDIS_UNLOCK(sc); + if (adapter == NULL || shutdownfunc == NULL) + return (EIO); + + if (sc->ndis_chars->nmc_rsvd0 == NULL) + MSCALL1(shutdownfunc, adapter); + else + MSCALL1(shutdownfunc, sc->ndis_chars->nmc_rsvd0); + + TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link); + + return (0); +} + +int +ndis_pnpevent_nic(arg, type) + void *arg; + int type; +{ + device_t dev; + struct ndis_softc *sc; + ndis_handle adapter; + ndis_pnpevent_handler pnpeventfunc; + + dev = arg; + sc = device_get_softc(arg); + NDIS_LOCK(sc); + adapter = sc->ndis_block->nmb_miniportadapterctx; + pnpeventfunc = sc->ndis_chars->nmc_pnpevent_handler; + NDIS_UNLOCK(sc); + if (adapter == NULL || pnpeventfunc == NULL) + return (EIO); + + if (sc->ndis_chars->nmc_rsvd0 == NULL) + MSCALL4(pnpeventfunc, adapter, type, NULL, 0); + else + MSCALL4(pnpeventfunc, sc->ndis_chars->nmc_rsvd0, type, NULL, 0); + + return (0); +} + +int +ndis_init_nic(arg) + void *arg; +{ + struct ndis_softc *sc; + ndis_miniport_block *block; + ndis_init_handler initfunc; + ndis_status status, openstatus = 0; + ndis_medium mediumarray[NdisMediumMax]; + uint32_t chosenmedium, i; + + if (arg == NULL) + return (EINVAL); + + sc = arg; + NDIS_LOCK(sc); + block = sc->ndis_block; + initfunc = sc->ndis_chars->nmc_init_func; + NDIS_UNLOCK(sc); + + sc->ndis_block->nmb_timerlist = NULL; + + for (i = 0; i < NdisMediumMax; i++) + mediumarray[i] = i; + + status = MSCALL6(initfunc, &openstatus, &chosenmedium, + mediumarray, NdisMediumMax, block, block); + + /* + * If the init fails, blow away the other exported routines + * we obtained from the driver so we can't call them later. + * If the init failed, none of these will work. + */ + if (status != NDIS_STATUS_SUCCESS) { + NDIS_LOCK(sc); + sc->ndis_block->nmb_miniportadapterctx = NULL; + NDIS_UNLOCK(sc); + return (ENXIO); + } + + /* + * This may look really goofy, but apparently it is possible + * to halt a miniport too soon after it's been initialized. + * After MiniportInitialize() finishes, pause for 1 second + * to give the chip a chance to handle any short-lived timers + * that were set in motion. If we call MiniportHalt() too soon, + * some of the timers may not be cancelled, because the driver + * expects them to fire before the halt is called. + */ + + pause("ndwait", hz); + + NDIS_LOCK(sc); + sc->ndis_block->nmb_devicectx = sc; + NDIS_UNLOCK(sc); + + return (0); +} + +static void +ndis_intrsetup(dpc, dobj, ip, sc) + kdpc *dpc; + device_object *dobj; + irp *ip; + struct ndis_softc *sc; +{ + ndis_miniport_interrupt *intr; + + intr = sc->ndis_block->nmb_interrupt; + + /* Sanity check. */ + + if (intr == NULL) + return; + + KeAcquireSpinLockAtDpcLevel(&intr->ni_dpccountlock); + KeResetEvent(&intr->ni_dpcevt); + if (KeInsertQueueDpc(&intr->ni_dpc, NULL, NULL) == TRUE) + intr->ni_dpccnt++; + KeReleaseSpinLockFromDpcLevel(&intr->ni_dpccountlock); +} + +int +ndis_get_info(arg, oid, buf, buflen) + void *arg; + ndis_oid oid; + void *buf; + int *buflen; +{ + struct ndis_softc *sc; + ndis_status rval; + ndis_handle adapter; + ndis_queryinfo_handler queryfunc; + uint32_t byteswritten = 0, bytesneeded = 0; + uint8_t irql; + uint64_t duetime; + + sc = arg; + + KeResetEvent(&sc->ndis_block->nmb_getevent); + + KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); + + if (sc->ndis_block->nmb_pendingreq != NULL) { + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); + panic("ndis_get_info() called while other request pending"); + } else + sc->ndis_block->nmb_pendingreq = (ndis_request *)sc; + + queryfunc = sc->ndis_chars->nmc_queryinfo_func; + adapter = sc->ndis_block->nmb_miniportadapterctx; + + if (adapter == NULL || queryfunc == NULL || + sc->ndis_block->nmb_devicectx == NULL) { + sc->ndis_block->nmb_pendingreq = NULL; + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); + return (ENXIO); + } + + rval = MSCALL6(queryfunc, adapter, oid, buf, *buflen, + &byteswritten, &bytesneeded); + + sc->ndis_block->nmb_pendingreq = NULL; + + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); + + /* Wait for requests that block. */ + + if (rval == NDIS_STATUS_PENDING) { + /* Wait up to 5 seconds. */ + duetime = (5 * 1000000) * -10; + KeWaitForSingleObject(&sc->ndis_block->nmb_getevent, + 0, 0, FALSE, &duetime); + rval = sc->ndis_block->nmb_getstat; + } + + if (byteswritten) + *buflen = byteswritten; + if (bytesneeded) + *buflen = bytesneeded; + + if (rval == NDIS_STATUS_INVALID_LENGTH || + rval == NDIS_STATUS_BUFFER_TOO_SHORT) + return (ENOSPC); + + if (rval == NDIS_STATUS_INVALID_OID) + return (EINVAL); + + if (rval == NDIS_STATUS_NOT_SUPPORTED || + rval == NDIS_STATUS_NOT_ACCEPTED) + return (ENOTSUP); + + if (rval != NDIS_STATUS_SUCCESS) + return (ENODEV); + + return (0); +} + +uint32_t +NdisAddDevice(drv, pdo) + driver_object *drv; + device_object *pdo; +{ + device_object *fdo; + ndis_miniport_block *block; + struct ndis_softc *sc; + uint32_t status; + int error; + + sc = device_get_softc(pdo->do_devext); + + if (sc->ndis_iftype == PCMCIABus || sc->ndis_iftype == PCIBus) { + error = bus_setup_intr(sc->ndis_dev, sc->ndis_irq, + INTR_TYPE_NET | INTR_MPSAFE, + NULL, ntoskrnl_intr, NULL, &sc->ndis_intrhand); + if (error) + return (NDIS_STATUS_FAILURE); + } + + status = IoCreateDevice(drv, sizeof(ndis_miniport_block), NULL, + FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo); + + if (status != STATUS_SUCCESS) + return (status); + + block = fdo->do_devext; + + block->nmb_filterdbs.nf_ethdb = block; + block->nmb_deviceobj = fdo; + block->nmb_physdeviceobj = pdo; + block->nmb_nextdeviceobj = IoAttachDeviceToDeviceStack(fdo, pdo); + KeInitializeSpinLock(&block->nmb_lock); + KeInitializeSpinLock(&block->nmb_returnlock); + KeInitializeEvent(&block->nmb_getevent, EVENT_TYPE_NOTIFY, TRUE); + KeInitializeEvent(&block->nmb_setevent, EVENT_TYPE_NOTIFY, TRUE); + KeInitializeEvent(&block->nmb_resetevent, EVENT_TYPE_NOTIFY, TRUE); + InitializeListHead(&block->nmb_parmlist); + InitializeListHead(&block->nmb_returnlist); + block->nmb_returnitem = IoAllocateWorkItem(fdo); + + /* + * Stash pointers to the miniport block and miniport + * characteristics info in the if_ndis softc so the + * UNIX wrapper driver can get to them later. + */ + sc->ndis_block = block; + sc->ndis_chars = IoGetDriverObjectExtension(drv, (void *)1); + + /* + * If the driver has a MiniportTransferData() function, + * we should allocate a private RX packet pool. + */ + + if (sc->ndis_chars->nmc_transferdata_func != NULL) { + NdisAllocatePacketPool(&status, &block->nmb_rxpool, + 32, PROTOCOL_RESERVED_SIZE_IN_PACKET); + if (status != NDIS_STATUS_SUCCESS) { + IoDetachDevice(block->nmb_nextdeviceobj); + IoDeleteDevice(fdo); + return (status); + } + InitializeListHead((&block->nmb_packetlist)); + } + + /* Give interrupt handling priority over timers. */ + IoInitializeDpcRequest(fdo, kernndis_functbl[6].ipt_wrap); + KeSetImportanceDpc(&fdo->do_dpc, KDPC_IMPORTANCE_HIGH); + + /* Finish up BSD-specific setup. */ + + block->nmb_signature = (void *)0xcafebabe; + block->nmb_status_func = kernndis_functbl[0].ipt_wrap; + block->nmb_statusdone_func = kernndis_functbl[1].ipt_wrap; + block->nmb_setdone_func = kernndis_functbl[2].ipt_wrap; + block->nmb_querydone_func = kernndis_functbl[3].ipt_wrap; + block->nmb_resetdone_func = kernndis_functbl[4].ipt_wrap; + block->nmb_sendrsrc_func = kernndis_functbl[5].ipt_wrap; + block->nmb_pendingreq = NULL; + + TAILQ_INSERT_TAIL(&ndis_devhead, block, link); + + return (STATUS_SUCCESS); +} + +int +ndis_unload_driver(arg) + void *arg; +{ + struct ndis_softc *sc; + device_object *fdo; + + sc = arg; + + if (sc->ndis_intrhand) + bus_teardown_intr(sc->ndis_dev, + sc->ndis_irq, sc->ndis_intrhand); + + if (sc->ndis_block->nmb_rlist != NULL) + free(sc->ndis_block->nmb_rlist, M_DEVBUF); + + ndis_flush_sysctls(sc); + + TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link); + + if (sc->ndis_chars->nmc_transferdata_func != NULL) + NdisFreePacketPool(sc->ndis_block->nmb_rxpool); + fdo = sc->ndis_block->nmb_deviceobj; + IoFreeWorkItem(sc->ndis_block->nmb_returnitem); + IoDetachDevice(sc->ndis_block->nmb_nextdeviceobj); + IoDeleteDevice(fdo); + + return (0); +} diff --git a/sys/compat/ndis/kern_windrv.c b/sys/compat/ndis/kern_windrv.c new file mode 100644 index 0000000..5572988 --- /dev/null +++ b/sys/compat/ndis/kern_windrv.c @@ -0,0 +1,988 @@ +/*- + * Copyright (c) 2005 + * Bill Paul <wpaul@windriver.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, 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 Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD + * 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/unistd.h> +#include <sys/types.h> + +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/module.h> +#include <sys/conf.h> +#include <sys/mbuf.h> +#include <sys/bus.h> +#include <sys/proc.h> +#include <sys/sched.h> +#include <sys/smp.h> + +#include <sys/queue.h> + +#ifdef __i386__ +#include <machine/segments.h> +#endif + +#include <dev/usb/usb.h> + +#include <compat/ndis/pe_var.h> +#include <compat/ndis/cfg_var.h> +#include <compat/ndis/resource_var.h> +#include <compat/ndis/ntoskrnl_var.h> +#include <compat/ndis/ndis_var.h> +#include <compat/ndis/hal_var.h> +#include <compat/ndis/usbd_var.h> + +static struct mtx drvdb_mtx; +static STAILQ_HEAD(drvdb, drvdb_ent) drvdb_head; + +static driver_object fake_pci_driver; /* serves both PCI and cardbus */ +static driver_object fake_pccard_driver; + +#ifdef __i386__ +static void x86_oldldt(void *); +static void x86_newldt(void *); + +struct tid { + void *tid_except_list; /* 0x00 */ + uint32_t tid_oldfs; /* 0x04 */ + uint32_t tid_selector; /* 0x08 */ + struct tid *tid_self; /* 0x0C */ + int tid_cpu; /* 0x10 */ +}; + +static struct tid *my_tids; +#endif /* __i386__ */ + +#define DUMMY_REGISTRY_PATH "\\\\some\\bogus\\path" + +int +windrv_libinit(void) +{ + STAILQ_INIT(&drvdb_head); + mtx_init(&drvdb_mtx, "Windows driver DB lock", + "Windows internal lock", MTX_DEF); + + /* + * PCI and pccard devices don't need to use IRPs to + * interact with their bus drivers (usually), so our + * emulated PCI and pccard drivers are just stubs. + * USB devices, on the other hand, do all their I/O + * by exchanging IRPs with the USB bus driver, so + * for that we need to provide emulator dispatcher + * routines, which are in a separate module. + */ + + windrv_bus_attach(&fake_pci_driver, "PCI Bus"); + windrv_bus_attach(&fake_pccard_driver, "PCCARD Bus"); + +#ifdef __i386__ + + /* + * In order to properly support SMP machines, we have + * to modify the GDT on each CPU, since we never know + * on which one we'll end up running. + */ + + my_tids = ExAllocatePoolWithTag(NonPagedPool, + sizeof(struct tid) * mp_ncpus, 0); + if (my_tids == NULL) + panic("failed to allocate thread info blocks"); + smp_rendezvous(NULL, x86_newldt, NULL, NULL); +#endif + return (0); +} + +int +windrv_libfini(void) +{ + struct drvdb_ent *d; + + mtx_lock(&drvdb_mtx); + while(STAILQ_FIRST(&drvdb_head) != NULL) { + d = STAILQ_FIRST(&drvdb_head); + STAILQ_REMOVE_HEAD(&drvdb_head, link); + free(d, M_DEVBUF); + } + mtx_unlock(&drvdb_mtx); + + RtlFreeUnicodeString(&fake_pci_driver.dro_drivername); + RtlFreeUnicodeString(&fake_pccard_driver.dro_drivername); + + mtx_destroy(&drvdb_mtx); + +#ifdef __i386__ + smp_rendezvous(NULL, x86_oldldt, NULL, NULL); + ExFreePool(my_tids); +#endif + return (0); +} + +/* + * Given the address of a driver image, find its corresponding + * driver_object. + */ + +driver_object * +windrv_lookup(img, name) + vm_offset_t img; + char *name; +{ + struct drvdb_ent *d; + unicode_string us; + ansi_string as; + + bzero((char *)&us, sizeof(us)); + + /* Damn unicode. */ + + if (name != NULL) { + RtlInitAnsiString(&as, name); + if (RtlAnsiStringToUnicodeString(&us, &as, TRUE)) + return (NULL); + } + + mtx_lock(&drvdb_mtx); + STAILQ_FOREACH(d, &drvdb_head, link) { + if (d->windrv_object->dro_driverstart == (void *)img || + (bcmp((char *)d->windrv_object->dro_drivername.us_buf, + (char *)us.us_buf, us.us_len) == 0 && us.us_len)) { + mtx_unlock(&drvdb_mtx); + if (name != NULL) + ExFreePool(us.us_buf); + return (d->windrv_object); + } + } + mtx_unlock(&drvdb_mtx); + + if (name != NULL) + RtlFreeUnicodeString(&us); + + return (NULL); +} + +struct drvdb_ent * +windrv_match(matchfunc, ctx) + matchfuncptr matchfunc; + void *ctx; +{ + struct drvdb_ent *d; + int match; + + mtx_lock(&drvdb_mtx); + STAILQ_FOREACH(d, &drvdb_head, link) { + if (d->windrv_devlist == NULL) + continue; + match = matchfunc(d->windrv_bustype, d->windrv_devlist, ctx); + if (match == TRUE) { + mtx_unlock(&drvdb_mtx); + return (d); + } + } + mtx_unlock(&drvdb_mtx); + + return (NULL); +} + +/* + * Remove a driver_object from our datatabase and destroy it. Throw + * away any custom driver extension info that may have been added. + */ + +int +windrv_unload(mod, img, len) + module_t mod; + vm_offset_t img; + int len; +{ + struct drvdb_ent *db, *r = NULL; + driver_object *drv; + device_object *d, *pdo; + device_t dev; + list_entry *e; + + drv = windrv_lookup(img, NULL); + + /* + * When we unload a driver image, we need to force a + * detach of any devices that might be using it. We + * need the PDOs of all attached devices for this. + * Getting at them is a little hard. We basically + * have to walk the device lists of all our bus + * drivers. + */ + + mtx_lock(&drvdb_mtx); + STAILQ_FOREACH(db, &drvdb_head, link) { + /* + * Fake bus drivers have no devlist info. + * If this driver has devlist info, it's + * a loaded Windows driver and has no PDOs, + * so skip it. + */ + if (db->windrv_devlist != NULL) + continue; + pdo = db->windrv_object->dro_devobj; + while (pdo != NULL) { + d = pdo->do_attacheddev; + if (d->do_drvobj != drv) { + pdo = pdo->do_nextdev; + continue; + } + dev = pdo->do_devext; + pdo = pdo->do_nextdev; + mtx_unlock(&drvdb_mtx); + device_detach(dev); + mtx_lock(&drvdb_mtx); + } + } + + STAILQ_FOREACH(db, &drvdb_head, link) { + if (db->windrv_object->dro_driverstart == (void *)img) { + r = db; + STAILQ_REMOVE(&drvdb_head, db, drvdb_ent, link); + break; + } + } + mtx_unlock(&drvdb_mtx); + + if (r == NULL) + return (ENOENT); + + if (drv == NULL) + return (ENOENT); + + /* + * Destroy any custom extensions that may have been added. + */ + drv = r->windrv_object; + while (!IsListEmpty(&drv->dro_driverext->dre_usrext)) { + e = RemoveHeadList(&drv->dro_driverext->dre_usrext); + ExFreePool(e); + } + + /* Free the driver extension */ + free(drv->dro_driverext, M_DEVBUF); + + /* Free the driver name */ + RtlFreeUnicodeString(&drv->dro_drivername); + + /* Free driver object */ + free(drv, M_DEVBUF); + + /* Free our DB handle */ + free(r, M_DEVBUF); + + return (0); +} + +#define WINDRV_LOADED htonl(0x42534F44) + +#ifdef __amd64__ +static void +patch_user_shared_data_address(vm_offset_t img, size_t len) +{ + unsigned long i, n, max_addr, *addr; + + n = len - sizeof(unsigned long); + max_addr = KI_USER_SHARED_DATA + sizeof(kuser_shared_data); + for (i = 0; i < n; i++) { + addr = (unsigned long *)(img + i); + if (*addr >= KI_USER_SHARED_DATA && *addr < max_addr) { + *addr -= KI_USER_SHARED_DATA; + *addr += (unsigned long)&kuser_shared_data; + } + } +} +#endif + +/* + * Loader routine for actual Windows driver modules, ultimately + * calls the driver's DriverEntry() routine. + */ + +int +windrv_load(mod, img, len, bustype, devlist, regvals) + module_t mod; + vm_offset_t img; + int len; + interface_type bustype; + void *devlist; + ndis_cfg *regvals; +{ + image_import_descriptor imp_desc; + image_optional_header opt_hdr; + driver_entry entry; + struct drvdb_ent *new; + struct driver_object *drv; + int status; + uint32_t *ptr; + ansi_string as; + + /* + * First step: try to relocate and dynalink the executable + * driver image. + */ + + ptr = (uint32_t *)(img + 8); + if (*ptr == WINDRV_LOADED) + goto skipreloc; + + /* Perform text relocation */ + if (pe_relocate(img)) + return (ENOEXEC); + + /* Dynamically link the NDIS.SYS routines -- required. */ + if (pe_patch_imports(img, "NDIS", ndis_functbl)) + return (ENOEXEC); + + /* Dynamically link the HAL.dll routines -- optional. */ + if (pe_get_import_descriptor(img, &imp_desc, "HAL") == 0) { + if (pe_patch_imports(img, "HAL", hal_functbl)) + return (ENOEXEC); + } + + /* Dynamically link ntoskrnl.exe -- optional. */ + if (pe_get_import_descriptor(img, &imp_desc, "ntoskrnl") == 0) { + if (pe_patch_imports(img, "ntoskrnl", ntoskrnl_functbl)) + return (ENOEXEC); + } + +#ifdef __amd64__ + patch_user_shared_data_address(img, len); +#endif + + /* Dynamically link USBD.SYS -- optional */ + if (pe_get_import_descriptor(img, &imp_desc, "USBD") == 0) { + if (pe_patch_imports(img, "USBD", usbd_functbl)) + return (ENOEXEC); + } + + *ptr = WINDRV_LOADED; + +skipreloc: + + /* Next step: find the driver entry point. */ + + pe_get_optional_header(img, &opt_hdr); + entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr); + + /* Next step: allocate and store a driver object. */ + + new = malloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT|M_ZERO); + if (new == NULL) + return (ENOMEM); + + drv = malloc(sizeof(driver_object), M_DEVBUF, M_NOWAIT|M_ZERO); + if (drv == NULL) { + free (new, M_DEVBUF); + return (ENOMEM); + } + + /* Allocate a driver extension structure too. */ + + drv->dro_driverext = malloc(sizeof(driver_extension), + M_DEVBUF, M_NOWAIT|M_ZERO); + + if (drv->dro_driverext == NULL) { + free(new, M_DEVBUF); + free(drv, M_DEVBUF); + return (ENOMEM); + } + + InitializeListHead((&drv->dro_driverext->dre_usrext)); + + drv->dro_driverstart = (void *)img; + drv->dro_driversize = len; + + RtlInitAnsiString(&as, DUMMY_REGISTRY_PATH); + if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE)) { + free(new, M_DEVBUF); + free(drv, M_DEVBUF); + return (ENOMEM); + } + + new->windrv_object = drv; + new->windrv_regvals = regvals; + new->windrv_devlist = devlist; + new->windrv_bustype = bustype; + + /* Now call the DriverEntry() function. */ + + status = MSCALL2(entry, drv, &drv->dro_drivername); + + if (status != STATUS_SUCCESS) { + RtlFreeUnicodeString(&drv->dro_drivername); + free(drv, M_DEVBUF); + free(new, M_DEVBUF); + return (ENODEV); + } + + mtx_lock(&drvdb_mtx); + STAILQ_INSERT_HEAD(&drvdb_head, new, link); + mtx_unlock(&drvdb_mtx); + + return (0); +} + +/* + * Make a new Physical Device Object for a device that was + * detected/plugged in. For us, the PDO is just a way to + * get at the device_t. + */ + +int +windrv_create_pdo(drv, bsddev) + driver_object *drv; + device_t bsddev; +{ + device_object *dev; + + /* + * This is a new physical device object, which technically + * is the "top of the stack." Consequently, we don't do + * an IoAttachDeviceToDeviceStack() here. + */ + + mtx_lock(&drvdb_mtx); + IoCreateDevice(drv, 0, NULL, FILE_DEVICE_UNKNOWN, 0, FALSE, &dev); + mtx_unlock(&drvdb_mtx); + + /* Stash pointer to our BSD device handle. */ + + dev->do_devext = bsddev; + + return (STATUS_SUCCESS); +} + +void +windrv_destroy_pdo(drv, bsddev) + driver_object *drv; + device_t bsddev; +{ + device_object *pdo; + + pdo = windrv_find_pdo(drv, bsddev); + + /* Remove reference to device_t */ + + pdo->do_devext = NULL; + + mtx_lock(&drvdb_mtx); + IoDeleteDevice(pdo); + mtx_unlock(&drvdb_mtx); +} + +/* + * Given a device_t, find the corresponding PDO in a driver's + * device list. + */ + +device_object * +windrv_find_pdo(drv, bsddev) + driver_object *drv; + device_t bsddev; +{ + device_object *pdo; + + mtx_lock(&drvdb_mtx); + pdo = drv->dro_devobj; + while (pdo != NULL) { + if (pdo->do_devext == bsddev) { + mtx_unlock(&drvdb_mtx); + return (pdo); + } + pdo = pdo->do_nextdev; + } + mtx_unlock(&drvdb_mtx); + + return (NULL); +} + +/* + * Add an internally emulated driver to the database. We need this + * to set up an emulated bus driver so that it can receive IRPs. + */ + +int +windrv_bus_attach(drv, name) + driver_object *drv; + char *name; +{ + struct drvdb_ent *new; + ansi_string as; + + new = malloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT|M_ZERO); + if (new == NULL) + return (ENOMEM); + + RtlInitAnsiString(&as, name); + if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE)) + { + free(new, M_DEVBUF); + return (ENOMEM); + } + + /* + * Set up a fake image pointer to avoid false matches + * in windrv_lookup(). + */ + drv->dro_driverstart = (void *)0xFFFFFFFF; + + new->windrv_object = drv; + new->windrv_devlist = NULL; + new->windrv_regvals = NULL; + + mtx_lock(&drvdb_mtx); + STAILQ_INSERT_HEAD(&drvdb_head, new, link); + mtx_unlock(&drvdb_mtx); + + return (0); +} + +#ifdef __amd64__ + +extern void x86_64_wrap(void); +extern void x86_64_wrap_call(void); +extern void x86_64_wrap_end(void); + +int +windrv_wrap(func, wrap, argcnt, ftype) + funcptr func; + funcptr *wrap; + int argcnt; + int ftype; +{ + funcptr p; + vm_offset_t *calladdr; + vm_offset_t wrapstart, wrapend, wrapcall; + + wrapstart = (vm_offset_t)&x86_64_wrap; + wrapend = (vm_offset_t)&x86_64_wrap_end; + wrapcall = (vm_offset_t)&x86_64_wrap_call; + + /* Allocate a new wrapper instance. */ + + p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT); + if (p == NULL) + return (ENOMEM); + + /* Copy over the code. */ + + bcopy((char *)wrapstart, p, (wrapend - wrapstart)); + + /* Insert the function address into the new wrapper instance. */ + + calladdr = (uint64_t *)((char *)p + (wrapcall - wrapstart) + 2); + *calladdr = (vm_offset_t)func; + + *wrap = p; + + return (0); +} +#endif /* __amd64__ */ + + +#ifdef __i386__ + +struct x86desc { + uint16_t x_lolimit; + uint16_t x_base0; + uint8_t x_base1; + uint8_t x_flags; + uint8_t x_hilimit; + uint8_t x_base2; +}; + +struct gdt { + uint16_t limit; + void *base; +} __attribute__((__packed__)); + +extern uint16_t x86_getfs(void); +extern void x86_setfs(uint16_t); +extern void *x86_gettid(void); +extern void x86_critical_enter(void); +extern void x86_critical_exit(void); +extern void x86_getldt(struct gdt *, uint16_t *); +extern void x86_setldt(struct gdt *, uint16_t); + +#define SEL_LDT 4 /* local descriptor table */ +#define SEL_TO_FS(x) (((x) << 3)) + +/* + * FreeBSD 6.0 and later has a special GDT segment reserved + * specifically for us, so if GNDIS_SEL is defined, use that. + * If not, use GTGATE_SEL, which is uninitialized and infrequently + * used. + */ + +#ifdef GNDIS_SEL +#define FREEBSD_EMPTYSEL GNDIS_SEL +#else +#define FREEBSD_EMPTYSEL GTGATE_SEL /* slot 7 */ +#endif + +/* + * The meanings of various bits in a descriptor vary a little + * depending on whether the descriptor will be used as a + * code, data or system descriptor. (And that in turn depends + * on which segment register selects the descriptor.) + * We're only trying to create a data segment, so the definitions + * below are the ones that apply to a data descriptor. + */ + +#define SEGFLAGLO_PRESENT 0x80 /* segment is present */ +#define SEGFLAGLO_PRIVLVL 0x60 /* privlevel needed for this seg */ +#define SEGFLAGLO_CD 0x10 /* 1 = code/data, 0 = system */ +#define SEGFLAGLO_MBZ 0x08 /* must be zero */ +#define SEGFLAGLO_EXPANDDOWN 0x04 /* limit expands down */ +#define SEGFLAGLO_WRITEABLE 0x02 /* segment is writeable */ +#define SEGGLAGLO_ACCESSED 0x01 /* segment has been accessed */ + +#define SEGFLAGHI_GRAN 0x80 /* granularity, 1 = byte, 0 = page */ +#define SEGFLAGHI_BIG 0x40 /* 1 = 32 bit stack, 0 = 16 bit */ + +/* + * Context switch from UNIX to Windows. Save the existing value + * of %fs for this processor, then change it to point to our + * fake TID. Note that it is also possible to pin ourselves + * to our current CPU, though I'm not sure this is really + * necessary. It depends on whether or not an interrupt might + * preempt us while Windows code is running and we wind up + * scheduled onto another CPU as a result. So far, it doesn't + * seem like this is what happens. + */ + +void +ctxsw_utow(void) +{ + struct tid *t; + + t = &my_tids[curthread->td_oncpu]; + + /* + * Ugly hack. During system bootstrap (cold == 1), only CPU 0 + * is running. So if we were loaded at bootstrap, only CPU 0 + * will have our special GDT entry. This is a problem for SMP + * systems, so to deal with this, we check here to make sure + * the TID for this processor has been initialized, and if it + * hasn't, we need to do it right now or else things will + * explode. + */ + + if (t->tid_self != t) + x86_newldt(NULL); + + x86_critical_enter(); + t->tid_oldfs = x86_getfs(); + t->tid_cpu = curthread->td_oncpu; + sched_pin(); + x86_setfs(SEL_TO_FS(t->tid_selector)); + x86_critical_exit(); + + /* Now entering Windows land, population: you. */ +} + +/* + * Context switch from Windows back to UNIX. Restore %fs to + * its previous value. This always occurs after a call to + * ctxsw_utow(). + */ + +void +ctxsw_wtou(void) +{ + struct tid *t; + + x86_critical_enter(); + t = x86_gettid(); + x86_setfs(t->tid_oldfs); + sched_unpin(); + x86_critical_exit(); + + /* Welcome back to UNIX land, we missed you. */ + +#ifdef EXTRA_SANITY + if (t->tid_cpu != curthread->td_oncpu) + panic("ctxsw GOT MOVED TO OTHER CPU!"); +#endif +} + +static int windrv_wrap_stdcall(funcptr, funcptr *, int); +static int windrv_wrap_fastcall(funcptr, funcptr *, int); +static int windrv_wrap_regparm(funcptr, funcptr *); + +extern void x86_fastcall_wrap(void); +extern void x86_fastcall_wrap_call(void); +extern void x86_fastcall_wrap_arg(void); +extern void x86_fastcall_wrap_end(void); + +static int +windrv_wrap_fastcall(func, wrap, argcnt) + funcptr func; + funcptr *wrap; + int8_t argcnt; +{ + funcptr p; + vm_offset_t *calladdr; + uint8_t *argaddr; + vm_offset_t wrapstart, wrapend, wrapcall, wraparg; + + wrapstart = (vm_offset_t)&x86_fastcall_wrap; + wrapend = (vm_offset_t)&x86_fastcall_wrap_end; + wrapcall = (vm_offset_t)&x86_fastcall_wrap_call; + wraparg = (vm_offset_t)&x86_fastcall_wrap_arg; + + /* Allocate a new wrapper instance. */ + + p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT); + if (p == NULL) + return (ENOMEM); + + /* Copy over the code. */ + + bcopy((char *)wrapstart, p, (wrapend - wrapstart)); + + /* Insert the function address into the new wrapper instance. */ + + calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1)); + *calladdr = (vm_offset_t)func; + + argcnt -= 2; + if (argcnt < 1) + argcnt = 0; + + argaddr = (u_int8_t *)((char *)p + ((wraparg - wrapstart) + 1)); + *argaddr = argcnt * sizeof(uint32_t); + + *wrap = p; + + return (0); +} + +extern void x86_stdcall_wrap(void); +extern void x86_stdcall_wrap_call(void); +extern void x86_stdcall_wrap_arg(void); +extern void x86_stdcall_wrap_end(void); + +static int +windrv_wrap_stdcall(func, wrap, argcnt) + funcptr func; + funcptr *wrap; + uint8_t argcnt; +{ + funcptr p; + vm_offset_t *calladdr; + uint8_t *argaddr; + vm_offset_t wrapstart, wrapend, wrapcall, wraparg; + + wrapstart = (vm_offset_t)&x86_stdcall_wrap; + wrapend = (vm_offset_t)&x86_stdcall_wrap_end; + wrapcall = (vm_offset_t)&x86_stdcall_wrap_call; + wraparg = (vm_offset_t)&x86_stdcall_wrap_arg; + + /* Allocate a new wrapper instance. */ + + p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT); + if (p == NULL) + return (ENOMEM); + + /* Copy over the code. */ + + bcopy((char *)wrapstart, p, (wrapend - wrapstart)); + + /* Insert the function address into the new wrapper instance. */ + + calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1)); + *calladdr = (vm_offset_t)func; + + argaddr = (u_int8_t *)((char *)p + ((wraparg - wrapstart) + 1)); + *argaddr = argcnt * sizeof(uint32_t); + + *wrap = p; + + return (0); +} + +extern void x86_regparm_wrap(void); +extern void x86_regparm_wrap_call(void); +extern void x86_regparm_wrap_end(void); + +static int +windrv_wrap_regparm(func, wrap) + funcptr func; + funcptr *wrap; +{ + funcptr p; + vm_offset_t *calladdr; + vm_offset_t wrapstart, wrapend, wrapcall; + + wrapstart = (vm_offset_t)&x86_regparm_wrap; + wrapend = (vm_offset_t)&x86_regparm_wrap_end; + wrapcall = (vm_offset_t)&x86_regparm_wrap_call; + + /* Allocate a new wrapper instance. */ + + p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT); + if (p == NULL) + return (ENOMEM); + + /* Copy over the code. */ + + bcopy(x86_regparm_wrap, p, (wrapend - wrapstart)); + + /* Insert the function address into the new wrapper instance. */ + + calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1)); + *calladdr = (vm_offset_t)func; + + *wrap = p; + + return (0); +} + +int +windrv_wrap(func, wrap, argcnt, ftype) + funcptr func; + funcptr *wrap; + int argcnt; + int ftype; +{ + switch(ftype) { + case WINDRV_WRAP_FASTCALL: + return (windrv_wrap_fastcall(func, wrap, argcnt)); + case WINDRV_WRAP_STDCALL: + return (windrv_wrap_stdcall(func, wrap, argcnt)); + case WINDRV_WRAP_REGPARM: + return (windrv_wrap_regparm(func, wrap)); + case WINDRV_WRAP_CDECL: + return (windrv_wrap_stdcall(func, wrap, 0)); + default: + break; + } + + return (EINVAL); +} + +static void +x86_oldldt(dummy) + void *dummy; +{ + struct x86desc *gdt; + struct gdt gtable; + uint16_t ltable; + + mtx_lock_spin(&dt_lock); + + /* Grab location of existing GDT. */ + + x86_getldt(>able, <able); + + /* Find the slot we updated. */ + + gdt = gtable.base; + gdt += FREEBSD_EMPTYSEL; + + /* Empty it out. */ + + bzero((char *)gdt, sizeof(struct x86desc)); + + /* Restore GDT. */ + + x86_setldt(>able, ltable); + + mtx_unlock_spin(&dt_lock); +} + +static void +x86_newldt(dummy) + void *dummy; +{ + struct gdt gtable; + uint16_t ltable; + struct x86desc *l; + struct thread *t; + + t = curthread; + + mtx_lock_spin(&dt_lock); + + /* Grab location of existing GDT. */ + + x86_getldt(>able, <able); + + /* Get pointer to the GDT table. */ + + l = gtable.base; + + /* Get pointer to empty slot */ + + l += FREEBSD_EMPTYSEL; + + /* Initialize TID for this CPU. */ + + my_tids[t->td_oncpu].tid_selector = FREEBSD_EMPTYSEL; + my_tids[t->td_oncpu].tid_self = &my_tids[t->td_oncpu]; + + /* Set up new GDT entry. */ + + l->x_lolimit = sizeof(struct tid); + l->x_hilimit = SEGFLAGHI_GRAN|SEGFLAGHI_BIG; + l->x_base0 = (vm_offset_t)(&my_tids[t->td_oncpu]) & 0xFFFF; + l->x_base1 = ((vm_offset_t)(&my_tids[t->td_oncpu]) >> 16) & 0xFF; + l->x_base2 = ((vm_offset_t)(&my_tids[t->td_oncpu]) >> 24) & 0xFF; + l->x_flags = SEGFLAGLO_PRESENT|SEGFLAGLO_CD|SEGFLAGLO_WRITEABLE; + + /* Update the GDT. */ + + x86_setldt(>able, ltable); + + mtx_unlock_spin(&dt_lock); + + /* Whew. */ +} + +#endif /* __i386__ */ + +int +windrv_unwrap(func) + funcptr func; +{ + free(func, M_DEVBUF); + + return (0); +} diff --git a/sys/compat/ndis/ndis_var.h b/sys/compat/ndis/ndis_var.h new file mode 100644 index 0000000..2692e54 --- /dev/null +++ b/sys/compat/ndis/ndis_var.h @@ -0,0 +1,1767 @@ +/*- + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.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, 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 Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD + * 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 _NDIS_VAR_H_ +#define _NDIS_VAR_H_ + +/* Forward declarations */ +struct ndis_miniport_block; +struct ndis_mdriver_block; +typedef struct ndis_miniport_block ndis_miniport_block; +typedef struct ndis_mdriver_block ndis_mdriver_block; + +/* Base types */ +typedef uint32_t ndis_status; +typedef void *ndis_handle; +typedef uint32_t ndis_oid; +typedef uint32_t ndis_error_code; +typedef register_t ndis_kspin_lock; +typedef uint8_t ndis_kirql; + +/* + * NDIS status codes (there are lots of them). The ones that + * don't seem to fit the pattern are actually mapped to generic + * NT status codes. + */ + +#define NDIS_STATUS_SUCCESS 0 +#define NDIS_STATUS_PENDING 0x00000103 +#define NDIS_STATUS_NOT_RECOGNIZED 0x00010001 +#define NDIS_STATUS_NOT_COPIED 0x00010002 +#define NDIS_STATUS_NOT_ACCEPTED 0x00010003 +#define NDIS_STATUS_CALL_ACTIVE 0x00010007 +#define NDIS_STATUS_ONLINE 0x40010003 +#define NDIS_STATUS_RESET_START 0x40010004 +#define NDIS_STATUS_RESET_END 0x40010005 +#define NDIS_STATUS_RING_STATUS 0x40010006 +#define NDIS_STATUS_CLOSED 0x40010007 +#define NDIS_STATUS_WAN_LINE_UP 0x40010008 +#define NDIS_STATUS_WAN_LINE_DOWN 0x40010009 +#define NDIS_STATUS_WAN_FRAGMENT 0x4001000A +#define NDIS_STATUS_MEDIA_CONNECT 0x4001000B +#define NDIS_STATUS_MEDIA_DISCONNECT 0x4001000C +#define NDIS_STATUS_HARDWARE_LINE_UP 0x4001000D +#define NDIS_STATUS_HARDWARE_LINE_DOWN 0x4001000E +#define NDIS_STATUS_INTERFACE_UP 0x4001000F +#define NDIS_STATUS_INTERFACE_DOWN 0x40010010 +#define NDIS_STATUS_MEDIA_BUSY 0x40010011 +#define NDIS_STATUS_MEDIA_SPECIFIC_INDICATION 0x40010012 +#define NDIS_STATUS_WW_INDICATION NDIS_STATUS_MEDIA_SPECIFIC_INDICATION +#define NDIS_STATUS_LINK_SPEED_CHANGE 0x40010013 +#define NDIS_STATUS_WAN_GET_STATS 0x40010014 +#define NDIS_STATUS_WAN_CO_FRAGMENT 0x40010015 +#define NDIS_STATUS_WAN_CO_LINKPARAMS 0x40010016 +#define NDIS_STATUS_NOT_RESETTABLE 0x80010001 +#define NDIS_STATUS_SOFT_ERRORS 0x80010003 +#define NDIS_STATUS_HARD_ERRORS 0x80010004 +#define NDIS_STATUS_BUFFER_OVERFLOW 0x80000005 +#define NDIS_STATUS_FAILURE 0xC0000001 +#define NDIS_STATUS_RESOURCES 0xC000009A +#define NDIS_STATUS_CLOSING 0xC0010002 +#define NDIS_STATUS_BAD_VERSION 0xC0010004 +#define NDIS_STATUS_BAD_CHARACTERISTICS 0xC0010005 +#define NDIS_STATUS_ADAPTER_NOT_FOUND 0xC0010006 +#define NDIS_STATUS_OPEN_FAILED 0xC0010007 +#define NDIS_STATUS_DEVICE_FAILED 0xC0010008 +#define NDIS_STATUS_MULTICAST_FULL 0xC0010009 +#define NDIS_STATUS_MULTICAST_EXISTS 0xC001000A +#define NDIS_STATUS_MULTICAST_NOT_FOUND 0xC001000B +#define NDIS_STATUS_REQUEST_ABORTED 0xC001000C +#define NDIS_STATUS_RESET_IN_PROGRESS 0xC001000D +#define NDIS_STATUS_CLOSING_INDICATING 0xC001000E +#define NDIS_STATUS_NOT_SUPPORTED 0xC00000BB +#define NDIS_STATUS_INVALID_PACKET 0xC001000F +#define NDIS_STATUS_OPEN_LIST_FULL 0xC0010010 +#define NDIS_STATUS_ADAPTER_NOT_READY 0xC0010011 +#define NDIS_STATUS_ADAPTER_NOT_OPEN 0xC0010012 +#define NDIS_STATUS_NOT_INDICATING 0xC0010013 +#define NDIS_STATUS_INVALID_LENGTH 0xC0010014 +#define NDIS_STATUS_INVALID_DATA 0xC0010015 +#define NDIS_STATUS_BUFFER_TOO_SHORT 0xC0010016 +#define NDIS_STATUS_INVALID_OID 0xC0010017 +#define NDIS_STATUS_ADAPTER_REMOVED 0xC0010018 +#define NDIS_STATUS_UNSUPPORTED_MEDIA 0xC0010019 +#define NDIS_STATUS_GROUP_ADDRESS_IN_USE 0xC001001A +#define NDIS_STATUS_FILE_NOT_FOUND 0xC001001B +#define NDIS_STATUS_ERROR_READING_FILE 0xC001001C +#define NDIS_STATUS_ALREADY_MAPPED 0xC001001D +#define NDIS_STATUS_RESOURCE_CONFLICT 0xC001001E +#define NDIS_STATUS_NO_CABLE 0xC001001F +#define NDIS_STATUS_INVALID_SAP 0xC0010020 +#define NDIS_STATUS_SAP_IN_USE 0xC0010021 +#define NDIS_STATUS_INVALID_ADDRESS 0xC0010022 +#define NDIS_STATUS_VC_NOT_ACTIVATED 0xC0010023 +#define NDIS_STATUS_DEST_OUT_OF_ORDER 0xC0010024 +#define NDIS_STATUS_VC_NOT_AVAILABLE 0xC0010025 +#define NDIS_STATUS_CELLRATE_NOT_AVAILABLE 0xC0010026 +#define NDIS_STATUS_INCOMPATABLE_QOS 0xC0010027 +#define NDIS_STATUS_AAL_PARAMS_UNSUPPORTED 0xC0010028 +#define NDIS_STATUS_NO_ROUTE_TO_DESTINATION 0xC0010029 +#define NDIS_STATUS_TOKEN_RING_OPEN_ERROR 0xC0011000 +#define NDIS_STATUS_INVALID_DEVICE_REQUEST 0xC0000010 +#define NDIS_STATUS_NETWORK_UNREACHABLE 0xC000023C + +/* + * NDIS event codes. They are usually reported to NdisWriteErrorLogEntry(). + */ + +#define EVENT_NDIS_RESOURCE_CONFLICT 0xC0001388 +#define EVENT_NDIS_OUT_OF_RESOURCE 0xC0001389 +#define EVENT_NDIS_HARDWARE_FAILURE 0xC000138A +#define EVENT_NDIS_ADAPTER_NOT_FOUND 0xC000138B +#define EVENT_NDIS_INTERRUPT_CONNECT 0xC000138C +#define EVENT_NDIS_DRIVER_FAILURE 0xC000138D +#define EVENT_NDIS_BAD_VERSION 0xC000138E +#define EVENT_NDIS_TIMEOUT 0x8000138F +#define EVENT_NDIS_NETWORK_ADDRESS 0xC0001390 +#define EVENT_NDIS_UNSUPPORTED_CONFIGURATION 0xC0001391 +#define EVENT_NDIS_INVALID_VALUE_FROM_ADAPTER 0xC0001392 +#define EVENT_NDIS_MISSING_CONFIGURATION_PARAMETER 0xC0001393 +#define EVENT_NDIS_BAD_IO_BASE_ADDRESS 0xC0001394 +#define EVENT_NDIS_RECEIVE_SPACE_SMALL 0x40001395 +#define EVENT_NDIS_ADAPTER_DISABLED 0x80001396 +#define EVENT_NDIS_IO_PORT_CONFLICT 0x80001397 +#define EVENT_NDIS_PORT_OR_DMA_CONFLICT 0x80001398 +#define EVENT_NDIS_MEMORY_CONFLICT 0x80001399 +#define EVENT_NDIS_INTERRUPT_CONFLICT 0x8000139A +#define EVENT_NDIS_DMA_CONFLICT 0x8000139B +#define EVENT_NDIS_INVALID_DOWNLOAD_FILE_ERROR 0xC000139C +#define EVENT_NDIS_MAXRECEIVES_ERROR 0x8000139D +#define EVENT_NDIS_MAXTRANSMITS_ERROR 0x8000139E +#define EVENT_NDIS_MAXFRAMESIZE_ERROR 0x8000139F +#define EVENT_NDIS_MAXINTERNALBUFS_ERROR 0x800013A0 +#define EVENT_NDIS_MAXMULTICAST_ERROR 0x800013A1 +#define EVENT_NDIS_PRODUCTID_ERROR 0x800013A2 +#define EVENT_NDIS_LOBE_FAILUE_ERROR 0x800013A3 +#define EVENT_NDIS_SIGNAL_LOSS_ERROR 0x800013A4 +#define EVENT_NDIS_REMOVE_RECEIVED_ERROR 0x800013A5 +#define EVENT_NDIS_TOKEN_RING_CORRECTION 0x400013A6 +#define EVENT_NDIS_ADAPTER_CHECK_ERROR 0xC00013A7 +#define EVENT_NDIS_RESET_FAILURE_ERROR 0x800013A8 +#define EVENT_NDIS_CABLE_DISCONNECTED_ERROR 0x800013A9 +#define EVENT_NDIS_RESET_FAILURE_CORRECTION 0x800013AA + +/* + * NDIS OIDs used by the queryinfo/setinfo routines. + * Some are required by all NDIS drivers, some are specific to + * a particular type of device, and some are purely optional. + * Unfortunately, one of the purely optional OIDs is the one + * that lets us set the MAC address of the device. + */ + +/* Required OIDs */ +#define OID_GEN_SUPPORTED_LIST 0x00010101 +#define OID_GEN_HARDWARE_STATUS 0x00010102 +#define OID_GEN_MEDIA_SUPPORTED 0x00010103 +#define OID_GEN_MEDIA_IN_USE 0x00010104 +#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105 +#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106 +#define OID_GEN_LINK_SPEED 0x00010107 +#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108 +#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109 +#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A +#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B +#define OID_GEN_VENDOR_ID 0x0001010C +#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D +#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E +#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F +#define OID_GEN_DRIVER_VERSION 0x00010110 +#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111 +#define OID_GEN_PROTOCOL_OPTIONS 0x00010112 +#define OID_GEN_MAC_OPTIONS 0x00010113 +#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114 +#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115 +#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116 +#define OID_GEN_SUPPORTED_GUIDS 0x00010117 +#define OID_GEN_NETWORK_LAYER_ADDRESSES 0x00010118 /* Set only */ +#define OID_GEN_TRANSPORT_HEADER_OFFSET 0x00010119 /* Set only */ +#define OID_GEN_MACHINE_NAME 0x0001021A +#define OID_GEN_RNDIS_CONFIG_PARAMETER 0x0001021B /* Set only */ +#define OID_GEN_VLAN_ID 0x0001021C + +/* Optional OIDs. */ +#define OID_GEN_MEDIA_CAPABILITIES 0x00010201 +#define OID_GEN_PHYSICAL_MEDIUM 0x00010202 + +/* Required statistics OIDs. */ +#define OID_GEN_XMIT_OK 0x00020101 +#define OID_GEN_RCV_OK 0x00020102 +#define OID_GEN_XMIT_ERROR 0x00020103 +#define OID_GEN_RCV_ERROR 0x00020104 +#define OID_GEN_RCV_NO_BUFFER 0x00020105 + +/* Optional OID statistics */ +#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201 +#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202 +#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203 +#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204 +#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205 +#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206 +#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207 +#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208 +#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209 +#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A +#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B +#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C +#define OID_GEN_RCV_CRC_ERROR 0x0002020D +#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E +#define OID_GEN_GET_TIME_CAPS 0x0002020F +#define OID_GEN_GET_NETCARD_TIME 0x00020210 +#define OID_GEN_NETCARD_LOAD 0x00020211 +#define OID_GEN_DEVICE_PROFILE 0x00020212 + +/* 802.3 (ethernet) OIDs */ +#define OID_802_3_PERMANENT_ADDRESS 0x01010101 +#define OID_802_3_CURRENT_ADDRESS 0x01010102 +#define OID_802_3_MULTICAST_LIST 0x01010103 +#define OID_802_3_MAXIMUM_LIST_SIZE 0x01010104 +#define OID_802_3_MAC_OPTIONS 0x01010105 +#define NDIS_802_3_MAC_OPTION_PRIORITY 0x00000001 +#define OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101 +#define OID_802_3_XMIT_ONE_COLLISION 0x01020102 +#define OID_802_3_XMIT_MORE_COLLISIONS 0x01020103 +#define OID_802_3_XMIT_DEFERRED 0x01020201 +#define OID_802_3_XMIT_MAX_COLLISIONS 0x01020202 +#define OID_802_3_RCV_OVERRUN 0x01020203 +#define OID_802_3_XMIT_UNDERRUN 0x01020204 +#define OID_802_3_XMIT_HEARTBEAT_FAILURE 0x01020205 +#define OID_802_3_XMIT_TIMES_CRS_LOST 0x01020206 +#define OID_802_3_XMIT_LATE_COLLISIONS 0x01020207 + +/* PnP and power management OIDs */ +#define OID_PNP_CAPABILITIES 0xFD010100 +#define OID_PNP_SET_POWER 0xFD010101 +#define OID_PNP_QUERY_POWER 0xFD010102 +#define OID_PNP_ADD_WAKE_UP_PATTERN 0xFD010103 +#define OID_PNP_REMOVE_WAKE_UP_PATTERN 0xFD010104 +#define OID_PNP_WAKE_UP_PATTERN_LIST 0xFD010105 +#define OID_PNP_ENABLE_WAKE_UP 0xFD010106 + +/* + * These are the possible power states for + * OID_PNP_SET_POWER and OID_PNP_QUERY_POWER. + */ +#define NDIS_POWERSTATE_UNSPEC 0 +#define NDIS_POWERSTATE_D0 1 +#define NDIS_POWERSTATE_D1 2 +#define NDIS_POWERSTATE_D2 3 +#define NDIS_POWERSTATE_D3 4 + +/* + * These are used with the MiniportPnpEventNotify() method. + */ + +#define NDIS_POWERPROFILE_BATTERY 0 +#define NDIS_POWERPROFILE_ACONLINE 1 + +#define NDIS_PNP_EVENT_QUERY_REMOVED 0 +#define NDIS_PNP_EVENT_REMOVED 1 +#define NDIS_PNP_EVENT_SURPRISE_REMOVED 2 +#define NDIS_PNP_EVENT_QUERY_STOPPED 3 +#define NDIS_PNP_EVENT_STOPPED 4 +#define NDIS_PNP_EVENT_PROFILECHANGED 5 + + +/* PnP/PM Statistics (Optional). */ +#define OID_PNP_WAKE_UP_OK 0xFD020200 +#define OID_PNP_WAKE_UP_ERROR 0xFD020201 + +/* The following bits are defined for OID_PNP_ENABLE_WAKE_UP */ +#define NDIS_PNP_WAKE_UP_MAGIC_PACKET 0x00000001 +#define NDIS_PNP_WAKE_UP_PATTERN_MATCH 0x00000002 +#define NDIS_PNP_WAKE_UP_LINK_CHANGE 0x00000004 + +/* 802.11 OIDs */ +#define OID_802_11_BSSID 0x0D010101 +#define OID_802_11_SSID 0x0D010102 +#define OID_802_11_NETWORK_TYPES_SUPPORTED 0x0D010203 +#define OID_802_11_NETWORK_TYPE_IN_USE 0x0D010204 +#define OID_802_11_TX_POWER_LEVEL 0x0D010205 +#define OID_802_11_RSSI 0x0D010206 +#define OID_802_11_RSSI_TRIGGER 0x0D010207 +#define OID_802_11_INFRASTRUCTURE_MODE 0x0D010108 +#define OID_802_11_FRAGMENTATION_THRESHOLD 0x0D010209 +#define OID_802_11_RTS_THRESHOLD 0x0D01020A +#define OID_802_11_NUMBER_OF_ANTENNAS 0x0D01020B +#define OID_802_11_RX_ANTENNA_SELECTED 0x0D01020C +#define OID_802_11_TX_ANTENNA_SELECTED 0x0D01020D +#define OID_802_11_SUPPORTED_RATES 0x0D01020E +#define OID_802_11_DESIRED_RATES 0x0D010210 +#define OID_802_11_CONFIGURATION 0x0D010211 +#define OID_802_11_STATISTICS 0x0D020212 +#define OID_802_11_ADD_WEP 0x0D010113 +#define OID_802_11_REMOVE_WEP 0x0D010114 +#define OID_802_11_DISASSOCIATE 0x0D010115 +#define OID_802_11_POWER_MODE 0x0D010216 +#define OID_802_11_BSSID_LIST 0x0D010217 +#define OID_802_11_AUTHENTICATION_MODE 0x0D010118 +#define OID_802_11_PRIVACY_FILTER 0x0D010119 +#define OID_802_11_BSSID_LIST_SCAN 0x0D01011A +#define OID_802_11_WEP_STATUS 0x0D01011B +#define OID_802_11_ENCRYPTION_STATUS OID_802_11_WEP_STATUS +#define OID_802_11_RELOAD_DEFAULTS 0x0D01011C +#define OID_802_11_ADD_KEY 0x0D01011D +#define OID_802_11_REMOVE_KEY 0x0D01011E +#define OID_802_11_ASSOCIATION_INFORMATION 0x0D01011F +#define OID_802_11_TEST 0x0D010120 +#define OID_802_11_CAPABILITY 0x0D010122 +#define OID_802_11_PMKID 0x0D010123 + +/* structures/definitions for 802.11 */ +#define NDIS_80211_NETTYPE_11FH 0x00000000 +#define NDIS_80211_NETTYPE_11DS 0x00000001 +#define NDIS_80211_NETTYPE_11OFDM5 0x00000002 +#define NDIS_80211_NETTYPE_11OFDM24 0x00000003 +#define NDIS_80211_NETTYPE_AUTO 0x00000004 + +struct ndis_80211_nettype_list { + uint32_t ntl_items; + uint32_t ntl_type[1]; +}; + +#define NDIS_80211_POWERMODE_CAM 0x00000000 +#define NDIS_80211_POWERMODE_MAX_PSP 0x00000001 +#define NDIS_80211_POWERMODE_FAST_PSP 0x00000002 + +typedef uint32_t ndis_80211_power; /* Power in milliwatts */ +typedef uint32_t ndis_80211_rssi; /* Signal strength in dBm */ + +struct ndis_80211_config_fh { + uint32_t ncf_length; + uint32_t ncf_hoppatterh; + uint32_t ncf_hopset; + uint32_t ncf_dwelltime; +}; + +typedef struct ndis_80211_config_fh ndis_80211_config_fh; + +struct ndis_80211_config { + uint32_t nc_length; + uint32_t nc_beaconperiod; + uint32_t nc_atimwin; + uint32_t nc_dsconfig; + ndis_80211_config_fh nc_fhconfig; +}; + +typedef struct ndis_80211_config ndis_80211_config; + +struct ndis_80211_stats { + uint32_t ns_length; + uint64_t ns_txfragcnt; + uint64_t ns_txmcastcnt; + uint64_t ns_failedcnt; + uint64_t ns_retrycnt; + uint64_t ns_multiretrycnt; + uint64_t ns_rtssuccesscnt; + uint64_t ns_rtsfailcnt; + uint64_t ns_ackfailcnt; + uint64_t ns_dupeframecnt; + uint64_t ns_rxfragcnt; + uint64_t ns_rxmcastcnt; + uint64_t ns_fcserrcnt; +}; + +typedef struct ndis_80211_stats ndis_80211_stats; + +typedef uint32_t ndis_80211_key_idx; + +struct ndis_80211_wep { + uint32_t nw_length; + uint32_t nw_keyidx; + uint32_t nw_keylen; + uint8_t nw_keydata[256]; +}; + +typedef struct ndis_80211_wep ndis_80211_wep; + +#define NDIS_80211_WEPKEY_TX 0x80000000 +#define NDIS_80211_WEPKEY_PERCLIENT 0x40000000 + +#define NDIS_80211_NET_INFRA_IBSS 0x00000000 +#define NDIS_80211_NET_INFRA_BSS 0x00000001 +#define NDIS_80211_NET_INFRA_AUTO 0x00000002 + +#define NDIS_80211_AUTHMODE_OPEN 0x00000000 +#define NDIS_80211_AUTHMODE_SHARED 0x00000001 +#define NDIS_80211_AUTHMODE_AUTO 0x00000002 +#define NDIS_80211_AUTHMODE_WPA 0x00000003 +#define NDIS_80211_AUTHMODE_WPAPSK 0x00000004 +#define NDIS_80211_AUTHMODE_WPANONE 0x00000005 +#define NDIS_80211_AUTHMODE_WPA2 0x00000006 +#define NDIS_80211_AUTHMODE_WPA2PSK 0x00000007 + +typedef uint8_t ndis_80211_rates[8]; +typedef uint8_t ndis_80211_rates_ex[16]; +typedef uint8_t ndis_80211_macaddr[6]; + +struct ndis_80211_ssid { + uint32_t ns_ssidlen; + uint8_t ns_ssid[32]; +}; + +typedef struct ndis_80211_ssid ndis_80211_ssid; + +struct ndis_wlan_bssid { + uint32_t nwb_length; + ndis_80211_macaddr nwb_macaddr; + uint8_t nwb_rsvd[2]; + ndis_80211_ssid nwb_ssid; + uint32_t nwb_privacy; + ndis_80211_rssi nwb_rssi; + uint32_t nwb_nettype; + ndis_80211_config nwb_config; + uint32_t nwb_netinfra; + ndis_80211_rates nwb_supportedrates; +}; + +typedef struct ndis_wlan_bssid ndis_wlan_bssid; + +struct ndis_80211_bssid_list { + uint32_t nbl_items; + ndis_wlan_bssid nbl_bssid[1]; +}; + +typedef struct ndis_80211_bssid_list ndis_80211_bssid_list; + +struct ndis_wlan_bssid_ex { + uint32_t nwbx_len; + ndis_80211_macaddr nwbx_macaddr; + uint8_t nwbx_rsvd[2]; + ndis_80211_ssid nwbx_ssid; + uint32_t nwbx_privacy; + ndis_80211_rssi nwbx_rssi; + uint32_t nwbx_nettype; + ndis_80211_config nwbx_config; + uint32_t nwbx_netinfra; + ndis_80211_rates_ex nwbx_supportedrates; + uint32_t nwbx_ielen; + uint8_t nwbx_ies[1]; +}; + +typedef struct ndis_wlan_bssid_ex ndis_wlan_bssid_ex; + +struct ndis_80211_bssid_list_ex { + uint32_t nblx_items; + ndis_wlan_bssid_ex nblx_bssid[1]; +}; + +typedef struct ndis_80211_bssid_list_ex ndis_80211_bssid_list_ex; + +struct ndis_80211_fixed_ies { + uint8_t nfi_tstamp[8]; + uint16_t nfi_beaconint; + uint16_t nfi_caps; +}; + +struct ndis_80211_variable_ies { + uint8_t nvi_elemid; + uint8_t nvi_len; + uint8_t nvi_data[1]; +}; + +typedef uint32_t ndis_80211_fragthresh; +typedef uint32_t ndis_80211_rtsthresh; +typedef uint32_t ndis_80211_antenna; + +#define NDIS_80211_PRIVFILT_ACCEPTALL 0x00000000 +#define NDIS_80211_PRIVFILT_8021XWEP 0x00000001 + +#define NDIS_80211_WEPSTAT_ENABLED 0x00000000 +#define NDIS_80211_WEPSTAT_ENC1ENABLED NDIS_80211_WEPSTAT_ENABLED +#define NDIS_80211_WEPSTAT_DISABLED 0x00000001 +#define NDIS_80211_WEPSTAT_ENCDISABLED NDIS_80211_WEPSTAT_DISABLED +#define NDIS_80211_WEPSTAT_KEYABSENT 0x00000002 +#define NDIS_80211_WEPSTAT_ENC1KEYABSENT NDIS_80211_WEPSTAT_KEYABSENT +#define NDIS_80211_WEPSTAT_NOTSUPPORTED 0x00000003 +#define NDIS_80211_WEPSTAT_ENCNOTSUPPORTED NDIS_80211_WEPSTAT_NOTSUPPORTED +#define NDIS_80211_WEPSTAT_ENC2ENABLED 0x00000004 +#define NDIS_80211_WEPSTAT_ENC2KEYABSENT 0x00000005 +#define NDIS_80211_WEPSTAT_ENC3ENABLED 0x00000006 +#define NDIS_80211_WEPSTAT_ENC3KEYABSENT 0x00000007 + +#define NDIS_80211_RELOADDEFAULT_WEP 0x00000000 + +#define NDIS_80211_STATUSTYPE_AUTH 0x00000000 +#define NDIS_80211_STATUSTYPE_PMKIDLIST 0x00000001 + +struct ndis_80211_status_indication { + uint32_t nsi_type; +}; + +typedef struct ndis_80211_status_indication ndis_80211_status_indication; + +#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01 +#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02 +#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06 +#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E + +struct ndis_80211_auth_request { + uint32_t nar_len; + ndis_80211_macaddr nar_bssid; + uint32_t nar_flags; +}; + +typedef struct ndis_80211_auth_request ndis_80211_auth_request; + +struct ndis_80211_key { + uint32_t nk_len; + uint32_t nk_keyidx; + uint32_t nk_keylen; + ndis_80211_macaddr nk_bssid; + uint8_t nk_pad[6]; + uint64_t nk_keyrsc; + uint8_t nk_keydata[32]; +}; + +typedef struct ndis_80211_key ndis_80211_key; + +struct ndis_80211_remove_key { + uint32_t nk_len; + uint32_t nk_keyidx; + ndis_80211_macaddr nk_bssid; +}; + +typedef struct ndis_80211_remove_key ndis_80211_remove_key; + +#define NDIS_80211_AI_REQFI_CAPABILITIES 0x00000001 +#define NDIS_80211_AI_REQFI_LISTENINTERVAL 0x00000002 +#define NDIS_80211_AI_REQFI_CURRENTAPADDRESS 0x00000004 + +#define NDIS_80211_AI_RESFI_CAPABILITIES 0x00000001 +#define NDIS_80211_AI_RESFI_STATUSCODE 0x00000002 +#define NDIS_80211_AI_RESFI_ASSOCIATIONID 0x00000004 + +struct ndis_80211_ai_reqfi { + uint16_t naq_caps; + uint16_t naq_listentint; + ndis_80211_macaddr naq_currentapaddr; +}; + +typedef struct ndis_80211_ai_reqfi ndis_80211_ai_reqfi; + +struct ndis_80211_ai_resfi { + uint16_t nas_caps; + uint16_t nas_statuscode; + uint16_t nas_associd; +}; + +typedef struct ndis_80211_ai_resfi ndis_80211_ai_resfi; + +struct ndis_80211_assoc_info { + uint32_t nai_len; + uint16_t nai_avail_req_fixed_ies; + ndis_80211_ai_reqfi nai_req_fixed_ies; + uint32_t nai_req_ielen; + uint32_t nai_offset_req_ies; + uint16_t nai_avail_resp_fixed_ies; + ndis_80211_ai_resfi nai_resp_fixed_iex; + uint32_t nai_resp_ielen; + uint32_t nai_offset_resp_ies; +}; + +typedef struct ndis_80211_assoc_info ndis_80211_assoc_info; + +struct ndis_80211_auth_event { + ndis_80211_status_indication nae_status; + ndis_80211_auth_request nae_request[1]; +}; + +typedef struct ndis_80211_auth_event ndis_80211_auth_event; + +struct ndis_80211_test { + uint32_t nt_len; + uint32_t nt_type; + union { + ndis_80211_auth_event nt_authevent; + uint32_t nt_rssitrigger; + } u; +}; + +typedef struct ndis_80211_test ndis_80211_test; + +struct ndis_80211_auth_encrypt { + uint32_t ne_authmode; + uint32_t ne_cryptstat; +}; + +typedef struct ndis_80211_auth_encrypt ndis_80211_auth_encrypt; + +struct ndis_80211_caps { + uint32_t nc_len; + uint32_t nc_ver; + uint32_t nc_numpmkids; + ndis_80211_auth_encrypt nc_authencs[1]; +}; + +typedef struct ndis_80211_caps ndis_80211_caps; + +struct ndis_80211_bssidinfo { + ndis_80211_macaddr nb_bssid; + uint8_t nb_pmkid[16]; +}; + +typedef struct ndis_80211_bssidinfo ndis_80211_bssidinfo; + +struct ndis_80211_pmkid { + uint32_t np_len; + uint32_t np_bssidcnt; + ndis_80211_bssidinfo np_bssidinfo[1]; +}; + +typedef struct ndis_80211_pmkid ndis_80211_pmkid; + +struct ndis_80211_pmkid_cand { + ndis_80211_macaddr npc_bssid; + uint32_t npc_flags; +}; + +typedef struct ndis_80211_pmkid_cand ndis_80211_pmkid_cand; + +#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED (0x01) + +struct ndis_80211_pmkid_candidate_list { + uint32_t npcl_version; + uint32_t npcl_numcandidates; + ndis_80211_pmkid_cand npcl_candidatelist[1]; +}; + +typedef struct ndis_80211_pmkid_candidate_list ndis_80211_pmkid_candidate_list; + +struct ndis_80211_enc_indication { + uint32_t nei_statustype; + ndis_80211_pmkid_candidate_list nei_pmkidlist; +}; + +typedef struct ndis_80211_enc_indication ndis_80211_enc_indication; + +/* TCP OIDs. */ + +#define OID_TCP_TASK_OFFLOAD 0xFC010201 +#define OID_TCP_TASK_IPSEC_ADD_SA 0xFC010202 +#define OID_TCP_TASK_IPSEC_DELETE_SA 0xFC010203 +#define OID_TCP_SAN_SUPPORT 0xFC010204 + + +#define NDIS_TASK_OFFLOAD_VERSION 1 + +#define NDIS_TASK_TCPIP_CSUM 0x00000000 +#define NDIS_TASK_IPSEC 0x00000001 +#define NDIS_TASK_TCP_LARGESEND 0x00000002 + +#define NDIS_ENCAP_UNSPEC 0x00000000 +#define NDIS_ENCAP_NULL 0x00000001 +#define NDIS_ENCAP_IEEE802_3 0x00000002 +#define NDIS_ENCAP_IEEE802_5 0x00000003 +#define NDIS_ENCAP_SNAP_ROUTED 0x00000004 +#define NDIS_ENCAP_SNAP_BRIDGED 0x00000005 + +#define NDIS_ENCAPFLAG_FIXEDHDRLEN 0x00000001 + +struct ndis_encap_fmt { + uint32_t nef_encap; + uint32_t nef_flags; + uint32_t nef_encaphdrlen; +}; + +typedef struct ndis_encap_fmt ndis_encap_fmt; + +struct ndis_task_offload_hdr { + uint32_t ntoh_vers; + uint32_t ntoh_len; + uint32_t ntoh_rsvd; + uint32_t ntoh_offset_firsttask; + ndis_encap_fmt ntoh_encapfmt; +}; + +typedef struct ndis_task_offload_hdr ndis_task_offload_hdr; + +struct ndis_task_offload { + uint32_t nto_vers; + uint32_t nto_len; + uint32_t nto_task; + uint32_t nto_offset_nexttask; + uint32_t nto_taskbuflen; + uint8_t nto_taskbuf[1]; +}; + +typedef struct ndis_task_offload ndis_task_offload; + +#define NDIS_TCPSUM_FLAGS_IP_OPTS 0x00000001 +#define NDIS_TCPSUM_FLAGS_TCP_OPTS 0x00000002 +#define NDIS_TCPSUM_FLAGS_TCP_CSUM 0x00000004 +#define NDIS_TCPSUM_FLAGS_UDP_CSUM 0x00000008 +#define NDIS_TCPSUM_FLAGS_IP_CSUM 0x00000010 + +struct ndis_task_tcpip_csum { + uint32_t nttc_v4tx; + uint32_t nttc_v4rx; + uint32_t nttc_v6tx; + uint32_t nttc_v6rx; +}; + +typedef struct ndis_task_tcpip_csum ndis_task_tcpip_csum; + +struct ndis_task_tcp_largesend { + uint32_t nttl_vers; + uint32_t nttl_maxofflen; + uint32_t nttl_minsegcnt; + uint8_t nttl_tcpopt; + uint8_t nttl_ipopt; +}; + +typedef struct ndis_task_tcp_largesend ndis_task_tcp_largesend; + +#define NDIS_IPSEC_AH_MD5 0x00000001 +#define NDIS_IPSEC_AH_SHA1 0x00000002 +#define NDIS_IPSEC_AH_TRANSPORT 0x00000004 +#define NDIS_IPSEC_AH_TUNNEL 0x00000008 +#define NDIS_IPSEC_AH_SEND 0x00000010 +#define NDIS_IPSEC_AH_RECEIVE 0x00000020 + +#define NDIS_IPSEC_ESP_DES 0x00000001 +#define NDIS_IPSEC_ESP_RSVD 0x00000002 +#define NDIS_IPSEC_ESP_3DES 0x00000004 +#define NDIS_IPSEC_ESP_NULL 0x00000008 +#define NDIS_IPSEC_ESP_TRANSPORT 0x00000010 +#define NDIS_IPSEC_ESP_TUNNEL 0x00000020 +#define NDIS_IPSEC_ESP_SEND 0x00000040 +#define NDIS_IPSEC_ESP_RECEIVE 0x00000080 + +struct ndis_task_ipsec { + uint32_t nti_ah_esp_combined; + uint32_t nti_ah_transport_tunnel_combined; + uint32_t nti_v4_options; + uint32_t nti_rsvd; + uint32_t nti_v4ah; + uint32_t nti_v4esp; +}; + +typedef struct ndis_task_ipsec ndis_task_ipsec; + +/* + * Attribures of NDIS drivers. Not all drivers support + * all attributes. + */ + +#define NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT 0x00000001 +#define NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT 0x00000002 +#define NDIS_ATTRIBUTE_IGNORE_TOKEN_RING_ERRORS 0x00000004 +#define NDIS_ATTRIBUTE_BUS_MASTER 0x00000008 +#define NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER 0x00000010 +#define NDIS_ATTRIBUTE_DESERIALIZE 0x00000020 +#define NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND 0x00000040 +#define NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK 0x00000080 +#define NDIS_ATTRIBUTE_NOT_CO_NDIS 0x00000100 +#define NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS 0x00000200 + +#define NDIS_SERIALIZED(block) \ + (((block)->nmb_flags & NDIS_ATTRIBUTE_DESERIALIZE) == 0) + +enum ndis_media_state { + nmc_connected, + nmc_disconnected +}; + +typedef enum ndis_media_state ndis_media_state; + +/* Ndis Packet Filter Bits (OID_GEN_CURRENT_PACKET_FILTER). */ + +#define NDIS_PACKET_TYPE_DIRECTED 0x00000001 +#define NDIS_PACKET_TYPE_MULTICAST 0x00000002 +#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004 +#define NDIS_PACKET_TYPE_BROADCAST 0x00000008 +#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010 +#define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020 +#define NDIS_PACKET_TYPE_SMT 0x00000040 +#define NDIS_PACKET_TYPE_ALL_LOCAL 0x00000080 +#define NDIS_PACKET_TYPE_GROUP 0x00001000 +#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x00002000 +#define NDIS_PACKET_TYPE_FUNCTIONAL 0x00004000 +#define NDIS_PACKET_TYPE_MAC_FRAME 0x00008000 + + +/* Ndis MAC option bits (OID_GEN_MAC_OPTIONS). */ + +#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA 0x00000001 +#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED 0x00000002 +#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND 0x00000004 +#define NDIS_MAC_OPTION_NO_LOOPBACK 0x00000008 +#define NDIS_MAC_OPTION_FULL_DUPLEX 0x00000010 +#define NDIS_MAC_OPTION_EOTX_INDICATION 0x00000020 +#define NDIS_MAC_OPTION_8021P_PRIORITY 0x00000040 +#define NDIS_MAC_OPTION_SUPPORTS_MAC_ADDRESS_OVERWRITE 0x00000080 +#define NDIS_MAC_OPTION_RECEIVE_AT_DPC 0x00000100 +#define NDIS_MAC_OPTION_8021Q_VLAN 0x00000200 +#define NDIS_MAC_OPTION_RESERVED 0x80000000 + +#define NDIS_DMA_24BITS 0x00 +#define NDIS_DMA_32BITS 0x01 +#define NDIS_DMA_64BITS 0x02 + +/* +struct ndis_physaddr { +#ifdef __i386__ + uint64_t np_quad; +#endif +#ifdef __amd64__ + uint32_t np_low; + uint32_t np_high; +#define np_quad np_low +#endif +#ifdef notdef + uint32_t np_low; + uint32_t np_high; +#endif +}; +*/ + +typedef struct physaddr ndis_physaddr; + +struct ndis_ansi_string { + uint16_t nas_len; + uint16_t nas_maxlen; + char *nas_buf; +}; + +typedef struct ndis_ansi_string ndis_ansi_string; + +#ifdef notdef +/* + * nus_buf is really a wchar_t *, but it's inconvenient to include + * all the necessary header goop needed to define it, and it's a + * pointer anyway, so for now, just make it a uint16_t *. + */ +struct ndis_unicode_string { + uint16_t nus_len; + uint16_t nus_maxlen; + uint16_t *nus_buf; +}; +typedef struct ndis_unicode_string ndis_unicode_string; +#endif + +typedef unicode_string ndis_unicode_string; + +enum ndis_parm_type { + ndis_parm_int, + ndis_parm_hexint, + ndis_parm_string, + ndis_parm_multistring, + ndis_parm_binary +}; + +typedef enum ndis_parm_type ndis_parm_type; + +struct ndis_binary_data { + uint16_t nbd_len; + void *nbd_buf; +}; + +typedef struct ndis_binary_data ndis_binary_data; + +struct ndis_config_parm { + ndis_parm_type ncp_type; + union { + uint32_t ncp_intdata; + ndis_unicode_string ncp_stringdata; + ndis_binary_data ncp_binarydata; + } ncp_parmdata; +}; + +/* + * Not part of Windows NDIS spec; we uses this to keep a + * list of ndis_config_parm structures that we've allocated. + */ + +typedef struct ndis_config_parm ndis_config_parm; + +struct ndis_parmlist_entry { + list_entry np_list; + ndis_config_parm np_parm; +}; + +typedef struct ndis_parmlist_entry ndis_parmlist_entry; + +#ifdef notdef +struct ndis_list_entry { + struct ndis_list_entry *nle_flink; + struct ndis_list_entry *nle_blink; +}; + +typedef struct ndis_list_entry ndis_list_entry; +#endif + +struct ndis_bind_paths { + uint32_t nbp_number; + ndis_unicode_string nbp_paths[1]; +}; + +typedef struct ndis_bind_paths ndis_bind_paths; + +#ifdef notdef +struct dispatch_header { + uint8_t dh_type; + uint8_t dh_abs; + uint8_t dh_size; + uint8_t dh_inserted; + uint32_t dh_sigstate; + list_entry dh_waitlisthead; +}; +#endif + +#define dispatch_header nt_dispatch_header + +struct ndis_ktimer { + struct dispatch_header nk_header; + uint64_t nk_duetime; + list_entry nk_timerlistentry; + void *nk_dpc; + uint32_t nk_period; +}; + +struct ndis_kevent { + struct dispatch_header nk_header; +}; + +struct ndis_event { + struct nt_kevent ne_event; +}; + +typedef struct ndis_event ndis_event; + +/* Kernel defered procedure call (i.e. timer callback) */ + +struct ndis_kdpc; +typedef void (*ndis_kdpc_func)(struct ndis_kdpc *, void *, void *, void *); + +struct ndis_kdpc { + uint16_t nk_type; + uint8_t nk_num; + uint8_t nk_importance; + list_entry nk_dpclistentry; + ndis_kdpc_func nk_deferedfunc; + void *nk_deferredctx; + void *nk_sysarg1; + void *nk_sysarg2; + uint32_t *nk_lock; +}; + +struct ndis_timer { + struct ktimer nt_ktimer; + struct kdpc nt_kdpc; +}; + +typedef struct ndis_timer ndis_timer; + +typedef void (*ndis_timer_function)(void *, void *, void *, void *); + +struct ndis_miniport_timer { + struct ktimer nmt_ktimer; + struct kdpc nmt_kdpc; + ndis_timer_function nmt_timerfunc; + void *nmt_timerctx; + ndis_miniport_block *nmt_block; + struct ndis_miniport_timer *nmt_nexttimer; +}; + +typedef struct ndis_miniport_timer ndis_miniport_timer; + +struct ndis_spin_lock { + ndis_kspin_lock nsl_spinlock; + ndis_kirql nsl_kirql; +}; + +typedef struct ndis_spin_lock ndis_spin_lock; + +struct ndis_rw_lock { + union { + kspin_lock nrl_spinlock; + void *nrl_ctx; + } u; + uint8_t nrl_rsvd[16]; +}; + +#define nrl_spinlock u.nrl_spinlock +#define nrl_ctx u.nrl_ctx; + +typedef struct ndis_rw_lock ndis_rw_lock; + +struct ndis_lock_state { + uint16_t nls_lockstate; + ndis_kirql nls_oldirql; +}; + +typedef struct ndis_lock_state ndis_lock_state; + +struct ndis_request { + uint8_t nr_macreserved[4*sizeof(void *)]; + uint32_t nr_requesttype; + union _ndis_data { + struct _ndis_query_information { + ndis_oid nr_oid; + void *nr_infobuf; + uint32_t nr_infobuflen; + uint32_t nr_byteswritten; + uint32_t nr_bytesneeded; + } ndis_query_information; + struct _ndis_set_information { + ndis_oid nr_oid; + void *nr_infobuf; + uint32_t nr_infobuflen; + uint32_t nr_byteswritten; + uint32_t nr_bytesneeded; + } ndis_set_information; + } ndis_data; + /* NDIS 5.0 extentions */ + uint8_t nr_ndis_rsvd[9 * sizeof(void *)]; + union { + uint8_t nr_callmgr_rsvd[2 * sizeof(void *)]; + uint8_t nr_protocol_rsvd[2 * sizeof(void *)]; + } u; + uint8_t nr_miniport_rsvd[2 * sizeof(void *)]; +}; + +typedef struct ndis_request ndis_request; + +/* + * Filler, not used. + */ +struct ndis_miniport_interrupt { + kinterrupt *ni_introbj; + ndis_kspin_lock ni_dpccountlock; + void *ni_rsvd; + void *ni_isrfunc; + void *ni_dpcfunc; + kdpc ni_dpc; + ndis_miniport_block *ni_block; + uint8_t ni_dpccnt; + uint8_t ni_filler1; + struct nt_kevent ni_dpcevt; + uint8_t ni_shared; + uint8_t ni_isrreq; +}; + +typedef struct ndis_miniport_interrupt ndis_miniport_interrupt; + +enum ndis_interrupt_mode { + nim_level, + nim_latched +}; + +typedef enum ndis_interrupt_mode ndis_interrupt_mode; + +#define NUMBER_OF_SINGLE_WORK_ITEMS 6 + +struct ndis_work_item; + +typedef void (*ndis_proc)(struct ndis_work_item *, void *); + +struct ndis_work_item { + void *nwi_ctx; + ndis_proc nwi_func; + uint8_t nwi_wraprsvd[sizeof(void *) * 8]; +}; + +typedef struct ndis_work_item ndis_work_item; + +#define NdisInitializeWorkItem(w, f, c) \ + do { \ + (w)->nwi_ctx = c; \ + (w)->nwi_func = f; \ + } while (0) + +#ifdef notdef +struct ndis_buffer { + struct ndis_buffer *nb_next; + uint16_t nb_size; + uint16_t nb_flags; + void *nb_process; + void *nb_mappedsystemva; + void *nb_startva; + uint32_t nb_bytecount; + uint32_t nb_byteoffset; +}; + +typedef struct ndis_buffer ndis_buffer; +#endif + +struct ndis_sc_element { + ndis_physaddr nse_addr; + uint32_t nse_len; + uint32_t *nse_rsvd; +}; + +typedef struct ndis_sc_element ndis_sc_element; + +#define NDIS_MAXSEG 32 +#define NDIS_BUS_SPACE_SHARED_MAXADDR 0x3E7FFFFF + +struct ndis_sc_list { + uint32_t nsl_frags; + uint32_t *nsl_rsvd; + ndis_sc_element nsl_elements[NDIS_MAXSEG]; +}; + +typedef struct ndis_sc_list ndis_sc_list; + +struct ndis_tcpip_csum { + union { + uint32_t ntc_txflags; + uint32_t ntc_rxflags; + uint32_t ntc_val; + } u; +}; + +typedef struct ndis_tcpip_csum ndis_tcpip_csum; + +#define NDIS_TXCSUM_DO_IPV4 0x00000001 +#define NDIS_TXCSUM_DO_IPV6 0x00000002 +#define NDIS_TXCSUM_DO_TCP 0x00000004 +#define NDIS_TXCSUM_DO_UDP 0x00000008 +#define NDIS_TXCSUM_DO_IP 0x00000010 + +#define NDIS_RXCSUM_TCP_FAILED 0x00000001 +#define NDIS_RXCSUM_UDP_FAILED 0x00000002 +#define NDIS_RXCSUM_IP_FAILED 0x00000004 +#define NDIS_RXCSUM_TCP_PASSED 0x00000008 +#define NDIS_RXCSUM_UDP_PASSED 0x00000010 +#define NDIS_RXCSUM_IP_PASSED 0x00000020 +#define NDIS_RXCSUM_LOOPBACK 0x00000040 + +struct ndis_vlan { + union { + struct { + uint32_t nvt_userprio:3; + uint32_t nvt_canformatid:1; + uint32_t nvt_vlanid:12; + uint32_t nvt_rsvd:16; + } nv_taghdr; + } u; +}; + +typedef struct ndis_vlan ndis_vlan; + +enum ndis_perpkt_info { + ndis_tcpipcsum_info, + ndis_ipsec_info, + ndis_largesend_info, + ndis_classhandle_info, + ndis_rsvd, + ndis_sclist_info, + ndis_ieee8021q_info, + ndis_originalpkt_info, + ndis_packetcancelid, + ndis_maxpkt_info +}; + +typedef enum ndis_perpkt_info ndis_perpkt_info; + +struct ndis_packet_extension { + void *npe_info[ndis_maxpkt_info]; +}; + +typedef struct ndis_packet_extension ndis_packet_extension; + +struct ndis_packet_private { + uint32_t npp_physcnt; + uint32_t npp_totlen; + ndis_buffer *npp_head; + ndis_buffer *npp_tail; + + void *npp_pool; + uint32_t npp_count; + uint32_t npp_flags; + uint8_t npp_validcounts; + uint8_t npp_ndispktflags; + uint16_t npp_packetooboffset; +}; + +#define NDIS_FLAGS_PROTOCOL_ID_MASK 0x0000000F +#define NDIS_FLAGS_MULTICAST_PACKET 0x00000010 +#define NDIS_FLAGS_RESERVED2 0x00000020 +#define NDIS_FLAGS_RESERVED3 0x00000040 +#define NDIS_FLAGS_DONT_LOOPBACK 0x00000080 +#define NDIS_FLAGS_IS_LOOPBACK_PACKET 0x00000100 +#define NDIS_FLAGS_LOOPBACK_ONLY 0x00000200 +#define NDIS_FLAGS_RESERVED4 0x00000400 +#define NDIS_FLAGS_DOUBLE_BUFFERED 0x00000800 +#define NDIS_FLAGS_SENT_AT_DPC 0x00001000 +#define NDIS_FLAGS_USES_SG_BUFFER_LIST 0x00002000 + +#define NDIS_PACKET_WRAPPER_RESERVED 0x3F +#define NDIS_PACKET_CONTAINS_MEDIA_SPECIFIC_INFO 0x40 +#define NDIS_PACKET_ALLOCATED_BY_NDIS 0x80 + +#define NDIS_PROTOCOL_ID_DEFAULT 0x00 +#define NDIS_PROTOCOL_ID_TCP_IP 0x02 +#define NDIS_PROTOCOL_ID_IPX 0x06 +#define NDIS_PROTOCOL_ID_NBF 0x07 +#define NDIS_PROTOCOL_ID_MAX 0x0F +#define NDIS_PROTOCOL_ID_MASK 0x0F + +typedef struct ndis_packet_private ndis_packet_private; + +enum ndis_classid { + ndis_class_802_3prio, + ndis_class_wirelesswan_mbx, + ndis_class_irda_packetinfo, + ndis_class_atm_aainfo +}; + +typedef enum ndis_classid ndis_classid; + +struct ndis_mediaspecific_info { + uint32_t nmi_nextentoffset; + ndis_classid nmi_classid; + uint32_t nmi_size; + uint8_t nmi_classinfo[1]; +}; + +typedef struct ndis_mediaspecific_info ndis_mediaspecific_info; + +struct ndis_packet_oob { + union { + uint64_t npo_timetotx; + uint64_t npo_timetxed; + } u; + uint64_t npo_timerxed; + uint32_t npo_hdrlen; + uint32_t npo_mediaspecific_len; + void *npo_mediaspecific; + ndis_status npo_status; +}; + +typedef struct ndis_packet_oob ndis_packet_oob; + +/* + * Our protocol private region for handling ethernet. + * We need this to stash some of the things returned + * by NdisMEthIndicateReceive(). + */ + +struct ndis_ethpriv { + void *nep_ctx; /* packet context */ + long nep_offset; /* residual data to transfer */ + void *nep_pad[2]; +}; + +typedef struct ndis_ethpriv ndis_ethpriv; + +#define PROTOCOL_RESERVED_SIZE_IN_PACKET (4 * sizeof(void *)) + +struct ndis_packet { + ndis_packet_private np_private; + union { + /* For connectionless miniports. */ + struct { + uint8_t np_miniport_rsvd[2 * sizeof(void *)]; + uint8_t np_wrapper_rsvd[2 * sizeof(void *)]; + } np_clrsvd; + /* For de-serialized miniports */ + struct { + uint8_t np_miniport_rsvdex[3 * sizeof(void *)]; + uint8_t np_wrapper_rsvdex[sizeof(void *)]; + } np_dsrsvd; + struct { + uint8_t np_mac_rsvd[4 * sizeof(void *)]; + } np_macrsvd; + } u; + uint32_t *np_rsvd[2]; + uint8_t np_protocolreserved[PROTOCOL_RESERVED_SIZE_IN_PACKET]; + + /* + * This next part is probably wrong, but we need some place + * to put the out of band data structure... + */ + ndis_packet_oob np_oob; + ndis_packet_extension np_ext; + ndis_sc_list np_sclist; + + /* BSD-specific stuff which should be invisible to drivers. */ + + uint32_t np_refcnt; + void *np_softc; + void *np_m0; + int np_txidx; + list_entry np_list; +}; + +typedef struct ndis_packet ndis_packet; + +struct ndis_packet_pool { + slist_header np_head; + int np_dead; + nt_kevent np_event; + kspin_lock np_lock; + int np_cnt; + int np_len; + int np_protrsvd; + void *np_pktmem; +}; + +typedef struct ndis_packet_pool ndis_packet_pool; + +/* mbuf ext type for NDIS */ +#define EXT_NDIS EXT_NET_DRV + +/* mtx type for NDIS */ +#define MTX_NDIS_LOCK "NDIS lock" + +struct ndis_filterdbs { + union { + void *nf_ethdb; + void *nf_nulldb; + } u; + void *nf_trdb; + void *nf_fddidb; + void *nf_arcdb; +}; + +typedef struct ndis_filterdbs ndis_filterdbs; + +#define nf_ethdb u.nf_ethdb + +enum ndis_medium { + NdisMedium802_3, + NdisMedium802_5, + NdisMediumFddi, + NdisMediumWan, + NdisMediumLocalTalk, + NdisMediumDix, /* defined for convenience, not a real medium */ + NdisMediumArcnetRaw, + NdisMediumArcnet878_2, + NdisMediumAtm, + NdisMediumWirelessWan, + NdisMediumIrda, + NdisMediumBpc, + NdisMediumCoWan, + NdisMedium1394, + NdisMediumMax +}; + +typedef enum ndis_medium ndis_medium; +/* +enum interface_type { + InterfaceTypeUndefined = -1, + Internal, + Isa, + Eisa, + MicroChannel, + TurboChannel, + PCIBus, + VMEBus, + NuBus, + PCMCIABus, + CBus, + MPIBus, + MPSABus, + ProcessorInternal, + InternalPowerBus, + PNPISABus, + PNPBus, + MaximumInterfaceType +}; +*/ +enum ndis_interface_type { + NdisInterfaceInternal = Internal, + NdisInterfaceIsa = Isa, + NdisInterfaceEisa = Eisa, + NdisInterfaceMca = MicroChannel, + NdisInterfaceTurboChannel = TurboChannel, + NdisInterfacePci = PCIBus, + NdisInterfacePcMcia = PCMCIABus +}; + +typedef enum ndis_interface_type ndis_interface_type; + +struct ndis_paddr_unit { + ndis_physaddr npu_physaddr; + uint32_t npu_len; +}; + +typedef struct ndis_paddr_unit ndis_paddr_unit; + +struct ndis_map_arg { + ndis_paddr_unit *nma_fraglist; + int nma_cnt; + int nma_max; +}; + +/* + * Miniport characteristics were originally defined in the NDIS 3.0 + * spec and then extended twice, in NDIS 4.0 and 5.0. + */ + +struct ndis_miniport_characteristics { + + /* NDIS 3.0 */ + + uint8_t nmc_version_major; + uint8_t nmc_version_minor; + uint16_t nmc_pad; + uint32_t nmc_rsvd; + void * nmc_checkhang_func; + void * nmc_disable_interrupts_func; + void * nmc_enable_interrupts_func; + void * nmc_halt_func; + void * nmc_interrupt_func; + void * nmc_init_func; + void * nmc_isr_func; + void * nmc_queryinfo_func; + void * nmc_reconfig_func; + void * nmc_reset_func; + void * nmc_sendsingle_func; + void * nmc_setinfo_func; + void * nmc_transferdata_func; + + /* NDIS 4.0 extentions */ + + void * nmc_return_packet_func; + void * nmc_sendmulti_func; + void * nmc_allocate_complete_func; + + /* NDIS 5.0 extensions */ + + void * nmc_cocreatevc_func; + void * nmc_codeletevc_func; + void * nmc_coactivatevc_func; + void * nmc_codeactivatevc_func; + void * nmc_comultisend_func; + void * nmc_corequest_func; + + /* NDIS 5.1 extentions */ + + void * nmc_canceltxpkts_handler; + void * nmc_pnpevent_handler; + void * nmc_shutdown_handler; + void * nmc_rsvd0; + void * nmc_rsvd1; + void * nmc_rsvd2; + void * nmc_rsvd3; +}; + +typedef struct ndis_miniport_characteristics ndis_miniport_characteristics; + +struct ndis_driver_object { + char *ndo_ifname; + void *ndo_softc; + ndis_miniport_characteristics ndo_chars; +}; + +typedef struct ndis_driver_object ndis_driver_object; + +struct ndis_reference { + ndis_kspin_lock nr_spinlock; + uint16_t nr_refcnt; + uint8_t nr_closing; +}; + +typedef struct ndis_reference ndis_reference; + +struct ndis_timer_entry { + struct callout nte_ch; + ndis_miniport_timer *nte_timer; + TAILQ_ENTRY(ndis_timer_entry) link; +}; + +TAILQ_HEAD(nte_head, ndis_timer_entry); + +#define NDIS_FH_TYPE_VFS 0 +#define NDIS_FH_TYPE_MODULE 1 + +struct ndis_fh { + int nf_type; + char *nf_name; + void *nf_vp; + void *nf_map; + uint32_t nf_maplen; +}; + +typedef struct ndis_fh ndis_fh; + +/* + * The miniport block is basically the internal NDIS handle. We need + * to define this because, unfortunately, it is not entirely opaque + * to NDIS drivers. For one thing, it contains the function pointer + * to the NDIS packet receive handler, which is invoked out of the + * NDIS block via a macro rather than a function pointer. (The + * NdisMIndicateReceivePacket() routine is a macro rather than + * a function.) For another, the driver maintains a pointer to the + * miniport block and passes it as a handle to various NDIS functions. + * (The driver never really knows this because it's hidden behind + * an ndis_handle though.) + * + * The miniport block has two parts: the first part contains fields + * that must never change, since they are referenced by driver + * binaries through macros. The second part is ignored by the driver, + * but contains various things used internaly by NDIS.SYS. In our + * case, we define the first 'immutable' part exactly as it appears + * in Windows, but don't bother duplicating the Windows definitions + * for the second part. Instead, we replace them with a few BSD-specific + * things. + */ + +struct ndis_miniport_block { + /* + * Windows-specific portion -- DO NOT MODIFY OR NDIS + * DRIVERS WILL NOT WORK. + */ + void *nmb_signature; /* magic number */ + ndis_miniport_block *nmb_nextminiport; + ndis_mdriver_block *nmb_driverhandle; + ndis_handle nmb_miniportadapterctx; + ndis_unicode_string nmb_name; + ndis_bind_paths *nmb_bindpaths; + ndis_handle nmb_openqueue; + ndis_reference nmb_ref; + ndis_handle nmb_devicectx; + uint8_t nmb_padding; + uint8_t nmb_lockacquired; + uint8_t nmb_pmodeopens; + uint8_t nmb_assignedcpu; + ndis_kspin_lock nmb_lock; + ndis_request *nmb_mediarequest; + ndis_miniport_interrupt *nmb_interrupt; + uint32_t nmb_flags; + uint32_t nmb_pnpflags; + list_entry nmb_packetlist; + ndis_packet *nmb_firstpendingtxpacket; + ndis_packet *nmb_returnpacketqueue; + uint32_t nmb_requestbuffer; + void *nmb_setmcastbuf; + ndis_miniport_block *nmb_primaryminiport; + void *nmb_wrapperctx; + void *nmb_busdatactx; + uint32_t nmb_pnpcaps; + cm_resource_list *nmb_resources; + ndis_timer nmb_wkupdpctimer; + ndis_unicode_string nmb_basename; + ndis_unicode_string nmb_symlinkname; + uint32_t nmb_checkforhangsecs; + uint16_t nmb_cfhticks; + uint16_t nmb_cfhcurrticks; + ndis_status nmb_resetstatus; + ndis_handle nmb_resetopen; + ndis_filterdbs nmb_filterdbs; + void *nmb_pktind_func; + void *nmb_senddone_func; + void *nmb_sendrsrc_func; + void *nmb_resetdone_func; + ndis_medium nmb_medium; + uint32_t nmb_busnum; + uint32_t nmb_bustype; + uint32_t nmb_adaptertype; + device_object *nmb_deviceobj; /* Functional device */ + device_object *nmb_physdeviceobj; /* Physical device */ + device_object *nmb_nextdeviceobj; /* Next dev in stack */ + void *nmb_mapreg; + void *nmb_callmgraflist; + void *nmb_miniportthread; + void *nmb_setinfobuf; + uint16_t nmb_setinfobuflen; + uint16_t nmb_maxsendpkts; + ndis_status nmb_fakestatus; + void *nmb_lockhandler; + ndis_unicode_string *nmb_adapterinstancename; + void *nmb_timerqueue; + uint32_t nmb_mactoptions; + ndis_request *nmb_pendingreq; + uint32_t nmb_maxlongaddrs; + uint32_t nmb_maxshortaddrs; + uint32_t nmb_currlookahead; + uint32_t nmb_maxlookahead; + void *nmb_interrupt_func; + void *nmb_disableintr_func; + void *nmb_enableintr_func; + void *nmb_sendpkts_func; + void *nmb_deferredsend_func; + void *nmb_ethrxindicate_func; + void *nmb_txrxindicate_func; + void *nmb_fddirxindicate_func; + void *nmb_ethrxdone_func; + void *nmb_txrxdone_func; + void *nmb_fddirxcond_func; + void *nmb_status_func; + void *nmb_statusdone_func; + void *nmb_tdcond_func; + void *nmb_querydone_func; + void *nmb_setdone_func; + void *nmb_wantxdone_func; + void *nmb_wanrx_func; + void *nmb_wanrxdone_func; + /* + * End of windows-specific portion of miniport block. Everything + * below is BSD-specific. + */ + list_entry nmb_parmlist; + ndis_resource_list *nmb_rlist; + ndis_status nmb_getstat; + nt_kevent nmb_getevent; + ndis_status nmb_setstat; + nt_kevent nmb_setevent; + nt_kevent nmb_resetevent; + io_workitem *nmb_returnitem; + ndis_miniport_timer *nmb_timerlist; + ndis_handle nmb_rxpool; + list_entry nmb_returnlist; + kspin_lock nmb_returnlock; + TAILQ_ENTRY(ndis_miniport_block) link; +}; + +TAILQ_HEAD(nd_head, ndis_miniport_block); + +typedef ndis_status (*ndis_init_handler)(ndis_status *, uint32_t *, + ndis_medium *, uint32_t, ndis_handle, ndis_handle); +typedef ndis_status (*ndis_queryinfo_handler)(ndis_handle, ndis_oid, + void *, uint32_t, uint32_t *, uint32_t *); +typedef ndis_status (*ndis_setinfo_handler)(ndis_handle, ndis_oid, + void *, uint32_t, uint32_t *, uint32_t *); +typedef ndis_status (*ndis_sendsingle_handler)(ndis_handle, + ndis_packet *, uint32_t); +typedef ndis_status (*ndis_sendmulti_handler)(ndis_handle, + ndis_packet **, uint32_t); +typedef void (*ndis_isr_handler)(uint8_t *, uint8_t *, ndis_handle); +typedef void (*ndis_interrupt_handler)(ndis_handle); +typedef int (*ndis_reset_handler)(uint8_t *, ndis_handle); +typedef void (*ndis_halt_handler)(ndis_handle); +typedef void (*ndis_return_handler)(ndis_handle, ndis_packet *); +typedef void (*ndis_enable_interrupts_handler)(ndis_handle); +typedef void (*ndis_disable_interrupts_handler)(ndis_handle); +typedef void (*ndis_shutdown_handler)(void *); +typedef void (*ndis_pnpevent_handler)(void *, int, void *, uint32_t); +typedef void (*ndis_allocdone_handler)(ndis_handle, void *, + ndis_physaddr *, uint32_t, void *); +typedef uint8_t (*ndis_checkforhang_handler)(ndis_handle); + +typedef ndis_status (*driver_entry)(void *, unicode_string *); + +extern image_patch_table ndis_functbl[]; + +#define NDIS_TASKQUEUE 1 +#define NDIS_SWI 2 + +#define NDIS_PSTATE_RUNNING 1 +#define NDIS_PSTATE_SLEEPING 2 + +#define NdisQueryPacket(p, pbufcnt, bufcnt, firstbuf, plen) \ + do { \ + if ((firstbuf) != NULL) { \ + ndis_buffer **_first; \ + _first = firstbuf; \ + *(_first) = (p)->np_private.npp_head; \ + } \ + if ((plen) || (bufcnt) || (pbufcnt)) { \ + if ((p)->np_private.npp_validcounts == FALSE) { \ + ndis_buffer *tmp; \ + unsigned int tlen = 0, pcnt = 0; \ + unsigned int add = 0; \ + unsigned int pktlen, off; \ + \ + tmp = (p)->np_private.npp_head; \ + while (tmp != NULL) { \ + off = MmGetMdlByteOffset(tmp); \ + pktlen = MmGetMdlByteCount(tmp);\ + tlen += pktlen; \ + pcnt += \ + NDIS_BUFFER_TO_SPAN_PAGES(tmp); \ + add++; \ + tmp = tmp->mdl_next; \ + } \ + (p)->np_private.npp_count = add; \ + (p)->np_private.npp_totlen = tlen; \ + (p)->np_private.npp_physcnt = pcnt; \ + (p)->np_private.npp_validcounts = TRUE; \ + } \ + if (pbufcnt) { \ + unsigned int *_pbufcnt; \ + _pbufcnt = (pbufcnt); \ + *(_pbufcnt) = (p)->np_private.npp_physcnt; \ + } \ + if (bufcnt) { \ + unsigned int *_bufcnt; \ + _bufcnt = (bufcnt); \ + *(_bufcnt) = (p)->np_private.npp_count; \ + } \ + if (plen) { \ + unsigned int *_plen; \ + _plen = (plen); \ + *(_plen) = (p)->np_private.npp_totlen; \ + } \ + } \ + } while (0) + +__BEGIN_DECLS +extern int ndis_libinit(void); +extern int ndis_libfini(void); +extern int ndis_load_driver(vm_offset_t, void *); +extern int ndis_unload_driver(void *); +extern int ndis_mtop(struct mbuf *, ndis_packet **); +extern int ndis_ptom(struct mbuf **, ndis_packet *); +extern int ndis_get_info(void *, ndis_oid, void *, int *); +extern int ndis_set_info(void *, ndis_oid, void *, int *); +extern void *ndis_get_routine_address(struct image_patch_table *, char *); +extern int ndis_get_supported_oids(void *, ndis_oid **, int *); +extern int ndis_send_packets(void *, ndis_packet **, int); +extern int ndis_send_packet(void *, ndis_packet *); +extern int ndis_convert_res(void *); +extern int ndis_alloc_amem(void *); +extern void ndis_free_amem(void *); +extern void ndis_free_packet(ndis_packet *); +extern void ndis_free_bufs(ndis_buffer *); +extern int ndis_reset_nic(void *); +extern int ndis_halt_nic(void *); +extern int ndis_shutdown_nic(void *); +extern int ndis_pnpevent_nic(void *, int); +extern int ndis_init_nic(void *); +extern void ndis_return_packet(void *, void *); +extern int ndis_init_dma(void *); +extern int ndis_destroy_dma(void *); +extern int ndis_create_sysctls(void *); +extern int ndis_add_sysctl(void *, char *, char *, char *, int); +extern int ndis_flush_sysctls(void *); + +extern uint32_t NdisAddDevice(driver_object *, device_object *); +extern void NdisAllocatePacketPool(ndis_status *, + ndis_handle *, uint32_t, uint32_t); +extern void NdisAllocatePacketPoolEx(ndis_status *, + ndis_handle *, uint32_t, uint32_t, uint32_t); +extern uint32_t NdisPacketPoolUsage(ndis_handle); +extern void NdisFreePacketPool(ndis_handle); +extern void NdisAllocatePacket(ndis_status *, + ndis_packet **, ndis_handle); +extern void NdisFreePacket(ndis_packet *); +extern ndis_status NdisScheduleWorkItem(ndis_work_item *); +extern void NdisMSleep(uint32_t); +__END_DECLS + +#endif /* _NDIS_VAR_H_ */ diff --git a/sys/compat/ndis/ntoskrnl_var.h b/sys/compat/ndis/ntoskrnl_var.h new file mode 100644 index 0000000..2642626 --- /dev/null +++ b/sys/compat/ndis/ntoskrnl_var.h @@ -0,0 +1,1529 @@ +/*- + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.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, 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 Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD + * 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 _NTOSKRNL_VAR_H_ +#define _NTOSKRNL_VAR_H_ + +#define MTX_NTOSKRNL_SPIN_LOCK "NDIS thread lock" + +/* + * us_buf is really a wchar_t *, but it's inconvenient to include + * all the necessary header goop needed to define it, and it's a + * pointer anyway, so for now, just make it a uint16_t *. + */ +struct unicode_string { + uint16_t us_len; + uint16_t us_maxlen; + uint16_t *us_buf; +}; + +typedef struct unicode_string unicode_string; + +struct ansi_string { + uint16_t as_len; + uint16_t as_maxlen; + char *as_buf; +}; + +typedef struct ansi_string ansi_string; + +/* + * Windows memory descriptor list. In Windows, it's possible for + * buffers to be passed between user and kernel contexts without + * copying. Buffers may also be allocated in either paged or + * non-paged memory regions. An MDL describes the pages of memory + * used to contain a particular buffer. Note that a single MDL + * may describe a buffer that spans multiple pages. An array of + * page addresses appears immediately after the MDL structure itself. + * MDLs are therefore implicitly variably sized, even though they + * don't look it. + * + * Note that in FreeBSD, we can take many shortcuts in the way + * we handle MDLs because: + * + * - We are only concerned with pages in kernel context. This means + * we will only ever use the kernel's memory map, and remapping + * of buffers is never needed. + * + * - Kernel pages can never be paged out, so we don't have to worry + * about whether or not a page is actually mapped before going to + * touch it. + */ + +struct mdl { + struct mdl *mdl_next; + uint16_t mdl_size; + uint16_t mdl_flags; + void *mdl_process; + void *mdl_mappedsystemva; + void *mdl_startva; + uint32_t mdl_bytecount; + uint32_t mdl_byteoffset; +}; + +typedef struct mdl mdl, ndis_buffer; + +/* MDL flags */ + +#define MDL_MAPPED_TO_SYSTEM_VA 0x0001 +#define MDL_PAGES_LOCKED 0x0002 +#define MDL_SOURCE_IS_NONPAGED_POOL 0x0004 +#define MDL_ALLOCATED_FIXED_SIZE 0x0008 +#define MDL_PARTIAL 0x0010 +#define MDL_PARTIAL_HAS_BEEN_MAPPED 0x0020 +#define MDL_IO_PAGE_READ 0x0040 +#define MDL_WRITE_OPERATION 0x0080 +#define MDL_PARENT_MAPPED_SYSTEM_VA 0x0100 +#define MDL_FREE_EXTRA_PTES 0x0200 +#define MDL_IO_SPACE 0x0800 +#define MDL_NETWORK_HEADER 0x1000 +#define MDL_MAPPING_CAN_FAIL 0x2000 +#define MDL_ALLOCATED_MUST_SUCCEED 0x4000 +#define MDL_ZONE_ALLOCED 0x8000 /* BSD private */ + +#define MDL_ZONE_PAGES 16 +#define MDL_ZONE_SIZE (sizeof(mdl) + (sizeof(vm_offset_t) * MDL_ZONE_PAGES)) + +/* Note: assumes x86 page size of 4K. */ + +#ifndef PAGE_SHIFT +#if PAGE_SIZE == 4096 +#define PAGE_SHIFT 12 +#elif PAGE_SIZE == 8192 +#define PAGE_SHIFT 13 +#else +#error PAGE_SHIFT undefined! +#endif +#endif + +#define SPAN_PAGES(ptr, len) \ + ((uint32_t)((((uintptr_t)(ptr) & (PAGE_SIZE - 1)) + \ + (len) + (PAGE_SIZE - 1)) >> PAGE_SHIFT)) + +#define PAGE_ALIGN(ptr) \ + ((void *)((uintptr_t)(ptr) & ~(PAGE_SIZE - 1))) + +#define BYTE_OFFSET(ptr) \ + ((uint32_t)((uintptr_t)(ptr) & (PAGE_SIZE - 1))) + +#define MDL_PAGES(m) (vm_offset_t *)(m + 1) + +#define MmInitializeMdl(b, baseva, len) \ + (b)->mdl_next = NULL; \ + (b)->mdl_size = (uint16_t)(sizeof(mdl) + \ + (sizeof(vm_offset_t) * SPAN_PAGES((baseva), (len)))); \ + (b)->mdl_flags = 0; \ + (b)->mdl_startva = (void *)PAGE_ALIGN((baseva)); \ + (b)->mdl_byteoffset = BYTE_OFFSET((baseva)); \ + (b)->mdl_bytecount = (uint32_t)(len); + +#define MmGetMdlByteOffset(mdl) ((mdl)->mdl_byteoffset) +#define MmGetMdlByteCount(mdl) ((mdl)->mdl_bytecount) +#define MmGetMdlVirtualAddress(mdl) \ + ((void *)((char *)((mdl)->mdl_startva) + (mdl)->mdl_byteoffset)) +#define MmGetMdlStartVa(mdl) ((mdl)->mdl_startva) +#define MmGetMdlPfnArray(mdl) MDL_PAGES(mdl) + +#define WDM_MAJOR 1 +#define WDM_MINOR_WIN98 0x00 +#define WDM_MINOR_WINME 0x05 +#define WDM_MINOR_WIN2000 0x10 +#define WDM_MINOR_WINXP 0x20 +#define WDM_MINOR_WIN2003 0x30 + +enum nt_caching_type { + MmNonCached = 0, + MmCached = 1, + MmWriteCombined = 2, + MmHardwareCoherentCached = 3, + MmNonCachedUnordered = 4, + MmUSWCCached = 5, + MmMaximumCacheType = 6 +}; + +/*- + * The ndis_kspin_lock type is called KSPIN_LOCK in MS-Windows. + * According to the Windows DDK header files, KSPIN_LOCK is defined like this: + * typedef ULONG_PTR KSPIN_LOCK; + * + * From basetsd.h (SDK, Feb. 2003): + * typedef [public] unsigned __int3264 ULONG_PTR, *PULONG_PTR; + * typedef unsigned __int64 ULONG_PTR, *PULONG_PTR; + * typedef _W64 unsigned long ULONG_PTR, *PULONG_PTR; + * + * The keyword __int3264 specifies an integral type that has the following + * properties: + * + It is 32-bit on 32-bit platforms + * + It is 64-bit on 64-bit platforms + * + It is 32-bit on the wire for backward compatibility. + * It gets truncated on the sending side and extended appropriately + * (signed or unsigned) on the receiving side. + * + * Thus register_t seems the proper mapping onto FreeBSD for spin locks. + */ + +typedef register_t kspin_lock; + +struct slist_entry { + struct slist_entry *sl_next; +}; + +typedef struct slist_entry slist_entry; + +union slist_header { + uint64_t slh_align; + struct { + struct slist_entry *slh_next; + uint16_t slh_depth; + uint16_t slh_seq; + } slh_list; +}; + +typedef union slist_header slist_header; + +struct list_entry { + struct list_entry *nle_flink; + struct list_entry *nle_blink; +}; + +typedef struct list_entry list_entry; + +#define InitializeListHead(l) \ + (l)->nle_flink = (l)->nle_blink = (l) + +#define IsListEmpty(h) \ + ((h)->nle_flink == (h)) + +#define RemoveEntryList(e) \ + do { \ + list_entry *b; \ + list_entry *f; \ + \ + f = (e)->nle_flink; \ + b = (e)->nle_blink; \ + b->nle_flink = f; \ + f->nle_blink = b; \ + } while (0) + +/* These two have to be inlined since they return things. */ + +static __inline__ list_entry * +RemoveHeadList(list_entry *l) +{ + list_entry *f; + list_entry *e; + + e = l->nle_flink; + f = e->nle_flink; + l->nle_flink = f; + f->nle_blink = l; + + return (e); +} + +static __inline__ list_entry * +RemoveTailList(list_entry *l) +{ + list_entry *b; + list_entry *e; + + e = l->nle_blink; + b = e->nle_blink; + l->nle_blink = b; + b->nle_flink = l; + + return (e); +} + +#define InsertTailList(l, e) \ + do { \ + list_entry *b; \ + \ + b = l->nle_blink; \ + e->nle_flink = l; \ + e->nle_blink = b; \ + b->nle_flink = (e); \ + l->nle_blink = (e); \ + } while (0) + +#define InsertHeadList(l, e) \ + do { \ + list_entry *f; \ + \ + f = l->nle_flink; \ + e->nle_flink = f; \ + e->nle_blink = l; \ + f->nle_blink = e; \ + l->nle_flink = e; \ + } while (0) + +#define CONTAINING_RECORD(addr, type, field) \ + ((type *)((vm_offset_t)(addr) - (vm_offset_t)(&((type *)0)->field))) + +struct nt_dispatch_header { + uint8_t dh_type; + uint8_t dh_abs; + uint8_t dh_size; + uint8_t dh_inserted; + int32_t dh_sigstate; + list_entry dh_waitlisthead; +}; + +typedef struct nt_dispatch_header nt_dispatch_header; + +/* Dispatcher object types */ + +#define DISP_TYPE_NOTIFICATION_EVENT 0 /* KEVENT */ +#define DISP_TYPE_SYNCHRONIZATION_EVENT 1 /* KEVENT */ +#define DISP_TYPE_MUTANT 2 /* KMUTANT/KMUTEX */ +#define DISP_TYPE_PROCESS 3 /* KPROCESS */ +#define DISP_TYPE_QUEUE 4 /* KQUEUE */ +#define DISP_TYPE_SEMAPHORE 5 /* KSEMAPHORE */ +#define DISP_TYPE_THREAD 6 /* KTHREAD */ +#define DISP_TYPE_NOTIFICATION_TIMER 8 /* KTIMER */ +#define DISP_TYPE_SYNCHRONIZATION_TIMER 9 /* KTIMER */ + +#define OTYPE_EVENT 0 +#define OTYPE_MUTEX 1 +#define OTYPE_THREAD 2 +#define OTYPE_TIMER 3 + +/* Windows dispatcher levels. */ + +#define PASSIVE_LEVEL 0 +#define LOW_LEVEL 0 +#define APC_LEVEL 1 +#define DISPATCH_LEVEL 2 +#define DEVICE_LEVEL (DISPATCH_LEVEL + 1) +#define PROFILE_LEVEL 27 +#define CLOCK1_LEVEL 28 +#define CLOCK2_LEVEL 28 +#define IPI_LEVEL 29 +#define POWER_LEVEL 30 +#define HIGH_LEVEL 31 + +#define SYNC_LEVEL_UP DISPATCH_LEVEL +#define SYNC_LEVEL_MP (IPI_LEVEL - 1) + +#define AT_PASSIVE_LEVEL(td) \ + ((td)->td_proc->p_flag & P_KTHREAD == FALSE) + +#define AT_DISPATCH_LEVEL(td) \ + ((td)->td_base_pri == PI_REALTIME) + +#define AT_DIRQL_LEVEL(td) \ + ((td)->td_priority <= PI_NET) + +#define AT_HIGH_LEVEL(td) \ + ((td)->td_critnest != 0) + +struct nt_objref { + nt_dispatch_header no_dh; + void *no_obj; + TAILQ_ENTRY(nt_objref) link; +}; + +TAILQ_HEAD(nt_objref_head, nt_objref); + +typedef struct nt_objref nt_objref; + +#define EVENT_TYPE_NOTIFY 0 +#define EVENT_TYPE_SYNC 1 + +/* + * We need to use the timeout()/untimeout() API for ktimers + * since timers can be initialized, but not destroyed (so + * malloc()ing our own callout structures would mean a leak, + * since there'd be no way to free() them). This means we + * need to use struct callout_handle, which is really just a + * pointer. To make it easier to deal with, we use a union + * to overlay the callout_handle over the k_timerlistentry. + * The latter is a list_entry, which is two pointers, so + * there's enough space available to hide a callout_handle + * there. + */ + +struct ktimer { + nt_dispatch_header k_header; + uint64_t k_duetime; + union { + list_entry k_timerlistentry; + struct callout *k_callout; + } u; + void *k_dpc; + uint32_t k_period; +}; + +#define k_timerlistentry u.k_timerlistentry +#define k_callout u.k_callout + +typedef struct ktimer ktimer; + +struct nt_kevent { + nt_dispatch_header k_header; +}; + +typedef struct nt_kevent nt_kevent; + +/* Kernel defered procedure call (i.e. timer callback) */ + +struct kdpc; +typedef void (*kdpc_func)(struct kdpc *, void *, void *, void *); + +struct kdpc { + uint16_t k_type; + uint8_t k_num; /* CPU number */ + uint8_t k_importance; /* priority */ + list_entry k_dpclistentry; + void *k_deferedfunc; + void *k_deferredctx; + void *k_sysarg1; + void *k_sysarg2; + void *k_lock; +}; + +#define KDPC_IMPORTANCE_LOW 0 +#define KDPC_IMPORTANCE_MEDIUM 1 +#define KDPC_IMPORTANCE_HIGH 2 + +#define KDPC_CPU_DEFAULT 255 + +typedef struct kdpc kdpc; + +/* + * Note: the acquisition count is BSD-specific. The Microsoft + * documentation says that mutexes can be acquired recursively + * by a given thread, but that you must release the mutex as + * many times as you acquired it before it will be set to the + * signalled state (i.e. before any other threads waiting on + * the object will be woken up). However the Windows KMUTANT + * structure has no field for keeping track of the number of + * acquisitions, so we need to add one ourselves. As long as + * driver code treats the mutex as opaque, we should be ok. + */ +struct kmutant { + nt_dispatch_header km_header; + list_entry km_listentry; + void *km_ownerthread; + uint8_t km_abandoned; + uint8_t km_apcdisable; +}; + +typedef struct kmutant kmutant; + +#define LOOKASIDE_DEPTH 256 + +struct general_lookaside { + slist_header gl_listhead; + uint16_t gl_depth; + uint16_t gl_maxdepth; + uint32_t gl_totallocs; + union { + uint32_t gl_allocmisses; + uint32_t gl_allochits; + } u_a; + uint32_t gl_totalfrees; + union { + uint32_t gl_freemisses; + uint32_t gl_freehits; + } u_m; + uint32_t gl_type; + uint32_t gl_tag; + uint32_t gl_size; + void *gl_allocfunc; + void *gl_freefunc; + list_entry gl_listent; + uint32_t gl_lasttotallocs; + union { + uint32_t gl_lastallocmisses; + uint32_t gl_lastallochits; + } u_l; + uint32_t gl_rsvd[2]; +}; + +typedef struct general_lookaside general_lookaside; + +struct npaged_lookaside_list { + general_lookaside nll_l; +#ifdef __i386__ + kspin_lock nll_obsoletelock; +#endif +}; + +typedef struct npaged_lookaside_list npaged_lookaside_list; +typedef struct npaged_lookaside_list paged_lookaside_list; + +typedef void * (*lookaside_alloc_func)(uint32_t, size_t, uint32_t); +typedef void (*lookaside_free_func)(void *); + +struct irp; + +struct kdevice_qentry { + list_entry kqe_devlistent; + uint32_t kqe_sortkey; + uint8_t kqe_inserted; +}; + +typedef struct kdevice_qentry kdevice_qentry; + +struct kdevice_queue { + uint16_t kq_type; + uint16_t kq_size; + list_entry kq_devlisthead; + kspin_lock kq_lock; + uint8_t kq_busy; +}; + +typedef struct kdevice_queue kdevice_queue; + +struct wait_ctx_block { + kdevice_qentry wcb_waitqueue; + void *wcb_devfunc; + void *wcb_devctx; + uint32_t wcb_mapregcnt; + void *wcb_devobj; + void *wcb_curirp; + void *wcb_bufchaindpc; +}; + +typedef struct wait_ctx_block wait_ctx_block; + +struct wait_block { + list_entry wb_waitlist; + void *wb_kthread; + nt_dispatch_header *wb_object; + struct wait_block *wb_next; +#ifdef notdef + uint16_t wb_waitkey; + uint16_t wb_waittype; +#endif + uint8_t wb_waitkey; + uint8_t wb_waittype; + uint8_t wb_awakened; + uint8_t wb_oldpri; +}; + +typedef struct wait_block wait_block; + +#define wb_ext wb_kthread + +#define THREAD_WAIT_OBJECTS 3 +#define MAX_WAIT_OBJECTS 64 + +#define WAITTYPE_ALL 0 +#define WAITTYPE_ANY 1 + +#define WAITKEY_VALID 0x8000 + +/* kthread priority */ +#define LOW_PRIORITY 0 +#define LOW_REALTIME_PRIORITY 16 +#define HIGH_PRIORITY 31 + +struct thread_context { + void *tc_thrctx; + void *tc_thrfunc; +}; + +typedef struct thread_context thread_context; + +/* Forward declaration */ +struct driver_object; +struct devobj_extension; + +struct driver_extension { + struct driver_object *dre_driverobj; + void *dre_adddevicefunc; + uint32_t dre_reinitcnt; + unicode_string dre_srvname; + + /* + * Drivers are allowed to add one or more custom extensions + * to the driver object, but there's no special pointer + * for them. Hang them off here for now. + */ + + list_entry dre_usrext; +}; + +typedef struct driver_extension driver_extension; + +struct custom_extension { + list_entry ce_list; + void *ce_clid; +}; + +typedef struct custom_extension custom_extension; + +/* + * The KINTERRUPT structure in Windows is opaque to drivers. + * We define our own custom version with things we need. + */ + +struct kinterrupt { + list_entry ki_list; + device_t ki_dev; + int ki_rid; + void *ki_cookie; + struct resource *ki_irq; + kspin_lock ki_lock_priv; + kspin_lock *ki_lock; + void *ki_svcfunc; + void *ki_svcctx; +}; + +typedef struct kinterrupt kinterrupt; + +struct ksystem_time { + uint32_t low_part; + int32_t high1_time; + int32_t high2_time; +}; + +enum nt_product_type { + NT_PRODUCT_WIN_NT = 1, + NT_PRODUCT_LAN_MAN_NT, + NT_PRODUCT_SERVER +}; + +enum alt_arch_type { + STANDARD_DESIGN, + NEC98x86, + END_ALTERNATIVES +}; + +struct kuser_shared_data { + uint32_t tick_count; + uint32_t tick_count_multiplier; + volatile struct ksystem_time interrupt_time; + volatile struct ksystem_time system_time; + volatile struct ksystem_time time_zone_bias; + uint16_t image_number_low; + uint16_t image_number_high; + int16_t nt_system_root[260]; + uint32_t max_stack_trace_depth; + uint32_t crypto_exponent; + uint32_t time_zone_id; + uint32_t large_page_min; + uint32_t reserved2[7]; + enum nt_product_type nt_product_type; + uint8_t product_type_is_valid; + uint32_t nt_major_version; + uint32_t nt_minor_version; + uint8_t processor_features[64]; + uint32_t reserved1; + uint32_t reserved3; + volatile uint32_t time_slip; + enum alt_arch_type alt_arch_type; + int64_t system_expiration_date; + uint32_t suite_mask; + uint8_t kdbg_enabled; + volatile uint32_t active_console; + volatile uint32_t dismount_count; + uint32_t com_plus_package; + uint32_t last_system_rit_event_tick_count; + uint32_t num_phys_pages; + uint8_t safe_boot_mode; + uint32_t trace_log; + uint64_t fill0; + uint64_t sys_call[4]; + union { + volatile struct ksystem_time tick_count; + volatile uint64_t tick_count_quad; + } tick; +}; + +/* + * In Windows, there are Physical Device Objects (PDOs) and + * Functional Device Objects (FDOs). Physical Device Objects are + * created and maintained by bus drivers. For example, the PCI + * bus driver might detect two PCI ethernet cards on a given + * bus. The PCI bus driver will then allocate two device_objects + * for its own internal bookeeping purposes. This is analagous + * to the device_t that the FreeBSD PCI code allocates and passes + * into each PCI driver's probe and attach routines. + * + * When an ethernet driver claims one of the ethernet cards + * on the bus, it will create its own device_object. This is + * the Functional Device Object. This object is analagous to the + * device-specific softc structure. + */ + +struct device_object { + uint16_t do_type; + uint16_t do_size; + uint32_t do_refcnt; + struct driver_object *do_drvobj; + struct device_object *do_nextdev; + struct device_object *do_attacheddev; + struct irp *do_currirp; + void *do_iotimer; + uint32_t do_flags; + uint32_t do_characteristics; + void *do_vpb; + void *do_devext; + uint32_t do_devtype; + uint8_t do_stacksize; + union { + list_entry do_listent; + wait_ctx_block do_wcb; + } queue; + uint32_t do_alignreq; + kdevice_queue do_devqueue; + struct kdpc do_dpc; + uint32_t do_activethreads; + void *do_securitydesc; + struct nt_kevent do_devlock; + uint16_t do_sectorsz; + uint16_t do_spare1; + struct devobj_extension *do_devobj_ext; + void *do_rsvd; +}; + +typedef struct device_object device_object; + +struct devobj_extension { + uint16_t dve_type; + uint16_t dve_size; + device_object *dve_devobj; +}; + +typedef struct devobj_extension devobj_extension; + +/* Device object flags */ + +#define DO_VERIFY_VOLUME 0x00000002 +#define DO_BUFFERED_IO 0x00000004 +#define DO_EXCLUSIVE 0x00000008 +#define DO_DIRECT_IO 0x00000010 +#define DO_MAP_IO_BUFFER 0x00000020 +#define DO_DEVICE_HAS_NAME 0x00000040 +#define DO_DEVICE_INITIALIZING 0x00000080 +#define DO_SYSTEM_BOOT_PARTITION 0x00000100 +#define DO_LONG_TERM_REQUESTS 0x00000200 +#define DO_NEVER_LAST_DEVICE 0x00000400 +#define DO_SHUTDOWN_REGISTERED 0x00000800 +#define DO_BUS_ENUMERATED_DEVICE 0x00001000 +#define DO_POWER_PAGABLE 0x00002000 +#define DO_POWER_INRUSH 0x00004000 +#define DO_LOW_PRIORITY_FILESYSTEM 0x00010000 + +/* Priority boosts */ + +#define IO_NO_INCREMENT 0 +#define IO_CD_ROM_INCREMENT 1 +#define IO_DISK_INCREMENT 1 +#define IO_KEYBOARD_INCREMENT 6 +#define IO_MAILSLOT_INCREMENT 2 +#define IO_MOUSE_INCREMENT 6 +#define IO_NAMED_PIPE_INCREMENT 2 +#define IO_NETWORK_INCREMENT 2 +#define IO_PARALLEL_INCREMENT 1 +#define IO_SERIAL_INCREMENT 2 +#define IO_SOUND_INCREMENT 8 +#define IO_VIDEO_INCREMENT 1 + +/* IRP major codes */ + +#define IRP_MJ_CREATE 0x00 +#define IRP_MJ_CREATE_NAMED_PIPE 0x01 +#define IRP_MJ_CLOSE 0x02 +#define IRP_MJ_READ 0x03 +#define IRP_MJ_WRITE 0x04 +#define IRP_MJ_QUERY_INFORMATION 0x05 +#define IRP_MJ_SET_INFORMATION 0x06 +#define IRP_MJ_QUERY_EA 0x07 +#define IRP_MJ_SET_EA 0x08 +#define IRP_MJ_FLUSH_BUFFERS 0x09 +#define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0a +#define IRP_MJ_SET_VOLUME_INFORMATION 0x0b +#define IRP_MJ_DIRECTORY_CONTROL 0x0c +#define IRP_MJ_FILE_SYSTEM_CONTROL 0x0d +#define IRP_MJ_DEVICE_CONTROL 0x0e +#define IRP_MJ_INTERNAL_DEVICE_CONTROL 0x0f +#define IRP_MJ_SHUTDOWN 0x10 +#define IRP_MJ_LOCK_CONTROL 0x11 +#define IRP_MJ_CLEANUP 0x12 +#define IRP_MJ_CREATE_MAILSLOT 0x13 +#define IRP_MJ_QUERY_SECURITY 0x14 +#define IRP_MJ_SET_SECURITY 0x15 +#define IRP_MJ_POWER 0x16 +#define IRP_MJ_SYSTEM_CONTROL 0x17 +#define IRP_MJ_DEVICE_CHANGE 0x18 +#define IRP_MJ_QUERY_QUOTA 0x19 +#define IRP_MJ_SET_QUOTA 0x1a +#define IRP_MJ_PNP 0x1b +#define IRP_MJ_PNP_POWER IRP_MJ_PNP // Obsolete.... +#define IRP_MJ_MAXIMUM_FUNCTION 0x1b +#define IRP_MJ_SCSI IRP_MJ_INTERNAL_DEVICE_CONTROL + +/* IRP minor codes */ + +#define IRP_MN_QUERY_DIRECTORY 0x01 +#define IRP_MN_NOTIFY_CHANGE_DIRECTORY 0x02 +#define IRP_MN_USER_FS_REQUEST 0x00 + +#define IRP_MN_MOUNT_VOLUME 0x01 +#define IRP_MN_VERIFY_VOLUME 0x02 +#define IRP_MN_LOAD_FILE_SYSTEM 0x03 +#define IRP_MN_TRACK_LINK 0x04 +#define IRP_MN_KERNEL_CALL 0x04 + +#define IRP_MN_LOCK 0x01 +#define IRP_MN_UNLOCK_SINGLE 0x02 +#define IRP_MN_UNLOCK_ALL 0x03 +#define IRP_MN_UNLOCK_ALL_BY_KEY 0x04 + +#define IRP_MN_NORMAL 0x00 +#define IRP_MN_DPC 0x01 +#define IRP_MN_MDL 0x02 +#define IRP_MN_COMPLETE 0x04 +#define IRP_MN_COMPRESSED 0x08 + +#define IRP_MN_MDL_DPC (IRP_MN_MDL | IRP_MN_DPC) +#define IRP_MN_COMPLETE_MDL (IRP_MN_COMPLETE | IRP_MN_MDL) +#define IRP_MN_COMPLETE_MDL_DPC (IRP_MN_COMPLETE_MDL | IRP_MN_DPC) + +#define IRP_MN_SCSI_CLASS 0x01 + +#define IRP_MN_START_DEVICE 0x00 +#define IRP_MN_QUERY_REMOVE_DEVICE 0x01 +#define IRP_MN_REMOVE_DEVICE 0x02 +#define IRP_MN_CANCEL_REMOVE_DEVICE 0x03 +#define IRP_MN_STOP_DEVICE 0x04 +#define IRP_MN_QUERY_STOP_DEVICE 0x05 +#define IRP_MN_CANCEL_STOP_DEVICE 0x06 + +#define IRP_MN_QUERY_DEVICE_RELATIONS 0x07 +#define IRP_MN_QUERY_INTERFACE 0x08 +#define IRP_MN_QUERY_CAPABILITIES 0x09 +#define IRP_MN_QUERY_RESOURCES 0x0A +#define IRP_MN_QUERY_RESOURCE_REQUIREMENTS 0x0B +#define IRP_MN_QUERY_DEVICE_TEXT 0x0C +#define IRP_MN_FILTER_RESOURCE_REQUIREMENTS 0x0D + +#define IRP_MN_READ_CONFIG 0x0F +#define IRP_MN_WRITE_CONFIG 0x10 +#define IRP_MN_EJECT 0x11 +#define IRP_MN_SET_LOCK 0x12 +#define IRP_MN_QUERY_ID 0x13 +#define IRP_MN_QUERY_PNP_DEVICE_STATE 0x14 +#define IRP_MN_QUERY_BUS_INFORMATION 0x15 +#define IRP_MN_DEVICE_USAGE_NOTIFICATION 0x16 +#define IRP_MN_SURPRISE_REMOVAL 0x17 +#define IRP_MN_QUERY_LEGACY_BUS_INFORMATION 0x18 + +#define IRP_MN_WAIT_WAKE 0x00 +#define IRP_MN_POWER_SEQUENCE 0x01 +#define IRP_MN_SET_POWER 0x02 +#define IRP_MN_QUERY_POWER 0x03 + +#define IRP_MN_QUERY_ALL_DATA 0x00 +#define IRP_MN_QUERY_SINGLE_INSTANCE 0x01 +#define IRP_MN_CHANGE_SINGLE_INSTANCE 0x02 +#define IRP_MN_CHANGE_SINGLE_ITEM 0x03 +#define IRP_MN_ENABLE_EVENTS 0x04 +#define IRP_MN_DISABLE_EVENTS 0x05 +#define IRP_MN_ENABLE_COLLECTION 0x06 +#define IRP_MN_DISABLE_COLLECTION 0x07 +#define IRP_MN_REGINFO 0x08 +#define IRP_MN_EXECUTE_METHOD 0x09 +#define IRP_MN_REGINFO_EX 0x0b + +/* IRP flags */ + +#define IRP_NOCACHE 0x00000001 +#define IRP_PAGING_IO 0x00000002 +#define IRP_MOUNT_COMPLETION 0x00000002 +#define IRP_SYNCHRONOUS_API 0x00000004 +#define IRP_ASSOCIATED_IRP 0x00000008 +#define IRP_BUFFERED_IO 0x00000010 +#define IRP_DEALLOCATE_BUFFER 0x00000020 +#define IRP_INPUT_OPERATION 0x00000040 +#define IRP_SYNCHRONOUS_PAGING_IO 0x00000040 +#define IRP_CREATE_OPERATION 0x00000080 +#define IRP_READ_OPERATION 0x00000100 +#define IRP_WRITE_OPERATION 0x00000200 +#define IRP_CLOSE_OPERATION 0x00000400 +#define IRP_DEFER_IO_COMPLETION 0x00000800 +#define IRP_OB_QUERY_NAME 0x00001000 +#define IRP_HOLD_DEVICE_QUEUE 0x00002000 +#define IRP_RETRY_IO_COMPLETION 0x00004000 +#define IRP_CLASS_CACHE_OPERATION 0x00008000 +#define IRP_SET_USER_EVENT IRP_CLOSE_OPERATION + +/* IRP I/O control flags */ + +#define IRP_QUOTA_CHARGED 0x01 +#define IRP_ALLOCATED_MUST_SUCCEED 0x02 +#define IRP_ALLOCATED_FIXED_SIZE 0x04 +#define IRP_LOOKASIDE_ALLOCATION 0x08 + +/* I/O method types */ + +#define METHOD_BUFFERED 0 +#define METHOD_IN_DIRECT 1 +#define METHOD_OUT_DIRECT 2 +#define METHOD_NEITHER 3 + +/* File access types */ + +#define FILE_ANY_ACCESS 0x0000 +#define FILE_SPECIAL_ACCESS FILE_ANY_ACCESS +#define FILE_READ_ACCESS 0x0001 +#define FILE_WRITE_ACCESS 0x0002 + +/* Recover I/O access method from IOCTL code. */ + +#define IO_METHOD(x) ((x) & 0xFFFFFFFC) + +/* Recover function code from IOCTL code */ + +#define IO_FUNC(x) (((x) & 0x7FFC) >> 2) + +/* Macro to construct an IOCTL code. */ + +#define IOCTL_CODE(dev, func, iomethod, acc) \ + ((dev) << 16) | (acc << 14) | (func << 2) | (iomethod)) + + +struct io_status_block { + union { + uint32_t isb_status; + void *isb_ptr; + } u; + register_t isb_info; +}; +#define isb_status u.isb_status +#define isb_ptr u.isb_ptr + +typedef struct io_status_block io_status_block; + +struct kapc { + uint16_t apc_type; + uint16_t apc_size; + uint32_t apc_spare0; + void *apc_thread; + list_entry apc_list; + void *apc_kernfunc; + void *apc_rundownfunc; + void *apc_normalfunc; + void *apc_normctx; + void *apc_sysarg1; + void *apc_sysarg2; + uint8_t apc_stateidx; + uint8_t apc_cpumode; + uint8_t apc_inserted; +}; + +typedef struct kapc kapc; + +typedef uint32_t (*completion_func)(device_object *, + struct irp *, void *); +typedef uint32_t (*cancel_func)(device_object *, + struct irp *); + +struct io_stack_location { + uint8_t isl_major; + uint8_t isl_minor; + uint8_t isl_flags; + uint8_t isl_ctl; + + /* + * There's a big-ass union here in the actual Windows + * definition of the stucture, but it contains stuff + * that doesn't really apply to BSD, and defining it + * all properly would require duplicating over a dozen + * other structures that we'll never use. Since the + * io_stack_location structure is opaque to drivers + * anyway, I'm not going to bother with the extra crap. + */ + + union { + struct { + uint32_t isl_len; + uint32_t *isl_key; + uint64_t isl_byteoff; + } isl_read; + struct { + uint32_t isl_len; + uint32_t *isl_key; + uint64_t isl_byteoff; + } isl_write; + struct { + uint32_t isl_obuflen; + uint32_t isl_ibuflen; + uint32_t isl_iocode; + void *isl_type3ibuf; + } isl_ioctl; + struct { + void *isl_arg1; + void *isl_arg2; + void *isl_arg3; + void *isl_arg4; + } isl_others; + } isl_parameters __attribute__((packed)); + + void *isl_devobj; + void *isl_fileobj; + completion_func isl_completionfunc; + void *isl_completionctx; +}; + +typedef struct io_stack_location io_stack_location; + +/* Stack location control flags */ + +#define SL_PENDING_RETURNED 0x01 +#define SL_INVOKE_ON_CANCEL 0x20 +#define SL_INVOKE_ON_SUCCESS 0x40 +#define SL_INVOKE_ON_ERROR 0x80 + +struct irp { + uint16_t irp_type; + uint16_t irp_size; + mdl *irp_mdl; + uint32_t irp_flags; + union { + struct irp *irp_master; + uint32_t irp_irpcnt; + void *irp_sysbuf; + } irp_assoc; + list_entry irp_thlist; + io_status_block irp_iostat; + uint8_t irp_reqmode; + uint8_t irp_pendingreturned; + uint8_t irp_stackcnt; + uint8_t irp_currentstackloc; + uint8_t irp_cancel; + uint8_t irp_cancelirql; + uint8_t irp_apcenv; + uint8_t irp_allocflags; + io_status_block *irp_usriostat; + nt_kevent *irp_usrevent; + union { + struct { + void *irp_apcfunc; + void *irp_apcctx; + } irp_asyncparms; + uint64_t irp_allocsz; + } irp_overlay; + cancel_func irp_cancelfunc; + void *irp_userbuf; + + /* Windows kernel info */ + + union { + struct { + union { + kdevice_qentry irp_dqe; + struct { + void *irp_drvctx[4]; + } s1; + } u1; + void *irp_thread; + char *irp_auxbuf; + struct { + list_entry irp_list; + union { + io_stack_location *irp_csl; + uint32_t irp_pkttype; + } u2; + } s2; + void *irp_fileobj; + } irp_overlay; + union { + kapc irp_apc; + struct { + void *irp_ep; + void *irp_dev; + } irp_usb; + } irp_misc; + void *irp_compkey; + } irp_tail; +}; + +#define irp_csl s2.u2.irp_csl +#define irp_pkttype s2.u2.irp_pkttype + +#define IRP_NDIS_DEV(irp) (irp)->irp_tail.irp_misc.irp_usb.irp_dev +#define IRP_NDISUSB_EP(irp) (irp)->irp_tail.irp_misc.irp_usb.irp_ep + +typedef struct irp irp; + +#define InterlockedExchangePointer(dst, val) \ + (void *)InterlockedExchange((uint32_t *)(dst), (uintptr_t)(val)) + +#define IoSizeOfIrp(ssize) \ + ((uint16_t) (sizeof(irp) + ((ssize) * (sizeof(io_stack_location))))) + +#define IoSetCancelRoutine(irp, func) \ + (cancel_func)InterlockedExchangePointer( \ + (void *)&(ip)->irp_cancelfunc, (void *)(func)) + +#define IoSetCancelValue(irp, val) \ + (u_long)InterlockedExchangePointer( \ + (void *)&(ip)->irp_cancel, (void *)(val)) + +#define IoGetCurrentIrpStackLocation(irp) \ + (irp)->irp_tail.irp_overlay.irp_csl + +#define IoGetNextIrpStackLocation(irp) \ + ((irp)->irp_tail.irp_overlay.irp_csl - 1) + +#define IoSetNextIrpStackLocation(irp) \ + do { \ + irp->irp_currentstackloc--; \ + irp->irp_tail.irp_overlay.irp_csl--; \ + } while(0) + +#define IoSetCompletionRoutine(irp, func, ctx, ok, err, cancel) \ + do { \ + io_stack_location *s; \ + s = IoGetNextIrpStackLocation((irp)); \ + s->isl_completionfunc = (func); \ + s->isl_completionctx = (ctx); \ + s->isl_ctl = 0; \ + if (ok) s->isl_ctl = SL_INVOKE_ON_SUCCESS; \ + if (err) s->isl_ctl |= SL_INVOKE_ON_ERROR; \ + if (cancel) s->isl_ctl |= SL_INVOKE_ON_CANCEL; \ + } while(0) + +#define IoMarkIrpPending(irp) \ + IoGetCurrentIrpStackLocation(irp)->isl_ctl |= SL_PENDING_RETURNED +#define IoUnmarkIrpPending(irp) \ + IoGetCurrentIrpStackLocation(irp)->isl_ctl &= ~SL_PENDING_RETURNED + +#define IoCopyCurrentIrpStackLocationToNext(irp) \ + do { \ + io_stack_location *src, *dst; \ + src = IoGetCurrentIrpStackLocation(irp); \ + dst = IoGetNextIrpStackLocation(irp); \ + bcopy((char *)src, (char *)dst, \ + offsetof(io_stack_location, isl_completionfunc)); \ + } while(0) + +#define IoSkipCurrentIrpStackLocation(irp) \ + do { \ + (irp)->irp_currentstackloc++; \ + (irp)->irp_tail.irp_overlay.irp_csl++; \ + } while(0) + +#define IoInitializeDpcRequest(dobj, dpcfunc) \ + KeInitializeDpc(&(dobj)->do_dpc, dpcfunc, dobj) + +#define IoRequestDpc(dobj, irp, ctx) \ + KeInsertQueueDpc(&(dobj)->do_dpc, irp, ctx) + +typedef uint32_t (*driver_dispatch)(device_object *, irp *); + +/* + * The driver_object is allocated once for each driver that's loaded + * into the system. A new one is allocated for each driver and + * populated a bit via the driver's DriverEntry function. + * In general, a Windows DriverEntry() function will provide a pointer + * to its AddDevice() method and set up the dispatch table. + * For NDIS drivers, this is all done behind the scenes in the + * NdisInitializeWrapper() and/or NdisMRegisterMiniport() routines. + */ + +struct driver_object { + uint16_t dro_type; + uint16_t dro_size; + device_object *dro_devobj; + uint32_t dro_flags; + void *dro_driverstart; + uint32_t dro_driversize; + void *dro_driversection; + driver_extension *dro_driverext; + unicode_string dro_drivername; + unicode_string *dro_hwdb; + void *dro_pfastiodispatch; + void *dro_driverinitfunc; + void *dro_driverstartiofunc; + void *dro_driverunloadfunc; + driver_dispatch dro_dispatch[IRP_MJ_MAXIMUM_FUNCTION + 1]; +}; + +typedef struct driver_object driver_object; + +#define DEVPROP_DEVICE_DESCRIPTION 0x00000000 +#define DEVPROP_HARDWARE_ID 0x00000001 +#define DEVPROP_COMPATIBLE_IDS 0x00000002 +#define DEVPROP_BOOTCONF 0x00000003 +#define DEVPROP_BOOTCONF_TRANSLATED 0x00000004 +#define DEVPROP_CLASS_NAME 0x00000005 +#define DEVPROP_CLASS_GUID 0x00000006 +#define DEVPROP_DRIVER_KEYNAME 0x00000007 +#define DEVPROP_MANUFACTURER 0x00000008 +#define DEVPROP_FRIENDLYNAME 0x00000009 +#define DEVPROP_LOCATION_INFO 0x0000000A +#define DEVPROP_PHYSDEV_NAME 0x0000000B +#define DEVPROP_BUSTYPE_GUID 0x0000000C +#define DEVPROP_LEGACY_BUSTYPE 0x0000000D +#define DEVPROP_BUS_NUMBER 0x0000000E +#define DEVPROP_ENUMERATOR_NAME 0x0000000F +#define DEVPROP_ADDRESS 0x00000010 +#define DEVPROP_UINUMBER 0x00000011 +#define DEVPROP_INSTALL_STATE 0x00000012 +#define DEVPROP_REMOVAL_POLICY 0x00000013 + +/* Various supported device types (used with IoCreateDevice()) */ + +#define FILE_DEVICE_BEEP 0x00000001 +#define FILE_DEVICE_CD_ROM 0x00000002 +#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 +#define FILE_DEVICE_CONTROLLER 0x00000004 +#define FILE_DEVICE_DATALINK 0x00000005 +#define FILE_DEVICE_DFS 0x00000006 +#define FILE_DEVICE_DISK 0x00000007 +#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008 +#define FILE_DEVICE_FILE_SYSTEM 0x00000009 +#define FILE_DEVICE_INPORT_PORT 0x0000000A +#define FILE_DEVICE_KEYBOARD 0x0000000B +#define FILE_DEVICE_MAILSLOT 0x0000000C +#define FILE_DEVICE_MIDI_IN 0x0000000D +#define FILE_DEVICE_MIDI_OUT 0x0000000E +#define FILE_DEVICE_MOUSE 0x0000000F +#define FILE_DEVICE_MULTI_UNC_PROVIDER 0x00000010 +#define FILE_DEVICE_NAMED_PIPE 0x00000011 +#define FILE_DEVICE_NETWORK 0x00000012 +#define FILE_DEVICE_NETWORK_BROWSER 0x00000013 +#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014 +#define FILE_DEVICE_NULL 0x00000015 +#define FILE_DEVICE_PARALLEL_PORT 0x00000016 +#define FILE_DEVICE_PHYSICAL_NETCARD 0x00000017 +#define FILE_DEVICE_PRINTER 0x00000018 +#define FILE_DEVICE_SCANNER 0x00000019 +#define FILE_DEVICE_SERIAL_MOUSE_PORT 0x0000001A +#define FILE_DEVICE_SERIAL_PORT 0x0000001B +#define FILE_DEVICE_SCREEN 0x0000001C +#define FILE_DEVICE_SOUND 0x0000001D +#define FILE_DEVICE_STREAMS 0x0000001E +#define FILE_DEVICE_TAPE 0x0000001F +#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020 +#define FILE_DEVICE_TRANSPORT 0x00000021 +#define FILE_DEVICE_UNKNOWN 0x00000022 +#define FILE_DEVICE_VIDEO 0x00000023 +#define FILE_DEVICE_VIRTUAL_DISK 0x00000024 +#define FILE_DEVICE_WAVE_IN 0x00000025 +#define FILE_DEVICE_WAVE_OUT 0x00000026 +#define FILE_DEVICE_8042_PORT 0x00000027 +#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028 +#define FILE_DEVICE_BATTERY 0x00000029 +#define FILE_DEVICE_BUS_EXTENDER 0x0000002A +#define FILE_DEVICE_MODEM 0x0000002B +#define FILE_DEVICE_VDM 0x0000002C +#define FILE_DEVICE_MASS_STORAGE 0x0000002D +#define FILE_DEVICE_SMB 0x0000002E +#define FILE_DEVICE_KS 0x0000002F +#define FILE_DEVICE_CHANGER 0x00000030 +#define FILE_DEVICE_SMARTCARD 0x00000031 +#define FILE_DEVICE_ACPI 0x00000032 +#define FILE_DEVICE_DVD 0x00000033 +#define FILE_DEVICE_FULLSCREEN_VIDEO 0x00000034 +#define FILE_DEVICE_DFS_FILE_SYSTEM 0x00000035 +#define FILE_DEVICE_DFS_VOLUME 0x00000036 +#define FILE_DEVICE_SERENUM 0x00000037 +#define FILE_DEVICE_TERMSRV 0x00000038 +#define FILE_DEVICE_KSEC 0x00000039 +#define FILE_DEVICE_FIPS 0x0000003A + +/* Device characteristics */ + +#define FILE_REMOVABLE_MEDIA 0x00000001 +#define FILE_READ_ONLY_DEVICE 0x00000002 +#define FILE_FLOPPY_DISKETTE 0x00000004 +#define FILE_WRITE_ONCE_MEDIA 0x00000008 +#define FILE_REMOTE_DEVICE 0x00000010 +#define FILE_DEVICE_IS_MOUNTED 0x00000020 +#define FILE_VIRTUAL_VOLUME 0x00000040 +#define FILE_AUTOGENERATED_DEVICE_NAME 0x00000080 +#define FILE_DEVICE_SECURE_OPEN 0x00000100 + +/* Status codes */ + +#define STATUS_SUCCESS 0x00000000 +#define STATUS_USER_APC 0x000000C0 +#define STATUS_KERNEL_APC 0x00000100 +#define STATUS_ALERTED 0x00000101 +#define STATUS_TIMEOUT 0x00000102 +#define STATUS_PENDING 0x00000103 +#define STATUS_FAILURE 0xC0000001 +#define STATUS_NOT_IMPLEMENTED 0xC0000002 +#define STATUS_ACCESS_VIOLATION 0xC0000005 +#define STATUS_INVALID_PARAMETER 0xC000000D +#define STATUS_INVALID_DEVICE_REQUEST 0xC0000010 +#define STATUS_MORE_PROCESSING_REQUIRED 0xC0000016 +#define STATUS_NO_MEMORY 0xC0000017 +#define STATUS_BUFFER_TOO_SMALL 0xC0000023 +#define STATUS_MUTANT_NOT_OWNED 0xC0000046 +#define STATUS_NOT_SUPPORTED 0xC00000BB +#define STATUS_INVALID_PARAMETER_2 0xC00000F0 +#define STATUS_INSUFFICIENT_RESOURCES 0xC000009A +#define STATUS_DEVICE_NOT_CONNECTED 0xC000009D +#define STATUS_CANCELLED 0xC0000120 +#define STATUS_NOT_FOUND 0xC0000225 +#define STATUS_DEVICE_REMOVED 0xC00002B6 + +#define STATUS_WAIT_0 0x00000000 + +/* Memory pool types, for ExAllocatePoolWithTag() */ + +#define NonPagedPool 0x00000000 +#define PagedPool 0x00000001 +#define NonPagedPoolMustSucceed 0x00000002 +#define DontUseThisType 0x00000003 +#define NonPagedPoolCacheAligned 0x00000004 +#define PagedPoolCacheAligned 0x00000005 +#define NonPagedPoolCacheAlignedMustS 0x00000006 +#define MaxPoolType 0x00000007 + +/* + * IO_WORKITEM is an opaque structures that must be allocated + * via IoAllocateWorkItem() and released via IoFreeWorkItem(). + * Consequently, we can define it any way we want. + */ +typedef void (*io_workitem_func)(device_object *, void *); + +struct io_workitem { + io_workitem_func iw_func; + void *iw_ctx; + list_entry iw_listentry; + device_object *iw_dobj; + int iw_idx; +}; + +typedef struct io_workitem io_workitem; + +#define WORKQUEUE_CRITICAL 0 +#define WORKQUEUE_DELAYED 1 +#define WORKQUEUE_HYPERCRITICAL 2 + +#define WORKITEM_THREADS 4 +#define WORKITEM_LEGACY_THREAD 3 +#define WORKIDX_INC(x) (x) = (x + 1) % WORKITEM_LEGACY_THREAD + +/* + * Older, deprecated work item API, needed to support NdisQueueWorkItem(). + */ + +struct work_queue_item; + +typedef void (*work_item_func)(struct work_queue_item *, void *); + +struct work_queue_item { + list_entry wqi_entry; + work_item_func wqi_func; + void *wqi_ctx; +}; + +typedef struct work_queue_item work_queue_item; + +#define ExInitializeWorkItem(w, func, ctx) \ + do { \ + (w)->wqi_func = (func); \ + (w)->wqi_ctx = (ctx); \ + InitializeListHead(&((w)->wqi_entry)); \ + } while (0) + +/* + * FreeBSD's kernel stack is 2 pages in size by default. The + * Windows stack is larger, so we need to give our threads more + * stack pages. 4 should be enough, we use 8 just to extra safe. + */ +#define NDIS_KSTACK_PAGES 8 + +/* + * Different kinds of function wrapping we can do. + */ + +#define WINDRV_WRAP_STDCALL 1 +#define WINDRV_WRAP_FASTCALL 2 +#define WINDRV_WRAP_REGPARM 3 +#define WINDRV_WRAP_CDECL 4 +#define WINDRV_WRAP_AMD64 5 + +struct drvdb_ent { + driver_object *windrv_object; + void *windrv_devlist; + ndis_cfg *windrv_regvals; + interface_type windrv_bustype; + STAILQ_ENTRY(drvdb_ent) link; +}; + +extern image_patch_table ntoskrnl_functbl[]; +#ifdef __amd64__ +extern struct kuser_shared_data kuser_shared_data; +#endif +typedef void (*funcptr)(void); +typedef int (*matchfuncptr)(interface_type, void *, void *); + +__BEGIN_DECLS +extern int windrv_libinit(void); +extern int windrv_libfini(void); +extern driver_object *windrv_lookup(vm_offset_t, char *); +extern struct drvdb_ent *windrv_match(matchfuncptr, void *); +extern int windrv_load(module_t, vm_offset_t, int, interface_type, + void *, ndis_cfg *); +extern int windrv_unload(module_t, vm_offset_t, int); +extern int windrv_create_pdo(driver_object *, device_t); +extern void windrv_destroy_pdo(driver_object *, device_t); +extern device_object *windrv_find_pdo(driver_object *, device_t); +extern int windrv_bus_attach(driver_object *, char *); +extern int windrv_wrap(funcptr, funcptr *, int, int); +extern int windrv_unwrap(funcptr); +extern void ctxsw_utow(void); +extern void ctxsw_wtou(void); + +extern int ntoskrnl_libinit(void); +extern int ntoskrnl_libfini(void); + +extern void ntoskrnl_intr(void *); +extern void ntoskrnl_time(uint64_t *); + +extern uint16_t ExQueryDepthSList(slist_header *); +extern slist_entry + *InterlockedPushEntrySList(slist_header *, slist_entry *); +extern slist_entry *InterlockedPopEntrySList(slist_header *); +extern uint32_t RtlUnicodeStringToAnsiString(ansi_string *, + unicode_string *, uint8_t); +extern uint32_t RtlAnsiStringToUnicodeString(unicode_string *, + ansi_string *, uint8_t); +extern void RtlInitAnsiString(ansi_string *, char *); +extern void RtlInitUnicodeString(unicode_string *, + uint16_t *); +extern void RtlFreeUnicodeString(unicode_string *); +extern void RtlFreeAnsiString(ansi_string *); +extern void KeInitializeDpc(kdpc *, void *, void *); +extern uint8_t KeInsertQueueDpc(kdpc *, void *, void *); +extern uint8_t KeRemoveQueueDpc(kdpc *); +extern void KeSetImportanceDpc(kdpc *, uint32_t); +extern void KeSetTargetProcessorDpc(kdpc *, uint8_t); +extern void KeFlushQueuedDpcs(void); +extern uint32_t KeGetCurrentProcessorNumber(void); +extern void KeInitializeTimer(ktimer *); +extern void KeInitializeTimerEx(ktimer *, uint32_t); +extern uint8_t KeSetTimer(ktimer *, int64_t, kdpc *); +extern uint8_t KeSetTimerEx(ktimer *, int64_t, uint32_t, kdpc *); +extern uint8_t KeCancelTimer(ktimer *); +extern uint8_t KeReadStateTimer(ktimer *); +extern uint32_t KeWaitForSingleObject(void *, uint32_t, + uint32_t, uint8_t, int64_t *); +extern void KeInitializeEvent(nt_kevent *, uint32_t, uint8_t); +extern void KeClearEvent(nt_kevent *); +extern uint32_t KeReadStateEvent(nt_kevent *); +extern uint32_t KeSetEvent(nt_kevent *, uint32_t, uint8_t); +extern uint32_t KeResetEvent(nt_kevent *); +#ifdef __i386__ +extern void KefAcquireSpinLockAtDpcLevel(kspin_lock *); +extern void KefReleaseSpinLockFromDpcLevel(kspin_lock *); +extern uint8_t KeAcquireSpinLockRaiseToDpc(kspin_lock *); +#else +extern void KeAcquireSpinLockAtDpcLevel(kspin_lock *); +extern void KeReleaseSpinLockFromDpcLevel(kspin_lock *); +#endif +extern void KeInitializeSpinLock(kspin_lock *); +extern uint8_t KeAcquireInterruptSpinLock(kinterrupt *); +extern void KeReleaseInterruptSpinLock(kinterrupt *, uint8_t); +extern uint8_t KeSynchronizeExecution(kinterrupt *, void *, void *); +extern uintptr_t InterlockedExchange(volatile uint32_t *, + uintptr_t); +extern void *ExAllocatePoolWithTag(uint32_t, size_t, uint32_t); +extern void ExFreePool(void *); +extern uint32_t IoConnectInterrupt(kinterrupt **, void *, void *, + kspin_lock *, uint32_t, uint8_t, uint8_t, uint8_t, uint8_t, + uint32_t, uint8_t); +extern uint8_t MmIsAddressValid(void *); +extern void *MmGetSystemRoutineAddress(unicode_string *); +extern void *MmMapIoSpace(uint64_t, uint32_t, uint32_t); +extern void MmUnmapIoSpace(void *, size_t); +extern void MmBuildMdlForNonPagedPool(mdl *); +extern void IoDisconnectInterrupt(kinterrupt *); +extern uint32_t IoAllocateDriverObjectExtension(driver_object *, + void *, uint32_t, void **); +extern void *IoGetDriverObjectExtension(driver_object *, void *); +extern uint32_t IoCreateDevice(driver_object *, uint32_t, + unicode_string *, uint32_t, uint32_t, uint8_t, device_object **); +extern void IoDeleteDevice(device_object *); +extern device_object *IoGetAttachedDevice(device_object *); +extern uint32_t IofCallDriver(device_object *, irp *); +extern void IofCompleteRequest(irp *, uint8_t); +extern void IoAcquireCancelSpinLock(uint8_t *); +extern void IoReleaseCancelSpinLock(uint8_t); +extern uint8_t IoCancelIrp(irp *); +extern void IoDetachDevice(device_object *); +extern device_object *IoAttachDeviceToDeviceStack(device_object *, + device_object *); +extern mdl *IoAllocateMdl(void *, uint32_t, uint8_t, uint8_t, irp *); +extern void IoFreeMdl(mdl *); +extern io_workitem *IoAllocateWorkItem(device_object *); +extern void ExQueueWorkItem(work_queue_item *, u_int32_t); +extern void IoFreeWorkItem(io_workitem *); +extern void IoQueueWorkItem(io_workitem *, io_workitem_func, + uint32_t, void *); + +#define IoCallDriver(a, b) IofCallDriver(a, b) +#define IoCompleteRequest(a, b) IofCompleteRequest(a, b) + +/* + * On the Windows x86 arch, KeAcquireSpinLock() and KeReleaseSpinLock() + * routines live in the HAL. We try to imitate this behavior. + */ +#ifdef __i386__ +#define KI_USER_SHARED_DATA 0xffdf0000 +#define KeAcquireSpinLock(a, b) *(b) = KfAcquireSpinLock(a) +#define KeReleaseSpinLock(a, b) KfReleaseSpinLock(a, b) +#define KeRaiseIrql(a, b) *(b) = KfRaiseIrql(a) +#define KeLowerIrql(a) KfLowerIrql(a) +#define KeAcquireSpinLockAtDpcLevel(a) KefAcquireSpinLockAtDpcLevel(a) +#define KeReleaseSpinLockFromDpcLevel(a) KefReleaseSpinLockFromDpcLevel(a) +#endif /* __i386__ */ + +#ifdef __amd64__ +#define KI_USER_SHARED_DATA 0xfffff78000000000UL +#define KeAcquireSpinLock(a, b) *(b) = KfAcquireSpinLock(a) +#define KeReleaseSpinLock(a, b) KfReleaseSpinLock(a, b) + +/* + * These may need to be redefined later; + * not sure where they live on amd64 yet. + */ +#define KeRaiseIrql(a, b) *(b) = KfRaiseIrql(a) +#define KeLowerIrql(a) KfLowerIrql(a) +#endif /* __amd64__ */ + +__END_DECLS + +#endif /* _NTOSKRNL_VAR_H_ */ diff --git a/sys/compat/ndis/pe_var.h b/sys/compat/ndis/pe_var.h new file mode 100644 index 0000000..84e0162 --- /dev/null +++ b/sys/compat/ndis/pe_var.h @@ -0,0 +1,549 @@ +/*- + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.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, 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 Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD + * 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 _PE_VAR_H_ +#define _PE_VAR_H_ + +/* + * Image Format + */ + +#define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */ +#define IMAGE_OS2_SIGNATURE 0x454E /* NE */ +#define IMAGE_OS2_SIGNATURE_LE 0x454C /* LE */ +#define IMAGE_VXD_SIGNATURE 0x454C /* LE */ +#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */ + +/* + * All PE files have one of these, just so if you attempt to + * run them, they'll print out a message telling you they can + * only be run in Windows. + */ + +struct image_dos_header { + uint16_t idh_magic; /* Magic number */ + uint16_t idh_cblp; /* Bytes on last page of file */ + uint16_t idh_cp; /* Pages in file */ + uint16_t idh_crlc; /* Relocations */ + uint16_t idh_cparhdr; /* Size of header in paragraphs */ + uint16_t idh_minalloc; /* Minimum extra paragraphs needed */ + uint16_t idh_maxalloc; /* Maximum extra paragraphs needed */ + uint16_t idh_ss; /* Initial (relative) SS value */ + uint16_t idh_sp; /* Initial SP value */ + uint16_t idh_csum; /* Checksum */ + uint16_t idh_ip; /* Initial IP value */ + uint16_t idh_cs; /* Initial (relative) CS value */ + uint16_t idh_lfarlc; /* File address of relocation table */ + uint16_t idh_ovno; /* Overlay number */ + uint16_t idh_rsvd1[4]; /* Reserved words */ + uint16_t idh_oemid; /* OEM identifier (for idh_oeminfo) */ + uint16_t idh_oeminfo; /* OEM information; oemid specific */ + uint16_t idh_rsvd2[10]; /* Reserved words */ + uint32_t idh_lfanew; /* File address of new exe header */ +}; + +typedef struct image_dos_header image_dos_header; + +/* + * File header format. + */ + +struct image_file_header { + uint16_t ifh_machine; /* Machine type */ + uint16_t ifh_numsections; /* # of sections */ + uint32_t ifh_timestamp; /* Date/time stamp */ + uint32_t ifh_symtblptr; /* Offset to symbol table */ + uint32_t ifh_numsyms; /* # of symbols */ + uint16_t ifh_optionalhdrlen; /* Size of optional header */ + uint16_t ifh_characteristics; /* Characteristics */ +}; + +typedef struct image_file_header image_file_header; + +/* Machine types */ + +#define IMAGE_FILE_MACHINE_UNKNOWN 0 +#define IMAGE_FILE_MACHINE_I860 0x014d +#define IMAGE_FILE_MACHINE_I386 0x014c +#define IMAGE_FILE_MACHINE_R3000 0x0162 +#define IMAGE_FILE_MACHINE_R4000 0x0166 +#define IMAGE_FILE_MACHINE_R10000 0x0168 +#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 +#define IMAGE_FILE_MACHINE_ALPHA 0x0184 +#define IMAGE_FILE_MACHINE_SH3 0x01a2 +#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 +#define IMAGE_FILE_MACHINE_SH3E 0x01a4 +#define IMAGE_FILE_MACHINE_SH4 0x01a6 +#define IMAGE_FILE_MACHINE_SH5 0x01a8 +#define IMAGE_FILE_MACHINE_ARM 0x01c0 +#define IMAGE_FILE_MACHINE_THUMB 0x01c2 +#define IMAGE_FILE_MACHINE_AM33 0x01d3 +#define IMAGE_FILE_MACHINE_POWERPC 0x01f0 +#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 +#define IMAGE_FILE_MACHINE_IA64 0x0200 +#define IMAGE_FILE_MACHINE_MIPS16 0x0266 +#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 +#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 +#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 +#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64 +#define IMAGE_FILE_MACHINE_TRICORE 0x0520 +#define IMAGE_FILE_MACHINE_CEF 0x0cef +#define IMAGE_FILE_MACHINE_EBC 0x0ebc +#define IMAGE_FILE_MACHINE_AMD64 0x8664 +#define IMAGE_FILE_MACHINE_M32R 0x9041 +#define IMAGE_FILE_MACHINE_CEE 0xc0ee + +/* Characteristics */ + +#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 /* No relocation info */ +#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 +#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 +#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 +#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 +#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 +#define IMAGE_FILE_16BIT_MACHINE 0x0040 +#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 +#define IMAGE_FILE_32BIT_MACHINE 0x0100 +#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 +#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 +#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 +#define IMAGE_FILE_SYSTEM 0x1000 +#define IMAGE_FILE_DLL 0x2000 +#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 +#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 + +#define IMAGE_SIZEOF_FILE_HEADER 20 + +/* + * Directory format. + */ + +struct image_data_directory { + uint32_t idd_vaddr; /* virtual address */ + uint32_t idd_size; /* size */ +}; + +typedef struct image_data_directory image_data_directory; + +#define IMAGE_DIRECTORY_ENTRIES_MAX 16 + +/* + * Optional header format. + */ + +struct image_optional_header { + + /* Standard fields */ + + uint16_t ioh_magic; + uint8_t ioh_linkerver_major; + uint8_t ioh_linkerver_minor; + uint32_t ioh_codesize; + uint32_t ioh_datasize; + uint32_t ioh_bsssize; + uint32_t ioh_entryaddr; + uint32_t ioh_codebaseaddr; +#ifndef __amd64__ + uint32_t ioh_databaseaddr; +#endif + + /* NT-specific fields */ + + uintptr_t ioh_imagebase; + uint32_t ioh_sectalign; + uint32_t ioh_filealign; + uint16_t ioh_osver_major; + uint16_t ioh_osver_minor; + uint16_t ioh_imagever_major; + uint16_t ioh_imagever_minor; + uint16_t ioh_subsys_major; + uint16_t ioh_subsys_minor; + uint32_t ioh_win32ver; + uint32_t ioh_imagesize; + uint32_t ioh_headersize; + uint32_t ioh_csum; + uint16_t ioh_subsys; + uint16_t ioh_dll_characteristics; + uintptr_t ioh_stackreservesize; + uintptr_t ioh_stackcommitsize; + uintptr_t ioh_heapreservesize; + uintptr_t ioh_heapcommitsize; + uint16_t ioh_loaderflags; + uint32_t ioh_rva_size_cnt; + image_data_directory ioh_datadir[IMAGE_DIRECTORY_ENTRIES_MAX]; +}; + +typedef struct image_optional_header image_optional_header; + +struct image_nt_header { + uint32_t inh_signature; + image_file_header inh_filehdr; + image_optional_header inh_optionalhdr; +}; + +typedef struct image_nt_header image_nt_header; + +#define IMAGE_SIZEOF_NT_HEADER(nthdr) \ + (offsetof(image_nt_header, inh_optionalhdr) + \ + ((image_nt_header *)(nthdr))->inh_filehdr.ifh_optionalhdrlen) + +/* Directory Entries */ + +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 /* Export Directory */ +#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 /* Import Directory */ +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 /* Resource Directory */ +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 /* Exception Directory */ +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 /* Security Directory */ +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 /* Base Relocation Table */ +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 /* Debug Directory */ +#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 /* Description String */ +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 /* Machine Value (MIPS GP) */ +#define IMAGE_DIRECTORY_ENTRY_TLS 9 /* TLS Directory */ +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 /* Load Configuration Directory */ +#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 /* Bound Import Directory in headers */ +#define IMAGE_DIRECTORY_ENTRY_IAT 12 /* Import Address Table */ +#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 +#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 + +/* Resource types */ + +#define RT_CURSOR 1 +#define RT_BITMAP 2 +#define RT_ICON 3 +#define RT_MENU 4 +#define RT_DIALOG 5 +#define RT_STRING 6 +#define RT_FONTDIR 7 +#define RT_FONT 8 +#define RT_ACCELERATOR 9 +#define RT_RCDATA 10 +#define RT_MESSAGETABLE 11 +#define RT_GROUP_CURSOR 12 +#define RT_GROUP_ICON 14 +#define RT_VERSION 16 +#define RT_DLGINCLUDE 17 +#define RT_PLUGPLAY 19 +#define RT_VXD 20 +#define RT_ANICURSOR 21 +#define RT_ANIICON 22 +#define RT_HTML 23 + +/* + * Section header format. + */ + +#define IMAGE_SHORT_NAME_LEN 8 + +struct image_section_header { + uint8_t ish_name[IMAGE_SHORT_NAME_LEN]; + union { + uint32_t ish_paddr; + uint32_t ish_vsize; + } ish_misc; + uint32_t ish_vaddr; + uint32_t ish_rawdatasize; + uint32_t ish_rawdataaddr; + uint32_t ish_relocaddr; + uint32_t ish_linenumaddr; + uint16_t ish_numrelocs; + uint16_t ish_numlinenums; + uint32_t ish_characteristics; +}; + +typedef struct image_section_header image_section_header; + +#define IMAGE_SIZEOF_SECTION_HEADER 40 + +#define IMAGE_FIRST_SECTION(nthdr) \ + ((image_section_header *)((vm_offset_t)(nthdr) + \ + offsetof(image_nt_header, inh_optionalhdr) + \ + ((image_nt_header *)(nthdr))->inh_filehdr.ifh_optionalhdrlen)) + +/* + * Import format + */ + +struct image_import_by_name { + uint16_t iibn_hint; + uint8_t iibn_name[1]; +}; + +#define IMAGE_ORDINAL_FLAG 0x80000000 +#define IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff) + +struct image_import_descriptor { + uint32_t iid_import_name_table_addr; + uint32_t iid_timestamp; + uint32_t iid_forwardchain; + uint32_t iid_nameaddr; + uint32_t iid_import_address_table_addr; +}; + +typedef struct image_import_descriptor image_import_descriptor; + +struct image_base_reloc { + uint32_t ibr_vaddr; + uint32_t ibr_blocksize; + uint16_t ibr_rel[1]; +}; + +typedef struct image_base_reloc image_base_reloc; + +#define IMR_RELTYPE(x) ((x >> 12) & 0xF) +#define IMR_RELOFFSET(x) (x & 0xFFF) + +/* generic relocation types */ +#define IMAGE_REL_BASED_ABSOLUTE 0 +#define IMAGE_REL_BASED_HIGH 1 +#define IMAGE_REL_BASED_LOW 2 +#define IMAGE_REL_BASED_HIGHLOW 3 +#define IMAGE_REL_BASED_HIGHADJ 4 +#define IMAGE_REL_BASED_MIPS_JMPADDR 5 +#define IMAGE_REL_BASED_SECTION 6 +#define IMAGE_REL_BASED_REL 7 +#define IMAGE_REL_BASED_MIPS_JMPADDR16 9 +#define IMAGE_REL_BASED_IA64_IMM64 9 /* yes, 9 too */ +#define IMAGE_REL_BASED_DIR64 10 +#define IMAGE_REL_BASED_HIGH3ADJ 11 + +struct image_resource_directory_entry { + uint32_t irde_name; + uint32_t irde_dataoff; +}; + +typedef struct image_resource_directory_entry image_resource_directory_entry; + +#define RESOURCE_NAME_STR 0x80000000 +#define RESOURCE_DIR_FLAG 0x80000000 + +struct image_resource_directory { + uint32_t ird_characteristics; + uint32_t ird_timestamp; + uint16_t ird_majorver; + uint16_t ird_minorver; + uint16_t ird_named_entries; + uint16_t ird_id_entries; +#ifdef notdef + image_resource_directory_entry ird_entries[1]; +#endif +}; + +typedef struct image_resource_directory image_resource_directory; + +struct image_resource_directory_string { + uint16_t irds_len; + char irds_name[1]; +}; + +typedef struct image_resource_directory_string image_resource_directory_string; + +struct image_resource_directory_string_u { + uint16_t irds_len; + char irds_name[1]; +}; + +typedef struct image_resource_directory_string_u + image_resource_directory_string_u; + +struct image_resource_data_entry { + uint32_t irde_offset; + uint32_t irde_size; + uint32_t irde_codepage; + uint32_t irde_rsvd; +}; + +typedef struct image_resource_data_entry image_resource_data_entry; + +struct message_resource_data { + uint32_t mrd_numblocks; +#ifdef notdef + message_resource_block mrd_blocks[1]; +#endif +}; + +typedef struct message_resource_data message_resource_data; + +struct message_resource_block { + uint32_t mrb_lowid; + uint32_t mrb_highid; + uint32_t mrb_entryoff; +}; + +typedef struct message_resource_block message_resource_block; + +struct message_resource_entry { + uint16_t mre_len; + uint16_t mre_flags; + char mre_text[]; +}; + +typedef struct message_resource_entry message_resource_entry; + +#define MESSAGE_RESOURCE_UNICODE 0x0001 + +struct image_patch_table { + char *ipt_name; + void (*ipt_func)(void); + void (*ipt_wrap)(void); + int ipt_argcnt; + int ipt_ftype; +}; + +typedef struct image_patch_table image_patch_table; + +/* + * AMD64 support. Microsoft uses a different calling convention + * than everyone else on the amd64 platform. Sadly, gcc has no + * built-in support for it (yet). + * + * The three major differences we're concerned with are: + * + * - The first 4 register-sized arguments are passed in the + * %rcx, %rdx, %r8 and %r9 registers, and the rest are pushed + * onto the stack. (The ELF ABI uses 6 registers, not 4). + * + * - The caller must reserve space on the stack for the 4 + * register arguments in case the callee has to spill them. + * + * - The stack myst be 16-byte aligned by the time the callee + * executes. A call instruction implicitly pushes an 8 byte + * return address onto the stack. We have to make sure that + * the amount of space we consume, plus the return address, + * is a multiple of 16 bytes in size. This means that in + * some cases, we may need to chew up an extra 8 bytes on + * the stack that will be unused. + * + * On the bright side, Microsoft seems to be using just the one + * calling convention for all functions on amd64, unlike x86 where + * they use a mix of _stdcall, _fastcall and _cdecl. + */ + +#ifdef __amd64__ + +extern uint64_t x86_64_call1(void *, uint64_t); +extern uint64_t x86_64_call2(void *, uint64_t, uint64_t); +extern uint64_t x86_64_call3(void *, uint64_t, uint64_t, uint64_t); +extern uint64_t x86_64_call4(void *, uint64_t, uint64_t, uint64_t, uint64_t); +extern uint64_t x86_64_call5(void *, uint64_t, uint64_t, uint64_t, uint64_t, + uint64_t); +extern uint64_t x86_64_call6(void *, uint64_t, uint64_t, uint64_t, uint64_t, + uint64_t, uint64_t); + + +#define MSCALL1(fn, a) \ + x86_64_call1((fn), (uint64_t)(a)) +#define MSCALL2(fn, a, b) \ + x86_64_call2((fn), (uint64_t)(a), (uint64_t)(b)) +#define MSCALL3(fn, a, b, c) \ + x86_64_call3((fn), (uint64_t)(a), (uint64_t)(b), \ + (uint64_t)(c)) +#define MSCALL4(fn, a, b, c, d) \ + x86_64_call4((fn), (uint64_t)(a), (uint64_t)(b), \ + (uint64_t)(c), (uint64_t)(d)) +#define MSCALL5(fn, a, b, c, d, e) \ + x86_64_call5((fn), (uint64_t)(a), (uint64_t)(b), \ + (uint64_t)(c), (uint64_t)(d), (uint64_t)(e)) +#define MSCALL6(fn, a, b, c, d, e, f) \ + x86_64_call6((fn), (uint64_t)(a), (uint64_t)(b), \ + (uint64_t)(c), (uint64_t)(d), (uint64_t)(e), (uint64_t)(f)) + +#endif /* __amd64__ */ + +#ifdef __i386__ + +extern uint32_t x86_stdcall_call(void *, int, ...); + +#define MSCALL1(fn, a) x86_stdcall_call(fn, 1, (a)) +#define MSCALL2(fn, a, b) x86_stdcall_call(fn, 2, (a), (b)) +#define MSCALL3(fn, a, b, c) x86_stdcall_call(fn, 3, (a), (b), (c)) +#define MSCALL4(fn, a, b, c, d) x86_stdcall_call(fn, 4, (a), (b), (c), (d)) +#define MSCALL5(fn, a, b, c, d, e) \ + x86_stdcall_call(fn, 5, (a), (b), (c), (d), (e)) +#define MSCALL6(fn, a, b, c, d, e, f) \ + x86_stdcall_call(fn, 6, (a), (b), (c), (d), (e), (f)) + +#endif /* __i386__ */ + + +#define FUNC void(*)(void) + +#ifdef __i386__ +#define IMPORT_SFUNC(x, y) { #x, (FUNC)x, NULL, y, WINDRV_WRAP_STDCALL } +#define IMPORT_SFUNC_MAP(x, y, z) \ + { #x, (FUNC)y, NULL, z, WINDRV_WRAP_STDCALL } +#define IMPORT_FFUNC(x, y) { #x, (FUNC)x, NULL, y, WINDRV_WRAP_FASTCALL } +#define IMPORT_FFUNC_MAP(x, y, z) \ + { #x, (FUNC)y, NULL, z, WINDRV_WRAP_FASTCALL } +#define IMPORT_RFUNC(x, y) { #x, (FUNC)x, NULL, y, WINDRV_WRAP_REGPARM } +#define IMPORT_RFUNC_MAP(x, y, z) \ + { #x, (FUNC)y, NULL, z, WINDRV_WRAP_REGPARM } +#define IMPORT_CFUNC(x, y) { #x, (FUNC)x, NULL, y, WINDRV_WRAP_CDECL } +#define IMPORT_CFUNC_MAP(x, y, z) \ + { #x, (FUNC)y, NULL, z, WINDRV_WRAP_CDECL } +#endif /* __i386__ */ + +#ifdef __amd64__ +#define IMPORT_SFUNC(x, y) { #x, (FUNC)x, NULL, y, WINDRV_WRAP_AMD64 } +#define IMPORT_SFUNC_MAP(x, y, z) \ + { #x, (FUNC)y, NULL, z, WINDRV_WRAP_AMD64 } +#define IMPORT_FFUNC(x, y) { #x, (FUNC)x, NULL, y, WINDRV_WRAP_AMD64 } +#define IMPORT_FFUNC_MAP(x, y, z) \ + { #x, (FUNC)y, NULL, z, WINDRV_WRAP_AMD64 } +#define IMPORT_RFUNC(x, y) { #x, (FUNC)x, NULL, y, WINDRV_WRAP_AMD64 } +#define IMPORT_RFUNC_MAP(x, y, z) \ + { #x, (FUNC)y, NULL, z, WINDRV_WRAP_AMD64 } +#define IMPORT_CFUNC(x, y) { #x, (FUNC)x, NULL, y, WINDRV_WRAP_AMD64 } +#define IMPORT_CFUNC_MAP(x, y, z) \ + { #x, (FUNC)y, NULL, z, WINDRV_WRAP_AMD64 } +#endif /* __amd64__ */ + +__BEGIN_DECLS +extern int pe_get_dos_header(vm_offset_t, image_dos_header *); +extern int pe_is_nt_image(vm_offset_t); +extern int pe_get_optional_header(vm_offset_t, image_optional_header *); +extern int pe_get_file_header(vm_offset_t, image_file_header *); +extern int pe_get_section_header(vm_offset_t, image_section_header *); +extern int pe_numsections(vm_offset_t); +extern vm_offset_t pe_imagebase(vm_offset_t); +extern vm_offset_t pe_directory_offset(vm_offset_t, uint32_t); +extern vm_offset_t pe_translate_addr (vm_offset_t, vm_offset_t); +extern int pe_get_section(vm_offset_t, image_section_header *, const char *); +extern int pe_relocate(vm_offset_t); +extern int pe_get_import_descriptor(vm_offset_t, image_import_descriptor *, char *); +extern int pe_patch_imports(vm_offset_t, char *, image_patch_table *); +extern int pe_get_messagetable(vm_offset_t, message_resource_data **); +extern int pe_get_message(vm_offset_t, uint32_t, char **, int *, uint16_t *); +__END_DECLS + +#endif /* _PE_VAR_H_ */ diff --git a/sys/compat/ndis/resource_var.h b/sys/compat/ndis/resource_var.h new file mode 100644 index 0000000..5ce096c --- /dev/null +++ b/sys/compat/ndis/resource_var.h @@ -0,0 +1,199 @@ +/*- + * Copyright (c) 2005 + * Bill Paul <wpaul@windriver.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, 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 Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD + * 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 _RESOURCE_VAR_H_ +#define _RESOURCE_VAR_H_ + +typedef int cm_resource_type; + +struct physaddr { + uint64_t np_quad; +#ifdef notdef + uint32_t np_low; + uint32_t np_high; +#endif +}; + +typedef struct physaddr physaddr; + +enum interface_type { + InterfaceTypeUndefined = -1, + Internal, + Isa, + Eisa, + MicroChannel, + TurboChannel, + PCIBus, + VMEBus, + NuBus, + PCMCIABus, + CBus, + MPIBus, + MPSABus, + ProcessorInternal, + InternalPowerBus, + PNPISABus, + PNPBus, + MaximumInterfaceType +}; + +typedef enum interface_type interface_type; + +#define CmResourceTypeNull 0 /* ResType_All or ResType_None (0x0000) */ +#define CmResourceTypePort 1 /* ResType_IO (0x0002) */ +#define CmResourceTypeInterrupt 2 /* ResType_IRQ (0x0004) */ +#define CmResourceTypeMemory 3 /* ResType_Mem (0x0001) */ +#define CmResourceTypeDma 4 /* ResType_DMA (0x0003) */ +#define CmResourceTypeDeviceSpecific 5 /* ResType_ClassSpecific (0xFFFF) */ +#define CmResourceTypeBusNumber 6 /* ResType_BusNumber (0x0006) */ +#define CmResourceTypeMaximum 7 +#define CmResourceTypeNonArbitrated 128 /* Not arbitrated if 0x80 bit set */ +#define CmResourceTypeConfigData 128 /* ResType_Reserved (0x8000) */ +#define CmResourceTypeDevicePrivate 129 /* ResType_DevicePrivate (0x8001) */ +#define CmResourceTypePcCardConfig 130 /* ResType_PcCardConfig (0x8002) */ + +enum cm_share_disposition { + CmResourceShareUndetermined = 0, /* Reserved */ + CmResourceShareDeviceExclusive, + CmResourceShareDriverExclusive, + CmResourceShareShared +}; + +typedef enum cm_share_disposition cm_share_disposition; + +/* Define the bit masks for Flags when type is CmResourceTypeInterrupt */ + +#define CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE 0 +#define CM_RESOURCE_INTERRUPT_LATCHED 1 + +/* Define the bit masks for Flags when type is CmResourceTypeMemory */ + +#define CM_RESOURCE_MEMORY_READ_WRITE 0x0000 +#define CM_RESOURCE_MEMORY_READ_ONLY 0x0001 +#define CM_RESOURCE_MEMORY_WRITE_ONLY 0x0002 +#define CM_RESOURCE_MEMORY_PREFETCHABLE 0x0004 + +#define CM_RESOURCE_MEMORY_COMBINEDWRITE 0x0008 +#define CM_RESOURCE_MEMORY_24 0x0010 +#define CM_RESOURCE_MEMORY_CACHEABLE 0x0020 + +/* Define the bit masks for Flags when type is CmResourceTypePort */ + +#define CM_RESOURCE_PORT_MEMORY 0x0000 +#define CM_RESOURCE_PORT_IO 0x0001 +#define CM_RESOURCE_PORT_10_BIT_DECODE 0x0004 +#define CM_RESOURCE_PORT_12_BIT_DECODE 0x0008 +#define CM_RESOURCE_PORT_16_BIT_DECODE 0x0010 +#define CM_RESOURCE_PORT_POSITIVE_DECODE 0x0020 +#define CM_RESOURCE_PORT_PASSIVE_DECODE 0x0040 +#define CM_RESOURCE_PORT_WINDOW_DECODE 0x0080 + +/* Define the bit masks for Flags when type is CmResourceTypeDma */ + +#define CM_RESOURCE_DMA_8 0x0000 +#define CM_RESOURCE_DMA_16 0x0001 +#define CM_RESOURCE_DMA_32 0x0002 +#define CM_RESOURCE_DMA_8_AND_16 0x0004 +#define CM_RESOURCE_DMA_BUS_MASTER 0x0008 +#define CM_RESOURCE_DMA_TYPE_A 0x0010 +#define CM_RESOURCE_DMA_TYPE_B 0x0020 +#define CM_RESOURCE_DMA_TYPE_F 0x0040 + +struct cm_partial_resource_desc { + uint8_t cprd_type; + uint8_t cprd_sharedisp; + uint16_t cprd_flags; + union { + struct { + physaddr cprd_start; + uint32_t cprd_len; + } cprd_generic; + struct { + physaddr cprd_start; + uint32_t cprd_len; + } cprd_port; + struct { + uint32_t cprd_level; + uint32_t cprd_vector; + uint32_t cprd_affinity; + } cprd_intr; + struct { + physaddr cprd_start; + uint32_t cprd_len; + } cprd_mem; + struct { + uint32_t cprd_chan; + uint32_t cprd_port; + uint32_t cprd_rsvd; + } cprd_dmachan; + struct { + uint32_t cprd_data[3]; + } cprd_devpriv; + struct { + uint32_t cprd_datasize; + uint32_t cprd_rsvd1; + uint32_t cprd_rsvd2; + } cprd_devspec; + } u __attribute__((packed)); +}; + +typedef struct cm_partial_resource_desc cm_partial_resource_desc; + +struct cm_partial_resource_list { + uint16_t cprl_version; + uint16_t cprl_revision; + uint32_t cprl_count; + cm_partial_resource_desc cprl_partial_descs[1]; +}; + +typedef struct cm_partial_resource_list cm_partial_resource_list; + +struct cm_full_resource_list { + interface_type cfrl_type; + uint32_t cfrl_busnum; + cm_partial_resource_desc cfrl_partiallist; +}; + +typedef struct cm_full_resource_list cm_full_resource_list; + +struct cm_resource_list { + uint32_t crl_count; + cm_full_resource_list crl_rlist; +}; + +typedef struct cm_resource_list cm_resource_list; + +typedef cm_partial_resource_list ndis_resource_list; + +#endif /* _RESOURCE_VAR_H_ */ diff --git a/sys/compat/ndis/subr_hal.c b/sys/compat/ndis/subr_hal.c new file mode 100644 index 0000000..62d97ad --- /dev/null +++ b/sys/compat/ndis/subr_hal.c @@ -0,0 +1,481 @@ +/*- + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.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, 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 Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD + * 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/types.h> +#include <sys/errno.h> + +#include <sys/callout.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/proc.h> +#include <sys/sched.h> +#include <sys/module.h> + +#include <sys/systm.h> +#include <machine/bus.h> + +#include <sys/bus.h> +#include <sys/rman.h> + +#include <compat/ndis/pe_var.h> +#include <compat/ndis/resource_var.h> +#include <compat/ndis/cfg_var.h> +#include <compat/ndis/ntoskrnl_var.h> +#include <compat/ndis/hal_var.h> + +static void KeStallExecutionProcessor(uint32_t); +static void WRITE_PORT_BUFFER_ULONG(uint32_t *, + uint32_t *, uint32_t); +static void WRITE_PORT_BUFFER_USHORT(uint16_t *, + uint16_t *, uint32_t); +static void WRITE_PORT_BUFFER_UCHAR(uint8_t *, + uint8_t *, uint32_t); +static void WRITE_PORT_ULONG(uint32_t *, uint32_t); +static void WRITE_PORT_USHORT(uint16_t *, uint16_t); +static void WRITE_PORT_UCHAR(uint8_t *, uint8_t); +static uint32_t READ_PORT_ULONG(uint32_t *); +static uint16_t READ_PORT_USHORT(uint16_t *); +static uint8_t READ_PORT_UCHAR(uint8_t *); +static void READ_PORT_BUFFER_ULONG(uint32_t *, + uint32_t *, uint32_t); +static void READ_PORT_BUFFER_USHORT(uint16_t *, + uint16_t *, uint32_t); +static void READ_PORT_BUFFER_UCHAR(uint8_t *, + uint8_t *, uint32_t); +static uint64_t KeQueryPerformanceCounter(uint64_t *); +static void _KeLowerIrql(uint8_t); +static uint8_t KeRaiseIrqlToDpcLevel(void); +static void dummy (void); + +#define NDIS_MAXCPUS 64 +static struct mtx disp_lock[NDIS_MAXCPUS]; + +int +hal_libinit() +{ + image_patch_table *patch; + int i; + + for (i = 0; i < NDIS_MAXCPUS; i++) + mtx_init(&disp_lock[i], "HAL preemption lock", + "HAL lock", MTX_RECURSE|MTX_DEF); + + patch = hal_functbl; + while (patch->ipt_func != NULL) { + windrv_wrap((funcptr)patch->ipt_func, + (funcptr *)&patch->ipt_wrap, + patch->ipt_argcnt, patch->ipt_ftype); + patch++; + } + + return (0); +} + +int +hal_libfini() +{ + image_patch_table *patch; + int i; + + for (i = 0; i < NDIS_MAXCPUS; i++) + mtx_destroy(&disp_lock[i]); + + patch = hal_functbl; + while (patch->ipt_func != NULL) { + windrv_unwrap(patch->ipt_wrap); + patch++; + } + + return (0); +} + +static void +KeStallExecutionProcessor(usecs) + uint32_t usecs; +{ + DELAY(usecs); +} + +static void +WRITE_PORT_ULONG(port, val) + uint32_t *port; + uint32_t val; +{ + bus_space_write_4(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port, val); +} + +static void +WRITE_PORT_USHORT(uint16_t *port, uint16_t val) +{ + bus_space_write_2(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port, val); +} + +static void +WRITE_PORT_UCHAR(uint8_t *port, uint8_t val) +{ + bus_space_write_1(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port, val); +} + +static void +WRITE_PORT_BUFFER_ULONG(port, val, cnt) + uint32_t *port; + uint32_t *val; + uint32_t cnt; +{ + bus_space_write_multi_4(NDIS_BUS_SPACE_IO, 0x0, + (bus_size_t)port, val, cnt); +} + +static void +WRITE_PORT_BUFFER_USHORT(port, val, cnt) + uint16_t *port; + uint16_t *val; + uint32_t cnt; +{ + bus_space_write_multi_2(NDIS_BUS_SPACE_IO, 0x0, + (bus_size_t)port, val, cnt); +} + +static void +WRITE_PORT_BUFFER_UCHAR(port, val, cnt) + uint8_t *port; + uint8_t *val; + uint32_t cnt; +{ + bus_space_write_multi_1(NDIS_BUS_SPACE_IO, 0x0, + (bus_size_t)port, val, cnt); +} + +static uint16_t +READ_PORT_USHORT(port) + uint16_t *port; +{ + return (bus_space_read_2(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port)); +} + +static uint32_t +READ_PORT_ULONG(port) + uint32_t *port; +{ + return (bus_space_read_4(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port)); +} + +static uint8_t +READ_PORT_UCHAR(port) + uint8_t *port; +{ + return (bus_space_read_1(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port)); +} + +static void +READ_PORT_BUFFER_ULONG(port, val, cnt) + uint32_t *port; + uint32_t *val; + uint32_t cnt; +{ + bus_space_read_multi_4(NDIS_BUS_SPACE_IO, 0x0, + (bus_size_t)port, val, cnt); +} + +static void +READ_PORT_BUFFER_USHORT(port, val, cnt) + uint16_t *port; + uint16_t *val; + uint32_t cnt; +{ + bus_space_read_multi_2(NDIS_BUS_SPACE_IO, 0x0, + (bus_size_t)port, val, cnt); +} + +static void +READ_PORT_BUFFER_UCHAR(port, val, cnt) + uint8_t *port; + uint8_t *val; + uint32_t cnt; +{ + bus_space_read_multi_1(NDIS_BUS_SPACE_IO, 0x0, + (bus_size_t)port, val, cnt); +} + +/* + * The spinlock implementation in Windows differs from that of FreeBSD. + * The basic operation of spinlocks involves two steps: 1) spin in a + * tight loop while trying to acquire a lock, 2) after obtaining the + * lock, disable preemption. (Note that on uniprocessor systems, you're + * allowed to skip the first step and just lock out pre-emption, since + * it's not possible for you to be in contention with another running + * thread.) Later, you release the lock then re-enable preemption. + * The difference between Windows and FreeBSD lies in how preemption + * is disabled. In FreeBSD, it's done using critical_enter(), which on + * the x86 arch translates to a cli instruction. This masks off all + * interrupts, and effectively stops the scheduler from ever running + * so _nothing_ can execute except the current thread. In Windows, + * preemption is disabled by raising the processor IRQL to DISPATCH_LEVEL. + * This stops other threads from running, but does _not_ block device + * interrupts. This means ISRs can still run, and they can make other + * threads runable, but those other threads won't be able to execute + * until the current thread lowers the IRQL to something less than + * DISPATCH_LEVEL. + * + * There's another commonly used IRQL in Windows, which is APC_LEVEL. + * An APC is an Asynchronous Procedure Call, which differs from a DPC + * (Defered Procedure Call) in that a DPC is queued up to run in + * another thread, while an APC runs in the thread that scheduled + * it (similar to a signal handler in a UNIX process). We don't + * actually support the notion of APCs in FreeBSD, so for now, the + * only IRQLs we're interested in are DISPATCH_LEVEL and PASSIVE_LEVEL. + * + * To simulate DISPATCH_LEVEL, we raise the current thread's priority + * to PI_REALTIME, which is the highest we can give it. This should, + * if I understand things correctly, prevent anything except for an + * interrupt thread from preempting us. PASSIVE_LEVEL is basically + * everything else. + * + * Be aware that, at least on the x86 arch, the Windows spinlock + * functions are divided up in peculiar ways. The actual spinlock + * functions are KfAcquireSpinLock() and KfReleaseSpinLock(), and + * they live in HAL.dll. Meanwhile, KeInitializeSpinLock(), + * KefAcquireSpinLockAtDpcLevel() and KefReleaseSpinLockFromDpcLevel() + * live in ntoskrnl.exe. Most Windows source code will call + * KeAcquireSpinLock() and KeReleaseSpinLock(), but these are just + * macros that call KfAcquireSpinLock() and KfReleaseSpinLock(). + * KefAcquireSpinLockAtDpcLevel() and KefReleaseSpinLockFromDpcLevel() + * perform the lock aquisition/release functions without doing the + * IRQL manipulation, and are used when one is already running at + * DISPATCH_LEVEL. Make sense? Good. + * + * According to the Microsoft documentation, any thread that calls + * KeAcquireSpinLock() must be running at IRQL <= DISPATCH_LEVEL. If + * we detect someone trying to acquire a spinlock from DEVICE_LEVEL + * or HIGH_LEVEL, we panic. + * + * Alternate sleep-lock-based spinlock implementation + * -------------------------------------------------- + * + * The earlier spinlock implementation was arguably a bit of a hack + * and presented several problems. It was basically designed to provide + * the functionality of spinlocks without incurring the wrath of + * WITNESS. We could get away with using both our spinlock implementation + * and FreeBSD sleep locks at the same time, but if WITNESS knew what + * we were really up to, it would have spanked us rather severely. + * + * There's another method we can use based entirely on sleep locks. + * First, it's important to realize that everything we're locking + * resides inside Project Evil itself: any critical data being locked + * by drivers belongs to the drivers, and should not be referenced + * by any other OS code outside of the NDISulator. The priority-based + * locking scheme has system-wide effects, just like real spinlocks + * (blocking preemption affects the whole CPU), but since we keep all + * our critical data private, we can use a simpler mechanism that + * affects only code/threads directly related to Project Evil. + * + * The idea is to create a sleep lock mutex for each CPU in the system. + * When a CPU running in the NDISulator wants to acquire a spinlock, it + * does the following: + * - Pin ourselves to the current CPU + * - Acquire the mutex for the current CPU + * - Spin on the spinlock variable using atomic test and set, just like + * a real spinlock. + * - Once we have the lock, we execute our critical code + * + * To give up the lock, we do: + * - Clear the spinlock variable with an atomic op + * - Release the per-CPU mutex + * - Unpin ourselves from the current CPU. + * + * On a uniprocessor system, this means all threads that access protected + * data are serialized through the per-CPU mutex. After one thread + * acquires the 'spinlock,' any other thread that uses a spinlock on the + * current CPU will block on the per-CPU mutex, which has the same general + * effect of blocking pre-emption, but _only_ for those threads that are + * running NDISulator code. + * + * On a multiprocessor system, threads on different CPUs all block on + * their respective per-CPU mutex, and the atomic test/set operation + * on the spinlock variable provides inter-CPU synchronization, though + * only for threads running NDISulator code. + * + * This method solves an important problem. In Windows, you're allowed + * to do an ExAllocatePoolWithTag() with a spinlock held, provided you + * allocate from NonPagedPool. This implies an atomic heap allocation + * that will not cause the current thread to sleep. (You can't sleep + * while holding real spinlock: clowns will eat you.) But in FreeBSD, + * malloc(9) _always_ triggers the acquisition of a sleep lock, even + * when you use M_NOWAIT. This is not a problem for FreeBSD native + * code: you're allowed to sleep in things like interrupt threads. But + * it is a problem with the old priority-based spinlock implementation: + * even though we get away with it most of the time, we really can't + * do a malloc(9) after doing a KeAcquireSpinLock() or KeRaiseIrql(). + * With the new implementation, it's not a problem: you're allowed to + * acquire more than one sleep lock (as long as you avoid lock order + * reversals). + * + * The one drawback to this approach is that now we have a lot of + * contention on one per-CPU mutex within the NDISulator code. Whether + * or not this is preferable to the expected Windows spinlock behavior + * of blocking pre-emption is debatable. + */ + +uint8_t +KfAcquireSpinLock(lock) + kspin_lock *lock; +{ + uint8_t oldirql; + + KeRaiseIrql(DISPATCH_LEVEL, &oldirql); + KeAcquireSpinLockAtDpcLevel(lock); + + return (oldirql); +} + +void +KfReleaseSpinLock(kspin_lock *lock, uint8_t newirql) +{ + KeReleaseSpinLockFromDpcLevel(lock); + KeLowerIrql(newirql); +} + +uint8_t +KeGetCurrentIrql() +{ + if (mtx_owned(&disp_lock[curthread->td_oncpu])) + return (DISPATCH_LEVEL); + return (PASSIVE_LEVEL); +} + +static uint64_t +KeQueryPerformanceCounter(freq) + uint64_t *freq; +{ + if (freq != NULL) + *freq = hz; + + return ((uint64_t)ticks); +} + +uint8_t +KfRaiseIrql(uint8_t irql) +{ + uint8_t oldirql; + + sched_pin(); + oldirql = KeGetCurrentIrql(); + + /* I am so going to hell for this. */ + if (oldirql > irql) + panic("IRQL_NOT_LESS_THAN_OR_EQUAL"); + + if (oldirql != DISPATCH_LEVEL) + mtx_lock(&disp_lock[curthread->td_oncpu]); + else + sched_unpin(); + +/*printf("RAISE IRQL: %d %d\n", irql, oldirql);*/ + + return (oldirql); +} + +void +KfLowerIrql(uint8_t oldirql) +{ + if (oldirql == DISPATCH_LEVEL) + return; + + if (KeGetCurrentIrql() != DISPATCH_LEVEL) + panic("IRQL_NOT_GREATER_THAN"); + + mtx_unlock(&disp_lock[curthread->td_oncpu]); + sched_unpin(); +} + +static uint8_t +KeRaiseIrqlToDpcLevel(void) +{ + uint8_t irql; + + KeRaiseIrql(DISPATCH_LEVEL, &irql); + return (irql); +} + +static void +_KeLowerIrql(uint8_t oldirql) +{ + KeLowerIrql(oldirql); +} + +static void dummy() +{ + printf("hal dummy called...\n"); +} + +image_patch_table hal_functbl[] = { + IMPORT_SFUNC(KeStallExecutionProcessor, 1), + IMPORT_SFUNC(WRITE_PORT_ULONG, 2), + IMPORT_SFUNC(WRITE_PORT_USHORT, 2), + IMPORT_SFUNC(WRITE_PORT_UCHAR, 2), + IMPORT_SFUNC(WRITE_PORT_BUFFER_ULONG, 3), + IMPORT_SFUNC(WRITE_PORT_BUFFER_USHORT, 3), + IMPORT_SFUNC(WRITE_PORT_BUFFER_UCHAR, 3), + IMPORT_SFUNC(READ_PORT_ULONG, 1), + IMPORT_SFUNC(READ_PORT_USHORT, 1), + IMPORT_SFUNC(READ_PORT_UCHAR, 1), + IMPORT_SFUNC(READ_PORT_BUFFER_ULONG, 3), + IMPORT_SFUNC(READ_PORT_BUFFER_USHORT, 3), + IMPORT_SFUNC(READ_PORT_BUFFER_UCHAR, 3), + IMPORT_FFUNC(KfAcquireSpinLock, 1), + IMPORT_FFUNC(KfReleaseSpinLock, 1), + IMPORT_SFUNC(KeGetCurrentIrql, 0), + IMPORT_SFUNC(KeQueryPerformanceCounter, 1), + IMPORT_FFUNC(KfLowerIrql, 1), + IMPORT_FFUNC(KfRaiseIrql, 1), + IMPORT_SFUNC(KeRaiseIrqlToDpcLevel, 0), +#undef KeLowerIrql + IMPORT_SFUNC_MAP(KeLowerIrql, _KeLowerIrql, 1), + + /* + * This last entry is a catch-all for any function we haven't + * implemented yet. The PE import list patching routine will + * use it for any function that doesn't have an explicit match + * in this table. + */ + + { NULL, (FUNC)dummy, NULL, 0, WINDRV_WRAP_STDCALL }, + + /* End of list. */ + + { NULL, NULL, NULL } +}; diff --git a/sys/compat/ndis/subr_ndis.c b/sys/compat/ndis/subr_ndis.c new file mode 100644 index 0000000..bc13b2f --- /dev/null +++ b/sys/compat/ndis/subr_ndis.c @@ -0,0 +1,3371 @@ +/*- + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.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, 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 Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD + * 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$"); + +/* + * This file implements a translation layer between the BSD networking + * infrasturcture and Windows(R) NDIS network driver modules. A Windows + * NDIS driver calls into several functions in the NDIS.SYS Windows + * kernel module and exports a table of functions designed to be called + * by the NDIS subsystem. Using the PE loader, we can patch our own + * versions of the NDIS routines into a given Windows driver module and + * convince the driver that it is in fact running on Windows. + * + * We provide a table of all our implemented NDIS routines which is patched + * into the driver object code. All our exported routines must use the + * _stdcall calling convention, since that's what the Windows object code + * expects. + */ + + +#include <sys/ctype.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/errno.h> + +#include <sys/callout.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/socket.h> +#include <sys/sysctl.h> +#include <sys/timespec.h> +#include <sys/smp.h> +#include <sys/queue.h> +#include <sys/proc.h> +#include <sys/filedesc.h> +#include <sys/namei.h> +#include <sys/fcntl.h> +#include <sys/vnode.h> +#include <sys/kthread.h> +#include <sys/linker.h> +#include <sys/mount.h> +#include <sys/sysproto.h> + +#include <net/if.h> +#include <net/if_arp.h> +#include <net/ethernet.h> +#include <net/if_dl.h> +#include <net/if_media.h> + +#include <machine/atomic.h> +#include <machine/bus.h> +#include <machine/resource.h> + +#include <sys/bus.h> +#include <sys/rman.h> + +#include <machine/stdarg.h> + +#include <net80211/ieee80211_var.h> +#include <net80211/ieee80211_ioctl.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> + +#include <compat/ndis/pe_var.h> +#include <compat/ndis/cfg_var.h> +#include <compat/ndis/resource_var.h> +#include <compat/ndis/ntoskrnl_var.h> +#include <compat/ndis/hal_var.h> +#include <compat/ndis/ndis_var.h> +#include <dev/if_ndis/if_ndisvar.h> + +#include <vm/vm.h> +#include <vm/vm_param.h> +#include <vm/pmap.h> +#include <vm/uma.h> +#include <vm/vm_kern.h> +#include <vm/vm_map.h> + +static char ndis_filepath[MAXPATHLEN]; + +SYSCTL_STRING(_hw, OID_AUTO, ndis_filepath, CTLFLAG_RW, ndis_filepath, + MAXPATHLEN, "Path used by NdisOpenFile() to search for files"); + +static void NdisInitializeWrapper(ndis_handle *, + driver_object *, void *, void *); +static ndis_status NdisMRegisterMiniport(ndis_handle, + ndis_miniport_characteristics *, int); +static ndis_status NdisAllocateMemoryWithTag(void **, + uint32_t, uint32_t); +static ndis_status NdisAllocateMemory(void **, + uint32_t, uint32_t, ndis_physaddr); +static void NdisFreeMemory(void *, uint32_t, uint32_t); +static ndis_status NdisMSetAttributesEx(ndis_handle, ndis_handle, + uint32_t, uint32_t, ndis_interface_type); +static void NdisOpenConfiguration(ndis_status *, + ndis_handle *, ndis_handle); +static void NdisOpenConfigurationKeyByIndex(ndis_status *, + ndis_handle, uint32_t, unicode_string *, ndis_handle *); +static void NdisOpenConfigurationKeyByName(ndis_status *, + ndis_handle, unicode_string *, ndis_handle *); +static ndis_status ndis_encode_parm(ndis_miniport_block *, + struct sysctl_oid *, ndis_parm_type, ndis_config_parm **); +static ndis_status ndis_decode_parm(ndis_miniport_block *, + ndis_config_parm *, char *); +static void NdisReadConfiguration(ndis_status *, ndis_config_parm **, + ndis_handle, unicode_string *, ndis_parm_type); +static void NdisWriteConfiguration(ndis_status *, ndis_handle, + unicode_string *, ndis_config_parm *); +static void NdisCloseConfiguration(ndis_handle); +static void NdisAllocateSpinLock(ndis_spin_lock *); +static void NdisFreeSpinLock(ndis_spin_lock *); +static void NdisAcquireSpinLock(ndis_spin_lock *); +static void NdisReleaseSpinLock(ndis_spin_lock *); +static void NdisDprAcquireSpinLock(ndis_spin_lock *); +static void NdisDprReleaseSpinLock(ndis_spin_lock *); +static void NdisInitializeReadWriteLock(ndis_rw_lock *); +static void NdisAcquireReadWriteLock(ndis_rw_lock *, + uint8_t, ndis_lock_state *); +static void NdisReleaseReadWriteLock(ndis_rw_lock *, ndis_lock_state *); +static uint32_t NdisReadPciSlotInformation(ndis_handle, uint32_t, + uint32_t, void *, uint32_t); +static uint32_t NdisWritePciSlotInformation(ndis_handle, uint32_t, + uint32_t, void *, uint32_t); +static void NdisWriteErrorLogEntry(ndis_handle, ndis_error_code, uint32_t, ...); +static void ndis_map_cb(void *, bus_dma_segment_t *, int, int); +static void NdisMStartBufferPhysicalMapping(ndis_handle, + ndis_buffer *, uint32_t, uint8_t, ndis_paddr_unit *, uint32_t *); +static void NdisMCompleteBufferPhysicalMapping(ndis_handle, + ndis_buffer *, uint32_t); +static void NdisMInitializeTimer(ndis_miniport_timer *, ndis_handle, + ndis_timer_function, void *); +static void NdisInitializeTimer(ndis_timer *, + ndis_timer_function, void *); +static void NdisSetTimer(ndis_timer *, uint32_t); +static void NdisMSetPeriodicTimer(ndis_miniport_timer *, uint32_t); +static void NdisMCancelTimer(ndis_timer *, uint8_t *); +static void ndis_timercall(kdpc *, ndis_miniport_timer *, + void *, void *); +static void NdisMQueryAdapterResources(ndis_status *, ndis_handle, + ndis_resource_list *, uint32_t *); +static ndis_status NdisMRegisterIoPortRange(void **, + ndis_handle, uint32_t, uint32_t); +static void NdisMDeregisterIoPortRange(ndis_handle, + uint32_t, uint32_t, void *); +static void NdisReadNetworkAddress(ndis_status *, void **, + uint32_t *, ndis_handle); +static ndis_status NdisQueryMapRegisterCount(uint32_t, uint32_t *); +static ndis_status NdisMAllocateMapRegisters(ndis_handle, + uint32_t, uint8_t, uint32_t, uint32_t); +static void NdisMFreeMapRegisters(ndis_handle); +static void ndis_mapshared_cb(void *, bus_dma_segment_t *, int, int); +static void NdisMAllocateSharedMemory(ndis_handle, uint32_t, + uint8_t, void **, ndis_physaddr *); +static void ndis_asyncmem_complete(device_object *, void *); +static ndis_status NdisMAllocateSharedMemoryAsync(ndis_handle, + uint32_t, uint8_t, void *); +static void NdisMFreeSharedMemory(ndis_handle, uint32_t, + uint8_t, void *, ndis_physaddr); +static ndis_status NdisMMapIoSpace(void **, ndis_handle, + ndis_physaddr, uint32_t); +static void NdisMUnmapIoSpace(ndis_handle, void *, uint32_t); +static uint32_t NdisGetCacheFillSize(void); +static void *NdisGetRoutineAddress(unicode_string *); +static uint32_t NdisMGetDmaAlignment(ndis_handle); +static ndis_status NdisMInitializeScatterGatherDma(ndis_handle, + uint8_t, uint32_t); +static void NdisUnchainBufferAtFront(ndis_packet *, ndis_buffer **); +static void NdisUnchainBufferAtBack(ndis_packet *, ndis_buffer **); +static void NdisAllocateBufferPool(ndis_status *, + ndis_handle *, uint32_t); +static void NdisFreeBufferPool(ndis_handle); +static void NdisAllocateBuffer(ndis_status *, ndis_buffer **, + ndis_handle, void *, uint32_t); +static void NdisFreeBuffer(ndis_buffer *); +static uint32_t NdisBufferLength(ndis_buffer *); +static void NdisQueryBuffer(ndis_buffer *, void **, uint32_t *); +static void NdisQueryBufferSafe(ndis_buffer *, void **, + uint32_t *, uint32_t); +static void *NdisBufferVirtualAddress(ndis_buffer *); +static void *NdisBufferVirtualAddressSafe(ndis_buffer *, uint32_t); +static void NdisAdjustBufferLength(ndis_buffer *, int); +static uint32_t NdisInterlockedIncrement(uint32_t *); +static uint32_t NdisInterlockedDecrement(uint32_t *); +static void NdisInitializeEvent(ndis_event *); +static void NdisSetEvent(ndis_event *); +static void NdisResetEvent(ndis_event *); +static uint8_t NdisWaitEvent(ndis_event *, uint32_t); +static ndis_status NdisUnicodeStringToAnsiString(ansi_string *, + unicode_string *); +static ndis_status + NdisAnsiStringToUnicodeString(unicode_string *, ansi_string *); +static ndis_status NdisMPciAssignResources(ndis_handle, + uint32_t, ndis_resource_list **); +static ndis_status NdisMRegisterInterrupt(ndis_miniport_interrupt *, + ndis_handle, uint32_t, uint32_t, uint8_t, + uint8_t, ndis_interrupt_mode); +static void NdisMDeregisterInterrupt(ndis_miniport_interrupt *); +static void NdisMRegisterAdapterShutdownHandler(ndis_handle, void *, + ndis_shutdown_handler); +static void NdisMDeregisterAdapterShutdownHandler(ndis_handle); +static uint32_t NDIS_BUFFER_TO_SPAN_PAGES(ndis_buffer *); +static void NdisGetBufferPhysicalArraySize(ndis_buffer *, + uint32_t *); +static void NdisQueryBufferOffset(ndis_buffer *, + uint32_t *, uint32_t *); +static uint32_t NdisReadPcmciaAttributeMemory(ndis_handle, + uint32_t, void *, uint32_t); +static uint32_t NdisWritePcmciaAttributeMemory(ndis_handle, + uint32_t, void *, uint32_t); +static list_entry *NdisInterlockedInsertHeadList(list_entry *, + list_entry *, ndis_spin_lock *); +static list_entry *NdisInterlockedRemoveHeadList(list_entry *, + ndis_spin_lock *); +static list_entry *NdisInterlockedInsertTailList(list_entry *, + list_entry *, ndis_spin_lock *); +static uint8_t + NdisMSynchronizeWithInterrupt(ndis_miniport_interrupt *, + void *, void *); +static void NdisGetCurrentSystemTime(uint64_t *); +static void NdisGetSystemUpTime(uint32_t *); +static uint32_t NdisGetVersion(void); +static void NdisInitializeString(unicode_string *, char *); +static void NdisInitAnsiString(ansi_string *, char *); +static void NdisInitUnicodeString(unicode_string *, uint16_t *); +static void NdisFreeString(unicode_string *); +static ndis_status NdisMRemoveMiniport(ndis_handle *); +static void NdisTerminateWrapper(ndis_handle, void *); +static void NdisMGetDeviceProperty(ndis_handle, device_object **, + device_object **, device_object **, cm_resource_list *, + cm_resource_list *); +static void NdisGetFirstBufferFromPacket(ndis_packet *, + ndis_buffer **, void **, uint32_t *, uint32_t *); +static void NdisGetFirstBufferFromPacketSafe(ndis_packet *, + ndis_buffer **, void **, uint32_t *, uint32_t *, uint32_t); +static int ndis_find_sym(linker_file_t, char *, char *, caddr_t *); +static void NdisOpenFile(ndis_status *, ndis_handle *, uint32_t *, + unicode_string *, ndis_physaddr); +static void NdisMapFile(ndis_status *, void **, ndis_handle); +static void NdisUnmapFile(ndis_handle); +static void NdisCloseFile(ndis_handle); +static uint8_t NdisSystemProcessorCount(void); +static void NdisGetCurrentProcessorCounts(uint32_t *, uint32_t *, uint32_t *); +static void NdisMIndicateStatusComplete(ndis_handle); +static void NdisMIndicateStatus(ndis_handle, ndis_status, + void *, uint32_t); +static uint8_t ndis_intr(kinterrupt *, void *); +static void ndis_intrhand(kdpc *, ndis_miniport_interrupt *, void *, void *); +static funcptr ndis_findwrap(funcptr); +static void NdisCopyFromPacketToPacket(ndis_packet *, + uint32_t, uint32_t, ndis_packet *, uint32_t, uint32_t *); +static void NdisCopyFromPacketToPacketSafe(ndis_packet *, + uint32_t, uint32_t, ndis_packet *, uint32_t, uint32_t *, uint32_t); +static void NdisIMCopySendPerPacketInfo(ndis_packet *, ndis_packet *); +static ndis_status NdisMRegisterDevice(ndis_handle, + unicode_string *, unicode_string *, driver_dispatch **, + void **, ndis_handle *); +static ndis_status NdisMDeregisterDevice(ndis_handle); +static ndis_status + NdisMQueryAdapterInstanceName(unicode_string *, ndis_handle); +static void NdisMRegisterUnloadHandler(ndis_handle, void *); +static void dummy(void); + +/* + * Some really old drivers do not properly check the return value + * from NdisAllocatePacket() and NdisAllocateBuffer() and will + * sometimes allocate few more buffers/packets that they originally + * requested when they created the pool. To prevent this from being + * a problem, we allocate a few extra buffers/packets beyond what + * the driver asks for. This #define controls how many. + */ +#define NDIS_POOL_EXTRA 16 + +int +ndis_libinit() +{ + image_patch_table *patch; + + strcpy(ndis_filepath, "/compat/ndis"); + + patch = ndis_functbl; + while (patch->ipt_func != NULL) { + windrv_wrap((funcptr)patch->ipt_func, + (funcptr *)&patch->ipt_wrap, + patch->ipt_argcnt, patch->ipt_ftype); + patch++; + } + + return (0); +} + +int +ndis_libfini() +{ + image_patch_table *patch; + + patch = ndis_functbl; + while (patch->ipt_func != NULL) { + windrv_unwrap(patch->ipt_wrap); + patch++; + } + + return (0); +} + +static funcptr +ndis_findwrap(func) + funcptr func; +{ + image_patch_table *patch; + + patch = ndis_functbl; + while (patch->ipt_func != NULL) { + if ((funcptr)patch->ipt_func == func) + return ((funcptr)patch->ipt_wrap); + patch++; + } + + return (NULL); +} + +/* + * This routine does the messy Windows Driver Model device attachment + * stuff on behalf of NDIS drivers. We register our own AddDevice + * routine here + */ +static void +NdisInitializeWrapper(wrapper, drv, path, unused) + ndis_handle *wrapper; + driver_object *drv; + void *path; + void *unused; +{ + /* + * As of yet, I haven't come up with a compelling + * reason to define a private NDIS wrapper structure, + * so we use a pointer to the driver object as the + * wrapper handle. The driver object has the miniport + * characteristics struct for this driver hung off it + * via IoAllocateDriverObjectExtension(), and that's + * really all the private data we need. + */ + + *wrapper = drv; + + /* + * If this was really Windows, we'd be registering dispatch + * routines for the NDIS miniport module here, but we're + * not Windows so all we really need to do is set up an + * AddDevice function that'll be invoked when a new device + * instance appears. + */ + + drv->dro_driverext->dre_adddevicefunc = NdisAddDevice; +} + +static void +NdisTerminateWrapper(handle, syspec) + ndis_handle handle; + void *syspec; +{ + /* Nothing to see here, move along. */ +} + +static ndis_status +NdisMRegisterMiniport(handle, characteristics, len) + ndis_handle handle; + ndis_miniport_characteristics *characteristics; + int len; +{ + ndis_miniport_characteristics *ch = NULL; + driver_object *drv; + + drv = (driver_object *)handle; + + /* + * We need to save the NDIS miniport characteristics + * somewhere. This data is per-driver, not per-device + * (all devices handled by the same driver have the + * same characteristics) so we hook it onto the driver + * object using IoAllocateDriverObjectExtension(). + * The extra extension info is automagically deleted when + * the driver is unloaded (see windrv_unload()). + */ + + if (IoAllocateDriverObjectExtension(drv, (void *)1, + sizeof(ndis_miniport_characteristics), (void **)&ch) != + STATUS_SUCCESS) { + return (NDIS_STATUS_RESOURCES); + } + + bzero((char *)ch, sizeof(ndis_miniport_characteristics)); + + bcopy((char *)characteristics, (char *)ch, len); + + if (ch->nmc_version_major < 5 || ch->nmc_version_minor < 1) { + ch->nmc_shutdown_handler = NULL; + ch->nmc_canceltxpkts_handler = NULL; + ch->nmc_pnpevent_handler = NULL; + } + + return (NDIS_STATUS_SUCCESS); +} + +static ndis_status +NdisAllocateMemoryWithTag(vaddr, len, tag) + void **vaddr; + uint32_t len; + uint32_t tag; +{ + void *mem; + + mem = ExAllocatePoolWithTag(NonPagedPool, len, tag); + if (mem == NULL) { + return (NDIS_STATUS_RESOURCES); + } + *vaddr = mem; + + return (NDIS_STATUS_SUCCESS); +} + +static ndis_status +NdisAllocateMemory(vaddr, len, flags, highaddr) + void **vaddr; + uint32_t len; + uint32_t flags; + ndis_physaddr highaddr; +{ + void *mem; + + mem = ExAllocatePoolWithTag(NonPagedPool, len, 0); + if (mem == NULL) + return (NDIS_STATUS_RESOURCES); + *vaddr = mem; + + return (NDIS_STATUS_SUCCESS); +} + +static void +NdisFreeMemory(vaddr, len, flags) + void *vaddr; + uint32_t len; + uint32_t flags; +{ + if (len == 0) + return; + + ExFreePool(vaddr); +} + +static ndis_status +NdisMSetAttributesEx(adapter_handle, adapter_ctx, hangsecs, + flags, iftype) + ndis_handle adapter_handle; + ndis_handle adapter_ctx; + uint32_t hangsecs; + uint32_t flags; + ndis_interface_type iftype; +{ + ndis_miniport_block *block; + + /* + * Save the adapter context, we need it for calling + * the driver's internal functions. + */ + block = (ndis_miniport_block *)adapter_handle; + block->nmb_miniportadapterctx = adapter_ctx; + block->nmb_checkforhangsecs = hangsecs; + block->nmb_flags = flags; + + return (NDIS_STATUS_SUCCESS); +} + +static void +NdisOpenConfiguration(status, cfg, wrapctx) + ndis_status *status; + ndis_handle *cfg; + ndis_handle wrapctx; +{ + *cfg = wrapctx; + *status = NDIS_STATUS_SUCCESS; +} + +static void +NdisOpenConfigurationKeyByName(status, cfg, subkey, subhandle) + ndis_status *status; + ndis_handle cfg; + unicode_string *subkey; + ndis_handle *subhandle; +{ + *subhandle = cfg; + *status = NDIS_STATUS_SUCCESS; +} + +static void +NdisOpenConfigurationKeyByIndex(status, cfg, idx, subkey, subhandle) + ndis_status *status; + ndis_handle cfg; + uint32_t idx; + unicode_string *subkey; + ndis_handle *subhandle; +{ + *status = NDIS_STATUS_FAILURE; +} + +static ndis_status +ndis_encode_parm(block, oid, type, parm) + ndis_miniport_block *block; + struct sysctl_oid *oid; + ndis_parm_type type; + ndis_config_parm **parm; +{ + ndis_config_parm *p; + ndis_parmlist_entry *np; + unicode_string *us; + ansi_string as; + int base = 0; + uint32_t val; + char tmp[32]; + + np = ExAllocatePoolWithTag(NonPagedPool, + sizeof(ndis_parmlist_entry), 0); + if (np == NULL) + return (NDIS_STATUS_RESOURCES); + InsertHeadList((&block->nmb_parmlist), (&np->np_list)); + *parm = p = &np->np_parm; + + switch(type) { + case ndis_parm_string: + /* See if this might be a number. */ + val = strtoul((char *)oid->oid_arg1, NULL, 10); + us = &p->ncp_parmdata.ncp_stringdata; + p->ncp_type = ndis_parm_string; + if (val) { + snprintf(tmp, 32, "%x", val); + RtlInitAnsiString(&as, tmp); + } else { + RtlInitAnsiString(&as, (char *)oid->oid_arg1); + } + + if (RtlAnsiStringToUnicodeString(us, &as, TRUE)) { + ExFreePool(np); + return (NDIS_STATUS_RESOURCES); + } + break; + case ndis_parm_int: + if (strncmp((char *)oid->oid_arg1, "0x", 2) == 0) + base = 16; + else + base = 10; + p->ncp_type = ndis_parm_int; + p->ncp_parmdata.ncp_intdata = + strtol((char *)oid->oid_arg1, NULL, base); + break; + case ndis_parm_hexint: +#ifdef notdef + if (strncmp((char *)oid->oid_arg1, "0x", 2) == 0) + base = 16; + else + base = 10; +#endif + base = 16; + p->ncp_type = ndis_parm_hexint; + p->ncp_parmdata.ncp_intdata = + strtoul((char *)oid->oid_arg1, NULL, base); + break; + default: + return (NDIS_STATUS_FAILURE); + break; + } + + return (NDIS_STATUS_SUCCESS); +} + +static void +NdisReadConfiguration(status, parm, cfg, key, type) + ndis_status *status; + ndis_config_parm **parm; + ndis_handle cfg; + unicode_string *key; + ndis_parm_type type; +{ + char *keystr = NULL; + ndis_miniport_block *block; + struct ndis_softc *sc; + struct sysctl_oid *oidp; + struct sysctl_ctx_entry *e; + ansi_string as; + + block = (ndis_miniport_block *)cfg; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + if (key->us_len == 0 || key->us_buf == NULL) { + *status = NDIS_STATUS_FAILURE; + return; + } + + if (RtlUnicodeStringToAnsiString(&as, key, TRUE)) { + *status = NDIS_STATUS_RESOURCES; + return; + } + + keystr = as.as_buf; + + /* + * See if registry key is already in a list of known keys + * included with the driver. + */ + TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) { + oidp = e->entry; + if (strcasecmp(oidp->oid_name, keystr) == 0) { + if (strcmp((char *)oidp->oid_arg1, "UNSET") == 0) { + RtlFreeAnsiString(&as); + *status = NDIS_STATUS_FAILURE; + return; + } + + *status = ndis_encode_parm(block, oidp, type, parm); + RtlFreeAnsiString(&as); + return; + } + } + + /* + * If the key didn't match, add it to the list of dynamically + * created ones. Sometimes, drivers refer to registry keys + * that aren't documented in their .INF files. These keys + * are supposed to be created by some sort of utility or + * control panel snap-in that comes with the driver software. + * Sometimes it's useful to be able to manipulate these. + * If the driver requests the key in the form of a string, + * make its default value an empty string, otherwise default + * it to "0". + */ + + if (type == ndis_parm_int || type == ndis_parm_hexint) + ndis_add_sysctl(sc, keystr, "(dynamic integer key)", + "UNSET", CTLFLAG_RW); + else + ndis_add_sysctl(sc, keystr, "(dynamic string key)", + "UNSET", CTLFLAG_RW); + + RtlFreeAnsiString(&as); + *status = NDIS_STATUS_FAILURE; +} + +static ndis_status +ndis_decode_parm(block, parm, val) + ndis_miniport_block *block; + ndis_config_parm *parm; + char *val; +{ + unicode_string *ustr; + ansi_string as; + + switch(parm->ncp_type) { + case ndis_parm_string: + ustr = &parm->ncp_parmdata.ncp_stringdata; + if (RtlUnicodeStringToAnsiString(&as, ustr, TRUE)) + return (NDIS_STATUS_RESOURCES); + bcopy(as.as_buf, val, as.as_len); + RtlFreeAnsiString(&as); + break; + case ndis_parm_int: + sprintf(val, "%d", parm->ncp_parmdata.ncp_intdata); + break; + case ndis_parm_hexint: + sprintf(val, "%xu", parm->ncp_parmdata.ncp_intdata); + break; + default: + return (NDIS_STATUS_FAILURE); + break; + } + return (NDIS_STATUS_SUCCESS); +} + +static void +NdisWriteConfiguration(status, cfg, key, parm) + ndis_status *status; + ndis_handle cfg; + unicode_string *key; + ndis_config_parm *parm; +{ + ansi_string as; + char *keystr = NULL; + ndis_miniport_block *block; + struct ndis_softc *sc; + struct sysctl_oid *oidp; + struct sysctl_ctx_entry *e; + char val[256]; + + block = (ndis_miniport_block *)cfg; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + if (RtlUnicodeStringToAnsiString(&as, key, TRUE)) { + *status = NDIS_STATUS_RESOURCES; + return; + } + + keystr = as.as_buf; + + /* Decode the parameter into a string. */ + bzero(val, sizeof(val)); + *status = ndis_decode_parm(block, parm, val); + if (*status != NDIS_STATUS_SUCCESS) { + RtlFreeAnsiString(&as); + return; + } + + /* See if the key already exists. */ + + TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) { + oidp = e->entry; + if (strcasecmp(oidp->oid_name, keystr) == 0) { + /* Found it, set the value. */ + strcpy((char *)oidp->oid_arg1, val); + RtlFreeAnsiString(&as); + return; + } + } + + /* Not found, add a new key with the specified value. */ + ndis_add_sysctl(sc, keystr, "(dynamically set key)", + val, CTLFLAG_RW); + + RtlFreeAnsiString(&as); + *status = NDIS_STATUS_SUCCESS; +} + +static void +NdisCloseConfiguration(cfg) + ndis_handle cfg; +{ + list_entry *e; + ndis_parmlist_entry *pe; + ndis_miniport_block *block; + ndis_config_parm *p; + + block = (ndis_miniport_block *)cfg; + + while (!IsListEmpty(&block->nmb_parmlist)) { + e = RemoveHeadList(&block->nmb_parmlist); + pe = CONTAINING_RECORD(e, ndis_parmlist_entry, np_list); + p = &pe->np_parm; + if (p->ncp_type == ndis_parm_string) + RtlFreeUnicodeString(&p->ncp_parmdata.ncp_stringdata); + ExFreePool(e); + } +} + +/* + * Initialize a Windows spinlock. + */ +static void +NdisAllocateSpinLock(lock) + ndis_spin_lock *lock; +{ + KeInitializeSpinLock(&lock->nsl_spinlock); + lock->nsl_kirql = 0; +} + +/* + * Destroy a Windows spinlock. This is a no-op for now. There are two reasons + * for this. One is that it's sort of superfluous: we don't have to do anything + * special to deallocate the spinlock. The other is that there are some buggy + * drivers which call NdisFreeSpinLock() _after_ calling NdisFreeMemory() on + * the block of memory in which the spinlock resides. (Yes, ADMtek, I'm + * talking to you.) + */ +static void +NdisFreeSpinLock(lock) + ndis_spin_lock *lock; +{ +#ifdef notdef + KeInitializeSpinLock(&lock->nsl_spinlock); + lock->nsl_kirql = 0; +#endif +} + +/* + * Acquire a spinlock from IRQL <= DISPATCH_LEVEL. + */ + +static void +NdisAcquireSpinLock(lock) + ndis_spin_lock *lock; +{ + KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql); +} + +/* + * Release a spinlock from IRQL == DISPATCH_LEVEL. + */ + +static void +NdisReleaseSpinLock(lock) + ndis_spin_lock *lock; +{ + KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql); +} + +/* + * Acquire a spinlock when already running at IRQL == DISPATCH_LEVEL. + */ +static void +NdisDprAcquireSpinLock(lock) + ndis_spin_lock *lock; +{ + KeAcquireSpinLockAtDpcLevel(&lock->nsl_spinlock); +} + +/* + * Release a spinlock without leaving IRQL == DISPATCH_LEVEL. + */ +static void +NdisDprReleaseSpinLock(lock) + ndis_spin_lock *lock; +{ + KeReleaseSpinLockFromDpcLevel(&lock->nsl_spinlock); +} + +static void +NdisInitializeReadWriteLock(lock) + ndis_rw_lock *lock; +{ + KeInitializeSpinLock(&lock->nrl_spinlock); + bzero((char *)&lock->nrl_rsvd, sizeof(lock->nrl_rsvd)); +} + +static void +NdisAcquireReadWriteLock(ndis_rw_lock *lock, uint8_t writeacc, + ndis_lock_state *state) +{ + if (writeacc == TRUE) { + KeAcquireSpinLock(&lock->nrl_spinlock, &state->nls_oldirql); + lock->nrl_rsvd[0]++; + } else + lock->nrl_rsvd[1]++; +} + +static void +NdisReleaseReadWriteLock(lock, state) + ndis_rw_lock *lock; + ndis_lock_state *state; +{ + if (lock->nrl_rsvd[0]) { + lock->nrl_rsvd[0]--; + KeReleaseSpinLock(&lock->nrl_spinlock, state->nls_oldirql); + } else + lock->nrl_rsvd[1]--; +} + +static uint32_t +NdisReadPciSlotInformation(adapter, slot, offset, buf, len) + ndis_handle adapter; + uint32_t slot; + uint32_t offset; + void *buf; + uint32_t len; +{ + ndis_miniport_block *block; + int i; + char *dest; + device_t dev; + + block = (ndis_miniport_block *)adapter; + dest = buf; + if (block == NULL) + return (0); + + dev = block->nmb_physdeviceobj->do_devext; + + /* + * I have a test system consisting of a Sun w2100z + * dual 2.4Ghz Opteron machine and an Atheros 802.11a/b/g + * "Aries" miniPCI NIC. (The NIC is installed in the + * machine using a miniPCI to PCI bus adapter card.) + * When running in SMP mode, I found that + * performing a large number of consecutive calls to + * NdisReadPciSlotInformation() would result in a + * sudden system reset (or in some cases a freeze). + * My suspicion is that the multiple reads are somehow + * triggering a fatal PCI bus error that leads to a + * machine check. The 1us delay in the loop below + * seems to prevent this problem. + */ + + for (i = 0; i < len; i++) { + DELAY(1); + dest[i] = pci_read_config(dev, i + offset, 1); + } + + return (len); +} + +static uint32_t +NdisWritePciSlotInformation(adapter, slot, offset, buf, len) + ndis_handle adapter; + uint32_t slot; + uint32_t offset; + void *buf; + uint32_t len; +{ + ndis_miniport_block *block; + int i; + char *dest; + device_t dev; + + block = (ndis_miniport_block *)adapter; + dest = buf; + + if (block == NULL) + return (0); + + dev = block->nmb_physdeviceobj->do_devext; + for (i = 0; i < len; i++) { + DELAY(1); + pci_write_config(dev, i + offset, dest[i], 1); + } + + return (len); +} + +/* + * The errorlog routine uses a variable argument list, so we + * have to declare it this way. + */ + +#define ERRMSGLEN 512 +static void +NdisWriteErrorLogEntry(ndis_handle adapter, ndis_error_code code, + uint32_t numerrors, ...) +{ + ndis_miniport_block *block; + va_list ap; + int i, error; + char *str = NULL; + uint16_t flags; + device_t dev; + driver_object *drv; + struct ndis_softc *sc; + struct ifnet *ifp; + unicode_string us; + ansi_string as = { 0, 0, NULL }; + + block = (ndis_miniport_block *)adapter; + dev = block->nmb_physdeviceobj->do_devext; + drv = block->nmb_deviceobj->do_drvobj; + sc = device_get_softc(dev); + ifp = sc->ifp; + + if (ifp != NULL && ifp->if_flags & IFF_DEBUG) { + error = pe_get_message((vm_offset_t)drv->dro_driverstart, + code, &str, &i, &flags); + if (error == 0) { + if (flags & MESSAGE_RESOURCE_UNICODE) { + RtlInitUnicodeString(&us, (uint16_t *)str); + if (RtlUnicodeStringToAnsiString(&as, + &us, TRUE) == STATUS_SUCCESS) + str = as.as_buf; + else + str = NULL; + } + } + } + + device_printf(dev, "NDIS ERROR: %x (%s)\n", code, + str == NULL ? "unknown error" : str); + + if (ifp != NULL && ifp->if_flags & IFF_DEBUG) { + device_printf(dev, "NDIS NUMERRORS: %x\n", numerrors); + va_start(ap, numerrors); + for (i = 0; i < numerrors; i++) + device_printf(dev, "argptr: %p\n", + va_arg(ap, void *)); + va_end(ap); + } + + if (as.as_len) + RtlFreeAnsiString(&as); +} + +static void +ndis_map_cb(arg, segs, nseg, error) + void *arg; + bus_dma_segment_t *segs; + int nseg; + int error; +{ + struct ndis_map_arg *ctx; + int i; + + if (error) + return; + + ctx = arg; + + for (i = 0; i < nseg; i++) { + ctx->nma_fraglist[i].npu_physaddr.np_quad = segs[i].ds_addr; + ctx->nma_fraglist[i].npu_len = segs[i].ds_len; + } + + ctx->nma_cnt = nseg; +} + +static void +NdisMStartBufferPhysicalMapping(ndis_handle adapter, ndis_buffer *buf, + uint32_t mapreg, uint8_t writedev, ndis_paddr_unit *addrarray, + uint32_t *arraysize) +{ + ndis_miniport_block *block; + struct ndis_softc *sc; + struct ndis_map_arg nma; + bus_dmamap_t map; + int error; + + if (adapter == NULL) + return; + + block = (ndis_miniport_block *)adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + if (mapreg > sc->ndis_mmapcnt) + return; + + map = sc->ndis_mmaps[mapreg]; + nma.nma_fraglist = addrarray; + + error = bus_dmamap_load(sc->ndis_mtag, map, + MmGetMdlVirtualAddress(buf), MmGetMdlByteCount(buf), ndis_map_cb, + (void *)&nma, BUS_DMA_NOWAIT); + + if (error) + return; + + bus_dmamap_sync(sc->ndis_mtag, map, + writedev ? BUS_DMASYNC_PREWRITE : BUS_DMASYNC_PREREAD); + + *arraysize = nma.nma_cnt; +} + +static void +NdisMCompleteBufferPhysicalMapping(adapter, buf, mapreg) + ndis_handle adapter; + ndis_buffer *buf; + uint32_t mapreg; +{ + ndis_miniport_block *block; + struct ndis_softc *sc; + bus_dmamap_t map; + + if (adapter == NULL) + return; + + block = (ndis_miniport_block *)adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + if (mapreg > sc->ndis_mmapcnt) + return; + + map = sc->ndis_mmaps[mapreg]; + + bus_dmamap_sync(sc->ndis_mtag, map, + BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); + + bus_dmamap_unload(sc->ndis_mtag, map); +} + +/* + * This is an older (?) timer init routine which doesn't + * accept a miniport context handle. Serialized miniports should + * never call this function. + */ + +static void +NdisInitializeTimer(timer, func, ctx) + ndis_timer *timer; + ndis_timer_function func; + void *ctx; +{ + KeInitializeTimer(&timer->nt_ktimer); + KeInitializeDpc(&timer->nt_kdpc, func, ctx); + KeSetImportanceDpc(&timer->nt_kdpc, KDPC_IMPORTANCE_LOW); +} + +static void +ndis_timercall(dpc, timer, sysarg1, sysarg2) + kdpc *dpc; + ndis_miniport_timer *timer; + void *sysarg1; + void *sysarg2; +{ + /* + * Since we're called as a DPC, we should be running + * at DISPATCH_LEVEL here. This means to acquire the + * spinlock, we can use KeAcquireSpinLockAtDpcLevel() + * rather than KeAcquireSpinLock(). + */ + if (NDIS_SERIALIZED(timer->nmt_block)) + KeAcquireSpinLockAtDpcLevel(&timer->nmt_block->nmb_lock); + + MSCALL4(timer->nmt_timerfunc, dpc, timer->nmt_timerctx, + sysarg1, sysarg2); + + if (NDIS_SERIALIZED(timer->nmt_block)) + KeReleaseSpinLockFromDpcLevel(&timer->nmt_block->nmb_lock); +} + +/* + * For a long time I wondered why there were two NDIS timer initialization + * routines, and why this one needed an NDIS_MINIPORT_TIMER and the + * MiniportAdapterHandle. The NDIS_MINIPORT_TIMER has its own callout + * function and context pointers separate from those in the DPC, which + * allows for another level of indirection: when the timer fires, we + * can have our own timer function invoked, and from there we can call + * the driver's function. But why go to all that trouble? Then it hit + * me: for serialized miniports, the timer callouts are not re-entrant. + * By trapping the callouts and having access to the MiniportAdapterHandle, + * we can protect the driver callouts by acquiring the NDIS serialization + * lock. This is essential for allowing serialized miniports to work + * correctly on SMP systems. On UP hosts, setting IRQL to DISPATCH_LEVEL + * is enough to prevent other threads from pre-empting you, but with + * SMP, you must acquire a lock as well, otherwise the other CPU is + * free to clobber you. + */ +static void +NdisMInitializeTimer(timer, handle, func, ctx) + ndis_miniport_timer *timer; + ndis_handle handle; + ndis_timer_function func; + void *ctx; +{ + ndis_miniport_block *block; + struct ndis_softc *sc; + + block = (ndis_miniport_block *)handle; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + /* Save the driver's funcptr and context */ + + timer->nmt_timerfunc = func; + timer->nmt_timerctx = ctx; + timer->nmt_block = handle; + + /* + * Set up the timer so it will call our intermediate DPC. + * Be sure to use the wrapped entry point, since + * ntoskrnl_run_dpc() expects to invoke a function with + * Microsoft calling conventions. + */ + KeInitializeTimer(&timer->nmt_ktimer); + KeInitializeDpc(&timer->nmt_kdpc, + ndis_findwrap((funcptr)ndis_timercall), timer); + timer->nmt_ktimer.k_dpc = &timer->nmt_kdpc; +} + +/* + * In Windows, there's both an NdisMSetTimer() and an NdisSetTimer(), + * but the former is just a macro wrapper around the latter. + */ +static void +NdisSetTimer(timer, msecs) + ndis_timer *timer; + uint32_t msecs; +{ + /* + * KeSetTimer() wants the period in + * hundred nanosecond intervals. + */ + KeSetTimer(&timer->nt_ktimer, + ((int64_t)msecs * -10000), &timer->nt_kdpc); +} + +static void +NdisMSetPeriodicTimer(timer, msecs) + ndis_miniport_timer *timer; + uint32_t msecs; +{ + KeSetTimerEx(&timer->nmt_ktimer, + ((int64_t)msecs * -10000), msecs, &timer->nmt_kdpc); +} + +/* + * Technically, this is really NdisCancelTimer(), but we also + * (ab)use it for NdisMCancelTimer(), since in our implementation + * we don't need the extra info in the ndis_miniport_timer + * structure just to cancel a timer. + */ + +static void +NdisMCancelTimer(timer, cancelled) + ndis_timer *timer; + uint8_t *cancelled; +{ + + *cancelled = KeCancelTimer(&timer->nt_ktimer); +} + +static void +NdisMQueryAdapterResources(status, adapter, list, buflen) + ndis_status *status; + ndis_handle adapter; + ndis_resource_list *list; + uint32_t *buflen; +{ + ndis_miniport_block *block; + struct ndis_softc *sc; + int rsclen; + + block = (ndis_miniport_block *)adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + rsclen = sizeof(ndis_resource_list) + + (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)); + if (*buflen < rsclen) { + *buflen = rsclen; + *status = NDIS_STATUS_INVALID_LENGTH; + return; + } + + bcopy((char *)block->nmb_rlist, (char *)list, rsclen); + *status = NDIS_STATUS_SUCCESS; +} + +static ndis_status +NdisMRegisterIoPortRange(offset, adapter, port, numports) + void **offset; + ndis_handle adapter; + uint32_t port; + uint32_t numports; +{ + struct ndis_miniport_block *block; + struct ndis_softc *sc; + + if (adapter == NULL) + return (NDIS_STATUS_FAILURE); + + block = (ndis_miniport_block *)adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + if (sc->ndis_res_io == NULL) + return (NDIS_STATUS_FAILURE); + + /* Don't let the device map more ports than we have. */ + if (rman_get_size(sc->ndis_res_io) < numports) + return (NDIS_STATUS_INVALID_LENGTH); + + *offset = (void *)rman_get_start(sc->ndis_res_io); + + return (NDIS_STATUS_SUCCESS); +} + +static void +NdisMDeregisterIoPortRange(adapter, port, numports, offset) + ndis_handle adapter; + uint32_t port; + uint32_t numports; + void *offset; +{ +} + +static void +NdisReadNetworkAddress(status, addr, addrlen, adapter) + ndis_status *status; + void **addr; + uint32_t *addrlen; + ndis_handle adapter; +{ + struct ndis_softc *sc; + ndis_miniport_block *block; + uint8_t empty[] = { 0, 0, 0, 0, 0, 0 }; + + block = (ndis_miniport_block *)adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + if (sc->ifp == NULL) { + *status = NDIS_STATUS_FAILURE; + return; + } + + if (sc->ifp->if_addr == NULL || + bcmp(IF_LLADDR(sc->ifp), empty, ETHER_ADDR_LEN) == 0) + *status = NDIS_STATUS_FAILURE; + else { + *addr = IF_LLADDR(sc->ifp); + *addrlen = ETHER_ADDR_LEN; + *status = NDIS_STATUS_SUCCESS; + } +} + +static ndis_status +NdisQueryMapRegisterCount(bustype, cnt) + uint32_t bustype; + uint32_t *cnt; +{ + *cnt = 8192; + return (NDIS_STATUS_SUCCESS); +} + +static ndis_status +NdisMAllocateMapRegisters(ndis_handle adapter, uint32_t dmachannel, + uint8_t dmasize, uint32_t physmapneeded, uint32_t maxmap) +{ + struct ndis_softc *sc; + ndis_miniport_block *block; + int error, i, nseg = NDIS_MAXSEG; + + block = (ndis_miniport_block *)adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + sc->ndis_mmaps = malloc(sizeof(bus_dmamap_t) * physmapneeded, + M_DEVBUF, M_NOWAIT|M_ZERO); + + if (sc->ndis_mmaps == NULL) + return (NDIS_STATUS_RESOURCES); + + error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, + NULL, maxmap * nseg, nseg, maxmap, BUS_DMA_ALLOCNOW, + NULL, NULL, &sc->ndis_mtag); + + if (error) { + free(sc->ndis_mmaps, M_DEVBUF); + return (NDIS_STATUS_RESOURCES); + } + + for (i = 0; i < physmapneeded; i++) + bus_dmamap_create(sc->ndis_mtag, 0, &sc->ndis_mmaps[i]); + + sc->ndis_mmapcnt = physmapneeded; + + return (NDIS_STATUS_SUCCESS); +} + +static void +NdisMFreeMapRegisters(adapter) + ndis_handle adapter; +{ + struct ndis_softc *sc; + ndis_miniport_block *block; + int i; + + block = (ndis_miniport_block *)adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + for (i = 0; i < sc->ndis_mmapcnt; i++) + bus_dmamap_destroy(sc->ndis_mtag, sc->ndis_mmaps[i]); + + free(sc->ndis_mmaps, M_DEVBUF); + + bus_dma_tag_destroy(sc->ndis_mtag); +} + +static void +ndis_mapshared_cb(arg, segs, nseg, error) + void *arg; + bus_dma_segment_t *segs; + int nseg; + int error; +{ + ndis_physaddr *p; + + if (error || nseg > 1) + return; + + p = arg; + + p->np_quad = segs[0].ds_addr; +} + +/* + * This maps to bus_dmamem_alloc(). + */ + +static void +NdisMAllocateSharedMemory(ndis_handle adapter, uint32_t len, uint8_t cached, + void **vaddr, ndis_physaddr *paddr) +{ + ndis_miniport_block *block; + struct ndis_softc *sc; + struct ndis_shmem *sh; + int error; + + if (adapter == NULL) + return; + + block = (ndis_miniport_block *)adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + sh = malloc(sizeof(struct ndis_shmem), M_DEVBUF, M_NOWAIT|M_ZERO); + if (sh == NULL) + return; + + InitializeListHead(&sh->ndis_list); + + /* + * When performing shared memory allocations, create a tag + * with a lowaddr limit that restricts physical memory mappings + * so that they all fall within the first 1GB of memory. + * At least one device/driver combination (Linksys Instant + * Wireless PCI Card V2.7, Broadcom 802.11b) seems to have + * problems with performing DMA operations with physical + * addresses that lie above the 1GB mark. I don't know if this + * is a hardware limitation or if the addresses are being + * truncated within the driver, but this seems to be the only + * way to make these cards work reliably in systems with more + * than 1GB of physical memory. + */ + + error = bus_dma_tag_create(sc->ndis_parent_tag, 64, + 0, NDIS_BUS_SPACE_SHARED_MAXADDR, BUS_SPACE_MAXADDR, NULL, + NULL, len, 1, len, BUS_DMA_ALLOCNOW, NULL, NULL, + &sh->ndis_stag); + + if (error) { + free(sh, M_DEVBUF); + return; + } + + error = bus_dmamem_alloc(sh->ndis_stag, vaddr, + BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sh->ndis_smap); + + if (error) { + bus_dma_tag_destroy(sh->ndis_stag); + free(sh, M_DEVBUF); + return; + } + + error = bus_dmamap_load(sh->ndis_stag, sh->ndis_smap, *vaddr, + len, ndis_mapshared_cb, (void *)paddr, BUS_DMA_NOWAIT); + + if (error) { + bus_dmamem_free(sh->ndis_stag, *vaddr, sh->ndis_smap); + bus_dma_tag_destroy(sh->ndis_stag); + free(sh, M_DEVBUF); + return; + } + + /* + * Save the physical address along with the source address. + * The AirGo MIMO driver will call NdisMFreeSharedMemory() + * with a bogus virtual address sometimes, but with a valid + * physical address. To keep this from causing trouble, we + * use the physical address to as a sanity check in case + * searching based on the virtual address fails. + */ + + NDIS_LOCK(sc); + sh->ndis_paddr.np_quad = paddr->np_quad; + sh->ndis_saddr = *vaddr; + InsertHeadList((&sc->ndis_shlist), (&sh->ndis_list)); + NDIS_UNLOCK(sc); +} + +struct ndis_allocwork { + uint32_t na_len; + uint8_t na_cached; + void *na_ctx; + io_workitem *na_iw; +}; + +static void +ndis_asyncmem_complete(dobj, arg) + device_object *dobj; + void *arg; +{ + ndis_miniport_block *block; + struct ndis_softc *sc; + struct ndis_allocwork *w; + void *vaddr; + ndis_physaddr paddr; + ndis_allocdone_handler donefunc; + + w = arg; + block = (ndis_miniport_block *)dobj->do_devext; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + vaddr = NULL; + paddr.np_quad = 0; + + donefunc = sc->ndis_chars->nmc_allocate_complete_func; + NdisMAllocateSharedMemory(block, w->na_len, + w->na_cached, &vaddr, &paddr); + MSCALL5(donefunc, block, vaddr, &paddr, w->na_len, w->na_ctx); + + IoFreeWorkItem(w->na_iw); + free(w, M_DEVBUF); +} + +static ndis_status +NdisMAllocateSharedMemoryAsync(ndis_handle adapter, uint32_t len, + uint8_t cached, void *ctx) +{ + ndis_miniport_block *block; + struct ndis_allocwork *w; + io_workitem *iw; + io_workitem_func ifw; + + if (adapter == NULL) + return (NDIS_STATUS_FAILURE); + + block = adapter; + + iw = IoAllocateWorkItem(block->nmb_deviceobj); + if (iw == NULL) + return (NDIS_STATUS_FAILURE); + + w = malloc(sizeof(struct ndis_allocwork), M_TEMP, M_NOWAIT); + + if (w == NULL) + return (NDIS_STATUS_FAILURE); + + w->na_cached = cached; + w->na_len = len; + w->na_ctx = ctx; + w->na_iw = iw; + + ifw = (io_workitem_func)ndis_findwrap((funcptr)ndis_asyncmem_complete); + IoQueueWorkItem(iw, ifw, WORKQUEUE_DELAYED, w); + + return (NDIS_STATUS_PENDING); +} + +static void +NdisMFreeSharedMemory(ndis_handle adapter, uint32_t len, uint8_t cached, + void *vaddr, ndis_physaddr paddr) +{ + ndis_miniport_block *block; + struct ndis_softc *sc; + struct ndis_shmem *sh = NULL; + list_entry *l; + + if (vaddr == NULL || adapter == NULL) + return; + + block = (ndis_miniport_block *)adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + /* Sanity check: is list empty? */ + + if (IsListEmpty(&sc->ndis_shlist)) + return; + + NDIS_LOCK(sc); + l = sc->ndis_shlist.nle_flink; + while (l != &sc->ndis_shlist) { + sh = CONTAINING_RECORD(l, struct ndis_shmem, ndis_list); + if (sh->ndis_saddr == vaddr) + break; + /* + * Check the physaddr too, just in case the driver lied + * about the virtual address. + */ + if (sh->ndis_paddr.np_quad == paddr.np_quad) + break; + l = l->nle_flink; + } + + if (sh == NULL) { + NDIS_UNLOCK(sc); + printf("NDIS: buggy driver tried to free " + "invalid shared memory: vaddr: %p paddr: 0x%jx\n", + vaddr, (uintmax_t)paddr.np_quad); + return; + } + + RemoveEntryList(&sh->ndis_list); + + NDIS_UNLOCK(sc); + + bus_dmamap_unload(sh->ndis_stag, sh->ndis_smap); + bus_dmamem_free(sh->ndis_stag, sh->ndis_saddr, sh->ndis_smap); + bus_dma_tag_destroy(sh->ndis_stag); + + free(sh, M_DEVBUF); +} + +static ndis_status +NdisMMapIoSpace(vaddr, adapter, paddr, len) + void **vaddr; + ndis_handle adapter; + ndis_physaddr paddr; + uint32_t len; +{ + if (adapter == NULL) + return (NDIS_STATUS_FAILURE); + + *vaddr = MmMapIoSpace(paddr.np_quad, len, 0); + + if (*vaddr == NULL) + return (NDIS_STATUS_FAILURE); + + return (NDIS_STATUS_SUCCESS); +} + +static void +NdisMUnmapIoSpace(adapter, vaddr, len) + ndis_handle adapter; + void *vaddr; + uint32_t len; +{ + MmUnmapIoSpace(vaddr, len); +} + +static uint32_t +NdisGetCacheFillSize(void) +{ + return (128); +} + +static void * +NdisGetRoutineAddress(ustr) + unicode_string *ustr; +{ + ansi_string astr; + + if (RtlUnicodeStringToAnsiString(&astr, ustr, TRUE)) + return (NULL); + return (ndis_get_routine_address(ndis_functbl, astr.as_buf)); +} + +static uint32_t +NdisMGetDmaAlignment(handle) + ndis_handle handle; +{ + return (16); +} + +/* + * NDIS has two methods for dealing with NICs that support DMA. + * One is to just pass packets to the driver and let it call + * NdisMStartBufferPhysicalMapping() to map each buffer in the packet + * all by itself, and the other is to let the NDIS library handle the + * buffer mapping internally, and hand the driver an already populated + * scatter/gather fragment list. If the driver calls + * NdisMInitializeScatterGatherDma(), it wants to use the latter + * method. + */ + +static ndis_status +NdisMInitializeScatterGatherDma(ndis_handle adapter, uint8_t is64, + uint32_t maxphysmap) +{ + struct ndis_softc *sc; + ndis_miniport_block *block; + int error; + + if (adapter == NULL) + return (NDIS_STATUS_FAILURE); + block = (ndis_miniport_block *)adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + /* Don't do this twice. */ + if (sc->ndis_sc == 1) + return (NDIS_STATUS_SUCCESS); + + error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + MCLBYTES * NDIS_MAXSEG, NDIS_MAXSEG, MCLBYTES, BUS_DMA_ALLOCNOW, + NULL, NULL, &sc->ndis_ttag); + + sc->ndis_sc = 1; + + return (NDIS_STATUS_SUCCESS); +} + +void +NdisAllocatePacketPool(status, pool, descnum, protrsvdlen) + ndis_status *status; + ndis_handle *pool; + uint32_t descnum; + uint32_t protrsvdlen; +{ + ndis_packet_pool *p; + ndis_packet *packets; + int i; + + p = ExAllocatePoolWithTag(NonPagedPool, sizeof(ndis_packet_pool), 0); + if (p == NULL) { + *status = NDIS_STATUS_RESOURCES; + return; + } + + p->np_cnt = descnum + NDIS_POOL_EXTRA; + p->np_protrsvd = protrsvdlen; + p->np_len = sizeof(ndis_packet) + protrsvdlen; + + packets = ExAllocatePoolWithTag(NonPagedPool, p->np_cnt * + p->np_len, 0); + + + if (packets == NULL) { + ExFreePool(p); + *status = NDIS_STATUS_RESOURCES; + return; + } + + p->np_pktmem = packets; + + for (i = 0; i < p->np_cnt; i++) + InterlockedPushEntrySList(&p->np_head, + (struct slist_entry *)&packets[i]); + +#ifdef NDIS_DEBUG_PACKETS + p->np_dead = 0; + KeInitializeSpinLock(&p->np_lock); + KeInitializeEvent(&p->np_event, EVENT_TYPE_NOTIFY, TRUE); +#endif + + *pool = p; + *status = NDIS_STATUS_SUCCESS; +} + +void +NdisAllocatePacketPoolEx(status, pool, descnum, oflowdescnum, protrsvdlen) + ndis_status *status; + ndis_handle *pool; + uint32_t descnum; + uint32_t oflowdescnum; + uint32_t protrsvdlen; +{ + return (NdisAllocatePacketPool(status, pool, + descnum + oflowdescnum, protrsvdlen)); +} + +uint32_t +NdisPacketPoolUsage(pool) + ndis_handle pool; +{ + ndis_packet_pool *p; + + p = (ndis_packet_pool *)pool; + return (p->np_cnt - ExQueryDepthSList(&p->np_head)); +} + +void +NdisFreePacketPool(pool) + ndis_handle pool; +{ + ndis_packet_pool *p; + int usage; +#ifdef NDIS_DEBUG_PACKETS + uint8_t irql; +#endif + + p = (ndis_packet_pool *)pool; + +#ifdef NDIS_DEBUG_PACKETS + KeAcquireSpinLock(&p->np_lock, &irql); +#endif + + usage = NdisPacketPoolUsage(pool); + +#ifdef NDIS_DEBUG_PACKETS + if (usage) { + p->np_dead = 1; + KeResetEvent(&p->np_event); + KeReleaseSpinLock(&p->np_lock, irql); + KeWaitForSingleObject(&p->np_event, 0, 0, FALSE, NULL); + } else + KeReleaseSpinLock(&p->np_lock, irql); +#endif + + ExFreePool(p->np_pktmem); + ExFreePool(p); +} + +void +NdisAllocatePacket(status, packet, pool) + ndis_status *status; + ndis_packet **packet; + ndis_handle pool; +{ + ndis_packet_pool *p; + ndis_packet *pkt; +#ifdef NDIS_DEBUG_PACKETS + uint8_t irql; +#endif + + p = (ndis_packet_pool *)pool; + +#ifdef NDIS_DEBUG_PACKETS + KeAcquireSpinLock(&p->np_lock, &irql); + if (p->np_dead) { + KeReleaseSpinLock(&p->np_lock, irql); + printf("NDIS: tried to allocate packet from dead pool %p\n", + pool); + *status = NDIS_STATUS_RESOURCES; + return; + } +#endif + + pkt = (ndis_packet *)InterlockedPopEntrySList(&p->np_head); + +#ifdef NDIS_DEBUG_PACKETS + KeReleaseSpinLock(&p->np_lock, irql); +#endif + + if (pkt == NULL) { + *status = NDIS_STATUS_RESOURCES; + return; + } + + + bzero((char *)pkt, sizeof(ndis_packet)); + + /* Save pointer to the pool. */ + pkt->np_private.npp_pool = pool; + + /* Set the oob offset pointer. Lots of things expect this. */ + pkt->np_private.npp_packetooboffset = offsetof(ndis_packet, np_oob); + + /* + * We must initialize the packet flags correctly in order + * for the NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO() and + * NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO() macros to work + * correctly. + */ + pkt->np_private.npp_ndispktflags = NDIS_PACKET_ALLOCATED_BY_NDIS; + pkt->np_private.npp_validcounts = FALSE; + + *packet = pkt; + + *status = NDIS_STATUS_SUCCESS; +} + +void +NdisFreePacket(packet) + ndis_packet *packet; +{ + ndis_packet_pool *p; +#ifdef NDIS_DEBUG_PACKETS + uint8_t irql; +#endif + + p = (ndis_packet_pool *)packet->np_private.npp_pool; + +#ifdef NDIS_DEBUG_PACKETS + KeAcquireSpinLock(&p->np_lock, &irql); +#endif + + InterlockedPushEntrySList(&p->np_head, (slist_entry *)packet); + +#ifdef NDIS_DEBUG_PACKETS + if (p->np_dead) { + if (ExQueryDepthSList(&p->np_head) == p->np_cnt) + KeSetEvent(&p->np_event, IO_NO_INCREMENT, FALSE); + } + KeReleaseSpinLock(&p->np_lock, irql); +#endif +} + +static void +NdisUnchainBufferAtFront(packet, buf) + ndis_packet *packet; + ndis_buffer **buf; +{ + ndis_packet_private *priv; + + if (packet == NULL || buf == NULL) + return; + + priv = &packet->np_private; + + priv->npp_validcounts = FALSE; + + if (priv->npp_head == priv->npp_tail) { + *buf = priv->npp_head; + priv->npp_head = priv->npp_tail = NULL; + } else { + *buf = priv->npp_head; + priv->npp_head = (*buf)->mdl_next; + } +} + +static void +NdisUnchainBufferAtBack(packet, buf) + ndis_packet *packet; + ndis_buffer **buf; +{ + ndis_packet_private *priv; + ndis_buffer *tmp; + + if (packet == NULL || buf == NULL) + return; + + priv = &packet->np_private; + + priv->npp_validcounts = FALSE; + + if (priv->npp_head == priv->npp_tail) { + *buf = priv->npp_head; + priv->npp_head = priv->npp_tail = NULL; + } else { + *buf = priv->npp_tail; + tmp = priv->npp_head; + while (tmp->mdl_next != priv->npp_tail) + tmp = tmp->mdl_next; + priv->npp_tail = tmp; + tmp->mdl_next = NULL; + } +} + +/* + * The NDIS "buffer" is really an MDL (memory descriptor list) + * which is used to describe a buffer in a way that allows it + * to mapped into different contexts. We have to be careful how + * we handle them: in some versions of Windows, the NdisFreeBuffer() + * routine is an actual function in the NDIS API, but in others + * it's just a macro wrapper around IoFreeMdl(). There's really + * no way to use the 'descnum' parameter to count how many + * "buffers" are allocated since in order to use IoFreeMdl() to + * dispose of a buffer, we have to use IoAllocateMdl() to allocate + * them, and IoAllocateMdl() just grabs them out of the heap. + */ + +static void +NdisAllocateBufferPool(status, pool, descnum) + ndis_status *status; + ndis_handle *pool; + uint32_t descnum; +{ + + /* + * The only thing we can really do here is verify that descnum + * is a reasonable value, but I really don't know what to check + * it against. + */ + + *pool = NonPagedPool; + *status = NDIS_STATUS_SUCCESS; +} + +static void +NdisFreeBufferPool(pool) + ndis_handle pool; +{ +} + +static void +NdisAllocateBuffer(status, buffer, pool, vaddr, len) + ndis_status *status; + ndis_buffer **buffer; + ndis_handle pool; + void *vaddr; + uint32_t len; +{ + ndis_buffer *buf; + + buf = IoAllocateMdl(vaddr, len, FALSE, FALSE, NULL); + if (buf == NULL) { + *status = NDIS_STATUS_RESOURCES; + return; + } + + MmBuildMdlForNonPagedPool(buf); + + *buffer = buf; + *status = NDIS_STATUS_SUCCESS; +} + +static void +NdisFreeBuffer(buf) + ndis_buffer *buf; +{ + IoFreeMdl(buf); +} + +/* Aw c'mon. */ + +static uint32_t +NdisBufferLength(buf) + ndis_buffer *buf; +{ + return (MmGetMdlByteCount(buf)); +} + +/* + * Get the virtual address and length of a buffer. + * Note: the vaddr argument is optional. + */ + +static void +NdisQueryBuffer(buf, vaddr, len) + ndis_buffer *buf; + void **vaddr; + uint32_t *len; +{ + if (vaddr != NULL) + *vaddr = MmGetMdlVirtualAddress(buf); + *len = MmGetMdlByteCount(buf); +} + +/* Same as above -- we don't care about the priority. */ + +static void +NdisQueryBufferSafe(buf, vaddr, len, prio) + ndis_buffer *buf; + void **vaddr; + uint32_t *len; + uint32_t prio; +{ + if (vaddr != NULL) + *vaddr = MmGetMdlVirtualAddress(buf); + *len = MmGetMdlByteCount(buf); +} + +/* Damnit Microsoft!! How many ways can you do the same thing?! */ + +static void * +NdisBufferVirtualAddress(buf) + ndis_buffer *buf; +{ + return (MmGetMdlVirtualAddress(buf)); +} + +static void * +NdisBufferVirtualAddressSafe(buf, prio) + ndis_buffer *buf; + uint32_t prio; +{ + return (MmGetMdlVirtualAddress(buf)); +} + +static void +NdisAdjustBufferLength(buf, len) + ndis_buffer *buf; + int len; +{ + MmGetMdlByteCount(buf) = len; +} + +static uint32_t +NdisInterlockedIncrement(addend) + uint32_t *addend; +{ + atomic_add_long((u_long *)addend, 1); + return (*addend); +} + +static uint32_t +NdisInterlockedDecrement(addend) + uint32_t *addend; +{ + atomic_subtract_long((u_long *)addend, 1); + return (*addend); +} + +static uint32_t +NdisGetVersion(void) +{ + return (0x00050001); +} + +static void +NdisInitializeEvent(event) + ndis_event *event; +{ + /* + * NDIS events are always notification + * events, and should be initialized to the + * not signaled state. + */ + KeInitializeEvent(&event->ne_event, EVENT_TYPE_NOTIFY, FALSE); +} + +static void +NdisSetEvent(event) + ndis_event *event; +{ + KeSetEvent(&event->ne_event, IO_NO_INCREMENT, FALSE); +} + +static void +NdisResetEvent(event) + ndis_event *event; +{ + KeResetEvent(&event->ne_event); +} + +static uint8_t +NdisWaitEvent(event, msecs) + ndis_event *event; + uint32_t msecs; +{ + int64_t duetime; + uint32_t rval; + + duetime = ((int64_t)msecs * -10000); + rval = KeWaitForSingleObject(event, + 0, 0, TRUE, msecs ? & duetime : NULL); + + if (rval == STATUS_TIMEOUT) + return (FALSE); + + return (TRUE); +} + +static ndis_status +NdisUnicodeStringToAnsiString(dstr, sstr) + ansi_string *dstr; + unicode_string *sstr; +{ + uint32_t rval; + + rval = RtlUnicodeStringToAnsiString(dstr, sstr, FALSE); + + if (rval == STATUS_INSUFFICIENT_RESOURCES) + return (NDIS_STATUS_RESOURCES); + if (rval) + return (NDIS_STATUS_FAILURE); + + return (NDIS_STATUS_SUCCESS); +} + +static ndis_status +NdisAnsiStringToUnicodeString(dstr, sstr) + unicode_string *dstr; + ansi_string *sstr; +{ + uint32_t rval; + + rval = RtlAnsiStringToUnicodeString(dstr, sstr, FALSE); + + if (rval == STATUS_INSUFFICIENT_RESOURCES) + return (NDIS_STATUS_RESOURCES); + if (rval) + return (NDIS_STATUS_FAILURE); + + return (NDIS_STATUS_SUCCESS); +} + +static ndis_status +NdisMPciAssignResources(adapter, slot, list) + ndis_handle adapter; + uint32_t slot; + ndis_resource_list **list; +{ + ndis_miniport_block *block; + + if (adapter == NULL || list == NULL) + return (NDIS_STATUS_FAILURE); + + block = (ndis_miniport_block *)adapter; + *list = block->nmb_rlist; + + return (NDIS_STATUS_SUCCESS); +} + +static uint8_t +ndis_intr(iobj, arg) + kinterrupt *iobj; + void *arg; +{ + struct ndis_softc *sc; + uint8_t is_our_intr = FALSE; + int call_isr = 0; + ndis_miniport_interrupt *intr; + + sc = arg; + intr = sc->ndis_block->nmb_interrupt; + + if (intr == NULL || sc->ndis_block->nmb_miniportadapterctx == NULL) + return (FALSE); + + if (sc->ndis_block->nmb_interrupt->ni_isrreq == TRUE) + MSCALL3(intr->ni_isrfunc, &is_our_intr, &call_isr, + sc->ndis_block->nmb_miniportadapterctx); + else { + MSCALL1(sc->ndis_chars->nmc_disable_interrupts_func, + sc->ndis_block->nmb_miniportadapterctx); + call_isr = 1; + } + + if (call_isr) + IoRequestDpc(sc->ndis_block->nmb_deviceobj, NULL, sc); + + return (is_our_intr); +} + +static void +ndis_intrhand(dpc, intr, sysarg1, sysarg2) + kdpc *dpc; + ndis_miniport_interrupt *intr; + void *sysarg1; + void *sysarg2; +{ + struct ndis_softc *sc; + ndis_miniport_block *block; + ndis_handle adapter; + + block = intr->ni_block; + adapter = block->nmb_miniportadapterctx; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + + if (NDIS_SERIALIZED(sc->ndis_block)) + KeAcquireSpinLockAtDpcLevel(&block->nmb_lock); + + MSCALL1(intr->ni_dpcfunc, adapter); + + /* If there's a MiniportEnableInterrupt() routine, call it. */ + + if (sc->ndis_chars->nmc_enable_interrupts_func != NULL) + MSCALL1(sc->ndis_chars->nmc_enable_interrupts_func, adapter); + + if (NDIS_SERIALIZED(sc->ndis_block)) + KeReleaseSpinLockFromDpcLevel(&block->nmb_lock); + + /* + * Set the completion event if we've drained all + * pending interrupts. + */ + + KeAcquireSpinLockAtDpcLevel(&intr->ni_dpccountlock); + intr->ni_dpccnt--; + if (intr->ni_dpccnt == 0) + KeSetEvent(&intr->ni_dpcevt, IO_NO_INCREMENT, FALSE); + KeReleaseSpinLockFromDpcLevel(&intr->ni_dpccountlock); +} + +static ndis_status +NdisMRegisterInterrupt(ndis_miniport_interrupt *intr, ndis_handle adapter, + uint32_t ivec, uint32_t ilevel, uint8_t reqisr, uint8_t shared, + ndis_interrupt_mode imode) +{ + ndis_miniport_block *block; + ndis_miniport_characteristics *ch; + struct ndis_softc *sc; + int error; + + block = adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + ch = IoGetDriverObjectExtension(block->nmb_deviceobj->do_drvobj, + (void *)1); + + intr->ni_rsvd = ExAllocatePoolWithTag(NonPagedPool, + sizeof(struct mtx), 0); + if (intr->ni_rsvd == NULL) + return (NDIS_STATUS_RESOURCES); + + intr->ni_block = adapter; + intr->ni_isrreq = reqisr; + intr->ni_shared = shared; + intr->ni_dpccnt = 0; + intr->ni_isrfunc = ch->nmc_isr_func; + intr->ni_dpcfunc = ch->nmc_interrupt_func; + + KeInitializeEvent(&intr->ni_dpcevt, EVENT_TYPE_NOTIFY, TRUE); + KeInitializeDpc(&intr->ni_dpc, + ndis_findwrap((funcptr)ndis_intrhand), intr); + KeSetImportanceDpc(&intr->ni_dpc, KDPC_IMPORTANCE_LOW); + + error = IoConnectInterrupt(&intr->ni_introbj, + ndis_findwrap((funcptr)ndis_intr), sc, NULL, + ivec, ilevel, 0, imode, shared, 0, FALSE); + + if (error != STATUS_SUCCESS) + return (NDIS_STATUS_FAILURE); + + block->nmb_interrupt = intr; + + return (NDIS_STATUS_SUCCESS); +} + +static void +NdisMDeregisterInterrupt(intr) + ndis_miniport_interrupt *intr; +{ + ndis_miniport_block *block; + uint8_t irql; + + block = intr->ni_block; + + /* Should really be KeSynchronizeExecution() */ + + KeAcquireSpinLock(intr->ni_introbj->ki_lock, &irql); + block->nmb_interrupt = NULL; + KeReleaseSpinLock(intr->ni_introbj->ki_lock, irql); +/* + KeFlushQueuedDpcs(); +*/ + /* Disconnect our ISR */ + + IoDisconnectInterrupt(intr->ni_introbj); + + KeWaitForSingleObject(&intr->ni_dpcevt, 0, 0, FALSE, NULL); + KeResetEvent(&intr->ni_dpcevt); +} + +static void +NdisMRegisterAdapterShutdownHandler(adapter, shutdownctx, shutdownfunc) + ndis_handle adapter; + void *shutdownctx; + ndis_shutdown_handler shutdownfunc; +{ + ndis_miniport_block *block; + ndis_miniport_characteristics *chars; + struct ndis_softc *sc; + + if (adapter == NULL) + return; + + block = (ndis_miniport_block *)adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + chars = sc->ndis_chars; + + chars->nmc_shutdown_handler = shutdownfunc; + chars->nmc_rsvd0 = shutdownctx; +} + +static void +NdisMDeregisterAdapterShutdownHandler(adapter) + ndis_handle adapter; +{ + ndis_miniport_block *block; + ndis_miniport_characteristics *chars; + struct ndis_softc *sc; + + if (adapter == NULL) + return; + + block = (ndis_miniport_block *)adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + chars = sc->ndis_chars; + + chars->nmc_shutdown_handler = NULL; + chars->nmc_rsvd0 = NULL; +} + +static uint32_t +NDIS_BUFFER_TO_SPAN_PAGES(buf) + ndis_buffer *buf; +{ + if (buf == NULL) + return (0); + if (MmGetMdlByteCount(buf) == 0) + return (1); + return (SPAN_PAGES(MmGetMdlVirtualAddress(buf), + MmGetMdlByteCount(buf))); +} + +static void +NdisGetBufferPhysicalArraySize(buf, pages) + ndis_buffer *buf; + uint32_t *pages; +{ + if (buf == NULL) + return; + + *pages = NDIS_BUFFER_TO_SPAN_PAGES(buf); +} + +static void +NdisQueryBufferOffset(buf, off, len) + ndis_buffer *buf; + uint32_t *off; + uint32_t *len; +{ + if (buf == NULL) + return; + + *off = MmGetMdlByteOffset(buf); + *len = MmGetMdlByteCount(buf); +} + +void +NdisMSleep(usecs) + uint32_t usecs; +{ + ktimer timer; + + /* + * During system bootstrap, (i.e. cold == 1), we aren't + * allowed to sleep, so we have to do a hard DELAY() + * instead. + */ + + if (cold) + DELAY(usecs); + else { + KeInitializeTimer(&timer); + KeSetTimer(&timer, ((int64_t)usecs * -10), NULL); + KeWaitForSingleObject(&timer, 0, 0, FALSE, NULL); + } +} + +static uint32_t +NdisReadPcmciaAttributeMemory(handle, offset, buf, len) + ndis_handle handle; + uint32_t offset; + void *buf; + uint32_t len; +{ + struct ndis_softc *sc; + ndis_miniport_block *block; + bus_space_handle_t bh; + bus_space_tag_t bt; + char *dest; + int i; + + if (handle == NULL) + return (0); + + block = (ndis_miniport_block *)handle; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + dest = buf; + + bh = rman_get_bushandle(sc->ndis_res_am); + bt = rman_get_bustag(sc->ndis_res_am); + + for (i = 0; i < len; i++) + dest[i] = bus_space_read_1(bt, bh, (offset + i) * 2); + + return (i); +} + +static uint32_t +NdisWritePcmciaAttributeMemory(handle, offset, buf, len) + ndis_handle handle; + uint32_t offset; + void *buf; + uint32_t len; +{ + struct ndis_softc *sc; + ndis_miniport_block *block; + bus_space_handle_t bh; + bus_space_tag_t bt; + char *src; + int i; + + if (handle == NULL) + return (0); + + block = (ndis_miniport_block *)handle; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + src = buf; + + bh = rman_get_bushandle(sc->ndis_res_am); + bt = rman_get_bustag(sc->ndis_res_am); + + for (i = 0; i < len; i++) + bus_space_write_1(bt, bh, (offset + i) * 2, src[i]); + + return (i); +} + +static list_entry * +NdisInterlockedInsertHeadList(head, entry, lock) + list_entry *head; + list_entry *entry; + ndis_spin_lock *lock; +{ + list_entry *flink; + + KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql); + flink = head->nle_flink; + entry->nle_flink = flink; + entry->nle_blink = head; + flink->nle_blink = entry; + head->nle_flink = entry; + KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql); + + return (flink); +} + +static list_entry * +NdisInterlockedRemoveHeadList(head, lock) + list_entry *head; + ndis_spin_lock *lock; +{ + list_entry *flink; + list_entry *entry; + + KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql); + entry = head->nle_flink; + flink = entry->nle_flink; + head->nle_flink = flink; + flink->nle_blink = head; + KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql); + + return (entry); +} + +static list_entry * +NdisInterlockedInsertTailList(head, entry, lock) + list_entry *head; + list_entry *entry; + ndis_spin_lock *lock; +{ + list_entry *blink; + + KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql); + blink = head->nle_blink; + entry->nle_flink = head; + entry->nle_blink = blink; + blink->nle_flink = entry; + head->nle_blink = entry; + KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql); + + return (blink); +} + +static uint8_t +NdisMSynchronizeWithInterrupt(intr, syncfunc, syncctx) + ndis_miniport_interrupt *intr; + void *syncfunc; + void *syncctx; +{ + return (KeSynchronizeExecution(intr->ni_introbj, syncfunc, syncctx)); +} + +static void +NdisGetCurrentSystemTime(tval) + uint64_t *tval; +{ + ntoskrnl_time(tval); +} + +/* + * Return the number of milliseconds since the system booted. + */ +static void +NdisGetSystemUpTime(tval) + uint32_t *tval; +{ + struct timespec ts; + + nanouptime(&ts); + *tval = ts.tv_nsec / 1000000 + ts.tv_sec * 1000; +} + +static void +NdisInitializeString(dst, src) + unicode_string *dst; + char *src; +{ + ansi_string as; + RtlInitAnsiString(&as, src); + RtlAnsiStringToUnicodeString(dst, &as, TRUE); +} + +static void +NdisFreeString(str) + unicode_string *str; +{ + RtlFreeUnicodeString(str); +} + +static ndis_status +NdisMRemoveMiniport(adapter) + ndis_handle *adapter; +{ + return (NDIS_STATUS_SUCCESS); +} + +static void +NdisInitAnsiString(dst, src) + ansi_string *dst; + char *src; +{ + RtlInitAnsiString(dst, src); +} + +static void +NdisInitUnicodeString(dst, src) + unicode_string *dst; + uint16_t *src; +{ + RtlInitUnicodeString(dst, src); +} + +static void NdisMGetDeviceProperty(adapter, phydevobj, + funcdevobj, nextdevobj, resources, transresources) + ndis_handle adapter; + device_object **phydevobj; + device_object **funcdevobj; + device_object **nextdevobj; + cm_resource_list *resources; + cm_resource_list *transresources; +{ + ndis_miniport_block *block; + + block = (ndis_miniport_block *)adapter; + + if (phydevobj != NULL) + *phydevobj = block->nmb_physdeviceobj; + if (funcdevobj != NULL) + *funcdevobj = block->nmb_deviceobj; + if (nextdevobj != NULL) + *nextdevobj = block->nmb_nextdeviceobj; +} + +static void +NdisGetFirstBufferFromPacket(packet, buf, firstva, firstlen, totlen) + ndis_packet *packet; + ndis_buffer **buf; + void **firstva; + uint32_t *firstlen; + uint32_t *totlen; +{ + ndis_buffer *tmp; + + tmp = packet->np_private.npp_head; + *buf = tmp; + if (tmp == NULL) { + *firstva = NULL; + *firstlen = *totlen = 0; + } else { + *firstva = MmGetMdlVirtualAddress(tmp); + *firstlen = *totlen = MmGetMdlByteCount(tmp); + for (tmp = tmp->mdl_next; tmp != NULL; tmp = tmp->mdl_next) + *totlen += MmGetMdlByteCount(tmp); + } +} + +static void +NdisGetFirstBufferFromPacketSafe(packet, buf, firstva, firstlen, totlen, prio) + ndis_packet *packet; + ndis_buffer **buf; + void **firstva; + uint32_t *firstlen; + uint32_t *totlen; + uint32_t prio; +{ + NdisGetFirstBufferFromPacket(packet, buf, firstva, firstlen, totlen); +} + +static int +ndis_find_sym(lf, filename, suffix, sym) + linker_file_t lf; + char *filename; + char *suffix; + caddr_t *sym; +{ + char *fullsym; + char *suf; + int i; + + fullsym = ExAllocatePoolWithTag(NonPagedPool, MAXPATHLEN, 0); + if (fullsym == NULL) + return (ENOMEM); + + bzero(fullsym, MAXPATHLEN); + strncpy(fullsym, filename, MAXPATHLEN); + if (strlen(filename) < 4) { + ExFreePool(fullsym); + return (EINVAL); + } + + /* If the filename has a .ko suffix, strip if off. */ + suf = fullsym + (strlen(filename) - 3); + if (strcmp(suf, ".ko") == 0) + *suf = '\0'; + + for (i = 0; i < strlen(fullsym); i++) { + if (fullsym[i] == '.') + fullsym[i] = '_'; + else + fullsym[i] = tolower(fullsym[i]); + } + strcat(fullsym, suffix); + *sym = linker_file_lookup_symbol(lf, fullsym, 0); + ExFreePool(fullsym); + if (*sym == 0) + return (ENOENT); + + return (0); +} + +struct ndis_checkmodule { + char *afilename; + ndis_fh *fh; +}; + +/* + * See if a single module contains the symbols for a specified file. + */ +static int +NdisCheckModule(linker_file_t lf, void *context) +{ + struct ndis_checkmodule *nc; + caddr_t kldstart, kldend; + + nc = (struct ndis_checkmodule *)context; + if (ndis_find_sym(lf, nc->afilename, "_start", &kldstart)) + return (0); + if (ndis_find_sym(lf, nc->afilename, "_end", &kldend)) + return (0); + nc->fh->nf_vp = lf; + nc->fh->nf_map = NULL; + nc->fh->nf_type = NDIS_FH_TYPE_MODULE; + nc->fh->nf_maplen = (kldend - kldstart) & 0xFFFFFFFF; + return (1); +} + +/* can also return NDIS_STATUS_RESOURCES/NDIS_STATUS_ERROR_READING_FILE */ +static void +NdisOpenFile(status, filehandle, filelength, filename, highestaddr) + ndis_status *status; + ndis_handle *filehandle; + uint32_t *filelength; + unicode_string *filename; + ndis_physaddr highestaddr; +{ + ansi_string as; + char *afilename = NULL; + struct thread *td = curthread; + struct nameidata nd; + int flags, error; + struct vattr vat; + struct vattr *vap = &vat; + ndis_fh *fh; + char *path; + struct ndis_checkmodule nc; + + if (RtlUnicodeStringToAnsiString(&as, filename, TRUE)) { + *status = NDIS_STATUS_RESOURCES; + return; + } + + afilename = strdup(as.as_buf, M_DEVBUF); + RtlFreeAnsiString(&as); + + fh = ExAllocatePoolWithTag(NonPagedPool, sizeof(ndis_fh), 0); + if (fh == NULL) { + free(afilename, M_DEVBUF); + *status = NDIS_STATUS_RESOURCES; + return; + } + + fh->nf_name = afilename; + + /* + * During system bootstrap, it's impossible to load files + * from the rootfs since it's not mounted yet. We therefore + * offer the possibility of opening files that have been + * preloaded as modules instead. Both choices will work + * when kldloading a module from multiuser, but only the + * module option will work during bootstrap. The module + * loading option works by using the ndiscvt(8) utility + * to convert the arbitrary file into a .ko using objcopy(1). + * This file will contain two special symbols: filename_start + * and filename_end. All we have to do is traverse the KLD + * list in search of those symbols and we've found the file + * data. As an added bonus, ndiscvt(8) will also generate + * a normal .o file which can be linked statically with + * the kernel. This means that the symbols will actual reside + * in the kernel's symbol table, but that doesn't matter to + * us since the kernel appears to us as just another module. + */ + + nc.afilename = afilename; + nc.fh = fh; + if (linker_file_foreach(NdisCheckModule, &nc)) { + *filelength = fh->nf_maplen; + *filehandle = fh; + *status = NDIS_STATUS_SUCCESS; + return; + } + + if (TAILQ_EMPTY(&mountlist)) { + ExFreePool(fh); + *status = NDIS_STATUS_FILE_NOT_FOUND; + printf("NDIS: could not find file %s in linker list\n", + afilename); + printf("NDIS: and no filesystems mounted yet, " + "aborting NdisOpenFile()\n"); + free(afilename, M_DEVBUF); + return; + } + + path = ExAllocatePoolWithTag(NonPagedPool, MAXPATHLEN, 0); + if (path == NULL) { + ExFreePool(fh); + free(afilename, M_DEVBUF); + *status = NDIS_STATUS_RESOURCES; + return; + } + + snprintf(path, MAXPATHLEN, "%s/%s", ndis_filepath, afilename); + + /* Some threads don't have a current working directory. */ + + if (td->td_proc->p_fd->fd_rdir == NULL) + td->td_proc->p_fd->fd_rdir = rootvnode; + if (td->td_proc->p_fd->fd_cdir == NULL) + td->td_proc->p_fd->fd_cdir = rootvnode; + + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, td); + + flags = FREAD; + error = vn_open(&nd, &flags, 0, NULL); + if (error) { + *status = NDIS_STATUS_FILE_NOT_FOUND; + ExFreePool(fh); + printf("NDIS: open file %s failed: %d\n", path, error); + ExFreePool(path); + free(afilename, M_DEVBUF); + return; + } + + ExFreePool(path); + + NDFREE(&nd, NDF_ONLY_PNBUF); + + /* Get the file size. */ + VOP_GETATTR(nd.ni_vp, vap, td->td_ucred); + VOP_UNLOCK(nd.ni_vp, 0); + + fh->nf_vp = nd.ni_vp; + fh->nf_map = NULL; + fh->nf_type = NDIS_FH_TYPE_VFS; + *filehandle = fh; + *filelength = fh->nf_maplen = vap->va_size & 0xFFFFFFFF; + *status = NDIS_STATUS_SUCCESS; +} + +static void +NdisMapFile(status, mappedbuffer, filehandle) + ndis_status *status; + void **mappedbuffer; + ndis_handle filehandle; +{ + ndis_fh *fh; + struct thread *td = curthread; + linker_file_t lf; + caddr_t kldstart; + int error; + ssize_t resid; + struct vnode *vp; + + if (filehandle == NULL) { + *status = NDIS_STATUS_FAILURE; + return; + } + + fh = (ndis_fh *)filehandle; + + if (fh->nf_vp == NULL) { + *status = NDIS_STATUS_FAILURE; + return; + } + + if (fh->nf_map != NULL) { + *status = NDIS_STATUS_ALREADY_MAPPED; + return; + } + + if (fh->nf_type == NDIS_FH_TYPE_MODULE) { + lf = fh->nf_vp; + if (ndis_find_sym(lf, fh->nf_name, "_start", &kldstart)) { + *status = NDIS_STATUS_FAILURE; + return; + } + fh->nf_map = kldstart; + *status = NDIS_STATUS_SUCCESS; + *mappedbuffer = fh->nf_map; + return; + } + + fh->nf_map = ExAllocatePoolWithTag(NonPagedPool, fh->nf_maplen, 0); + + if (fh->nf_map == NULL) { + *status = NDIS_STATUS_RESOURCES; + return; + } + + vp = fh->nf_vp; + error = vn_rdwr(UIO_READ, vp, fh->nf_map, fh->nf_maplen, 0, + UIO_SYSSPACE, 0, td->td_ucred, NOCRED, &resid, td); + + if (error) + *status = NDIS_STATUS_FAILURE; + else { + *status = NDIS_STATUS_SUCCESS; + *mappedbuffer = fh->nf_map; + } +} + +static void +NdisUnmapFile(filehandle) + ndis_handle filehandle; +{ + ndis_fh *fh; + fh = (ndis_fh *)filehandle; + + if (fh->nf_map == NULL) + return; + + if (fh->nf_type == NDIS_FH_TYPE_VFS) + ExFreePool(fh->nf_map); + fh->nf_map = NULL; +} + +static void +NdisCloseFile(filehandle) + ndis_handle filehandle; +{ + struct thread *td = curthread; + ndis_fh *fh; + struct vnode *vp; + + if (filehandle == NULL) + return; + + fh = (ndis_fh *)filehandle; + if (fh->nf_map != NULL) { + if (fh->nf_type == NDIS_FH_TYPE_VFS) + ExFreePool(fh->nf_map); + fh->nf_map = NULL; + } + + if (fh->nf_vp == NULL) + return; + + if (fh->nf_type == NDIS_FH_TYPE_VFS) { + vp = fh->nf_vp; + vn_close(vp, FREAD, td->td_ucred, td); + } + + fh->nf_vp = NULL; + free(fh->nf_name, M_DEVBUF); + ExFreePool(fh); +} + +static uint8_t +NdisSystemProcessorCount() +{ + return (mp_ncpus); +} + +static void +NdisGetCurrentProcessorCounts(idle_count, kernel_and_user, index) + uint32_t *idle_count; + uint32_t *kernel_and_user; + uint32_t *index; +{ + struct pcpu *pcpu; + + pcpu = pcpu_find(curthread->td_oncpu); + *index = pcpu->pc_cpuid; + *idle_count = pcpu->pc_cp_time[CP_IDLE]; + *kernel_and_user = pcpu->pc_cp_time[CP_INTR]; +} + +typedef void (*ndis_statusdone_handler)(ndis_handle); +typedef void (*ndis_status_handler)(ndis_handle, ndis_status, + void *, uint32_t); + +static void +NdisMIndicateStatusComplete(adapter) + ndis_handle adapter; +{ + ndis_miniport_block *block; + ndis_statusdone_handler statusdonefunc; + + block = (ndis_miniport_block *)adapter; + statusdonefunc = block->nmb_statusdone_func; + + MSCALL1(statusdonefunc, adapter); +} + +static void +NdisMIndicateStatus(adapter, status, sbuf, slen) + ndis_handle adapter; + ndis_status status; + void *sbuf; + uint32_t slen; +{ + ndis_miniport_block *block; + ndis_status_handler statusfunc; + + block = (ndis_miniport_block *)adapter; + statusfunc = block->nmb_status_func; + + MSCALL4(statusfunc, adapter, status, sbuf, slen); +} + +/* + * The DDK documentation says that you should use IoQueueWorkItem() + * instead of ExQueueWorkItem(). The problem is, IoQueueWorkItem() + * is fundamentally incompatible with NdisScheduleWorkItem(), which + * depends on the API semantics of ExQueueWorkItem(). In our world, + * ExQueueWorkItem() is implemented on top of IoAllocateQueueItem() + * anyway. + * + * There are actually three distinct APIs here. NdisScheduleWorkItem() + * takes a pointer to an NDIS_WORK_ITEM. ExQueueWorkItem() takes a pointer + * to a WORK_QUEUE_ITEM. And finally, IoQueueWorkItem() takes a pointer + * to an opaque work item thingie which you get from IoAllocateWorkItem(). + * An NDIS_WORK_ITEM is not the same as a WORK_QUEUE_ITEM. However, + * the NDIS_WORK_ITEM has some opaque storage at the end of it, and we + * (ab)use this storage as a WORK_QUEUE_ITEM, which is what we submit + * to ExQueueWorkItem(). + * + * Got all that? (Sheesh.) + */ + +ndis_status +NdisScheduleWorkItem(work) + ndis_work_item *work; +{ + work_queue_item *wqi; + + wqi = (work_queue_item *)work->nwi_wraprsvd; + ExInitializeWorkItem(wqi, + (work_item_func)work->nwi_func, work->nwi_ctx); + ExQueueWorkItem(wqi, WORKQUEUE_DELAYED); + + return (NDIS_STATUS_SUCCESS); +} + +static void +NdisCopyFromPacketToPacket(dpkt, doff, reqlen, spkt, soff, cpylen) + ndis_packet *dpkt; + uint32_t doff; + uint32_t reqlen; + ndis_packet *spkt; + uint32_t soff; + uint32_t *cpylen; +{ + ndis_buffer *src, *dst; + char *sptr, *dptr; + int resid, copied, len, scnt, dcnt; + + *cpylen = 0; + + src = spkt->np_private.npp_head; + dst = dpkt->np_private.npp_head; + + sptr = MmGetMdlVirtualAddress(src); + dptr = MmGetMdlVirtualAddress(dst); + scnt = MmGetMdlByteCount(src); + dcnt = MmGetMdlByteCount(dst); + + while (soff) { + if (MmGetMdlByteCount(src) > soff) { + sptr += soff; + scnt = MmGetMdlByteCount(src)- soff; + break; + } + soff -= MmGetMdlByteCount(src); + src = src->mdl_next; + if (src == NULL) + return; + sptr = MmGetMdlVirtualAddress(src); + } + + while (doff) { + if (MmGetMdlByteCount(dst) > doff) { + dptr += doff; + dcnt = MmGetMdlByteCount(dst) - doff; + break; + } + doff -= MmGetMdlByteCount(dst); + dst = dst->mdl_next; + if (dst == NULL) + return; + dptr = MmGetMdlVirtualAddress(dst); + } + + resid = reqlen; + copied = 0; + + while(1) { + if (resid < scnt) + len = resid; + else + len = scnt; + if (dcnt < len) + len = dcnt; + + bcopy(sptr, dptr, len); + + copied += len; + resid -= len; + if (resid == 0) + break; + + dcnt -= len; + if (dcnt == 0) { + dst = dst->mdl_next; + if (dst == NULL) + break; + dptr = MmGetMdlVirtualAddress(dst); + dcnt = MmGetMdlByteCount(dst); + } + + scnt -= len; + if (scnt == 0) { + src = src->mdl_next; + if (src == NULL) + break; + sptr = MmGetMdlVirtualAddress(src); + scnt = MmGetMdlByteCount(src); + } + } + + *cpylen = copied; +} + +static void +NdisCopyFromPacketToPacketSafe(dpkt, doff, reqlen, spkt, soff, cpylen, prio) + ndis_packet *dpkt; + uint32_t doff; + uint32_t reqlen; + ndis_packet *spkt; + uint32_t soff; + uint32_t *cpylen; + uint32_t prio; +{ + NdisCopyFromPacketToPacket(dpkt, doff, reqlen, spkt, soff, cpylen); +} + +static void +NdisIMCopySendPerPacketInfo(dpkt, spkt) + ndis_packet *dpkt; + ndis_packet *spkt; +{ + memcpy(&dpkt->np_ext, &spkt->np_ext, sizeof(ndis_packet_extension)); +} + +static ndis_status +NdisMRegisterDevice(handle, devname, symname, majorfuncs, devobj, devhandle) + ndis_handle handle; + unicode_string *devname; + unicode_string *symname; + driver_dispatch *majorfuncs[]; + void **devobj; + ndis_handle *devhandle; +{ + uint32_t status; + device_object *dobj; + + status = IoCreateDevice(handle, 0, devname, + FILE_DEVICE_UNKNOWN, 0, FALSE, &dobj); + + if (status == STATUS_SUCCESS) { + *devobj = dobj; + *devhandle = dobj; + } + + return (status); +} + +static ndis_status +NdisMDeregisterDevice(handle) + ndis_handle handle; +{ + IoDeleteDevice(handle); + return (NDIS_STATUS_SUCCESS); +} + +static ndis_status +NdisMQueryAdapterInstanceName(name, handle) + unicode_string *name; + ndis_handle handle; +{ + ndis_miniport_block *block; + device_t dev; + ansi_string as; + + block = (ndis_miniport_block *)handle; + dev = block->nmb_physdeviceobj->do_devext; + + RtlInitAnsiString(&as, __DECONST(char *, device_get_nameunit(dev))); + if (RtlAnsiStringToUnicodeString(name, &as, TRUE)) + return (NDIS_STATUS_RESOURCES); + + return (NDIS_STATUS_SUCCESS); +} + +static void +NdisMRegisterUnloadHandler(handle, func) + ndis_handle handle; + void *func; +{ +} + +static void +dummy() +{ + printf("NDIS dummy called...\n"); +} + +/* + * Note: a couple of entries in this table specify the + * number of arguments as "foo + 1". These are routines + * that accept a 64-bit argument, passed by value. On + * x86, these arguments consume two longwords on the stack, + * so we lie and say there's one additional argument so + * that the wrapping routines will do the right thing. + */ + +image_patch_table ndis_functbl[] = { + IMPORT_SFUNC(NdisCopyFromPacketToPacket, 6), + IMPORT_SFUNC(NdisCopyFromPacketToPacketSafe, 7), + IMPORT_SFUNC(NdisIMCopySendPerPacketInfo, 2), + IMPORT_SFUNC(NdisScheduleWorkItem, 1), + IMPORT_SFUNC(NdisMIndicateStatusComplete, 1), + IMPORT_SFUNC(NdisMIndicateStatus, 4), + IMPORT_SFUNC(NdisSystemProcessorCount, 0), + IMPORT_SFUNC(NdisGetCurrentProcessorCounts, 3), + IMPORT_SFUNC(NdisUnchainBufferAtBack, 2), + IMPORT_SFUNC(NdisGetFirstBufferFromPacket, 5), + IMPORT_SFUNC(NdisGetFirstBufferFromPacketSafe, 6), + IMPORT_SFUNC(NdisGetBufferPhysicalArraySize, 2), + IMPORT_SFUNC(NdisMGetDeviceProperty, 6), + IMPORT_SFUNC(NdisInitAnsiString, 2), + IMPORT_SFUNC(NdisInitUnicodeString, 2), + IMPORT_SFUNC(NdisWriteConfiguration, 4), + IMPORT_SFUNC(NdisAnsiStringToUnicodeString, 2), + IMPORT_SFUNC(NdisTerminateWrapper, 2), + IMPORT_SFUNC(NdisOpenConfigurationKeyByName, 4), + IMPORT_SFUNC(NdisOpenConfigurationKeyByIndex, 5), + IMPORT_SFUNC(NdisMRemoveMiniport, 1), + IMPORT_SFUNC(NdisInitializeString, 2), + IMPORT_SFUNC(NdisFreeString, 1), + IMPORT_SFUNC(NdisGetCurrentSystemTime, 1), + IMPORT_SFUNC(NdisGetRoutineAddress, 1), + IMPORT_SFUNC(NdisGetSystemUpTime, 1), + IMPORT_SFUNC(NdisGetVersion, 0), + IMPORT_SFUNC(NdisMSynchronizeWithInterrupt, 3), + IMPORT_SFUNC(NdisMAllocateSharedMemoryAsync, 4), + IMPORT_SFUNC(NdisInterlockedInsertHeadList, 3), + IMPORT_SFUNC(NdisInterlockedInsertTailList, 3), + IMPORT_SFUNC(NdisInterlockedRemoveHeadList, 2), + IMPORT_SFUNC(NdisInitializeWrapper, 4), + IMPORT_SFUNC(NdisMRegisterMiniport, 3), + IMPORT_SFUNC(NdisAllocateMemoryWithTag, 3), + IMPORT_SFUNC(NdisAllocateMemory, 4 + 1), + IMPORT_SFUNC(NdisMSetAttributesEx, 5), + IMPORT_SFUNC(NdisCloseConfiguration, 1), + IMPORT_SFUNC(NdisReadConfiguration, 5), + IMPORT_SFUNC(NdisOpenConfiguration, 3), + IMPORT_SFUNC(NdisAcquireSpinLock, 1), + IMPORT_SFUNC(NdisReleaseSpinLock, 1), + IMPORT_SFUNC(NdisDprAcquireSpinLock, 1), + IMPORT_SFUNC(NdisDprReleaseSpinLock, 1), + IMPORT_SFUNC(NdisAllocateSpinLock, 1), + IMPORT_SFUNC(NdisInitializeReadWriteLock, 1), + IMPORT_SFUNC(NdisAcquireReadWriteLock, 3), + IMPORT_SFUNC(NdisReleaseReadWriteLock, 2), + IMPORT_SFUNC(NdisFreeSpinLock, 1), + IMPORT_SFUNC(NdisFreeMemory, 3), + IMPORT_SFUNC(NdisReadPciSlotInformation, 5), + IMPORT_SFUNC(NdisWritePciSlotInformation, 5), + IMPORT_SFUNC_MAP(NdisImmediateReadPciSlotInformation, + NdisReadPciSlotInformation, 5), + IMPORT_SFUNC_MAP(NdisImmediateWritePciSlotInformation, + NdisWritePciSlotInformation, 5), + IMPORT_CFUNC(NdisWriteErrorLogEntry, 0), + IMPORT_SFUNC(NdisMStartBufferPhysicalMapping, 6), + IMPORT_SFUNC(NdisMCompleteBufferPhysicalMapping, 3), + IMPORT_SFUNC(NdisMInitializeTimer, 4), + IMPORT_SFUNC(NdisInitializeTimer, 3), + IMPORT_SFUNC(NdisSetTimer, 2), + IMPORT_SFUNC(NdisMCancelTimer, 2), + IMPORT_SFUNC_MAP(NdisCancelTimer, NdisMCancelTimer, 2), + IMPORT_SFUNC(NdisMSetPeriodicTimer, 2), + IMPORT_SFUNC(NdisMQueryAdapterResources, 4), + IMPORT_SFUNC(NdisMRegisterIoPortRange, 4), + IMPORT_SFUNC(NdisMDeregisterIoPortRange, 4), + IMPORT_SFUNC(NdisReadNetworkAddress, 4), + IMPORT_SFUNC(NdisQueryMapRegisterCount, 2), + IMPORT_SFUNC(NdisMAllocateMapRegisters, 5), + IMPORT_SFUNC(NdisMFreeMapRegisters, 1), + IMPORT_SFUNC(NdisMAllocateSharedMemory, 5), + IMPORT_SFUNC(NdisMMapIoSpace, 4 + 1), + IMPORT_SFUNC(NdisMUnmapIoSpace, 3), + IMPORT_SFUNC(NdisGetCacheFillSize, 0), + IMPORT_SFUNC(NdisMGetDmaAlignment, 1), + IMPORT_SFUNC(NdisMInitializeScatterGatherDma, 3), + IMPORT_SFUNC(NdisAllocatePacketPool, 4), + IMPORT_SFUNC(NdisAllocatePacketPoolEx, 5), + IMPORT_SFUNC(NdisAllocatePacket, 3), + IMPORT_SFUNC(NdisFreePacket, 1), + IMPORT_SFUNC(NdisFreePacketPool, 1), + IMPORT_SFUNC_MAP(NdisDprAllocatePacket, NdisAllocatePacket, 3), + IMPORT_SFUNC_MAP(NdisDprFreePacket, NdisFreePacket, 1), + IMPORT_SFUNC(NdisAllocateBufferPool, 3), + IMPORT_SFUNC(NdisAllocateBuffer, 5), + IMPORT_SFUNC(NdisQueryBuffer, 3), + IMPORT_SFUNC(NdisQueryBufferSafe, 4), + IMPORT_SFUNC(NdisBufferVirtualAddress, 1), + IMPORT_SFUNC(NdisBufferVirtualAddressSafe, 2), + IMPORT_SFUNC(NdisBufferLength, 1), + IMPORT_SFUNC(NdisFreeBuffer, 1), + IMPORT_SFUNC(NdisFreeBufferPool, 1), + IMPORT_SFUNC(NdisInterlockedIncrement, 1), + IMPORT_SFUNC(NdisInterlockedDecrement, 1), + IMPORT_SFUNC(NdisInitializeEvent, 1), + IMPORT_SFUNC(NdisSetEvent, 1), + IMPORT_SFUNC(NdisResetEvent, 1), + IMPORT_SFUNC(NdisWaitEvent, 2), + IMPORT_SFUNC(NdisUnicodeStringToAnsiString, 2), + IMPORT_SFUNC(NdisMPciAssignResources, 3), + IMPORT_SFUNC(NdisMFreeSharedMemory, 5 + 1), + IMPORT_SFUNC(NdisMRegisterInterrupt, 7), + IMPORT_SFUNC(NdisMDeregisterInterrupt, 1), + IMPORT_SFUNC(NdisMRegisterAdapterShutdownHandler, 3), + IMPORT_SFUNC(NdisMDeregisterAdapterShutdownHandler, 1), + IMPORT_SFUNC(NDIS_BUFFER_TO_SPAN_PAGES, 1), + IMPORT_SFUNC(NdisQueryBufferOffset, 3), + IMPORT_SFUNC(NdisAdjustBufferLength, 2), + IMPORT_SFUNC(NdisPacketPoolUsage, 1), + IMPORT_SFUNC(NdisMSleep, 1), + IMPORT_SFUNC(NdisUnchainBufferAtFront, 2), + IMPORT_SFUNC(NdisReadPcmciaAttributeMemory, 4), + IMPORT_SFUNC(NdisWritePcmciaAttributeMemory, 4), + IMPORT_SFUNC(NdisOpenFile, 5 + 1), + IMPORT_SFUNC(NdisMapFile, 3), + IMPORT_SFUNC(NdisUnmapFile, 1), + IMPORT_SFUNC(NdisCloseFile, 1), + IMPORT_SFUNC(NdisMRegisterDevice, 6), + IMPORT_SFUNC(NdisMDeregisterDevice, 1), + IMPORT_SFUNC(NdisMQueryAdapterInstanceName, 2), + IMPORT_SFUNC(NdisMRegisterUnloadHandler, 2), + IMPORT_SFUNC(ndis_timercall, 4), + IMPORT_SFUNC(ndis_asyncmem_complete, 2), + IMPORT_SFUNC(ndis_intr, 2), + IMPORT_SFUNC(ndis_intrhand, 4), + + /* + * This last entry is a catch-all for any function we haven't + * implemented yet. The PE import list patching routine will + * use it for any function that doesn't have an explicit match + * in this table. + */ + + { NULL, (FUNC)dummy, NULL, 0, WINDRV_WRAP_STDCALL }, + + /* End of list. */ + + { NULL, NULL, NULL } +}; diff --git a/sys/compat/ndis/subr_ntoskrnl.c b/sys/compat/ndis/subr_ntoskrnl.c new file mode 100644 index 0000000..02e8e45 --- /dev/null +++ b/sys/compat/ndis/subr_ntoskrnl.c @@ -0,0 +1,4457 @@ +/*- + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.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, 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 Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD + * 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/ctype.h> +#include <sys/unistd.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/errno.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/lock.h> +#include <sys/mutex.h> + +#include <sys/callout.h> +#include <sys/kdb.h> +#include <sys/kernel.h> +#include <sys/proc.h> +#include <sys/condvar.h> +#include <sys/kthread.h> +#include <sys/module.h> +#include <sys/smp.h> +#include <sys/sched.h> +#include <sys/sysctl.h> + +#include <machine/atomic.h> +#include <machine/bus.h> +#include <machine/stdarg.h> +#include <machine/resource.h> + +#include <sys/bus.h> +#include <sys/rman.h> + +#include <vm/vm.h> +#include <vm/vm_param.h> +#include <vm/pmap.h> +#include <vm/uma.h> +#include <vm/vm_kern.h> +#include <vm/vm_map.h> +#include <vm/vm_extern.h> + +#include <compat/ndis/pe_var.h> +#include <compat/ndis/cfg_var.h> +#include <compat/ndis/resource_var.h> +#include <compat/ndis/ntoskrnl_var.h> +#include <compat/ndis/hal_var.h> +#include <compat/ndis/ndis_var.h> + +#ifdef NTOSKRNL_DEBUG_TIMERS +static int sysctl_show_timers(SYSCTL_HANDLER_ARGS); + +SYSCTL_PROC(_debug, OID_AUTO, ntoskrnl_timers, CTLTYPE_INT | CTLFLAG_RW, + NULL, 0, sysctl_show_timers, "I", + "Show ntoskrnl timer stats"); +#endif + +struct kdpc_queue { + list_entry kq_disp; + struct thread *kq_td; + int kq_cpu; + int kq_exit; + int kq_running; + kspin_lock kq_lock; + nt_kevent kq_proc; + nt_kevent kq_done; +}; + +typedef struct kdpc_queue kdpc_queue; + +struct wb_ext { + struct cv we_cv; + struct thread *we_td; +}; + +typedef struct wb_ext wb_ext; + +#define NTOSKRNL_TIMEOUTS 256 +#ifdef NTOSKRNL_DEBUG_TIMERS +static uint64_t ntoskrnl_timer_fires; +static uint64_t ntoskrnl_timer_sets; +static uint64_t ntoskrnl_timer_reloads; +static uint64_t ntoskrnl_timer_cancels; +#endif + +struct callout_entry { + struct callout ce_callout; + list_entry ce_list; +}; + +typedef struct callout_entry callout_entry; + +static struct list_entry ntoskrnl_calllist; +static struct mtx ntoskrnl_calllock; +struct kuser_shared_data kuser_shared_data; + +static struct list_entry ntoskrnl_intlist; +static kspin_lock ntoskrnl_intlock; + +static uint8_t RtlEqualUnicodeString(unicode_string *, + unicode_string *, uint8_t); +static void RtlCopyString(ansi_string *, const ansi_string *); +static void RtlCopyUnicodeString(unicode_string *, + unicode_string *); +static irp *IoBuildSynchronousFsdRequest(uint32_t, device_object *, + void *, uint32_t, uint64_t *, nt_kevent *, io_status_block *); +static irp *IoBuildAsynchronousFsdRequest(uint32_t, + device_object *, void *, uint32_t, uint64_t *, io_status_block *); +static irp *IoBuildDeviceIoControlRequest(uint32_t, + device_object *, void *, uint32_t, void *, uint32_t, + uint8_t, nt_kevent *, io_status_block *); +static irp *IoAllocateIrp(uint8_t, uint8_t); +static void IoReuseIrp(irp *, uint32_t); +static void IoFreeIrp(irp *); +static void IoInitializeIrp(irp *, uint16_t, uint8_t); +static irp *IoMakeAssociatedIrp(irp *, uint8_t); +static uint32_t KeWaitForMultipleObjects(uint32_t, + nt_dispatch_header **, uint32_t, uint32_t, uint32_t, uint8_t, + int64_t *, wait_block *); +static void ntoskrnl_waittest(nt_dispatch_header *, uint32_t); +static void ntoskrnl_satisfy_wait(nt_dispatch_header *, struct thread *); +static void ntoskrnl_satisfy_multiple_waits(wait_block *); +static int ntoskrnl_is_signalled(nt_dispatch_header *, struct thread *); +static void ntoskrnl_insert_timer(ktimer *, int); +static void ntoskrnl_remove_timer(ktimer *); +#ifdef NTOSKRNL_DEBUG_TIMERS +static void ntoskrnl_show_timers(void); +#endif +static void ntoskrnl_timercall(void *); +static void ntoskrnl_dpc_thread(void *); +static void ntoskrnl_destroy_dpc_threads(void); +static void ntoskrnl_destroy_workitem_threads(void); +static void ntoskrnl_workitem_thread(void *); +static void ntoskrnl_workitem(device_object *, void *); +static void ntoskrnl_unicode_to_ascii(uint16_t *, char *, int); +static void ntoskrnl_ascii_to_unicode(char *, uint16_t *, int); +static uint8_t ntoskrnl_insert_dpc(list_entry *, kdpc *); +static void WRITE_REGISTER_USHORT(uint16_t *, uint16_t); +static uint16_t READ_REGISTER_USHORT(uint16_t *); +static void WRITE_REGISTER_ULONG(uint32_t *, uint32_t); +static uint32_t READ_REGISTER_ULONG(uint32_t *); +static void WRITE_REGISTER_UCHAR(uint8_t *, uint8_t); +static uint8_t READ_REGISTER_UCHAR(uint8_t *); +static int64_t _allmul(int64_t, int64_t); +static int64_t _alldiv(int64_t, int64_t); +static int64_t _allrem(int64_t, int64_t); +static int64_t _allshr(int64_t, uint8_t); +static int64_t _allshl(int64_t, uint8_t); +static uint64_t _aullmul(uint64_t, uint64_t); +static uint64_t _aulldiv(uint64_t, uint64_t); +static uint64_t _aullrem(uint64_t, uint64_t); +static uint64_t _aullshr(uint64_t, uint8_t); +static uint64_t _aullshl(uint64_t, uint8_t); +static slist_entry *ntoskrnl_pushsl(slist_header *, slist_entry *); +static void InitializeSListHead(slist_header *); +static slist_entry *ntoskrnl_popsl(slist_header *); +static void ExFreePoolWithTag(void *, uint32_t); +static void ExInitializePagedLookasideList(paged_lookaside_list *, + lookaside_alloc_func *, lookaside_free_func *, + uint32_t, size_t, uint32_t, uint16_t); +static void ExDeletePagedLookasideList(paged_lookaside_list *); +static void ExInitializeNPagedLookasideList(npaged_lookaside_list *, + lookaside_alloc_func *, lookaside_free_func *, + uint32_t, size_t, uint32_t, uint16_t); +static void ExDeleteNPagedLookasideList(npaged_lookaside_list *); +static slist_entry + *ExInterlockedPushEntrySList(slist_header *, + slist_entry *, kspin_lock *); +static slist_entry + *ExInterlockedPopEntrySList(slist_header *, kspin_lock *); +static uint32_t InterlockedIncrement(volatile uint32_t *); +static uint32_t InterlockedDecrement(volatile uint32_t *); +static void ExInterlockedAddLargeStatistic(uint64_t *, uint32_t); +static void *MmAllocateContiguousMemory(uint32_t, uint64_t); +static void *MmAllocateContiguousMemorySpecifyCache(uint32_t, + uint64_t, uint64_t, uint64_t, enum nt_caching_type); +static void MmFreeContiguousMemory(void *); +static void MmFreeContiguousMemorySpecifyCache(void *, uint32_t, + enum nt_caching_type); +static uint32_t MmSizeOfMdl(void *, size_t); +static void *MmMapLockedPages(mdl *, uint8_t); +static void *MmMapLockedPagesSpecifyCache(mdl *, + uint8_t, uint32_t, void *, uint32_t, uint32_t); +static void MmUnmapLockedPages(void *, mdl *); +static device_t ntoskrnl_finddev(device_t, uint64_t, struct resource **); +static void RtlZeroMemory(void *, size_t); +static void RtlSecureZeroMemory(void *, size_t); +static void RtlFillMemory(void *, size_t, uint8_t); +static void RtlMoveMemory(void *, const void *, size_t); +static ndis_status RtlCharToInteger(const char *, uint32_t, uint32_t *); +static void RtlCopyMemory(void *, const void *, size_t); +static size_t RtlCompareMemory(const void *, const void *, size_t); +static ndis_status RtlUnicodeStringToInteger(unicode_string *, + uint32_t, uint32_t *); +static int atoi (const char *); +static long atol (const char *); +static int rand(void); +static void srand(unsigned int); +static void KeQuerySystemTime(uint64_t *); +static uint32_t KeTickCount(void); +static uint8_t IoIsWdmVersionAvailable(uint8_t, uint8_t); +static int32_t IoOpenDeviceRegistryKey(struct device_object *, uint32_t, + uint32_t, void **); +static void ntoskrnl_thrfunc(void *); +static ndis_status PsCreateSystemThread(ndis_handle *, + uint32_t, void *, ndis_handle, void *, void *, void *); +static ndis_status PsTerminateSystemThread(ndis_status); +static ndis_status IoGetDeviceObjectPointer(unicode_string *, + uint32_t, void *, device_object *); +static ndis_status IoGetDeviceProperty(device_object *, uint32_t, + uint32_t, void *, uint32_t *); +static void KeInitializeMutex(kmutant *, uint32_t); +static uint32_t KeReleaseMutex(kmutant *, uint8_t); +static uint32_t KeReadStateMutex(kmutant *); +static ndis_status ObReferenceObjectByHandle(ndis_handle, + uint32_t, void *, uint8_t, void **, void **); +static void ObfDereferenceObject(void *); +static uint32_t ZwClose(ndis_handle); +static uint32_t WmiQueryTraceInformation(uint32_t, void *, uint32_t, + uint32_t, void *); +static uint32_t WmiTraceMessage(uint64_t, uint32_t, void *, uint16_t, ...); +static uint32_t IoWMIRegistrationControl(device_object *, uint32_t); +static void *ntoskrnl_memset(void *, int, size_t); +static void *ntoskrnl_memmove(void *, void *, size_t); +static void *ntoskrnl_memchr(void *, unsigned char, size_t); +static char *ntoskrnl_strstr(char *, char *); +static char *ntoskrnl_strncat(char *, char *, size_t); +static int ntoskrnl_toupper(int); +static int ntoskrnl_tolower(int); +static funcptr ntoskrnl_findwrap(funcptr); +static uint32_t DbgPrint(char *, ...); +static void DbgBreakPoint(void); +static void KeBugCheckEx(uint32_t, u_long, u_long, u_long, u_long); +static int32_t KeDelayExecutionThread(uint8_t, uint8_t, int64_t *); +static int32_t KeSetPriorityThread(struct thread *, int32_t); +static void dummy(void); + +static struct mtx ntoskrnl_dispatchlock; +static struct mtx ntoskrnl_interlock; +static kspin_lock ntoskrnl_cancellock; +static int ntoskrnl_kth = 0; +static struct nt_objref_head ntoskrnl_reflist; +static uma_zone_t mdl_zone; +static uma_zone_t iw_zone; +static struct kdpc_queue *kq_queues; +static struct kdpc_queue *wq_queues; +static int wq_idx = 0; + +int +ntoskrnl_libinit() +{ + image_patch_table *patch; + int error; + struct proc *p; + kdpc_queue *kq; + callout_entry *e; + int i; + + mtx_init(&ntoskrnl_dispatchlock, + "ntoskrnl dispatch lock", MTX_NDIS_LOCK, MTX_DEF|MTX_RECURSE); + mtx_init(&ntoskrnl_interlock, MTX_NTOSKRNL_SPIN_LOCK, NULL, MTX_SPIN); + KeInitializeSpinLock(&ntoskrnl_cancellock); + KeInitializeSpinLock(&ntoskrnl_intlock); + TAILQ_INIT(&ntoskrnl_reflist); + + InitializeListHead(&ntoskrnl_calllist); + InitializeListHead(&ntoskrnl_intlist); + mtx_init(&ntoskrnl_calllock, MTX_NTOSKRNL_SPIN_LOCK, NULL, MTX_SPIN); + + kq_queues = ExAllocatePoolWithTag(NonPagedPool, +#ifdef NTOSKRNL_MULTIPLE_DPCS + sizeof(kdpc_queue) * mp_ncpus, 0); +#else + sizeof(kdpc_queue), 0); +#endif + + if (kq_queues == NULL) + return (ENOMEM); + + wq_queues = ExAllocatePoolWithTag(NonPagedPool, + sizeof(kdpc_queue) * WORKITEM_THREADS, 0); + + if (wq_queues == NULL) + return (ENOMEM); + +#ifdef NTOSKRNL_MULTIPLE_DPCS + bzero((char *)kq_queues, sizeof(kdpc_queue) * mp_ncpus); +#else + bzero((char *)kq_queues, sizeof(kdpc_queue)); +#endif + bzero((char *)wq_queues, sizeof(kdpc_queue) * WORKITEM_THREADS); + + /* + * Launch the DPC threads. + */ + +#ifdef NTOSKRNL_MULTIPLE_DPCS + for (i = 0; i < mp_ncpus; i++) { +#else + for (i = 0; i < 1; i++) { +#endif + kq = kq_queues + i; + kq->kq_cpu = i; + error = kproc_create(ntoskrnl_dpc_thread, kq, &p, + RFHIGHPID, NDIS_KSTACK_PAGES, "Windows DPC %d", i); + if (error) + panic("failed to launch DPC thread"); + } + + /* + * Launch the workitem threads. + */ + + for (i = 0; i < WORKITEM_THREADS; i++) { + kq = wq_queues + i; + error = kproc_create(ntoskrnl_workitem_thread, kq, &p, + RFHIGHPID, NDIS_KSTACK_PAGES, "Windows Workitem %d", i); + if (error) + panic("failed to launch workitem thread"); + } + + patch = ntoskrnl_functbl; + while (patch->ipt_func != NULL) { + windrv_wrap((funcptr)patch->ipt_func, + (funcptr *)&patch->ipt_wrap, + patch->ipt_argcnt, patch->ipt_ftype); + patch++; + } + + for (i = 0; i < NTOSKRNL_TIMEOUTS; i++) { + e = ExAllocatePoolWithTag(NonPagedPool, + sizeof(callout_entry), 0); + if (e == NULL) + panic("failed to allocate timeouts"); + mtx_lock_spin(&ntoskrnl_calllock); + InsertHeadList((&ntoskrnl_calllist), (&e->ce_list)); + mtx_unlock_spin(&ntoskrnl_calllock); + } + + /* + * MDLs are supposed to be variable size (they describe + * buffers containing some number of pages, but we don't + * know ahead of time how many pages that will be). But + * always allocating them off the heap is very slow. As + * a compromise, we create an MDL UMA zone big enough to + * handle any buffer requiring up to 16 pages, and we + * use those for any MDLs for buffers of 16 pages or less + * in size. For buffers larger than that (which we assume + * will be few and far between, we allocate the MDLs off + * the heap. + */ + + mdl_zone = uma_zcreate("Windows MDL", MDL_ZONE_SIZE, + NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); + + iw_zone = uma_zcreate("Windows WorkItem", sizeof(io_workitem), + NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); + + return (0); +} + +int +ntoskrnl_libfini() +{ + image_patch_table *patch; + callout_entry *e; + list_entry *l; + + patch = ntoskrnl_functbl; + while (patch->ipt_func != NULL) { + windrv_unwrap(patch->ipt_wrap); + patch++; + } + + /* Stop the workitem queues. */ + ntoskrnl_destroy_workitem_threads(); + /* Stop the DPC queues. */ + ntoskrnl_destroy_dpc_threads(); + + ExFreePool(kq_queues); + ExFreePool(wq_queues); + + uma_zdestroy(mdl_zone); + uma_zdestroy(iw_zone); + + mtx_lock_spin(&ntoskrnl_calllock); + while(!IsListEmpty(&ntoskrnl_calllist)) { + l = RemoveHeadList(&ntoskrnl_calllist); + e = CONTAINING_RECORD(l, callout_entry, ce_list); + mtx_unlock_spin(&ntoskrnl_calllock); + ExFreePool(e); + mtx_lock_spin(&ntoskrnl_calllock); + } + mtx_unlock_spin(&ntoskrnl_calllock); + + mtx_destroy(&ntoskrnl_dispatchlock); + mtx_destroy(&ntoskrnl_interlock); + mtx_destroy(&ntoskrnl_calllock); + + return (0); +} + +/* + * We need to be able to reference this externally from the wrapper; + * GCC only generates a local implementation of memset. + */ +static void * +ntoskrnl_memset(buf, ch, size) + void *buf; + int ch; + size_t size; +{ + return (memset(buf, ch, size)); +} + +static void * +ntoskrnl_memmove(dst, src, size) + void *src; + void *dst; + size_t size; +{ + bcopy(src, dst, size); + return (dst); +} + +static void * +ntoskrnl_memchr(void *buf, unsigned char ch, size_t len) +{ + if (len != 0) { + unsigned char *p = buf; + + do { + if (*p++ == ch) + return (p - 1); + } while (--len != 0); + } + return (NULL); +} + +static char * +ntoskrnl_strstr(s, find) + char *s, *find; +{ + char c, sc; + size_t len; + + if ((c = *find++) != 0) { + len = strlen(find); + do { + do { + if ((sc = *s++) == 0) + return (NULL); + } while (sc != c); + } while (strncmp(s, find, len) != 0); + s--; + } + return ((char *)s); +} + +/* Taken from libc */ +static char * +ntoskrnl_strncat(dst, src, n) + char *dst; + char *src; + size_t n; +{ + if (n != 0) { + char *d = dst; + const char *s = src; + + while (*d != 0) + d++; + do { + if ((*d = *s++) == 0) + break; + d++; + } while (--n != 0); + *d = 0; + } + return (dst); +} + +static int +ntoskrnl_toupper(c) + int c; +{ + return (toupper(c)); +} + +static int +ntoskrnl_tolower(c) + int c; +{ + return (tolower(c)); +} + +static uint8_t +RtlEqualUnicodeString(unicode_string *str1, unicode_string *str2, + uint8_t caseinsensitive) +{ + int i; + + if (str1->us_len != str2->us_len) + return (FALSE); + + for (i = 0; i < str1->us_len; i++) { + if (caseinsensitive == TRUE) { + if (toupper((char)(str1->us_buf[i] & 0xFF)) != + toupper((char)(str2->us_buf[i] & 0xFF))) + return (FALSE); + } else { + if (str1->us_buf[i] != str2->us_buf[i]) + return (FALSE); + } + } + + return (TRUE); +} + +static void +RtlCopyString(dst, src) + ansi_string *dst; + const ansi_string *src; +{ + if (src != NULL && src->as_buf != NULL && dst->as_buf != NULL) { + dst->as_len = min(src->as_len, dst->as_maxlen); + memcpy(dst->as_buf, src->as_buf, dst->as_len); + if (dst->as_len < dst->as_maxlen) + dst->as_buf[dst->as_len] = 0; + } else + dst->as_len = 0; +} + +static void +RtlCopyUnicodeString(dest, src) + unicode_string *dest; + unicode_string *src; +{ + + if (dest->us_maxlen >= src->us_len) + dest->us_len = src->us_len; + else + dest->us_len = dest->us_maxlen; + memcpy(dest->us_buf, src->us_buf, dest->us_len); +} + +static void +ntoskrnl_ascii_to_unicode(ascii, unicode, len) + char *ascii; + uint16_t *unicode; + int len; +{ + int i; + uint16_t *ustr; + + ustr = unicode; + for (i = 0; i < len; i++) { + *ustr = (uint16_t)ascii[i]; + ustr++; + } +} + +static void +ntoskrnl_unicode_to_ascii(unicode, ascii, len) + uint16_t *unicode; + char *ascii; + int len; +{ + int i; + uint8_t *astr; + + astr = ascii; + for (i = 0; i < len / 2; i++) { + *astr = (uint8_t)unicode[i]; + astr++; + } +} + +uint32_t +RtlUnicodeStringToAnsiString(ansi_string *dest, unicode_string *src, uint8_t allocate) +{ + if (dest == NULL || src == NULL) + return (STATUS_INVALID_PARAMETER); + + dest->as_len = src->us_len / 2; + if (dest->as_maxlen < dest->as_len) + dest->as_len = dest->as_maxlen; + + if (allocate == TRUE) { + dest->as_buf = ExAllocatePoolWithTag(NonPagedPool, + (src->us_len / 2) + 1, 0); + if (dest->as_buf == NULL) + return (STATUS_INSUFFICIENT_RESOURCES); + dest->as_len = dest->as_maxlen = src->us_len / 2; + } else { + dest->as_len = src->us_len / 2; /* XXX */ + if (dest->as_maxlen < dest->as_len) + dest->as_len = dest->as_maxlen; + } + + ntoskrnl_unicode_to_ascii(src->us_buf, dest->as_buf, + dest->as_len * 2); + + return (STATUS_SUCCESS); +} + +uint32_t +RtlAnsiStringToUnicodeString(unicode_string *dest, ansi_string *src, + uint8_t allocate) +{ + if (dest == NULL || src == NULL) + return (STATUS_INVALID_PARAMETER); + + if (allocate == TRUE) { + dest->us_buf = ExAllocatePoolWithTag(NonPagedPool, + src->as_len * 2, 0); + if (dest->us_buf == NULL) + return (STATUS_INSUFFICIENT_RESOURCES); + dest->us_len = dest->us_maxlen = strlen(src->as_buf) * 2; + } else { + dest->us_len = src->as_len * 2; /* XXX */ + if (dest->us_maxlen < dest->us_len) + dest->us_len = dest->us_maxlen; + } + + ntoskrnl_ascii_to_unicode(src->as_buf, dest->us_buf, + dest->us_len / 2); + + return (STATUS_SUCCESS); +} + +void * +ExAllocatePoolWithTag(pooltype, len, tag) + uint32_t pooltype; + size_t len; + uint32_t tag; +{ + void *buf; + + buf = malloc(len, M_DEVBUF, M_NOWAIT|M_ZERO); + if (buf == NULL) + return (NULL); + + return (buf); +} + +static void +ExFreePoolWithTag(buf, tag) + void *buf; + uint32_t tag; +{ + ExFreePool(buf); +} + +void +ExFreePool(buf) + void *buf; +{ + free(buf, M_DEVBUF); +} + +uint32_t +IoAllocateDriverObjectExtension(drv, clid, extlen, ext) + driver_object *drv; + void *clid; + uint32_t extlen; + void **ext; +{ + custom_extension *ce; + + ce = ExAllocatePoolWithTag(NonPagedPool, sizeof(custom_extension) + + extlen, 0); + + if (ce == NULL) + return (STATUS_INSUFFICIENT_RESOURCES); + + ce->ce_clid = clid; + InsertTailList((&drv->dro_driverext->dre_usrext), (&ce->ce_list)); + + *ext = (void *)(ce + 1); + + return (STATUS_SUCCESS); +} + +void * +IoGetDriverObjectExtension(drv, clid) + driver_object *drv; + void *clid; +{ + list_entry *e; + custom_extension *ce; + + /* + * Sanity check. Our dummy bus drivers don't have + * any driver extentions. + */ + + if (drv->dro_driverext == NULL) + return (NULL); + + e = drv->dro_driverext->dre_usrext.nle_flink; + while (e != &drv->dro_driverext->dre_usrext) { + ce = (custom_extension *)e; + if (ce->ce_clid == clid) + return ((void *)(ce + 1)); + e = e->nle_flink; + } + + return (NULL); +} + + +uint32_t +IoCreateDevice(driver_object *drv, uint32_t devextlen, unicode_string *devname, + uint32_t devtype, uint32_t devchars, uint8_t exclusive, + device_object **newdev) +{ + device_object *dev; + + dev = ExAllocatePoolWithTag(NonPagedPool, sizeof(device_object), 0); + if (dev == NULL) + return (STATUS_INSUFFICIENT_RESOURCES); + + dev->do_type = devtype; + dev->do_drvobj = drv; + dev->do_currirp = NULL; + dev->do_flags = 0; + + if (devextlen) { + dev->do_devext = ExAllocatePoolWithTag(NonPagedPool, + devextlen, 0); + + if (dev->do_devext == NULL) { + ExFreePool(dev); + return (STATUS_INSUFFICIENT_RESOURCES); + } + + bzero(dev->do_devext, devextlen); + } else + dev->do_devext = NULL; + + dev->do_size = sizeof(device_object) + devextlen; + dev->do_refcnt = 1; + dev->do_attacheddev = NULL; + dev->do_nextdev = NULL; + dev->do_devtype = devtype; + dev->do_stacksize = 1; + dev->do_alignreq = 1; + dev->do_characteristics = devchars; + dev->do_iotimer = NULL; + KeInitializeEvent(&dev->do_devlock, EVENT_TYPE_SYNC, TRUE); + + /* + * Vpd is used for disk/tape devices, + * but we don't support those. (Yet.) + */ + dev->do_vpb = NULL; + + dev->do_devobj_ext = ExAllocatePoolWithTag(NonPagedPool, + sizeof(devobj_extension), 0); + + if (dev->do_devobj_ext == NULL) { + if (dev->do_devext != NULL) + ExFreePool(dev->do_devext); + ExFreePool(dev); + return (STATUS_INSUFFICIENT_RESOURCES); + } + + dev->do_devobj_ext->dve_type = 0; + dev->do_devobj_ext->dve_size = sizeof(devobj_extension); + dev->do_devobj_ext->dve_devobj = dev; + + /* + * Attach this device to the driver object's list + * of devices. Note: this is not the same as attaching + * the device to the device stack. The driver's AddDevice + * routine must explicitly call IoAddDeviceToDeviceStack() + * to do that. + */ + + if (drv->dro_devobj == NULL) { + drv->dro_devobj = dev; + dev->do_nextdev = NULL; + } else { + dev->do_nextdev = drv->dro_devobj; + drv->dro_devobj = dev; + } + + *newdev = dev; + + return (STATUS_SUCCESS); +} + +void +IoDeleteDevice(dev) + device_object *dev; +{ + device_object *prev; + + if (dev == NULL) + return; + + if (dev->do_devobj_ext != NULL) + ExFreePool(dev->do_devobj_ext); + + if (dev->do_devext != NULL) + ExFreePool(dev->do_devext); + + /* Unlink the device from the driver's device list. */ + + prev = dev->do_drvobj->dro_devobj; + if (prev == dev) + dev->do_drvobj->dro_devobj = dev->do_nextdev; + else { + while (prev->do_nextdev != dev) + prev = prev->do_nextdev; + prev->do_nextdev = dev->do_nextdev; + } + + ExFreePool(dev); +} + +device_object * +IoGetAttachedDevice(dev) + device_object *dev; +{ + device_object *d; + + if (dev == NULL) + return (NULL); + + d = dev; + + while (d->do_attacheddev != NULL) + d = d->do_attacheddev; + + return (d); +} + +static irp * +IoBuildSynchronousFsdRequest(func, dobj, buf, len, off, event, status) + uint32_t func; + device_object *dobj; + void *buf; + uint32_t len; + uint64_t *off; + nt_kevent *event; + io_status_block *status; +{ + irp *ip; + + ip = IoBuildAsynchronousFsdRequest(func, dobj, buf, len, off, status); + if (ip == NULL) + return (NULL); + ip->irp_usrevent = event; + + return (ip); +} + +static irp * +IoBuildAsynchronousFsdRequest(func, dobj, buf, len, off, status) + uint32_t func; + device_object *dobj; + void *buf; + uint32_t len; + uint64_t *off; + io_status_block *status; +{ + irp *ip; + io_stack_location *sl; + + ip = IoAllocateIrp(dobj->do_stacksize, TRUE); + if (ip == NULL) + return (NULL); + + ip->irp_usriostat = status; + ip->irp_tail.irp_overlay.irp_thread = NULL; + + sl = IoGetNextIrpStackLocation(ip); + sl->isl_major = func; + sl->isl_minor = 0; + sl->isl_flags = 0; + sl->isl_ctl = 0; + sl->isl_devobj = dobj; + sl->isl_fileobj = NULL; + sl->isl_completionfunc = NULL; + + ip->irp_userbuf = buf; + + if (dobj->do_flags & DO_BUFFERED_IO) { + ip->irp_assoc.irp_sysbuf = + ExAllocatePoolWithTag(NonPagedPool, len, 0); + if (ip->irp_assoc.irp_sysbuf == NULL) { + IoFreeIrp(ip); + return (NULL); + } + bcopy(buf, ip->irp_assoc.irp_sysbuf, len); + } + + if (dobj->do_flags & DO_DIRECT_IO) { + ip->irp_mdl = IoAllocateMdl(buf, len, FALSE, FALSE, ip); + if (ip->irp_mdl == NULL) { + if (ip->irp_assoc.irp_sysbuf != NULL) + ExFreePool(ip->irp_assoc.irp_sysbuf); + IoFreeIrp(ip); + return (NULL); + } + ip->irp_userbuf = NULL; + ip->irp_assoc.irp_sysbuf = NULL; + } + + if (func == IRP_MJ_READ) { + sl->isl_parameters.isl_read.isl_len = len; + if (off != NULL) + sl->isl_parameters.isl_read.isl_byteoff = *off; + else + sl->isl_parameters.isl_read.isl_byteoff = 0; + } + + if (func == IRP_MJ_WRITE) { + sl->isl_parameters.isl_write.isl_len = len; + if (off != NULL) + sl->isl_parameters.isl_write.isl_byteoff = *off; + else + sl->isl_parameters.isl_write.isl_byteoff = 0; + } + + return (ip); +} + +static irp * +IoBuildDeviceIoControlRequest(uint32_t iocode, device_object *dobj, void *ibuf, + uint32_t ilen, void *obuf, uint32_t olen, uint8_t isinternal, + nt_kevent *event, io_status_block *status) +{ + irp *ip; + io_stack_location *sl; + uint32_t buflen; + + ip = IoAllocateIrp(dobj->do_stacksize, TRUE); + if (ip == NULL) + return (NULL); + ip->irp_usrevent = event; + ip->irp_usriostat = status; + ip->irp_tail.irp_overlay.irp_thread = NULL; + + sl = IoGetNextIrpStackLocation(ip); + sl->isl_major = isinternal == TRUE ? + IRP_MJ_INTERNAL_DEVICE_CONTROL : IRP_MJ_DEVICE_CONTROL; + sl->isl_minor = 0; + sl->isl_flags = 0; + sl->isl_ctl = 0; + sl->isl_devobj = dobj; + sl->isl_fileobj = NULL; + sl->isl_completionfunc = NULL; + sl->isl_parameters.isl_ioctl.isl_iocode = iocode; + sl->isl_parameters.isl_ioctl.isl_ibuflen = ilen; + sl->isl_parameters.isl_ioctl.isl_obuflen = olen; + + switch(IO_METHOD(iocode)) { + case METHOD_BUFFERED: + if (ilen > olen) + buflen = ilen; + else + buflen = olen; + if (buflen) { + ip->irp_assoc.irp_sysbuf = + ExAllocatePoolWithTag(NonPagedPool, buflen, 0); + if (ip->irp_assoc.irp_sysbuf == NULL) { + IoFreeIrp(ip); + return (NULL); + } + } + if (ilen && ibuf != NULL) { + bcopy(ibuf, ip->irp_assoc.irp_sysbuf, ilen); + bzero((char *)ip->irp_assoc.irp_sysbuf + ilen, + buflen - ilen); + } else + bzero(ip->irp_assoc.irp_sysbuf, ilen); + ip->irp_userbuf = obuf; + break; + case METHOD_IN_DIRECT: + case METHOD_OUT_DIRECT: + if (ilen && ibuf != NULL) { + ip->irp_assoc.irp_sysbuf = + ExAllocatePoolWithTag(NonPagedPool, ilen, 0); + if (ip->irp_assoc.irp_sysbuf == NULL) { + IoFreeIrp(ip); + return (NULL); + } + bcopy(ibuf, ip->irp_assoc.irp_sysbuf, ilen); + } + if (olen && obuf != NULL) { + ip->irp_mdl = IoAllocateMdl(obuf, olen, + FALSE, FALSE, ip); + /* + * Normally we would MmProbeAndLockPages() + * here, but we don't have to in our + * imlementation. + */ + } + break; + case METHOD_NEITHER: + ip->irp_userbuf = obuf; + sl->isl_parameters.isl_ioctl.isl_type3ibuf = ibuf; + break; + default: + break; + } + + /* + * Ideally, we should associate this IRP with the calling + * thread here. + */ + + return (ip); +} + +static irp * +IoAllocateIrp(uint8_t stsize, uint8_t chargequota) +{ + irp *i; + + i = ExAllocatePoolWithTag(NonPagedPool, IoSizeOfIrp(stsize), 0); + if (i == NULL) + return (NULL); + + IoInitializeIrp(i, IoSizeOfIrp(stsize), stsize); + + return (i); +} + +static irp * +IoMakeAssociatedIrp(irp *ip, uint8_t stsize) +{ + irp *associrp; + + associrp = IoAllocateIrp(stsize, FALSE); + if (associrp == NULL) + return (NULL); + + mtx_lock(&ntoskrnl_dispatchlock); + associrp->irp_flags |= IRP_ASSOCIATED_IRP; + associrp->irp_tail.irp_overlay.irp_thread = + ip->irp_tail.irp_overlay.irp_thread; + associrp->irp_assoc.irp_master = ip; + mtx_unlock(&ntoskrnl_dispatchlock); + + return (associrp); +} + +static void +IoFreeIrp(ip) + irp *ip; +{ + ExFreePool(ip); +} + +static void +IoInitializeIrp(irp *io, uint16_t psize, uint8_t ssize) +{ + bzero((char *)io, IoSizeOfIrp(ssize)); + io->irp_size = psize; + io->irp_stackcnt = ssize; + io->irp_currentstackloc = ssize; + InitializeListHead(&io->irp_thlist); + io->irp_tail.irp_overlay.irp_csl = + (io_stack_location *)(io + 1) + ssize; +} + +static void +IoReuseIrp(ip, status) + irp *ip; + uint32_t status; +{ + uint8_t allocflags; + + allocflags = ip->irp_allocflags; + IoInitializeIrp(ip, ip->irp_size, ip->irp_stackcnt); + ip->irp_iostat.isb_status = status; + ip->irp_allocflags = allocflags; +} + +void +IoAcquireCancelSpinLock(uint8_t *irql) +{ + KeAcquireSpinLock(&ntoskrnl_cancellock, irql); +} + +void +IoReleaseCancelSpinLock(uint8_t irql) +{ + KeReleaseSpinLock(&ntoskrnl_cancellock, irql); +} + +uint8_t +IoCancelIrp(irp *ip) +{ + cancel_func cfunc; + uint8_t cancelirql; + + IoAcquireCancelSpinLock(&cancelirql); + cfunc = IoSetCancelRoutine(ip, NULL); + ip->irp_cancel = TRUE; + if (cfunc == NULL) { + IoReleaseCancelSpinLock(cancelirql); + return (FALSE); + } + ip->irp_cancelirql = cancelirql; + MSCALL2(cfunc, IoGetCurrentIrpStackLocation(ip)->isl_devobj, ip); + return (uint8_t)IoSetCancelValue(ip, TRUE); +} + +uint32_t +IofCallDriver(dobj, ip) + device_object *dobj; + irp *ip; +{ + driver_object *drvobj; + io_stack_location *sl; + uint32_t status; + driver_dispatch disp; + + drvobj = dobj->do_drvobj; + + if (ip->irp_currentstackloc <= 0) + panic("IoCallDriver(): out of stack locations"); + + IoSetNextIrpStackLocation(ip); + sl = IoGetCurrentIrpStackLocation(ip); + + sl->isl_devobj = dobj; + + disp = drvobj->dro_dispatch[sl->isl_major]; + status = MSCALL2(disp, dobj, ip); + + return (status); +} + +void +IofCompleteRequest(irp *ip, uint8_t prioboost) +{ + uint32_t status; + device_object *dobj; + io_stack_location *sl; + completion_func cf; + + KASSERT(ip->irp_iostat.isb_status != STATUS_PENDING, + ("incorrect IRP(%p) status (STATUS_PENDING)", ip)); + + sl = IoGetCurrentIrpStackLocation(ip); + IoSkipCurrentIrpStackLocation(ip); + + do { + if (sl->isl_ctl & SL_PENDING_RETURNED) + ip->irp_pendingreturned = TRUE; + + if (ip->irp_currentstackloc != (ip->irp_stackcnt + 1)) + dobj = IoGetCurrentIrpStackLocation(ip)->isl_devobj; + else + dobj = NULL; + + if (sl->isl_completionfunc != NULL && + ((ip->irp_iostat.isb_status == STATUS_SUCCESS && + sl->isl_ctl & SL_INVOKE_ON_SUCCESS) || + (ip->irp_iostat.isb_status != STATUS_SUCCESS && + sl->isl_ctl & SL_INVOKE_ON_ERROR) || + (ip->irp_cancel == TRUE && + sl->isl_ctl & SL_INVOKE_ON_CANCEL))) { + cf = sl->isl_completionfunc; + status = MSCALL3(cf, dobj, ip, sl->isl_completionctx); + if (status == STATUS_MORE_PROCESSING_REQUIRED) + return; + } else { + if ((ip->irp_currentstackloc <= ip->irp_stackcnt) && + (ip->irp_pendingreturned == TRUE)) + IoMarkIrpPending(ip); + } + + /* move to the next. */ + IoSkipCurrentIrpStackLocation(ip); + sl++; + } while (ip->irp_currentstackloc <= (ip->irp_stackcnt + 1)); + + if (ip->irp_usriostat != NULL) + *ip->irp_usriostat = ip->irp_iostat; + if (ip->irp_usrevent != NULL) + KeSetEvent(ip->irp_usrevent, prioboost, FALSE); + + /* Handle any associated IRPs. */ + + if (ip->irp_flags & IRP_ASSOCIATED_IRP) { + uint32_t masterirpcnt; + irp *masterirp; + mdl *m; + + masterirp = ip->irp_assoc.irp_master; + masterirpcnt = + InterlockedDecrement(&masterirp->irp_assoc.irp_irpcnt); + + while ((m = ip->irp_mdl) != NULL) { + ip->irp_mdl = m->mdl_next; + IoFreeMdl(m); + } + IoFreeIrp(ip); + if (masterirpcnt == 0) + IoCompleteRequest(masterirp, IO_NO_INCREMENT); + return; + } + + /* With any luck, these conditions will never arise. */ + + if (ip->irp_flags & IRP_PAGING_IO) { + if (ip->irp_mdl != NULL) + IoFreeMdl(ip->irp_mdl); + IoFreeIrp(ip); + } +} + +void +ntoskrnl_intr(arg) + void *arg; +{ + kinterrupt *iobj; + uint8_t irql; + uint8_t claimed; + list_entry *l; + + KeAcquireSpinLock(&ntoskrnl_intlock, &irql); + l = ntoskrnl_intlist.nle_flink; + while (l != &ntoskrnl_intlist) { + iobj = CONTAINING_RECORD(l, kinterrupt, ki_list); + claimed = MSCALL2(iobj->ki_svcfunc, iobj, iobj->ki_svcctx); + if (claimed == TRUE) + break; + l = l->nle_flink; + } + KeReleaseSpinLock(&ntoskrnl_intlock, irql); +} + +uint8_t +KeAcquireInterruptSpinLock(iobj) + kinterrupt *iobj; +{ + uint8_t irql; + KeAcquireSpinLock(&ntoskrnl_intlock, &irql); + return (irql); +} + +void +KeReleaseInterruptSpinLock(kinterrupt *iobj, uint8_t irql) +{ + KeReleaseSpinLock(&ntoskrnl_intlock, irql); +} + +uint8_t +KeSynchronizeExecution(iobj, syncfunc, syncctx) + kinterrupt *iobj; + void *syncfunc; + void *syncctx; +{ + uint8_t irql; + + KeAcquireSpinLock(&ntoskrnl_intlock, &irql); + MSCALL1(syncfunc, syncctx); + KeReleaseSpinLock(&ntoskrnl_intlock, irql); + + return (TRUE); +} + +/* + * IoConnectInterrupt() is passed only the interrupt vector and + * irql that a device wants to use, but no device-specific tag + * of any kind. This conflicts rather badly with FreeBSD's + * bus_setup_intr(), which needs the device_t for the device + * requesting interrupt delivery. In order to bypass this + * inconsistency, we implement a second level of interrupt + * dispatching on top of bus_setup_intr(). All devices use + * ntoskrnl_intr() as their ISR, and any device requesting + * interrupts will be registered with ntoskrnl_intr()'s interrupt + * dispatch list. When an interrupt arrives, we walk the list + * and invoke all the registered ISRs. This effectively makes all + * interrupts shared, but it's the only way to duplicate the + * semantics of IoConnectInterrupt() and IoDisconnectInterrupt() properly. + */ + +uint32_t +IoConnectInterrupt(kinterrupt **iobj, void *svcfunc, void *svcctx, + kspin_lock *lock, uint32_t vector, uint8_t irql, uint8_t syncirql, + uint8_t imode, uint8_t shared, uint32_t affinity, uint8_t savefloat) +{ + uint8_t curirql; + + *iobj = ExAllocatePoolWithTag(NonPagedPool, sizeof(kinterrupt), 0); + if (*iobj == NULL) + return (STATUS_INSUFFICIENT_RESOURCES); + + (*iobj)->ki_svcfunc = svcfunc; + (*iobj)->ki_svcctx = svcctx; + + if (lock == NULL) { + KeInitializeSpinLock(&(*iobj)->ki_lock_priv); + (*iobj)->ki_lock = &(*iobj)->ki_lock_priv; + } else + (*iobj)->ki_lock = lock; + + KeAcquireSpinLock(&ntoskrnl_intlock, &curirql); + InsertHeadList((&ntoskrnl_intlist), (&(*iobj)->ki_list)); + KeReleaseSpinLock(&ntoskrnl_intlock, curirql); + + return (STATUS_SUCCESS); +} + +void +IoDisconnectInterrupt(iobj) + kinterrupt *iobj; +{ + uint8_t irql; + + if (iobj == NULL) + return; + + KeAcquireSpinLock(&ntoskrnl_intlock, &irql); + RemoveEntryList((&iobj->ki_list)); + KeReleaseSpinLock(&ntoskrnl_intlock, irql); + + ExFreePool(iobj); +} + +device_object * +IoAttachDeviceToDeviceStack(src, dst) + device_object *src; + device_object *dst; +{ + device_object *attached; + + mtx_lock(&ntoskrnl_dispatchlock); + attached = IoGetAttachedDevice(dst); + attached->do_attacheddev = src; + src->do_attacheddev = NULL; + src->do_stacksize = attached->do_stacksize + 1; + mtx_unlock(&ntoskrnl_dispatchlock); + + return (attached); +} + +void +IoDetachDevice(topdev) + device_object *topdev; +{ + device_object *tail; + + mtx_lock(&ntoskrnl_dispatchlock); + + /* First, break the chain. */ + tail = topdev->do_attacheddev; + if (tail == NULL) { + mtx_unlock(&ntoskrnl_dispatchlock); + return; + } + topdev->do_attacheddev = tail->do_attacheddev; + topdev->do_refcnt--; + + /* Now reduce the stacksize count for the takm_il objects. */ + + tail = topdev->do_attacheddev; + while (tail != NULL) { + tail->do_stacksize--; + tail = tail->do_attacheddev; + } + + mtx_unlock(&ntoskrnl_dispatchlock); +} + +/* + * For the most part, an object is considered signalled if + * dh_sigstate == TRUE. The exception is for mutant objects + * (mutexes), where the logic works like this: + * + * - If the thread already owns the object and sigstate is + * less than or equal to 0, then the object is considered + * signalled (recursive acquisition). + * - If dh_sigstate == 1, the object is also considered + * signalled. + */ + +static int +ntoskrnl_is_signalled(obj, td) + nt_dispatch_header *obj; + struct thread *td; +{ + kmutant *km; + + if (obj->dh_type == DISP_TYPE_MUTANT) { + km = (kmutant *)obj; + if ((obj->dh_sigstate <= 0 && km->km_ownerthread == td) || + obj->dh_sigstate == 1) + return (TRUE); + return (FALSE); + } + + if (obj->dh_sigstate > 0) + return (TRUE); + return (FALSE); +} + +static void +ntoskrnl_satisfy_wait(obj, td) + nt_dispatch_header *obj; + struct thread *td; +{ + kmutant *km; + + switch (obj->dh_type) { + case DISP_TYPE_MUTANT: + km = (struct kmutant *)obj; + obj->dh_sigstate--; + /* + * If sigstate reaches 0, the mutex is now + * non-signalled (the new thread owns it). + */ + if (obj->dh_sigstate == 0) { + km->km_ownerthread = td; + if (km->km_abandoned == TRUE) + km->km_abandoned = FALSE; + } + break; + /* Synchronization objects get reset to unsignalled. */ + case DISP_TYPE_SYNCHRONIZATION_EVENT: + case DISP_TYPE_SYNCHRONIZATION_TIMER: + obj->dh_sigstate = 0; + break; + case DISP_TYPE_SEMAPHORE: + obj->dh_sigstate--; + break; + default: + break; + } +} + +static void +ntoskrnl_satisfy_multiple_waits(wb) + wait_block *wb; +{ + wait_block *cur; + struct thread *td; + + cur = wb; + td = wb->wb_kthread; + + do { + ntoskrnl_satisfy_wait(wb->wb_object, td); + cur->wb_awakened = TRUE; + cur = cur->wb_next; + } while (cur != wb); +} + +/* Always called with dispatcher lock held. */ +static void +ntoskrnl_waittest(obj, increment) + nt_dispatch_header *obj; + uint32_t increment; +{ + wait_block *w, *next; + list_entry *e; + struct thread *td; + wb_ext *we; + int satisfied; + + /* + * Once an object has been signalled, we walk its list of + * wait blocks. If a wait block can be awakened, then satisfy + * waits as necessary and wake the thread. + * + * The rules work like this: + * + * If a wait block is marked as WAITTYPE_ANY, then + * we can satisfy the wait conditions on the current + * object and wake the thread right away. Satisfying + * the wait also has the effect of breaking us out + * of the search loop. + * + * If the object is marked as WAITTYLE_ALL, then the + * wait block will be part of a circularly linked + * list of wait blocks belonging to a waiting thread + * that's sleeping in KeWaitForMultipleObjects(). In + * order to wake the thread, all the objects in the + * wait list must be in the signalled state. If they + * are, we then satisfy all of them and wake the + * thread. + * + */ + + e = obj->dh_waitlisthead.nle_flink; + + while (e != &obj->dh_waitlisthead && obj->dh_sigstate > 0) { + w = CONTAINING_RECORD(e, wait_block, wb_waitlist); + we = w->wb_ext; + td = we->we_td; + satisfied = FALSE; + if (w->wb_waittype == WAITTYPE_ANY) { + /* + * Thread can be awakened if + * any wait is satisfied. + */ + ntoskrnl_satisfy_wait(obj, td); + satisfied = TRUE; + w->wb_awakened = TRUE; + } else { + /* + * Thread can only be woken up + * if all waits are satisfied. + * If the thread is waiting on multiple + * objects, they should all be linked + * through the wb_next pointers in the + * wait blocks. + */ + satisfied = TRUE; + next = w->wb_next; + while (next != w) { + if (ntoskrnl_is_signalled(obj, td) == FALSE) { + satisfied = FALSE; + break; + } + next = next->wb_next; + } + ntoskrnl_satisfy_multiple_waits(w); + } + + if (satisfied == TRUE) + cv_broadcastpri(&we->we_cv, + (w->wb_oldpri - (increment * 4)) > PRI_MIN_KERN ? + w->wb_oldpri - (increment * 4) : PRI_MIN_KERN); + + e = e->nle_flink; + } +} + +/* + * Return the number of 100 nanosecond intervals since + * January 1, 1601. (?!?!) + */ +void +ntoskrnl_time(tval) + uint64_t *tval; +{ + struct timespec ts; + + nanotime(&ts); + *tval = (uint64_t)ts.tv_nsec / 100 + (uint64_t)ts.tv_sec * 10000000 + + 11644473600 * 10000000; /* 100ns ticks from 1601 to 1970 */ +} + +static void +KeQuerySystemTime(current_time) + uint64_t *current_time; +{ + ntoskrnl_time(current_time); +} + +static uint32_t +KeTickCount(void) +{ + struct timeval tv; + getmicrouptime(&tv); + return tvtohz(&tv); +} + + +/* + * KeWaitForSingleObject() is a tricky beast, because it can be used + * with several different object types: semaphores, timers, events, + * mutexes and threads. Semaphores don't appear very often, but the + * other object types are quite common. KeWaitForSingleObject() is + * what's normally used to acquire a mutex, and it can be used to + * wait for a thread termination. + * + * The Windows NDIS API is implemented in terms of Windows kernel + * primitives, and some of the object manipulation is duplicated in + * NDIS. For example, NDIS has timers and events, which are actually + * Windows kevents and ktimers. Now, you're supposed to only use the + * NDIS variants of these objects within the confines of the NDIS API, + * but there are some naughty developers out there who will use + * KeWaitForSingleObject() on NDIS timer and event objects, so we + * have to support that as well. Conseqently, our NDIS timer and event + * code has to be closely tied into our ntoskrnl timer and event code, + * just as it is in Windows. + * + * KeWaitForSingleObject() may do different things for different kinds + * of objects: + * + * - For events, we check if the event has been signalled. If the + * event is already in the signalled state, we just return immediately, + * otherwise we wait for it to be set to the signalled state by someone + * else calling KeSetEvent(). Events can be either synchronization or + * notification events. + * + * - For timers, if the timer has already fired and the timer is in + * the signalled state, we just return, otherwise we wait on the + * timer. Unlike an event, timers get signalled automatically when + * they expire rather than someone having to trip them manually. + * Timers initialized with KeInitializeTimer() are always notification + * events: KeInitializeTimerEx() lets you initialize a timer as + * either a notification or synchronization event. + * + * - For mutexes, we try to acquire the mutex and if we can't, we wait + * on the mutex until it's available and then grab it. When a mutex is + * released, it enters the signalled state, which wakes up one of the + * threads waiting to acquire it. Mutexes are always synchronization + * events. + * + * - For threads, the only thing we do is wait until the thread object + * enters a signalled state, which occurs when the thread terminates. + * Threads are always notification events. + * + * A notification event wakes up all threads waiting on an object. A + * synchronization event wakes up just one. Also, a synchronization event + * is auto-clearing, which means we automatically set the event back to + * the non-signalled state once the wakeup is done. + */ + +uint32_t +KeWaitForSingleObject(void *arg, uint32_t reason, uint32_t mode, + uint8_t alertable, int64_t *duetime) +{ + wait_block w; + struct thread *td = curthread; + struct timeval tv; + int error = 0; + uint64_t curtime; + wb_ext we; + nt_dispatch_header *obj; + + obj = arg; + + if (obj == NULL) + return (STATUS_INVALID_PARAMETER); + + mtx_lock(&ntoskrnl_dispatchlock); + + cv_init(&we.we_cv, "KeWFS"); + we.we_td = td; + + /* + * Check to see if this object is already signalled, + * and just return without waiting if it is. + */ + if (ntoskrnl_is_signalled(obj, td) == TRUE) { + /* Sanity check the signal state value. */ + if (obj->dh_sigstate != INT32_MIN) { + ntoskrnl_satisfy_wait(obj, curthread); + mtx_unlock(&ntoskrnl_dispatchlock); + return (STATUS_SUCCESS); + } else { + /* + * There's a limit to how many times we can + * recursively acquire a mutant. If we hit + * the limit, something is very wrong. + */ + if (obj->dh_type == DISP_TYPE_MUTANT) { + mtx_unlock(&ntoskrnl_dispatchlock); + panic("mutant limit exceeded"); + } + } + } + + bzero((char *)&w, sizeof(wait_block)); + w.wb_object = obj; + w.wb_ext = &we; + w.wb_waittype = WAITTYPE_ANY; + w.wb_next = &w; + w.wb_waitkey = 0; + w.wb_awakened = FALSE; + w.wb_oldpri = td->td_priority; + + InsertTailList((&obj->dh_waitlisthead), (&w.wb_waitlist)); + + /* + * The timeout value is specified in 100 nanosecond units + * and can be a positive or negative number. If it's positive, + * then the duetime is absolute, and we need to convert it + * to an absolute offset relative to now in order to use it. + * If it's negative, then the duetime is relative and we + * just have to convert the units. + */ + + if (duetime != NULL) { + if (*duetime < 0) { + tv.tv_sec = - (*duetime) / 10000000; + tv.tv_usec = (- (*duetime) / 10) - + (tv.tv_sec * 1000000); + } else { + ntoskrnl_time(&curtime); + if (*duetime < curtime) + tv.tv_sec = tv.tv_usec = 0; + else { + tv.tv_sec = ((*duetime) - curtime) / 10000000; + tv.tv_usec = ((*duetime) - curtime) / 10 - + (tv.tv_sec * 1000000); + } + } + } + + if (duetime == NULL) + cv_wait(&we.we_cv, &ntoskrnl_dispatchlock); + else + error = cv_timedwait(&we.we_cv, + &ntoskrnl_dispatchlock, tvtohz(&tv)); + + RemoveEntryList(&w.wb_waitlist); + + cv_destroy(&we.we_cv); + + /* We timed out. Leave the object alone and return status. */ + + if (error == EWOULDBLOCK) { + mtx_unlock(&ntoskrnl_dispatchlock); + return (STATUS_TIMEOUT); + } + + mtx_unlock(&ntoskrnl_dispatchlock); + + return (STATUS_SUCCESS); +/* + return (KeWaitForMultipleObjects(1, &obj, WAITTYPE_ALL, reason, + mode, alertable, duetime, &w)); +*/ +} + +static uint32_t +KeWaitForMultipleObjects(uint32_t cnt, nt_dispatch_header *obj[], uint32_t wtype, + uint32_t reason, uint32_t mode, uint8_t alertable, int64_t *duetime, + wait_block *wb_array) +{ + struct thread *td = curthread; + wait_block *whead, *w; + wait_block _wb_array[MAX_WAIT_OBJECTS]; + nt_dispatch_header *cur; + struct timeval tv; + int i, wcnt = 0, error = 0; + uint64_t curtime; + struct timespec t1, t2; + uint32_t status = STATUS_SUCCESS; + wb_ext we; + + if (cnt > MAX_WAIT_OBJECTS) + return (STATUS_INVALID_PARAMETER); + if (cnt > THREAD_WAIT_OBJECTS && wb_array == NULL) + return (STATUS_INVALID_PARAMETER); + + mtx_lock(&ntoskrnl_dispatchlock); + + cv_init(&we.we_cv, "KeWFM"); + we.we_td = td; + + if (wb_array == NULL) + whead = _wb_array; + else + whead = wb_array; + + bzero((char *)whead, sizeof(wait_block) * cnt); + + /* First pass: see if we can satisfy any waits immediately. */ + + wcnt = 0; + w = whead; + + for (i = 0; i < cnt; i++) { + InsertTailList((&obj[i]->dh_waitlisthead), + (&w->wb_waitlist)); + w->wb_ext = &we; + w->wb_object = obj[i]; + w->wb_waittype = wtype; + w->wb_waitkey = i; + w->wb_awakened = FALSE; + w->wb_oldpri = td->td_priority; + w->wb_next = w + 1; + w++; + wcnt++; + if (ntoskrnl_is_signalled(obj[i], td)) { + /* + * There's a limit to how many times + * we can recursively acquire a mutant. + * If we hit the limit, something + * is very wrong. + */ + if (obj[i]->dh_sigstate == INT32_MIN && + obj[i]->dh_type == DISP_TYPE_MUTANT) { + mtx_unlock(&ntoskrnl_dispatchlock); + panic("mutant limit exceeded"); + } + + /* + * If this is a WAITTYPE_ANY wait, then + * satisfy the waited object and exit + * right now. + */ + + if (wtype == WAITTYPE_ANY) { + ntoskrnl_satisfy_wait(obj[i], td); + status = STATUS_WAIT_0 + i; + goto wait_done; + } else { + w--; + wcnt--; + w->wb_object = NULL; + RemoveEntryList(&w->wb_waitlist); + } + } + } + + /* + * If this is a WAITTYPE_ALL wait and all objects are + * already signalled, satisfy the waits and exit now. + */ + + if (wtype == WAITTYPE_ALL && wcnt == 0) { + for (i = 0; i < cnt; i++) + ntoskrnl_satisfy_wait(obj[i], td); + status = STATUS_SUCCESS; + goto wait_done; + } + + /* + * Create a circular waitblock list. The waitcount + * must always be non-zero when we get here. + */ + + (w - 1)->wb_next = whead; + + /* Wait on any objects that aren't yet signalled. */ + + /* Calculate timeout, if any. */ + + if (duetime != NULL) { + if (*duetime < 0) { + tv.tv_sec = - (*duetime) / 10000000; + tv.tv_usec = (- (*duetime) / 10) - + (tv.tv_sec * 1000000); + } else { + ntoskrnl_time(&curtime); + if (*duetime < curtime) + tv.tv_sec = tv.tv_usec = 0; + else { + tv.tv_sec = ((*duetime) - curtime) / 10000000; + tv.tv_usec = ((*duetime) - curtime) / 10 - + (tv.tv_sec * 1000000); + } + } + } + + while (wcnt) { + nanotime(&t1); + + if (duetime == NULL) + cv_wait(&we.we_cv, &ntoskrnl_dispatchlock); + else + error = cv_timedwait(&we.we_cv, + &ntoskrnl_dispatchlock, tvtohz(&tv)); + + /* Wait with timeout expired. */ + + if (error) { + status = STATUS_TIMEOUT; + goto wait_done; + } + + nanotime(&t2); + + /* See what's been signalled. */ + + w = whead; + do { + cur = w->wb_object; + if (ntoskrnl_is_signalled(cur, td) == TRUE || + w->wb_awakened == TRUE) { + /* Sanity check the signal state value. */ + if (cur->dh_sigstate == INT32_MIN && + cur->dh_type == DISP_TYPE_MUTANT) { + mtx_unlock(&ntoskrnl_dispatchlock); + panic("mutant limit exceeded"); + } + wcnt--; + if (wtype == WAITTYPE_ANY) { + status = w->wb_waitkey & + STATUS_WAIT_0; + goto wait_done; + } + } + w = w->wb_next; + } while (w != whead); + + /* + * If all objects have been signalled, or if this + * is a WAITTYPE_ANY wait and we were woke up by + * someone, we can bail. + */ + + if (wcnt == 0) { + status = STATUS_SUCCESS; + goto wait_done; + } + + /* + * If this is WAITTYPE_ALL wait, and there's still + * objects that haven't been signalled, deduct the + * time that's elapsed so far from the timeout and + * wait again (or continue waiting indefinitely if + * there's no timeout). + */ + + if (duetime != NULL) { + tv.tv_sec -= (t2.tv_sec - t1.tv_sec); + tv.tv_usec -= (t2.tv_nsec - t1.tv_nsec) / 1000; + } + } + + +wait_done: + + cv_destroy(&we.we_cv); + + for (i = 0; i < cnt; i++) { + if (whead[i].wb_object != NULL) + RemoveEntryList(&whead[i].wb_waitlist); + + } + mtx_unlock(&ntoskrnl_dispatchlock); + + return (status); +} + +static void +WRITE_REGISTER_USHORT(uint16_t *reg, uint16_t val) +{ + bus_space_write_2(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg, val); +} + +static uint16_t +READ_REGISTER_USHORT(reg) + uint16_t *reg; +{ + return (bus_space_read_2(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg)); +} + +static void +WRITE_REGISTER_ULONG(reg, val) + uint32_t *reg; + uint32_t val; +{ + bus_space_write_4(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg, val); +} + +static uint32_t +READ_REGISTER_ULONG(reg) + uint32_t *reg; +{ + return (bus_space_read_4(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg)); +} + +static uint8_t +READ_REGISTER_UCHAR(uint8_t *reg) +{ + return (bus_space_read_1(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg)); +} + +static void +WRITE_REGISTER_UCHAR(uint8_t *reg, uint8_t val) +{ + bus_space_write_1(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg, val); +} + +static int64_t +_allmul(a, b) + int64_t a; + int64_t b; +{ + return (a * b); +} + +static int64_t +_alldiv(a, b) + int64_t a; + int64_t b; +{ + return (a / b); +} + +static int64_t +_allrem(a, b) + int64_t a; + int64_t b; +{ + return (a % b); +} + +static uint64_t +_aullmul(a, b) + uint64_t a; + uint64_t b; +{ + return (a * b); +} + +static uint64_t +_aulldiv(a, b) + uint64_t a; + uint64_t b; +{ + return (a / b); +} + +static uint64_t +_aullrem(a, b) + uint64_t a; + uint64_t b; +{ + return (a % b); +} + +static int64_t +_allshl(int64_t a, uint8_t b) +{ + return (a << b); +} + +static uint64_t +_aullshl(uint64_t a, uint8_t b) +{ + return (a << b); +} + +static int64_t +_allshr(int64_t a, uint8_t b) +{ + return (a >> b); +} + +static uint64_t +_aullshr(uint64_t a, uint8_t b) +{ + return (a >> b); +} + +static slist_entry * +ntoskrnl_pushsl(head, entry) + slist_header *head; + slist_entry *entry; +{ + slist_entry *oldhead; + + oldhead = head->slh_list.slh_next; + entry->sl_next = head->slh_list.slh_next; + head->slh_list.slh_next = entry; + head->slh_list.slh_depth++; + head->slh_list.slh_seq++; + + return (oldhead); +} + +static void +InitializeSListHead(head) + slist_header *head; +{ + memset(head, 0, sizeof(*head)); +} + +static slist_entry * +ntoskrnl_popsl(head) + slist_header *head; +{ + slist_entry *first; + + first = head->slh_list.slh_next; + if (first != NULL) { + head->slh_list.slh_next = first->sl_next; + head->slh_list.slh_depth--; + head->slh_list.slh_seq++; + } + + return (first); +} + +/* + * We need this to make lookaside lists work for amd64. + * We pass a pointer to ExAllocatePoolWithTag() the lookaside + * list structure. For amd64 to work right, this has to be a + * pointer to the wrapped version of the routine, not the + * original. Letting the Windows driver invoke the original + * function directly will result in a convention calling + * mismatch and a pretty crash. On x86, this effectively + * becomes a no-op since ipt_func and ipt_wrap are the same. + */ + +static funcptr +ntoskrnl_findwrap(func) + funcptr func; +{ + image_patch_table *patch; + + patch = ntoskrnl_functbl; + while (patch->ipt_func != NULL) { + if ((funcptr)patch->ipt_func == func) + return ((funcptr)patch->ipt_wrap); + patch++; + } + + return (NULL); +} + +static void +ExInitializePagedLookasideList(paged_lookaside_list *lookaside, + lookaside_alloc_func *allocfunc, lookaside_free_func *freefunc, + uint32_t flags, size_t size, uint32_t tag, uint16_t depth) +{ + bzero((char *)lookaside, sizeof(paged_lookaside_list)); + + if (size < sizeof(slist_entry)) + lookaside->nll_l.gl_size = sizeof(slist_entry); + else + lookaside->nll_l.gl_size = size; + lookaside->nll_l.gl_tag = tag; + if (allocfunc == NULL) + lookaside->nll_l.gl_allocfunc = + ntoskrnl_findwrap((funcptr)ExAllocatePoolWithTag); + else + lookaside->nll_l.gl_allocfunc = allocfunc; + + if (freefunc == NULL) + lookaside->nll_l.gl_freefunc = + ntoskrnl_findwrap((funcptr)ExFreePool); + else + lookaside->nll_l.gl_freefunc = freefunc; + +#ifdef __i386__ + KeInitializeSpinLock(&lookaside->nll_obsoletelock); +#endif + + lookaside->nll_l.gl_type = NonPagedPool; + lookaside->nll_l.gl_depth = depth; + lookaside->nll_l.gl_maxdepth = LOOKASIDE_DEPTH; +} + +static void +ExDeletePagedLookasideList(lookaside) + paged_lookaside_list *lookaside; +{ + void *buf; + void (*freefunc)(void *); + + freefunc = lookaside->nll_l.gl_freefunc; + while((buf = ntoskrnl_popsl(&lookaside->nll_l.gl_listhead)) != NULL) + MSCALL1(freefunc, buf); +} + +static void +ExInitializeNPagedLookasideList(npaged_lookaside_list *lookaside, + lookaside_alloc_func *allocfunc, lookaside_free_func *freefunc, + uint32_t flags, size_t size, uint32_t tag, uint16_t depth) +{ + bzero((char *)lookaside, sizeof(npaged_lookaside_list)); + + if (size < sizeof(slist_entry)) + lookaside->nll_l.gl_size = sizeof(slist_entry); + else + lookaside->nll_l.gl_size = size; + lookaside->nll_l.gl_tag = tag; + if (allocfunc == NULL) + lookaside->nll_l.gl_allocfunc = + ntoskrnl_findwrap((funcptr)ExAllocatePoolWithTag); + else + lookaside->nll_l.gl_allocfunc = allocfunc; + + if (freefunc == NULL) + lookaside->nll_l.gl_freefunc = + ntoskrnl_findwrap((funcptr)ExFreePool); + else + lookaside->nll_l.gl_freefunc = freefunc; + +#ifdef __i386__ + KeInitializeSpinLock(&lookaside->nll_obsoletelock); +#endif + + lookaside->nll_l.gl_type = NonPagedPool; + lookaside->nll_l.gl_depth = depth; + lookaside->nll_l.gl_maxdepth = LOOKASIDE_DEPTH; +} + +static void +ExDeleteNPagedLookasideList(lookaside) + npaged_lookaside_list *lookaside; +{ + void *buf; + void (*freefunc)(void *); + + freefunc = lookaside->nll_l.gl_freefunc; + while((buf = ntoskrnl_popsl(&lookaside->nll_l.gl_listhead)) != NULL) + MSCALL1(freefunc, buf); +} + +slist_entry * +InterlockedPushEntrySList(head, entry) + slist_header *head; + slist_entry *entry; +{ + slist_entry *oldhead; + + mtx_lock_spin(&ntoskrnl_interlock); + oldhead = ntoskrnl_pushsl(head, entry); + mtx_unlock_spin(&ntoskrnl_interlock); + + return (oldhead); +} + +slist_entry * +InterlockedPopEntrySList(head) + slist_header *head; +{ + slist_entry *first; + + mtx_lock_spin(&ntoskrnl_interlock); + first = ntoskrnl_popsl(head); + mtx_unlock_spin(&ntoskrnl_interlock); + + return (first); +} + +static slist_entry * +ExInterlockedPushEntrySList(head, entry, lock) + slist_header *head; + slist_entry *entry; + kspin_lock *lock; +{ + return (InterlockedPushEntrySList(head, entry)); +} + +static slist_entry * +ExInterlockedPopEntrySList(head, lock) + slist_header *head; + kspin_lock *lock; +{ + return (InterlockedPopEntrySList(head)); +} + +uint16_t +ExQueryDepthSList(head) + slist_header *head; +{ + uint16_t depth; + + mtx_lock_spin(&ntoskrnl_interlock); + depth = head->slh_list.slh_depth; + mtx_unlock_spin(&ntoskrnl_interlock); + + return (depth); +} + +void +KeInitializeSpinLock(lock) + kspin_lock *lock; +{ + *lock = 0; +} + +#ifdef __i386__ +void +KefAcquireSpinLockAtDpcLevel(lock) + kspin_lock *lock; +{ +#ifdef NTOSKRNL_DEBUG_SPINLOCKS + int i = 0; +#endif + + while (atomic_cmpset_acq_int((volatile u_int *)lock, 0, 1) == 0) { + /* sit and spin */; +#ifdef NTOSKRNL_DEBUG_SPINLOCKS + i++; + if (i > 200000000) + panic("DEADLOCK!"); +#endif + } +} + +void +KefReleaseSpinLockFromDpcLevel(lock) + kspin_lock *lock; +{ + atomic_store_rel_int((volatile u_int *)lock, 0); +} + +uint8_t +KeAcquireSpinLockRaiseToDpc(kspin_lock *lock) +{ + uint8_t oldirql; + + if (KeGetCurrentIrql() > DISPATCH_LEVEL) + panic("IRQL_NOT_LESS_THAN_OR_EQUAL"); + + KeRaiseIrql(DISPATCH_LEVEL, &oldirql); + KeAcquireSpinLockAtDpcLevel(lock); + + return (oldirql); +} +#else +void +KeAcquireSpinLockAtDpcLevel(kspin_lock *lock) +{ + while (atomic_cmpset_acq_int((volatile u_int *)lock, 0, 1) == 0) + /* sit and spin */; +} + +void +KeReleaseSpinLockFromDpcLevel(kspin_lock *lock) +{ + atomic_store_rel_int((volatile u_int *)lock, 0); +} +#endif /* __i386__ */ + +uintptr_t +InterlockedExchange(dst, val) + volatile uint32_t *dst; + uintptr_t val; +{ + uintptr_t r; + + mtx_lock_spin(&ntoskrnl_interlock); + r = *dst; + *dst = val; + mtx_unlock_spin(&ntoskrnl_interlock); + + return (r); +} + +static uint32_t +InterlockedIncrement(addend) + volatile uint32_t *addend; +{ + atomic_add_long((volatile u_long *)addend, 1); + return (*addend); +} + +static uint32_t +InterlockedDecrement(addend) + volatile uint32_t *addend; +{ + atomic_subtract_long((volatile u_long *)addend, 1); + return (*addend); +} + +static void +ExInterlockedAddLargeStatistic(addend, inc) + uint64_t *addend; + uint32_t inc; +{ + mtx_lock_spin(&ntoskrnl_interlock); + *addend += inc; + mtx_unlock_spin(&ntoskrnl_interlock); +}; + +mdl * +IoAllocateMdl(void *vaddr, uint32_t len, uint8_t secondarybuf, + uint8_t chargequota, irp *iopkt) +{ + mdl *m; + int zone = 0; + + if (MmSizeOfMdl(vaddr, len) > MDL_ZONE_SIZE) + m = ExAllocatePoolWithTag(NonPagedPool, + MmSizeOfMdl(vaddr, len), 0); + else { + m = uma_zalloc(mdl_zone, M_NOWAIT | M_ZERO); + zone++; + } + + if (m == NULL) + return (NULL); + + MmInitializeMdl(m, vaddr, len); + + /* + * MmInitializMdl() clears the flags field, so we + * have to set this here. If the MDL came from the + * MDL UMA zone, tag it so we can release it to + * the right place later. + */ + if (zone) + m->mdl_flags = MDL_ZONE_ALLOCED; + + if (iopkt != NULL) { + if (secondarybuf == TRUE) { + mdl *last; + last = iopkt->irp_mdl; + while (last->mdl_next != NULL) + last = last->mdl_next; + last->mdl_next = m; + } else { + if (iopkt->irp_mdl != NULL) + panic("leaking an MDL in IoAllocateMdl()"); + iopkt->irp_mdl = m; + } + } + + return (m); +} + +void +IoFreeMdl(m) + mdl *m; +{ + if (m == NULL) + return; + + if (m->mdl_flags & MDL_ZONE_ALLOCED) + uma_zfree(mdl_zone, m); + else + ExFreePool(m); +} + +static void * +MmAllocateContiguousMemory(size, highest) + uint32_t size; + uint64_t highest; +{ + void *addr; + size_t pagelength = roundup(size, PAGE_SIZE); + + addr = ExAllocatePoolWithTag(NonPagedPool, pagelength, 0); + + return (addr); +} + +static void * +MmAllocateContiguousMemorySpecifyCache(size, lowest, highest, + boundary, cachetype) + uint32_t size; + uint64_t lowest; + uint64_t highest; + uint64_t boundary; + enum nt_caching_type cachetype; +{ + vm_memattr_t memattr; + void *ret; + + switch (cachetype) { + case MmNonCached: + memattr = VM_MEMATTR_UNCACHEABLE; + break; + case MmWriteCombined: + memattr = VM_MEMATTR_WRITE_COMBINING; + break; + case MmNonCachedUnordered: + memattr = VM_MEMATTR_UNCACHEABLE; + break; + case MmCached: + case MmHardwareCoherentCached: + case MmUSWCCached: + default: + memattr = VM_MEMATTR_DEFAULT; + break; + } + + ret = (void *)kmem_alloc_contig(kernel_map, size, M_ZERO | M_NOWAIT, + lowest, highest, PAGE_SIZE, boundary, memattr); + if (ret != NULL) + malloc_type_allocated(M_DEVBUF, round_page(size)); + return (ret); +} + +static void +MmFreeContiguousMemory(base) + void *base; +{ + ExFreePool(base); +} + +static void +MmFreeContiguousMemorySpecifyCache(base, size, cachetype) + void *base; + uint32_t size; + enum nt_caching_type cachetype; +{ + contigfree(base, size, M_DEVBUF); +} + +static uint32_t +MmSizeOfMdl(vaddr, len) + void *vaddr; + size_t len; +{ + uint32_t l; + + l = sizeof(struct mdl) + + (sizeof(vm_offset_t *) * SPAN_PAGES(vaddr, len)); + + return (l); +} + +/* + * The Microsoft documentation says this routine fills in the + * page array of an MDL with the _physical_ page addresses that + * comprise the buffer, but we don't really want to do that here. + * Instead, we just fill in the page array with the kernel virtual + * addresses of the buffers. + */ +void +MmBuildMdlForNonPagedPool(m) + mdl *m; +{ + vm_offset_t *mdl_pages; + int pagecnt, i; + + pagecnt = SPAN_PAGES(m->mdl_byteoffset, m->mdl_bytecount); + + if (pagecnt > (m->mdl_size - sizeof(mdl)) / sizeof(vm_offset_t *)) + panic("not enough pages in MDL to describe buffer"); + + mdl_pages = MmGetMdlPfnArray(m); + + for (i = 0; i < pagecnt; i++) + *mdl_pages = (vm_offset_t)m->mdl_startva + (i * PAGE_SIZE); + + m->mdl_flags |= MDL_SOURCE_IS_NONPAGED_POOL; + m->mdl_mappedsystemva = MmGetMdlVirtualAddress(m); +} + +static void * +MmMapLockedPages(mdl *buf, uint8_t accessmode) +{ + buf->mdl_flags |= MDL_MAPPED_TO_SYSTEM_VA; + return (MmGetMdlVirtualAddress(buf)); +} + +static void * +MmMapLockedPagesSpecifyCache(mdl *buf, uint8_t accessmode, uint32_t cachetype, + void *vaddr, uint32_t bugcheck, uint32_t prio) +{ + return (MmMapLockedPages(buf, accessmode)); +} + +static void +MmUnmapLockedPages(vaddr, buf) + void *vaddr; + mdl *buf; +{ + buf->mdl_flags &= ~MDL_MAPPED_TO_SYSTEM_VA; +} + +/* + * This function has a problem in that it will break if you + * compile this module without PAE and try to use it on a PAE + * kernel. Unfortunately, there's no way around this at the + * moment. It's slightly less broken that using pmap_kextract(). + * You'd think the virtual memory subsystem would help us out + * here, but it doesn't. + */ + +static uint64_t +MmGetPhysicalAddress(void *base) +{ + return (pmap_extract(kernel_map->pmap, (vm_offset_t)base)); +} + +void * +MmGetSystemRoutineAddress(ustr) + unicode_string *ustr; +{ + ansi_string astr; + + if (RtlUnicodeStringToAnsiString(&astr, ustr, TRUE)) + return (NULL); + return (ndis_get_routine_address(ntoskrnl_functbl, astr.as_buf)); +} + +uint8_t +MmIsAddressValid(vaddr) + void *vaddr; +{ + if (pmap_extract(kernel_map->pmap, (vm_offset_t)vaddr)) + return (TRUE); + + return (FALSE); +} + +void * +MmMapIoSpace(paddr, len, cachetype) + uint64_t paddr; + uint32_t len; + uint32_t cachetype; +{ + devclass_t nexus_class; + device_t *nexus_devs, devp; + int nexus_count = 0; + device_t matching_dev = NULL; + struct resource *res; + int i; + vm_offset_t v; + + /* There will always be at least one nexus. */ + + nexus_class = devclass_find("nexus"); + devclass_get_devices(nexus_class, &nexus_devs, &nexus_count); + + for (i = 0; i < nexus_count; i++) { + devp = nexus_devs[i]; + matching_dev = ntoskrnl_finddev(devp, paddr, &res); + if (matching_dev) + break; + } + + free(nexus_devs, M_TEMP); + + if (matching_dev == NULL) + return (NULL); + + v = (vm_offset_t)rman_get_virtual(res); + if (paddr > rman_get_start(res)) + v += paddr - rman_get_start(res); + + return ((void *)v); +} + +void +MmUnmapIoSpace(vaddr, len) + void *vaddr; + size_t len; +{ +} + + +static device_t +ntoskrnl_finddev(dev, paddr, res) + device_t dev; + uint64_t paddr; + struct resource **res; +{ + device_t *children = NULL; + device_t matching_dev; + int childcnt; + struct resource *r; + struct resource_list *rl; + struct resource_list_entry *rle; + uint32_t flags; + int i; + + /* We only want devices that have been successfully probed. */ + + if (device_is_alive(dev) == FALSE) + return (NULL); + + rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev); + if (rl != NULL) { + STAILQ_FOREACH(rle, rl, link) { + r = rle->res; + + if (r == NULL) + continue; + + flags = rman_get_flags(r); + + if (rle->type == SYS_RES_MEMORY && + paddr >= rman_get_start(r) && + paddr <= rman_get_end(r)) { + if (!(flags & RF_ACTIVE)) + bus_activate_resource(dev, + SYS_RES_MEMORY, 0, r); + *res = r; + return (dev); + } + } + } + + /* + * If this device has children, do another + * level of recursion to inspect them. + */ + + device_get_children(dev, &children, &childcnt); + + for (i = 0; i < childcnt; i++) { + matching_dev = ntoskrnl_finddev(children[i], paddr, res); + if (matching_dev != NULL) { + free(children, M_TEMP); + return (matching_dev); + } + } + + + /* Won't somebody please think of the children! */ + + if (children != NULL) + free(children, M_TEMP); + + return (NULL); +} + +/* + * Workitems are unlike DPCs, in that they run in a user-mode thread + * context rather than at DISPATCH_LEVEL in kernel context. In our + * case we run them in kernel context anyway. + */ +static void +ntoskrnl_workitem_thread(arg) + void *arg; +{ + kdpc_queue *kq; + list_entry *l; + io_workitem *iw; + uint8_t irql; + + kq = arg; + + InitializeListHead(&kq->kq_disp); + kq->kq_td = curthread; + kq->kq_exit = 0; + KeInitializeSpinLock(&kq->kq_lock); + KeInitializeEvent(&kq->kq_proc, EVENT_TYPE_SYNC, FALSE); + + while (1) { + KeWaitForSingleObject(&kq->kq_proc, 0, 0, TRUE, NULL); + + KeAcquireSpinLock(&kq->kq_lock, &irql); + + if (kq->kq_exit) { + kq->kq_exit = 0; + KeReleaseSpinLock(&kq->kq_lock, irql); + break; + } + + while (!IsListEmpty(&kq->kq_disp)) { + l = RemoveHeadList(&kq->kq_disp); + iw = CONTAINING_RECORD(l, + io_workitem, iw_listentry); + InitializeListHead((&iw->iw_listentry)); + if (iw->iw_func == NULL) + continue; + KeReleaseSpinLock(&kq->kq_lock, irql); + MSCALL2(iw->iw_func, iw->iw_dobj, iw->iw_ctx); + KeAcquireSpinLock(&kq->kq_lock, &irql); + } + + KeReleaseSpinLock(&kq->kq_lock, irql); + } + + kproc_exit(0); + return; /* notreached */ +} + +static ndis_status +RtlCharToInteger(src, base, val) + const char *src; + uint32_t base; + uint32_t *val; +{ + int negative = 0; + uint32_t res; + + if (!src || !val) + return (STATUS_ACCESS_VIOLATION); + while (*src != '\0' && *src <= ' ') + src++; + if (*src == '+') + src++; + else if (*src == '-') { + src++; + negative = 1; + } + if (base == 0) { + base = 10; + if (*src == '0') { + src++; + if (*src == 'b') { + base = 2; + src++; + } else if (*src == 'o') { + base = 8; + src++; + } else if (*src == 'x') { + base = 16; + src++; + } + } + } else if (!(base == 2 || base == 8 || base == 10 || base == 16)) + return (STATUS_INVALID_PARAMETER); + + for (res = 0; *src; src++) { + int v; + if (isdigit(*src)) + v = *src - '0'; + else if (isxdigit(*src)) + v = tolower(*src) - 'a' + 10; + else + v = base; + if (v >= base) + return (STATUS_INVALID_PARAMETER); + res = res * base + v; + } + *val = negative ? -res : res; + return (STATUS_SUCCESS); +} + +static void +ntoskrnl_destroy_workitem_threads(void) +{ + kdpc_queue *kq; + int i; + + for (i = 0; i < WORKITEM_THREADS; i++) { + kq = wq_queues + i; + kq->kq_exit = 1; + KeSetEvent(&kq->kq_proc, IO_NO_INCREMENT, FALSE); + while (kq->kq_exit) + tsleep(kq->kq_td->td_proc, PWAIT, "waitiw", hz/10); + } +} + +io_workitem * +IoAllocateWorkItem(dobj) + device_object *dobj; +{ + io_workitem *iw; + + iw = uma_zalloc(iw_zone, M_NOWAIT); + if (iw == NULL) + return (NULL); + + InitializeListHead(&iw->iw_listentry); + iw->iw_dobj = dobj; + + mtx_lock(&ntoskrnl_dispatchlock); + iw->iw_idx = wq_idx; + WORKIDX_INC(wq_idx); + mtx_unlock(&ntoskrnl_dispatchlock); + + return (iw); +} + +void +IoFreeWorkItem(iw) + io_workitem *iw; +{ + uma_zfree(iw_zone, iw); +} + +void +IoQueueWorkItem(iw, iw_func, qtype, ctx) + io_workitem *iw; + io_workitem_func iw_func; + uint32_t qtype; + void *ctx; +{ + kdpc_queue *kq; + list_entry *l; + io_workitem *cur; + uint8_t irql; + + kq = wq_queues + iw->iw_idx; + + KeAcquireSpinLock(&kq->kq_lock, &irql); + + /* + * Traverse the list and make sure this workitem hasn't + * already been inserted. Queuing the same workitem + * twice will hose the list but good. + */ + + l = kq->kq_disp.nle_flink; + while (l != &kq->kq_disp) { + cur = CONTAINING_RECORD(l, io_workitem, iw_listentry); + if (cur == iw) { + /* Already queued -- do nothing. */ + KeReleaseSpinLock(&kq->kq_lock, irql); + return; + } + l = l->nle_flink; + } + + iw->iw_func = iw_func; + iw->iw_ctx = ctx; + + InsertTailList((&kq->kq_disp), (&iw->iw_listentry)); + KeReleaseSpinLock(&kq->kq_lock, irql); + + KeSetEvent(&kq->kq_proc, IO_NO_INCREMENT, FALSE); +} + +static void +ntoskrnl_workitem(dobj, arg) + device_object *dobj; + void *arg; +{ + io_workitem *iw; + work_queue_item *w; + work_item_func f; + + iw = arg; + w = (work_queue_item *)dobj; + f = (work_item_func)w->wqi_func; + uma_zfree(iw_zone, iw); + MSCALL2(f, w, w->wqi_ctx); +} + +/* + * The ExQueueWorkItem() API is deprecated in Windows XP. Microsoft + * warns that it's unsafe and to use IoQueueWorkItem() instead. The + * problem with ExQueueWorkItem() is that it can't guard against + * the condition where a driver submits a job to the work queue and + * is then unloaded before the job is able to run. IoQueueWorkItem() + * acquires a reference to the device's device_object via the + * object manager and retains it until after the job has completed, + * which prevents the driver from being unloaded before the job + * runs. (We don't currently support this behavior, though hopefully + * that will change once the object manager API is fleshed out a bit.) + * + * Having said all that, the ExQueueWorkItem() API remains, because + * there are still other parts of Windows that use it, including + * NDIS itself: NdisScheduleWorkItem() calls ExQueueWorkItem(). + * We fake up the ExQueueWorkItem() API on top of our implementation + * of IoQueueWorkItem(). Workitem thread #3 is reserved exclusively + * for ExQueueWorkItem() jobs, and we pass a pointer to the work + * queue item (provided by the caller) in to IoAllocateWorkItem() + * instead of the device_object. We need to save this pointer so + * we can apply a sanity check: as with the DPC queue and other + * workitem queues, we can't allow the same work queue item to + * be queued twice. If it's already pending, we silently return + */ + +void +ExQueueWorkItem(w, qtype) + work_queue_item *w; + uint32_t qtype; +{ + io_workitem *iw; + io_workitem_func iwf; + kdpc_queue *kq; + list_entry *l; + io_workitem *cur; + uint8_t irql; + + + /* + * We need to do a special sanity test to make sure + * the ExQueueWorkItem() API isn't used to queue + * the same workitem twice. Rather than checking the + * io_workitem pointer itself, we test the attached + * device object, which is really a pointer to the + * legacy work queue item structure. + */ + + kq = wq_queues + WORKITEM_LEGACY_THREAD; + KeAcquireSpinLock(&kq->kq_lock, &irql); + l = kq->kq_disp.nle_flink; + while (l != &kq->kq_disp) { + cur = CONTAINING_RECORD(l, io_workitem, iw_listentry); + if (cur->iw_dobj == (device_object *)w) { + /* Already queued -- do nothing. */ + KeReleaseSpinLock(&kq->kq_lock, irql); + return; + } + l = l->nle_flink; + } + KeReleaseSpinLock(&kq->kq_lock, irql); + + iw = IoAllocateWorkItem((device_object *)w); + if (iw == NULL) + return; + + iw->iw_idx = WORKITEM_LEGACY_THREAD; + iwf = (io_workitem_func)ntoskrnl_findwrap((funcptr)ntoskrnl_workitem); + IoQueueWorkItem(iw, iwf, qtype, iw); +} + +static void +RtlZeroMemory(dst, len) + void *dst; + size_t len; +{ + bzero(dst, len); +} + +static void +RtlSecureZeroMemory(dst, len) + void *dst; + size_t len; +{ + memset(dst, 0, len); +} + +static void +RtlFillMemory(void *dst, size_t len, uint8_t c) +{ + memset(dst, c, len); +} + +static void +RtlMoveMemory(dst, src, len) + void *dst; + const void *src; + size_t len; +{ + memmove(dst, src, len); +} + +static void +RtlCopyMemory(dst, src, len) + void *dst; + const void *src; + size_t len; +{ + bcopy(src, dst, len); +} + +static size_t +RtlCompareMemory(s1, s2, len) + const void *s1; + const void *s2; + size_t len; +{ + size_t i; + uint8_t *m1, *m2; + + m1 = __DECONST(char *, s1); + m2 = __DECONST(char *, s2); + + for (i = 0; i < len && m1[i] == m2[i]; i++); + return (i); +} + +void +RtlInitAnsiString(dst, src) + ansi_string *dst; + char *src; +{ + ansi_string *a; + + a = dst; + if (a == NULL) + return; + if (src == NULL) { + a->as_len = a->as_maxlen = 0; + a->as_buf = NULL; + } else { + a->as_buf = src; + a->as_len = a->as_maxlen = strlen(src); + } +} + +void +RtlInitUnicodeString(dst, src) + unicode_string *dst; + uint16_t *src; +{ + unicode_string *u; + int i; + + u = dst; + if (u == NULL) + return; + if (src == NULL) { + u->us_len = u->us_maxlen = 0; + u->us_buf = NULL; + } else { + i = 0; + while(src[i] != 0) + i++; + u->us_buf = src; + u->us_len = u->us_maxlen = i * 2; + } +} + +ndis_status +RtlUnicodeStringToInteger(ustr, base, val) + unicode_string *ustr; + uint32_t base; + uint32_t *val; +{ + uint16_t *uchr; + int len, neg = 0; + char abuf[64]; + char *astr; + + uchr = ustr->us_buf; + len = ustr->us_len; + bzero(abuf, sizeof(abuf)); + + if ((char)((*uchr) & 0xFF) == '-') { + neg = 1; + uchr++; + len -= 2; + } else if ((char)((*uchr) & 0xFF) == '+') { + neg = 0; + uchr++; + len -= 2; + } + + if (base == 0) { + if ((char)((*uchr) & 0xFF) == 'b') { + base = 2; + uchr++; + len -= 2; + } else if ((char)((*uchr) & 0xFF) == 'o') { + base = 8; + uchr++; + len -= 2; + } else if ((char)((*uchr) & 0xFF) == 'x') { + base = 16; + uchr++; + len -= 2; + } else + base = 10; + } + + astr = abuf; + if (neg) { + strcpy(astr, "-"); + astr++; + } + + ntoskrnl_unicode_to_ascii(uchr, astr, len); + *val = strtoul(abuf, NULL, base); + + return (STATUS_SUCCESS); +} + +void +RtlFreeUnicodeString(ustr) + unicode_string *ustr; +{ + if (ustr->us_buf == NULL) + return; + ExFreePool(ustr->us_buf); + ustr->us_buf = NULL; +} + +void +RtlFreeAnsiString(astr) + ansi_string *astr; +{ + if (astr->as_buf == NULL) + return; + ExFreePool(astr->as_buf); + astr->as_buf = NULL; +} + +static int +atoi(str) + const char *str; +{ + return (int)strtol(str, (char **)NULL, 10); +} + +static long +atol(str) + const char *str; +{ + return strtol(str, (char **)NULL, 10); +} + +static int +rand(void) +{ + struct timeval tv; + + microtime(&tv); + srandom(tv.tv_usec); + return ((int)random()); +} + +static void +srand(seed) + unsigned int seed; +{ + srandom(seed); +} + +static uint8_t +IoIsWdmVersionAvailable(uint8_t major, uint8_t minor) +{ + if (major == WDM_MAJOR && minor == WDM_MINOR_WINXP) + return (TRUE); + return (FALSE); +} + +static int32_t +IoOpenDeviceRegistryKey(struct device_object *devobj, uint32_t type, + uint32_t mask, void **key) +{ + return (NDIS_STATUS_INVALID_DEVICE_REQUEST); +} + +static ndis_status +IoGetDeviceObjectPointer(name, reqaccess, fileobj, devobj) + unicode_string *name; + uint32_t reqaccess; + void *fileobj; + device_object *devobj; +{ + return (STATUS_SUCCESS); +} + +static ndis_status +IoGetDeviceProperty(devobj, regprop, buflen, prop, reslen) + device_object *devobj; + uint32_t regprop; + uint32_t buflen; + void *prop; + uint32_t *reslen; +{ + driver_object *drv; + uint16_t **name; + + drv = devobj->do_drvobj; + + switch (regprop) { + case DEVPROP_DRIVER_KEYNAME: + name = prop; + *name = drv->dro_drivername.us_buf; + *reslen = drv->dro_drivername.us_len; + break; + default: + return (STATUS_INVALID_PARAMETER_2); + break; + } + + return (STATUS_SUCCESS); +} + +static void +KeInitializeMutex(kmutex, level) + kmutant *kmutex; + uint32_t level; +{ + InitializeListHead((&kmutex->km_header.dh_waitlisthead)); + kmutex->km_abandoned = FALSE; + kmutex->km_apcdisable = 1; + kmutex->km_header.dh_sigstate = 1; + kmutex->km_header.dh_type = DISP_TYPE_MUTANT; + kmutex->km_header.dh_size = sizeof(kmutant) / sizeof(uint32_t); + kmutex->km_ownerthread = NULL; +} + +static uint32_t +KeReleaseMutex(kmutant *kmutex, uint8_t kwait) +{ + uint32_t prevstate; + + mtx_lock(&ntoskrnl_dispatchlock); + prevstate = kmutex->km_header.dh_sigstate; + if (kmutex->km_ownerthread != curthread) { + mtx_unlock(&ntoskrnl_dispatchlock); + return (STATUS_MUTANT_NOT_OWNED); + } + + kmutex->km_header.dh_sigstate++; + kmutex->km_abandoned = FALSE; + + if (kmutex->km_header.dh_sigstate == 1) { + kmutex->km_ownerthread = NULL; + ntoskrnl_waittest(&kmutex->km_header, IO_NO_INCREMENT); + } + + mtx_unlock(&ntoskrnl_dispatchlock); + + return (prevstate); +} + +static uint32_t +KeReadStateMutex(kmutex) + kmutant *kmutex; +{ + return (kmutex->km_header.dh_sigstate); +} + +void +KeInitializeEvent(nt_kevent *kevent, uint32_t type, uint8_t state) +{ + InitializeListHead((&kevent->k_header.dh_waitlisthead)); + kevent->k_header.dh_sigstate = state; + if (type == EVENT_TYPE_NOTIFY) + kevent->k_header.dh_type = DISP_TYPE_NOTIFICATION_EVENT; + else + kevent->k_header.dh_type = DISP_TYPE_SYNCHRONIZATION_EVENT; + kevent->k_header.dh_size = sizeof(nt_kevent) / sizeof(uint32_t); +} + +uint32_t +KeResetEvent(kevent) + nt_kevent *kevent; +{ + uint32_t prevstate; + + mtx_lock(&ntoskrnl_dispatchlock); + prevstate = kevent->k_header.dh_sigstate; + kevent->k_header.dh_sigstate = FALSE; + mtx_unlock(&ntoskrnl_dispatchlock); + + return (prevstate); +} + +uint32_t +KeSetEvent(nt_kevent *kevent, uint32_t increment, uint8_t kwait) +{ + uint32_t prevstate; + wait_block *w; + nt_dispatch_header *dh; + struct thread *td; + wb_ext *we; + + mtx_lock(&ntoskrnl_dispatchlock); + prevstate = kevent->k_header.dh_sigstate; + dh = &kevent->k_header; + + if (IsListEmpty(&dh->dh_waitlisthead)) + /* + * If there's nobody in the waitlist, just set + * the state to signalled. + */ + dh->dh_sigstate = 1; + else { + /* + * Get the first waiter. If this is a synchronization + * event, just wake up that one thread (don't bother + * setting the state to signalled since we're supposed + * to automatically clear synchronization events anyway). + * + * If it's a notification event, or the first + * waiter is doing a WAITTYPE_ALL wait, go through + * the full wait satisfaction process. + */ + w = CONTAINING_RECORD(dh->dh_waitlisthead.nle_flink, + wait_block, wb_waitlist); + we = w->wb_ext; + td = we->we_td; + if (kevent->k_header.dh_type == DISP_TYPE_NOTIFICATION_EVENT || + w->wb_waittype == WAITTYPE_ALL) { + if (prevstate == 0) { + dh->dh_sigstate = 1; + ntoskrnl_waittest(dh, increment); + } + } else { + w->wb_awakened |= TRUE; + cv_broadcastpri(&we->we_cv, + (w->wb_oldpri - (increment * 4)) > PRI_MIN_KERN ? + w->wb_oldpri - (increment * 4) : PRI_MIN_KERN); + } + } + + mtx_unlock(&ntoskrnl_dispatchlock); + + return (prevstate); +} + +void +KeClearEvent(kevent) + nt_kevent *kevent; +{ + kevent->k_header.dh_sigstate = FALSE; +} + +uint32_t +KeReadStateEvent(kevent) + nt_kevent *kevent; +{ + return (kevent->k_header.dh_sigstate); +} + +/* + * The object manager in Windows is responsible for managing + * references and access to various types of objects, including + * device_objects, events, threads, timers and so on. However, + * there's a difference in the way objects are handled in user + * mode versus kernel mode. + * + * In user mode (i.e. Win32 applications), all objects are + * managed by the object manager. For example, when you create + * a timer or event object, you actually end up with an + * object_header (for the object manager's bookkeeping + * purposes) and an object body (which contains the actual object + * structure, e.g. ktimer, kevent, etc...). This allows Windows + * to manage resource quotas and to enforce access restrictions + * on basically every kind of system object handled by the kernel. + * + * However, in kernel mode, you only end up using the object + * manager some of the time. For example, in a driver, you create + * a timer object by simply allocating the memory for a ktimer + * structure and initializing it with KeInitializeTimer(). Hence, + * the timer has no object_header and no reference counting or + * security/resource checks are done on it. The assumption in + * this case is that if you're running in kernel mode, you know + * what you're doing, and you're already at an elevated privilege + * anyway. + * + * There are some exceptions to this. The two most important ones + * for our purposes are device_objects and threads. We need to use + * the object manager to do reference counting on device_objects, + * and for threads, you can only get a pointer to a thread's + * dispatch header by using ObReferenceObjectByHandle() on the + * handle returned by PsCreateSystemThread(). + */ + +static ndis_status +ObReferenceObjectByHandle(ndis_handle handle, uint32_t reqaccess, void *otype, + uint8_t accessmode, void **object, void **handleinfo) +{ + nt_objref *nr; + + nr = malloc(sizeof(nt_objref), M_DEVBUF, M_NOWAIT|M_ZERO); + if (nr == NULL) + return (STATUS_INSUFFICIENT_RESOURCES); + + InitializeListHead((&nr->no_dh.dh_waitlisthead)); + nr->no_obj = handle; + nr->no_dh.dh_type = DISP_TYPE_THREAD; + nr->no_dh.dh_sigstate = 0; + nr->no_dh.dh_size = (uint8_t)(sizeof(struct thread) / + sizeof(uint32_t)); + TAILQ_INSERT_TAIL(&ntoskrnl_reflist, nr, link); + *object = nr; + + return (STATUS_SUCCESS); +} + +static void +ObfDereferenceObject(object) + void *object; +{ + nt_objref *nr; + + nr = object; + TAILQ_REMOVE(&ntoskrnl_reflist, nr, link); + free(nr, M_DEVBUF); +} + +static uint32_t +ZwClose(handle) + ndis_handle handle; +{ + return (STATUS_SUCCESS); +} + +static uint32_t +WmiQueryTraceInformation(traceclass, traceinfo, infolen, reqlen, buf) + uint32_t traceclass; + void *traceinfo; + uint32_t infolen; + uint32_t reqlen; + void *buf; +{ + return (STATUS_NOT_FOUND); +} + +static uint32_t +WmiTraceMessage(uint64_t loghandle, uint32_t messageflags, + void *guid, uint16_t messagenum, ...) +{ + return (STATUS_SUCCESS); +} + +static uint32_t +IoWMIRegistrationControl(dobj, action) + device_object *dobj; + uint32_t action; +{ + return (STATUS_SUCCESS); +} + +/* + * This is here just in case the thread returns without calling + * PsTerminateSystemThread(). + */ +static void +ntoskrnl_thrfunc(arg) + void *arg; +{ + thread_context *thrctx; + uint32_t (*tfunc)(void *); + void *tctx; + uint32_t rval; + + thrctx = arg; + tfunc = thrctx->tc_thrfunc; + tctx = thrctx->tc_thrctx; + free(thrctx, M_TEMP); + + rval = MSCALL1(tfunc, tctx); + + PsTerminateSystemThread(rval); + return; /* notreached */ +} + +static ndis_status +PsCreateSystemThread(handle, reqaccess, objattrs, phandle, + clientid, thrfunc, thrctx) + ndis_handle *handle; + uint32_t reqaccess; + void *objattrs; + ndis_handle phandle; + void *clientid; + void *thrfunc; + void *thrctx; +{ + int error; + thread_context *tc; + struct proc *p; + + tc = malloc(sizeof(thread_context), M_TEMP, M_NOWAIT); + if (tc == NULL) + return (STATUS_INSUFFICIENT_RESOURCES); + + tc->tc_thrctx = thrctx; + tc->tc_thrfunc = thrfunc; + + error = kproc_create(ntoskrnl_thrfunc, tc, &p, + RFHIGHPID, NDIS_KSTACK_PAGES, "Windows Kthread %d", ntoskrnl_kth); + + if (error) { + free(tc, M_TEMP); + return (STATUS_INSUFFICIENT_RESOURCES); + } + + *handle = p; + ntoskrnl_kth++; + + return (STATUS_SUCCESS); +} + +/* + * In Windows, the exit of a thread is an event that you're allowed + * to wait on, assuming you've obtained a reference to the thread using + * ObReferenceObjectByHandle(). Unfortunately, the only way we can + * simulate this behavior is to register each thread we create in a + * reference list, and if someone holds a reference to us, we poke + * them. + */ +static ndis_status +PsTerminateSystemThread(status) + ndis_status status; +{ + struct nt_objref *nr; + + mtx_lock(&ntoskrnl_dispatchlock); + TAILQ_FOREACH(nr, &ntoskrnl_reflist, link) { + if (nr->no_obj != curthread->td_proc) + continue; + nr->no_dh.dh_sigstate = 1; + ntoskrnl_waittest(&nr->no_dh, IO_NO_INCREMENT); + break; + } + mtx_unlock(&ntoskrnl_dispatchlock); + + ntoskrnl_kth--; + + kproc_exit(0); + return (0); /* notreached */ +} + +static uint32_t +DbgPrint(char *fmt, ...) +{ + va_list ap; + + if (bootverbose) { + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + } + + return (STATUS_SUCCESS); +} + +static void +DbgBreakPoint(void) +{ + + kdb_enter(KDB_WHY_NDIS, "DbgBreakPoint(): breakpoint"); +} + +static void +KeBugCheckEx(code, param1, param2, param3, param4) + uint32_t code; + u_long param1; + u_long param2; + u_long param3; + u_long param4; +{ + panic("KeBugCheckEx: STOP 0x%X", code); +} + +static void +ntoskrnl_timercall(arg) + void *arg; +{ + ktimer *timer; + struct timeval tv; + kdpc *dpc; + + mtx_lock(&ntoskrnl_dispatchlock); + + timer = arg; + +#ifdef NTOSKRNL_DEBUG_TIMERS + ntoskrnl_timer_fires++; +#endif + ntoskrnl_remove_timer(timer); + + /* + * This should never happen, but complain + * if it does. + */ + + if (timer->k_header.dh_inserted == FALSE) { + mtx_unlock(&ntoskrnl_dispatchlock); + printf("NTOS: timer %p fired even though " + "it was canceled\n", timer); + return; + } + + /* Mark the timer as no longer being on the timer queue. */ + + timer->k_header.dh_inserted = FALSE; + + /* Now signal the object and satisfy any waits on it. */ + + timer->k_header.dh_sigstate = 1; + ntoskrnl_waittest(&timer->k_header, IO_NO_INCREMENT); + + /* + * If this is a periodic timer, re-arm it + * so it will fire again. We do this before + * calling any deferred procedure calls because + * it's possible the DPC might cancel the timer, + * in which case it would be wrong for us to + * re-arm it again afterwards. + */ + + if (timer->k_period) { + tv.tv_sec = 0; + tv.tv_usec = timer->k_period * 1000; + timer->k_header.dh_inserted = TRUE; + ntoskrnl_insert_timer(timer, tvtohz(&tv)); +#ifdef NTOSKRNL_DEBUG_TIMERS + ntoskrnl_timer_reloads++; +#endif + } + + dpc = timer->k_dpc; + + mtx_unlock(&ntoskrnl_dispatchlock); + + /* If there's a DPC associated with the timer, queue it up. */ + + if (dpc != NULL) + KeInsertQueueDpc(dpc, NULL, NULL); +} + +#ifdef NTOSKRNL_DEBUG_TIMERS +static int +sysctl_show_timers(SYSCTL_HANDLER_ARGS) +{ + int ret; + + ret = 0; + ntoskrnl_show_timers(); + return (sysctl_handle_int(oidp, &ret, 0, req)); +} + +static void +ntoskrnl_show_timers() +{ + int i = 0; + list_entry *l; + + mtx_lock_spin(&ntoskrnl_calllock); + l = ntoskrnl_calllist.nle_flink; + while(l != &ntoskrnl_calllist) { + i++; + l = l->nle_flink; + } + mtx_unlock_spin(&ntoskrnl_calllock); + + printf("\n"); + printf("%d timers available (out of %d)\n", i, NTOSKRNL_TIMEOUTS); + printf("timer sets: %qu\n", ntoskrnl_timer_sets); + printf("timer reloads: %qu\n", ntoskrnl_timer_reloads); + printf("timer cancels: %qu\n", ntoskrnl_timer_cancels); + printf("timer fires: %qu\n", ntoskrnl_timer_fires); + printf("\n"); +} +#endif + +/* + * Must be called with dispatcher lock held. + */ + +static void +ntoskrnl_insert_timer(timer, ticks) + ktimer *timer; + int ticks; +{ + callout_entry *e; + list_entry *l; + struct callout *c; + + /* + * Try and allocate a timer. + */ + mtx_lock_spin(&ntoskrnl_calllock); + if (IsListEmpty(&ntoskrnl_calllist)) { + mtx_unlock_spin(&ntoskrnl_calllock); +#ifdef NTOSKRNL_DEBUG_TIMERS + ntoskrnl_show_timers(); +#endif + panic("out of timers!"); + } + l = RemoveHeadList(&ntoskrnl_calllist); + mtx_unlock_spin(&ntoskrnl_calllock); + + e = CONTAINING_RECORD(l, callout_entry, ce_list); + c = &e->ce_callout; + + timer->k_callout = c; + + callout_init(c, CALLOUT_MPSAFE); + callout_reset(c, ticks, ntoskrnl_timercall, timer); +} + +static void +ntoskrnl_remove_timer(timer) + ktimer *timer; +{ + callout_entry *e; + + e = (callout_entry *)timer->k_callout; + callout_stop(timer->k_callout); + + mtx_lock_spin(&ntoskrnl_calllock); + InsertHeadList((&ntoskrnl_calllist), (&e->ce_list)); + mtx_unlock_spin(&ntoskrnl_calllock); +} + +void +KeInitializeTimer(timer) + ktimer *timer; +{ + if (timer == NULL) + return; + + KeInitializeTimerEx(timer, EVENT_TYPE_NOTIFY); +} + +void +KeInitializeTimerEx(timer, type) + ktimer *timer; + uint32_t type; +{ + if (timer == NULL) + return; + + bzero((char *)timer, sizeof(ktimer)); + InitializeListHead((&timer->k_header.dh_waitlisthead)); + timer->k_header.dh_sigstate = FALSE; + timer->k_header.dh_inserted = FALSE; + if (type == EVENT_TYPE_NOTIFY) + timer->k_header.dh_type = DISP_TYPE_NOTIFICATION_TIMER; + else + timer->k_header.dh_type = DISP_TYPE_SYNCHRONIZATION_TIMER; + timer->k_header.dh_size = sizeof(ktimer) / sizeof(uint32_t); +} + +/* + * DPC subsystem. A Windows Defered Procedure Call has the following + * properties: + * - It runs at DISPATCH_LEVEL. + * - It can have one of 3 importance values that control when it + * runs relative to other DPCs in the queue. + * - On SMP systems, it can be set to run on a specific processor. + * In order to satisfy the last property, we create a DPC thread for + * each CPU in the system and bind it to that CPU. Each thread + * maintains three queues with different importance levels, which + * will be processed in order from lowest to highest. + * + * In Windows, interrupt handlers run as DPCs. (Not to be confused + * with ISRs, which run in interrupt context and can preempt DPCs.) + * ISRs are given the highest importance so that they'll take + * precedence over timers and other things. + */ + +static void +ntoskrnl_dpc_thread(arg) + void *arg; +{ + kdpc_queue *kq; + kdpc *d; + list_entry *l; + uint8_t irql; + + kq = arg; + + InitializeListHead(&kq->kq_disp); + kq->kq_td = curthread; + kq->kq_exit = 0; + kq->kq_running = FALSE; + KeInitializeSpinLock(&kq->kq_lock); + KeInitializeEvent(&kq->kq_proc, EVENT_TYPE_SYNC, FALSE); + KeInitializeEvent(&kq->kq_done, EVENT_TYPE_SYNC, FALSE); + + /* + * Elevate our priority. DPCs are used to run interrupt + * handlers, and they should trigger as soon as possible + * once scheduled by an ISR. + */ + + thread_lock(curthread); +#ifdef NTOSKRNL_MULTIPLE_DPCS + sched_bind(curthread, kq->kq_cpu); +#endif + sched_prio(curthread, PRI_MIN_KERN); + thread_unlock(curthread); + + while (1) { + KeWaitForSingleObject(&kq->kq_proc, 0, 0, TRUE, NULL); + + KeAcquireSpinLock(&kq->kq_lock, &irql); + + if (kq->kq_exit) { + kq->kq_exit = 0; + KeReleaseSpinLock(&kq->kq_lock, irql); + break; + } + + kq->kq_running = TRUE; + + while (!IsListEmpty(&kq->kq_disp)) { + l = RemoveHeadList((&kq->kq_disp)); + d = CONTAINING_RECORD(l, kdpc, k_dpclistentry); + InitializeListHead((&d->k_dpclistentry)); + KeReleaseSpinLockFromDpcLevel(&kq->kq_lock); + MSCALL4(d->k_deferedfunc, d, d->k_deferredctx, + d->k_sysarg1, d->k_sysarg2); + KeAcquireSpinLockAtDpcLevel(&kq->kq_lock); + } + + kq->kq_running = FALSE; + + KeReleaseSpinLock(&kq->kq_lock, irql); + + KeSetEvent(&kq->kq_done, IO_NO_INCREMENT, FALSE); + } + + kproc_exit(0); + return; /* notreached */ +} + +static void +ntoskrnl_destroy_dpc_threads(void) +{ + kdpc_queue *kq; + kdpc dpc; + int i; + + kq = kq_queues; +#ifdef NTOSKRNL_MULTIPLE_DPCS + for (i = 0; i < mp_ncpus; i++) { +#else + for (i = 0; i < 1; i++) { +#endif + kq += i; + + kq->kq_exit = 1; + KeInitializeDpc(&dpc, NULL, NULL); + KeSetTargetProcessorDpc(&dpc, i); + KeInsertQueueDpc(&dpc, NULL, NULL); + while (kq->kq_exit) + tsleep(kq->kq_td->td_proc, PWAIT, "dpcw", hz/10); + } +} + +static uint8_t +ntoskrnl_insert_dpc(head, dpc) + list_entry *head; + kdpc *dpc; +{ + list_entry *l; + kdpc *d; + + l = head->nle_flink; + while (l != head) { + d = CONTAINING_RECORD(l, kdpc, k_dpclistentry); + if (d == dpc) + return (FALSE); + l = l->nle_flink; + } + + if (dpc->k_importance == KDPC_IMPORTANCE_LOW) + InsertTailList((head), (&dpc->k_dpclistentry)); + else + InsertHeadList((head), (&dpc->k_dpclistentry)); + + return (TRUE); +} + +void +KeInitializeDpc(dpc, dpcfunc, dpcctx) + kdpc *dpc; + void *dpcfunc; + void *dpcctx; +{ + + if (dpc == NULL) + return; + + dpc->k_deferedfunc = dpcfunc; + dpc->k_deferredctx = dpcctx; + dpc->k_num = KDPC_CPU_DEFAULT; + dpc->k_importance = KDPC_IMPORTANCE_MEDIUM; + InitializeListHead((&dpc->k_dpclistentry)); +} + +uint8_t +KeInsertQueueDpc(dpc, sysarg1, sysarg2) + kdpc *dpc; + void *sysarg1; + void *sysarg2; +{ + kdpc_queue *kq; + uint8_t r; + uint8_t irql; + + if (dpc == NULL) + return (FALSE); + + kq = kq_queues; + +#ifdef NTOSKRNL_MULTIPLE_DPCS + KeRaiseIrql(DISPATCH_LEVEL, &irql); + + /* + * By default, the DPC is queued to run on the same CPU + * that scheduled it. + */ + + if (dpc->k_num == KDPC_CPU_DEFAULT) + kq += curthread->td_oncpu; + else + kq += dpc->k_num; + KeAcquireSpinLockAtDpcLevel(&kq->kq_lock); +#else + KeAcquireSpinLock(&kq->kq_lock, &irql); +#endif + + r = ntoskrnl_insert_dpc(&kq->kq_disp, dpc); + if (r == TRUE) { + dpc->k_sysarg1 = sysarg1; + dpc->k_sysarg2 = sysarg2; + } + KeReleaseSpinLock(&kq->kq_lock, irql); + + if (r == FALSE) + return (r); + + KeSetEvent(&kq->kq_proc, IO_NO_INCREMENT, FALSE); + + return (r); +} + +uint8_t +KeRemoveQueueDpc(dpc) + kdpc *dpc; +{ + kdpc_queue *kq; + uint8_t irql; + + if (dpc == NULL) + return (FALSE); + +#ifdef NTOSKRNL_MULTIPLE_DPCS + KeRaiseIrql(DISPATCH_LEVEL, &irql); + + kq = kq_queues + dpc->k_num; + + KeAcquireSpinLockAtDpcLevel(&kq->kq_lock); +#else + kq = kq_queues; + KeAcquireSpinLock(&kq->kq_lock, &irql); +#endif + + if (dpc->k_dpclistentry.nle_flink == &dpc->k_dpclistentry) { + KeReleaseSpinLockFromDpcLevel(&kq->kq_lock); + KeLowerIrql(irql); + return (FALSE); + } + + RemoveEntryList((&dpc->k_dpclistentry)); + InitializeListHead((&dpc->k_dpclistentry)); + + KeReleaseSpinLock(&kq->kq_lock, irql); + + return (TRUE); +} + +void +KeSetImportanceDpc(dpc, imp) + kdpc *dpc; + uint32_t imp; +{ + if (imp != KDPC_IMPORTANCE_LOW && + imp != KDPC_IMPORTANCE_MEDIUM && + imp != KDPC_IMPORTANCE_HIGH) + return; + + dpc->k_importance = (uint8_t)imp; +} + +void +KeSetTargetProcessorDpc(kdpc *dpc, uint8_t cpu) +{ + if (cpu > mp_ncpus) + return; + + dpc->k_num = cpu; +} + +void +KeFlushQueuedDpcs(void) +{ + kdpc_queue *kq; + int i; + + /* + * Poke each DPC queue and wait + * for them to drain. + */ + +#ifdef NTOSKRNL_MULTIPLE_DPCS + for (i = 0; i < mp_ncpus; i++) { +#else + for (i = 0; i < 1; i++) { +#endif + kq = kq_queues + i; + KeSetEvent(&kq->kq_proc, IO_NO_INCREMENT, FALSE); + KeWaitForSingleObject(&kq->kq_done, 0, 0, TRUE, NULL); + } +} + +uint32_t +KeGetCurrentProcessorNumber(void) +{ + return ((uint32_t)curthread->td_oncpu); +} + +uint8_t +KeSetTimerEx(timer, duetime, period, dpc) + ktimer *timer; + int64_t duetime; + uint32_t period; + kdpc *dpc; +{ + struct timeval tv; + uint64_t curtime; + uint8_t pending; + + if (timer == NULL) + return (FALSE); + + mtx_lock(&ntoskrnl_dispatchlock); + + if (timer->k_header.dh_inserted == TRUE) { + ntoskrnl_remove_timer(timer); +#ifdef NTOSKRNL_DEBUG_TIMERS + ntoskrnl_timer_cancels++; +#endif + timer->k_header.dh_inserted = FALSE; + pending = TRUE; + } else + pending = FALSE; + + timer->k_duetime = duetime; + timer->k_period = period; + timer->k_header.dh_sigstate = FALSE; + timer->k_dpc = dpc; + + if (duetime < 0) { + tv.tv_sec = - (duetime) / 10000000; + tv.tv_usec = (- (duetime) / 10) - + (tv.tv_sec * 1000000); + } else { + ntoskrnl_time(&curtime); + if (duetime < curtime) + tv.tv_sec = tv.tv_usec = 0; + else { + tv.tv_sec = ((duetime) - curtime) / 10000000; + tv.tv_usec = ((duetime) - curtime) / 10 - + (tv.tv_sec * 1000000); + } + } + + timer->k_header.dh_inserted = TRUE; + ntoskrnl_insert_timer(timer, tvtohz(&tv)); +#ifdef NTOSKRNL_DEBUG_TIMERS + ntoskrnl_timer_sets++; +#endif + + mtx_unlock(&ntoskrnl_dispatchlock); + + return (pending); +} + +uint8_t +KeSetTimer(timer, duetime, dpc) + ktimer *timer; + int64_t duetime; + kdpc *dpc; +{ + return (KeSetTimerEx(timer, duetime, 0, dpc)); +} + +/* + * The Windows DDK documentation seems to say that cancelling + * a timer that has a DPC will result in the DPC also being + * cancelled, but this isn't really the case. + */ + +uint8_t +KeCancelTimer(timer) + ktimer *timer; +{ + uint8_t pending; + + if (timer == NULL) + return (FALSE); + + mtx_lock(&ntoskrnl_dispatchlock); + + pending = timer->k_header.dh_inserted; + + if (timer->k_header.dh_inserted == TRUE) { + timer->k_header.dh_inserted = FALSE; + ntoskrnl_remove_timer(timer); +#ifdef NTOSKRNL_DEBUG_TIMERS + ntoskrnl_timer_cancels++; +#endif + } + + mtx_unlock(&ntoskrnl_dispatchlock); + + return (pending); +} + +uint8_t +KeReadStateTimer(timer) + ktimer *timer; +{ + return (timer->k_header.dh_sigstate); +} + +static int32_t +KeDelayExecutionThread(uint8_t wait_mode, uint8_t alertable, int64_t *interval) +{ + ktimer timer; + + if (wait_mode != 0) + panic("invalid wait_mode %d", wait_mode); + + KeInitializeTimer(&timer); + KeSetTimer(&timer, *interval, NULL); + KeWaitForSingleObject(&timer, 0, 0, alertable, NULL); + + return STATUS_SUCCESS; +} + +static uint64_t +KeQueryInterruptTime(void) +{ + int ticks; + struct timeval tv; + + getmicrouptime(&tv); + + ticks = tvtohz(&tv); + + return ticks * ((10000000 + hz - 1) / hz); +} + +static struct thread * +KeGetCurrentThread(void) +{ + + return curthread; +} + +static int32_t +KeSetPriorityThread(td, pri) + struct thread *td; + int32_t pri; +{ + int32_t old; + + if (td == NULL) + return LOW_REALTIME_PRIORITY; + + if (td->td_priority <= PRI_MIN_KERN) + old = HIGH_PRIORITY; + else if (td->td_priority >= PRI_MAX_KERN) + old = LOW_PRIORITY; + else + old = LOW_REALTIME_PRIORITY; + + thread_lock(td); + if (pri == HIGH_PRIORITY) + sched_prio(td, PRI_MIN_KERN); + if (pri == LOW_REALTIME_PRIORITY) + sched_prio(td, PRI_MIN_KERN + (PRI_MAX_KERN - PRI_MIN_KERN) / 2); + if (pri == LOW_PRIORITY) + sched_prio(td, PRI_MAX_KERN); + thread_unlock(td); + + return old; +} + +static void +dummy() +{ + printf("ntoskrnl dummy called...\n"); +} + + +image_patch_table ntoskrnl_functbl[] = { + IMPORT_SFUNC(RtlZeroMemory, 2), + IMPORT_SFUNC(RtlSecureZeroMemory, 2), + IMPORT_SFUNC(RtlFillMemory, 3), + IMPORT_SFUNC(RtlMoveMemory, 3), + IMPORT_SFUNC(RtlCharToInteger, 3), + IMPORT_SFUNC(RtlCopyMemory, 3), + IMPORT_SFUNC(RtlCopyString, 2), + IMPORT_SFUNC(RtlCompareMemory, 3), + IMPORT_SFUNC(RtlEqualUnicodeString, 3), + IMPORT_SFUNC(RtlCopyUnicodeString, 2), + IMPORT_SFUNC(RtlUnicodeStringToAnsiString, 3), + IMPORT_SFUNC(RtlAnsiStringToUnicodeString, 3), + IMPORT_SFUNC(RtlInitAnsiString, 2), + IMPORT_SFUNC_MAP(RtlInitString, RtlInitAnsiString, 2), + IMPORT_SFUNC(RtlInitUnicodeString, 2), + IMPORT_SFUNC(RtlFreeAnsiString, 1), + IMPORT_SFUNC(RtlFreeUnicodeString, 1), + IMPORT_SFUNC(RtlUnicodeStringToInteger, 3), + IMPORT_CFUNC(sprintf, 0), + IMPORT_CFUNC(vsprintf, 0), + IMPORT_CFUNC_MAP(_snprintf, snprintf, 0), + IMPORT_CFUNC_MAP(_vsnprintf, vsnprintf, 0), + IMPORT_CFUNC(DbgPrint, 0), + IMPORT_SFUNC(DbgBreakPoint, 0), + IMPORT_SFUNC(KeBugCheckEx, 5), + IMPORT_CFUNC(strncmp, 0), + IMPORT_CFUNC(strcmp, 0), + IMPORT_CFUNC_MAP(stricmp, strcasecmp, 0), + IMPORT_CFUNC(strncpy, 0), + IMPORT_CFUNC(strcpy, 0), + IMPORT_CFUNC(strlen, 0), + IMPORT_CFUNC_MAP(toupper, ntoskrnl_toupper, 0), + IMPORT_CFUNC_MAP(tolower, ntoskrnl_tolower, 0), + IMPORT_CFUNC_MAP(strstr, ntoskrnl_strstr, 0), + IMPORT_CFUNC_MAP(strncat, ntoskrnl_strncat, 0), + IMPORT_CFUNC_MAP(strchr, index, 0), + IMPORT_CFUNC_MAP(strrchr, rindex, 0), + IMPORT_CFUNC(memcpy, 0), + IMPORT_CFUNC_MAP(memmove, ntoskrnl_memmove, 0), + IMPORT_CFUNC_MAP(memset, ntoskrnl_memset, 0), + IMPORT_CFUNC_MAP(memchr, ntoskrnl_memchr, 0), + IMPORT_SFUNC(IoAllocateDriverObjectExtension, 4), + IMPORT_SFUNC(IoGetDriverObjectExtension, 2), + IMPORT_FFUNC(IofCallDriver, 2), + IMPORT_FFUNC(IofCompleteRequest, 2), + IMPORT_SFUNC(IoAcquireCancelSpinLock, 1), + IMPORT_SFUNC(IoReleaseCancelSpinLock, 1), + IMPORT_SFUNC(IoCancelIrp, 1), + IMPORT_SFUNC(IoConnectInterrupt, 11), + IMPORT_SFUNC(IoDisconnectInterrupt, 1), + IMPORT_SFUNC(IoCreateDevice, 7), + IMPORT_SFUNC(IoDeleteDevice, 1), + IMPORT_SFUNC(IoGetAttachedDevice, 1), + IMPORT_SFUNC(IoAttachDeviceToDeviceStack, 2), + IMPORT_SFUNC(IoDetachDevice, 1), + IMPORT_SFUNC(IoBuildSynchronousFsdRequest, 7), + IMPORT_SFUNC(IoBuildAsynchronousFsdRequest, 6), + IMPORT_SFUNC(IoBuildDeviceIoControlRequest, 9), + IMPORT_SFUNC(IoAllocateIrp, 2), + IMPORT_SFUNC(IoReuseIrp, 2), + IMPORT_SFUNC(IoMakeAssociatedIrp, 2), + IMPORT_SFUNC(IoFreeIrp, 1), + IMPORT_SFUNC(IoInitializeIrp, 3), + IMPORT_SFUNC(KeAcquireInterruptSpinLock, 1), + IMPORT_SFUNC(KeReleaseInterruptSpinLock, 2), + IMPORT_SFUNC(KeSynchronizeExecution, 3), + IMPORT_SFUNC(KeWaitForSingleObject, 5), + IMPORT_SFUNC(KeWaitForMultipleObjects, 8), + IMPORT_SFUNC(_allmul, 4), + IMPORT_SFUNC(_alldiv, 4), + IMPORT_SFUNC(_allrem, 4), + IMPORT_RFUNC(_allshr, 0), + IMPORT_RFUNC(_allshl, 0), + IMPORT_SFUNC(_aullmul, 4), + IMPORT_SFUNC(_aulldiv, 4), + IMPORT_SFUNC(_aullrem, 4), + IMPORT_RFUNC(_aullshr, 0), + IMPORT_RFUNC(_aullshl, 0), + IMPORT_CFUNC(atoi, 0), + IMPORT_CFUNC(atol, 0), + IMPORT_CFUNC(rand, 0), + IMPORT_CFUNC(srand, 0), + IMPORT_SFUNC(WRITE_REGISTER_USHORT, 2), + IMPORT_SFUNC(READ_REGISTER_USHORT, 1), + IMPORT_SFUNC(WRITE_REGISTER_ULONG, 2), + IMPORT_SFUNC(READ_REGISTER_ULONG, 1), + IMPORT_SFUNC(READ_REGISTER_UCHAR, 1), + IMPORT_SFUNC(WRITE_REGISTER_UCHAR, 2), + IMPORT_SFUNC(ExInitializePagedLookasideList, 7), + IMPORT_SFUNC(ExDeletePagedLookasideList, 1), + IMPORT_SFUNC(ExInitializeNPagedLookasideList, 7), + IMPORT_SFUNC(ExDeleteNPagedLookasideList, 1), + IMPORT_FFUNC(InterlockedPopEntrySList, 1), + IMPORT_FFUNC(InitializeSListHead, 1), + IMPORT_FFUNC(InterlockedPushEntrySList, 2), + IMPORT_SFUNC(ExQueryDepthSList, 1), + IMPORT_FFUNC_MAP(ExpInterlockedPopEntrySList, + InterlockedPopEntrySList, 1), + IMPORT_FFUNC_MAP(ExpInterlockedPushEntrySList, + InterlockedPushEntrySList, 2), + IMPORT_FFUNC(ExInterlockedPopEntrySList, 2), + IMPORT_FFUNC(ExInterlockedPushEntrySList, 3), + IMPORT_SFUNC(ExAllocatePoolWithTag, 3), + IMPORT_SFUNC(ExFreePoolWithTag, 2), + IMPORT_SFUNC(ExFreePool, 1), +#ifdef __i386__ + IMPORT_FFUNC(KefAcquireSpinLockAtDpcLevel, 1), + IMPORT_FFUNC(KefReleaseSpinLockFromDpcLevel,1), + IMPORT_FFUNC(KeAcquireSpinLockRaiseToDpc, 1), +#else + /* + * For AMD64, we can get away with just mapping + * KeAcquireSpinLockRaiseToDpc() directly to KfAcquireSpinLock() + * because the calling conventions end up being the same. + * On i386, we have to be careful because KfAcquireSpinLock() + * is _fastcall but KeAcquireSpinLockRaiseToDpc() isn't. + */ + IMPORT_SFUNC(KeAcquireSpinLockAtDpcLevel, 1), + IMPORT_SFUNC(KeReleaseSpinLockFromDpcLevel, 1), + IMPORT_SFUNC_MAP(KeAcquireSpinLockRaiseToDpc, KfAcquireSpinLock, 1), +#endif + IMPORT_SFUNC_MAP(KeReleaseSpinLock, KfReleaseSpinLock, 1), + IMPORT_FFUNC(InterlockedIncrement, 1), + IMPORT_FFUNC(InterlockedDecrement, 1), + IMPORT_FFUNC(InterlockedExchange, 2), + IMPORT_FFUNC(ExInterlockedAddLargeStatistic, 2), + IMPORT_SFUNC(IoAllocateMdl, 5), + IMPORT_SFUNC(IoFreeMdl, 1), + IMPORT_SFUNC(MmAllocateContiguousMemory, 2 + 1), + IMPORT_SFUNC(MmAllocateContiguousMemorySpecifyCache, 5 + 3), + IMPORT_SFUNC(MmFreeContiguousMemory, 1), + IMPORT_SFUNC(MmFreeContiguousMemorySpecifyCache, 3), + IMPORT_SFUNC(MmSizeOfMdl, 1), + IMPORT_SFUNC(MmMapLockedPages, 2), + IMPORT_SFUNC(MmMapLockedPagesSpecifyCache, 6), + IMPORT_SFUNC(MmUnmapLockedPages, 2), + IMPORT_SFUNC(MmBuildMdlForNonPagedPool, 1), + IMPORT_SFUNC(MmGetPhysicalAddress, 1), + IMPORT_SFUNC(MmGetSystemRoutineAddress, 1), + IMPORT_SFUNC(MmIsAddressValid, 1), + IMPORT_SFUNC(MmMapIoSpace, 3 + 1), + IMPORT_SFUNC(MmUnmapIoSpace, 2), + IMPORT_SFUNC(KeInitializeSpinLock, 1), + IMPORT_SFUNC(IoIsWdmVersionAvailable, 2), + IMPORT_SFUNC(IoOpenDeviceRegistryKey, 4), + IMPORT_SFUNC(IoGetDeviceObjectPointer, 4), + IMPORT_SFUNC(IoGetDeviceProperty, 5), + IMPORT_SFUNC(IoAllocateWorkItem, 1), + IMPORT_SFUNC(IoFreeWorkItem, 1), + IMPORT_SFUNC(IoQueueWorkItem, 4), + IMPORT_SFUNC(ExQueueWorkItem, 2), + IMPORT_SFUNC(ntoskrnl_workitem, 2), + IMPORT_SFUNC(KeInitializeMutex, 2), + IMPORT_SFUNC(KeReleaseMutex, 2), + IMPORT_SFUNC(KeReadStateMutex, 1), + IMPORT_SFUNC(KeInitializeEvent, 3), + IMPORT_SFUNC(KeSetEvent, 3), + IMPORT_SFUNC(KeResetEvent, 1), + IMPORT_SFUNC(KeClearEvent, 1), + IMPORT_SFUNC(KeReadStateEvent, 1), + IMPORT_SFUNC(KeInitializeTimer, 1), + IMPORT_SFUNC(KeInitializeTimerEx, 2), + IMPORT_SFUNC(KeSetTimer, 3), + IMPORT_SFUNC(KeSetTimerEx, 4), + IMPORT_SFUNC(KeCancelTimer, 1), + IMPORT_SFUNC(KeReadStateTimer, 1), + IMPORT_SFUNC(KeInitializeDpc, 3), + IMPORT_SFUNC(KeInsertQueueDpc, 3), + IMPORT_SFUNC(KeRemoveQueueDpc, 1), + IMPORT_SFUNC(KeSetImportanceDpc, 2), + IMPORT_SFUNC(KeSetTargetProcessorDpc, 2), + IMPORT_SFUNC(KeFlushQueuedDpcs, 0), + IMPORT_SFUNC(KeGetCurrentProcessorNumber, 1), + IMPORT_SFUNC(ObReferenceObjectByHandle, 6), + IMPORT_FFUNC(ObfDereferenceObject, 1), + IMPORT_SFUNC(ZwClose, 1), + IMPORT_SFUNC(PsCreateSystemThread, 7), + IMPORT_SFUNC(PsTerminateSystemThread, 1), + IMPORT_SFUNC(IoWMIRegistrationControl, 2), + IMPORT_SFUNC(WmiQueryTraceInformation, 5), + IMPORT_CFUNC(WmiTraceMessage, 0), + IMPORT_SFUNC(KeQuerySystemTime, 1), + IMPORT_CFUNC(KeTickCount, 0), + IMPORT_SFUNC(KeDelayExecutionThread, 3), + IMPORT_SFUNC(KeQueryInterruptTime, 0), + IMPORT_SFUNC(KeGetCurrentThread, 0), + IMPORT_SFUNC(KeSetPriorityThread, 2), + + /* + * This last entry is a catch-all for any function we haven't + * implemented yet. The PE import list patching routine will + * use it for any function that doesn't have an explicit match + * in this table. + */ + + { NULL, (FUNC)dummy, NULL, 0, WINDRV_WRAP_STDCALL }, + + /* End of list. */ + + { NULL, NULL, NULL } +}; diff --git a/sys/compat/ndis/subr_pe.c b/sys/compat/ndis/subr_pe.c new file mode 100644 index 0000000..fcbaef2 --- /dev/null +++ b/sys/compat/ndis/subr_pe.c @@ -0,0 +1,642 @@ +/*- + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.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, 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 Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD + * 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$"); + +/* + * This file contains routines for relocating and dynamically linking + * executable object code files in the Windows(r) PE (Portable Executable) + * format. In Windows, anything with a .EXE, .DLL or .SYS extention is + * considered an executable, and all such files have some structures in + * common. The PE format was apparently based largely on COFF but has + * mutated significantly over time. We are mainly concerned with .SYS files, + * so this module implements only enough routines to be able to parse the + * headers and sections of a .SYS object file and perform the necessary + * relocations and jump table patching to allow us to call into it + * (and to have it call back to us). Note that while this module + * can handle fixups for imported symbols, it knows nothing about + * exporting them. + */ + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/errno.h> +#ifdef _KERNEL +#include <sys/systm.h> +#else +#include <stdio.h> +#include <stddef.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#endif + +#include <compat/ndis/pe_var.h> + +static vm_offset_t pe_functbl_match(image_patch_table *, char *); + +/* + * Check for an MS-DOS executable header. All Windows binaries + * have a small MS-DOS executable prepended to them to print out + * the "This program requires Windows" message. Even .SYS files + * have this header, in spite of the fact that you're can't actually + * run them directly. + */ + +int +pe_get_dos_header(imgbase, hdr) + vm_offset_t imgbase; + image_dos_header *hdr; +{ + uint16_t signature; + + if (imgbase == 0 || hdr == NULL) + return (EINVAL); + + signature = *(uint16_t *)imgbase; + if (signature != IMAGE_DOS_SIGNATURE) + return (ENOEXEC); + + bcopy ((char *)imgbase, (char *)hdr, sizeof(image_dos_header)); + + return (0); +} + +/* + * Verify that this image has a Windows NT PE signature. + */ + +int +pe_is_nt_image(imgbase) + vm_offset_t imgbase; +{ + uint32_t signature; + image_dos_header *dos_hdr; + + if (imgbase == 0) + return (EINVAL); + + signature = *(uint16_t *)imgbase; + if (signature == IMAGE_DOS_SIGNATURE) { + dos_hdr = (image_dos_header *)imgbase; + signature = *(uint32_t *)(imgbase + dos_hdr->idh_lfanew); + if (signature == IMAGE_NT_SIGNATURE) + return (0); + } + + return (ENOEXEC); +} + +/* + * Return a copy of the optional header. This contains the + * executable entry point and the directory listing which we + * need to find the relocations and imports later. + */ + +int +pe_get_optional_header(imgbase, hdr) + vm_offset_t imgbase; + image_optional_header *hdr; +{ + image_dos_header *dos_hdr; + image_nt_header *nt_hdr; + + if (imgbase == 0 || hdr == NULL) + return (EINVAL); + + if (pe_is_nt_image(imgbase)) + return (EINVAL); + + dos_hdr = (image_dos_header *)(imgbase); + nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); + + bcopy ((char *)&nt_hdr->inh_optionalhdr, (char *)hdr, + nt_hdr->inh_filehdr.ifh_optionalhdrlen); + + return (0); +} + +/* + * Return a copy of the file header. Contains the number of + * sections in this image. + */ + +int +pe_get_file_header(imgbase, hdr) + vm_offset_t imgbase; + image_file_header *hdr; +{ + image_dos_header *dos_hdr; + image_nt_header *nt_hdr; + + if (imgbase == 0 || hdr == NULL) + return (EINVAL); + + if (pe_is_nt_image(imgbase)) + return (EINVAL); + + dos_hdr = (image_dos_header *)imgbase; + nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); + + /* + * Note: the size of the nt_header is variable since it + * can contain optional fields, as indicated by ifh_optionalhdrlen. + * However it happens we're only interested in fields in the + * non-variant portion of the nt_header structure, so we don't + * bother copying the optional parts here. + */ + + bcopy ((char *)&nt_hdr->inh_filehdr, (char *)hdr, + sizeof(image_file_header)); + + return (0); +} + +/* + * Return the header of the first section in this image (usually + * .text). + */ + +int +pe_get_section_header(imgbase, hdr) + vm_offset_t imgbase; + image_section_header *hdr; +{ + image_dos_header *dos_hdr; + image_nt_header *nt_hdr; + image_section_header *sect_hdr; + + if (imgbase == 0 || hdr == NULL) + return (EINVAL); + + if (pe_is_nt_image(imgbase)) + return (EINVAL); + + dos_hdr = (image_dos_header *)imgbase; + nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); + sect_hdr = IMAGE_FIRST_SECTION(nt_hdr); + + bcopy ((char *)sect_hdr, (char *)hdr, sizeof(image_section_header)); + + return (0); +} + +/* + * Return the number of sections in this executable, or 0 on error. + */ + +int +pe_numsections(imgbase) + vm_offset_t imgbase; +{ + image_file_header file_hdr; + + if (pe_get_file_header(imgbase, &file_hdr)) + return (0); + + return (file_hdr.ifh_numsections); +} + +/* + * Return the base address that this image was linked for. + * This helps us calculate relocation addresses later. + */ + +vm_offset_t +pe_imagebase(imgbase) + vm_offset_t imgbase; +{ + image_optional_header optional_hdr; + + if (pe_get_optional_header(imgbase, &optional_hdr)) + return (0); + + return (optional_hdr.ioh_imagebase); +} + +/* + * Return the offset of a given directory structure within the + * image. Directories reside within sections. + */ + +vm_offset_t +pe_directory_offset(imgbase, diridx) + vm_offset_t imgbase; + uint32_t diridx; +{ + image_optional_header opt_hdr; + vm_offset_t dir; + + if (pe_get_optional_header(imgbase, &opt_hdr)) + return (0); + + if (diridx >= opt_hdr.ioh_rva_size_cnt) + return (0); + + dir = opt_hdr.ioh_datadir[diridx].idd_vaddr; + + return (pe_translate_addr(imgbase, dir)); +} + +vm_offset_t +pe_translate_addr(imgbase, rva) + vm_offset_t imgbase; + vm_offset_t rva; +{ + image_optional_header opt_hdr; + image_section_header *sect_hdr; + image_dos_header *dos_hdr; + image_nt_header *nt_hdr; + int i = 0, sections, fixedlen; + + if (pe_get_optional_header(imgbase, &opt_hdr)) + return (0); + + sections = pe_numsections(imgbase); + + dos_hdr = (image_dos_header *)imgbase; + nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); + sect_hdr = IMAGE_FIRST_SECTION(nt_hdr); + + /* + * The test here is to see if the RVA falls somewhere + * inside the section, based on the section's start RVA + * and its length. However it seems sometimes the + * virtual length isn't enough to cover the entire + * area of the section. We fudge by taking into account + * the section alignment and rounding the section length + * up to a page boundary. + */ + while (i++ < sections) { + fixedlen = sect_hdr->ish_misc.ish_vsize; + fixedlen += ((opt_hdr.ioh_sectalign - 1) - + sect_hdr->ish_misc.ish_vsize) & + (opt_hdr.ioh_sectalign - 1); + if (sect_hdr->ish_vaddr <= (uint32_t)rva && + (sect_hdr->ish_vaddr + fixedlen) > + (uint32_t)rva) + break; + sect_hdr++; + } + + if (i > sections) + return (0); + + return ((vm_offset_t)(imgbase + rva - sect_hdr->ish_vaddr + + sect_hdr->ish_rawdataaddr)); +} + +/* + * Get the section header for a particular section. Note that + * section names can be anything, but there are some standard + * ones (.text, .data, .rdata, .reloc). + */ + +int +pe_get_section(imgbase, hdr, name) + vm_offset_t imgbase; + image_section_header *hdr; + const char *name; +{ + image_dos_header *dos_hdr; + image_nt_header *nt_hdr; + image_section_header *sect_hdr; + + int i, sections; + + if (imgbase == 0 || hdr == NULL) + return (EINVAL); + + if (pe_is_nt_image(imgbase)) + return (EINVAL); + + sections = pe_numsections(imgbase); + + dos_hdr = (image_dos_header *)imgbase; + nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); + sect_hdr = IMAGE_FIRST_SECTION(nt_hdr); + + for (i = 0; i < sections; i++) { + if (!strcmp ((char *)§_hdr->ish_name, name)) { + bcopy((char *)sect_hdr, (char *)hdr, + sizeof(image_section_header)); + return (0); + } else + sect_hdr++; + } + + return (ENOEXEC); +} + +/* + * Apply the base relocations to this image. The relocation table + * resides within the .reloc section. Relocations are specified in + * blocks which refer to a particular page. We apply the relocations + * one page block at a time. + */ + +int +pe_relocate(imgbase) + vm_offset_t imgbase; +{ + image_section_header sect; + image_base_reloc *relhdr; + uint16_t rel, *sloc; + vm_offset_t base; + vm_size_t delta; + uint32_t *lloc; + uint64_t *qloc; + int i, count; + vm_offset_t txt; + + base = pe_imagebase(imgbase); + pe_get_section(imgbase, §, ".text"); + txt = pe_translate_addr(imgbase, sect.ish_vaddr); + delta = (uint32_t)(txt) - base - sect.ish_vaddr; + + pe_get_section(imgbase, §, ".reloc"); + + relhdr = (image_base_reloc *)(imgbase + sect.ish_rawdataaddr); + + do { + count = (relhdr->ibr_blocksize - + (sizeof(uint32_t) * 2)) / sizeof(uint16_t); + for (i = 0; i < count; i++) { + rel = relhdr->ibr_rel[i]; + switch (IMR_RELTYPE(rel)) { + case IMAGE_REL_BASED_ABSOLUTE: + break; + case IMAGE_REL_BASED_HIGHLOW: + lloc = (uint32_t *)pe_translate_addr(imgbase, + relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); + *lloc = pe_translate_addr(imgbase, + (*lloc - base)); + break; + case IMAGE_REL_BASED_HIGH: + sloc = (uint16_t *)pe_translate_addr(imgbase, + relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); + *sloc += (delta & 0xFFFF0000) >> 16; + break; + case IMAGE_REL_BASED_LOW: + sloc = (uint16_t *)pe_translate_addr(imgbase, + relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); + *sloc += (delta & 0xFFFF); + break; + case IMAGE_REL_BASED_DIR64: + qloc = (uint64_t *)pe_translate_addr(imgbase, + relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); + *qloc = pe_translate_addr(imgbase, + (*qloc - base)); + break; + + default: + printf("[%d]reloc type: %d\n",i, + IMR_RELTYPE(rel)); + break; + } + } + relhdr = (image_base_reloc *)((vm_offset_t)relhdr + + relhdr->ibr_blocksize); + } while (relhdr->ibr_blocksize); + + return (0); +} + +/* + * Return the import descriptor for a particular module. An image + * may be linked against several modules, typically HAL.dll, ntoskrnl.exe + * and NDIS.SYS. For each module, there is a list of imported function + * names and their addresses. + * + * Note: module names are case insensitive! + */ + +int +pe_get_import_descriptor(imgbase, desc, module) + vm_offset_t imgbase; + image_import_descriptor *desc; + char *module; +{ + vm_offset_t offset; + image_import_descriptor *imp_desc; + char *modname; + + if (imgbase == 0 || module == NULL || desc == NULL) + return (EINVAL); + + offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_IMPORT); + if (offset == 0) + return (ENOENT); + + imp_desc = (void *)offset; + + while (imp_desc->iid_nameaddr) { + modname = (char *)pe_translate_addr(imgbase, + imp_desc->iid_nameaddr); + if (!strncasecmp(module, modname, strlen(module))) { + bcopy((char *)imp_desc, (char *)desc, + sizeof(image_import_descriptor)); + return (0); + } + imp_desc++; + } + + return (ENOENT); +} + +int +pe_get_messagetable(imgbase, md) + vm_offset_t imgbase; + message_resource_data **md; +{ + image_resource_directory *rdir, *rtype; + image_resource_directory_entry *dent, *dent2; + image_resource_data_entry *rent; + vm_offset_t offset; + int i; + + if (imgbase == 0) + return (EINVAL); + + offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_RESOURCE); + if (offset == 0) + return (ENOENT); + + rdir = (image_resource_directory *)offset; + + dent = (image_resource_directory_entry *)(offset + + sizeof(image_resource_directory)); + + for (i = 0; i < rdir->ird_id_entries; i++){ + if (dent->irde_name != RT_MESSAGETABLE) { + dent++; + continue; + } + dent2 = dent; + while (dent2->irde_dataoff & RESOURCE_DIR_FLAG) { + rtype = (image_resource_directory *)(offset + + (dent2->irde_dataoff & ~RESOURCE_DIR_FLAG)); + dent2 = (image_resource_directory_entry *) + ((uintptr_t)rtype + + sizeof(image_resource_directory)); + } + rent = (image_resource_data_entry *)(offset + + dent2->irde_dataoff); + *md = (message_resource_data *)pe_translate_addr(imgbase, + rent->irde_offset); + return (0); + } + + return (ENOENT); +} + +int +pe_get_message(imgbase, id, str, len, flags) + vm_offset_t imgbase; + uint32_t id; + char **str; + int *len; + uint16_t *flags; +{ + message_resource_data *md = NULL; + message_resource_block *mb; + message_resource_entry *me; + uint32_t i; + + pe_get_messagetable(imgbase, &md); + + if (md == NULL) + return (ENOENT); + + mb = (message_resource_block *)((uintptr_t)md + + sizeof(message_resource_data)); + + for (i = 0; i < md->mrd_numblocks; i++) { + if (id >= mb->mrb_lowid && id <= mb->mrb_highid) { + me = (message_resource_entry *)((uintptr_t)md + + mb->mrb_entryoff); + for (i = id - mb->mrb_lowid; i > 0; i--) + me = (message_resource_entry *)((uintptr_t)me + + me->mre_len); + *str = me->mre_text; + *len = me->mre_len; + *flags = me->mre_flags; + return (0); + } + mb++; + } + + return (ENOENT); +} + +/* + * Find the function that matches a particular name. This doesn't + * need to be particularly speedy since it's only run when loading + * a module for the first time. + */ + +static vm_offset_t +pe_functbl_match(functbl, name) + image_patch_table *functbl; + char *name; +{ + image_patch_table *p; + + if (functbl == NULL || name == NULL) + return (0); + + p = functbl; + + while (p->ipt_name != NULL) { + if (!strcmp(p->ipt_name, name)) + return ((vm_offset_t)p->ipt_wrap); + p++; + } + printf("no match for %s\n", name); + + /* + * Return the wrapper pointer for this routine. + * For x86, this is the same as the funcptr. + * For amd64, this points to a wrapper routine + * that does calling convention translation and + * then invokes the underlying routine. + */ + return ((vm_offset_t)p->ipt_wrap); +} + +/* + * Patch the imported function addresses for a given module. + * The caller must specify the module name and provide a table + * of function pointers that will be patched into the jump table. + * Note that there are actually two copies of the jump table: one + * copy is left alone. In a .SYS file, the jump tables are usually + * merged into the INIT segment. + */ + +int +pe_patch_imports(imgbase, module, functbl) + vm_offset_t imgbase; + char *module; + image_patch_table *functbl; +{ + image_import_descriptor imp_desc; + char *fname; + vm_offset_t *nptr, *fptr; + vm_offset_t func; + + if (imgbase == 0 || module == NULL || functbl == NULL) + return (EINVAL); + + if (pe_get_import_descriptor(imgbase, &imp_desc, module)) + return (ENOEXEC); + + nptr = (vm_offset_t *)pe_translate_addr(imgbase, + imp_desc.iid_import_name_table_addr); + fptr = (vm_offset_t *)pe_translate_addr(imgbase, + imp_desc.iid_import_address_table_addr); + + while (nptr != NULL && pe_translate_addr(imgbase, *nptr)) { + fname = (char *)pe_translate_addr(imgbase, (*nptr) + 2); + func = pe_functbl_match(functbl, fname); + if (func) + *fptr = func; +#ifdef notdef + if (*fptr == 0) + return (ENOENT); +#endif + nptr++; + fptr++; + } + + return (0); +} diff --git a/sys/compat/ndis/subr_usbd.c b/sys/compat/ndis/subr_usbd.c new file mode 100644 index 0000000..b989630 --- /dev/null +++ b/sys/compat/ndis/subr_usbd.c @@ -0,0 +1,1458 @@ +/*- + * Copyright (c) 2005 + * Bill Paul <wpaul@windriver.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, 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 Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD + * 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/unistd.h> +#include <sys/types.h> + +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/sx.h> +#include <sys/condvar.h> +#include <sys/module.h> +#include <sys/conf.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <machine/bus.h> +#include <sys/bus.h> + +#include <sys/queue.h> + +#include <net/if.h> +#include <net/if_media.h> +#include <net80211/ieee80211_var.h> +#include <net80211/ieee80211_ioctl.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> +#include <dev/usb/usbdi_util.h> +#include <dev/usb/usb_busdma.h> +#include <dev/usb/usb_device.h> +#include <dev/usb/usb_request.h> + +#include <compat/ndis/pe_var.h> +#include <compat/ndis/cfg_var.h> +#include <compat/ndis/resource_var.h> +#include <compat/ndis/ntoskrnl_var.h> +#include <compat/ndis/ndis_var.h> +#include <compat/ndis/hal_var.h> +#include <compat/ndis/usbd_var.h> +#include <dev/if_ndis/if_ndisvar.h> + +static driver_object usbd_driver; +static usb_callback_t usbd_non_isoc_callback; +static usb_callback_t usbd_ctrl_callback; + +#define USBD_CTRL_READ_PIPE 0 +#define USBD_CTRL_WRITE_PIPE 1 +#define USBD_CTRL_MAX_PIPE 2 +#define USBD_CTRL_READ_BUFFER_SP 256 +#define USBD_CTRL_WRITE_BUFFER_SP 256 +#define USBD_CTRL_READ_BUFFER_SIZE \ + (sizeof(struct usb_device_request) + USBD_CTRL_READ_BUFFER_SP) +#define USBD_CTRL_WRITE_BUFFER_SIZE \ + (sizeof(struct usb_device_request) + USBD_CTRL_WRITE_BUFFER_SP) +static struct usb_config usbd_default_epconfig[USBD_CTRL_MAX_PIPE] = { + [USBD_CTRL_READ_PIPE] = { + .type = UE_CONTROL, + .endpoint = 0x00, /* control pipe */ + .direction = UE_DIR_ANY, + .if_index = 0, + .bufsize = USBD_CTRL_READ_BUFFER_SIZE, + .flags = { .short_xfer_ok = 1, }, + .callback = &usbd_ctrl_callback, + .timeout = 5000, /* 5 seconds */ + }, + [USBD_CTRL_WRITE_PIPE] = { + .type = UE_CONTROL, + .endpoint = 0x00, /* control pipe */ + .direction = UE_DIR_ANY, + .if_index = 0, + .bufsize = USBD_CTRL_WRITE_BUFFER_SIZE, + .flags = { .proxy_buffer = 1, }, + .callback = &usbd_ctrl_callback, + .timeout = 5000, /* 5 seconds */ + } +}; + +static int32_t usbd_func_bulkintr(irp *); +static int32_t usbd_func_vendorclass(irp *); +static int32_t usbd_func_selconf(irp *); +static int32_t usbd_func_abort_pipe(irp *); +static usb_error_t usbd_setup_endpoint(irp *, uint8_t, + struct usb_endpoint_descriptor *); +static usb_error_t usbd_setup_endpoint_default(irp *, uint8_t); +static usb_error_t usbd_setup_endpoint_one(irp *, uint8_t, + struct ndisusb_ep *, struct usb_config *); +static int32_t usbd_func_getdesc(irp *); +static union usbd_urb *usbd_geturb(irp *); +static struct ndisusb_ep*usbd_get_ndisep(irp *, usb_endpoint_descriptor_t *); +static int32_t usbd_iodispatch(device_object *, irp *); +static int32_t usbd_ioinvalid(device_object *, irp *); +static int32_t usbd_pnp(device_object *, irp *); +static int32_t usbd_power(device_object *, irp *); +static void usbd_irpcancel(device_object *, irp *); +static int32_t usbd_submit_urb(irp *); +static int32_t usbd_urb2nt(int32_t); +static void usbd_task(device_object *, void *); +static int32_t usbd_taskadd(irp *, unsigned); +static void usbd_xfertask(device_object *, void *); +static void dummy(void); + +static union usbd_urb *USBD_CreateConfigurationRequestEx( + usb_config_descriptor_t *, + struct usbd_interface_list_entry *); +static union usbd_urb *USBD_CreateConfigurationRequest( + usb_config_descriptor_t *, + uint16_t *); +static void USBD_GetUSBDIVersion(usbd_version_info *); +static usb_interface_descriptor_t *USBD_ParseConfigurationDescriptorEx( + usb_config_descriptor_t *, void *, int32_t, int32_t, + int32_t, int32_t, int32_t); +static usb_interface_descriptor_t *USBD_ParseConfigurationDescriptor( + usb_config_descriptor_t *, uint8_t, uint8_t); + +/* + * We need to wrap these functions because these need `context switch' from + * Windows to UNIX before it's called. + */ +static funcptr usbd_iodispatch_wrap; +static funcptr usbd_ioinvalid_wrap; +static funcptr usbd_pnp_wrap; +static funcptr usbd_power_wrap; +static funcptr usbd_irpcancel_wrap; +static funcptr usbd_task_wrap; +static funcptr usbd_xfertask_wrap; + +int +usbd_libinit(void) +{ + image_patch_table *patch; + int i; + + patch = usbd_functbl; + while (patch->ipt_func != NULL) { + windrv_wrap((funcptr)patch->ipt_func, + (funcptr *)&patch->ipt_wrap, + patch->ipt_argcnt, patch->ipt_ftype); + patch++; + } + + windrv_wrap((funcptr)usbd_ioinvalid, + (funcptr *)&usbd_ioinvalid_wrap, 2, WINDRV_WRAP_STDCALL); + windrv_wrap((funcptr)usbd_iodispatch, + (funcptr *)&usbd_iodispatch_wrap, 2, WINDRV_WRAP_STDCALL); + windrv_wrap((funcptr)usbd_pnp, + (funcptr *)&usbd_pnp_wrap, 2, WINDRV_WRAP_STDCALL); + windrv_wrap((funcptr)usbd_power, + (funcptr *)&usbd_power_wrap, 2, WINDRV_WRAP_STDCALL); + windrv_wrap((funcptr)usbd_irpcancel, + (funcptr *)&usbd_irpcancel_wrap, 2, WINDRV_WRAP_STDCALL); + windrv_wrap((funcptr)usbd_task, + (funcptr *)&usbd_task_wrap, 2, WINDRV_WRAP_STDCALL); + windrv_wrap((funcptr)usbd_xfertask, + (funcptr *)&usbd_xfertask_wrap, 2, WINDRV_WRAP_STDCALL); + + /* Create a fake USB driver instance. */ + + windrv_bus_attach(&usbd_driver, "USB Bus"); + + /* Set up our dipatch routine. */ + for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) + usbd_driver.dro_dispatch[i] = + (driver_dispatch)usbd_ioinvalid_wrap; + + usbd_driver.dro_dispatch[IRP_MJ_INTERNAL_DEVICE_CONTROL] = + (driver_dispatch)usbd_iodispatch_wrap; + usbd_driver.dro_dispatch[IRP_MJ_DEVICE_CONTROL] = + (driver_dispatch)usbd_iodispatch_wrap; + usbd_driver.dro_dispatch[IRP_MJ_POWER] = + (driver_dispatch)usbd_power_wrap; + usbd_driver.dro_dispatch[IRP_MJ_PNP] = + (driver_dispatch)usbd_pnp_wrap; + + return (0); +} + +int +usbd_libfini(void) +{ + image_patch_table *patch; + + patch = usbd_functbl; + while (patch->ipt_func != NULL) { + windrv_unwrap(patch->ipt_wrap); + patch++; + } + + windrv_unwrap(usbd_ioinvalid_wrap); + windrv_unwrap(usbd_iodispatch_wrap); + windrv_unwrap(usbd_pnp_wrap); + windrv_unwrap(usbd_power_wrap); + windrv_unwrap(usbd_irpcancel_wrap); + windrv_unwrap(usbd_task_wrap); + windrv_unwrap(usbd_xfertask_wrap); + + free(usbd_driver.dro_drivername.us_buf, M_DEVBUF); + + return (0); +} + +static int32_t +usbd_iodispatch(device_object *dobj, irp *ip) +{ + device_t dev = dobj->do_devext; + int32_t status; + struct io_stack_location *irp_sl; + + irp_sl = IoGetCurrentIrpStackLocation(ip); + switch (irp_sl->isl_parameters.isl_ioctl.isl_iocode) { + case IOCTL_INTERNAL_USB_SUBMIT_URB: + IRP_NDIS_DEV(ip) = dev; + + status = usbd_submit_urb(ip); + break; + default: + device_printf(dev, "ioctl 0x%x isn't supported\n", + irp_sl->isl_parameters.isl_ioctl.isl_iocode); + status = USBD_STATUS_NOT_SUPPORTED; + break; + } + + if (status == USBD_STATUS_PENDING) + return (STATUS_PENDING); + + ip->irp_iostat.isb_status = usbd_urb2nt(status); + if (status != USBD_STATUS_SUCCESS) + ip->irp_iostat.isb_info = 0; + return (ip->irp_iostat.isb_status); +} + +static int32_t +usbd_ioinvalid(device_object *dobj, irp *ip) +{ + device_t dev = dobj->do_devext; + struct io_stack_location *irp_sl; + + irp_sl = IoGetCurrentIrpStackLocation(ip); + device_printf(dev, "invalid I/O dispatch %d:%d\n", irp_sl->isl_major, + irp_sl->isl_minor); + + ip->irp_iostat.isb_status = STATUS_FAILURE; + ip->irp_iostat.isb_info = 0; + + IoCompleteRequest(ip, IO_NO_INCREMENT); + + return (STATUS_FAILURE); +} + +static int32_t +usbd_pnp(device_object *dobj, irp *ip) +{ + device_t dev = dobj->do_devext; + struct io_stack_location *irp_sl; + + irp_sl = IoGetCurrentIrpStackLocation(ip); + device_printf(dev, "%s: unsupported I/O dispatch %d:%d\n", + __func__, irp_sl->isl_major, irp_sl->isl_minor); + + ip->irp_iostat.isb_status = STATUS_FAILURE; + ip->irp_iostat.isb_info = 0; + + IoCompleteRequest(ip, IO_NO_INCREMENT); + + return (STATUS_FAILURE); +} + +static int32_t +usbd_power(device_object *dobj, irp *ip) +{ + device_t dev = dobj->do_devext; + struct io_stack_location *irp_sl; + + irp_sl = IoGetCurrentIrpStackLocation(ip); + device_printf(dev, "%s: unsupported I/O dispatch %d:%d\n", + __func__, irp_sl->isl_major, irp_sl->isl_minor); + + ip->irp_iostat.isb_status = STATUS_FAILURE; + ip->irp_iostat.isb_info = 0; + + IoCompleteRequest(ip, IO_NO_INCREMENT); + + return (STATUS_FAILURE); +} + +/* Convert USBD_STATUS to NTSTATUS */ +static int32_t +usbd_urb2nt(int32_t status) +{ + + switch (status) { + case USBD_STATUS_SUCCESS: + return (STATUS_SUCCESS); + case USBD_STATUS_DEVICE_GONE: + return (STATUS_DEVICE_NOT_CONNECTED); + case USBD_STATUS_PENDING: + return (STATUS_PENDING); + case USBD_STATUS_NOT_SUPPORTED: + return (STATUS_NOT_IMPLEMENTED); + case USBD_STATUS_NO_MEMORY: + return (STATUS_NO_MEMORY); + case USBD_STATUS_REQUEST_FAILED: + return (STATUS_NOT_SUPPORTED); + case USBD_STATUS_CANCELED: + return (STATUS_CANCELLED); + default: + break; + } + + return (STATUS_FAILURE); +} + +/* Convert FreeBSD's usb_error_t to USBD_STATUS */ +static int32_t +usbd_usb2urb(int status) +{ + + switch (status) { + case USB_ERR_NORMAL_COMPLETION: + return (USBD_STATUS_SUCCESS); + case USB_ERR_PENDING_REQUESTS: + return (USBD_STATUS_PENDING); + case USB_ERR_TIMEOUT: + return (USBD_STATUS_TIMEOUT); + case USB_ERR_SHORT_XFER: + return (USBD_STATUS_ERROR_SHORT_TRANSFER); + case USB_ERR_IOERROR: + return (USBD_STATUS_XACT_ERROR); + case USB_ERR_NOMEM: + return (USBD_STATUS_NO_MEMORY); + case USB_ERR_INVAL: + return (USBD_STATUS_REQUEST_FAILED); + case USB_ERR_NOT_STARTED: + case USB_ERR_TOO_DEEP: + case USB_ERR_NO_POWER: + return (USBD_STATUS_DEVICE_GONE); + case USB_ERR_CANCELLED: + return (USBD_STATUS_CANCELED); + default: + break; + } + + return (USBD_STATUS_NOT_SUPPORTED); +} + +static union usbd_urb * +usbd_geturb(irp *ip) +{ + struct io_stack_location *irp_sl; + + irp_sl = IoGetCurrentIrpStackLocation(ip); + + return (irp_sl->isl_parameters.isl_others.isl_arg1); +} + +static int32_t +usbd_submit_urb(irp *ip) +{ + device_t dev = IRP_NDIS_DEV(ip); + int32_t status; + union usbd_urb *urb; + + urb = usbd_geturb(ip); + /* + * In a case of URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER, + * USBD_URB_STATUS(urb) would be set at callback functions like + * usbd_intr() or usbd_xfereof(). + */ + switch (urb->uu_hdr.uuh_func) { + case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: + status = usbd_func_bulkintr(ip); + if (status != USBD_STATUS_SUCCESS && + status != USBD_STATUS_PENDING) + USBD_URB_STATUS(urb) = status; + break; + case URB_FUNCTION_VENDOR_DEVICE: + case URB_FUNCTION_VENDOR_INTERFACE: + case URB_FUNCTION_VENDOR_ENDPOINT: + case URB_FUNCTION_VENDOR_OTHER: + case URB_FUNCTION_CLASS_DEVICE: + case URB_FUNCTION_CLASS_INTERFACE: + case URB_FUNCTION_CLASS_ENDPOINT: + case URB_FUNCTION_CLASS_OTHER: + status = usbd_func_vendorclass(ip); + USBD_URB_STATUS(urb) = status; + break; + case URB_FUNCTION_SELECT_CONFIGURATION: + status = usbd_func_selconf(ip); + USBD_URB_STATUS(urb) = status; + break; + case URB_FUNCTION_ABORT_PIPE: + status = usbd_func_abort_pipe(ip); + USBD_URB_STATUS(urb) = status; + break; + case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: + status = usbd_func_getdesc(ip); + USBD_URB_STATUS(urb) = status; + break; + default: + device_printf(dev, "func 0x%x isn't supported\n", + urb->uu_hdr.uuh_func); + USBD_URB_STATUS(urb) = status = USBD_STATUS_NOT_SUPPORTED; + break; + } + + return (status); +} + +static int32_t +usbd_func_getdesc(irp *ip) +{ +#define NDISUSB_GETDESC_MAXRETRIES 3 + device_t dev = IRP_NDIS_DEV(ip); + struct ndis_softc *sc = device_get_softc(dev); + struct usbd_urb_control_descriptor_request *ctldesc; + uint16_t actlen; + uint32_t len; + union usbd_urb *urb; + usb_config_descriptor_t *cdp; + usb_error_t status; + + urb = usbd_geturb(ip); + ctldesc = &urb->uu_ctldesc; + if (ctldesc->ucd_desctype == UDESC_CONFIG) { + /* + * The NDIS driver is not allowed to change the + * config! There is only one choice! + */ + cdp = usbd_get_config_descriptor(sc->ndisusb_dev); + if (cdp == NULL) { + status = USB_ERR_INVAL; + goto exit; + } + if (cdp->bDescriptorType != UDESC_CONFIG) { + device_printf(dev, "bad desc %d\n", + cdp->bDescriptorType); + status = USB_ERR_INVAL; + goto exit; + } + /* get minimum length */ + len = MIN(UGETW(cdp->wTotalLength), ctldesc->ucd_trans_buflen); + /* copy out config descriptor */ + memcpy(ctldesc->ucd_trans_buf, cdp, len); + /* set actual length */ + actlen = len; + status = USB_ERR_NORMAL_COMPLETION; + } else { + NDISUSB_LOCK(sc); + status = usbd_req_get_desc(sc->ndisusb_dev, &sc->ndisusb_mtx, + &actlen, ctldesc->ucd_trans_buf, 2, + ctldesc->ucd_trans_buflen, ctldesc->ucd_langid, + ctldesc->ucd_desctype, ctldesc->ucd_idx, + NDISUSB_GETDESC_MAXRETRIES); + NDISUSB_UNLOCK(sc); + } +exit: + if (status != USB_ERR_NORMAL_COMPLETION) { + ctldesc->ucd_trans_buflen = 0; + return usbd_usb2urb(status); + } + + ctldesc->ucd_trans_buflen = actlen; + ip->irp_iostat.isb_info = actlen; + + return (USBD_STATUS_SUCCESS); +#undef NDISUSB_GETDESC_MAXRETRIES +} + +static int32_t +usbd_func_selconf(irp *ip) +{ + device_t dev = IRP_NDIS_DEV(ip); + int i, j; + struct ndis_softc *sc = device_get_softc(dev); + struct usb_device *udev = sc->ndisusb_dev; + struct usb_endpoint *ep = NULL; + struct usbd_interface_information *intf; + struct usbd_pipe_information *pipe; + struct usbd_urb_select_configuration *selconf; + union usbd_urb *urb; + usb_config_descriptor_t *conf; + usb_endpoint_descriptor_t *edesc; + usb_error_t ret; + + urb = usbd_geturb(ip); + + selconf = &urb->uu_selconf; + conf = selconf->usc_conf; + if (conf == NULL) { + device_printf(dev, "select configuration is NULL\n"); + return usbd_usb2urb(USB_ERR_NORMAL_COMPLETION); + } + + intf = &selconf->usc_intf; + for (i = 0; i < conf->bNumInterface && intf->uii_len > 0; i++) { + ret = usbd_set_alt_interface_index(udev, + intf->uii_intfnum, intf->uii_altset); + if (ret != USB_ERR_NORMAL_COMPLETION && ret != USB_ERR_IN_USE) { + device_printf(dev, + "setting alternate interface failed: %s\n", + usbd_errstr(ret)); + return usbd_usb2urb(ret); + } + + for (j = 0; (ep = usb_endpoint_foreach(udev, ep)); j++) { + if (j >= intf->uii_numeps) { + device_printf(dev, + "endpoint %d and above are ignored", + intf->uii_numeps); + break; + } + edesc = ep->edesc; + pipe = &intf->uii_pipes[j]; + pipe->upi_handle = edesc; + pipe->upi_epaddr = edesc->bEndpointAddress; + pipe->upi_maxpktsize = UGETW(edesc->wMaxPacketSize); + pipe->upi_type = UE_GET_XFERTYPE(edesc->bmAttributes); + + ret = usbd_setup_endpoint(ip, intf->uii_intfnum, edesc); + if (ret != USB_ERR_NORMAL_COMPLETION) + return usbd_usb2urb(ret); + + if (pipe->upi_type != UE_INTERRUPT) + continue; + + /* XXX we're following linux USB's interval policy. */ + if (udev->speed == USB_SPEED_LOW) + pipe->upi_interval = edesc->bInterval + 5; + else if (udev->speed == USB_SPEED_FULL) + pipe->upi_interval = edesc->bInterval; + else { + int k0 = 0, k1 = 1; + do { + k1 = k1 * 2; + k0 = k0 + 1; + } while (k1 < edesc->bInterval); + pipe->upi_interval = k0; + } + } + + intf = (struct usbd_interface_information *)(((char *)intf) + + intf->uii_len); + } + + return (USBD_STATUS_SUCCESS); +} + +static usb_error_t +usbd_setup_endpoint_one(irp *ip, uint8_t ifidx, struct ndisusb_ep *ne, + struct usb_config *epconf) +{ + device_t dev = IRP_NDIS_DEV(ip); + struct ndis_softc *sc = device_get_softc(dev); + struct usb_xfer *xfer; + usb_error_t status; + + InitializeListHead(&ne->ne_active); + InitializeListHead(&ne->ne_pending); + KeInitializeSpinLock(&ne->ne_lock); + + status = usbd_transfer_setup(sc->ndisusb_dev, &ifidx, ne->ne_xfer, + epconf, 1, sc, &sc->ndisusb_mtx); + if (status != USB_ERR_NORMAL_COMPLETION) { + device_printf(dev, "couldn't setup xfer: %s\n", + usbd_errstr(status)); + return (status); + } + xfer = ne->ne_xfer[0]; + usbd_xfer_set_priv(xfer, ne); + + return (status); +} + +static usb_error_t +usbd_setup_endpoint_default(irp *ip, uint8_t ifidx) +{ + device_t dev = IRP_NDIS_DEV(ip); + struct ndis_softc *sc = device_get_softc(dev); + usb_error_t status; + + if (ifidx > 0) + device_printf(dev, "warning: ifidx > 0 isn't supported.\n"); + + status = usbd_setup_endpoint_one(ip, ifidx, &sc->ndisusb_dread_ep, + &usbd_default_epconfig[USBD_CTRL_READ_PIPE]); + if (status != USB_ERR_NORMAL_COMPLETION) + return (status); + + status = usbd_setup_endpoint_one(ip, ifidx, &sc->ndisusb_dwrite_ep, + &usbd_default_epconfig[USBD_CTRL_WRITE_PIPE]); + return (status); +} + +static usb_error_t +usbd_setup_endpoint(irp *ip, uint8_t ifidx, + struct usb_endpoint_descriptor *ep) +{ + device_t dev = IRP_NDIS_DEV(ip); + struct ndis_softc *sc = device_get_softc(dev); + struct ndisusb_ep *ne; + struct usb_config cfg; + struct usb_xfer *xfer; + usb_error_t status; + + /* check for non-supported transfer types */ + if (UE_GET_XFERTYPE(ep->bmAttributes) == UE_CONTROL || + UE_GET_XFERTYPE(ep->bmAttributes) == UE_ISOCHRONOUS) { + device_printf(dev, "%s: unsuppotted transfer types %#x\n", + __func__, UE_GET_XFERTYPE(ep->bmAttributes)); + return (USB_ERR_INVAL); + } + + ne = &sc->ndisusb_ep[NDISUSB_GET_ENDPT(ep->bEndpointAddress)]; + InitializeListHead(&ne->ne_active); + InitializeListHead(&ne->ne_pending); + KeInitializeSpinLock(&ne->ne_lock); + ne->ne_dirin = UE_GET_DIR(ep->bEndpointAddress) >> 7; + + memset(&cfg, 0, sizeof(struct usb_config)); + cfg.type = UE_GET_XFERTYPE(ep->bmAttributes); + cfg.endpoint = UE_GET_ADDR(ep->bEndpointAddress); + cfg.direction = UE_GET_DIR(ep->bEndpointAddress); + cfg.callback = &usbd_non_isoc_callback; + cfg.bufsize = UGETW(ep->wMaxPacketSize); + cfg.flags.proxy_buffer = 1; + if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN) + cfg.flags.short_xfer_ok = 1; + + status = usbd_transfer_setup(sc->ndisusb_dev, &ifidx, ne->ne_xfer, + &cfg, 1, sc, &sc->ndisusb_mtx); + if (status != USB_ERR_NORMAL_COMPLETION) { + device_printf(dev, "couldn't setup xfer: %s\n", + usbd_errstr(status)); + return (status); + } + xfer = ne->ne_xfer[0]; + usbd_xfer_set_priv(xfer, ne); + if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN) + usbd_xfer_set_timeout(xfer, NDISUSB_NO_TIMEOUT); + else { + if (UE_GET_XFERTYPE(ep->bmAttributes) == UE_BULK) + usbd_xfer_set_timeout(xfer, NDISUSB_TX_TIMEOUT); + else + usbd_xfer_set_timeout(xfer, NDISUSB_INTR_TIMEOUT); + } + + return (status); +} + +static int32_t +usbd_func_abort_pipe(irp *ip) +{ + device_t dev = IRP_NDIS_DEV(ip); + struct ndis_softc *sc = device_get_softc(dev); + struct ndisusb_ep *ne; + union usbd_urb *urb; + + urb = usbd_geturb(ip); + ne = usbd_get_ndisep(ip, urb->uu_pipe.upr_handle); + if (ne == NULL) { + device_printf(IRP_NDIS_DEV(ip), "get NULL endpoint info.\n"); + return (USBD_STATUS_INVALID_PIPE_HANDLE); + } + + NDISUSB_LOCK(sc); + usbd_transfer_stop(ne->ne_xfer[0]); + usbd_transfer_start(ne->ne_xfer[0]); + NDISUSB_UNLOCK(sc); + + return (USBD_STATUS_SUCCESS); +} + +static int32_t +usbd_func_vendorclass(irp *ip) +{ + device_t dev = IRP_NDIS_DEV(ip); + int32_t error; + struct ndis_softc *sc = device_get_softc(dev); + struct ndisusb_ep *ne; + struct ndisusb_xfer *nx; + struct usbd_urb_vendor_or_class_request *vcreq; + union usbd_urb *urb; + + if (!(sc->ndisusb_status & NDISUSB_STATUS_SETUP_EP)) { + /* + * XXX In some cases the interface number isn't 0. However + * some driver (eg. RTL8187L NDIS driver) calls this function + * before calling URB_FUNCTION_SELECT_CONFIGURATION. + */ + error = usbd_setup_endpoint_default(ip, 0); + if (error != USB_ERR_NORMAL_COMPLETION) + return usbd_usb2urb(error); + sc->ndisusb_status |= NDISUSB_STATUS_SETUP_EP; + } + + urb = usbd_geturb(ip); + vcreq = &urb->uu_vcreq; + ne = (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) ? + &sc->ndisusb_dread_ep : &sc->ndisusb_dwrite_ep; + IRP_NDISUSB_EP(ip) = ne; + ip->irp_cancelfunc = (cancel_func)usbd_irpcancel_wrap; + + nx = malloc(sizeof(struct ndisusb_xfer), M_USBDEV, M_NOWAIT | M_ZERO); + if (nx == NULL) { + device_printf(IRP_NDIS_DEV(ip), "out of memory\n"); + return (USBD_STATUS_NO_MEMORY); + } + nx->nx_ep = ne; + nx->nx_priv = ip; + KeAcquireSpinLockAtDpcLevel(&ne->ne_lock); + InsertTailList((&ne->ne_pending), (&nx->nx_next)); + KeReleaseSpinLockFromDpcLevel(&ne->ne_lock); + + /* we've done to setup xfer. Let's transfer it. */ + ip->irp_iostat.isb_status = STATUS_PENDING; + ip->irp_iostat.isb_info = 0; + USBD_URB_STATUS(urb) = USBD_STATUS_PENDING; + IoMarkIrpPending(ip); + + error = usbd_taskadd(ip, NDISUSB_TASK_VENDOR); + if (error != USBD_STATUS_SUCCESS) + return (error); + + return (USBD_STATUS_PENDING); +} + +static void +usbd_irpcancel(device_object *dobj, irp *ip) +{ + device_t dev = IRP_NDIS_DEV(ip); + struct ndis_softc *sc = device_get_softc(dev); + struct ndisusb_ep *ne = IRP_NDISUSB_EP(ip); + + if (ne == NULL) { + ip->irp_cancel = TRUE; + IoReleaseCancelSpinLock(ip->irp_cancelirql); + return; + } + + /* + * Make sure that the current USB transfer proxy is + * cancelled and then restarted. + */ + NDISUSB_LOCK(sc); + usbd_transfer_stop(ne->ne_xfer[0]); + usbd_transfer_start(ne->ne_xfer[0]); + NDISUSB_UNLOCK(sc); + + ip->irp_cancel = TRUE; + IoReleaseCancelSpinLock(ip->irp_cancelirql); +} + +static void +usbd_xfer_complete(struct ndis_softc *sc, struct ndisusb_ep *ne, + struct ndisusb_xfer *nx, usb_error_t status) +{ + struct ndisusb_xferdone *nd; + uint8_t irql; + + nd = malloc(sizeof(struct ndisusb_xferdone), M_USBDEV, + M_NOWAIT | M_ZERO); + if (nd == NULL) { + device_printf(sc->ndis_dev, "out of memory"); + return; + } + nd->nd_xfer = nx; + nd->nd_status = status; + + KeAcquireSpinLock(&sc->ndisusb_xferdonelock, &irql); + InsertTailList((&sc->ndisusb_xferdonelist), (&nd->nd_donelist)); + KeReleaseSpinLock(&sc->ndisusb_xferdonelock, irql); + + IoQueueWorkItem(sc->ndisusb_xferdoneitem, + (io_workitem_func)usbd_xfertask_wrap, WORKQUEUE_CRITICAL, sc); +} + +static struct ndisusb_xfer * +usbd_aq_getfirst(struct ndis_softc *sc, struct ndisusb_ep *ne) +{ + struct ndisusb_xfer *nx; + + KeAcquireSpinLockAtDpcLevel(&ne->ne_lock); + if (IsListEmpty(&ne->ne_active)) { + device_printf(sc->ndis_dev, + "%s: the active queue can't be empty.\n", __func__); + KeReleaseSpinLockFromDpcLevel(&ne->ne_lock); + return (NULL); + } + nx = CONTAINING_RECORD(ne->ne_active.nle_flink, struct ndisusb_xfer, + nx_next); + RemoveEntryList(&nx->nx_next); + KeReleaseSpinLockFromDpcLevel(&ne->ne_lock); + + return (nx); +} + +static void +usbd_non_isoc_callback(struct usb_xfer *xfer, usb_error_t error) +{ + irp *ip; + struct ndis_softc *sc = usbd_xfer_softc(xfer); + struct ndisusb_ep *ne = usbd_xfer_get_priv(xfer); + struct ndisusb_xfer *nx; + struct usbd_urb_bulk_or_intr_transfer *ubi; + struct usb_page_cache *pc; + uint8_t irql; + uint32_t len; + union usbd_urb *urb; + usb_endpoint_descriptor_t *ep; + int actlen, sumlen; + + usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); + + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + nx = usbd_aq_getfirst(sc, ne); + pc = usbd_xfer_get_frame(xfer, 0); + if (nx == NULL) + return; + + /* copy in data with regard to the URB */ + if (ne->ne_dirin != 0) + usbd_copy_out(pc, 0, nx->nx_urbbuf, actlen); + nx->nx_urbbuf += actlen; + nx->nx_urbactlen += actlen; + nx->nx_urblen -= actlen; + + /* check for short transfer */ + if (actlen < sumlen) + nx->nx_urblen = 0; + else { + /* check remainder */ + if (nx->nx_urblen > 0) { + KeAcquireSpinLock(&ne->ne_lock, &irql); + InsertHeadList((&ne->ne_active), (&nx->nx_next)); + KeReleaseSpinLock(&ne->ne_lock, irql); + + ip = nx->nx_priv; + urb = usbd_geturb(ip); + ubi = &urb->uu_bulkintr; + ep = ubi->ubi_epdesc; + goto extra; + } + } + usbd_xfer_complete(sc, ne, nx, + ((actlen < sumlen) && (nx->nx_shortxfer == 0)) ? + USB_ERR_SHORT_XFER : USB_ERR_NORMAL_COMPLETION); + + /* fall through */ + case USB_ST_SETUP: +next: + /* get next transfer */ + KeAcquireSpinLock(&ne->ne_lock, &irql); + if (IsListEmpty(&ne->ne_pending)) { + KeReleaseSpinLock(&ne->ne_lock, irql); + return; + } + nx = CONTAINING_RECORD(ne->ne_pending.nle_flink, + struct ndisusb_xfer, nx_next); + RemoveEntryList(&nx->nx_next); + /* add a entry to the active queue's tail. */ + InsertTailList((&ne->ne_active), (&nx->nx_next)); + KeReleaseSpinLock(&ne->ne_lock, irql); + + ip = nx->nx_priv; + urb = usbd_geturb(ip); + ubi = &urb->uu_bulkintr; + ep = ubi->ubi_epdesc; + + nx->nx_urbbuf = ubi->ubi_trans_buf; + nx->nx_urbactlen = 0; + nx->nx_urblen = ubi->ubi_trans_buflen; + nx->nx_shortxfer = (ubi->ubi_trans_flags & + USBD_SHORT_TRANSFER_OK) ? 1 : 0; +extra: + len = MIN(usbd_xfer_max_len(xfer), nx->nx_urblen); + pc = usbd_xfer_get_frame(xfer, 0); + if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_OUT) + usbd_copy_in(pc, 0, nx->nx_urbbuf, len); + usbd_xfer_set_frame_len(xfer, 0, len); + usbd_xfer_set_frames(xfer, 1); + usbd_transfer_submit(xfer); + break; + default: + nx = usbd_aq_getfirst(sc, ne); + if (nx == NULL) + return; + if (error != USB_ERR_CANCELLED) { + usbd_xfer_set_stall(xfer); + device_printf(sc->ndis_dev, "usb xfer warning (%s)\n", + usbd_errstr(error)); + } + usbd_xfer_complete(sc, ne, nx, error); + if (error != USB_ERR_CANCELLED) + goto next; + break; + } +} + +static void +usbd_ctrl_callback(struct usb_xfer *xfer, usb_error_t error) +{ + irp *ip; + struct ndis_softc *sc = usbd_xfer_softc(xfer); + struct ndisusb_ep *ne = usbd_xfer_get_priv(xfer); + struct ndisusb_xfer *nx; + uint8_t irql; + union usbd_urb *urb; + struct usbd_urb_vendor_or_class_request *vcreq; + struct usb_page_cache *pc; + uint8_t type = 0; + struct usb_device_request req; + int len; + + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + nx = usbd_aq_getfirst(sc, ne); + if (nx == NULL) + return; + + ip = nx->nx_priv; + urb = usbd_geturb(ip); + vcreq = &urb->uu_vcreq; + + if (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) { + pc = usbd_xfer_get_frame(xfer, 1); + len = usbd_xfer_frame_len(xfer, 1); + usbd_copy_out(pc, 0, vcreq->uvc_trans_buf, len); + nx->nx_urbactlen += len; + } + + usbd_xfer_complete(sc, ne, nx, USB_ERR_NORMAL_COMPLETION); + /* fall through */ + case USB_ST_SETUP: +next: + /* get next transfer */ + KeAcquireSpinLock(&ne->ne_lock, &irql); + if (IsListEmpty(&ne->ne_pending)) { + KeReleaseSpinLock(&ne->ne_lock, irql); + return; + } + nx = CONTAINING_RECORD(ne->ne_pending.nle_flink, + struct ndisusb_xfer, nx_next); + RemoveEntryList(&nx->nx_next); + /* add a entry to the active queue's tail. */ + InsertTailList((&ne->ne_active), (&nx->nx_next)); + KeReleaseSpinLock(&ne->ne_lock, irql); + + ip = nx->nx_priv; + urb = usbd_geturb(ip); + vcreq = &urb->uu_vcreq; + + switch (urb->uu_hdr.uuh_func) { + case URB_FUNCTION_CLASS_DEVICE: + type = UT_CLASS | UT_DEVICE; + break; + case URB_FUNCTION_CLASS_INTERFACE: + type = UT_CLASS | UT_INTERFACE; + break; + case URB_FUNCTION_CLASS_OTHER: + type = UT_CLASS | UT_OTHER; + break; + case URB_FUNCTION_CLASS_ENDPOINT: + type = UT_CLASS | UT_ENDPOINT; + break; + case URB_FUNCTION_VENDOR_DEVICE: + type = UT_VENDOR | UT_DEVICE; + break; + case URB_FUNCTION_VENDOR_INTERFACE: + type = UT_VENDOR | UT_INTERFACE; + break; + case URB_FUNCTION_VENDOR_OTHER: + type = UT_VENDOR | UT_OTHER; + break; + case URB_FUNCTION_VENDOR_ENDPOINT: + type = UT_VENDOR | UT_ENDPOINT; + break; + default: + /* never reached. */ + break; + } + + type |= (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) ? + UT_READ : UT_WRITE; + type |= vcreq->uvc_reserved1; + + req.bmRequestType = type; + req.bRequest = vcreq->uvc_req; + USETW(req.wIndex, vcreq->uvc_idx); + USETW(req.wValue, vcreq->uvc_value); + USETW(req.wLength, vcreq->uvc_trans_buflen); + + nx->nx_urbbuf = vcreq->uvc_trans_buf; + nx->nx_urblen = vcreq->uvc_trans_buflen; + nx->nx_urbactlen = 0; + + pc = usbd_xfer_get_frame(xfer, 0); + usbd_copy_in(pc, 0, &req, sizeof(req)); + usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); + usbd_xfer_set_frames(xfer, 1); + if (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) { + if (vcreq->uvc_trans_buflen >= USBD_CTRL_READ_BUFFER_SP) + device_printf(sc->ndis_dev, + "warning: not enough buffer space (%d).\n", + vcreq->uvc_trans_buflen); + usbd_xfer_set_frame_len(xfer, 1, + MIN(usbd_xfer_max_len(xfer), + vcreq->uvc_trans_buflen)); + usbd_xfer_set_frames(xfer, 2); + } else { + if (nx->nx_urblen > USBD_CTRL_WRITE_BUFFER_SP) + device_printf(sc->ndis_dev, + "warning: not enough write buffer space" + " (%d).\n", nx->nx_urblen); + /* + * XXX with my local tests there was no cases to require + * a extra buffer until now but it'd need to update in + * the future if it needs to be. + */ + if (nx->nx_urblen > 0) { + pc = usbd_xfer_get_frame(xfer, 1); + usbd_copy_in(pc, 0, nx->nx_urbbuf, + nx->nx_urblen); + usbd_xfer_set_frame_len(xfer, 1, nx->nx_urblen); + usbd_xfer_set_frames(xfer, 2); + } + } + usbd_transfer_submit(xfer); + break; + default: + nx = usbd_aq_getfirst(sc, ne); + if (nx == NULL) + return; + if (error != USB_ERR_CANCELLED) { + usbd_xfer_set_stall(xfer); + device_printf(sc->ndis_dev, "usb xfer warning (%s)\n", + usbd_errstr(error)); + } + usbd_xfer_complete(sc, ne, nx, error); + if (error != USB_ERR_CANCELLED) + goto next; + break; + } +} + +static struct ndisusb_ep * +usbd_get_ndisep(irp *ip, usb_endpoint_descriptor_t *ep) +{ + device_t dev = IRP_NDIS_DEV(ip); + struct ndis_softc *sc = device_get_softc(dev); + struct ndisusb_ep *ne; + + ne = &sc->ndisusb_ep[NDISUSB_GET_ENDPT(ep->bEndpointAddress)]; + + IRP_NDISUSB_EP(ip) = ne; + ip->irp_cancelfunc = (cancel_func)usbd_irpcancel_wrap; + + return (ne); +} + +static void +usbd_xfertask(device_object *dobj, void *arg) +{ + int error; + irp *ip; + device_t dev; + list_entry *l; + struct ndis_softc *sc = arg; + struct ndisusb_xferdone *nd; + struct ndisusb_xfer *nq; + struct usbd_urb_bulk_or_intr_transfer *ubi; + struct usbd_urb_vendor_or_class_request *vcreq; + union usbd_urb *urb; + usb_error_t status; + void *priv; + + dev = sc->ndis_dev; + + if (IsListEmpty(&sc->ndisusb_xferdonelist)) + return; + + KeAcquireSpinLockAtDpcLevel(&sc->ndisusb_xferdonelock); + l = sc->ndisusb_xferdonelist.nle_flink; + while (l != &sc->ndisusb_xferdonelist) { + nd = CONTAINING_RECORD(l, struct ndisusb_xferdone, nd_donelist); + nq = nd->nd_xfer; + priv = nq->nx_priv; + status = nd->nd_status; + error = 0; + ip = priv; + urb = usbd_geturb(ip); + + ip->irp_cancelfunc = NULL; + IRP_NDISUSB_EP(ip) = NULL; + + switch (status) { + case USB_ERR_NORMAL_COMPLETION: + if (urb->uu_hdr.uuh_func == + URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER) { + ubi = &urb->uu_bulkintr; + ubi->ubi_trans_buflen = nq->nx_urbactlen; + } else { + vcreq = &urb->uu_vcreq; + vcreq->uvc_trans_buflen = nq->nx_urbactlen; + } + ip->irp_iostat.isb_info = nq->nx_urbactlen; + ip->irp_iostat.isb_status = STATUS_SUCCESS; + USBD_URB_STATUS(urb) = USBD_STATUS_SUCCESS; + break; + case USB_ERR_CANCELLED: + ip->irp_iostat.isb_info = 0; + ip->irp_iostat.isb_status = STATUS_CANCELLED; + USBD_URB_STATUS(urb) = USBD_STATUS_CANCELED; + break; + default: + ip->irp_iostat.isb_info = 0; + USBD_URB_STATUS(urb) = usbd_usb2urb(status); + ip->irp_iostat.isb_status = + usbd_urb2nt(USBD_URB_STATUS(urb)); + break; + } + + l = l->nle_flink; + RemoveEntryList(&nd->nd_donelist); + free(nq, M_USBDEV); + free(nd, M_USBDEV); + if (error) + continue; + KeReleaseSpinLockFromDpcLevel(&sc->ndisusb_xferdonelock); + /* NB: call after cleaning */ + IoCompleteRequest(ip, IO_NO_INCREMENT); + KeAcquireSpinLockAtDpcLevel(&sc->ndisusb_xferdonelock); + } + KeReleaseSpinLockFromDpcLevel(&sc->ndisusb_xferdonelock); +} + +/* + * this function is for mainly deferring a task to the another thread because + * we don't want to be in the scope of HAL lock. + */ +static int32_t +usbd_taskadd(irp *ip, unsigned type) +{ + device_t dev = IRP_NDIS_DEV(ip); + struct ndis_softc *sc = device_get_softc(dev); + struct ndisusb_task *nt; + + nt = malloc(sizeof(struct ndisusb_task), M_USBDEV, M_NOWAIT | M_ZERO); + if (nt == NULL) + return (USBD_STATUS_NO_MEMORY); + nt->nt_type = type; + nt->nt_ctx = ip; + + KeAcquireSpinLockAtDpcLevel(&sc->ndisusb_tasklock); + InsertTailList((&sc->ndisusb_tasklist), (&nt->nt_tasklist)); + KeReleaseSpinLockFromDpcLevel(&sc->ndisusb_tasklock); + + IoQueueWorkItem(sc->ndisusb_taskitem, + (io_workitem_func)usbd_task_wrap, WORKQUEUE_CRITICAL, sc); + + return (USBD_STATUS_SUCCESS); +} + +static void +usbd_task(device_object *dobj, void *arg) +{ + irp *ip; + list_entry *l; + struct ndis_softc *sc = arg; + struct ndisusb_ep *ne; + struct ndisusb_task *nt; + union usbd_urb *urb; + + if (IsListEmpty(&sc->ndisusb_tasklist)) + return; + + KeAcquireSpinLockAtDpcLevel(&sc->ndisusb_tasklock); + l = sc->ndisusb_tasklist.nle_flink; + while (l != &sc->ndisusb_tasklist) { + nt = CONTAINING_RECORD(l, struct ndisusb_task, nt_tasklist); + + ip = nt->nt_ctx; + urb = usbd_geturb(ip); + + KeReleaseSpinLockFromDpcLevel(&sc->ndisusb_tasklock); + NDISUSB_LOCK(sc); + switch (nt->nt_type) { + case NDISUSB_TASK_TSTART: + ne = usbd_get_ndisep(ip, urb->uu_bulkintr.ubi_epdesc); + if (ne == NULL) + goto exit; + usbd_transfer_start(ne->ne_xfer[0]); + break; + case NDISUSB_TASK_IRPCANCEL: + ne = usbd_get_ndisep(ip, + (nt->nt_type == NDISUSB_TASK_IRPCANCEL) ? + urb->uu_bulkintr.ubi_epdesc : + urb->uu_pipe.upr_handle); + if (ne == NULL) + goto exit; + + usbd_transfer_stop(ne->ne_xfer[0]); + usbd_transfer_start(ne->ne_xfer[0]); + break; + case NDISUSB_TASK_VENDOR: + ne = (urb->uu_vcreq.uvc_trans_flags & + USBD_TRANSFER_DIRECTION_IN) ? + &sc->ndisusb_dread_ep : &sc->ndisusb_dwrite_ep; + usbd_transfer_start(ne->ne_xfer[0]); + break; + default: + break; + } +exit: + NDISUSB_UNLOCK(sc); + KeAcquireSpinLockAtDpcLevel(&sc->ndisusb_tasklock); + + l = l->nle_flink; + RemoveEntryList(&nt->nt_tasklist); + free(nt, M_USBDEV); + } + KeReleaseSpinLockFromDpcLevel(&sc->ndisusb_tasklock); +} + +static int32_t +usbd_func_bulkintr(irp *ip) +{ + int32_t error; + struct ndisusb_ep *ne; + struct ndisusb_xfer *nx; + struct usbd_urb_bulk_or_intr_transfer *ubi; + union usbd_urb *urb; + usb_endpoint_descriptor_t *ep; + + urb = usbd_geturb(ip); + ubi = &urb->uu_bulkintr; + ep = ubi->ubi_epdesc; + if (ep == NULL) + return (USBD_STATUS_INVALID_PIPE_HANDLE); + + ne = usbd_get_ndisep(ip, ep); + if (ne == NULL) { + device_printf(IRP_NDIS_DEV(ip), "get NULL endpoint info.\n"); + return (USBD_STATUS_INVALID_PIPE_HANDLE); + } + + nx = malloc(sizeof(struct ndisusb_xfer), M_USBDEV, M_NOWAIT | M_ZERO); + if (nx == NULL) { + device_printf(IRP_NDIS_DEV(ip), "out of memory\n"); + return (USBD_STATUS_NO_MEMORY); + } + nx->nx_ep = ne; + nx->nx_priv = ip; + KeAcquireSpinLockAtDpcLevel(&ne->ne_lock); + InsertTailList((&ne->ne_pending), (&nx->nx_next)); + KeReleaseSpinLockFromDpcLevel(&ne->ne_lock); + + /* we've done to setup xfer. Let's transfer it. */ + ip->irp_iostat.isb_status = STATUS_PENDING; + ip->irp_iostat.isb_info = 0; + USBD_URB_STATUS(urb) = USBD_STATUS_PENDING; + IoMarkIrpPending(ip); + + error = usbd_taskadd(ip, NDISUSB_TASK_TSTART); + if (error != USBD_STATUS_SUCCESS) + return (error); + + return (USBD_STATUS_PENDING); +} + +static union usbd_urb * +USBD_CreateConfigurationRequest(usb_config_descriptor_t *conf, uint16_t *len) +{ + struct usbd_interface_list_entry list[2]; + union usbd_urb *urb; + + bzero(list, sizeof(struct usbd_interface_list_entry) * 2); + list[0].uil_intfdesc = USBD_ParseConfigurationDescriptorEx(conf, conf, + -1, -1, -1, -1, -1); + urb = USBD_CreateConfigurationRequestEx(conf, list); + if (urb == NULL) + return (NULL); + + *len = urb->uu_selconf.usc_hdr.uuh_len; + return (urb); +} + +static union usbd_urb * +USBD_CreateConfigurationRequestEx(usb_config_descriptor_t *conf, + struct usbd_interface_list_entry *list) +{ + int i, j, size; + struct usbd_interface_information *intf; + struct usbd_pipe_information *pipe; + struct usbd_urb_select_configuration *selconf; + usb_interface_descriptor_t *desc; + + for (i = 0, size = 0; i < conf->bNumInterface; i++) { + j = list[i].uil_intfdesc->bNumEndpoints; + size = size + sizeof(struct usbd_interface_information) + + sizeof(struct usbd_pipe_information) * (j - 1); + } + size += sizeof(struct usbd_urb_select_configuration) - + sizeof(struct usbd_interface_information); + + selconf = ExAllocatePoolWithTag(NonPagedPool, size, 0); + if (selconf == NULL) + return (NULL); + selconf->usc_hdr.uuh_func = URB_FUNCTION_SELECT_CONFIGURATION; + selconf->usc_hdr.uuh_len = size; + selconf->usc_handle = conf; + selconf->usc_conf = conf; + + intf = &selconf->usc_intf; + for (i = 0; i < conf->bNumInterface; i++) { + if (list[i].uil_intfdesc == NULL) + break; + + list[i].uil_intf = intf; + desc = list[i].uil_intfdesc; + + intf->uii_len = sizeof(struct usbd_interface_information) + + (desc->bNumEndpoints - 1) * + sizeof(struct usbd_pipe_information); + intf->uii_intfnum = desc->bInterfaceNumber; + intf->uii_altset = desc->bAlternateSetting; + intf->uii_intfclass = desc->bInterfaceClass; + intf->uii_intfsubclass = desc->bInterfaceSubClass; + intf->uii_intfproto = desc->bInterfaceProtocol; + intf->uii_handle = desc; + intf->uii_numeps = desc->bNumEndpoints; + + pipe = &intf->uii_pipes[0]; + for (j = 0; j < intf->uii_numeps; j++) + pipe[j].upi_maxtxsize = + USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE; + + intf = (struct usbd_interface_information *)((char *)intf + + intf->uii_len); + } + + return ((union usbd_urb *)selconf); +} + +static void +USBD_GetUSBDIVersion(usbd_version_info *ui) +{ + + /* Pretend to be Windows XP. */ + + ui->uvi_usbdi_vers = USBDI_VERSION; + ui->uvi_supported_vers = USB_VER_2_0; +} + +static usb_interface_descriptor_t * +USBD_ParseConfigurationDescriptor(usb_config_descriptor_t *conf, + uint8_t intfnum, uint8_t altset) +{ + + return USBD_ParseConfigurationDescriptorEx(conf, conf, intfnum, altset, + -1, -1, -1); +} + +static usb_interface_descriptor_t * +USBD_ParseConfigurationDescriptorEx(usb_config_descriptor_t *conf, + void *start, int32_t intfnum, int32_t altset, int32_t intfclass, + int32_t intfsubclass, int32_t intfproto) +{ + struct usb_descriptor *next = NULL; + usb_interface_descriptor_t *desc; + + while ((next = usb_desc_foreach(conf, next)) != NULL) { + desc = (usb_interface_descriptor_t *)next; + if (desc->bDescriptorType != UDESC_INTERFACE) + continue; + if (!(intfnum == -1 || desc->bInterfaceNumber == intfnum)) + continue; + if (!(altset == -1 || desc->bAlternateSetting == altset)) + continue; + if (!(intfclass == -1 || desc->bInterfaceClass == intfclass)) + continue; + if (!(intfsubclass == -1 || + desc->bInterfaceSubClass == intfsubclass)) + continue; + if (!(intfproto == -1 || desc->bInterfaceProtocol == intfproto)) + continue; + return (desc); + } + + return (NULL); +} + +static void +dummy(void) +{ + printf("USBD dummy called\n"); +} + +image_patch_table usbd_functbl[] = { + IMPORT_SFUNC(USBD_CreateConfigurationRequest, 2), + IMPORT_SFUNC(USBD_CreateConfigurationRequestEx, 2), + IMPORT_SFUNC_MAP(_USBD_CreateConfigurationRequestEx@8, + USBD_CreateConfigurationRequestEx, 2), + IMPORT_SFUNC(USBD_GetUSBDIVersion, 1), + IMPORT_SFUNC(USBD_ParseConfigurationDescriptor, 3), + IMPORT_SFUNC(USBD_ParseConfigurationDescriptorEx, 7), + IMPORT_SFUNC_MAP(_USBD_ParseConfigurationDescriptorEx@28, + USBD_ParseConfigurationDescriptorEx, 7), + + /* + * This last entry is a catch-all for any function we haven't + * implemented yet. The PE import list patching routine will + * use it for any function that doesn't have an explicit match + * in this table. + */ + + { NULL, (FUNC)dummy, NULL, 0, WINDRV_WRAP_STDCALL }, + + /* End of list. */ + + { NULL, NULL, NULL } +}; + +MODULE_DEPEND(ndis, usb, 1, 1, 1); diff --git a/sys/compat/ndis/usbd_var.h b/sys/compat/ndis/usbd_var.h new file mode 100644 index 0000000..019bd32 --- /dev/null +++ b/sys/compat/ndis/usbd_var.h @@ -0,0 +1,222 @@ +/*- + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.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, 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 Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD + * 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 _USBD_VAR_H_ +#define _USBD_VAR_H_ + +#define IOCTL_INTERNAL_USB_SUBMIT_URB 0x00220003 + +#define URB_FUNCTION_SELECT_CONFIGURATION 0x0000 +#define URB_FUNCTION_ABORT_PIPE 0x0002 +#define URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER 0x0009 +#define URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE 0x000B +#define URB_FUNCTION_VENDOR_DEVICE 0x0017 +#define URB_FUNCTION_VENDOR_INTERFACE 0x0018 +#define URB_FUNCTION_VENDOR_ENDPOINT 0x0019 +#define URB_FUNCTION_CLASS_DEVICE 0x001A +#define URB_FUNCTION_CLASS_INTERFACE 0x001B +#define URB_FUNCTION_CLASS_ENDPOINT 0x001C +#define URB_FUNCTION_CLASS_OTHER 0x001F +#define URB_FUNCTION_VENDOR_OTHER 0x0020 + +#define USBD_STATUS_SUCCESS 0x00000000 +#define USBD_STATUS_CANCELED 0x00010000 +#define USBD_STATUS_PENDING 0x40000000 +#define USBD_STATUS_NO_MEMORY 0x80000100 +#define USBD_STATUS_REQUEST_FAILED 0x80000500 +#define USBD_STATUS_INVALID_PIPE_HANDLE 0x80000600 +#define USBD_STATUS_ERROR_SHORT_TRANSFER 0x80000900 +#define USBD_STATUS_CRC 0xC0000001 +#define USBD_STATUS_BTSTUFF 0xC0000002 +#define USBD_STATUS_DATA_TOGGLE_MISMATCH 0xC0000003 +#define USBD_STATUS_STALL_PID 0xC0000004 +#define USBD_STATUS_DEV_NOT_RESPONDING 0xC0000005 +#define USBD_STATUS_PID_CHECK_FAILURE 0xC0000006 +#define USBD_STATUS_UNEXPECTED_PID 0xC0000007 +#define USBD_STATUS_DATA_OVERRUN 0xC0000008 +#define USBD_STATUS_DATA_UNDERRUN 0xC0000009 +#define USBD_STATUS_RESERVED1 0xC000000A +#define USBD_STATUS_RESERVED2 0xC000000B +#define USBD_STATUS_BUFFER_OVERRUN 0xC000000C +#define USBD_STATUS_BUFFER_UNDERRUN 0xC000000D +#define USBD_STATUS_NOT_ACCESSED 0xC000000F +#define USBD_STATUS_FIFO 0xC0000010 +#define USBD_STATUS_XACT_ERROR 0xC0000011 +#define USBD_STATUS_BABBLE_DETECTED 0xC0000012 +#define USBD_STATUS_DATA_BUFFER_ERROR 0xC0000013 +#define USBD_STATUS_NOT_SUPPORTED 0xC0000E00 +#define USBD_STATUS_TIMEOUT 0xC0006000 +#define USBD_STATUS_DEVICE_GONE 0xC0007000 + +struct usbd_urb_header { + uint16_t uuh_len; + uint16_t uuh_func; + int32_t uuh_status; + void *uuh_handle; + uint32_t uuh_flags; +}; + +enum usbd_pipe_type { + UsbdPipeTypeControl = UE_CONTROL, + UsbdPipeTypeIsochronous = UE_ISOCHRONOUS, + UsbdPipeTypeBulk = UE_BULK, + UsbdPipeTypeInterrupt = UE_INTERRUPT +}; + +struct usbd_pipe_information { + uint16_t upi_maxpktsize; + uint8_t upi_epaddr; + uint8_t upi_interval; + enum usbd_pipe_type upi_type; + usb_endpoint_descriptor_t *upi_handle; + uint32_t upi_maxtxsize; +#define USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE PAGE_SIZE + uint32_t upi_flags; +}; + +struct usbd_interface_information { + uint16_t uii_len; + uint8_t uii_intfnum; + uint8_t uii_altset; + uint8_t uii_intfclass; + uint8_t uii_intfsubclass; + uint8_t uii_intfproto; + uint8_t uii_reserved; + void *uii_handle; + uint32_t uii_numeps; + struct usbd_pipe_information uii_pipes[1]; +}; + +struct usbd_urb_select_interface { + struct usbd_urb_header usi_hdr; + void *usi_handle; + struct usbd_interface_information uusi_intf; +}; + +struct usbd_urb_select_configuration { + struct usbd_urb_header usc_hdr; + usb_config_descriptor_t *usc_conf; + void *usc_handle; + struct usbd_interface_information usc_intf; +}; + +struct usbd_urb_pipe_request { + struct usbd_urb_header upr_hdr; + usb_endpoint_descriptor_t *upr_handle; +}; + +struct usbd_hcd_area { + void *reserved8[8]; +}; + +struct usbd_urb_bulk_or_intr_transfer { + struct usbd_urb_header ubi_hdr; + usb_endpoint_descriptor_t *ubi_epdesc; + uint32_t ubi_trans_flags; +#define USBD_SHORT_TRANSFER_OK 0x00000002 + uint32_t ubi_trans_buflen; + void *ubi_trans_buf; + struct mdl *ubi_mdl; + union usbd_urb *ubi_urblink; + struct usbd_hcd_area ubi_hca; +}; + +struct usbd_urb_control_descriptor_request { + struct usbd_urb_header ucd_hdr; + void *ucd_reserved0; + uint32_t ucd_reserved1; + uint32_t ucd_trans_buflen; + void *ucd_trans_buf; + struct mdl *ucd_mdl; + union nt_urb *ucd_urblink; + struct usbd_hcd_area ucd_hca; + uint16_t ucd_reserved2; + uint8_t ucd_idx; + uint8_t ucd_desctype; + uint16_t ucd_langid; + uint16_t ucd_reserved3; +}; + +struct usbd_urb_vendor_or_class_request { + struct usbd_urb_header uvc_hdr; + void *uvc_reserved0; + uint32_t uvc_trans_flags; +#define USBD_TRANSFER_DIRECTION_IN 1 + uint32_t uvc_trans_buflen; + void *uvc_trans_buf; + struct mdl *uvc_mdl; + union nt_urb *uvc_urblink; + struct usbd_hcd_area uvc_hca; + uint8_t uvc_reserved1; + uint8_t uvc_req; + uint16_t uvc_value; + uint16_t uvc_idx; + uint16_t uvc_reserved2; +}; + +struct usbd_interface_list_entry { + usb_interface_descriptor_t *uil_intfdesc; + struct usbd_interface_information *uil_intf; +}; + +union usbd_urb { + struct usbd_urb_header uu_hdr; + struct usbd_urb_select_configuration uu_selconf; + struct usbd_urb_bulk_or_intr_transfer uu_bulkintr; + struct usbd_urb_control_descriptor_request uu_ctldesc; + struct usbd_urb_vendor_or_class_request uu_vcreq; + struct usbd_urb_pipe_request uu_pipe; +}; + +#define USBD_URB_STATUS(urb) ((urb)->uu_hdr.uuh_status) + +#define USBDI_VERSION 0x00000500 +#define USB_VER_1_1 0x00000110 +#define USB_VER_2_0 0x00000200 + +struct usbd_version_info { + uint32_t uvi_usbdi_vers; + uint32_t uvi_supported_vers; +}; + +typedef struct usbd_version_info usbd_version_info; + +extern image_patch_table usbd_functbl[]; + +__BEGIN_DECLS +extern int usbd_libinit(void); +extern int usbd_libfini(void); +__END_DECLS + +#endif /* _USBD_VAR_H_ */ diff --git a/sys/compat/ndis/winx32_wrap.S b/sys/compat/ndis/winx32_wrap.S new file mode 100644 index 0000000..c051504 --- /dev/null +++ b/sys/compat/ndis/winx32_wrap.S @@ -0,0 +1,385 @@ +/*- + * Copyright (c) 2005 + * Bill Paul <wpaul@windriver.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, 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 Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD + * 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$ + */ + +/* The 'ret' macro doesn't work in this file if GPROF is enabled. */ +#ifdef GPROF +#undef GPROF +#endif + +#include <machine/asmacros.h> + +/* + * This file contains assembly language wrappers for the different + * calling conventions supported by Windows on the i386 architecture. + * In FreeBSD, the whole OS typically use same C calling convention + * everywhere, namely _cdecl. Windows, on the other hand, uses several + * different C calling conventions depending on the circumstances: + * + * _stdcall: Used for most ordinary Windows APIs. With _stdcall, + * arguments are passed on the stack, and the callee unwinds the stack + * before returning control to the caller. Not suitable for variadic + * functions. + * + * _fastcall: Used for some APIs that may be invoked frequently and + * where speed is a critical factor (e.g. KeAcquireSpinLock() and + * KeReleaseSpinLock()) Similar to _stdcall, except the first 2 32-bit + * or smaller arguments are passed in the %ecx and %edx registers + * instead of on the stack. Not suitable for variadic functions. + * + * _cdecl: Used for standard C library routines and for variadic + * functions. + * + * _regparm(3): Used for certain assembly routines. All arguments + * passed in %eax, %ecx and %edx. + * + * Furthermore, there is an additional wrinkle that's not obvious + * with all code: Microsoft supports the use of exceptions in C + * (__try/__except) both in user _and_ kernel mode. Sadly, Windows + * structured exception handling uses machine-specific features + * that conflict rather badly with FreeBSD. (See utility routines + * at the end of this module for more details.) + * + * We want to support these calling conventions in as portable a manner + * as possible. The trick is doing it not only with different versions + * of GNU C, but with compilers other than GNU C (e.g. the Solaris + * SunOne C compiler). The only sure fire method is with assembly + * language trampoline code which both fixes up the argument passing, + * stack unwinding and exception/thread context all at once. + * + * You'll notice that we call the thunk/unthunk routines in the + * *_wrap() functions in an awkward way. Rather than branching + * directly to the address, we load the address into a register + * first as a literal value, then we branch to it. This is done + * to insure that the assembler doesn't translate the branch into + * a relative branch. We use the *_wrap() routines here as templates + * and create the actual trampolines at run time, at which point + * we only know the absolute addresses of the thunk and unthunk + * routines. So we need to make sure the templates have enough + * room in them for the full address. + * + * Also note that when we call the a thunk/unthunk routine after + * invoking a wrapped function, we have to make sure to preserve + * the value returned from that function. Most functions return + * a 32-bit value in %eax, however some routines return 64-bit + * values, which span both %eax and %edx. Consequently, we have + * to preserve both registers. + */ + +/* + * Handle _stdcall going from Windows to UNIX. + * This is frustrating, because to do it right you have to + * know how many arguments the called function takes, and there's + * no way to figure this out on the fly: you just have to be told + * ahead of time. We assume there will be 16 arguments. I don't + * think there are any Windows APIs that require this many. + */ + + .globl x86_stdcall_wrap_call + .globl x86_stdcall_wrap_arg + .globl x86_stdcall_wrap_end + +ENTRY(x86_stdcall_wrap) + push %esi + push %edi + sub $64,%esp + mov %esp,%esi + add $64+8+4,%esi + mov %esp,%edi + mov $16,%ecx # handle up to 16 args + rep + movsl + + movl $ctxsw_wtou, %eax + call *%eax # unthunk + +x86_stdcall_wrap_call: + movl $0,%eax + call *%eax # jump to routine + push %eax # preserve return val + push %edx + + movl $ctxsw_utow, %eax + call *%eax # thunk + + pop %edx + pop %eax # restore return val + + add $64,%esp # clean the stack + pop %edi + pop %esi +x86_stdcall_wrap_arg: + ret $0xFF +x86_stdcall_wrap_end: + + +/* + * Handle _stdcall going from UNIX to Windows. This routine + * expects to be passed the function to be called, number of + * args and the arguments for the Windows function on the stack. + */ + +ENTRY(x86_stdcall_call) + push %esi # must preserve %esi + push %edi # and %edi + + mov 16(%esp),%eax # get arg cnt + mov %eax,%ecx # save as copy count + mov %esp,%esi # Set source address register to point to + add $20,%esi # first agument to be forwarded. + shl $2,%eax # turn arg cnt into offset + sub %eax,%esp # shift stack to new location + mov %esp,%edi # store dest copy addr + rep # do the copy + movsl + + call ctxsw_utow # thunk + + call *12(%edi) # branch to stdcall routine + push %eax # preserve return val + push %edx + + call ctxsw_wtou # unthunk + + pop %edx + pop %eax # restore return val + mov %edi,%esp # restore stack + pop %edi # restore %edi + pop %esi # and %esi + ret + +/* + * Fastcall support. Similar to _stdcall, except the first + * two arguments are passed in %ecx and %edx. It happens we + * only support a small number of _fastcall APIs, none of them + * take more than three arguments. So to keep the code size + * and complexity down, we only handle 3 arguments here. + */ + +/* Call _fastcall function going from Windows to UNIX. */ + + .globl x86_fastcall_wrap_call + .globl x86_fastcall_wrap_arg + .globl x86_fastcall_wrap_end + +ENTRY(x86_fastcall_wrap) + mov 4(%esp),%eax + push %eax + push %edx + push %ecx + + movl $ctxsw_wtou, %eax + call *%eax # unthunk + +x86_fastcall_wrap_call: + mov $0,%eax + call *%eax # branch to fastcall routine + push %eax # preserve return val + push %edx + + movl $ctxsw_utow, %eax + call *%eax # thunk + + pop %edx + pop %eax # restore return val + add $12,%esp # clean the stack +x86_fastcall_wrap_arg: + ret $0xFF +x86_fastcall_wrap_end: + +/* + * Call _fastcall function going from UNIX to Windows. + * This routine isn't normally used since NDIS miniport drivers + * only have _stdcall entry points, but it's provided anyway + * to round out the API, and for testing purposes. + */ + +ENTRY(x86_fastcall_call) + mov 4(%esp),%eax + push 16(%esp) + + call ctxsw_utow # thunk + + mov 12(%esp),%ecx + mov 16(%esp),%edx + call *8(%esp) # branch to fastcall routine + push %eax # preserve return val + push %edx + + call ctxsw_wtou # unthunk + + pop %edx + pop %eax # restore return val + add $4,%esp # clean the stack + ret + +/* + * Call regparm(3) function going from Windows to UNIX. Arguments + * are passed in %eax, %edx and %ecx. Note that while additional + * arguments are passed on the stack, we never bother when them, + * since the only regparm(3) routines we need to wrap never take + * more than 3 arguments. + */ + + .globl x86_regparm_wrap_call + .globl x86_regparm_wrap_end + +ENTRY(x86_regparm_wrap) + push %ecx + push %edx + push %eax + + movl $ctxsw_wtou, %eax + call *%eax # unthunk + +x86_regparm_wrap_call: + movl $0,%eax + call *%eax # jump to routine + push %eax # preserve return val + push %edx # preserve return val + + movl $ctxsw_utow, %eax + call *%eax # thunk + + pop %edx # restore return val + pop %eax # restore return val + add $12,%esp # restore stack + ret +x86_regparm_wrap_end: + +/* + * Call regparm(3) function going from UNIX to Windows. + * This routine isn't normally used since NDIS miniport drivers + * only have _stdcall entry points, but it's provided anyway + * to round out the API, and for testing purposes. + */ + +ENTRY(x86_regparm_call) + call ctxsw_utow # thunk + + mov 8(%esp),%eax + mov 12(%esp),%edx + mov 16(%esp),%ecx + call *4(%esp) # branch to fastcall routine + push %eax # preserve return val + push %edx # preserve return val + + call ctxsw_wtou # unthunk + + pop %edx # restore return val + pop %eax # restore return val + ret + +/* + * Ugly hack alert: + * + * On Win32/i386, using __try/__except results in code that tries to + * manipulate what's supposed to be the Windows Threada Environment + * Block (TEB), which one accesses via the %fs register. In particular, + * %fs:0 (the first DWORD in the TEB) points to the exception + * registration list. Unfortunately, FreeBSD uses %fs for the + * per-cpu data structure (pcpu), and we can't allow Windows code + * to muck with that. I don't even know what Solaris uses %fs for + * (or if it even uses it at all). + * + * Even worse, in 32-bit protected mode, %fs is a selector that + * refers to an entry in either the GDT or the LDT. Ideally, we would + * like to be able to temporarily point it at another descriptor + * while Windows code executes, but to do that we need a separate + * descriptor entry of our own to play with. + * + * Therefore, we go to some trouble to learn the existing layout of + * the GDT and update it to include an extra entry that we can use. + * We need the following utility routines to help us do that. On + * FreeBSD, index #7 in the GDT happens to be unused, so we turn + * this into our own data segment descriptor. It would be better + * if we could use a private LDT entry, but there's no easy way to + * do that in SMP mode because of the way FreeBSD handles user LDTs. + * + * Once we have a custom descriptor, we have to thunk/unthunk whenever + * we cross between FreeBSD code and Windows code. The thunking is + * based on the premise that when executing instructions in the + * Windows binary itself, we won't go to sleep. This is because in + * order to yield the CPU, the code has to call back out to a FreeBSD + * routine first, and when that happens we can unthunk in order to + * restore FreeBSD context. What we're desperately trying to avoid is + * being involuntarily pre-empted with the %fs register still pointing + * to our fake TIB: if FreeBSD code runs with %fs pointing at our + * Windows TIB instead of pcpu, we'll panic the kernel. Fortunately, + * the only way involuntary preemption can occur is if an interrupt + * fires, and the trap handler saves/restores %fs for us. + * + * The thunking routines themselves, ctxsw_utow() (Context SWitch UNIX + * to Windows) and ctxsw_wtou() (Context SWitch Windows to UNIX), are + * external to this module. This is done simply because it's easier + * to manipulate data structures in C rather than assembly. + */ + +ENTRY(x86_getldt) + movl 4(%esp),%eax + sgdtl (%eax) + movl 8(%esp),%eax + sldt (%eax) + xor %eax,%eax + ret + +ENTRY(x86_setldt) + movl 4(%esp),%eax + lgdt (%eax) + jmp 1f + nop +1: + movl 8(%esp),%eax + lldt %ax + xor %eax,%eax + ret + +ENTRY(x86_getfs) + mov %fs,%ax + ret + +ENTRY(x86_setfs) + mov 4(%esp),%fs + ret + +ENTRY(x86_gettid) + mov %fs:12,%eax + ret + +ENTRY(x86_critical_enter) + cli + ret + +ENTRY(x86_critical_exit) + sti + ret diff --git a/sys/compat/ndis/winx64_wrap.S b/sys/compat/ndis/winx64_wrap.S new file mode 100644 index 0000000..3e5d994 --- /dev/null +++ b/sys/compat/ndis/winx64_wrap.S @@ -0,0 +1,179 @@ +/*- + * Copyright (c) 2005 + * Bill Paul <wpaul@windriver.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, 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 Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD + * 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. + * + * The x86_64 callback routines were written and graciously submitted + * by Ville-Pertti Keinonen <will@exomi.com>. + * + * $FreeBSD$ + */ + +#include <machine/asmacros.h> + +/* + * Wrapper for handling up to 16 arguments. We can't really + * know how many arguments the caller will pass us. I'm taking an + * educated guess that we'll never get over 16. Handling too + * few arguments is bad. Handling too many is inefficient, but + * not fatal. If someone can think of a way to handle an arbitrary + * number of arguments with more elegant code, freel free to let + * me know. + * + * Standard amd64 calling conventions specify the following registers + * to be used for passing the first 6 arguments: + * + * %rdi, %rsi, %rdx, %rcx, %r8, %r9 + * + * Further arguments are passed on the stack (the 7th argument is + * located immediately after the return address). + * + * Windows x86_64 calling conventions only pass the first 4 + * arguments in registers: + * + * %rcx, %rdx, %r8, %r9 + * + * Even when arguments are passed in registers, the stack must have + * space reserved for those arguments. Thus the 5th argument (the + * first non-register argument) is placed 32 bytes after the return + * address. Additionally, %rdi and %rsi must be preserved. (These + * two registers are not scratch registers in the standard convention.) + * + * Note that in this template, we load a contrived 64 bit address into + * %r11 to represent our jump address. This is to guarantee that the + * assembler leaves enough room to patch in an absolute 64-bit address + * later. The idea behind this code is that we want to avoid having to + * manually create all the wrapper functions at compile time with + * a bunch of macros. This is doable, but a) messy and b) requires + * us to maintain two separate tables (one for the UNIX function + * pointers and another with the wrappers). This means I'd have to + * update two different tables each time I added a function. + * + * To avoid this, we create the wrappers at runtime instead. The + * image patch tables now contain two pointers: one two the normal + * routine, and a blank one for the wrapper. To construct a wrapper, + * we allocate some memory and copy the template function into it, + * then patch the function pointer for the routine we want to wrap + * into the newly created wrapper. The subr_pe module can then + * simply patch the wrapper routine into the jump table into the + * windows image. As a bonus, the wrapper pointer not only serves + * as the wrapper entry point address, it's also a data pointer + * that we can pass to free() later when we unload the module. + */ + + .globl x86_64_wrap_call + .globl x86_64_wrap_end + +ENTRY(x86_64_wrap) + push %rbp # insure that the stack + mov %rsp,%rbp # is 16-byte aligned + and $-16,%rsp # + subq $96,%rsp # allocate space on stack + mov %rsi,96-8(%rsp) # save %rsi + mov %rdi,96-16(%rsp)# save %rdi + mov %rcx,%r10 # temporarily save %rcx in scratch + lea 56+8(%rbp),%rsi # source == old stack top (stack+56) + mov %rsp,%rdi # destination == new stack top + mov $10,%rcx # count == 10 quadwords + rep + movsq # copy old stack contents to new location + mov %r10,%rdi # set up arg0 (%rcx -> %rdi) + mov %rdx,%rsi # set up arg1 (%rdx -> %rsi) + mov %r8,%rdx # set up arg2 (%r8 -> %rdx) + mov %r9,%rcx # set up arg3 (%r9 -> %rcx) + mov 40+8(%rbp),%r8 # set up arg4 (stack+40 -> %r8) + mov 48+8(%rbp),%r9 # set up arg5 (stack+48 -> %r9) + xor %rax,%rax # clear return value +x86_64_wrap_call: + mov $0xFF00FF00FF00FF00,%r11 + callq *%r11 # call routine + mov 96-16(%rsp),%rdi# restore %rdi + mov 96-8(%rsp),%rsi # restore %rsi + leave # delete space on stack + ret +x86_64_wrap_end: + +/* + * Functions for invoking x86_64 callbacks. In each case, the first + * argument is a pointer to the function. + */ + +ENTRY(x86_64_call1) + subq $40,%rsp + mov %rsi,%rcx + call *%rdi + addq $40,%rsp + ret + +ENTRY(x86_64_call2) + subq $40,%rsp + mov %rsi,%rcx + /* %rdx is already correct */ + call *%rdi + addq $40,%rsp + ret + +ENTRY(x86_64_call3) + subq $40,%rsp + mov %rcx,%r8 + mov %rsi,%rcx + call *%rdi + addq $40,%rsp + ret + +ENTRY(x86_64_call4) + subq $40,%rsp + mov %r8,%r9 + mov %rcx,%r8 + mov %rsi,%rcx + call *%rdi + addq $40,%rsp + ret + +ENTRY(x86_64_call5) + subq $48,%rsp + mov %r9,32(%rsp) + mov %r8,%r9 + mov %rcx,%r8 + mov %rsi,%rcx + call *%rdi + addq $48,%rsp + ret + +ENTRY(x86_64_call6) + subq $56,%rsp + mov 56+8(%rsp),%rax + mov %r9,32(%rsp) + mov %rax,40(%rsp) + mov %r8,%r9 + mov %rcx,%r8 + mov %rsi,%rcx + call *%rdi + addq $56,%rsp + ret diff --git a/sys/compat/netbsd/dvcfg.h b/sys/compat/netbsd/dvcfg.h new file mode 100644 index 0000000..817ab3d --- /dev/null +++ b/sys/compat/netbsd/dvcfg.h @@ -0,0 +1,65 @@ +/* $FreeBSD$ */ +/* $NetBSD$ */ +/*- + * [NetBSD for NEC PC98 series] + * Copyright (c) 1996 NetBSD/pc98 porting staff. + * 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. + */ +/* + * Copyright (c) 1996 Naofumi HONDA. All rights reserved. + */ + +#ifndef _COMPAT_NETBSD_DVCFG_H_ +#define _COMPAT_NETBSD_DVCFG_H_ + +typedef void *dvcfg_hw_t; + +struct dvcfg_hwsel { + int cfg_max; + + dvcfg_hw_t *cfg_sel; +}; + +#define DVCFG_MAJOR(dvcfg) (((u_int)(dvcfg)) >> 16) +#define DVCFG_MINOR(dvcfg) (((u_int)(dvcfg)) & 0xffff) + +#define DVCFG_MKCFG(major, minor) ((((u_int)(major)) << 16) | ((minor) & 0xffff)) + +#define DVCFG_HWSEL_SZ(array) (sizeof(array) / sizeof(dvcfg_hw_t)) + +static __inline dvcfg_hw_t dvcfg_hw(struct dvcfg_hwsel *, u_int); + +static __inline dvcfg_hw_t +dvcfg_hw(selp, num) + struct dvcfg_hwsel *selp; + u_int num; +{ + + return ((num >= selp->cfg_max) ? 0 : selp->cfg_sel[num]); +} + +#define DVCFG_HW(SELP, NUM) dvcfg_hw((SELP), (NUM)) +#endif /* _COMPAT_NETBSD_DVCFG_H_ */ diff --git a/sys/compat/svr4/Makefile b/sys/compat/svr4/Makefile new file mode 100644 index 0000000..a90cd55 --- /dev/null +++ b/sys/compat/svr4/Makefile @@ -0,0 +1,17 @@ +# Makefile for syscall tables +# +# $FreeBSD$ + +all: + @echo "make sysent only" + +sysent: svr4_sysent.c svr4_syscall.h svr4_proto.h + +svr4_syscallnames.c svr4_sysent.c svr4_syscall.h svr4_proto.h: \ + ../../kern/makesyscalls.sh syscalls.master syscalls.conf + -mv -f svr4_syscallnames.c svr4_syscallnames.c.bak + -mv -f svr4_sysent.c svr4_sysent.c.bak + -mv -f svr4_syscall.h svr4_syscall.h.bak + -mv -f svr4_proto.h svr4_proto.h.bak + sh ../../kern/makesyscalls.sh syscalls.master syscalls.conf + diff --git a/sys/compat/svr4/imgact_svr4.c b/sys/compat/svr4/imgact_svr4.c new file mode 100644 index 0000000..69e8890 --- /dev/null +++ b/sys/compat/svr4/imgact_svr4.c @@ -0,0 +1,238 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994-1996 Søren Schmidt + * All rights reserved. + * + * Based heavily on /sys/kern/imgact_aout.c which is: + * Copyright (c) 1993, David Greenman + * + * 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 <sys/param.h> +#include <sys/systm.h> +#include <sys/exec.h> +#include <sys/imgact.h> +#include <sys/imgact_aout.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/mman.h> +#include <sys/mutex.h> +#include <sys/proc.h> +#include <sys/racct.h> +#include <sys/resourcevar.h> +#include <sys/vnode.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_extern.h> + +#include <compat/svr4/svr4.h> + +static int exec_svr4_imgact(struct image_params *iparams); + +static int +exec_svr4_imgact(imgp) + struct image_params *imgp; +{ + const struct exec *a_out = (const struct exec *) imgp->image_header; + struct vmspace *vmspace; + vm_offset_t vmaddr; + unsigned long virtual_offset, file_offset; + unsigned long bss_size; + ssize_t aresid; + int error; + + if (((a_out->a_magic >> 16) & 0xff) != 0x64) + return -1; + + /* + * Set file/virtual offset based on a.out variant. + */ + switch ((int)(a_out->a_magic & 0xffff)) { + case 0413: + virtual_offset = 0; + file_offset = 1024; + break; + case 0314: + virtual_offset = 4096; + file_offset = 0; + break; + default: + return (-1); + } + bss_size = round_page(a_out->a_bss); +#ifdef DEBUG + printf("imgact: text: %08lx, data: %08lx, bss: %08lx\n", (u_long)a_out->a_text, (u_long)a_out->a_data, bss_size); +#endif + + /* + * Check various fields in header for validity/bounds. + */ + if (a_out->a_entry < virtual_offset || + a_out->a_entry >= virtual_offset + a_out->a_text || + a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) + return (-1); + + /* text + data can't exceed file size */ + if (a_out->a_data + a_out->a_text > imgp->attr->va_size) + return (EFAULT); + /* + * text/data/bss must not exceed limits + */ + PROC_LOCK(imgp->proc); + if (a_out->a_text > maxtsiz || + a_out->a_data + bss_size > lim_cur(imgp->proc, RLIMIT_DATA) || + racct_set(imgp->proc, RACCT_DATA, a_out->a_data + bss_size) != 0) { + PROC_UNLOCK(imgp->proc); + return (ENOMEM); + } + PROC_UNLOCK(imgp->proc); + + VOP_UNLOCK(imgp->vp, 0); + + /* + * Destroy old process VM and create a new one (with a new stack) + */ + error = exec_new_vmspace(imgp, &svr4_sysvec); + if (error) + goto fail; + vmspace = imgp->proc->p_vmspace; + + /* + * 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) { +#ifdef DEBUG + printf("imgact: Non page aligned binary %lu\n", file_offset); +#endif + /* + * Map text+data+bss read/write/execute + */ + vmaddr = virtual_offset; + error = vm_map_find(&vmspace->vm_map, NULL, 0, &vmaddr, + a_out->a_text + a_out->a_data + bss_size, FALSE, + VM_PROT_ALL, VM_PROT_ALL, 0); + if (error) + goto fail; + + error = vn_rdwr(UIO_READ, imgp->vp, (void *)vmaddr, file_offset, + a_out->a_text + a_out->a_data, UIO_USERSPACE, 0, + curthread->td_ucred, NOCRED, &aresid, curthread); + if (error != 0) + goto fail; + if (aresid != 0) { + error = ENOEXEC; + goto fail; + } + + /* + * remove write enable on the 'text' part + */ + error = vm_map_protect(&vmspace->vm_map, + vmaddr, + vmaddr + a_out->a_text, + VM_PROT_EXECUTE|VM_PROT_READ, + TRUE); + if (error) + goto fail; + } + else { +#ifdef DEBUG + printf("imgact: Page aligned binary %lu\n", file_offset); +#endif + /* + * Map text+data read/execute + */ + vmaddr = virtual_offset; + error = vm_mmap(&vmspace->vm_map, &vmaddr, + a_out->a_text + a_out->a_data, + VM_PROT_READ | VM_PROT_EXECUTE, + VM_PROT_ALL, + MAP_PRIVATE | MAP_FIXED, + OBJT_VNODE, imgp->vp, file_offset); + if (error) + goto fail; + +#ifdef DEBUG + printf("imgact: startaddr=%08lx, length=%08lx\n", (u_long)vmaddr, + (u_long)a_out->a_text + a_out->a_data); +#endif + /* + * allow read/write of data + */ + error = vm_map_protect(&vmspace->vm_map, + vmaddr + a_out->a_text, + vmaddr + a_out->a_text + a_out->a_data, + VM_PROT_ALL, + FALSE); + if (error) + goto fail; + + /* + * Allocate anon demand-zeroed area for uninitialized data + */ + if (bss_size != 0) { + vmaddr = virtual_offset + a_out->a_text + a_out->a_data; + error = vm_map_find(&vmspace->vm_map, NULL, 0, &vmaddr, + bss_size, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0); + if (error) + goto fail; +#ifdef DEBUG + printf("imgact: bssaddr=%08lx, length=%08lx\n", + (u_long)vmaddr, bss_size); +#endif + + } + } + /* Fill in process VM information */ + vmspace->vm_tsize = round_page(a_out->a_text) >> PAGE_SHIFT; + vmspace->vm_dsize = round_page(a_out->a_data + bss_size) >> PAGE_SHIFT; + vmspace->vm_taddr = (caddr_t)virtual_offset; + vmspace->vm_daddr = (caddr_t)virtual_offset + a_out->a_text; + + /* Fill in image_params */ + imgp->interpreted = 0; + imgp->entry_addr = a_out->a_entry; + + imgp->proc->p_sysent = &svr4_sysvec; +fail: + vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); + return (error); +} + +/* + * Tell kern_execve.c about it, with a little help from the linker. + */ +struct execsw svr4_execsw = { exec_svr4_imgact, "svr4 ELF" }; +EXEC_SET(execsw_set, svr4_execsw); + diff --git a/sys/compat/svr4/svr4.h b/sys/compat/svr4/svr4.h new file mode 100644 index 0000000..84ee720 --- /dev/null +++ b/sys/compat/svr4/svr4.h @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 1998 Mark Newton + * 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. + * + * $FreeBSD$ + */ + +#include "opt_svr4.h" + +#if !defined(_SVR4_H) +#define _SVR4_H + +extern struct sysentvec svr4_sysvec; + +#define COMPAT_SVR4_SOLARIS2 + +#endif diff --git a/sys/compat/svr4/svr4_acl.h b/sys/compat/svr4/svr4_acl.h new file mode 100644 index 0000000..ef2da1a --- /dev/null +++ b/sys/compat/svr4/svr4_acl.h @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1996 Christos Zoulas. + * 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 Christos Zoulas. + * 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 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 _SVR4_ACL_H_ +#define _SVR4_ACL_H_ + +typedef struct svr4_aclent { + int a_type; + svr4_uid_t a_id; + svr4_o_mode_t a_perm; +} svr4_aclent_t; + +#define SVR4_SYS_GETACL 1 +#define SVR4_SYS_SETACL 2 +#define SVR4_SYS_GETACLCNT 3 + +#endif /* !_SVR4_ACL_H_ */ diff --git a/sys/compat/svr4/svr4_dirent.h b/sys/compat/svr4/svr4_dirent.h new file mode 100644 index 0000000..9ce7bf8 --- /dev/null +++ b/sys/compat/svr4/svr4_dirent.h @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_DIRENT_H_ +#define _SVR4_DIRENT_H_ + +#define SVR4_MAXNAMLEN 512 + +struct svr4_dirent { + svr4_ino_t d_ino; + svr4_off_t d_off; + u_short d_reclen; + char d_name[SVR4_MAXNAMLEN + 1]; +}; + +struct svr4_dirent64 { + svr4_ino64_t d_ino; + svr4_off64_t d_off; + u_short d_reclen; + char d_name[SVR4_MAXNAMLEN + 1]; +}; + +#define SVR4_NAMEOFF(dp) ((char *)&(dp)->d_name - (char *)dp) +#define SVR4_RECLEN(de,namlen) ALIGN((SVR4_NAMEOFF(de) + (namlen) + 1)) + +#endif /* !_SVR4_DIRENT_H_ */ diff --git a/sys/compat/svr4/svr4_errno.h b/sys/compat/svr4/svr4_errno.h new file mode 100644 index 0000000..b5fa274 --- /dev/null +++ b/sys/compat/svr4/svr4_errno.h @@ -0,0 +1,172 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_ERRNO_H_ +#define _SVR4_ERRNO_H_ + +#define SVR4_EPERM 1 +#define SVR4_ENOENT 2 +#define SVR4_ESRCH 3 +#define SVR4_EINTR 4 +#define SVR4_EIO 5 +#define SVR4_ENXIO 6 +#define SVR4_E2BIG 7 +#define SVR4_ENOEXEC 8 +#define SVR4_EBADF 9 +#define SVR4_ECHILD 10 +#define SVR4_EAGAIN 11 +#define SVR4_ENOMEM 12 +#define SVR4_EACCES 13 +#define SVR4_EFAULT 14 +#define SVR4_ENOTBLK 15 +#define SVR4_EBUSY 16 +#define SVR4_EEXIST 17 +#define SVR4_EXDEV 18 +#define SVR4_ENODEV 19 +#define SVR4_ENOTDIR 20 +#define SVR4_EISDIR 21 +#define SVR4_EINVAL 22 +#define SVR4_ENFILE 23 +#define SVR4_EMFILE 24 +#define SVR4_ENOTTY 25 +#define SVR4_ETXTBSY 26 +#define SVR4_EFBIG 27 +#define SVR4_ENOSPC 28 +#define SVR4_ESPIPE 29 +#define SVR4_EROFS 30 +#define SVR4_EMLINK 31 +#define SVR4_EPIPE 32 +#define SVR4_EDOM 33 +#define SVR4_ERANGE 34 +#define SVR4_ENOMSG 35 +#define SVR4_EIDRM 36 +#define SVR4_ECHRNG 37 +#define SVR4_EL2NSYNC 38 +#define SVR4_EL3HLT 39 +#define SVR4_EL3RST 40 +#define SVR4_ELNRNG 41 +#define SVR4_EUNATCH 42 +#define SVR4_ENOCSI 43 +#define SVR4_EL2HLT 44 +#define SVR4_EDEADLK 45 +#define SVR4_ENOLCK 46 +#define SVR4_EBADE 50 +#define SVR4_EBADR 51 +#define SVR4_EXFULL 52 +#define SVR4_ENOANO 53 +#define SVR4_EBADRQC 54 +#define SVR4_EBADSLT 55 +#define SVR4_EDEADLOCK 56 +#define SVR4_EBFONT 57 +#define SVR4_ENOSTR 60 +#define SVR4_ENODATA 61 +#define SVR4_ETIME 62 +#define SVR4_ENOSR 63 +#define SVR4_ENONET 64 +#define SVR4_ENOPKG 65 +#define SVR4_EREMOTE 66 +#define SVR4_ENOLINK 67 +#define SVR4_EADV 68 +#define SVR4_ESRMNT 69 +#define SVR4_ECOMM 70 +#define SVR4_EPROTO 71 +#define SVR4_EMULTIHOP 74 +#define SVR4_EBADMSG 77 +#define SVR4_ENAMETOOLONG 78 +#define SVR4_EOVERFLOW 79 +#define SVR4_ENOTUNIQ 80 +#define SVR4_EBADFD 81 +#define SVR4_EREMCHG 82 +#define SVR4_ELIBACC 83 +#define SVR4_ELIBBAD 84 +#define SVR4_ELIBSCN 85 +#define SVR4_ELIBMAX 86 +#define SVR4_ELIBEXEC 87 +#define SVR4_EILSEQ 88 +#define SVR4_ENOSYS 89 +#define SVR4_ELOOP 90 +#define SVR4_ERESTART 91 +#define SVR4_ESTRPIPE 92 +#define SVR4_ENOTEMPTY 93 +#define SVR4_EUSERS 94 +#define SVR4_ENOTSOCK 95 +#define SVR4_EDESTADDRREQ 96 +#define SVR4_EMSGSIZE 97 +#define SVR4_EPROTOTYPE 98 +#define SVR4_ENOPROTOOPT 99 +#define SVR4_EPROTONOSUPPORT 120 +#define SVR4_ESOCKTNOSUPPORT 121 +#define SVR4_EOPNOTSUPP 122 +#define SVR4_EPFNOSUPPORT 123 +#define SVR4_EAFNOSUPPORT 124 +#define SVR4_EADDRINUSE 125 +#define SVR4_EADDRNOTAVAIL 126 +#define SVR4_ENETDOWN 127 +#define SVR4_ENETUNREACH 128 +#define SVR4_ENETRESET 129 +#define SVR4_ECONNABORTED 130 +#define SVR4_ECONNRESET 131 +#define SVR4_ENOBUFS 132 +#define SVR4_EISCONN 133 +#define SVR4_ENOTCONN 134 +#define SVR4_EUCLEAN 135 +#define SVR4_ENOTNAM 137 +#define SVR4_ENAVAIL 138 +#define SVR4_EISNAM 139 +#define SVR4_EREMOTEIO 140 +#define SVR4_EINIT 141 +#define SVR4_EREMDEV 142 +#define SVR4_ESHUTDOWN 143 +#define SVR4_ETOOMANYREFS 144 +#define SVR4_ETIMEDOUT 145 +#define SVR4_ECONNREFUSED 146 +#define SVR4_EHOSTDOWN 147 +#define SVR4_EHOSTUNREACH 148 +#define SVR4_EWOULDBLOCK SVR4_EAGAIN +#define SVR4_EALREADY 149 +#define SVR4_EINPROGRESS 150 +#define SVR4_ESTALE 151 +#define SVR4_EIORESID 500 + +/* + * These ones are not translated... + */ +#define SVR4_EPROCLIM SVR4_ENOSYS +#define SVR4_EDQUOT SVR4_ENOSYS +#define SVR4_EBADRPC SVR4_ENOSYS +#define SVR4_ERPCMISMATCH SVR4_ENOSYS +#define SVR4_EPROGUNAVAIL SVR4_ENOSYS +#define SVR4_EPROGMISMATCH SVR4_ENOSYS +#define SVR4_EPROCUNAVAIL SVR4_ENOSYS +#define SVR4_EFTYPE SVR4_ENOSYS +#define SVR4_EAUTH SVR4_ENOSYS +#define SVR4_ENEEDAUTH SVR4_ENOSYS + +#endif /* !_SVR4_ERRNO_H_ */ diff --git a/sys/compat/svr4/svr4_exec.h b/sys/compat/svr4/svr4_exec.h new file mode 100644 index 0000000..adab956 --- /dev/null +++ b/sys/compat/svr4/svr4_exec.h @@ -0,0 +1,70 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_EXEC_H_ +#define _SVR4_EXEC_H_ + +#ifdef SVR4_COMPAT_SOLARIS2 +# define SVR4_AUX_ARGSIZ (sizeof(AuxInfo) * 12 / sizeof(char *)) +#else +# define SVR4_AUX_ARGSIZ (sizeof(AuxInfo) * 8 / sizeof(char *)) +#endif + +#if 0 +/* Don't think we need all this NetBSD stuff */ +/* + * The following is horrible; there must be a better way. I need to + * play with brk(2) a bit more. + */ +#ifdef __i386__ +/* + * I cannot load the interpreter after the data segment because brk(2) + * breaks. I have to load it somewhere before. Programs start at + * 0x08000000 so I load the interpreter far before. + */ +#define SVR4_INTERP_ADDR 0x01000000 +#endif + +#ifdef sparc +/* + * Here programs load at 0x00010000, so I load the interpreter far after + * the end of the data segment. + */ +#define SVR4_INTERP_ADDR 0x10000000 +#endif + +#ifndef SVR4_INTERP_ADDR +# define SVR4_INTERP_ADDR 0 +#endif +#endif + +/*void svr4_setregs(struct thread *, struct exec_package *, u_long);*/ + +#endif /* !_SVR4_EXEC_H_ */ diff --git a/sys/compat/svr4/svr4_fcntl.c b/sys/compat/svr4/svr4_fcntl.c new file mode 100644 index 0000000..86fab78 --- /dev/null +++ b/sys/compat/svr4/svr4_fcntl.c @@ -0,0 +1,724 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994, 1997 Christos Zoulas. + * 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 Christos Zoulas. + * 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 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/capability.h> +#include <sys/systm.h> +#include <sys/file.h> +#include <sys/filedesc.h> +/*#include <sys/ioctl.h>*/ +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/mount.h> +#include <sys/mutex.h> +#include <sys/namei.h> +#include <sys/priv.h> +#include <sys/proc.h> +#include <sys/stat.h> +#include <sys/syscallsubr.h> +#include <sys/unistd.h> +#include <sys/vnode.h> + +#include <sys/sysproto.h> + +#include <compat/svr4/svr4.h> +#include <compat/svr4/svr4_types.h> +#include <compat/svr4/svr4_signal.h> +#include <compat/svr4/svr4_proto.h> +#include <compat/svr4/svr4_util.h> +#include <compat/svr4/svr4_fcntl.h> + +#include <security/mac/mac_framework.h> + +static int svr4_to_bsd_flags(int); +static u_long svr4_to_bsd_cmd(u_long); +static int fd_revoke(struct thread *, int); +static int fd_truncate(struct thread *, int, struct flock *); +static int bsd_to_svr4_flags(int); +static void bsd_to_svr4_flock(struct flock *, struct svr4_flock *); +static void svr4_to_bsd_flock(struct svr4_flock *, struct flock *); +static void bsd_to_svr4_flock64(struct flock *, struct svr4_flock64 *); +static void svr4_to_bsd_flock64(struct svr4_flock64 *, struct flock *); + +static u_long +svr4_to_bsd_cmd(cmd) + u_long cmd; +{ + switch (cmd) { + case SVR4_F_DUPFD: + return F_DUPFD; + case SVR4_F_DUP2FD: + return F_DUP2FD; + case SVR4_F_GETFD: + return F_GETFD; + case SVR4_F_SETFD: + return F_SETFD; + case SVR4_F_GETFL: + return F_GETFL; + case SVR4_F_SETFL: + return F_SETFL; + case SVR4_F_GETLK: + return F_GETLK; + case SVR4_F_SETLK: + return F_SETLK; + case SVR4_F_SETLKW: + return F_SETLKW; + default: + return -1; + } +} + +static int +svr4_to_bsd_flags(l) + int l; +{ + int r = 0; + r |= (l & SVR4_O_RDONLY) ? O_RDONLY : 0; + r |= (l & SVR4_O_WRONLY) ? O_WRONLY : 0; + r |= (l & SVR4_O_RDWR) ? O_RDWR : 0; + r |= (l & SVR4_O_NDELAY) ? O_NONBLOCK : 0; + r |= (l & SVR4_O_APPEND) ? O_APPEND : 0; + r |= (l & SVR4_O_SYNC) ? O_FSYNC : 0; + r |= (l & SVR4_O_NONBLOCK) ? O_NONBLOCK : 0; + r |= (l & SVR4_O_PRIV) ? O_EXLOCK : 0; + r |= (l & SVR4_O_CREAT) ? O_CREAT : 0; + r |= (l & SVR4_O_TRUNC) ? O_TRUNC : 0; + r |= (l & SVR4_O_EXCL) ? O_EXCL : 0; + r |= (l & SVR4_O_NOCTTY) ? O_NOCTTY : 0; + return r; +} + +static int +bsd_to_svr4_flags(l) + int l; +{ + int r = 0; + r |= (l & O_RDONLY) ? SVR4_O_RDONLY : 0; + r |= (l & O_WRONLY) ? SVR4_O_WRONLY : 0; + r |= (l & O_RDWR) ? SVR4_O_RDWR : 0; + r |= (l & O_NDELAY) ? SVR4_O_NONBLOCK : 0; + r |= (l & O_APPEND) ? SVR4_O_APPEND : 0; + r |= (l & O_FSYNC) ? SVR4_O_SYNC : 0; + r |= (l & O_NONBLOCK) ? SVR4_O_NONBLOCK : 0; + r |= (l & O_EXLOCK) ? SVR4_O_PRIV : 0; + r |= (l & O_CREAT) ? SVR4_O_CREAT : 0; + r |= (l & O_TRUNC) ? SVR4_O_TRUNC : 0; + r |= (l & O_EXCL) ? SVR4_O_EXCL : 0; + r |= (l & O_NOCTTY) ? SVR4_O_NOCTTY : 0; + return r; +} + + +static void +bsd_to_svr4_flock(iflp, oflp) + struct flock *iflp; + struct svr4_flock *oflp; +{ + switch (iflp->l_type) { + case F_RDLCK: + oflp->l_type = SVR4_F_RDLCK; + break; + case F_WRLCK: + oflp->l_type = SVR4_F_WRLCK; + break; + case F_UNLCK: + oflp->l_type = SVR4_F_UNLCK; + break; + default: + oflp->l_type = -1; + break; + } + + oflp->l_whence = (short) iflp->l_whence; + oflp->l_start = (svr4_off_t) iflp->l_start; + oflp->l_len = (svr4_off_t) iflp->l_len; + oflp->l_sysid = 0; + oflp->l_pid = (svr4_pid_t) iflp->l_pid; +} + + +static void +svr4_to_bsd_flock(iflp, oflp) + struct svr4_flock *iflp; + struct flock *oflp; +{ + switch (iflp->l_type) { + case SVR4_F_RDLCK: + oflp->l_type = F_RDLCK; + break; + case SVR4_F_WRLCK: + oflp->l_type = F_WRLCK; + break; + case SVR4_F_UNLCK: + oflp->l_type = F_UNLCK; + break; + default: + oflp->l_type = -1; + break; + } + + oflp->l_whence = iflp->l_whence; + oflp->l_start = (off_t) iflp->l_start; + oflp->l_len = (off_t) iflp->l_len; + oflp->l_pid = (pid_t) iflp->l_pid; + oflp->l_sysid = iflp->l_sysid; +} + +static void +bsd_to_svr4_flock64(iflp, oflp) + struct flock *iflp; + struct svr4_flock64 *oflp; +{ + switch (iflp->l_type) { + case F_RDLCK: + oflp->l_type = SVR4_F_RDLCK; + break; + case F_WRLCK: + oflp->l_type = SVR4_F_WRLCK; + break; + case F_UNLCK: + oflp->l_type = SVR4_F_UNLCK; + break; + default: + oflp->l_type = -1; + break; + } + + oflp->l_whence = (short) iflp->l_whence; + oflp->l_start = (svr4_off64_t) iflp->l_start; + oflp->l_len = (svr4_off64_t) iflp->l_len; + oflp->l_sysid = iflp->l_sysid; + oflp->l_pid = (svr4_pid_t) iflp->l_pid; +} + + +static void +svr4_to_bsd_flock64(iflp, oflp) + struct svr4_flock64 *iflp; + struct flock *oflp; +{ + switch (iflp->l_type) { + case SVR4_F_RDLCK: + oflp->l_type = F_RDLCK; + break; + case SVR4_F_WRLCK: + oflp->l_type = F_WRLCK; + break; + case SVR4_F_UNLCK: + oflp->l_type = F_UNLCK; + break; + default: + oflp->l_type = -1; + break; + } + + oflp->l_whence = iflp->l_whence; + oflp->l_start = (off_t) iflp->l_start; + oflp->l_len = (off_t) iflp->l_len; + oflp->l_pid = (pid_t) iflp->l_pid; + +} + + +static int +fd_revoke(td, fd) + struct thread *td; + int fd; +{ + struct vnode *vp; + struct mount *mp; + struct vattr vattr; + int error, *retval; + + retval = td->td_retval; + /* + * If we ever want to support Capsicum on SVR4 processes (unlikely) + * or FreeBSD grows a native frevoke() (more likely), we will need a + * CAP_FREVOKE here. + * + * In the meantime, use CAP_ALL: if a SVR4 process wants to + * do an frevoke(), it needs to do it on either a regular file + * descriptor or a fully-privileged capability (which is effectively + * the same as a non-capability-restricted file descriptor). + */ + if ((error = fgetvp(td, fd, CAP_ALL, &vp)) != 0) + return (error); + + if (vp->v_type != VCHR && vp->v_type != VBLK) { + error = EINVAL; + goto out; + } + +#ifdef MAC + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + error = mac_vnode_check_revoke(td->td_ucred, vp); + VOP_UNLOCK(vp, 0); + if (error) + goto out; +#endif + + if ((error = VOP_GETATTR(vp, &vattr, td->td_ucred)) != 0) + goto out; + + if (td->td_ucred->cr_uid != vattr.va_uid && + (error = priv_check(td, PRIV_VFS_ADMIN)) != 0) + goto out; + + if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) + goto out; + if (vcount(vp) > 1) + VOP_REVOKE(vp, REVOKEALL); + vn_finished_write(mp); +out: + vrele(vp); + return error; +} + + +static int +fd_truncate(td, fd, flp) + struct thread *td; + int fd; + struct flock *flp; +{ + off_t start, length; + struct file *fp; + struct vnode *vp; + struct vattr vattr; + int error, *retval; + struct ftruncate_args ft; + + retval = td->td_retval; + + /* + * We only support truncating the file. + */ + if ((error = fget(td, fd, CAP_FTRUNCATE, &fp)) != 0) + return (error); + + vp = fp->f_vnode; + + if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { + fdrop(fp, td); + return ESPIPE; + } + + if ((error = VOP_GETATTR(vp, &vattr, td->td_ucred)) != 0) { + fdrop(fp, td); + return error; + } + + length = vattr.va_size; + + switch (flp->l_whence) { + case SEEK_CUR: + start = fp->f_offset + flp->l_start; + break; + + case SEEK_END: + start = flp->l_start + length; + break; + + case SEEK_SET: + start = flp->l_start; + break; + + default: + fdrop(fp, td); + return EINVAL; + } + + if (start + flp->l_len < length) { + /* We don't support free'ing in the middle of the file */ + fdrop(fp, td); + return EINVAL; + } + + ft.fd = fd; + ft.length = start; + + error = sys_ftruncate(td, &ft); + + fdrop(fp, td); + return (error); +} + +int +svr4_sys_open(td, uap) + struct thread *td; + struct svr4_sys_open_args *uap; +{ + struct proc *p = td->td_proc; + char *newpath; + int bsd_flags, error, retval; + + CHECKALTEXIST(td, uap->path, &newpath); + + bsd_flags = svr4_to_bsd_flags(uap->flags); + error = kern_open(td, newpath, UIO_SYSSPACE, bsd_flags, uap->mode); + free(newpath, M_TEMP); + + if (error) { + /* uprintf("svr4_open(%s, 0x%0x, 0%o): %d\n", uap->path, + uap->flags, uap->mode, error);*/ + return error; + } + + retval = td->td_retval[0]; + + PROC_LOCK(p); + if (!(bsd_flags & O_NOCTTY) && SESS_LEADER(p) && + !(p->p_flag & P_CONTROLT)) { +#if defined(NOTYET) + struct file *fp; + + error = fget(td, retval, CAP_IOCTL, &fp); + PROC_UNLOCK(p); + /* + * we may have lost a race the above open() and + * another thread issuing a close() + */ + if (error) + return (EBADF); /* XXX: correct errno? */ + /* ignore any error, just give it a try */ + if (fp->f_type == DTYPE_VNODE) + fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, td->td_ucred, + td); + fdrop(fp, td); + } else { + PROC_UNLOCK(p); + } +#else + } + PROC_UNLOCK(p); +#endif + return error; +} + +int +svr4_sys_open64(td, uap) + struct thread *td; + struct svr4_sys_open64_args *uap; +{ + return svr4_sys_open(td, (struct svr4_sys_open_args *)uap); +} + +int +svr4_sys_creat(td, uap) + struct thread *td; + struct svr4_sys_creat_args *uap; +{ + char *newpath; + int error; + + CHECKALTEXIST(td, uap->path, &newpath); + + error = kern_open(td, newpath, UIO_SYSSPACE, O_WRONLY | O_CREAT | + O_TRUNC, uap->mode); + free(newpath, M_TEMP); + return (error); +} + +int +svr4_sys_creat64(td, uap) + struct thread *td; + struct svr4_sys_creat64_args *uap; +{ + return svr4_sys_creat(td, (struct svr4_sys_creat_args *)uap); +} + +int +svr4_sys_llseek(td, uap) + struct thread *td; + struct svr4_sys_llseek_args *uap; +{ + struct lseek_args ap; + + ap.fd = uap->fd; + +#if BYTE_ORDER == BIG_ENDIAN + ap.offset = (((u_int64_t) uap->offset1) << 32) | + uap->offset2; +#else + ap.offset = (((u_int64_t) uap->offset2) << 32) | + uap->offset1; +#endif + ap.whence = uap->whence; + + return sys_lseek(td, &ap); +} + +int +svr4_sys_access(td, uap) + struct thread *td; + struct svr4_sys_access_args *uap; +{ + char *newpath; + int error; + + CHECKALTEXIST(td, uap->path, &newpath); + error = kern_access(td, newpath, UIO_SYSSPACE, uap->amode); + free(newpath, M_TEMP); + return (error); +} + +#if defined(NOTYET) +int +svr4_sys_pread(td, uap) + struct thread *td; + struct svr4_sys_pread_args *uap; +{ + struct pread_args pra; + + /* + * Just translate the args structure and call the NetBSD + * pread(2) system call (offset type is 64-bit in NetBSD). + */ + pra.fd = uap->fd; + pra.buf = uap->buf; + pra.nbyte = uap->nbyte; + pra.offset = uap->off; + + return pread(td, &pra); +} +#endif + +#if defined(NOTYET) +int +svr4_sys_pread64(td, v, retval) + struct thread *td; + void *v; + register_t *retval; +{ + + struct svr4_sys_pread64_args *uap = v; + struct sys_pread_args pra; + + /* + * Just translate the args structure and call the NetBSD + * pread(2) system call (offset type is 64-bit in NetBSD). + */ + pra.fd = uap->fd; + pra.buf = uap->buf; + pra.nbyte = uap->nbyte; + pra.offset = uap->off; + + return (sys_pread(td, &pra, retval)); +} +#endif /* NOTYET */ + +#if defined(NOTYET) +int +svr4_sys_pwrite(td, uap) + struct thread *td; + struct svr4_sys_pwrite_args *uap; +{ + struct pwrite_args pwa; + + /* + * Just translate the args structure and call the NetBSD + * pwrite(2) system call (offset type is 64-bit in NetBSD). + */ + pwa.fd = uap->fd; + pwa.buf = uap->buf; + pwa.nbyte = uap->nbyte; + pwa.offset = uap->off; + + return pwrite(td, &pwa); +} +#endif + +#if defined(NOTYET) +int +svr4_sys_pwrite64(td, v, retval) + struct thread *td; + void *v; + register_t *retval; +{ + struct svr4_sys_pwrite64_args *uap = v; + struct sys_pwrite_args pwa; + + /* + * Just translate the args structure and call the NetBSD + * pwrite(2) system call (offset type is 64-bit in NetBSD). + */ + pwa.fd = uap->fd; + pwa.buf = uap->buf; + pwa.nbyte = uap->nbyte; + pwa.offset = uap->off; + + return (sys_pwrite(td, &pwa, retval)); +} +#endif /* NOTYET */ + +int +svr4_sys_fcntl(td, uap) + struct thread *td; + struct svr4_sys_fcntl_args *uap; +{ + int cmd, error, *retval; + + retval = td->td_retval; + + cmd = svr4_to_bsd_cmd(uap->cmd); + + switch (cmd) { + case F_DUPFD: + case F_DUP2FD: + case F_GETFD: + case F_SETFD: + return (kern_fcntl(td, uap->fd, cmd, (intptr_t)uap->arg)); + + case F_GETFL: + error = kern_fcntl(td, uap->fd, cmd, (intptr_t)uap->arg); + if (error) + return (error); + *retval = bsd_to_svr4_flags(*retval); + return (error); + + case F_SETFL: + { + /* + * we must save the O_ASYNC flag, as that is + * handled by ioctl(_, I_SETSIG, _) emulation. + */ + int flags; + + DPRINTF(("Setting flags %p\n", uap->arg)); + + error = kern_fcntl(td, uap->fd, F_GETFL, 0); + if (error) + return (error); + flags = *retval; + flags &= O_ASYNC; + flags |= svr4_to_bsd_flags((u_long) uap->arg); + return (kern_fcntl(td, uap->fd, F_SETFL, flags)); + } + + case F_GETLK: + case F_SETLK: + case F_SETLKW: + { + struct svr4_flock ifl; + struct flock fl; + + error = copyin(uap->arg, &ifl, sizeof (ifl)); + if (error) + return (error); + + svr4_to_bsd_flock(&ifl, &fl); + + error = kern_fcntl(td, uap->fd, cmd, (intptr_t)&fl); + if (error || cmd != F_GETLK) + return (error); + + bsd_to_svr4_flock(&fl, &ifl); + + return (copyout(&ifl, uap->arg, sizeof (ifl))); + } + case -1: + switch (uap->cmd) { + case SVR4_F_FREESP: + { + struct svr4_flock ifl; + struct flock fl; + + error = copyin(uap->arg, &ifl, + sizeof ifl); + if (error) + return error; + svr4_to_bsd_flock(&ifl, &fl); + return fd_truncate(td, uap->fd, &fl); + } + + case SVR4_F_GETLK64: + case SVR4_F_SETLK64: + case SVR4_F_SETLKW64: + { + struct svr4_flock64 ifl; + struct flock fl; + + switch (uap->cmd) { + case SVR4_F_GETLK64: + cmd = F_GETLK; + break; + case SVR4_F_SETLK64: + cmd = F_SETLK; + break; + case SVR4_F_SETLKW64: + cmd = F_SETLKW; + break; + } + error = copyin(uap->arg, &ifl, + sizeof (ifl)); + if (error) + return (error); + + svr4_to_bsd_flock64(&ifl, &fl); + + error = kern_fcntl(td, uap->fd, cmd, + (intptr_t)&fl); + if (error || cmd != F_GETLK) + return (error); + + bsd_to_svr4_flock64(&fl, &ifl); + + return (copyout(&ifl, uap->arg, + sizeof (ifl))); + } + + case SVR4_F_FREESP64: + { + struct svr4_flock64 ifl; + struct flock fl; + + error = copyin(uap->arg, &ifl, + sizeof ifl); + if (error) + return error; + svr4_to_bsd_flock64(&ifl, &fl); + return fd_truncate(td, uap->fd, &fl); + } + + case SVR4_F_REVOKE: + return fd_revoke(td, uap->fd); + + default: + return ENOSYS; + } + + default: + return ENOSYS; + } +} diff --git a/sys/compat/svr4/svr4_fcntl.h b/sys/compat/svr4/svr4_fcntl.h new file mode 100644 index 0000000..1a354a7 --- /dev/null +++ b/sys/compat/svr4/svr4_fcntl.h @@ -0,0 +1,134 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_FCNTL_H_ +#define _SVR4_FCNTL_H_ + +#include <compat/svr4/svr4_types.h> +#include <sys/fcntl.h> + +#define SVR4_O_RDONLY 0x0000 +#define SVR4_O_WRONLY 0x0001 +#define SVR4_O_RDWR 0x0002 +#define SVR4_O_ACCMODE 0x0003 +#define SVR4_O_NDELAY 0x0004 +#define SVR4_O_APPEND 0x0008 +#define SVR4_O_SYNC 0x0010 +#define SVR4_O_NONBLOCK 0x0080 +#define SVR4_O_CREAT 0x0100 +#define SVR4_O_TRUNC 0x0200 +#define SVR4_O_EXCL 0x0400 +#define SVR4_O_NOCTTY 0x0800 +#define SVR4_O_PRIV 0x1000 + + +#define SVR4_FD_CLOEXEC 1 + +#define SVR4_F_DUPFD 0 +#define SVR4_F_GETFD 1 +#define SVR4_F_SETFD 2 +#define SVR4_F_GETFL 3 +#define SVR4_F_SETFL 4 +#define SVR4_F_GETLK_SVR3 5 +#define SVR4_F_SETLK 6 +#define SVR4_F_SETLKW 7 +#define SVR4_F_CHKFL 8 +#define SVR4_F_DUP2FD 9 +#define SVR4_F_ALLOCSP 10 +#define SVR4_F_FREESP 11 + +#define SVR4_F_ISSTREAM 13 +#define SVR4_F_GETLK 14 +#define SVR4_F_PRIV 15 +#define SVR4_F_NPRIV 16 +#define SVR4_F_QUOTACTL 17 +#define SVR4_F_BLOCKS 18 +#define SVR4_F_BLKSIZE 19 +#define SVR4_F_RSETLK 20 +#define SVR4_F_RGETLK 21 +#define SVR4_F_RSETLKW 22 +#define SVR4_F_GETOWN 23 +#define SVR4_F_SETOWN 24 +#define SVR4_F_REVOKE 25 +#define SVR4_F_HASREMOTELOCKS 26 +#define SVR4_F_FREESP64 27 + +#define SVR4_F_GETLK64 33 +#define SVR4_F_SETLK64 34 +#define SVR4_F_SETLKW64 35 + +#define SVR4_F_SHARE 40 +#define SVR4_F_UNSHARE 41 + +#define SVR4_F_CHSIZE_XENIX 0x6000 +#define SVR4_F_RDCHK_XENIX 0x6001 +#define SVR4_F_LK_UNLCK_XENIX 0x6300 +#define SVR4_F_LK_LOCK_XENIX 0x7200 +#define SVR4_F_LK_NBLCK_XENIX 0x6200 +#define SVR4_F_LK_RLCK_XENIX 0x7100 +#define SVR4_F_LK_NBRLCK_XENIX 0x6100 + +#define SVR4_LK_CMDTYPE(x) (((x) >> 12) & 0x7) +#define SVR4_LK_LCKTYPE(x) (((x) >> 8) & 0x7) + +#define SVR4_F_RDLCK 1 +#define SVR4_F_WRLCK 2 +#define SVR4_F_UNLCK 3 + +struct svr4_flock_svr3 { + short l_type; + short l_whence; + svr4_off_t l_start; + svr4_off_t l_len; + short l_sysid; + svr4_o_pid_t l_pid; +}; + + +struct svr4_flock { + short l_type; + short l_whence; + svr4_off_t l_start; + svr4_off_t l_len; + long l_sysid; + svr4_pid_t l_pid; + long pad[4]; +}; + +struct svr4_flock64 { + short l_type; + short l_whence; + svr4_off64_t l_start; + svr4_off64_t l_len; + long l_sysid; + svr4_pid_t l_pid; + long pad[4]; +}; +#endif /* !_SVR4_FCNTL_H_ */ diff --git a/sys/compat/svr4/svr4_filio.c b/sys/compat/svr4/svr4_filio.c new file mode 100644 index 0000000..0fbba07 --- /dev/null +++ b/sys/compat/svr4/svr4_filio.c @@ -0,0 +1,251 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/proc.h> +#include <sys/systm.h> +#include <sys/capability.h> +#include <sys/file.h> +#include <sys/filio.h> +#include <sys/lock.h> +#include <sys/signal.h> +#include <sys/filedesc.h> +#include <sys/poll.h> +#include <sys/malloc.h> +#include <sys/mutex.h> + +#include <sys/sysproto.h> + +#include <compat/svr4/svr4.h> +#include <compat/svr4/svr4_types.h> +#include <compat/svr4/svr4_util.h> +#include <compat/svr4/svr4_signal.h> +#include <compat/svr4/svr4_proto.h> +#include <compat/svr4/svr4_ioctl.h> +#include <compat/svr4/svr4_filio.h> + +/*#define GROTTY_READ_HACK*/ + +int +svr4_sys_poll(td, uap) + struct thread *td; + struct svr4_sys_poll_args *uap; +{ + int error; + struct poll_args pa; + struct pollfd *pfd; + int idx = 0, cerr; + u_long siz; + + if (uap->nfds > maxfilesperproc && uap->nfds > FD_SETSIZE) + return (EINVAL); + + pa.fds = uap->fds; + pa.nfds = uap->nfds; + pa.timeout = uap->timeout; + + siz = uap->nfds * sizeof(struct pollfd); + pfd = (struct pollfd *)malloc(siz, M_TEMP, M_WAITOK); + + error = sys_poll(td, (struct poll_args *)uap); + + if ((cerr = copyin(uap->fds, pfd, siz)) != 0) { + error = cerr; + goto done; + } + + for (idx = 0; idx < uap->nfds; idx++) { + /* POLLWRNORM already equals POLLOUT, so we don't worry about that */ + if (pfd[idx].revents & (POLLOUT | POLLWRNORM | POLLWRBAND)) + pfd[idx].revents |= (POLLOUT | POLLWRNORM | POLLWRBAND); + } + if ((cerr = copyout(pfd, uap->fds, siz)) != 0) { + error = cerr; + goto done; /* yeah, I know it's the next line, but this way I won't + forget to update it if I add more code */ + } +done: + free(pfd, M_TEMP); + return error; +} + +#if defined(READ_TEST) +int +svr4_sys_read(td, uap) + struct thread *td; + struct svr4_sys_read_args *uap; +{ + struct read_args ra; + struct file *fp; + struct socket *so = NULL; + int so_state; + sigset_t sigmask; + int rv; + + ra.fd = uap->fd; + ra.buf = uap->buf; + ra.nbyte = uap->nbyte; + + if (fget(td, uap->fd, CAP_READ, &fp) != 0) { + DPRINTF(("Something fishy with the user-supplied file descriptor...\n")); + return EBADF; + } + + if (fp->f_type == DTYPE_SOCKET) { + so = fp->f_data; + DPRINTF(("fd %d is a socket\n", uap->fd)); + if (so->so_state & SS_ASYNC) { + DPRINTF(("fd %d is an ASYNC socket!\n", uap->fd)); + } + DPRINTF(("Here are its flags: 0x%x\n", so->so_state)); +#if defined(GROTTY_READ_HACK) + so_state = so->so_state; + so->so_state &= ~SS_NBIO; +#endif + } + + rv = read(td, &ra); + + DPRINTF(("svr4_read(%d, 0x%0x, %d) = %d\n", + uap->fd, uap->buf, uap->nbyte, rv)); + if (rv == EAGAIN) { +#ifdef DEBUG_SVR4 + struct sigacts *ps; + + PROC_LOCK(td->td_proc); + ps = td->td_proc->p_sigacts; + mtx_lock(&ps->ps_mtx); +#endif + DPRINTF(("sigmask = 0x%x\n", td->td_sigmask)); + DPRINTF(("sigignore = 0x%x\n", ps->ps_sigignore)); + DPRINTF(("sigcaught = 0x%x\n", ps->ps_sigcatch)); + DPRINTF(("siglist = 0x%x\n", td->td_siglist)); +#ifdef DEBUG_SVR4 + mtx_unlock(&ps->ps_mtx); + PROC_UNLOCK(td->td_proc); +#endif + } + +#if defined(GROTTY_READ_HACK) + if (so) { /* We've already checked to see if this is a socket */ + so->so_state = so_state; + } +#endif + fdrop(fp, td); + + return(rv); +} +#endif /* READ_TEST */ + +#if defined(BOGUS) +int +svr4_sys_write(td, uap) + struct thread *td; + struct svr4_sys_write_args *uap; +{ + struct write_args wa; + struct file *fp; + int rv; + + wa.fd = uap->fd; + wa.buf = uap->buf; + wa.nbyte = uap->nbyte; + + rv = write(td, &wa); + + DPRINTF(("svr4_write(%d, 0x%0x, %d) = %d\n", + uap->fd, uap->buf, uap->nbyte, rv)); + + return(rv); +} +#endif /* BOGUS */ + +int +svr4_fil_ioctl(fp, td, retval, fd, cmd, data) + struct file *fp; + struct thread *td; + register_t *retval; + int fd; + u_long cmd; + caddr_t data; +{ + struct filedesc *fdp = td->td_proc->p_fd; + struct filedescent *fde; + int error, num; + + *retval = 0; + + switch (cmd) { + case SVR4_FIOCLEX: + FILEDESC_XLOCK(fdp); + fde = &fdp->fd_ofiles[fd]; + fde->fde_flags |= UF_EXCLOSE; + FILEDESC_XUNLOCK(fdp); + return 0; + + case SVR4_FIONCLEX: + FILEDESC_XLOCK(fdp); + fde = &fdp->fd_ofiles[fd]; + fde->fde_flags &= ~UF_EXCLOSE; + FILEDESC_XUNLOCK(fdp); + return 0; + + case SVR4_FIOGETOWN: + case SVR4_FIOSETOWN: + case SVR4_FIOASYNC: + case SVR4_FIONBIO: + case SVR4_FIONREAD: + if ((error = copyin(data, &num, sizeof(num))) != 0) + return error; + + switch (cmd) { + case SVR4_FIOGETOWN: cmd = FIOGETOWN; break; + case SVR4_FIOSETOWN: cmd = FIOSETOWN; break; + case SVR4_FIOASYNC: cmd = FIOASYNC; break; + case SVR4_FIONBIO: cmd = FIONBIO; break; + case SVR4_FIONREAD: cmd = FIONREAD; break; + } + +#ifdef SVR4_DEBUG + if (cmd == FIOASYNC) DPRINTF(("FIOASYNC\n")); +#endif + error = fo_ioctl(fp, cmd, (caddr_t) &num, td->td_ucred, td); + + if (error) + return error; + + return copyout(&num, data, sizeof(num)); + + default: + DPRINTF(("Unknown svr4 filio %lx\n", cmd)); + return 0; /* ENOSYS really */ + } +} diff --git a/sys/compat/svr4/svr4_filio.h b/sys/compat/svr4/svr4_filio.h new file mode 100644 index 0000000..baf81c7 --- /dev/null +++ b/sys/compat/svr4/svr4_filio.h @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_FILIO_H_ +#define _SVR4_FILIO_H_ + +#define SVR4_FIOC ('f' << 8) + +#define SVR4_FIOCLEX SVR4_IO('f', 1) +#define SVR4_FIONCLEX SVR4_IO('f', 2) + +#define SVR4_FIOGETOWN SVR4_IOR('f', 123, int) +#define SVR4_FIOSETOWN SVR4_IOW('f', 124, int) +#define SVR4_FIOASYNC SVR4_IOW('f', 125, int) +#define SVR4_FIONBIO SVR4_IOW('f', 126, int) +#define SVR4_FIONREAD SVR4_IOR('f', 127, int) + +#endif /* !_SVR4_FILIO_H_ */ diff --git a/sys/compat/svr4/svr4_fuser.h b/sys/compat/svr4/svr4_fuser.h new file mode 100644 index 0000000..df2db98 --- /dev/null +++ b/sys/compat/svr4/svr4_fuser.h @@ -0,0 +1,97 @@ +/* + * $FreeBSD$ + * Derived from: + * $NetBSD: svr4_fuser.h,v 1.4 1998/09/04 19:54:38 christos Exp $ */ + +/*- + * Original Copyright: + * + * Copyright (c) 1994 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 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. + */ + +/*- + * Portions of this code have been derived from code contributed to the + * FreeBSD Project by Mark Newton. + * + * Copyright (c) 1999 Mark Newton + * 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. + */ + +#ifndef _SVR4_FUSER_H_ +#define _SVR4_FUSER_H_ + +#include <compat/svr4/svr4_types.h> + +struct svr4_f_user { + svr4_pid_t fu_pid; + int fu_flags; + uid_t fu_uid; +}; + + +#define SVR4_F_FILE_ONLY 1 +#define SVR4_F_CONTAINED 2 + +#define SVR4_F_CDIR 0x01 +#define SVR4_F_RDIR 0x02 +#define SVR4_F_TEXT 0x04 +#define SVR4_F_MAP 0x08 +#define SVR4_F_OPEN 0x10 +#define SVR4_F_TRACE 0x20 +#define SVR4_F_TTY 0x40 + +#endif /* !_SVR4_FUSER_H_ */ diff --git a/sys/compat/svr4/svr4_hrt.h b/sys/compat/svr4/svr4_hrt.h new file mode 100644 index 0000000..5a3bb67 --- /dev/null +++ b/sys/compat/svr4/svr4_hrt.h @@ -0,0 +1,87 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_HRT_H_ +#define _SVR4_HRT_H_ + +#define SVR4_HRT_CNTL 0 +#define SVR4_HRT_CNTL_RES 0 +#define SVR4_HRT_CNTL_TOFD 1 +#define SVR4_HRT_CNTL_START 2 +#define SVR4_HRT_CNTL_GET 3 + +#define SVR4_HRT_ALRM 1 +#define SVR4_HRT_ALRM_DO 4 +#define SVR4_HRT_ALRM_REP 5 +#define SVR4_HRT_ALRM_TOD 6 +#define SVR4_HRT_ALRM_FUTREP 7 +#define SVR4_HRT_ALRM_TODREP 8 +#define SVR4_HRT_ALRM_PEND 9 + +#define SVR4_HRT_SLP 2 +#define SVR4_HRT_SLP_INT 10 +#define SVR4_HRT_SLP_TOD 11 + +#define SVR4_HRT_BSD 12 +#define SVR4_HRT_BSD_PEND 13 +#define SVR4_HRT_BSD_REP1 14 +#define SVR4_HRT_BSD_REP2 15 +#define SVR4_HRT_BSD_CANCEL 16 + +#define SVR4_HRT_CAN 3 + +#define SVR4_HRT_SEC 1 +#define SVR4_HRT_MSEC 1000 +#define SVR4_HRT_USEC 1000000 +#define SVR4_HRT_NSEC 1000000000 + +#define SVR4_HRT_TRUNC 0 +#define SVR4_HRT_RND 1 + +typedef struct { + u_long i_word1; + u_long i_word2; + int i_clock; +} svr4_hrt_interval_t; + +typedef struct { + u_long h_sec; + long h_rem; + u_long h_res; +} svr4_hrt_time_t; + +#define SVR4_HRT_DONE 1 +#define SVR4_HRT_ERROR 2 + +#define SVR4_HRT_CLK_STD 1 +#define SVR4_HRT_CLK_USERVIRT 2 +#define SVR4_HRT_CLK_PROCVIRT 4 + +#endif /* !_SVR4_HRT_H_ */ diff --git a/sys/compat/svr4/svr4_ioctl.c b/sys/compat/svr4/svr4_ioctl.c new file mode 100644 index 0000000..36b0580 --- /dev/null +++ b/sys/compat/svr4/svr4_ioctl.c @@ -0,0 +1,163 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/proc.h> +#include <sys/capability.h> +#include <sys/file.h> +#include <sys/filedesc.h> +#include <sys/fcntl.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/systm.h> + +#include <compat/svr4/svr4.h> +#include <compat/svr4/svr4_types.h> +#include <compat/svr4/svr4_util.h> +#include <compat/svr4/svr4_signal.h> +#include <compat/svr4/svr4_proto.h> +#include <compat/svr4/svr4_stropts.h> +#include <compat/svr4/svr4_ioctl.h> +#include <compat/svr4/svr4_termios.h> +#include <compat/svr4/svr4_filio.h> +#include <compat/svr4/svr4_sockio.h> + +#ifdef DEBUG_SVR4 +static void svr4_decode_cmd(u_long, char *, char *, int *, int *); +/* + * Decode an ioctl command symbolically + */ +static void +svr4_decode_cmd(cmd, dir, c, num, argsiz) + u_long cmd; + char *dir, *c; + int *num, *argsiz; +{ + if (cmd & SVR4_IOC_VOID) + *dir++ = 'V'; + if (cmd & SVR4_IOC_IN) + *dir++ = 'R'; + if (cmd & SVR4_IOC_OUT) + *dir++ = 'W'; + *dir = '\0'; + if (cmd & SVR4_IOC_INOUT) + *argsiz = (cmd >> 16) & 0xff; + else + *argsiz = -1; + + *c = (cmd >> 8) & 0xff; + *num = cmd & 0xff; +} +#endif + +int +svr4_sys_ioctl(td, uap) + struct thread *td; + struct svr4_sys_ioctl_args *uap; +{ + int *retval; + struct file *fp; + u_long cmd; + int (*fun)(struct file *, struct thread *, register_t *, + int, u_long, caddr_t); + int error; +#ifdef DEBUG_SVR4 + char dir[4]; + char c; + int num; + int argsiz; + + svr4_decode_cmd(uap->com, dir, &c, &num, &argsiz); + + DPRINTF(("svr4_ioctl[%lx](%d, _IO%s(%c, %d, %d), %p);\n", uap->com, uap->fd, + dir, c, num, argsiz, uap->data)); +#endif + retval = td->td_retval; + cmd = uap->com; + + if ((error = fget(td, uap->fd, CAP_IOCTL, &fp)) != 0) + return (error); + + if ((fp->f_flag & (FREAD | FWRITE)) == 0) { + fdrop(fp, td); + return EBADF; + } + +#if defined(DEBUG_SVR4) + if (fp->f_type == DTYPE_SOCKET) { + struct socket *so = fp->f_data; + DPRINTF(("<<< IN: so_state = 0x%x\n", so->so_state)); + } +#endif + + switch (cmd & 0xff00) { + case SVR4_TIOC: + DPRINTF(("term\n")); + fun = svr4_term_ioctl; + break; + + case SVR4_STR: + DPRINTF(("stream\n")); + fun = svr4_stream_ioctl; + break; + + case SVR4_FIOC: + DPRINTF(("file\n")); + fun = svr4_fil_ioctl; + break; + + case SVR4_SIOC: + DPRINTF(("socket\n")); + fun = svr4_sock_ioctl; + break; + + case SVR4_XIOC: + /* We do not support those */ + fdrop(fp, td); + return EINVAL; + + default: + fdrop(fp, td); + DPRINTF(("Unimplemented ioctl %lx\n", cmd)); + return 0; /* XXX: really ENOSYS */ + } +#if defined(DEBUG_SVR4) + if (fp->f_type == DTYPE_SOCKET) { + struct socket *so; + + so = fp->f_data; + DPRINTF((">>> OUT: so_state = 0x%x\n", so->so_state)); + } +#endif + error = (*fun)(fp, td, retval, uap->fd, cmd, uap->data); + fdrop(fp, td); + return (error); +} diff --git a/sys/compat/svr4/svr4_ioctl.h b/sys/compat/svr4/svr4_ioctl.h new file mode 100644 index 0000000..98b67a1 --- /dev/null +++ b/sys/compat/svr4/svr4_ioctl.h @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_IOCTL_H_ +#define _SVR4_IOCTL_H_ + +#define SVR4_IOC_VOID 0x20000000 +#define SVR4_IOC_OUT 0x40000000 +#define SVR4_IOC_IN 0x80000000 +#define SVR4_IOC_INOUT (SVR4_IOC_IN|SVR4_IOC_OUT) + +#define SVR4_IOC(inout,group,num,len) \ + (inout | ((len & 0xff) << 16) | ((group) << 8) | (num)) + +#define SVR4_XIOC ('X' << 8) + +#define SVR4_IO(g,n) SVR4_IOC(SVR4_IOC_VOID, (g), (n), 0) +#define SVR4_IOR(g,n,t) SVR4_IOC(SVR4_IOC_OUT, (g), (n), sizeof(t)) +#define SVR4_IOW(g,n,t) SVR4_IOC(SVR4_IOC_IN, (g), (n), sizeof(t)) +#define SVR4_IOWR(g,n,t) SVR4_IOC(SVR4_IOC_INOUT,(g), (n), sizeof(t)) + +int svr4_stream_ti_ioctl(struct file *, struct thread *, register_t *, + int, u_long, caddr_t); +int svr4_stream_ioctl(struct file *, struct thread *, register_t *, + int, u_long, caddr_t); +int svr4_term_ioctl(struct file *, struct thread *, register_t *, + int, u_long, caddr_t); +int svr4_fil_ioctl (struct file *, struct thread *, register_t *, + int, u_long, caddr_t); +int svr4_sock_ioctl (struct file *, struct thread *, register_t *, + int, u_long, caddr_t); + +#endif /* !_SVR4_IOCTL_H_ */ diff --git a/sys/compat/svr4/svr4_ipc.c b/sys/compat/svr4/svr4_ipc.c new file mode 100644 index 0000000..f816cb0 --- /dev/null +++ b/sys/compat/svr4/svr4_ipc.c @@ -0,0 +1,707 @@ +/*- + * Copyright (c) 1995 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 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. + */ +/*- + * Portions of this code have been derived from software contributed + * to the FreeBSD Project by Mark Newton. + * + * Copyright (c) 1999 Mark Newton + * 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. + * + * XXX- This code is presently a no-op on FreeBSD (and isn't compiled due + * to preprocessor conditionals). A nice project for a kernel hacking + * novice might be to MakeItGo, but I have more important fish to fry + * at present. + * + * Derived from: $NetBSD: svr4_ipc.c,v 1.7 1998/10/19 22:43:00 tron Exp $ + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_sysvipc.h" + +#include <sys/param.h> +#include <sys/ipc.h> +#include <sys/msg.h> +#include <sys/proc.h> +#include <sys/sem.h> +#include <sys/shm.h> +#include <sys/syscallsubr.h> +#include <sys/sysproto.h> +#include <sys/systm.h> +#include <sys/time.h> + +#include <compat/svr4/svr4.h> +#include <compat/svr4/svr4_types.h> +#include <compat/svr4/svr4_signal.h> +#include <compat/svr4/svr4_proto.h> +#include <compat/svr4/svr4_util.h> +#include <compat/svr4/svr4_ipc.h> + +#if defined(SYSVMSG) || defined(SYSVSHM) || defined(SYSVSEM) +static void svr4_to_bsd_ipc_perm(const struct svr4_ipc_perm *, + struct ipc_perm *); +static void bsd_to_svr4_ipc_perm(const struct ipc_perm *, + struct svr4_ipc_perm *); +#endif + +#ifdef SYSVSEM +static void bsd_to_svr4_semid_ds(const struct semid_ds *, + struct svr4_semid_ds *); +static void svr4_to_bsd_semid_ds(const struct svr4_semid_ds *, + struct semid_ds *); +static int svr4_semop(struct thread *, void *); +static int svr4_semget(struct thread *, void *); +static int svr4_semctl(struct thread *, void *); +#endif + +#ifdef SYSVMSG +static void bsd_to_svr4_msqid_ds(const struct msqid_ds *, + struct svr4_msqid_ds *); +static void svr4_to_bsd_msqid_ds(const struct svr4_msqid_ds *, + struct msqid_ds *); +static int svr4_msgsnd(struct thread *, void *); +static int svr4_msgrcv(struct thread *, void *); +static int svr4_msgget(struct thread *, void *); +static int svr4_msgctl(struct thread *, void *); +#endif + +#ifdef SYSVSHM +static void bsd_to_svr4_shmid_ds(const struct shmid_ds *, + struct svr4_shmid_ds *); +static void svr4_to_bsd_shmid_ds(const struct svr4_shmid_ds *, + struct shmid_ds *); +static int svr4_shmat(struct thread *, void *); +static int svr4_shmdt(struct thread *, void *); +static int svr4_shmget(struct thread *, void *); +static int svr4_shmctl(struct thread *, void *); +#endif + +#if defined(SYSVMSG) || defined(SYSVSHM) || defined(SYSVSEM) + +static void +svr4_to_bsd_ipc_perm(spp, bpp) + const struct svr4_ipc_perm *spp; + struct ipc_perm *bpp; +{ + bpp->key = spp->key; + bpp->uid = spp->uid; + bpp->gid = spp->gid; + bpp->cuid = spp->cuid; + bpp->cgid = spp->cgid; + bpp->mode = spp->mode; + bpp->seq = spp->seq; +} + +static void +bsd_to_svr4_ipc_perm(bpp, spp) + const struct ipc_perm *bpp; + struct svr4_ipc_perm *spp; +{ + spp->key = bpp->key; + spp->uid = bpp->uid; + spp->gid = bpp->gid; + spp->cuid = bpp->cuid; + spp->cgid = bpp->cgid; + spp->mode = bpp->mode; + spp->seq = bpp->seq; +} +#endif + +#ifdef SYSVSEM +static void +bsd_to_svr4_semid_ds(bds, sds) + const struct semid_ds *bds; + struct svr4_semid_ds *sds; +{ + bzero(sds, sizeof(*sds)); + bsd_to_svr4_ipc_perm(&bds->sem_perm, &sds->sem_perm); + sds->sem_base = (struct svr4_sem *) bds->sem_base; + sds->sem_nsems = bds->sem_nsems; + sds->sem_otime = bds->sem_otime; + sds->sem_ctime = bds->sem_ctime; +} + +static void +svr4_to_bsd_semid_ds(sds, bds) + const struct svr4_semid_ds *sds; + struct semid_ds *bds; +{ + svr4_to_bsd_ipc_perm(&sds->sem_perm, &bds->sem_perm); + bds->sem_base = (struct sem *) bds->sem_base; + bds->sem_nsems = sds->sem_nsems; + bds->sem_otime = sds->sem_otime; + bds->sem_ctime = sds->sem_ctime; +} + +struct svr4_sys_semctl_args { + int what; + int semid; + int semnum; + int cmd; + union semun arg; +}; + +static int +svr4_semctl(td, v) + struct thread *td; + void *v; +{ + struct svr4_sys_semctl_args *uap = v; + struct svr4_semid_ds ss; + struct semid_ds bs; + union semun semun; + register_t rval; + int cmd, error; + + switch (uap->cmd) { + case SVR4_SEM_GETZCNT: + cmd = GETZCNT; + break; + + case SVR4_SEM_GETNCNT: + cmd = GETNCNT; + break; + + case SVR4_SEM_GETPID: + cmd = GETPID; + break; + + case SVR4_SEM_GETVAL: + cmd = GETVAL; + break; + + case SVR4_SEM_SETVAL: + cmd = SETVAL; + break; + + case SVR4_SEM_GETALL: + cmd = GETVAL; + break; + + case SVR4_SEM_SETALL: + cmd = SETVAL; + break; + + case SVR4_IPC_STAT: + cmd = IPC_STAT; + semun.buf = &bs; + error = kern_semctl(td, uap->semid, uap->semnum, cmd, &semun, + &rval); + if (error) + return (error); + bsd_to_svr4_semid_ds(&bs, &ss); + error = copyout(&ss, uap->arg.buf, sizeof(ss)); + if (error == 0) + td->td_retval[0] = rval; + return (error); + + case SVR4_IPC_SET: + cmd = IPC_SET; + error = copyin(uap->arg.buf, (caddr_t) &ss, sizeof ss); + if (error) + return (error); + svr4_to_bsd_semid_ds(&ss, &bs); + semun.buf = &bs; + return (kern_semctl(td, uap->semid, uap->semnum, cmd, &semun, + td->td_retval)); + + case SVR4_IPC_RMID: + cmd = IPC_RMID; + break; + + default: + return EINVAL; + } + + return (kern_semctl(td, uap->semid, uap->semnum, cmd, &uap->arg, + td->td_retval)); +} + +struct svr4_sys_semget_args { + int what; + svr4_key_t key; + int nsems; + int semflg; +}; + +static int +svr4_semget(td, v) + struct thread *td; + void *v; +{ + struct svr4_sys_semget_args *uap = v; + struct semget_args ap; + + ap.key = uap->key; + ap.nsems = uap->nsems; + ap.semflg = uap->semflg; + + return sys_semget(td, &ap); +} + +struct svr4_sys_semop_args { + int what; + int semid; + struct svr4_sembuf * sops; + u_int nsops; +}; + +static int +svr4_semop(td, v) + struct thread *td; + void *v; +{ + struct svr4_sys_semop_args *uap = v; + struct semop_args ap; + + ap.semid = uap->semid; + /* These are the same */ + ap.sops = (struct sembuf *) uap->sops; + ap.nsops = uap->nsops; + + return sys_semop(td, &ap); +} + +int +svr4_sys_semsys(td, uap) + struct thread *td; + struct svr4_sys_semsys_args *uap; +{ + + DPRINTF(("svr4_semsys(%d)\n", uap->what)); + + switch (uap->what) { + case SVR4_semctl: + return svr4_semctl(td, uap); + case SVR4_semget: + return svr4_semget(td, uap); + case SVR4_semop: + return svr4_semop(td, uap); + default: + return EINVAL; + } +} + +MODULE_DEPEND(svr4elf, sysvsem, 1, 1, 1); +#endif + +#ifdef SYSVMSG +static void +bsd_to_svr4_msqid_ds(bds, sds) + const struct msqid_ds *bds; + struct svr4_msqid_ds *sds; +{ + bzero(sds, sizeof(*sds)); + bsd_to_svr4_ipc_perm(&bds->msg_perm, &sds->msg_perm); + sds->msg_first = (struct svr4_msg *) bds->msg_first; + sds->msg_last = (struct svr4_msg *) bds->msg_last; + sds->msg_cbytes = bds->msg_cbytes; + sds->msg_qnum = bds->msg_qnum; + sds->msg_qbytes = bds->msg_qbytes; + sds->msg_lspid = bds->msg_lspid; + sds->msg_lrpid = bds->msg_lrpid; + sds->msg_stime = bds->msg_stime; + sds->msg_rtime = bds->msg_rtime; + sds->msg_ctime = bds->msg_ctime; +} + +static void +svr4_to_bsd_msqid_ds(sds, bds) + const struct svr4_msqid_ds *sds; + struct msqid_ds *bds; +{ + svr4_to_bsd_ipc_perm(&sds->msg_perm, &bds->msg_perm); + bds->msg_first = (struct msg *) sds->msg_first; + bds->msg_last = (struct msg *) sds->msg_last; + bds->msg_cbytes = sds->msg_cbytes; + bds->msg_qnum = sds->msg_qnum; + bds->msg_qbytes = sds->msg_qbytes; + bds->msg_lspid = sds->msg_lspid; + bds->msg_lrpid = sds->msg_lrpid; + bds->msg_stime = sds->msg_stime; + bds->msg_rtime = sds->msg_rtime; + bds->msg_ctime = sds->msg_ctime; +} + +struct svr4_sys_msgsnd_args { + int what; + int msqid; + void * msgp; + size_t msgsz; + int msgflg; +}; + +static int +svr4_msgsnd(td, v) + struct thread *td; + void *v; +{ + struct svr4_sys_msgsnd_args *uap = v; + struct msgsnd_args ap; + + ap.msqid = uap->msqid; + ap.msgp = uap->msgp; + ap.msgsz = uap->msgsz; + ap.msgflg = uap->msgflg; + + return sys_msgsnd(td, &ap); +} + +struct svr4_sys_msgrcv_args { + int what; + int msqid; + void * msgp; + size_t msgsz; + long msgtyp; + int msgflg; +}; + +static int +svr4_msgrcv(td, v) + struct thread *td; + void *v; +{ + struct svr4_sys_msgrcv_args *uap = v; + struct msgrcv_args ap; + + ap.msqid = uap->msqid; + ap.msgp = uap->msgp; + ap.msgsz = uap->msgsz; + ap.msgtyp = uap->msgtyp; + ap.msgflg = uap->msgflg; + + return sys_msgrcv(td, &ap); +} + +struct svr4_sys_msgget_args { + int what; + svr4_key_t key; + int msgflg; +}; + +static int +svr4_msgget(td, v) + struct thread *td; + void *v; +{ + struct svr4_sys_msgget_args *uap = v; + struct msgget_args ap; + + ap.key = uap->key; + ap.msgflg = uap->msgflg; + + return sys_msgget(td, &ap); +} + +struct svr4_sys_msgctl_args { + int what; + int msqid; + int cmd; + struct svr4_msqid_ds * buf; +}; + +static int +svr4_msgctl(td, v) + struct thread *td; + void *v; +{ + struct svr4_sys_msgctl_args *uap = v; + struct svr4_msqid_ds ss; + struct msqid_ds bs; + int error; + + switch (uap->cmd) { + case SVR4_IPC_STAT: + error = kern_msgctl(td, uap->msqid, IPC_STAT, &bs); + if (error) + return error; + bsd_to_svr4_msqid_ds(&bs, &ss); + return copyout(&ss, uap->buf, sizeof ss); + + case SVR4_IPC_SET: + error = copyin(uap->buf, &ss, sizeof ss); + if (error) + return error; + svr4_to_bsd_msqid_ds(&ss, &bs); + return (kern_msgctl(td, uap->msqid, IPC_SET, &bs)); + + case SVR4_IPC_RMID: + return (kern_msgctl(td, uap->msqid, IPC_RMID, NULL)); + + default: + return EINVAL; + } +} + +int +svr4_sys_msgsys(td, uap) + struct thread *td; + struct svr4_sys_msgsys_args *uap; +{ + + DPRINTF(("svr4_msgsys(%d)\n", uap->what)); + + switch (uap->what) { + case SVR4_msgsnd: + return svr4_msgsnd(td, uap); + case SVR4_msgrcv: + return svr4_msgrcv(td, uap); + case SVR4_msgget: + return svr4_msgget(td, uap); + case SVR4_msgctl: + return svr4_msgctl(td, uap); + default: + return EINVAL; + } +} + +MODULE_DEPEND(svr4elf, sysvmsg, 1, 1, 1); +#endif + +#ifdef SYSVSHM + +static void +bsd_to_svr4_shmid_ds(bds, sds) + const struct shmid_ds *bds; + struct svr4_shmid_ds *sds; +{ + bzero(sds, sizeof(*sds)); + bsd_to_svr4_ipc_perm(&bds->shm_perm, &sds->shm_perm); + sds->shm_segsz = bds->shm_segsz; + sds->shm_lkcnt = 0; + sds->shm_lpid = bds->shm_lpid; + sds->shm_cpid = bds->shm_cpid; + sds->shm_amp = 0; + sds->shm_nattch = bds->shm_nattch; + sds->shm_cnattch = 0; + sds->shm_atime = bds->shm_atime; + sds->shm_dtime = bds->shm_dtime; + sds->shm_ctime = bds->shm_ctime; +} + +static void +svr4_to_bsd_shmid_ds(sds, bds) + const struct svr4_shmid_ds *sds; + struct shmid_ds *bds; +{ + svr4_to_bsd_ipc_perm(&sds->shm_perm, &bds->shm_perm); + bds->shm_segsz = sds->shm_segsz; + bds->shm_lpid = sds->shm_lpid; + bds->shm_cpid = sds->shm_cpid; + bds->shm_nattch = sds->shm_nattch; + bds->shm_atime = sds->shm_atime; + bds->shm_dtime = sds->shm_dtime; + bds->shm_ctime = sds->shm_ctime; +} + +struct svr4_sys_shmat_args { + int what; + int shmid; + void * shmaddr; + int shmflg; +}; + +static int +svr4_shmat(td, v) + struct thread *td; + void *v; +{ + struct svr4_sys_shmat_args *uap = v; + struct shmat_args ap; + + ap.shmid = uap->shmid; + ap.shmaddr = uap->shmaddr; + ap.shmflg = uap->shmflg; + + return sys_shmat(td, &ap); +} + +struct svr4_sys_shmdt_args { + int what; + void * shmaddr; +}; + +static int +svr4_shmdt(td, v) + struct thread *td; + void *v; +{ + struct svr4_sys_shmdt_args *uap = v; + struct shmdt_args ap; + + ap.shmaddr = uap->shmaddr; + + return sys_shmdt(td, &ap); +} + +struct svr4_sys_shmget_args { + int what; + key_t key; + int size; + int shmflg; +}; + +static int +svr4_shmget(td, v) + struct thread *td; + void *v; +{ + struct svr4_sys_shmget_args *uap = v; + struct shmget_args ap; + + ap.key = uap->key; + ap.size = uap->size; + ap.shmflg = uap->shmflg; + + return sys_shmget(td, &ap); +} + +struct svr4_sys_shmctl_args { + int what; + int shmid; + int cmd; + struct svr4_shmid_ds * buf; +}; + +int +svr4_shmctl(td, v) + struct thread *td; + void *v; +{ + struct svr4_sys_shmctl_args *uap = v; + struct shmid_ds bs; + struct svr4_shmid_ds ss; + size_t bufsize; + int cmd, error; + + if (uap->buf != NULL) { + switch (uap->cmd) { + case SVR4_IPC_SET: + case SVR4_SHM_LOCK: + case SVR4_SHM_UNLOCK: + error = copyin(uap->buf, &ss, sizeof(ss)); + if (error) + return (error); + svr4_to_bsd_shmid_ds(&ss, &bs); + break; + default: + return (EINVAL); + } + } + + switch (uap->cmd) { + case SVR4_IPC_STAT: + cmd = IPC_STAT; + break; + case SVR4_IPC_SET: + cmd = IPC_SET; + break; + case SVR4_IPC_RMID: + cmd = IPC_RMID; + break; + case SVR4_SHM_LOCK: + cmd = SHM_LOCK; + break; + case SVR4_SHM_UNLOCK: + cmd = SHM_UNLOCK; + break; + default: + return (EINVAL); + } + + error = kern_shmctl(td, uap->shmid, cmd, &bs, &bufsize); + if (error) + return (error); + + switch (uap->cmd) { + case SVR4_IPC_STAT: + if (uap->buf != NULL) { + bsd_to_svr4_shmid_ds(&bs, &ss); + error = copyout(&ss, uap->buf, sizeof(ss)); + } + break; + } + + return (error); +} + +int +svr4_sys_shmsys(td, uap) + struct thread *td; + struct svr4_sys_shmsys_args *uap; +{ + + DPRINTF(("svr4_shmsys(%d)\n", uap->what)); + + switch (uap->what) { + case SVR4_shmat: + return svr4_shmat(td, uap); + case SVR4_shmdt: + return svr4_shmdt(td, uap); + case SVR4_shmget: + return svr4_shmget(td, uap); + case SVR4_shmctl: + return svr4_shmctl(td, uap); + default: + return ENOSYS; + } +} + +MODULE_DEPEND(svr4elf, sysvshm, 1, 1, 1); +#endif /* SYSVSHM */ diff --git a/sys/compat/svr4/svr4_ipc.h b/sys/compat/svr4/svr4_ipc.h new file mode 100644 index 0000000..36cf3dd --- /dev/null +++ b/sys/compat/svr4/svr4_ipc.h @@ -0,0 +1,176 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1995 Christos Zoulas. 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 Christos Zoulas. + * 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 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 _SVR4_IPC_H_ +#define _SVR4_IPC_H_ + +/* + * General IPC + */ +#define SVR4_IPC_RMID 10 +#define SVR4_IPC_SET 11 +#define SVR4_IPC_STAT 12 + +struct svr4_ipc_perm { + svr4_uid_t uid; + svr4_gid_t gid; + svr4_uid_t cuid; + svr4_gid_t cgid; + svr4_mode_t mode; + u_long seq; + svr4_key_t key; + long pad[4]; +}; + +/* + * Message queues + */ +#define SVR4_msgget 0 +#define SVR4_msgctl 1 +#define SVR4_msgrcv 2 +#define SVR4_msgsnd 3 + +struct svr4_msg { + struct svr4_msg *msg_next; + long msg_type; + u_short msg_ts; + short msg_spot; +}; + +struct svr4_msqid_ds { + struct svr4_ipc_perm msg_perm; + struct svr4_msg *msg_first; + struct svr4_msg *msg_last; + u_long msg_cbytes; + u_long msg_qnum; + u_long msg_qbytes; + svr4_pid_t msg_lspid; + svr4_pid_t msg_lrpid; + svr4_time_t msg_stime; + long msg_pad1; + svr4_time_t msg_rtime; + long msg_pad2; + svr4_time_t msg_ctime; + long msg_pad3; + short msg_cv; + short msg_qnum_cv; + long msg_pad4[3]; +}; + +struct svr4_msgbuf { + long mtype; /* message type */ + char mtext[1]; /* message text */ +}; + +struct svr4_msginfo { + int msgmap; + int msgmax; + int msgmnb; + int msgmni; + int msgssz; + int msgtql; + u_short msgseg; +}; + +/* + * Shared memory + */ +#define SVR4_shmat 0 +#define SVR4_shmctl 1 +#define SVR4_shmdt 2 +#define SVR4_shmget 3 + +/* shmctl() operations */ +#define SVR4_SHM_LOCK 3 +#define SVR4_SHM_UNLOCK 4 + +struct svr4_shmid_ds { + struct svr4_ipc_perm shm_perm; + int shm_segsz; + void *shm_amp; + u_short shm_lkcnt; + svr4_pid_t shm_lpid; + svr4_pid_t shm_cpid; + u_long shm_nattch; + u_long shm_cnattch; + svr4_time_t shm_atime; + long shm_pad1; + svr4_time_t shm_dtime; + long shm_pad2; + svr4_time_t shm_ctime; + long shm_pad3; + long shm_pad4[4]; +}; + +/* + * Semaphores + */ +#define SVR4_semctl 0 +#define SVR4_semget 1 +#define SVR4_semop 2 + +/* semctl() operations */ +#define SVR4_SEM_GETNCNT 3 +#define SVR4_SEM_GETPID 4 +#define SVR4_SEM_GETVAL 5 +#define SVR4_SEM_GETALL 6 +#define SVR4_SEM_GETZCNT 7 +#define SVR4_SEM_SETVAL 8 +#define SVR4_SEM_SETALL 9 + +struct svr4_sem { + u_short semval; + svr4_pid_t sempid; + u_short semncnt; + u_short semzcnt; + u_short semncnt_cv; + u_short semzcnt_cv; +}; + +struct svr4_semid_ds { + struct svr4_ipc_perm sem_perm; + struct svr4_sem *sem_base; + u_short sem_nsems; + svr4_time_t sem_otime; + long sem_pad1; + svr4_time_t sem_ctime; + long sem_pad2; + long sem_pad3[4]; +}; + +struct svr4_sembuf { + u_short sem_num; + short sem_op; + short sem_flg; +}; + +#endif /* _SVR4_IPC_H */ diff --git a/sys/compat/svr4/svr4_misc.c b/sys/compat/svr4/svr4_misc.c new file mode 100644 index 0000000..0cfaeae --- /dev/null +++ b/sys/compat/svr4/svr4_misc.c @@ -0,0 +1,1658 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + */ +/* + * SVR4 compatibility module. + * + * SVR4 system calls that are implemented differently in BSD are + * handled here. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/capability.h> +#include <sys/dirent.h> +#include <sys/fcntl.h> +#include <sys/filedesc.h> +#include <sys/imgact.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/file.h> /* Must come after sys/malloc.h */ +#include <sys/mman.h> +#include <sys/mount.h> +#include <sys/msg.h> +#include <sys/mutex.h> +#include <sys/namei.h> +#include <sys/priv.h> +#include <sys/proc.h> +#include <sys/ptrace.h> +#include <sys/resource.h> +#include <sys/resourcevar.h> +#include <sys/sem.h> +#include <sys/signalvar.h> +#include <sys/stat.h> +#include <sys/sx.h> +#include <sys/syscallsubr.h> +#include <sys/sysproto.h> +#include <sys/time.h> +#include <sys/times.h> +#include <sys/uio.h> +#include <sys/vnode.h> +#include <sys/wait.h> + +#include <compat/svr4/svr4.h> +#include <compat/svr4/svr4_types.h> +#include <compat/svr4/svr4_signal.h> +#include <compat/svr4/svr4_proto.h> +#include <compat/svr4/svr4_util.h> +#include <compat/svr4/svr4_sysconfig.h> +#include <compat/svr4/svr4_dirent.h> +#include <compat/svr4/svr4_acl.h> +#include <compat/svr4/svr4_ulimit.h> +#include <compat/svr4/svr4_statvfs.h> +#include <compat/svr4/svr4_hrt.h> +#include <compat/svr4/svr4_mman.h> +#include <compat/svr4/svr4_wait.h> + +#include <security/mac/mac_framework.h> + +#include <machine/vmparam.h> +#include <vm/vm.h> +#include <vm/vm_param.h> +#include <vm/vm_map.h> +#if defined(__FreeBSD__) +#include <vm/uma.h> +#include <vm/vm_extern.h> +#endif + +#if defined(NetBSD) +# if defined(UVM) +# include <uvm/uvm_extern.h> +# endif +#endif + +#define BSD_DIRENT(cp) ((struct dirent *)(cp)) + +static int svr4_mknod(struct thread *, register_t *, char *, + svr4_mode_t, svr4_dev_t); + +static __inline clock_t timeval_to_clock_t(struct timeval *); +static int svr4_setinfo (pid_t , struct rusage *, int, svr4_siginfo_t *); + +struct svr4_hrtcntl_args; +static int svr4_hrtcntl (struct thread *, struct svr4_hrtcntl_args *, + register_t *); +static void bsd_statfs_to_svr4_statvfs(const struct statfs *, + struct svr4_statvfs *); +static void bsd_statfs_to_svr4_statvfs64(const struct statfs *, + struct svr4_statvfs64 *); +static struct proc *svr4_pfind(pid_t pid); + +/* BOGUS noop */ +#if defined(BOGUS) +int +svr4_sys_setitimer(td, uap) + struct thread *td; + struct svr4_sys_setitimer_args *uap; +{ + td->td_retval[0] = 0; + return 0; +} +#endif + +int +svr4_sys_wait(td, uap) + struct thread *td; + struct svr4_sys_wait_args *uap; +{ + int error, st, sig; + + error = kern_wait(td, WAIT_ANY, &st, 0, NULL); + if (error) + return (error); + + if (WIFSIGNALED(st)) { + sig = WTERMSIG(st); + if (sig >= 0 && sig < NSIG) + st = (st & ~0177) | SVR4_BSD2SVR4_SIG(sig); + } else if (WIFSTOPPED(st)) { + sig = WSTOPSIG(st); + if (sig >= 0 && sig < NSIG) + st = (st & ~0xff00) | (SVR4_BSD2SVR4_SIG(sig) << 8); + } + + /* + * It looks like wait(2) on svr4/solaris/2.4 returns + * the status in retval[1], and the pid on retval[0]. + */ + td->td_retval[1] = st; + + if (uap->status) + error = copyout(&st, uap->status, sizeof(st)); + + return (error); +} + +int +svr4_sys_execv(td, uap) + struct thread *td; + struct svr4_sys_execv_args *uap; +{ + struct image_args eargs; + char *path; + int error; + + CHECKALTEXIST(td, uap->path, &path); + + error = exec_copyin_args(&eargs, path, UIO_SYSSPACE, uap->argp, NULL); + free(path, M_TEMP); + if (error == 0) + error = kern_execve(td, &eargs, NULL); + return (error); +} + +int +svr4_sys_execve(td, uap) + struct thread *td; + struct svr4_sys_execve_args *uap; +{ + struct image_args eargs; + char *path; + int error; + + CHECKALTEXIST(td, uap->path, &path); + + error = exec_copyin_args(&eargs, path, UIO_SYSSPACE, uap->argp, + uap->envp); + free(path, M_TEMP); + if (error == 0) + error = kern_execve(td, &eargs, NULL); + return (error); +} + +int +svr4_sys_time(td, v) + struct thread *td; + struct svr4_sys_time_args *v; +{ + struct svr4_sys_time_args *uap = v; + int error = 0; + struct timeval tv; + + microtime(&tv); + if (uap->t) + error = copyout(&tv.tv_sec, uap->t, + sizeof(*(uap->t))); + td->td_retval[0] = (int) tv.tv_sec; + + return error; +} + + +/* + * Read SVR4-style directory entries. We suck them into kernel space so + * that they can be massaged before being copied out to user code. + * + * This code is ported from the Linux emulator: Changes to the VFS interface + * between FreeBSD and NetBSD have made it simpler to port it from there than + * to adapt the NetBSD version. + */ +int +svr4_sys_getdents64(td, uap) + struct thread *td; + struct svr4_sys_getdents64_args *uap; +{ + struct dirent *bdp; + struct vnode *vp; + caddr_t inp, buf; /* BSD-format */ + int len, reclen; /* BSD-format */ + caddr_t outp; /* SVR4-format */ + int resid, svr4reclen=0; /* SVR4-format */ + struct file *fp; + struct uio auio; + struct iovec aiov; + off_t off; + struct svr4_dirent64 svr4_dirent; + int buflen, error, eofflag, nbytes, justone; + u_long *cookies = NULL, *cookiep; + int ncookies; + + DPRINTF(("svr4_sys_getdents64(%d, *, %d)\n", + uap->fd, uap->nbytes)); + if ((error = getvnode(td->td_proc->p_fd, uap->fd, CAP_READ, &fp)) != 0) + return (error); + + if ((fp->f_flag & FREAD) == 0) { + fdrop(fp, td); + return (EBADF); + } + + vp = fp->f_vnode; + if (vp->v_type != VDIR) { + fdrop(fp, td); + return (EINVAL); + } + + nbytes = uap->nbytes; + if (nbytes == 1) { + nbytes = sizeof (struct svr4_dirent64); + justone = 1; + } + else + justone = 0; + + off = fp->f_offset; +#define DIRBLKSIZ 512 /* XXX we used to use ufs's DIRBLKSIZ */ + buflen = max(DIRBLKSIZ, nbytes); + buflen = min(buflen, MAXBSIZE); + buf = malloc(buflen, M_TEMP, M_WAITOK); + vn_lock(vp, LK_SHARED | LK_RETRY); +again: + aiov.iov_base = buf; + aiov.iov_len = buflen; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_td = td; + auio.uio_resid = buflen; + auio.uio_offset = off; + + if (cookies) { + free(cookies, M_TEMP); + cookies = NULL; + } + +#ifdef MAC + error = mac_vnode_check_readdir(td->td_ucred, vp); + if (error) + goto out; +#endif + + error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, + &ncookies, &cookies); + if (error) { + goto out; + } + + inp = buf; + outp = (caddr_t) uap->dp; + resid = nbytes; + if ((len = buflen - auio.uio_resid) <= 0) { + goto eof; + } + + cookiep = cookies; + + if (cookies) { + /* + * When using cookies, the vfs has the option of reading from + * a different offset than that supplied (UFS truncates the + * offset to a block boundary to make sure that it never reads + * partway through a directory entry, even if the directory + * has been compacted). + */ + while (len > 0 && ncookies > 0 && *cookiep <= off) { + bdp = (struct dirent *) inp; + len -= bdp->d_reclen; + inp += bdp->d_reclen; + cookiep++; + ncookies--; + } + } + + while (len > 0) { + if (cookiep && ncookies == 0) + break; + bdp = (struct dirent *) inp; + reclen = bdp->d_reclen; + if (reclen & 3) { + DPRINTF(("svr4_readdir: reclen=%d\n", reclen)); + error = EFAULT; + goto out; + } + + if (bdp->d_fileno == 0) { + inp += reclen; + if (cookiep) { + off = *cookiep++; + ncookies--; + } else + off += reclen; + len -= reclen; + continue; + } + svr4reclen = SVR4_RECLEN(&svr4_dirent, bdp->d_namlen); + if (reclen > len || resid < svr4reclen) { + outp++; + break; + } + svr4_dirent.d_ino = (long) bdp->d_fileno; + if (justone) { + /* + * old svr4-style readdir usage. + */ + svr4_dirent.d_off = (svr4_off_t) svr4reclen; + svr4_dirent.d_reclen = (u_short) bdp->d_namlen; + } else { + svr4_dirent.d_off = (svr4_off_t)(off + reclen); + svr4_dirent.d_reclen = (u_short) svr4reclen; + } + strlcpy(svr4_dirent.d_name, bdp->d_name, sizeof(svr4_dirent.d_name)); + if ((error = copyout((caddr_t)&svr4_dirent, outp, svr4reclen))) + goto out; + inp += reclen; + if (cookiep) { + off = *cookiep++; + ncookies--; + } else + off += reclen; + outp += svr4reclen; + resid -= svr4reclen; + len -= reclen; + if (justone) + break; + } + + if (outp == (caddr_t) uap->dp) + goto again; + fp->f_offset = off; + + if (justone) + nbytes = resid + svr4reclen; + +eof: + td->td_retval[0] = nbytes - resid; +out: + VOP_UNLOCK(vp, 0); + fdrop(fp, td); + if (cookies) + free(cookies, M_TEMP); + free(buf, M_TEMP); + return error; +} + + +int +svr4_sys_getdents(td, uap) + struct thread *td; + struct svr4_sys_getdents_args *uap; +{ + struct dirent *bdp; + struct vnode *vp; + caddr_t inp, buf; /* BSD-format */ + int len, reclen; /* BSD-format */ + caddr_t outp; /* SVR4-format */ + int resid, svr4_reclen; /* SVR4-format */ + struct file *fp; + struct uio auio; + struct iovec aiov; + struct svr4_dirent idb; + off_t off; /* true file offset */ + int buflen, error, eofflag; + u_long *cookiebuf = NULL, *cookie; + int ncookies = 0, *retval = td->td_retval; + + if (uap->nbytes < 0) + return (EINVAL); + + if ((error = getvnode(td->td_proc->p_fd, uap->fd, CAP_READ, &fp)) != 0) + return (error); + + if ((fp->f_flag & FREAD) == 0) { + fdrop(fp, td); + return (EBADF); + } + + vp = fp->f_vnode; + if (vp->v_type != VDIR) { + fdrop(fp, td); + return (EINVAL); + } + + buflen = min(MAXBSIZE, uap->nbytes); + buf = malloc(buflen, M_TEMP, M_WAITOK); + vn_lock(vp, LK_SHARED | LK_RETRY); + off = fp->f_offset; +again: + aiov.iov_base = buf; + aiov.iov_len = buflen; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_td = td; + auio.uio_resid = buflen; + auio.uio_offset = off; + +#ifdef MAC + error = mac_vnode_check_readdir(td->td_ucred, vp); + if (error) + goto out; +#endif + + /* + * First we read into the malloc'ed buffer, then + * we massage it into user space, one record at a time. + */ + error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, + &cookiebuf); + if (error) { + goto out; + } + + inp = buf; + outp = uap->buf; + resid = uap->nbytes; + if ((len = buflen - auio.uio_resid) == 0) + goto eof; + + for (cookie = cookiebuf; len > 0; len -= reclen) { + bdp = (struct dirent *)inp; + reclen = bdp->d_reclen; + if (reclen & 3) + panic("svr4_sys_getdents64: bad reclen"); + if (cookie) + off = *cookie++; /* each entry points to the next */ + else + off += reclen; + if ((off >> 32) != 0) { + uprintf("svr4_sys_getdents64: dir offset too large for emulated program"); + error = EINVAL; + goto out; + } + if (bdp->d_fileno == 0) { + inp += reclen; /* it is a hole; squish it out */ + continue; + } + svr4_reclen = SVR4_RECLEN(&idb, bdp->d_namlen); + if (reclen > len || resid < svr4_reclen) { + /* entry too big for buffer, so just stop */ + outp++; + break; + } + /* + * Massage in place to make a SVR4-shaped dirent (otherwise + * we have to worry about touching user memory outside of + * the copyout() call). + */ + idb.d_ino = (svr4_ino_t)bdp->d_fileno; + idb.d_off = (svr4_off_t)off; + idb.d_reclen = (u_short)svr4_reclen; + strlcpy(idb.d_name, bdp->d_name, sizeof(idb.d_name)); + if ((error = copyout((caddr_t)&idb, outp, svr4_reclen))) + goto out; + /* advance past this real entry */ + inp += reclen; + /* advance output past SVR4-shaped entry */ + outp += svr4_reclen; + resid -= svr4_reclen; + } + + /* if we squished out the whole block, try again */ + if (outp == uap->buf) + goto again; + fp->f_offset = off; /* update the vnode offset */ + +eof: + *retval = uap->nbytes - resid; +out: + VOP_UNLOCK(vp, 0); + fdrop(fp, td); + if (cookiebuf) + free(cookiebuf, M_TEMP); + free(buf, M_TEMP); + return error; +} + + +int +svr4_sys_mmap(td, uap) + struct thread *td; + struct svr4_sys_mmap_args *uap; +{ + struct mmap_args mm; + int *retval; + + retval = td->td_retval; +#define _MAP_NEW 0x80000000 + /* + * Verify the arguments. + */ + if (uap->prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) + return EINVAL; /* XXX still needed? */ + + if (uap->len == 0) + return EINVAL; + + mm.prot = uap->prot; + mm.len = uap->len; + mm.flags = uap->flags & ~_MAP_NEW; + mm.fd = uap->fd; + mm.addr = uap->addr; + mm.pos = uap->pos; + + return sys_mmap(td, &mm); +} + +int +svr4_sys_mmap64(td, uap) + struct thread *td; + struct svr4_sys_mmap64_args *uap; +{ + struct mmap_args mm; + void *rp; + +#define _MAP_NEW 0x80000000 + /* + * Verify the arguments. + */ + if (uap->prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) + return EINVAL; /* XXX still needed? */ + + if (uap->len == 0) + return EINVAL; + + mm.prot = uap->prot; + mm.len = uap->len; + mm.flags = uap->flags & ~_MAP_NEW; + mm.fd = uap->fd; + mm.addr = uap->addr; + mm.pos = uap->pos; + + rp = (void *) round_page((vm_offset_t)(td->td_proc->p_vmspace->vm_daddr + maxdsiz)); + if ((mm.flags & MAP_FIXED) == 0 && + mm.addr != 0 && (void *)mm.addr < rp) + mm.addr = rp; + + return sys_mmap(td, &mm); +} + + +int +svr4_sys_fchroot(td, uap) + struct thread *td; + struct svr4_sys_fchroot_args *uap; +{ + struct filedesc *fdp = td->td_proc->p_fd; + struct vnode *vp; + struct file *fp; + int error; + + if ((error = priv_check(td, PRIV_VFS_FCHROOT)) != 0) + return error; + /* XXX: we have the chroot priv... what cap might we need? all? */ + if ((error = getvnode(fdp, uap->fd, 0, &fp)) != 0) + return error; + vp = fp->f_vnode; + VREF(vp); + fdrop(fp, td); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + error = change_dir(vp, td); + if (error) + goto fail; +#ifdef MAC + error = mac_vnode_check_chroot(td->td_ucred, vp); + if (error) + goto fail; +#endif + VOP_UNLOCK(vp, 0); + error = change_root(vp, td); + vrele(vp); + return (error); +fail: + vput(vp); + return (error); +} + + +static int +svr4_mknod(td, retval, path, mode, dev) + struct thread *td; + register_t *retval; + char *path; + svr4_mode_t mode; + svr4_dev_t dev; +{ + char *newpath; + int error; + + CHECKALTEXIST(td, path, &newpath); + + if (S_ISFIFO(mode)) + error = kern_mkfifo(td, newpath, UIO_SYSSPACE, mode); + else + error = kern_mknod(td, newpath, UIO_SYSSPACE, mode, dev); + free(newpath, M_TEMP); + return (error); +} + + +int +svr4_sys_mknod(td, uap) + struct thread *td; + struct svr4_sys_mknod_args *uap; +{ + int *retval = td->td_retval; + return svr4_mknod(td, retval, + uap->path, uap->mode, + (svr4_dev_t)svr4_to_bsd_odev_t(uap->dev)); +} + + +int +svr4_sys_xmknod(td, uap) + struct thread *td; + struct svr4_sys_xmknod_args *uap; +{ + int *retval = td->td_retval; + return svr4_mknod(td, retval, + uap->path, uap->mode, + (svr4_dev_t)svr4_to_bsd_dev_t(uap->dev)); +} + + +int +svr4_sys_vhangup(td, uap) + struct thread *td; + struct svr4_sys_vhangup_args *uap; +{ + return 0; +} + + +int +svr4_sys_sysconfig(td, uap) + struct thread *td; + struct svr4_sys_sysconfig_args *uap; +{ + int *retval; + + retval = &(td->td_retval[0]); + + switch (uap->name) { + case SVR4_CONFIG_NGROUPS: + *retval = ngroups_max; + break; + case SVR4_CONFIG_CHILD_MAX: + *retval = maxproc; + break; + case SVR4_CONFIG_OPEN_FILES: + *retval = maxfiles; + break; + case SVR4_CONFIG_POSIX_VER: + *retval = 198808; + break; + case SVR4_CONFIG_PAGESIZE: + *retval = PAGE_SIZE; + break; + case SVR4_CONFIG_CLK_TCK: + *retval = 60; /* should this be `hz', ie. 100? */ + break; + case SVR4_CONFIG_XOPEN_VER: + *retval = 2; /* XXX: What should that be? */ + break; + case SVR4_CONFIG_PROF_TCK: + *retval = 60; /* XXX: What should that be? */ + break; + case SVR4_CONFIG_NPROC_CONF: + *retval = 1; /* Only one processor for now */ + break; + case SVR4_CONFIG_NPROC_ONLN: + *retval = 1; /* And it better be online */ + break; + case SVR4_CONFIG_AIO_LISTIO_MAX: + case SVR4_CONFIG_AIO_MAX: + case SVR4_CONFIG_AIO_PRIO_DELTA_MAX: + *retval = 0; /* No aio support */ + break; + case SVR4_CONFIG_DELAYTIMER_MAX: + *retval = 0; /* No delaytimer support */ + break; + case SVR4_CONFIG_MQ_OPEN_MAX: + *retval = msginfo.msgmni; + break; + case SVR4_CONFIG_MQ_PRIO_MAX: + *retval = 0; /* XXX: Don't know */ + break; + case SVR4_CONFIG_RTSIG_MAX: + *retval = 0; + break; + case SVR4_CONFIG_SEM_NSEMS_MAX: + *retval = seminfo.semmni; + break; + case SVR4_CONFIG_SEM_VALUE_MAX: + *retval = seminfo.semvmx; + break; + case SVR4_CONFIG_SIGQUEUE_MAX: + *retval = 0; /* XXX: Don't know */ + break; + case SVR4_CONFIG_SIGRT_MIN: + case SVR4_CONFIG_SIGRT_MAX: + *retval = 0; /* No real time signals */ + break; + case SVR4_CONFIG_TIMER_MAX: + *retval = 3; /* XXX: real, virtual, profiling */ + break; +#if defined(NOTYET) + case SVR4_CONFIG_PHYS_PAGES: +#if defined(UVM) + *retval = uvmexp.free; /* XXX: free instead of total */ +#else + *retval = cnt.v_free_count; /* XXX: free instead of total */ +#endif + break; + case SVR4_CONFIG_AVPHYS_PAGES: +#if defined(UVM) + *retval = uvmexp.active; /* XXX: active instead of avg */ +#else + *retval = cnt.v_active_count; /* XXX: active instead of avg */ +#endif + break; +#endif /* NOTYET */ + case SVR4_CONFIG_COHERENCY: + *retval = 0; /* XXX */ + break; + case SVR4_CONFIG_SPLIT_CACHE: + *retval = 0; /* XXX */ + break; + case SVR4_CONFIG_ICACHESZ: + *retval = 256; /* XXX */ + break; + case SVR4_CONFIG_DCACHESZ: + *retval = 256; /* XXX */ + break; + case SVR4_CONFIG_ICACHELINESZ: + *retval = 64; /* XXX */ + break; + case SVR4_CONFIG_DCACHELINESZ: + *retval = 64; /* XXX */ + break; + case SVR4_CONFIG_ICACHEBLKSZ: + *retval = 64; /* XXX */ + break; + case SVR4_CONFIG_DCACHEBLKSZ: + *retval = 64; /* XXX */ + break; + case SVR4_CONFIG_DCACHETBLKSZ: + *retval = 64; /* XXX */ + break; + case SVR4_CONFIG_ICACHE_ASSOC: + *retval = 1; /* XXX */ + break; + case SVR4_CONFIG_DCACHE_ASSOC: + *retval = 1; /* XXX */ + break; + case SVR4_CONFIG_MAXPID: + *retval = PID_MAX; + break; + case SVR4_CONFIG_STACK_PROT: + *retval = PROT_READ|PROT_WRITE|PROT_EXEC; + break; + default: + return EINVAL; + } + return 0; +} + +/* ARGSUSED */ +int +svr4_sys_break(td, uap) + struct thread *td; + struct svr4_sys_break_args *uap; +{ + struct obreak_args ap; + + ap.nsize = uap->nsize; + return (sys_obreak(td, &ap)); +} + +static __inline clock_t +timeval_to_clock_t(tv) + struct timeval *tv; +{ + return tv->tv_sec * hz + tv->tv_usec / (1000000 / hz); +} + + +int +svr4_sys_times(td, uap) + struct thread *td; + struct svr4_sys_times_args *uap; +{ + struct timeval tv, utime, stime, cutime, cstime; + struct tms tms; + struct proc *p; + int error; + + p = td->td_proc; + PROC_LOCK(p); + PROC_SLOCK(p); + calcru(p, &utime, &stime); + PROC_SUNLOCK(p); + calccru(p, &cutime, &cstime); + PROC_UNLOCK(p); + + tms.tms_utime = timeval_to_clock_t(&utime); + tms.tms_stime = timeval_to_clock_t(&stime); + + tms.tms_cutime = timeval_to_clock_t(&cutime); + tms.tms_cstime = timeval_to_clock_t(&cstime); + + error = copyout(&tms, uap->tp, sizeof(tms)); + if (error) + return (error); + + microtime(&tv); + td->td_retval[0] = (int)timeval_to_clock_t(&tv); + return (0); +} + + +int +svr4_sys_ulimit(td, uap) + struct thread *td; + struct svr4_sys_ulimit_args *uap; +{ + int *retval = td->td_retval; + int error; + + switch (uap->cmd) { + case SVR4_GFILLIM: + PROC_LOCK(td->td_proc); + *retval = lim_cur(td->td_proc, RLIMIT_FSIZE) / 512; + PROC_UNLOCK(td->td_proc); + if (*retval == -1) + *retval = 0x7fffffff; + return 0; + + case SVR4_SFILLIM: + { + struct rlimit krl; + + krl.rlim_cur = uap->newlimit * 512; + PROC_LOCK(td->td_proc); + krl.rlim_max = lim_max(td->td_proc, RLIMIT_FSIZE); + PROC_UNLOCK(td->td_proc); + + error = kern_setrlimit(td, RLIMIT_FSIZE, &krl); + if (error) + return error; + + PROC_LOCK(td->td_proc); + *retval = lim_cur(td->td_proc, RLIMIT_FSIZE); + PROC_UNLOCK(td->td_proc); + if (*retval == -1) + *retval = 0x7fffffff; + return 0; + } + + case SVR4_GMEMLIM: + { + struct vmspace *vm = td->td_proc->p_vmspace; + register_t r; + + PROC_LOCK(td->td_proc); + r = lim_cur(td->td_proc, RLIMIT_DATA); + PROC_UNLOCK(td->td_proc); + + if (r == -1) + r = 0x7fffffff; + r += (long) vm->vm_daddr; + if (r < 0) + r = 0x7fffffff; + *retval = r; + return 0; + } + + case SVR4_GDESLIM: + PROC_LOCK(td->td_proc); + *retval = lim_cur(td->td_proc, RLIMIT_NOFILE); + PROC_UNLOCK(td->td_proc); + if (*retval == -1) + *retval = 0x7fffffff; + return 0; + + default: + return EINVAL; + } +} + +static struct proc * +svr4_pfind(pid) + pid_t pid; +{ + struct proc *p; + + /* look in the live processes */ + if ((p = pfind(pid)) == NULL) + /* look in the zombies */ + p = zpfind(pid); + + return p; +} + + +int +svr4_sys_pgrpsys(td, uap) + struct thread *td; + struct svr4_sys_pgrpsys_args *uap; +{ + int *retval = td->td_retval; + struct proc *p = td->td_proc; + + switch (uap->cmd) { + case 1: /* setpgrp() */ + /* + * SVR4 setpgrp() (which takes no arguments) has the + * semantics that the session ID is also created anew, so + * in almost every sense, setpgrp() is identical to + * setsid() for SVR4. (Under BSD, the difference is that + * a setpgid(0,0) will not create a new session.) + */ + sys_setsid(td, NULL); + /*FALLTHROUGH*/ + + case 0: /* getpgrp() */ + PROC_LOCK(p); + *retval = p->p_pgrp->pg_id; + PROC_UNLOCK(p); + return 0; + + case 2: /* getsid(pid) */ + if (uap->pid == 0) + PROC_LOCK(p); + else if ((p = svr4_pfind(uap->pid)) == NULL) + return ESRCH; + /* + * This has already been initialized to the pid of + * the session leader. + */ + *retval = (register_t) p->p_session->s_sid; + PROC_UNLOCK(p); + return 0; + + case 3: /* setsid() */ + return sys_setsid(td, NULL); + + case 4: /* getpgid(pid) */ + + if (uap->pid == 0) + PROC_LOCK(p); + else if ((p = svr4_pfind(uap->pid)) == NULL) + return ESRCH; + + *retval = (int) p->p_pgrp->pg_id; + PROC_UNLOCK(p); + return 0; + + case 5: /* setpgid(pid, pgid); */ + { + struct setpgid_args sa; + + sa.pid = uap->pid; + sa.pgid = uap->pgid; + return sys_setpgid(td, &sa); + } + + default: + return EINVAL; + } +} + +struct svr4_hrtcntl_args { + int cmd; + int fun; + int clk; + svr4_hrt_interval_t * iv; + svr4_hrt_time_t * ti; +}; + + +static int +svr4_hrtcntl(td, uap, retval) + struct thread *td; + struct svr4_hrtcntl_args *uap; + register_t *retval; +{ + switch (uap->fun) { + case SVR4_HRT_CNTL_RES: + DPRINTF(("htrcntl(RES)\n")); + *retval = SVR4_HRT_USEC; + return 0; + + case SVR4_HRT_CNTL_TOFD: + DPRINTF(("htrcntl(TOFD)\n")); + { + struct timeval tv; + svr4_hrt_time_t t; + if (uap->clk != SVR4_HRT_CLK_STD) { + DPRINTF(("clk == %d\n", uap->clk)); + return EINVAL; + } + if (uap->ti == NULL) { + DPRINTF(("ti NULL\n")); + return EINVAL; + } + microtime(&tv); + t.h_sec = tv.tv_sec; + t.h_rem = tv.tv_usec; + t.h_res = SVR4_HRT_USEC; + return copyout(&t, uap->ti, sizeof(t)); + } + + case SVR4_HRT_CNTL_START: + DPRINTF(("htrcntl(START)\n")); + return ENOSYS; + + case SVR4_HRT_CNTL_GET: + DPRINTF(("htrcntl(GET)\n")); + return ENOSYS; + default: + DPRINTF(("Bad htrcntl command %d\n", uap->fun)); + return ENOSYS; + } +} + + +int +svr4_sys_hrtsys(td, uap) + struct thread *td; + struct svr4_sys_hrtsys_args *uap; +{ + int *retval = td->td_retval; + + switch (uap->cmd) { + case SVR4_HRT_CNTL: + return svr4_hrtcntl(td, (struct svr4_hrtcntl_args *) uap, + retval); + + case SVR4_HRT_ALRM: + DPRINTF(("hrtalarm\n")); + return ENOSYS; + + case SVR4_HRT_SLP: + DPRINTF(("hrtsleep\n")); + return ENOSYS; + + case SVR4_HRT_CAN: + DPRINTF(("hrtcancel\n")); + return ENOSYS; + + default: + DPRINTF(("Bad hrtsys command %d\n", uap->cmd)); + return EINVAL; + } +} + + +static int +svr4_setinfo(pid, ru, st, s) + pid_t pid; + struct rusage *ru; + int st; + svr4_siginfo_t *s; +{ + svr4_siginfo_t i; + int sig; + + memset(&i, 0, sizeof(i)); + + i.svr4_si_signo = SVR4_SIGCHLD; + i.svr4_si_errno = 0; /* XXX? */ + + i.svr4_si_pid = pid; + if (ru) { + i.svr4_si_stime = ru->ru_stime.tv_sec; + i.svr4_si_utime = ru->ru_utime.tv_sec; + } + + if (WIFEXITED(st)) { + i.svr4_si_status = WEXITSTATUS(st); + i.svr4_si_code = SVR4_CLD_EXITED; + } else if (WIFSTOPPED(st)) { + sig = WSTOPSIG(st); + if (sig >= 0 && sig < NSIG) + i.svr4_si_status = SVR4_BSD2SVR4_SIG(sig); + + if (i.svr4_si_status == SVR4_SIGCONT) + i.svr4_si_code = SVR4_CLD_CONTINUED; + else + i.svr4_si_code = SVR4_CLD_STOPPED; + } else { + sig = WTERMSIG(st); + if (sig >= 0 && sig < NSIG) + i.svr4_si_status = SVR4_BSD2SVR4_SIG(sig); + + if (WCOREDUMP(st)) + i.svr4_si_code = SVR4_CLD_DUMPED; + else + i.svr4_si_code = SVR4_CLD_KILLED; + } + + DPRINTF(("siginfo [pid %ld signo %d code %d errno %d status %d]\n", + i.svr4_si_pid, i.svr4_si_signo, i.svr4_si_code, i.svr4_si_errno, + i.svr4_si_status)); + + return copyout(&i, s, sizeof(i)); +} + + +int +svr4_sys_waitsys(td, uap) + struct thread *td; + struct svr4_sys_waitsys_args *uap; +{ + struct rusage ru; + pid_t pid; + int nfound, status; + int error, *retval = td->td_retval; + struct proc *p, *q; + + DPRINTF(("waitsys(%d, %d, %p, %x)\n", + uap->grp, uap->id, + uap->info, uap->options)); + + q = td->td_proc; + switch (uap->grp) { + case SVR4_P_PID: + pid = uap->id; + break; + + case SVR4_P_PGID: + PROC_LOCK(q); + pid = -q->p_pgid; + PROC_UNLOCK(q); + break; + + case SVR4_P_ALL: + pid = WAIT_ANY; + break; + + default: + return EINVAL; + } + + /* Hand off the easy cases to kern_wait(). */ + if (!(uap->options & (SVR4_WNOWAIT)) && + (uap->options & (SVR4_WEXITED | SVR4_WTRAPPED))) { + int options; + + options = 0; + if (uap->options & SVR4_WSTOPPED) + options |= WUNTRACED; + if (uap->options & SVR4_WCONTINUED) + options |= WCONTINUED; + if (uap->options & SVR4_WNOHANG) + options |= WNOHANG; + + error = kern_wait(td, pid, &status, options, &ru); + if (error) + return (error); + if (uap->options & SVR4_WNOHANG && *retval == 0) + error = svr4_setinfo(*retval, NULL, 0, uap->info); + else + error = svr4_setinfo(*retval, &ru, status, uap->info); + *retval = 0; + return (error); + } + + /* + * Ok, handle the weird cases. Either WNOWAIT is set (meaning we + * just want to see if there is a process to harvest, we don't + * want to actually harvest it), or WEXIT and WTRAPPED are clear + * meaning we want to ignore zombies. Either way, we don't have + * to handle harvesting zombies here. We do have to duplicate the + * other portions of kern_wait() though, especially for WCONTINUED + * and WSTOPPED. + */ +loop: + nfound = 0; + sx_slock(&proctree_lock); + LIST_FOREACH(p, &q->p_children, p_sibling) { + PROC_LOCK(p); + if (pid != WAIT_ANY && + p->p_pid != pid && p->p_pgid != -pid) { + PROC_UNLOCK(p); + DPRINTF(("pid %d pgid %d != %d\n", p->p_pid, + p->p_pgid, pid)); + continue; + } + if (p_canwait(td, p)) { + PROC_UNLOCK(p); + continue; + } + + nfound++; + + PROC_SLOCK(p); + /* + * See if we have a zombie. If so, WNOWAIT should be set, + * as otherwise we should have called kern_wait() up above. + */ + if ((p->p_state == PRS_ZOMBIE) && + ((uap->options & (SVR4_WEXITED|SVR4_WTRAPPED)))) { + PROC_SUNLOCK(p); + KASSERT(uap->options & SVR4_WNOWAIT, + ("WNOWAIT is clear")); + + /* Found a zombie, so cache info in local variables. */ + pid = p->p_pid; + status = p->p_xstat; + ru = p->p_ru; + PROC_SLOCK(p); + calcru(p, &ru.ru_utime, &ru.ru_stime); + PROC_SUNLOCK(p); + PROC_UNLOCK(p); + sx_sunlock(&proctree_lock); + + /* Copy the info out to userland. */ + *retval = 0; + DPRINTF(("found %d\n", pid)); + return (svr4_setinfo(pid, &ru, status, uap->info)); + } + + /* + * See if we have a stopped or continued process. + * XXX: This duplicates the same code in kern_wait(). + */ + if ((p->p_flag & P_STOPPED_SIG) && + (p->p_suspcount == p->p_numthreads) && + (p->p_flag & P_WAITED) == 0 && + (p->p_flag & P_TRACED || uap->options & SVR4_WSTOPPED)) { + PROC_SUNLOCK(p); + if (((uap->options & SVR4_WNOWAIT)) == 0) + p->p_flag |= P_WAITED; + sx_sunlock(&proctree_lock); + pid = p->p_pid; + status = W_STOPCODE(p->p_xstat); + ru = p->p_ru; + PROC_SLOCK(p); + calcru(p, &ru.ru_utime, &ru.ru_stime); + PROC_SUNLOCK(p); + PROC_UNLOCK(p); + + if (((uap->options & SVR4_WNOWAIT)) == 0) { + PROC_LOCK(q); + sigqueue_take(p->p_ksi); + PROC_UNLOCK(q); + } + + *retval = 0; + DPRINTF(("jobcontrol %d\n", pid)); + return (svr4_setinfo(pid, &ru, status, uap->info)); + } + PROC_SUNLOCK(p); + if (uap->options & SVR4_WCONTINUED && + (p->p_flag & P_CONTINUED)) { + sx_sunlock(&proctree_lock); + if (((uap->options & SVR4_WNOWAIT)) == 0) + p->p_flag &= ~P_CONTINUED; + pid = p->p_pid; + ru = p->p_ru; + status = SIGCONT; + PROC_SLOCK(p); + calcru(p, &ru.ru_utime, &ru.ru_stime); + PROC_SUNLOCK(p); + PROC_UNLOCK(p); + + if (((uap->options & SVR4_WNOWAIT)) == 0) { + PROC_LOCK(q); + sigqueue_take(p->p_ksi); + PROC_UNLOCK(q); + } + + *retval = 0; + DPRINTF(("jobcontrol %d\n", pid)); + return (svr4_setinfo(pid, &ru, status, uap->info)); + } + PROC_UNLOCK(p); + } + + if (nfound == 0) { + sx_sunlock(&proctree_lock); + return (ECHILD); + } + + if (uap->options & SVR4_WNOHANG) { + sx_sunlock(&proctree_lock); + *retval = 0; + return (svr4_setinfo(0, NULL, 0, uap->info)); + } + + PROC_LOCK(q); + sx_sunlock(&proctree_lock); + if (q->p_flag & P_STATCHILD) { + q->p_flag &= ~P_STATCHILD; + error = 0; + } else + error = msleep(q, &q->p_mtx, PWAIT | PCATCH, "svr4_wait", 0); + PROC_UNLOCK(q); + if (error) + return error; + goto loop; +} + + +static void +bsd_statfs_to_svr4_statvfs(bfs, sfs) + const struct statfs *bfs; + struct svr4_statvfs *sfs; +{ + sfs->f_bsize = bfs->f_iosize; /* XXX */ + sfs->f_frsize = bfs->f_bsize; + sfs->f_blocks = bfs->f_blocks; + sfs->f_bfree = bfs->f_bfree; + sfs->f_bavail = bfs->f_bavail; + sfs->f_files = bfs->f_files; + sfs->f_ffree = bfs->f_ffree; + sfs->f_favail = bfs->f_ffree; + sfs->f_fsid = bfs->f_fsid.val[0]; + memcpy(sfs->f_basetype, bfs->f_fstypename, sizeof(sfs->f_basetype)); + sfs->f_flag = 0; + if (bfs->f_flags & MNT_RDONLY) + sfs->f_flag |= SVR4_ST_RDONLY; + if (bfs->f_flags & MNT_NOSUID) + sfs->f_flag |= SVR4_ST_NOSUID; + sfs->f_namemax = MAXNAMLEN; + memcpy(sfs->f_fstr, bfs->f_fstypename, sizeof(sfs->f_fstr)); /* XXX */ + memset(sfs->f_filler, 0, sizeof(sfs->f_filler)); +} + + +static void +bsd_statfs_to_svr4_statvfs64(bfs, sfs) + const struct statfs *bfs; + struct svr4_statvfs64 *sfs; +{ + sfs->f_bsize = bfs->f_iosize; /* XXX */ + sfs->f_frsize = bfs->f_bsize; + sfs->f_blocks = bfs->f_blocks; + sfs->f_bfree = bfs->f_bfree; + sfs->f_bavail = bfs->f_bavail; + sfs->f_files = bfs->f_files; + sfs->f_ffree = bfs->f_ffree; + sfs->f_favail = bfs->f_ffree; + sfs->f_fsid = bfs->f_fsid.val[0]; + memcpy(sfs->f_basetype, bfs->f_fstypename, sizeof(sfs->f_basetype)); + sfs->f_flag = 0; + if (bfs->f_flags & MNT_RDONLY) + sfs->f_flag |= SVR4_ST_RDONLY; + if (bfs->f_flags & MNT_NOSUID) + sfs->f_flag |= SVR4_ST_NOSUID; + sfs->f_namemax = MAXNAMLEN; + memcpy(sfs->f_fstr, bfs->f_fstypename, sizeof(sfs->f_fstr)); /* XXX */ + memset(sfs->f_filler, 0, sizeof(sfs->f_filler)); +} + + +int +svr4_sys_statvfs(td, uap) + struct thread *td; + struct svr4_sys_statvfs_args *uap; +{ + struct svr4_statvfs sfs; + struct statfs bfs; + char *path; + int error; + + CHECKALTEXIST(td, uap->path, &path); + + error = kern_statfs(td, path, UIO_SYSSPACE, &bfs); + free(path, M_TEMP); + if (error) + return (error); + bsd_statfs_to_svr4_statvfs(&bfs, &sfs); + return copyout(&sfs, uap->fs, sizeof(sfs)); +} + + +int +svr4_sys_fstatvfs(td, uap) + struct thread *td; + struct svr4_sys_fstatvfs_args *uap; +{ + struct svr4_statvfs sfs; + struct statfs bfs; + int error; + + error = kern_fstatfs(td, uap->fd, &bfs); + if (error) + return (error); + bsd_statfs_to_svr4_statvfs(&bfs, &sfs); + return copyout(&sfs, uap->fs, sizeof(sfs)); +} + + +int +svr4_sys_statvfs64(td, uap) + struct thread *td; + struct svr4_sys_statvfs64_args *uap; +{ + struct svr4_statvfs64 sfs; + struct statfs bfs; + char *path; + int error; + + CHECKALTEXIST(td, uap->path, &path); + + error = kern_statfs(td, path, UIO_SYSSPACE, &bfs); + free(path, M_TEMP); + if (error) + return (error); + bsd_statfs_to_svr4_statvfs64(&bfs, &sfs); + return copyout(&sfs, uap->fs, sizeof(sfs)); +} + + +int +svr4_sys_fstatvfs64(td, uap) + struct thread *td; + struct svr4_sys_fstatvfs64_args *uap; +{ + struct svr4_statvfs64 sfs; + struct statfs bfs; + int error; + + error = kern_fstatfs(td, uap->fd, &bfs); + if (error) + return (error); + bsd_statfs_to_svr4_statvfs64(&bfs, &sfs); + return copyout(&sfs, uap->fs, sizeof(sfs)); +} + +int +svr4_sys_alarm(td, uap) + struct thread *td; + struct svr4_sys_alarm_args *uap; +{ + struct itimerval itv, oitv; + int error; + + timevalclear(&itv.it_interval); + itv.it_value.tv_sec = uap->sec; + itv.it_value.tv_usec = 0; + error = kern_setitimer(td, ITIMER_REAL, &itv, &oitv); + if (error) + return (error); + if (oitv.it_value.tv_usec != 0) + oitv.it_value.tv_sec++; + td->td_retval[0] = oitv.it_value.tv_sec; + return (0); +} + +int +svr4_sys_gettimeofday(td, uap) + struct thread *td; + struct svr4_sys_gettimeofday_args *uap; +{ + if (uap->tp) { + struct timeval atv; + + microtime(&atv); + return copyout(&atv, uap->tp, sizeof (atv)); + } + + return 0; +} + +int +svr4_sys_facl(td, uap) + struct thread *td; + struct svr4_sys_facl_args *uap; +{ + int *retval; + + retval = td->td_retval; + *retval = 0; + + switch (uap->cmd) { + case SVR4_SYS_SETACL: + /* We don't support acls on any filesystem */ + return ENOSYS; + + case SVR4_SYS_GETACL: + return copyout(retval, &uap->num, + sizeof(uap->num)); + + case SVR4_SYS_GETACLCNT: + return 0; + + default: + return EINVAL; + } +} + + +int +svr4_sys_acl(td, uap) + struct thread *td; + struct svr4_sys_acl_args *uap; +{ + /* XXX: for now the same */ + return svr4_sys_facl(td, (struct svr4_sys_facl_args *)uap); +} + +int +svr4_sys_auditsys(td, uap) + struct thread *td; + struct svr4_sys_auditsys_args *uap; +{ + /* + * XXX: Big brother is *not* watching. + */ + return 0; +} + +int +svr4_sys_memcntl(td, uap) + struct thread *td; + struct svr4_sys_memcntl_args *uap; +{ + switch (uap->cmd) { + case SVR4_MC_SYNC: + { + struct msync_args msa; + + msa.addr = uap->addr; + msa.len = uap->len; + msa.flags = (int)uap->arg; + + return sys_msync(td, &msa); + } + case SVR4_MC_ADVISE: + { + struct madvise_args maa; + + maa.addr = uap->addr; + maa.len = uap->len; + maa.behav = (int)uap->arg; + + return sys_madvise(td, &maa); + } + case SVR4_MC_LOCK: + case SVR4_MC_UNLOCK: + case SVR4_MC_LOCKAS: + case SVR4_MC_UNLOCKAS: + return EOPNOTSUPP; + default: + return ENOSYS; + } +} + + +int +svr4_sys_nice(td, uap) + struct thread *td; + struct svr4_sys_nice_args *uap; +{ + struct setpriority_args ap; + int error; + + ap.which = PRIO_PROCESS; + ap.who = 0; + ap.prio = uap->prio; + + if ((error = sys_setpriority(td, &ap)) != 0) + return error; + + /* the cast is stupid, but the structures are the same */ + if ((error = sys_getpriority(td, (struct getpriority_args *)&ap)) != 0) + return error; + + return 0; +} + +int +svr4_sys_resolvepath(td, uap) + struct thread *td; + struct svr4_sys_resolvepath_args *uap; +{ + struct nameidata nd; + int error, *retval = td->td_retval; + unsigned int ncopy; + + NDINIT(&nd, LOOKUP, NOFOLLOW | SAVENAME, UIO_USERSPACE, + uap->path, td); + + if ((error = namei(&nd)) != 0) + return (error); + NDFREE(&nd, NDF_NO_FREE_PNBUF); + + ncopy = min(uap->bufsiz, strlen(nd.ni_cnd.cn_pnbuf) + 1); + if ((error = copyout(nd.ni_cnd.cn_pnbuf, uap->buf, ncopy)) != 0) + goto bad; + + *retval = ncopy; +bad: + NDFREE(&nd, NDF_ONLY_PNBUF); + return error; +} diff --git a/sys/compat/svr4/svr4_mman.h b/sys/compat/svr4/svr4_mman.h new file mode 100644 index 0000000..e30e492 --- /dev/null +++ b/sys/compat/svr4/svr4_mman.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1997 Todd Vierling + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_MMAN_H_ +#define _SVR4_MMAN_H_ + +/* + * Commands and flags passed to memcntl(). + * Most of them are the same as <sys/mman.h>, but we need the MC_ + * memcntl command definitions. + */ + +#define SVR4_MC_SYNC 1 +#define SVR4_MC_LOCK 2 +#define SVR4_MC_UNLOCK 3 +#define SVR4_MC_ADVISE 4 +#define SVR4_MC_LOCKAS 5 +#define SVR4_MC_UNLOCKAS 6 + +#endif /* !_SVR4_MMAN_H */ diff --git a/sys/compat/svr4/svr4_proto.h b/sys/compat/svr4/svr4_proto.h new file mode 100644 index 0000000..0478d3c --- /dev/null +++ b/sys/compat/svr4/svr4_proto.h @@ -0,0 +1,596 @@ +/* + * System call prototypes. + * + * DO NOT EDIT-- this file is automatically generated. + * $FreeBSD$ + * created from FreeBSD: head/sys/compat/svr4/syscalls.master 227691 2011-11-19 06:35:15Z ed + */ + +#ifndef _SVR4_SYSPROTO_H_ +#define _SVR4_SYSPROTO_H_ + +#include <sys/signal.h> +#include <sys/acl.h> +#include <sys/cpuset.h> +#include <sys/_semaphore.h> +#include <sys/ucontext.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 svr4_sys_open_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; + char mode_l_[PADL_(int)]; int mode; char mode_r_[PADR_(int)]; +}; +struct svr4_sys_wait_args { + char status_l_[PADL_(int *)]; int * status; char status_r_[PADR_(int *)]; +}; +struct svr4_sys_creat_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char mode_l_[PADL_(int)]; int mode; char mode_r_[PADR_(int)]; +}; +struct svr4_sys_execv_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char argp_l_[PADL_(char **)]; char ** argp; char argp_r_[PADR_(char **)]; +}; +struct svr4_sys_time_args { + char t_l_[PADL_(time_t *)]; time_t * t; char t_r_[PADR_(time_t *)]; +}; +struct svr4_sys_mknod_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char mode_l_[PADL_(int)]; int mode; char mode_r_[PADR_(int)]; + char dev_l_[PADL_(int)]; int dev; char dev_r_[PADR_(int)]; +}; +struct svr4_sys_break_args { + char nsize_l_[PADL_(caddr_t)]; caddr_t nsize; char nsize_r_[PADR_(caddr_t)]; +}; +struct svr4_sys_stat_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char ub_l_[PADL_(struct svr4_stat *)]; struct svr4_stat * ub; char ub_r_[PADR_(struct svr4_stat *)]; +}; +struct svr4_sys_alarm_args { + char sec_l_[PADL_(unsigned)]; unsigned sec; char sec_r_[PADR_(unsigned)]; +}; +struct svr4_sys_fstat_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char sb_l_[PADL_(struct svr4_stat *)]; struct svr4_stat * sb; char sb_r_[PADR_(struct svr4_stat *)]; +}; +struct svr4_sys_pause_args { + register_t dummy; +}; +struct svr4_sys_utime_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char ubuf_l_[PADL_(struct svr4_utimbuf *)]; struct svr4_utimbuf * ubuf; char ubuf_r_[PADR_(struct svr4_utimbuf *)]; +}; +struct svr4_sys_access_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char amode_l_[PADL_(int)]; int amode; char amode_r_[PADR_(int)]; +}; +struct svr4_sys_nice_args { + char prio_l_[PADL_(int)]; int prio; char prio_r_[PADR_(int)]; +}; +struct svr4_sys_kill_args { + char pid_l_[PADL_(int)]; int pid; char pid_r_[PADR_(int)]; + char signum_l_[PADL_(int)]; int signum; char signum_r_[PADR_(int)]; +}; +struct svr4_sys_pgrpsys_args { + char cmd_l_[PADL_(int)]; int cmd; char cmd_r_[PADR_(int)]; + char pid_l_[PADL_(int)]; int pid; char pid_r_[PADR_(int)]; + char pgid_l_[PADL_(int)]; int pgid; char pgid_r_[PADR_(int)]; +}; +struct svr4_sys_times_args { + char tp_l_[PADL_(struct tms *)]; struct tms * tp; char tp_r_[PADR_(struct tms *)]; +}; +struct svr4_sys_signal_args { + char signum_l_[PADL_(int)]; int signum; char signum_r_[PADR_(int)]; + char handler_l_[PADL_(svr4_sig_t)]; svr4_sig_t handler; char handler_r_[PADR_(svr4_sig_t)]; +}; +struct svr4_sys_msgsys_args { + char what_l_[PADL_(int)]; int what; char what_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 svr4_sys_sysarch_args { + char op_l_[PADL_(int)]; int op; char op_r_[PADR_(int)]; + char a1_l_[PADL_(void *)]; void * a1; char a1_r_[PADR_(void *)]; +}; +struct svr4_sys_shmsys_args { + char what_l_[PADL_(int)]; int what; char what_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 svr4_sys_semsys_args { + char what_l_[PADL_(int)]; int what; char what_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 svr4_sys_ioctl_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char com_l_[PADL_(u_long)]; u_long com; char com_r_[PADR_(u_long)]; + char data_l_[PADL_(caddr_t)]; caddr_t data; char data_r_[PADR_(caddr_t)]; +}; +struct svr4_sys_utssys_args { + char a1_l_[PADL_(void *)]; void * a1; char a1_r_[PADR_(void *)]; + char a2_l_[PADL_(void *)]; void * a2; char a2_r_[PADR_(void *)]; + char sel_l_[PADL_(int)]; int sel; char sel_r_[PADR_(int)]; + char a3_l_[PADL_(void *)]; void * a3; char a3_r_[PADR_(void *)]; +}; +struct svr4_sys_execve_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char argp_l_[PADL_(char **)]; char ** argp; char argp_r_[PADR_(char **)]; + char envp_l_[PADL_(char **)]; char ** envp; char envp_r_[PADR_(char **)]; +}; +struct svr4_sys_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_(char *)]; char * arg; char arg_r_[PADR_(char *)]; +}; +struct svr4_sys_ulimit_args { + char cmd_l_[PADL_(int)]; int cmd; char cmd_r_[PADR_(int)]; + char newlimit_l_[PADL_(long)]; long newlimit; char newlimit_r_[PADR_(long)]; +}; +struct svr4_sys_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 nbytes_l_[PADL_(int)]; int nbytes; char nbytes_r_[PADR_(int)]; +}; +struct svr4_sys_getmsg_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char ctl_l_[PADL_(struct svr4_strbuf *)]; struct svr4_strbuf * ctl; char ctl_r_[PADR_(struct svr4_strbuf *)]; + char dat_l_[PADL_(struct svr4_strbuf *)]; struct svr4_strbuf * dat; char dat_r_[PADR_(struct svr4_strbuf *)]; + char flags_l_[PADL_(int *)]; int * flags; char flags_r_[PADR_(int *)]; +}; +struct svr4_sys_putmsg_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char ctl_l_[PADL_(struct svr4_strbuf *)]; struct svr4_strbuf * ctl; char ctl_r_[PADR_(struct svr4_strbuf *)]; + char dat_l_[PADL_(struct svr4_strbuf *)]; struct svr4_strbuf * dat; char dat_r_[PADR_(struct svr4_strbuf *)]; + char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; +}; +struct svr4_sys_poll_args { + char fds_l_[PADL_(struct pollfd *)]; struct pollfd * fds; char fds_r_[PADR_(struct pollfd *)]; + char nfds_l_[PADL_(unsigned int)]; unsigned int nfds; char nfds_r_[PADR_(unsigned int)]; + char timeout_l_[PADL_(int)]; int timeout; char timeout_r_[PADR_(int)]; +}; +struct svr4_sys_lstat_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char ub_l_[PADL_(struct svr4_stat *)]; struct svr4_stat * ub; char ub_r_[PADR_(struct svr4_stat *)]; +}; +struct svr4_sys_sigprocmask_args { + char how_l_[PADL_(int)]; int how; char how_r_[PADR_(int)]; + char set_l_[PADL_(svr4_sigset_t *)]; svr4_sigset_t * set; char set_r_[PADR_(svr4_sigset_t *)]; + char oset_l_[PADL_(svr4_sigset_t *)]; svr4_sigset_t * oset; char oset_r_[PADR_(svr4_sigset_t *)]; +}; +struct svr4_sys_sigsuspend_args { + char ss_l_[PADL_(svr4_sigset_t *)]; svr4_sigset_t * ss; char ss_r_[PADR_(svr4_sigset_t *)]; +}; +struct svr4_sys_sigaltstack_args { + char nss_l_[PADL_(struct svr4_sigaltstack *)]; struct svr4_sigaltstack * nss; char nss_r_[PADR_(struct svr4_sigaltstack *)]; + char oss_l_[PADL_(struct svr4_sigaltstack *)]; struct svr4_sigaltstack * oss; char oss_r_[PADR_(struct svr4_sigaltstack *)]; +}; +struct svr4_sys_sigaction_args { + char signum_l_[PADL_(int)]; int signum; char signum_r_[PADR_(int)]; + char nsa_l_[PADL_(struct svr4_sigaction *)]; struct svr4_sigaction * nsa; char nsa_r_[PADR_(struct svr4_sigaction *)]; + char osa_l_[PADL_(struct svr4_sigaction *)]; struct svr4_sigaction * osa; char osa_r_[PADR_(struct svr4_sigaction *)]; +}; +struct svr4_sys_sigpending_args { + char what_l_[PADL_(int)]; int what; char what_r_[PADR_(int)]; + char mask_l_[PADL_(svr4_sigset_t *)]; svr4_sigset_t * mask; char mask_r_[PADR_(svr4_sigset_t *)]; +}; +struct svr4_sys_context_args { + char func_l_[PADL_(int)]; int func; char func_r_[PADR_(int)]; + char uc_l_[PADL_(struct svr4_ucontext *)]; struct svr4_ucontext * uc; char uc_r_[PADR_(struct svr4_ucontext *)]; +}; +struct svr4_sys_statvfs_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char fs_l_[PADL_(struct svr4_statvfs *)]; struct svr4_statvfs * fs; char fs_r_[PADR_(struct svr4_statvfs *)]; +}; +struct svr4_sys_fstatvfs_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char fs_l_[PADL_(struct svr4_statvfs *)]; struct svr4_statvfs * fs; char fs_r_[PADR_(struct svr4_statvfs *)]; +}; +struct svr4_sys_waitsys_args { + char grp_l_[PADL_(int)]; int grp; char grp_r_[PADR_(int)]; + char id_l_[PADL_(int)]; int id; char id_r_[PADR_(int)]; + char info_l_[PADL_(union svr4_siginfo *)]; union svr4_siginfo * info; char info_r_[PADR_(union svr4_siginfo *)]; + char options_l_[PADL_(int)]; int options; char options_r_[PADR_(int)]; +}; +struct svr4_sys_hrtsys_args { + char cmd_l_[PADL_(int)]; int cmd; char cmd_r_[PADR_(int)]; + char fun_l_[PADL_(int)]; int fun; char fun_r_[PADR_(int)]; + char sub_l_[PADL_(int)]; int sub; char sub_r_[PADR_(int)]; + char rv1_l_[PADL_(void *)]; void * rv1; char rv1_r_[PADR_(void *)]; + char rv2_l_[PADL_(void *)]; void * rv2; char rv2_r_[PADR_(void *)]; +}; +struct svr4_sys_pathconf_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char name_l_[PADL_(int)]; int name; char name_r_[PADR_(int)]; +}; +struct svr4_sys_mmap_args { + char addr_l_[PADL_(caddr_t)]; caddr_t addr; char addr_r_[PADR_(caddr_t)]; + char len_l_[PADL_(svr4_size_t)]; svr4_size_t len; char len_r_[PADR_(svr4_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 pos_l_[PADL_(svr4_off_t)]; svr4_off_t pos; char pos_r_[PADR_(svr4_off_t)]; +}; +struct svr4_sys_fpathconf_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char name_l_[PADL_(int)]; int name; char name_r_[PADR_(int)]; +}; +struct svr4_sys_xstat_args { + char two_l_[PADL_(int)]; int two; char two_r_[PADR_(int)]; + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char ub_l_[PADL_(struct svr4_xstat *)]; struct svr4_xstat * ub; char ub_r_[PADR_(struct svr4_xstat *)]; +}; +struct svr4_sys_lxstat_args { + char two_l_[PADL_(int)]; int two; char two_r_[PADR_(int)]; + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char ub_l_[PADL_(struct svr4_xstat *)]; struct svr4_xstat * ub; char ub_r_[PADR_(struct svr4_xstat *)]; +}; +struct svr4_sys_fxstat_args { + char two_l_[PADL_(int)]; int two; char two_r_[PADR_(int)]; + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char sb_l_[PADL_(struct svr4_xstat *)]; struct svr4_xstat * sb; char sb_r_[PADR_(struct svr4_xstat *)]; +}; +struct svr4_sys_xmknod_args { + char two_l_[PADL_(int)]; int two; char two_r_[PADR_(int)]; + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char mode_l_[PADL_(svr4_mode_t)]; svr4_mode_t mode; char mode_r_[PADR_(svr4_mode_t)]; + char dev_l_[PADL_(svr4_dev_t)]; svr4_dev_t dev; char dev_r_[PADR_(svr4_dev_t)]; +}; +struct svr4_sys_setrlimit_args { + char which_l_[PADL_(int)]; int which; char which_r_[PADR_(int)]; + char rlp_l_[PADL_(const struct svr4_rlimit *)]; const struct svr4_rlimit * rlp; char rlp_r_[PADR_(const struct svr4_rlimit *)]; +}; +struct svr4_sys_getrlimit_args { + char which_l_[PADL_(int)]; int which; char which_r_[PADR_(int)]; + char rlp_l_[PADL_(struct svr4_rlimit *)]; struct svr4_rlimit * rlp; char rlp_r_[PADR_(struct svr4_rlimit *)]; +}; +struct svr4_sys_memcntl_args { + char addr_l_[PADL_(void *)]; void * addr; char addr_r_[PADR_(void *)]; + char len_l_[PADL_(svr4_size_t)]; svr4_size_t len; char len_r_[PADR_(svr4_size_t)]; + char cmd_l_[PADL_(int)]; int cmd; char cmd_r_[PADR_(int)]; + char arg_l_[PADL_(void *)]; void * arg; char arg_r_[PADR_(void *)]; + char attr_l_[PADL_(int)]; int attr; char attr_r_[PADR_(int)]; + char mask_l_[PADL_(int)]; int mask; char mask_r_[PADR_(int)]; +}; +struct svr4_sys_uname_args { + char name_l_[PADL_(struct svr4_utsname *)]; struct svr4_utsname * name; char name_r_[PADR_(struct svr4_utsname *)]; + char dummy_l_[PADL_(int)]; int dummy; char dummy_r_[PADR_(int)]; +}; +struct svr4_sys_sysconfig_args { + char name_l_[PADL_(int)]; int name; char name_r_[PADR_(int)]; +}; +struct svr4_sys_systeminfo_args { + char what_l_[PADL_(int)]; int what; char what_r_[PADR_(int)]; + char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; + char len_l_[PADL_(long)]; long len; char len_r_[PADR_(long)]; +}; +struct svr4_sys_fchroot_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; +}; +struct svr4_sys_utimes_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char tptr_l_[PADL_(struct timeval *)]; struct timeval * tptr; char tptr_r_[PADR_(struct timeval *)]; +}; +struct svr4_sys_vhangup_args { + register_t dummy; +}; +struct svr4_sys_gettimeofday_args { + char tp_l_[PADL_(struct timeval *)]; struct timeval * tp; char tp_r_[PADR_(struct timeval *)]; +}; +struct svr4_sys_llseek_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char offset1_l_[PADL_(long)]; long offset1; char offset1_r_[PADR_(long)]; + char offset2_l_[PADL_(long)]; long offset2; char offset2_r_[PADR_(long)]; + char whence_l_[PADL_(int)]; int whence; char whence_r_[PADR_(int)]; +}; +struct svr4_sys_acl_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char cmd_l_[PADL_(int)]; int cmd; char cmd_r_[PADR_(int)]; + char num_l_[PADL_(int)]; int num; char num_r_[PADR_(int)]; + char buf_l_[PADL_(struct svr4_aclent *)]; struct svr4_aclent * buf; char buf_r_[PADR_(struct svr4_aclent *)]; +}; +struct svr4_sys_auditsys_args { + char code_l_[PADL_(int)]; int code; char code_r_[PADR_(int)]; + char a1_l_[PADL_(int)]; int a1; char a1_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 svr4_sys_facl_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 num_l_[PADL_(int)]; int num; char num_r_[PADR_(int)]; + char buf_l_[PADL_(struct svr4_aclent *)]; struct svr4_aclent * buf; char buf_r_[PADR_(struct svr4_aclent *)]; +}; +struct svr4_sys_resolvepath_args { + char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; + char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; + char bufsiz_l_[PADL_(size_t)]; size_t bufsiz; char bufsiz_r_[PADR_(size_t)]; +}; +struct svr4_sys_getdents64_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char dp_l_[PADL_(struct svr4_dirent64 *)]; struct svr4_dirent64 * dp; char dp_r_[PADR_(struct svr4_dirent64 *)]; + char nbytes_l_[PADL_(int)]; int nbytes; char nbytes_r_[PADR_(int)]; +}; +struct svr4_sys_mmap64_args { + char addr_l_[PADL_(void *)]; void * addr; char addr_r_[PADR_(void *)]; + char len_l_[PADL_(svr4_size_t)]; svr4_size_t len; char len_r_[PADR_(svr4_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 pos_l_[PADL_(svr4_off64_t)]; svr4_off64_t pos; char pos_r_[PADR_(svr4_off64_t)]; +}; +struct svr4_sys_stat64_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char sb_l_[PADL_(struct svr4_stat64 *)]; struct svr4_stat64 * sb; char sb_r_[PADR_(struct svr4_stat64 *)]; +}; +struct svr4_sys_lstat64_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char sb_l_[PADL_(struct svr4_stat64 *)]; struct svr4_stat64 * sb; char sb_r_[PADR_(struct svr4_stat64 *)]; +}; +struct svr4_sys_fstat64_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char sb_l_[PADL_(struct svr4_stat64 *)]; struct svr4_stat64 * sb; char sb_r_[PADR_(struct svr4_stat64 *)]; +}; +struct svr4_sys_statvfs64_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char fs_l_[PADL_(struct svr4_statvfs64 *)]; struct svr4_statvfs64 * fs; char fs_r_[PADR_(struct svr4_statvfs64 *)]; +}; +struct svr4_sys_fstatvfs64_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char fs_l_[PADL_(struct svr4_statvfs64 *)]; struct svr4_statvfs64 * fs; char fs_r_[PADR_(struct svr4_statvfs64 *)]; +}; +struct svr4_sys_setrlimit64_args { + char which_l_[PADL_(int)]; int which; char which_r_[PADR_(int)]; + char rlp_l_[PADL_(const struct svr4_rlimit64 *)]; const struct svr4_rlimit64 * rlp; char rlp_r_[PADR_(const struct svr4_rlimit64 *)]; +}; +struct svr4_sys_getrlimit64_args { + char which_l_[PADL_(int)]; int which; char which_r_[PADR_(int)]; + char rlp_l_[PADL_(struct svr4_rlimit64 *)]; struct svr4_rlimit64 * rlp; char rlp_r_[PADR_(struct svr4_rlimit64 *)]; +}; +struct svr4_sys_creat64_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char mode_l_[PADL_(int)]; int mode; char mode_r_[PADR_(int)]; +}; +struct svr4_sys_open64_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; + char mode_l_[PADL_(int)]; int mode; char mode_r_[PADR_(int)]; +}; +struct svr4_sys_socket_args { + char domain_l_[PADL_(int)]; int domain; char domain_r_[PADR_(int)]; + char type_l_[PADL_(int)]; int type; char type_r_[PADR_(int)]; + char protocol_l_[PADL_(int)]; int protocol; char protocol_r_[PADR_(int)]; +}; +struct svr4_sys_recv_args { + char s_l_[PADL_(int)]; int s; char s_r_[PADR_(int)]; + char buf_l_[PADL_(caddr_t)]; caddr_t buf; char buf_r_[PADR_(caddr_t)]; + char len_l_[PADL_(int)]; int len; char len_r_[PADR_(int)]; + char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; +}; +struct svr4_sys_send_args { + char s_l_[PADL_(int)]; int s; char s_r_[PADR_(int)]; + char buf_l_[PADL_(caddr_t)]; caddr_t buf; char buf_r_[PADR_(caddr_t)]; + char len_l_[PADL_(int)]; int len; char len_r_[PADR_(int)]; + char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; +}; +struct svr4_sys_sendto_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_(size_t)]; size_t len; char len_r_[PADR_(size_t)]; + char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; + char to_l_[PADL_(struct sockaddr *)]; struct sockaddr * to; char to_r_[PADR_(struct sockaddr *)]; + char tolen_l_[PADL_(int)]; int tolen; char tolen_r_[PADR_(int)]; +}; +int svr4_sys_open(struct thread *, struct svr4_sys_open_args *); +int svr4_sys_wait(struct thread *, struct svr4_sys_wait_args *); +int svr4_sys_creat(struct thread *, struct svr4_sys_creat_args *); +int svr4_sys_execv(struct thread *, struct svr4_sys_execv_args *); +int svr4_sys_time(struct thread *, struct svr4_sys_time_args *); +int svr4_sys_mknod(struct thread *, struct svr4_sys_mknod_args *); +int svr4_sys_break(struct thread *, struct svr4_sys_break_args *); +int svr4_sys_stat(struct thread *, struct svr4_sys_stat_args *); +int svr4_sys_alarm(struct thread *, struct svr4_sys_alarm_args *); +int svr4_sys_fstat(struct thread *, struct svr4_sys_fstat_args *); +int svr4_sys_pause(struct thread *, struct svr4_sys_pause_args *); +int svr4_sys_utime(struct thread *, struct svr4_sys_utime_args *); +int svr4_sys_access(struct thread *, struct svr4_sys_access_args *); +int svr4_sys_nice(struct thread *, struct svr4_sys_nice_args *); +int svr4_sys_kill(struct thread *, struct svr4_sys_kill_args *); +int svr4_sys_pgrpsys(struct thread *, struct svr4_sys_pgrpsys_args *); +int svr4_sys_times(struct thread *, struct svr4_sys_times_args *); +int svr4_sys_signal(struct thread *, struct svr4_sys_signal_args *); +int svr4_sys_msgsys(struct thread *, struct svr4_sys_msgsys_args *); +int svr4_sys_sysarch(struct thread *, struct svr4_sys_sysarch_args *); +int svr4_sys_shmsys(struct thread *, struct svr4_sys_shmsys_args *); +int svr4_sys_semsys(struct thread *, struct svr4_sys_semsys_args *); +int svr4_sys_ioctl(struct thread *, struct svr4_sys_ioctl_args *); +int svr4_sys_utssys(struct thread *, struct svr4_sys_utssys_args *); +int svr4_sys_execve(struct thread *, struct svr4_sys_execve_args *); +int svr4_sys_fcntl(struct thread *, struct svr4_sys_fcntl_args *); +int svr4_sys_ulimit(struct thread *, struct svr4_sys_ulimit_args *); +int svr4_sys_getdents(struct thread *, struct svr4_sys_getdents_args *); +int svr4_sys_getmsg(struct thread *, struct svr4_sys_getmsg_args *); +int svr4_sys_putmsg(struct thread *, struct svr4_sys_putmsg_args *); +int svr4_sys_poll(struct thread *, struct svr4_sys_poll_args *); +int svr4_sys_lstat(struct thread *, struct svr4_sys_lstat_args *); +int svr4_sys_sigprocmask(struct thread *, struct svr4_sys_sigprocmask_args *); +int svr4_sys_sigsuspend(struct thread *, struct svr4_sys_sigsuspend_args *); +int svr4_sys_sigaltstack(struct thread *, struct svr4_sys_sigaltstack_args *); +int svr4_sys_sigaction(struct thread *, struct svr4_sys_sigaction_args *); +int svr4_sys_sigpending(struct thread *, struct svr4_sys_sigpending_args *); +int svr4_sys_context(struct thread *, struct svr4_sys_context_args *); +int svr4_sys_statvfs(struct thread *, struct svr4_sys_statvfs_args *); +int svr4_sys_fstatvfs(struct thread *, struct svr4_sys_fstatvfs_args *); +int svr4_sys_waitsys(struct thread *, struct svr4_sys_waitsys_args *); +int svr4_sys_hrtsys(struct thread *, struct svr4_sys_hrtsys_args *); +int svr4_sys_pathconf(struct thread *, struct svr4_sys_pathconf_args *); +int svr4_sys_mmap(struct thread *, struct svr4_sys_mmap_args *); +int svr4_sys_fpathconf(struct thread *, struct svr4_sys_fpathconf_args *); +int svr4_sys_xstat(struct thread *, struct svr4_sys_xstat_args *); +int svr4_sys_lxstat(struct thread *, struct svr4_sys_lxstat_args *); +int svr4_sys_fxstat(struct thread *, struct svr4_sys_fxstat_args *); +int svr4_sys_xmknod(struct thread *, struct svr4_sys_xmknod_args *); +int svr4_sys_setrlimit(struct thread *, struct svr4_sys_setrlimit_args *); +int svr4_sys_getrlimit(struct thread *, struct svr4_sys_getrlimit_args *); +int svr4_sys_memcntl(struct thread *, struct svr4_sys_memcntl_args *); +int svr4_sys_uname(struct thread *, struct svr4_sys_uname_args *); +int svr4_sys_sysconfig(struct thread *, struct svr4_sys_sysconfig_args *); +int svr4_sys_systeminfo(struct thread *, struct svr4_sys_systeminfo_args *); +int svr4_sys_fchroot(struct thread *, struct svr4_sys_fchroot_args *); +int svr4_sys_utimes(struct thread *, struct svr4_sys_utimes_args *); +int svr4_sys_vhangup(struct thread *, struct svr4_sys_vhangup_args *); +int svr4_sys_gettimeofday(struct thread *, struct svr4_sys_gettimeofday_args *); +int svr4_sys_llseek(struct thread *, struct svr4_sys_llseek_args *); +int svr4_sys_acl(struct thread *, struct svr4_sys_acl_args *); +int svr4_sys_auditsys(struct thread *, struct svr4_sys_auditsys_args *); +int svr4_sys_facl(struct thread *, struct svr4_sys_facl_args *); +int svr4_sys_resolvepath(struct thread *, struct svr4_sys_resolvepath_args *); +int svr4_sys_getdents64(struct thread *, struct svr4_sys_getdents64_args *); +int svr4_sys_mmap64(struct thread *, struct svr4_sys_mmap64_args *); +int svr4_sys_stat64(struct thread *, struct svr4_sys_stat64_args *); +int svr4_sys_lstat64(struct thread *, struct svr4_sys_lstat64_args *); +int svr4_sys_fstat64(struct thread *, struct svr4_sys_fstat64_args *); +int svr4_sys_statvfs64(struct thread *, struct svr4_sys_statvfs64_args *); +int svr4_sys_fstatvfs64(struct thread *, struct svr4_sys_fstatvfs64_args *); +int svr4_sys_setrlimit64(struct thread *, struct svr4_sys_setrlimit64_args *); +int svr4_sys_getrlimit64(struct thread *, struct svr4_sys_getrlimit64_args *); +int svr4_sys_creat64(struct thread *, struct svr4_sys_creat64_args *); +int svr4_sys_open64(struct thread *, struct svr4_sys_open64_args *); +int svr4_sys_socket(struct thread *, struct svr4_sys_socket_args *); +int svr4_sys_recv(struct thread *, struct svr4_sys_recv_args *); +int svr4_sys_send(struct thread *, struct svr4_sys_send_args *); +int svr4_sys_sendto(struct thread *, struct svr4_sys_sendto_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 */ + +#define SVR4_SYS_AUE_svr4_sys_open AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_wait AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_creat AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_execv AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_time AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_mknod AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_break AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_stat AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_alarm AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_fstat AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_pause AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_utime AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_access AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_nice AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_kill AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_pgrpsys AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_times AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_signal AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_msgsys AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_sysarch AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_shmsys AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_semsys AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_ioctl AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_utssys AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_execve AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_fcntl AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_ulimit AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_getdents AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_getmsg AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_putmsg AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_poll AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_lstat AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_sigprocmask AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_sigsuspend AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_sigaltstack AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_sigaction AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_sigpending AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_context AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_statvfs AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_fstatvfs AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_waitsys AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_hrtsys AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_pathconf AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_mmap AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_fpathconf AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_xstat AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_lxstat AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_fxstat AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_xmknod AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_setrlimit AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_getrlimit AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_memcntl AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_uname AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_sysconfig AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_systeminfo AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_fchroot AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_utimes AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_vhangup AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_gettimeofday AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_llseek AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_acl AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_auditsys AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_facl AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_resolvepath AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_getdents64 AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_mmap64 AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_stat64 AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_lstat64 AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_fstat64 AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_statvfs64 AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_fstatvfs64 AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_setrlimit64 AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_getrlimit64 AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_creat64 AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_open64 AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_socket AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_recv AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_send AUE_NULL +#define SVR4_SYS_AUE_svr4_sys_sendto AUE_NULL + +#undef PAD_ +#undef PADL_ +#undef PADR_ + +#endif /* !_SVR4_SYSPROTO_H_ */ diff --git a/sys/compat/svr4/svr4_resource.c b/sys/compat/svr4/svr4_resource.c new file mode 100644 index 0000000..7dd692a --- /dev/null +++ b/sys/compat/svr4/svr4_resource.c @@ -0,0 +1,321 @@ +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 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. + */ +/*- + * Portions of this software have been derived from software contributed + * to the FreeBSD Project by Mark Newton. + * + * Copyright (c) 1999 Mark Newton + * 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. + * + * Derived from: $NetBSD: svr4_resource.c,v 1.3 1998/12/13 18:00:52 christos Exp $ + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/file.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/proc.h> +#include <sys/resource.h> +#include <sys/resourcevar.h> +#include <sys/syscallsubr.h> + +#include <compat/svr4/svr4.h> +#include <compat/svr4/svr4_types.h> +#include <compat/svr4/svr4_resource.h> +#include <compat/svr4/svr4_signal.h> +#include <compat/svr4/svr4_proto.h> +#include <compat/svr4/svr4_util.h> + +static __inline int svr4_to_native_rl(int); + +static __inline int +svr4_to_native_rl(rl) + int rl; +{ + switch (rl) { + case SVR4_RLIMIT_CPU: + return RLIMIT_CPU; + case SVR4_RLIMIT_FSIZE: + return RLIMIT_FSIZE; + case SVR4_RLIMIT_DATA: + return RLIMIT_DATA; + case SVR4_RLIMIT_STACK: + return RLIMIT_STACK; + case SVR4_RLIMIT_CORE: + return RLIMIT_CORE; + case SVR4_RLIMIT_NOFILE: + return RLIMIT_NOFILE; + case SVR4_RLIMIT_VMEM: + return RLIMIT_VMEM; + default: + return -1; + } +} + +/* + * Check if the resource limit fits within the BSD range and it is not + * one of the magic SVR4 limit values + */ +#define OKLIMIT(l) (((int32_t)(l)) >= 0 && ((int32_t)(l)) < 0x7fffffff && \ + ((svr4_rlim_t)(l)) != SVR4_RLIM_INFINITY && \ + ((svr4_rlim_t)(l)) != SVR4_RLIM_SAVED_CUR && \ + ((svr4_rlim_t)(l)) != SVR4_RLIM_SAVED_MAX) + +#define OKLIMIT64(l) (((rlim_t)(l)) >= 0 && ((rlim_t)(l)) < RLIM_INFINITY && \ + ((svr4_rlim64_t)(l)) != SVR4_RLIM64_INFINITY && \ + ((svr4_rlim64_t)(l)) != SVR4_RLIM64_SAVED_CUR && \ + ((svr4_rlim64_t)(l)) != SVR4_RLIM64_SAVED_MAX) + +int +svr4_sys_getrlimit(td, uap) + struct thread *td; + struct svr4_sys_getrlimit_args *uap; +{ + int rl = svr4_to_native_rl(uap->which); + struct rlimit blim; + struct svr4_rlimit slim; + + if (rl == -1) + return EINVAL; + + PROC_LOCK(td->td_proc); + lim_rlimit(td->td_proc, rl, &blim); + PROC_UNLOCK(td->td_proc); + + /* + * Our infinity, is their maxfiles. + */ + if (rl == RLIMIT_NOFILE && blim.rlim_max == RLIM_INFINITY) + blim.rlim_max = maxfiles; + + /* + * If the limit can be be represented, it is returned. + * Otherwise, if rlim_cur == rlim_max, return RLIM_SAVED_MAX + * else return RLIM_SAVED_CUR + */ + if (blim.rlim_max == RLIM_INFINITY) + slim.rlim_max = SVR4_RLIM_INFINITY; + else if (OKLIMIT(blim.rlim_max)) + slim.rlim_max = (svr4_rlim_t) blim.rlim_max; + else + slim.rlim_max = SVR4_RLIM_SAVED_MAX; + + if (blim.rlim_cur == RLIM_INFINITY) + slim.rlim_cur = SVR4_RLIM_INFINITY; + else if (OKLIMIT(blim.rlim_cur)) + slim.rlim_cur = (svr4_rlim_t) blim.rlim_cur; + else if (blim.rlim_max == blim.rlim_cur) + slim.rlim_cur = SVR4_RLIM_SAVED_MAX; + else + slim.rlim_cur = SVR4_RLIM_SAVED_CUR; + + return copyout(&slim, uap->rlp, sizeof(*uap->rlp)); +} + + +int +svr4_sys_setrlimit(td, uap) + struct thread *td; + struct svr4_sys_setrlimit_args *uap; +{ + int rl = svr4_to_native_rl(uap->which); + struct rlimit blim, curlim; + struct svr4_rlimit slim; + int error; + + if (rl == -1) + return EINVAL; + + if ((error = copyin(uap->rlp, &slim, sizeof(slim))) != 0) + return error; + + PROC_LOCK(td->td_proc); + lim_rlimit(td->td_proc, rl, &curlim); + PROC_UNLOCK(td->td_proc); + + /* + * if the limit is SVR4_RLIM_INFINITY, then we set it to our + * unlimited. + * We should also: If it is SVR4_RLIM_SAVED_MAX, we should set the + * new limit to the corresponding saved hard limit, and if + * it is equal to SVR4_RLIM_SAVED_CUR, we should set it to the + * corresponding saved soft limit. + * + */ + if (slim.rlim_max == SVR4_RLIM_INFINITY) + blim.rlim_max = RLIM_INFINITY; + else if (OKLIMIT(slim.rlim_max)) + blim.rlim_max = (rlim_t) slim.rlim_max; + else if (slim.rlim_max == SVR4_RLIM_SAVED_MAX) + blim.rlim_max = curlim.rlim_max; + else if (slim.rlim_max == SVR4_RLIM_SAVED_CUR) + blim.rlim_max = curlim.rlim_cur; + + if (slim.rlim_cur == SVR4_RLIM_INFINITY) + blim.rlim_cur = RLIM_INFINITY; + else if (OKLIMIT(slim.rlim_cur)) + blim.rlim_cur = (rlim_t) slim.rlim_cur; + else if (slim.rlim_cur == SVR4_RLIM_SAVED_MAX) + blim.rlim_cur = curlim.rlim_max; + else if (slim.rlim_cur == SVR4_RLIM_SAVED_CUR) + blim.rlim_cur = curlim.rlim_cur; + + return (kern_setrlimit(td, rl, &blim)); +} + + +int +svr4_sys_getrlimit64(td, uap) + struct thread *td; + struct svr4_sys_getrlimit64_args *uap; +{ + int rl = svr4_to_native_rl(uap->which); + struct rlimit blim; + struct svr4_rlimit64 slim; + + if (rl == -1) + return EINVAL; + + PROC_LOCK(td->td_proc); + lim_rlimit(td->td_proc, rl, &blim); + PROC_UNLOCK(td->td_proc); + + /* + * Our infinity, is their maxfiles. + */ + if (rl == RLIMIT_NOFILE && blim.rlim_max == RLIM_INFINITY) + blim.rlim_max = maxfiles; + + /* + * If the limit can be be represented, it is returned. + * Otherwise, if rlim_cur == rlim_max, return SVR4_RLIM_SAVED_MAX + * else return SVR4_RLIM_SAVED_CUR + */ + if (blim.rlim_max == RLIM_INFINITY) + slim.rlim_max = SVR4_RLIM64_INFINITY; + else if (OKLIMIT64(blim.rlim_max)) + slim.rlim_max = (svr4_rlim64_t) blim.rlim_max; + else + slim.rlim_max = SVR4_RLIM64_SAVED_MAX; + + if (blim.rlim_cur == RLIM_INFINITY) + slim.rlim_cur = SVR4_RLIM64_INFINITY; + else if (OKLIMIT64(blim.rlim_cur)) + slim.rlim_cur = (svr4_rlim64_t) blim.rlim_cur; + else if (blim.rlim_max == blim.rlim_cur) + slim.rlim_cur = SVR4_RLIM64_SAVED_MAX; + else + slim.rlim_cur = SVR4_RLIM64_SAVED_CUR; + + return copyout(&slim, uap->rlp, sizeof(*uap->rlp)); +} + + +int +svr4_sys_setrlimit64(td, uap) + struct thread *td; + struct svr4_sys_setrlimit64_args *uap; +{ + int rl = svr4_to_native_rl(uap->which); + struct rlimit blim, curlim; + struct svr4_rlimit64 slim; + int error; + + if (rl == -1) + return EINVAL; + + if ((error = copyin(uap->rlp, &slim, sizeof(slim))) != 0) + return error; + + PROC_LOCK(td->td_proc); + lim_rlimit(td->td_proc, rl, &curlim); + PROC_UNLOCK(td->td_proc); + + /* + * if the limit is SVR4_RLIM64_INFINITY, then we set it to our + * unlimited. + * We should also: If it is SVR4_RLIM64_SAVED_MAX, we should set the + * new limit to the corresponding saved hard limit, and if + * it is equal to SVR4_RLIM64_SAVED_CUR, we should set it to the + * corresponding saved soft limit. + * + */ + if (slim.rlim_max == SVR4_RLIM64_INFINITY) + blim.rlim_max = RLIM_INFINITY; + else if (OKLIMIT64(slim.rlim_max)) + blim.rlim_max = (rlim_t) slim.rlim_max; + else if (slim.rlim_max == SVR4_RLIM64_SAVED_MAX) + blim.rlim_max = curlim.rlim_max; + else if (slim.rlim_max == SVR4_RLIM64_SAVED_CUR) + blim.rlim_max = curlim.rlim_cur; + + if (slim.rlim_cur == SVR4_RLIM64_INFINITY) + blim.rlim_cur = RLIM_INFINITY; + else if (OKLIMIT64(slim.rlim_cur)) + blim.rlim_cur = (rlim_t) slim.rlim_cur; + else if (slim.rlim_cur == SVR4_RLIM64_SAVED_MAX) + blim.rlim_cur = curlim.rlim_max; + else if (slim.rlim_cur == SVR4_RLIM64_SAVED_CUR) + blim.rlim_cur = curlim.rlim_cur; + + return (kern_setrlimit(td, rl, &blim)); +} diff --git a/sys/compat/svr4/svr4_resource.h b/sys/compat/svr4/svr4_resource.h new file mode 100644 index 0000000..4b93e9a --- /dev/null +++ b/sys/compat/svr4/svr4_resource.h @@ -0,0 +1,109 @@ +/* Derived from: + * $NetBSD: svr4_resource.h,v 1.1 1998/11/28 21:53:02 christos Exp $ */ + +/*- + * Original copyright: + * + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 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$ + */ + +/*- + * Portions of this code derived from software contributed to the + * FreeBSD Project by Mark Newton. + * + * Copyright (c) 1999 Mark Newton + * 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. + */ + +#ifndef _SVR4_RESOURCE_H_ +#define _SVR4_RESOURCE_H_ + +#define SVR4_RLIMIT_CPU 0 +#define SVR4_RLIMIT_FSIZE 1 +#define SVR4_RLIMIT_DATA 2 +#define SVR4_RLIMIT_STACK 3 +#define SVR4_RLIMIT_CORE 4 +#define SVR4_RLIMIT_NOFILE 5 +#define SVR4_RLIMIT_VMEM 6 +#define SVR4_RLIMIT_AS SVR4_RLIMIT_VMEM +#define SVR4_RLIM_NLIMITS 7 + +typedef u_int32_t svr4_rlim_t; + +#define SVR4_RLIM_SAVED_CUR 0x7ffffffd +#define SVR4_RLIM_SAVED_MAX 0x7ffffffe +#define SVR4_RLIM_INFINITY 0x7fffffff + +struct svr4_rlimit { + svr4_rlim_t rlim_cur; + svr4_rlim_t rlim_max; +}; + +typedef u_int64_t svr4_rlim64_t; + +#define SVR4_RLIM64_SAVED_CUR ((svr4_rlim64_t) -1) +#define SVR4_RLIM64_SAVED_MAX ((svr4_rlim64_t) -2) +#define SVR4_RLIM64_INFINITY ((svr4_rlim64_t) -3) + +struct svr4_rlimit64 { + svr4_rlim64_t rlim_cur; + svr4_rlim64_t rlim_max; +}; + +#endif /* !_SVR4_RESOURCE_H_ */ diff --git a/sys/compat/svr4/svr4_siginfo.h b/sys/compat/svr4/svr4_siginfo.h new file mode 100644 index 0000000..35e653b --- /dev/null +++ b/sys/compat/svr4/svr4_siginfo.h @@ -0,0 +1,111 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_SIGINFO_H_ +#define _SVR4_SIGINFO_H_ + +#define SVR4_ILL_ILLOPC 1 +#define SVR4_ILL_ILLOPN 2 +#define SVR4_ILL_ILLADR 3 +#define SVR4_ILL_ILLTRP 4 +#define SVR4_ILL_PRVOPC 5 +#define SVR4_ILL_PRVREG 6 +#define SVR4_ILL_COPROC 7 +#define SVR4_ILL_BADSTK 8 + +#define SVR4_FPE_INTDIV 1 +#define SVR4_FPE_INTOVF 2 +#define SVR4_FPE_FLTDIV 3 +#define SVR4_FPE_FLTOVF 4 +#define SVR4_FPE_FLTUND 5 +#define SVR4_FPE_FLTRES 6 +#define SVR4_FPE_FLTINV 7 +#define SVR4_FPE_FLTSUB 8 + +#define SVR4_SEGV_MAPERR 1 +#define SVR4_SEGV_ACCERR 2 + +#define SVR4_BUS_ADRALN 1 +#define SVR4_BUS_ADRERR 2 +#define SVR4_BUS_OBJERR 3 + +#define SVR4_TRAP_BRKPT 1 +#define SVR4_TRAP_TRACE 2 + +#define SVR4_POLL_IN 1 +#define SVR4_POLL_OUT 2 +#define SVR4_POLL_MSG 3 +#define SVR4_POLL_ERR 4 +#define SVR4_POLL_PRI 5 + +#define SVR4_CLD_EXITED 1 +#define SVR4_CLD_KILLED 2 +#define SVR4_CLD_DUMPED 3 +#define SVR4_CLD_TRAPPED 4 +#define SVR4_CLD_STOPPED 5 +#define SVR4_CLD_CONTINUED 6 + +#define SVR4_EMT_TAGOVF 1 + +typedef union svr4_siginfo { + char si_pad[128]; /* Total size; for future expansion */ + struct { + int _signo; + int _code; + int _errno; + union { + struct { + svr4_pid_t _pid; + svr4_clock_t _utime; + int _status; + svr4_clock_t _stime; + } _child; + + struct { + caddr_t _addr; + int _trap; + } _fault; + } _reason; + } _info; +} svr4_siginfo_t; + +#define svr4_si_signo _info._signo +#define svr4_si_code _info._code +#define svr4_si_errno _info._errno + +#define svr4_si_pid _info._reason._child._pid +#define svr4_si_stime _info._reason._child._stime +#define svr4_si_status _info._reason._child._status +#define svr4_si_utime _info._reason._child._utime + +#define svr4_si_addr _info._reason._fault._addr +#define svr4_si_trap _info._reason._fault._trap + +#endif /* !_SVR4_SIGINFO_H_ */ diff --git a/sys/compat/svr4/svr4_signal.c b/sys/compat/svr4/svr4_signal.c new file mode 100644 index 0000000..3791c05 --- /dev/null +++ b/sys/compat/svr4/svr4_signal.c @@ -0,0 +1,577 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/filedesc.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/proc.h> +#include <sys/signal.h> +#include <sys/signalvar.h> +#include <sys/syscallsubr.h> +#include <sys/sysproto.h> + +#include <machine/cpu.h> + +#include <compat/svr4/svr4.h> +#include <compat/svr4/svr4_types.h> +#include <compat/svr4/svr4_signal.h> +#include <compat/svr4/svr4_proto.h> +#include <compat/svr4/svr4_util.h> +#include <compat/svr4/svr4_ucontext.h> + +#define svr4_sigmask(n) (1 << (((n) - 1) & 31)) +#define svr4_sigword(n) (((n) - 1) >> 5) +#define svr4_sigemptyset(s) memset((s), 0, sizeof(*(s))) +#define svr4_sigismember(s, n) ((s)->bits[svr4_sigword(n)] & svr4_sigmask(n)) +#define svr4_sigaddset(s, n) ((s)->bits[svr4_sigword(n)] |= svr4_sigmask(n)) + +void svr4_to_bsd_sigaction(const struct svr4_sigaction *, struct sigaction *); +void bsd_to_svr4_sigaction(const struct sigaction *, struct svr4_sigaction *); +void svr4_sigfillset(svr4_sigset_t *); + +int bsd_to_svr4_sig[SVR4_NSIG] = { + 0, + SVR4_SIGHUP, + SVR4_SIGINT, + SVR4_SIGQUIT, + SVR4_SIGILL, + SVR4_SIGTRAP, + SVR4_SIGABRT, + SVR4_SIGEMT, + SVR4_SIGFPE, + SVR4_SIGKILL, + SVR4_SIGBUS, + SVR4_SIGSEGV, + SVR4_SIGSYS, + SVR4_SIGPIPE, + SVR4_SIGALRM, + SVR4_SIGTERM, + SVR4_SIGURG, + SVR4_SIGSTOP, + SVR4_SIGTSTP, + SVR4_SIGCONT, + SVR4_SIGCHLD, + SVR4_SIGTTIN, + SVR4_SIGTTOU, + SVR4_SIGIO, + SVR4_SIGXCPU, + SVR4_SIGXFSZ, + SVR4_SIGVTALRM, + SVR4_SIGPROF, + SVR4_SIGWINCH, + 0, /* SIGINFO */ + SVR4_SIGUSR1, + SVR4_SIGUSR2, +}; + +int svr4_to_bsd_sig[SVR4_NSIG] = { + 0, + SIGHUP, + SIGINT, + SIGQUIT, + SIGILL, + SIGTRAP, + SIGABRT, + SIGEMT, + SIGFPE, + SIGKILL, + SIGBUS, + SIGSEGV, + SIGSYS, + SIGPIPE, + SIGALRM, + SIGTERM, + SIGUSR1, + SIGUSR2, + SIGCHLD, + 0, /* XXX NetBSD uses SIGPWR here, but we don't seem to have one */ + SIGWINCH, + SIGURG, + SIGIO, + SIGSTOP, + SIGTSTP, + SIGCONT, + SIGTTIN, + SIGTTOU, + SIGVTALRM, + SIGPROF, + SIGXCPU, + SIGXFSZ, +}; + +void +svr4_sigfillset(s) + svr4_sigset_t *s; +{ + int i; + + svr4_sigemptyset(s); + for (i = 1; i < SVR4_NSIG; i++) + if (svr4_to_bsd_sig[i] != 0) + svr4_sigaddset(s, i); +} + +void +svr4_to_bsd_sigset(sss, bss) + const svr4_sigset_t *sss; + sigset_t *bss; +{ + int i, newsig; + + SIGEMPTYSET(*bss); + for (i = 1; i < SVR4_NSIG; i++) + if (svr4_sigismember(sss, i)) { + newsig = svr4_to_bsd_sig[i]; + if (newsig) + SIGADDSET(*bss, newsig); + } +} + +void +bsd_to_svr4_sigset(bss, sss) + const sigset_t *bss; + svr4_sigset_t *sss; +{ + int i, newsig; + + svr4_sigemptyset(sss); + for (i = 1; i < SVR4_NSIG; i++) { + if (SIGISMEMBER(*bss, i)) { + newsig = bsd_to_svr4_sig[i]; + if (newsig) + svr4_sigaddset(sss, newsig); + } + } +} + +/* + * XXX: Only a subset of the flags is currently implemented. + */ +void +svr4_to_bsd_sigaction(ssa, bsa) + const struct svr4_sigaction *ssa; + struct sigaction *bsa; +{ + + bsa->sa_handler = (sig_t) ssa->ssa_handler; + svr4_to_bsd_sigset(&ssa->ssa_mask, &bsa->sa_mask); + bsa->sa_flags = 0; + if ((ssa->ssa_flags & SVR4_SA_ONSTACK) != 0) + bsa->sa_flags |= SA_ONSTACK; + if ((ssa->ssa_flags & SVR4_SA_RESETHAND) != 0) + bsa->sa_flags |= SA_RESETHAND; + if ((ssa->ssa_flags & SVR4_SA_RESTART) != 0) + bsa->sa_flags |= SA_RESTART; + if ((ssa->ssa_flags & SVR4_SA_SIGINFO) != 0) + DPRINTF(("svr4_to_bsd_sigaction: SA_SIGINFO ignored\n")); + if ((ssa->ssa_flags & SVR4_SA_NOCLDSTOP) != 0) + bsa->sa_flags |= SA_NOCLDSTOP; + if ((ssa->ssa_flags & SVR4_SA_NODEFER) != 0) + bsa->sa_flags |= SA_NODEFER; + if ((ssa->ssa_flags & SVR4_SA_NOCLDWAIT) != 0) + bsa->sa_flags |= SA_NOCLDWAIT; + if ((ssa->ssa_flags & ~SVR4_SA_ALLBITS) != 0) + DPRINTF(("svr4_to_bsd_sigaction: extra bits ignored\n")); +} + +void +bsd_to_svr4_sigaction(bsa, ssa) + const struct sigaction *bsa; + struct svr4_sigaction *ssa; +{ + + ssa->ssa_handler = (svr4_sig_t) bsa->sa_handler; + bsd_to_svr4_sigset(&bsa->sa_mask, &ssa->ssa_mask); + ssa->ssa_flags = 0; + if ((bsa->sa_flags & SA_ONSTACK) != 0) + ssa->ssa_flags |= SVR4_SA_ONSTACK; + if ((bsa->sa_flags & SA_RESETHAND) != 0) + ssa->ssa_flags |= SVR4_SA_RESETHAND; + if ((bsa->sa_flags & SA_RESTART) != 0) + ssa->ssa_flags |= SVR4_SA_RESTART; + if ((bsa->sa_flags & SA_NODEFER) != 0) + ssa->ssa_flags |= SVR4_SA_NODEFER; + if ((bsa->sa_flags & SA_NOCLDSTOP) != 0) + ssa->ssa_flags |= SVR4_SA_NOCLDSTOP; +} + +void +svr4_to_bsd_sigaltstack(sss, bss) + const struct svr4_sigaltstack *sss; + struct sigaltstack *bss; +{ + + bss->ss_sp = sss->ss_sp; + bss->ss_size = sss->ss_size; + bss->ss_flags = 0; + if ((sss->ss_flags & SVR4_SS_DISABLE) != 0) + bss->ss_flags |= SS_DISABLE; + if ((sss->ss_flags & SVR4_SS_ONSTACK) != 0) + bss->ss_flags |= SS_ONSTACK; + if ((sss->ss_flags & ~SVR4_SS_ALLBITS) != 0) + /*XXX*/ uprintf("svr4_to_bsd_sigaltstack: extra bits ignored\n"); +} + +void +bsd_to_svr4_sigaltstack(bss, sss) + const struct sigaltstack *bss; + struct svr4_sigaltstack *sss; +{ + + sss->ss_sp = bss->ss_sp; + sss->ss_size = bss->ss_size; + sss->ss_flags = 0; + if ((bss->ss_flags & SS_DISABLE) != 0) + sss->ss_flags |= SVR4_SS_DISABLE; + if ((bss->ss_flags & SS_ONSTACK) != 0) + sss->ss_flags |= SVR4_SS_ONSTACK; +} + +int +svr4_sys_sigaction(td, uap) + struct thread *td; + struct svr4_sys_sigaction_args *uap; +{ + struct svr4_sigaction isa; + struct sigaction nbsa, obsa; + struct sigaction *nbsap; + int error; + + if (uap->signum < 0 || uap->signum >= SVR4_NSIG) + return (EINVAL); + + DPRINTF(("@@@ svr4_sys_sigaction(%d, %d, %d)\n", td->td_proc->p_pid, + uap->signum, + SVR4_SVR42BSD_SIG(uap->signum))); + + if (uap->nsa != NULL) { + if ((error = copyin(uap->nsa, &isa, sizeof(isa))) != 0) + return (error); + svr4_to_bsd_sigaction(&isa, &nbsa); + nbsap = &nbsa; + } else + nbsap = NULL; +#if defined(DEBUG_SVR4) + { + int i; + for (i = 0; i < 4; i++) + DPRINTF(("\tssa_mask[%d] = %lx\n", i, + isa.ssa_mask.bits[i])); + DPRINTF(("\tssa_handler = %p\n", isa.ssa_handler)); + } +#endif + error = kern_sigaction(td, SVR4_SVR42BSD_SIG(uap->signum), nbsap, &obsa, + 0); + if (error == 0 && uap->osa != NULL) { + bsd_to_svr4_sigaction(&obsa, &isa); + error = copyout(&isa, uap->osa, sizeof(isa)); + } + return (error); +} + +int +svr4_sys_sigaltstack(td, uap) + struct thread *td; + struct svr4_sys_sigaltstack_args *uap; +{ + struct svr4_sigaltstack sss; + struct sigaltstack nbss, obss, *nbssp; + int error; + + if (uap->nss != NULL) { + if ((error = copyin(uap->nss, &sss, sizeof(sss))) != 0) + return (error); + svr4_to_bsd_sigaltstack(&sss, &nbss); + nbssp = &nbss; + } else + nbssp = NULL; + error = kern_sigaltstack(td, nbssp, &obss); + if (error == 0 && uap->oss != NULL) { + bsd_to_svr4_sigaltstack(&obss, &sss); + error = copyout(&sss, uap->oss, sizeof(sss)); + } + return (error); +} + +/* + * Stolen from the ibcs2 one + */ +int +svr4_sys_signal(td, uap) + struct thread *td; + struct svr4_sys_signal_args *uap; +{ + struct proc *p; + int signum; + int error; + + p = td->td_proc; + DPRINTF(("@@@ svr4_sys_signal(%d)\n", p->p_pid)); + + signum = SVR4_SIGNO(uap->signum); + if (signum < 0 || signum >= SVR4_NSIG) { + if (SVR4_SIGCALL(uap->signum) == SVR4_SIGNAL_MASK || + SVR4_SIGCALL(uap->signum) == SVR4_SIGDEFER_MASK) + td->td_retval[0] = (int)SVR4_SIG_ERR; + return (EINVAL); + } + signum = SVR4_SVR42BSD_SIG(signum); + + switch (SVR4_SIGCALL(uap->signum)) { + case SVR4_SIGDEFER_MASK: + if (uap->handler == SVR4_SIG_HOLD) + goto sighold; + /* FALLTHROUGH */ + + case SVR4_SIGNAL_MASK: + { + struct sigaction nbsa, obsa; + + nbsa.sa_handler = (sig_t) uap->handler; + SIGEMPTYSET(nbsa.sa_mask); + nbsa.sa_flags = 0; + if (signum != SIGALRM) + nbsa.sa_flags = SA_RESTART; + error = kern_sigaction(td, signum, &nbsa, &obsa, 0); + if (error != 0) { + DPRINTF(("signal: sigaction failed: %d\n", + error)); + td->td_retval[0] = (int)SVR4_SIG_ERR; + return (error); + } + td->td_retval[0] = (int)obsa.sa_handler; + return (0); + } + + case SVR4_SIGHOLD_MASK: +sighold: + { + sigset_t set; + + SIGEMPTYSET(set); + SIGADDSET(set, signum); + return (kern_sigprocmask(td, SIG_BLOCK, &set, NULL, 0)); + } + + case SVR4_SIGRELSE_MASK: + { + sigset_t set; + + SIGEMPTYSET(set); + SIGADDSET(set, signum); + return (kern_sigprocmask(td, SIG_UNBLOCK, &set, NULL, + 0)); + } + + case SVR4_SIGIGNORE_MASK: + { + struct sigaction sa; + + sa.sa_handler = SIG_IGN; + SIGEMPTYSET(sa.sa_mask); + sa.sa_flags = 0; + error = kern_sigaction(td, signum, &sa, NULL, 0); + if (error != 0) + DPRINTF(("sigignore: sigaction failed\n")); + return (error); + } + + case SVR4_SIGPAUSE_MASK: + { + sigset_t mask; + + PROC_LOCK(p); + mask = td->td_sigmask; + PROC_UNLOCK(p); + SIGDELSET(mask, signum); + return kern_sigsuspend(td, mask); + } + + default: + return (ENOSYS); + } +} + + +int +svr4_sys_sigprocmask(td, uap) + struct thread *td; + struct svr4_sys_sigprocmask_args *uap; +{ + svr4_sigset_t sss; + sigset_t oss, nss; + sigset_t *nssp; + int error; + + if (uap->set != NULL) { + if ((error = copyin(uap->set, &sss, sizeof(sss))) != 0) + return error; + svr4_to_bsd_sigset(&sss, &nss); + nssp = &nss; + } else + nssp = NULL; + + /* SVR/4 sigprocmask flag values are the same as the FreeBSD values. */ + error = kern_sigprocmask(td, uap->how, nssp, &oss, 0); + if (error == 0 && uap->oset != NULL) { + bsd_to_svr4_sigset(&oss, &sss); + error = copyout(&sss, uap->oset, sizeof(sss)); + } + return (error); +} + +int +svr4_sys_sigpending(td, uap) + struct thread *td; + struct svr4_sys_sigpending_args *uap; +{ + struct proc *p; + sigset_t bss; + svr4_sigset_t sss; + + p = td->td_proc; + DPRINTF(("@@@ svr4_sys_sigpending(%d)\n", p->p_pid)); + switch (uap->what) { + case 1: /* sigpending */ + if (uap->mask == NULL) + return 0; + PROC_LOCK(p); + bss = p->p_siglist; + SIGSETOR(bss, td->td_siglist); + SIGSETAND(bss, td->td_sigmask); + PROC_UNLOCK(p); + bsd_to_svr4_sigset(&bss, &sss); + break; + + case 2: /* sigfillset */ + svr4_sigfillset(&sss); +#if defined(DEBUG_SVR4) + { + int i; + for (i = 0; i < 4; i++) + DPRINTF(("new sigset[%d] = %lx\n", i, (long)sss.bits[i])); + } +#endif + break; + + default: + return EINVAL; + } + + return copyout(&sss, uap->mask, sizeof(sss)); +} + +int +svr4_sys_sigsuspend(td, uap) + struct thread *td; + struct svr4_sys_sigsuspend_args *uap; +{ + svr4_sigset_t sss; + sigset_t bss; + int error; + + if ((error = copyin(uap->ss, &sss, sizeof(sss))) != 0) + return error; + + svr4_to_bsd_sigset(&sss, &bss); + return kern_sigsuspend(td, bss); +} + + +int +svr4_sys_kill(td, uap) + struct thread *td; + struct svr4_sys_kill_args *uap; +{ + struct kill_args ka; + + if (uap->signum < 0 || uap->signum >= SVR4_NSIG) + return (EINVAL); + ka.pid = uap->pid; + ka.signum = SVR4_SVR42BSD_SIG(uap->signum); + return sys_kill(td, &ka); +} + + +int +svr4_sys_context(td, uap) + struct thread *td; + struct svr4_sys_context_args *uap; +{ + struct svr4_ucontext uc; + int error, onstack; + + switch (uap->func) { + case 0: + DPRINTF(("getcontext(%p)\n", uap->uc)); + PROC_LOCK(td->td_proc); + onstack = sigonstack(cpu_getstack(td)); + PROC_UNLOCK(td->td_proc); + svr4_getcontext(td, &uc, &td->td_sigmask, onstack); + return copyout(&uc, uap->uc, sizeof(uc)); + + case 1: + DPRINTF(("setcontext(%p)\n", uap->uc)); + if ((error = copyin(uap->uc, &uc, sizeof(uc))) != 0) + return error; + DPRINTF(("uc_flags = %lx\n", uc.uc_flags)); +#if defined(DEBUG_SVR4) + { + int i; + for (i = 0; i < 4; i++) + DPRINTF(("uc_sigmask[%d] = %lx\n", i, + uc.uc_sigmask.bits[i])); + } +#endif + return svr4_setcontext(td, &uc); + + default: + DPRINTF(("context(%d, %p)\n", uap->func, + uap->uc)); + return ENOSYS; + } + return 0; +} + +int +svr4_sys_pause(td, uap) + struct thread *td; + struct svr4_sys_pause_args *uap; +{ + sigset_t mask; + + PROC_LOCK(td->td_proc); + mask = td->td_sigmask; + PROC_UNLOCK(td->td_proc); + return kern_sigsuspend(td, mask); +} diff --git a/sys/compat/svr4/svr4_signal.h b/sys/compat/svr4/svr4_signal.h new file mode 100644 index 0000000..218236d --- /dev/null +++ b/sys/compat/svr4/svr4_signal.h @@ -0,0 +1,144 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_SIGNAL_H_ +#define _SVR4_SIGNAL_H_ + +#include <i386/svr4/svr4_machdep.h> +#include <compat/svr4/svr4_siginfo.h> + +#define SVR4_SIGHUP 1 +#define SVR4_SIGINT 2 +#define SVR4_SIGQUIT 3 +#define SVR4_SIGILL 4 +#define SVR4_SIGTRAP 5 +#define SVR4_SIGIOT 6 +#define SVR4_SIGABRT 6 +#define SVR4_SIGEMT 7 +#define SVR4_SIGFPE 8 +#define SVR4_SIGKILL 9 +#define SVR4_SIGBUS 10 +#define SVR4_SIGSEGV 11 +#define SVR4_SIGSYS 12 +#define SVR4_SIGPIPE 13 +#define SVR4_SIGALRM 14 +#define SVR4_SIGTERM 15 +#define SVR4_SIGUSR1 16 +#define SVR4_SIGUSR2 17 +#define SVR4_SIGCLD 18 +#define SVR4_SIGCHLD 18 +#define SVR4_SIGPWR 19 +#define SVR4_SIGWINCH 20 +#define SVR4_SIGURG 21 +#define SVR4_SIGPOLL 22 +#define SVR4_SIGIO 22 +#define SVR4_SIGSTOP 23 +#define SVR4_SIGTSTP 24 +#define SVR4_SIGCONT 25 +#define SVR4_SIGTTIN 26 +#define SVR4_SIGTTOU 27 +#define SVR4_SIGVTALRM 28 +#define SVR4_SIGPROF 29 +#define SVR4_SIGXCPU 30 +#define SVR4_SIGXFSZ 31 +#define SVR4_NSIG 32 + +#define SVR4_SIGNO_MASK 0x00FF +#define SVR4_SIGNAL_MASK 0x0000 +#define SVR4_SIGDEFER_MASK 0x0100 +#define SVR4_SIGHOLD_MASK 0x0200 +#define SVR4_SIGRELSE_MASK 0x0400 +#define SVR4_SIGIGNORE_MASK 0x0800 +#define SVR4_SIGPAUSE_MASK 0x1000 + +typedef void (*svr4_sig_t)(int, svr4_siginfo_t *, void *); +#define SVR4_SIG_DFL (svr4_sig_t) 0 +#define SVR4_SIG_ERR (svr4_sig_t) -1 +#define SVR4_SIG_IGN (svr4_sig_t) 1 +#define SVR4_SIG_HOLD (svr4_sig_t) 2 + +#define SVR4_SIGNO(a) ((a) & SVR4_SIGNO_MASK) +#define SVR4_SIGCALL(a) ((a) & ~SVR4_SIGNO_MASK) + +#define SVR4_SIG_BLOCK 1 +#define SVR4_SIG_UNBLOCK 2 +#define SVR4_SIG_SETMASK 3 + +extern int bsd_to_svr4_sig[SVR4_NSIG]; +extern int svr4_to_bsd_sig[SVR4_NSIG]; + +#define SVR4_BSD2SVR4_SIG(sig) \ + (((sig) < SVR4_NSIG) ? bsd_to_svr4_sig[sig] : sig) +#define SVR4_SVR42BSD_SIG(sig) \ + (((sig) < SVR4_NSIG) ? svr4_to_bsd_sig[sig] : sig) + +typedef struct { + u_long bits[4]; +} svr4_sigset_t; + +struct svr4_sigaction { + int ssa_flags; + svr4_sig_t ssa_handler; + svr4_sigset_t ssa_mask; + int ssa_reserved[2]; +}; + +struct svr4_sigaltstack { + char *ss_sp; + int ss_size; + int ss_flags; +}; + +/* sa_flags */ +#define SVR4_SA_ONSTACK 0x00000001 +#define SVR4_SA_RESETHAND 0x00000002 +#define SVR4_SA_RESTART 0x00000004 +#define SVR4_SA_SIGINFO 0x00000008 +#define SVR4_SA_NODEFER 0x00000010 +#define SVR4_SA_NOCLDWAIT 0x00010000 /* No zombies */ +#define SVR4_SA_NOCLDSTOP 0x00020000 /* No jcl */ +#define SVR4_SA_ALLBITS 0x0003001f + +/* ss_flags */ +#define SVR4_SS_ONSTACK 0x00000001 +#define SVR4_SS_DISABLE 0x00000002 +#define SVR4_SS_ALLBITS 0x00000003 + +#define SVR4_MINSIGSTKSZ 8192 + +struct ksiginfo; + +void bsd_to_svr4_sigaltstack(const struct sigaltstack *, struct svr4_sigaltstack *); +void bsd_to_svr4_sigset(const sigset_t *, svr4_sigset_t *); +void svr4_to_bsd_sigaltstack(const struct svr4_sigaltstack *, struct sigaltstack *); +void svr4_to_bsd_sigset(const svr4_sigset_t *, sigset_t *); +void svr4_sendsig(sig_t, struct ksiginfo *, sigset_t *); + +#endif /* !_SVR4_SIGNAL_H_ */ diff --git a/sys/compat/svr4/svr4_socket.c b/sys/compat/svr4/svr4_socket.c new file mode 100644 index 0000000..038267c --- /dev/null +++ b/sys/compat/svr4/svr4_socket.c @@ -0,0 +1,242 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1996 Christos Zoulas. + * 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 Christos Zoulas. + * 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 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. + */ + +/* + * In SVR4 unix domain sockets are referenced sometimes + * (in putmsg(2) for example) as a [device, inode] pair instead of a pathname. + * Since there is no iname() routine in the kernel, and we need access to + * a mapping from inode to pathname, we keep our own table. This is a simple + * linked list that contains the pathname, the [device, inode] pair, the + * file corresponding to that socket and the process. When the + * socket gets closed we remove the item from the list. The list gets loaded + * every time a stat(2) call finds a socket. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/queue.h> +#include <sys/eventhandler.h> +#include <sys/file.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/sysproto.h> +#include <sys/un.h> +#include <sys/stat.h> +#include <sys/proc.h> +#include <sys/malloc.h> + +#include <compat/svr4/svr4.h> +#include <compat/svr4/svr4_types.h> +#include <compat/svr4/svr4_util.h> +#include <compat/svr4/svr4_socket.h> +#include <compat/svr4/svr4_signal.h> +#include <compat/svr4/svr4_sockmod.h> +#include <compat/svr4/svr4_proto.h> + +struct svr4_sockcache_entry { + struct proc *p; /* Process for the socket */ + void *cookie; /* Internal cookie used for matching */ + struct sockaddr_un sock;/* Pathname for the socket */ + dev_t dev; /* Device where the socket lives on */ + ino_t ino; /* Inode where the socket lives on */ + TAILQ_ENTRY(svr4_sockcache_entry) entries; +}; + +static TAILQ_HEAD(, svr4_sockcache_entry) svr4_head; +static struct mtx svr4_sockcache_lock; +static eventhandler_tag svr4_sockcache_exit_tag, svr4_sockcache_exec_tag; + +static void svr4_purge_sockcache(void *arg, struct proc *p); + +int +svr4_find_socket(td, fp, dev, ino, saun) + struct thread *td; + struct file *fp; + dev_t dev; + ino_t ino; + struct sockaddr_un *saun; +{ + struct svr4_sockcache_entry *e; + void *cookie = ((struct socket *)fp->f_data)->so_emuldata; + + DPRINTF(("svr4_find_socket: [%p,%d,%d]: ", td, dev, ino)); + mtx_lock(&svr4_sockcache_lock); + TAILQ_FOREACH(e, &svr4_head, entries) + if (e->p == td->td_proc && e->dev == dev && e->ino == ino) { +#ifdef DIAGNOSTIC + if (e->cookie != NULL && e->cookie != cookie) + panic("svr4 socket cookie mismatch"); +#endif + e->cookie = cookie; + DPRINTF(("%s\n", e->sock.sun_path)); + *saun = e->sock; + mtx_unlock(&svr4_sockcache_lock); + return (0); + } + + mtx_unlock(&svr4_sockcache_lock); + DPRINTF(("not found\n")); + return (ENOENT); +} + +int +svr4_add_socket(td, path, st) + struct thread *td; + const char *path; + struct stat *st; +{ + struct svr4_sockcache_entry *e; + size_t len; + int error; + + e = malloc(sizeof(*e), M_TEMP, M_WAITOK); + e->cookie = NULL; + e->dev = st->st_dev; + e->ino = st->st_ino; + e->p = td->td_proc; + + if ((error = copyinstr(path, e->sock.sun_path, + sizeof(e->sock.sun_path), &len)) != 0) { + DPRINTF(("svr4_add_socket: copyinstr failed %d\n", error)); + free(e, M_TEMP); + return error; + } + + e->sock.sun_family = AF_LOCAL; + e->sock.sun_len = len; + + mtx_lock(&svr4_sockcache_lock); + TAILQ_INSERT_HEAD(&svr4_head, e, entries); + mtx_unlock(&svr4_sockcache_lock); + DPRINTF(("svr4_add_socket: %s [%p,%d,%d]\n", e->sock.sun_path, + td->td_proc, e->dev, e->ino)); + return 0; +} + +void +svr4_delete_socket(p, fp) + struct proc *p; + struct file *fp; +{ + struct svr4_sockcache_entry *e; + void *cookie = ((struct socket *)fp->f_data)->so_emuldata; + + mtx_lock(&svr4_sockcache_lock); + TAILQ_FOREACH(e, &svr4_head, entries) + if (e->p == p && e->cookie == cookie) { + TAILQ_REMOVE(&svr4_head, e, entries); + mtx_unlock(&svr4_sockcache_lock); + DPRINTF(("svr4_delete_socket: %s [%p,%d,%d]\n", + e->sock.sun_path, p, (int)e->dev, e->ino)); + free(e, M_TEMP); + return; + } + mtx_unlock(&svr4_sockcache_lock); +} + +void +svr4_purge_sockcache(arg, p) + void *arg; + struct proc *p; +{ + struct svr4_sockcache_entry *e, *ne; + + mtx_lock(&svr4_sockcache_lock); + TAILQ_FOREACH_SAFE(e, &svr4_head, entries, ne) { + if (e->p == p) { + TAILQ_REMOVE(&svr4_head, e, entries); + DPRINTF(("svr4_purge_sockcache: %s [%p,%d,%d]\n", + e->sock.sun_path, p, (int)e->dev, e->ino)); + free(e, M_TEMP); + } + } + mtx_unlock(&svr4_sockcache_lock); +} + +void +svr4_sockcache_init(void) +{ + + TAILQ_INIT(&svr4_head); + mtx_init(&svr4_sockcache_lock, "svr4 socket cache", NULL, MTX_DEF); + svr4_sockcache_exit_tag = EVENTHANDLER_REGISTER(process_exit, + svr4_purge_sockcache, NULL, EVENTHANDLER_PRI_ANY); + svr4_sockcache_exec_tag = EVENTHANDLER_REGISTER(process_exec, + svr4_purge_sockcache, NULL, EVENTHANDLER_PRI_ANY); +} + +void +svr4_sockcache_destroy(void) +{ + + KASSERT(TAILQ_EMPTY(&svr4_head), + ("%s: sockcache entries still around", __func__)); + EVENTHANDLER_DEREGISTER(process_exec, svr4_sockcache_exec_tag); + EVENTHANDLER_DEREGISTER(process_exit, svr4_sockcache_exit_tag); + mtx_destroy(&svr4_sockcache_lock); +} + +int +svr4_sys_socket(td, uap) + struct thread *td; + struct svr4_sys_socket_args *uap; +{ + switch (uap->type) { + case SVR4_SOCK_DGRAM: + uap->type = SOCK_DGRAM; + break; + + case SVR4_SOCK_STREAM: + uap->type = SOCK_STREAM; + break; + + case SVR4_SOCK_RAW: + uap->type = SOCK_RAW; + break; + + case SVR4_SOCK_RDM: + uap->type = SOCK_RDM; + break; + + case SVR4_SOCK_SEQPACKET: + uap->type = SOCK_SEQPACKET; + break; + default: + return EINVAL; + } + return sys_socket(td, (struct socket_args *)uap); +} diff --git a/sys/compat/svr4/svr4_socket.h b/sys/compat/svr4/svr4_socket.h new file mode 100644 index 0000000..cbe7401 --- /dev/null +++ b/sys/compat/svr4/svr4_socket.h @@ -0,0 +1,58 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1996 Christos Zoulas. + * 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 Christos Zoulas. + * 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 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 _SVR4_SOCKET_H_ +#define _SVR4_SOCKET_H_ + +#include <netinet/in.h> + +struct sockaddr_un; +struct proc; +struct thread; +struct file; + +struct svr4_sockaddr_in { + u_char sin_family; + u_short sin_port; + struct in_addr sin_addr; + u_char sin_zero[8]; +}; + +int svr4_add_socket(struct thread *, const char *, struct stat *); +void svr4_delete_socket(struct proc *, struct file *); +int svr4_find_socket(struct thread *, struct file *, dev_t, ino_t, + struct sockaddr_un *); +void svr4_sockcache_init(void); +void svr4_sockcache_destroy(void); + +#endif /* _SVR4_SOCKET_H_ */ diff --git a/sys/compat/svr4/svr4_sockio.c b/sys/compat/svr4/svr4_sockio.c new file mode 100644 index 0000000..afb3cfe --- /dev/null +++ b/sys/compat/svr4/svr4_sockio.c @@ -0,0 +1,168 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1995 Christos Zoulas + * 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/proc.h> +#include <sys/systm.h> +#include <sys/file.h> +#include <sys/filedesc.h> +#include <sys/sockio.h> +#include <sys/socket.h> + +#include <net/if.h> +#include <net/vnet.h> + +#include <compat/svr4/svr4.h> +#include <compat/svr4/svr4_util.h> +#include <compat/svr4/svr4_ioctl.h> +#include <compat/svr4/svr4_sockio.h> + +static int bsd_to_svr4_flags(int); + +#define bsd_to_svr4_flag(a) \ + if (bf & __CONCAT(I,a)) sf |= __CONCAT(SVR4_I,a) + +static int +bsd_to_svr4_flags(bf) + int bf; +{ + int sf = 0; + bsd_to_svr4_flag(FF_UP); + bsd_to_svr4_flag(FF_BROADCAST); + bsd_to_svr4_flag(FF_DEBUG); + bsd_to_svr4_flag(FF_LOOPBACK); + bsd_to_svr4_flag(FF_POINTOPOINT); +#if defined(IFF_NOTRAILERS) + bsd_to_svr4_flag(FF_NOTRAILERS); +#endif + if (bf & IFF_DRV_RUNNING) + sf |= SVR4_IFF_RUNNING; + bsd_to_svr4_flag(FF_NOARP); + bsd_to_svr4_flag(FF_PROMISC); + bsd_to_svr4_flag(FF_ALLMULTI); + bsd_to_svr4_flag(FF_MULTICAST); + return sf; +} + +int +svr4_sock_ioctl(fp, td, retval, fd, cmd, data) + struct file *fp; + struct thread *td; + register_t *retval; + int fd; + u_long cmd; + caddr_t data; +{ + int error; + + *retval = 0; + + switch (cmd) { + case SVR4_SIOCGIFNUM: + { + struct ifnet *ifp; + struct ifaddr *ifa; + int ifnum = 0; + + /* + * This does not return the number of physical + * interfaces (if_index), but the number of interfaces + * + addresses like ifconf() does, because this number + * is used by code that will call SVR4_SIOCGIFCONF to + * find the space needed for SVR4_SIOCGIFCONF. So we + * count the number of ifreq entries that the next + * SVR4_SIOCGIFCONF will return. Maybe a more correct + * fix is to make SVR4_SIOCGIFCONF return only one + * entry per physical interface? + */ + IFNET_RLOCK(); + TAILQ_FOREACH(ifp, &V_ifnet, if_link) + if (TAILQ_EMPTY(&ifp->if_addrhead)) + ifnum++; + else + TAILQ_FOREACH(ifa, &ifp->if_addrhead, + ifa_link) + ifnum++; + IFNET_RUNLOCK(); + DPRINTF(("SIOCGIFNUM %d\n", ifnum)); + return copyout(&ifnum, data, sizeof(ifnum)); + } + + case SVR4_SIOCGIFFLAGS: + { + struct ifreq br; + struct svr4_ifreq sr; + + if ((error = copyin(data, &sr, sizeof(sr))) != 0) + return error; + + (void) strlcpy(br.ifr_name, sr.svr4_ifr_name, + sizeof(br.ifr_name)); + if ((error = fo_ioctl(fp, SIOCGIFFLAGS, + (caddr_t) &br, td->td_ucred, + td)) != 0) { + DPRINTF(("SIOCGIFFLAGS (%s) %s: error %d\n", + br.ifr_name, sr.svr4_ifr_name, error)); + return error; + } + + sr.svr4_ifr_flags = bsd_to_svr4_flags(br.ifr_flags); + DPRINTF(("SIOCGIFFLAGS %s = %x\n", + sr.svr4_ifr_name, sr.svr4_ifr_flags)); + return copyout(&sr, data, sizeof(sr)); + } + + case SVR4_SIOCGIFCONF: + { + struct svr4_ifconf sc; + + if ((error = copyin(data, &sc, sizeof(sc))) != 0) + return error; + + DPRINTF(("ifreq %d svr4_ifreq %d ifc_len %d\n", + sizeof(struct ifreq), sizeof(struct svr4_ifreq), + sc.svr4_ifc_len)); + + if ((error = fo_ioctl(fp, OSIOCGIFCONF, + (caddr_t) &sc, td->td_ucred, + td)) != 0) + return error; + + DPRINTF(("SIOCGIFCONF\n")); + return 0; + } + + + default: + DPRINTF(("Unknown svr4 sockio %lx\n", cmd)); + return 0; /* ENOSYS really */ + } +} diff --git a/sys/compat/svr4/svr4_sockio.h b/sys/compat/svr4/svr4_sockio.h new file mode 100644 index 0000000..6160aa3 --- /dev/null +++ b/sys/compat/svr4/svr4_sockio.h @@ -0,0 +1,93 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1995 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_SOCKIO_H_ +#define _SVR4_SOCKIO_H_ + +#define SVR4_IFF_UP 0x0001 +#define SVR4_IFF_BROADCAST 0x0002 +#define SVR4_IFF_DEBUG 0x0004 +#define SVR4_IFF_LOOPBACK 0x0008 +#define SVR4_IFF_POINTOPOINT 0x0010 +#define SVR4_IFF_NOTRAILERS 0x0020 +#define SVR4_IFF_RUNNING 0x0040 +#define SVR4_IFF_NOARP 0x0080 +#define SVR4_IFF_PROMISC 0x0100 +#define SVR4_IFF_ALLMULTI 0x0200 +#define SVR4_IFF_INTELLIGENT 0x0400 +#define SVR4_IFF_MULTICAST 0x0800 +#define SVR4_IFF_MULTI_BCAST 0x1000 +#define SVR4_IFF_UNNUMBERED 0x2000 +#define SVR4_IFF_PRIVATE 0x8000 + +struct svr4_ifreq { +#define SVR4_IFNAMSIZ 16 + char svr4_ifr_name[SVR4_IFNAMSIZ]; + union { + struct osockaddr ifru_addr; + struct osockaddr ifru_dstaddr; + struct osockaddr ifru_broadaddr; + short ifru_flags; + int ifru_metric; + char ifru_data; + char ifru_enaddr[6]; + int if_muxid[2]; + + } ifr_ifru; + +#define svr4_ifr_addr ifr_ifru.ifru_addr +#define svr4_ifr_dstaddr ifr_ifru.ifru_dstaddr +#define svr4_ifr_broadaddr ifr_ifru.ifru_broadaddr +#define svr4_ifr_flags ifr_ifru.ifru_flags +#define svr4_ifr_metric ifr_ifru.ifru_metric +#define svr4_ifr_data ifr_ifru.ifru_data +#define svr4_ifr_enaddr ifr_ifru.ifru_enaddr +#define svr4_ifr_muxid ifr_ifru.ifru_muxid + +}; + +struct svr4_ifconf { + int svr4_ifc_len; + union { + caddr_t ifcu_buf; + struct svr4_ifreq *ifcu_req; + } ifc_ifcu; + +#define svr4_ifc_buf ifc_ifcu.ifcu_buf +#define svr4_ifc_req ifc_ifcu.ifcu_req +}; + +#define SVR4_SIOC ('i' << 8) + +#define SVR4_SIOCGIFFLAGS SVR4_IOWR('i', 17, struct svr4_ifreq) +#define SVR4_SIOCGIFCONF SVR4_IOWR('i', 20, struct svr4_ifconf) +#define SVR4_SIOCGIFNUM SVR4_IOR('i', 87, int) + +#endif /* !_SVR4_SOCKIO_H_ */ diff --git a/sys/compat/svr4/svr4_sockmod.h b/sys/compat/svr4/svr4_sockmod.h new file mode 100644 index 0000000..622ff6f --- /dev/null +++ b/sys/compat/svr4/svr4_sockmod.h @@ -0,0 +1,83 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_SOCKMOD_H_ +#define _SVR4_SOCKMOD_H_ + +#define SVR4_SIMOD ('I' << 8) + +#define SVR4_SI_OGETUDATA (SVR4_SIMOD|101) +#define SVR4_SI_SHUTDOWN (SVR4_SIMOD|102) +#define SVR4_SI_LISTEN (SVR4_SIMOD|103) +#define SVR4_SI_SETMYNAME (SVR4_SIMOD|104) +#define SVR4_SI_SETPEERNAME (SVR4_SIMOD|105) +#define SVR4_SI_GETINTRANSIT (SVR4_SIMOD|106) +#define SVR4_SI_TCL_LINK (SVR4_SIMOD|107) +#define SVR4_SI_TCL_UNLINK (SVR4_SIMOD|108) +#define SVR4_SI_SOCKPARAMS (SVR4_SIMOD|109) +#define SVR4_SI_GETUDATA (SVR4_SIMOD|110) + + +#define SVR4_SOCK_DGRAM 1 +#define SVR4_SOCK_STREAM 2 +#define SVR4_SOCK_STREAM_ORD 3 +#define SVR4_SOCK_RAW 4 +#define SVR4_SOCK_RDM 5 +#define SVR4_SOCK_SEQPACKET 6 + +struct svr4_si_sockparms { + int family; + int type; + int protocol; +}; + +struct svr4_si_oudata { + int tidusize; + int addrsize; + int optsize; + int etsdusize; + int servtype; + int so_state; + int so_options; + int tsdusize; +}; + +struct svr4_si_udata { + int tidusize; + int addrsize; + int optsize; + int etsdusize; + int servtype; + int so_state; + int so_options; + int tsdusize; + struct svr4_si_sockparms sockparms; +}; +#endif /* !_SVR4_SOCKMOD_H_ */ diff --git a/sys/compat/svr4/svr4_stat.c b/sys/compat/svr4/svr4_stat.c new file mode 100644 index 0000000..b686642 --- /dev/null +++ b/sys/compat/svr4/svr4_stat.c @@ -0,0 +1,699 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/stat.h> +#include <sys/filedesc.h> +#include <sys/jail.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/namei.h> +#include <sys/unistd.h> +#include <sys/time.h> +#include <sys/syscallsubr.h> +#include <sys/sysctl.h> +#include <sys/sysproto.h> +#include <sys/un.h> + +#include <vm/vm.h> + +#include <netinet/in.h> + +#include <compat/svr4/svr4.h> +#include <compat/svr4/svr4_types.h> +#include <compat/svr4/svr4_signal.h> +#include <compat/svr4/svr4_proto.h> +#include <compat/svr4/svr4_util.h> +#include <compat/svr4/svr4_stat.h> +#include <compat/svr4/svr4_ustat.h> +#include <compat/svr4/svr4_utsname.h> +#include <compat/svr4/svr4_systeminfo.h> +#include <compat/svr4/svr4_socket.h> +#include <compat/svr4/svr4_time.h> +#if defined(NOTYET) +#include "svr4_fuser.h" +#endif + +#ifdef sparc +/* + * Solaris-2.4 on the sparc has the old stat call using the new + * stat data structure... + */ +# define SVR4_NO_OSTAT +#endif + +struct svr4_ustat_args { + svr4_dev_t dev; + struct svr4_ustat * name; +}; + +static void bsd_to_svr4_xstat(struct stat *, struct svr4_xstat *); +static void bsd_to_svr4_stat64(struct stat *, struct svr4_stat64 *); +int svr4_ustat(struct thread *, struct svr4_ustat_args *); +static int svr4_to_bsd_pathconf(int); + +/* + * SVR4 uses named pipes as named sockets, so we tell programs + * that sockets are named pipes with mode 0 + */ +#define BSD_TO_SVR4_MODE(mode) (S_ISSOCK(mode) ? S_IFIFO : (mode)) + + +#ifndef SVR4_NO_OSTAT +static void bsd_to_svr4_stat(struct stat *, struct svr4_stat *); + +static void +bsd_to_svr4_stat(st, st4) + struct stat *st; + struct svr4_stat *st4; +{ + memset(st4, 0, sizeof(*st4)); + st4->st_dev = bsd_to_svr4_odev_t(st->st_dev); + st4->st_ino = st->st_ino; + st4->st_mode = BSD_TO_SVR4_MODE(st->st_mode); + st4->st_nlink = st->st_nlink; + st4->st_uid = st->st_uid; + st4->st_gid = st->st_gid; + st4->st_rdev = bsd_to_svr4_odev_t(st->st_rdev); + st4->st_size = st->st_size; + st4->st_atim = st->st_atim.tv_sec; + st4->st_mtim = st->st_mtim.tv_sec; + st4->st_ctim = st->st_ctim.tv_sec; +} +#endif + + +static void +bsd_to_svr4_xstat(st, st4) + struct stat *st; + struct svr4_xstat *st4; +{ + memset(st4, 0, sizeof(*st4)); + st4->st_dev = bsd_to_svr4_dev_t(st->st_dev); + st4->st_ino = st->st_ino; + st4->st_mode = BSD_TO_SVR4_MODE(st->st_mode); + st4->st_nlink = st->st_nlink; + st4->st_uid = st->st_uid; + st4->st_gid = st->st_gid; + st4->st_rdev = bsd_to_svr4_dev_t(st->st_rdev); + st4->st_size = st->st_size; + st4->st_atim = st->st_atim; + st4->st_mtim = st->st_mtim; + st4->st_ctim = st->st_ctim; + st4->st_blksize = st->st_blksize; + st4->st_blocks = st->st_blocks; + strcpy(st4->st_fstype, "unknown"); +} + + +static void +bsd_to_svr4_stat64(st, st4) + struct stat *st; + struct svr4_stat64 *st4; +{ + memset(st4, 0, sizeof(*st4)); + st4->st_dev = bsd_to_svr4_dev_t(st->st_dev); + st4->st_ino = st->st_ino; + st4->st_mode = BSD_TO_SVR4_MODE(st->st_mode); + st4->st_nlink = st->st_nlink; + st4->st_uid = st->st_uid; + st4->st_gid = st->st_gid; + st4->st_rdev = bsd_to_svr4_dev_t(st->st_rdev); + st4->st_size = st->st_size; + st4->st_atim = st->st_atim; + st4->st_mtim = st->st_mtim; + st4->st_ctim = st->st_ctim; + st4->st_blksize = st->st_blksize; + st4->st_blocks = st->st_blocks; + strcpy(st4->st_fstype, "unknown"); +} + +int +svr4_sys_stat(td, uap) + struct thread *td; + struct svr4_sys_stat_args *uap; +{ + struct svr4_stat svr4_st; + struct stat st; + char *path; + int error; + + CHECKALTEXIST(td, uap->path, &path); + + error = kern_stat(td, path, UIO_SYSSPACE, &st); + free(path, M_TEMP); + if (error) + return (error); + bsd_to_svr4_stat(&st, &svr4_st); + + if (S_ISSOCK(st.st_mode)) + (void) svr4_add_socket(td, uap->path, &st); + + return (copyout(&svr4_st, uap->ub, sizeof svr4_st)); +} + + +int +svr4_sys_lstat(td, uap) + struct thread *td; + struct svr4_sys_lstat_args *uap; +{ + struct svr4_stat svr4_st; + struct stat st; + char *path; + int error; + + CHECKALTEXIST(td, uap->path, &path); + + error = kern_lstat(td, path, UIO_SYSSPACE, &st); + free(path, M_TEMP); + if (error) + return (error); + bsd_to_svr4_stat(&st, &svr4_st); + + if (S_ISSOCK(st.st_mode)) + (void) svr4_add_socket(td, uap->path, &st); + + return (copyout(&svr4_st, uap->ub, sizeof svr4_st)); +} + + +int +svr4_sys_fstat(td, uap) + struct thread *td; + struct svr4_sys_fstat_args *uap; +{ + struct svr4_stat svr4_st; + struct stat st; + int error; + + + error = kern_fstat(td, uap->fd, &st); + if (error) + return (error); + bsd_to_svr4_stat(&st, &svr4_st); + return (copyout(&svr4_st, uap->sb, sizeof svr4_st)); +} + + +int +svr4_sys_xstat(td, uap) + struct thread *td; + struct svr4_sys_xstat_args *uap; +{ + struct svr4_xstat svr4_st; + struct stat st; + char *path; + int error; + + CHECKALTEXIST(td, uap->path, &path); + + error = kern_stat(td, path, UIO_SYSSPACE, &st); + free(path, M_TEMP); + if (error) + return (error); + + bsd_to_svr4_xstat(&st, &svr4_st); + +#if defined(SOCKET_NOTYET) + if (S_ISSOCK(st.st_mode)) + (void) svr4_add_socket(td, uap->path, &st); +#endif + + return (copyout(&svr4_st, uap->ub, sizeof svr4_st)); +} + +int +svr4_sys_lxstat(td, uap) + struct thread *td; + struct svr4_sys_lxstat_args *uap; +{ + struct svr4_xstat svr4_st; + struct stat st; + char *path; + int error; + + CHECKALTEXIST(td, uap->path, &path); + + error = kern_lstat(td, path, UIO_SYSSPACE, &st); + free(path, M_TEMP); + if (error) + return (error); + + bsd_to_svr4_xstat(&st, &svr4_st); + +#if defined(SOCKET_NOTYET) + if (S_ISSOCK(st.st_mode)) + (void) svr4_add_socket(td, uap->path, &st); +#endif + return (copyout(&svr4_st, uap->ub, sizeof svr4_st)); +} + + +int +svr4_sys_fxstat(td, uap) + struct thread *td; + struct svr4_sys_fxstat_args *uap; +{ + struct svr4_xstat svr4_st; + struct stat st; + int error; + + + error = kern_fstat(td, uap->fd, &st); + if (error) + return (error); + bsd_to_svr4_xstat(&st, &svr4_st); + return (copyout(&svr4_st, uap->sb, sizeof svr4_st)); +} + +int +svr4_sys_stat64(td, uap) + struct thread *td; + struct svr4_sys_stat64_args *uap; +{ + struct svr4_stat64 svr4_st; + struct stat st; + char *path; + int error; + + CHECKALTEXIST(td, uap->path, &path); + + error = kern_stat(td, path, UIO_SYSSPACE, &st); + free(path, M_TEMP); + if (error) + return (error); + + bsd_to_svr4_stat64(&st, &svr4_st); + + if (S_ISSOCK(st.st_mode)) + (void) svr4_add_socket(td, uap->path, &st); + + return (copyout(&svr4_st, uap->sb, sizeof svr4_st)); +} + + +int +svr4_sys_lstat64(td, uap) + struct thread *td; + struct svr4_sys_lstat64_args *uap; +{ + struct svr4_stat64 svr4_st; + struct stat st; + char *path; + int error; + + CHECKALTEXIST(td, uap->path, &path); + + error = kern_lstat(td, path, UIO_SYSSPACE, &st); + free(path, M_TEMP); + if (error) + return (error); + + bsd_to_svr4_stat64(&st, &svr4_st); + + if (S_ISSOCK(st.st_mode)) + (void) svr4_add_socket(td, uap->path, &st); + + return (copyout(&svr4_st, uap->sb, sizeof svr4_st)); +} + + +int +svr4_sys_fstat64(td, uap) + struct thread *td; + struct svr4_sys_fstat64_args *uap; +{ + struct svr4_stat64 svr4_st; + struct stat st; + int error; + + error = kern_fstat(td, uap->fd, &st); + if (error) + return (error); + bsd_to_svr4_stat64(&st, &svr4_st); + return (copyout(&svr4_st, uap->sb, sizeof svr4_st)); +} + + +int +svr4_ustat(td, uap) + struct thread *td; + struct svr4_ustat_args *uap; +{ + struct svr4_ustat us; + int error; + + memset(&us, 0, sizeof us); + + /* + * XXX: should set f_tfree and f_tinode at least + * How do we translate dev -> fstat? (and then to svr4_ustat) + */ + if ((error = copyout(&us, uap->name, sizeof us)) != 0) + return (error); + + return 0; +} + +/*extern char ostype[], osrelease[], version[], machine[];*/ + +int +svr4_sys_uname(td, uap) + struct thread *td; + struct svr4_sys_uname_args *uap; +{ + struct svr4_utsname sut; + + memset(&sut, 0, sizeof(sut)); + + strlcpy(sut.sysname, ostype, sizeof(sut.sysname)); + getcredhostname(td->td_ucred, sut.nodename, sizeof(sut.nodename)); + strlcpy(sut.release, osrelease, sizeof(sut.release)); + strlcpy(sut.version, version, sizeof(sut.version)); + strlcpy(sut.machine, machine, sizeof(sut.machine)); + + return copyout((caddr_t) &sut, (caddr_t) uap->name, + sizeof(struct svr4_utsname)); +} + +int +svr4_sys_systeminfo(td, uap) + struct thread *td; + struct svr4_sys_systeminfo_args *uap; +{ + char *str = NULL; + int error = 0; + register_t *retval = td->td_retval; + u_long hostid; + size_t len = 0; + char buf[MAXHOSTNAMELEN]; + u_int rlen = uap->len; + + switch (uap->what) { + case SVR4_SI_SYSNAME: + str = ostype; + break; + + case SVR4_SI_HOSTNAME: + getcredhostname(td->td_ucred, buf, sizeof(buf)); + str = buf; + break; + + case SVR4_SI_RELEASE: + str = osrelease; + break; + + case SVR4_SI_VERSION: + str = version; + break; + + case SVR4_SI_MACHINE: + str = machine; + break; + + case SVR4_SI_ARCHITECTURE: + str = machine; + break; + + case SVR4_SI_ISALIST: +#if defined(__sparc__) + str = "sparcv9 sparcv9-fsmuld sparcv8 sparcv8-fsmuld sparcv7 sparc"; +#elif defined(__i386__) + str = "i386"; +#elif defined(__amd64__) + str = "amd64"; +#else + str = "unknown"; +#endif + break; + + case SVR4_SI_HW_SERIAL: + getcredhostid(td->td_ucred, &hostid); + snprintf(buf, sizeof(buf), "%lu", hostid); + str = buf; + break; + + case SVR4_SI_HW_PROVIDER: + str = ostype; + break; + + case SVR4_SI_SRPC_DOMAIN: + getcreddomainname(td->td_ucred, buf, sizeof(buf)); + str = buf; + break; + + case SVR4_SI_PLATFORM: +#if defined(__i386__) + str = "i86pc"; +#else + str = "unknown"; +#endif + break; + + case SVR4_SI_KERB_REALM: + str = "unsupported"; + break; +#if defined(WHY_DOES_AN_EMULATOR_WANT_TO_SET_HOSTNAMES) + case SVR4_SI_SET_HOSTNAME: + name = KERN_HOSTNAME; + return kern_sysctl(&name, 1, 0, 0, uap->buf, rlen, td); + + case SVR4_SI_SET_SRPC_DOMAIN: + name = KERN_NISDOMAINNAME; + return kern_sysctl(&name, 1, 0, 0, uap->buf, rlen, td); +#else + case SVR4_SI_SET_HOSTNAME: + case SVR4_SI_SET_SRPC_DOMAIN: + /* FALLTHROUGH */ +#endif + case SVR4_SI_SET_KERB_REALM: + return 0; + + default: + DPRINTF(("Bad systeminfo command %d\n", uap->what)); + return ENOSYS; + } + + if (str) { + len = strlen(str) + 1; + if (len > rlen) + len = rlen; + + if (uap->buf) { + error = copyout(str, uap->buf, len); + if (error) + return error; + /* make sure we are NULL terminated */ + buf[0] = '\0'; + error = copyout(buf, &(uap->buf[len - 1]), 1); + } + else + error = 0; + } + /* XXX NetBSD has hostname setting stuff here. Why would an emulator + want to do that? */ + + *retval = len; + return error; +} + +int +svr4_sys_utssys(td, uap) + struct thread *td; + struct svr4_sys_utssys_args *uap; +{ + switch (uap->sel) { + case 0: /* uname(2) */ + { + struct svr4_sys_uname_args ua; + ua.name = uap->a1; + return svr4_sys_uname(td, &ua); + } + + case 2: /* ustat(2) */ + { + struct svr4_ustat_args ua; + ua.dev = (svr4_dev_t) uap->a2; + ua.name = uap->a1; + return svr4_ustat(td, &ua); + } + + case 3: /* fusers(2) */ + return ENOSYS; + + default: + return ENOSYS; + } + return ENOSYS; +} + + +int +svr4_sys_utime(td, uap) + struct thread *td; + struct svr4_sys_utime_args *uap; +{ + struct svr4_utimbuf ub; + struct timeval tbuf[2], *tp; + char *path; + int error; + + if (uap->ubuf != NULL) { + error = copyin(uap->ubuf, &ub, sizeof(ub)); + if (error) + return (error); + tbuf[0].tv_sec = ub.actime; + tbuf[0].tv_usec = 0; + tbuf[1].tv_sec = ub.modtime; + tbuf[1].tv_usec = 0; + tp = tbuf; + } else + tp = NULL; + + CHECKALTEXIST(td, uap->path, &path); + error = kern_utimes(td, path, UIO_SYSSPACE, tp, UIO_SYSSPACE); + free(path, M_TEMP); + return (error); +} + + +int +svr4_sys_utimes(td, uap) + struct thread *td; + struct svr4_sys_utimes_args *uap; +{ + char *path; + int error; + + CHECKALTEXIST(td, uap->path, &path); + error = kern_utimes(td, path, UIO_SYSSPACE, uap->tptr, UIO_USERSPACE); + free(path, M_TEMP); + return (error); +} + +static int +svr4_to_bsd_pathconf(name) + int name; +{ + switch (name) { + case SVR4_PC_LINK_MAX: + return _PC_LINK_MAX; + + case SVR4_PC_MAX_CANON: + return _PC_MAX_CANON; + + case SVR4_PC_MAX_INPUT: + return _PC_MAX_INPUT; + + case SVR4_PC_NAME_MAX: + return _PC_NAME_MAX; + + case SVR4_PC_PATH_MAX: + return _PC_PATH_MAX; + + case SVR4_PC_PIPE_BUF: + return _PC_PIPE_BUF; + + case SVR4_PC_NO_TRUNC: + return _PC_NO_TRUNC; + + case SVR4_PC_VDISABLE: + return _PC_VDISABLE; + + case SVR4_PC_CHOWN_RESTRICTED: + return _PC_CHOWN_RESTRICTED; + case SVR4_PC_SYNC_IO: +#if defined(_PC_SYNC_IO) + return _PC_SYNC_IO; +#else + return 0; +#endif + case SVR4_PC_ASYNC_IO: + case SVR4_PC_PRIO_IO: + /* Not supported */ + return 0; + + default: + /* Invalid */ + return -1; + } +} + + +int +svr4_sys_pathconf(td, uap) + struct thread *td; + struct svr4_sys_pathconf_args *uap; +{ + char *path; + int error, name; + + name = svr4_to_bsd_pathconf(uap->name); + + switch (name) { + case -1: + td->td_retval[0] = -1; + return (EINVAL); + case 0: + td->td_retval[0] = 0; + return (0); + default: + CHECKALTEXIST(td, uap->path, &path); + error = kern_pathconf(td, path, UIO_SYSSPACE, name, FOLLOW); + free(path, M_TEMP); + return (error); + } +} + + +int +svr4_sys_fpathconf(td, uap) + struct thread *td; + struct svr4_sys_fpathconf_args *uap; +{ + register_t *retval = td->td_retval; + + uap->name = svr4_to_bsd_pathconf(uap->name); + + switch (uap->name) { + case -1: + *retval = -1; + return EINVAL; + case 0: + *retval = 0; + return 0; + default: + return sys_fpathconf(td, (struct fpathconf_args *)uap); + } +} diff --git a/sys/compat/svr4/svr4_stat.h b/sys/compat/svr4/svr4_stat.h new file mode 100644 index 0000000..03d6e3c --- /dev/null +++ b/sys/compat/svr4/svr4_stat.h @@ -0,0 +1,105 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_STAT_H_ +#define _SVR4_STAT_H_ + +#include <compat/svr4/svr4_types.h> +#include <sys/stat.h> + +struct svr4_stat { + svr4_o_dev_t st_dev; + svr4_o_ino_t st_ino; + svr4_o_mode_t st_mode; + svr4_o_nlink_t st_nlink; + svr4_o_uid_t st_uid; + svr4_o_gid_t st_gid; + svr4_o_dev_t st_rdev; + svr4_off_t st_size; + svr4_time_t st_atim; + svr4_time_t st_mtim; + svr4_time_t st_ctim; +}; + +struct svr4_xstat { + svr4_dev_t st_dev; + long st_pad1[3]; + svr4_ino_t st_ino; + svr4_mode_t st_mode; + svr4_nlink_t st_nlink; + svr4_uid_t st_uid; + svr4_gid_t st_gid; + svr4_dev_t st_rdev; + long st_pad2[2]; + svr4_off_t st_size; + long st_pad3; + svr4_timestruc_t st_atim; + svr4_timestruc_t st_mtim; + svr4_timestruc_t st_ctim; + long st_blksize; + svr4_blkcnt_t st_blocks; + char st_fstype[16]; + long st_pad4[8]; +}; + +struct svr4_stat64 { + svr4_dev_t st_dev; + long st_pad1[3]; + svr4_ino64_t st_ino; + svr4_mode_t st_mode; + svr4_nlink_t st_nlink; + svr4_uid_t st_uid; + svr4_gid_t st_gid; + svr4_dev_t st_rdev; + long st_pad2[2]; + svr4_off64_t st_size; + svr4_timestruc_t st_atim; + svr4_timestruc_t st_mtim; + svr4_timestruc_t st_ctim; + long st_blksize; + svr4_blkcnt64_t st_blocks; + char st_fstype[16]; + long st_pad4[8]; +}; + +#define SVR4_PC_LINK_MAX 1 +#define SVR4_PC_MAX_CANON 2 +#define SVR4_PC_MAX_INPUT 3 +#define SVR4_PC_NAME_MAX 4 +#define SVR4_PC_PATH_MAX 5 +#define SVR4_PC_PIPE_BUF 6 +#define SVR4_PC_NO_TRUNC 7 +#define SVR4_PC_VDISABLE 8 +#define SVR4_PC_CHOWN_RESTRICTED 9 +#define SVR4_PC_ASYNC_IO 10 +#define SVR4_PC_PRIO_IO 11 +#define SVR4_PC_SYNC_IO 12 + +#endif /* !_SVR4_STAT_H_ */ diff --git a/sys/compat/svr4/svr4_statvfs.h b/sys/compat/svr4/svr4_statvfs.h new file mode 100644 index 0000000..7db9655 --- /dev/null +++ b/sys/compat/svr4/svr4_statvfs.h @@ -0,0 +1,72 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_STATVFS_H_ +#define _SVR4_STATVFS_H_ + +typedef struct svr4_statvfs { + u_long f_bsize; + u_long f_frsize; + svr4_fsblkcnt_t f_blocks; + svr4_fsblkcnt_t f_bfree; + svr4_fsblkcnt_t f_bavail; + svr4_fsblkcnt_t f_files; + svr4_fsblkcnt_t f_ffree; + svr4_fsblkcnt_t f_favail; + u_long f_fsid; + char f_basetype[16]; + u_long f_flag; + u_long f_namemax; + char f_fstr[32]; + u_long f_filler[16]; +} svr4_statvfs_t; + +typedef struct svr4_statvfs64 { + u_long f_bsize; + u_long f_frsize; + svr4_fsblkcnt64_t f_blocks; + svr4_fsblkcnt64_t f_bfree; + svr4_fsblkcnt64_t f_bavail; + svr4_fsblkcnt64_t f_files; + svr4_fsblkcnt64_t f_ffree; + svr4_fsblkcnt64_t f_favail; + u_long f_fsid; + char f_basetype[16]; + u_long f_flag; + u_long f_namemax; + char f_fstr[32]; + u_long f_filler[16]; +} svr4_statvfs64_t; + +#define SVR4_ST_RDONLY 0x01 +#define SVR4_ST_NOSUID 0x02 +#define SVR4_ST_NOTRUNC 0x04 + +#endif /* !_SVR4_STATVFS_H_ */ diff --git a/sys/compat/svr4/svr4_stream.c b/sys/compat/svr4/svr4_stream.c new file mode 100644 index 0000000..1c7e83e --- /dev/null +++ b/sys/compat/svr4/svr4_stream.c @@ -0,0 +1,2038 @@ +/*- + * Copyright (c) 1998 Mark Newton. All rights reserved. + * Copyright (c) 1994, 1996 Christos Zoulas. 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 Christos Zoulas. + * 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 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. + */ + +/* + * Pretend that we have streams... + * Yes, this is gross. + * + * ToDo: The state machine for getmsg needs re-thinking + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_compat.h" +#include "opt_ktrace.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/capability.h> +#include <sys/fcntl.h> +#include <sys/filedesc.h> +#include <sys/filio.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/file.h> /* Must come after sys/malloc.h */ +#include <sys/mbuf.h> +#include <sys/mutex.h> +#include <sys/proc.h> +#include <sys/protosw.h> +#include <sys/signal.h> +#include <sys/signalvar.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/stat.h> +#include <sys/syscallsubr.h> +#include <sys/sysproto.h> +#include <sys/uio.h> +#include <sys/ktrace.h> /* Must come after sys/uio.h */ +#include <sys/un.h> + +#include <netinet/in.h> + +#include <compat/svr4/svr4.h> +#include <compat/svr4/svr4_types.h> +#include <compat/svr4/svr4_util.h> +#include <compat/svr4/svr4_signal.h> +#include <compat/svr4/svr4_proto.h> +#include <compat/svr4/svr4_stropts.h> +#include <compat/svr4/svr4_timod.h> +#include <compat/svr4/svr4_sockmod.h> +#include <compat/svr4/svr4_ioctl.h> +#include <compat/svr4/svr4_socket.h> + +/* Utils */ +static int clean_pipe(struct thread *, char *); +static void getparm(struct file *, struct svr4_si_sockparms *); +static int svr4_do_putmsg(struct thread *, struct svr4_sys_putmsg_args *, + struct file *); +static int svr4_do_getmsg(struct thread *, struct svr4_sys_getmsg_args *, + struct file *); + +/* Address Conversions */ +static void sockaddr_to_netaddr_in(struct svr4_strmcmd *, + const struct sockaddr_in *); +static void sockaddr_to_netaddr_un(struct svr4_strmcmd *, + const struct sockaddr_un *); +static void netaddr_to_sockaddr_in(struct sockaddr_in *, + const struct svr4_strmcmd *); +static void netaddr_to_sockaddr_un(struct sockaddr_un *, + const struct svr4_strmcmd *); + +/* stream ioctls */ +static int i_nread(struct file *, struct thread *, register_t *, int, + u_long, caddr_t); +static int i_fdinsert(struct file *, struct thread *, register_t *, int, + u_long, caddr_t); +static int i_str(struct file *, struct thread *, register_t *, int, + u_long, caddr_t); +static int i_setsig(struct file *, struct thread *, register_t *, int, + u_long, caddr_t); +static int i_getsig(struct file *, struct thread *, register_t *, int, + u_long, caddr_t); +static int _i_bind_rsvd(struct file *, struct thread *, register_t *, int, + u_long, caddr_t); +static int _i_rele_rsvd(struct file *, struct thread *, register_t *, int, + u_long, caddr_t); + +/* i_str sockmod calls */ +static int sockmod(struct file *, int, struct svr4_strioctl *, + struct thread *); +static int si_listen(struct file *, int, struct svr4_strioctl *, + struct thread *); +static int si_ogetudata(struct file *, int, struct svr4_strioctl *, + struct thread *); +static int si_sockparams(struct file *, int, struct svr4_strioctl *, + struct thread *); +static int si_shutdown (struct file *, int, struct svr4_strioctl *, + struct thread *); +static int si_getudata(struct file *, int, struct svr4_strioctl *, + struct thread *); + +/* i_str timod calls */ +static int timod(struct file *, int, struct svr4_strioctl *, struct thread *); +static int ti_getinfo(struct file *, int, struct svr4_strioctl *, + struct thread *); +static int ti_bind(struct file *, int, struct svr4_strioctl *, struct thread *); + +#ifdef DEBUG_SVR4 +static void bufprint(u_char *, size_t); +static int show_ioc(const char *, struct svr4_strioctl *); +static int show_strbuf(struct svr4_strbuf *); +static void show_msg(const char *, int, struct svr4_strbuf *, + struct svr4_strbuf *, int); + +static void +bufprint(buf, len) + u_char *buf; + size_t len; +{ + size_t i; + + uprintf("\n\t"); + for (i = 0; i < len; i++) { + uprintf("%x ", buf[i]); + if (i && (i % 16) == 0) + uprintf("\n\t"); + } +} + +static int +show_ioc(str, ioc) + const char *str; + struct svr4_strioctl *ioc; +{ + u_char *ptr = NULL; + int len; + int error; + + len = ioc->len; + if (len > 1024) + len = 1024; + + if (len > 0) { + ptr = (u_char *) malloc(len, M_TEMP, M_WAITOK); + if ((error = copyin(ioc->buf, ptr, len)) != 0) { + free((char *) ptr, M_TEMP); + return error; + } + } + + uprintf("%s cmd = %ld, timeout = %d, len = %d, buf = %p { ", + str, ioc->cmd, ioc->timeout, ioc->len, ioc->buf); + + if (ptr != NULL) + bufprint(ptr, len); + + uprintf("}\n"); + + if (ptr != NULL) + free((char *) ptr, M_TEMP); + return 0; +} + + +static int +show_strbuf(str) + struct svr4_strbuf *str; +{ + int error; + u_char *ptr = NULL; + int maxlen = str->maxlen; + int len = str->len; + + if (maxlen > 8192) + maxlen = 8192; + + if (maxlen < 0) + maxlen = 0; + + if (len >= maxlen) + len = maxlen; + + if (len > 0) { + ptr = (u_char *) malloc(len, M_TEMP, M_WAITOK); + + if ((error = copyin(str->buf, ptr, len)) != 0) { + free((char *) ptr, M_TEMP); + return error; + } + } + + uprintf(", { %d, %d, %p=[ ", str->maxlen, str->len, str->buf); + + if (ptr) + bufprint(ptr, len); + + uprintf("]}"); + + if (ptr) + free((char *) ptr, M_TEMP); + + return 0; +} + + +static void +show_msg(str, fd, ctl, dat, flags) + const char *str; + int fd; + struct svr4_strbuf *ctl; + struct svr4_strbuf *dat; + int flags; +{ + struct svr4_strbuf buf; + int error; + + uprintf("%s(%d", str, fd); + if (ctl != NULL) { + if ((error = copyin(ctl, &buf, sizeof(buf))) != 0) + return; + show_strbuf(&buf); + } + else + uprintf(", NULL"); + + if (dat != NULL) { + if ((error = copyin(dat, &buf, sizeof(buf))) != 0) + return; + show_strbuf(&buf); + } + else + uprintf(", NULL"); + + uprintf(", %x);\n", flags); +} + +#endif /* DEBUG_SVR4 */ + +/* + * We are faced with an interesting situation. On svr4 unix sockets + * are really pipes. But we really have sockets, and we might as + * well use them. At the point where svr4 calls TI_BIND, it has + * already created a named pipe for the socket using mknod(2). + * We need to create a socket with the same name when we bind, + * so we need to remove the pipe before, otherwise we'll get address + * already in use. So we *carefully* remove the pipe, to avoid + * using this as a random file removal tool. We use system calls + * to avoid code duplication. + */ +static int +clean_pipe(td, path) + struct thread *td; + char *path; +{ + struct stat st; + int error; + + error = kern_lstat(td, path, UIO_SYSSPACE, &st); + + /* + * Make sure we are dealing with a mode 0 named pipe. + */ + if ((st.st_mode & S_IFMT) != S_IFIFO) + return (0); + + if ((st.st_mode & ALLPERMS) != 0) + return (0); + + error = kern_unlink(td, path, UIO_SYSSPACE); + if (error) + DPRINTF(("clean_pipe: unlink failed %d\n", error)); + return (error); +} + + +static void +sockaddr_to_netaddr_in(sc, sain) + struct svr4_strmcmd *sc; + const struct sockaddr_in *sain; +{ + struct svr4_netaddr_in *na; + na = SVR4_ADDROF(sc); + + na->family = sain->sin_family; + na->port = sain->sin_port; + na->addr = sain->sin_addr.s_addr; + DPRINTF(("sockaddr_in -> netaddr %d %d %lx\n", na->family, na->port, + na->addr)); +} + + +static void +sockaddr_to_netaddr_un(sc, saun) + struct svr4_strmcmd *sc; + const struct sockaddr_un *saun; +{ + struct svr4_netaddr_un *na; + char *dst, *edst = ((char *) sc) + sc->offs + sizeof(na->family) + 1 - + sizeof(*sc); + const char *src; + + na = SVR4_ADDROF(sc); + na->family = saun->sun_family; + for (src = saun->sun_path, dst = na->path; (*dst++ = *src++) != '\0'; ) + if (dst == edst) + break; + DPRINTF(("sockaddr_un -> netaddr %d %s\n", na->family, na->path)); +} + + +static void +netaddr_to_sockaddr_in(sain, sc) + struct sockaddr_in *sain; + const struct svr4_strmcmd *sc; +{ + const struct svr4_netaddr_in *na; + + + na = SVR4_C_ADDROF(sc); + memset(sain, 0, sizeof(*sain)); + sain->sin_len = sizeof(*sain); + sain->sin_family = na->family; + sain->sin_port = na->port; + sain->sin_addr.s_addr = na->addr; + DPRINTF(("netaddr -> sockaddr_in %d %d %x\n", sain->sin_family, + sain->sin_port, sain->sin_addr.s_addr)); +} + + +static void +netaddr_to_sockaddr_un(saun, sc) + struct sockaddr_un *saun; + const struct svr4_strmcmd *sc; +{ + const struct svr4_netaddr_un *na; + char *dst, *edst = &saun->sun_path[sizeof(saun->sun_path) - 1]; + const char *src; + + na = SVR4_C_ADDROF(sc); + memset(saun, 0, sizeof(*saun)); + saun->sun_family = na->family; + for (src = na->path, dst = saun->sun_path; (*dst++ = *src++) != '\0'; ) + if (dst == edst) + break; + saun->sun_len = dst - saun->sun_path; + DPRINTF(("netaddr -> sockaddr_un %d %s\n", saun->sun_family, + saun->sun_path)); +} + + +static void +getparm(fp, pa) + struct file *fp; + struct svr4_si_sockparms *pa; +{ + struct svr4_strm *st; + struct socket *so; + + st = svr4_stream_get(fp); + if (st == NULL) + return; + + so = fp->f_data; + + pa->family = st->s_family; + + switch (so->so_type) { + case SOCK_DGRAM: + pa->type = SVR4_T_CLTS; + pa->protocol = IPPROTO_UDP; + DPRINTF(("getparm(dgram)\n")); + return; + + case SOCK_STREAM: + pa->type = SVR4_T_COTS; /* What about T_COTS_ORD? XXX */ + pa->protocol = IPPROTO_IP; + DPRINTF(("getparm(stream)\n")); + return; + + case SOCK_RAW: + pa->type = SVR4_T_CLTS; + pa->protocol = IPPROTO_RAW; + DPRINTF(("getparm(raw)\n")); + return; + + default: + pa->type = 0; + pa->protocol = 0; + DPRINTF(("getparm(type %d?)\n", so->so_type)); + return; + } +} + + +static int +si_ogetudata(fp, fd, ioc, td) + struct file *fp; + int fd; + struct svr4_strioctl *ioc; + struct thread *td; +{ + int error; + struct svr4_si_oudata ud; + struct svr4_si_sockparms pa; + + if (ioc->len != sizeof(ud) && ioc->len != sizeof(ud) - sizeof(int)) { + DPRINTF(("SI_OGETUDATA: Wrong size %d != %d\n", + sizeof(ud), ioc->len)); + return EINVAL; + } + + if ((error = copyin(ioc->buf, &ud, sizeof(ud))) != 0) + return error; + + getparm(fp, &pa); + + switch (pa.family) { + case AF_INET: + ud.tidusize = 16384; + ud.addrsize = sizeof(struct svr4_sockaddr_in); + if (pa.type == SVR4_SOCK_STREAM) + ud.etsdusize = 1; + else + ud.etsdusize = 0; + break; + + case AF_LOCAL: + ud.tidusize = 65536; + ud.addrsize = 128; + ud.etsdusize = 128; + break; + + default: + DPRINTF(("SI_OGETUDATA: Unsupported address family %d\n", + pa.family)); + return ENOSYS; + } + + /* I have no idea what these should be! */ + ud.optsize = 128; + ud.tsdusize = 128; + + ud.servtype = pa.type; + + /* XXX: Fixme */ + ud.so_state = 0; + ud.so_options = 0; + return copyout(&ud, ioc->buf, ioc->len); +} + + +static int +si_sockparams(fp, fd, ioc, td) + struct file *fp; + int fd; + struct svr4_strioctl *ioc; + struct thread *td; +{ + struct svr4_si_sockparms pa; + + getparm(fp, &pa); + return copyout(&pa, ioc->buf, sizeof(pa)); +} + + +static int +si_listen(fp, fd, ioc, td) + struct file *fp; + int fd; + struct svr4_strioctl *ioc; + struct thread *td; +{ + int error; + struct svr4_strm *st = svr4_stream_get(fp); + struct svr4_strmcmd lst; + struct listen_args la; + + if (st == NULL) + return EINVAL; + + if (ioc->len < 0 || ioc->len > sizeof(lst)) + return EINVAL; + + if ((error = copyin(ioc->buf, &lst, ioc->len)) != 0) + return error; + + if (lst.cmd != SVR4_TI_OLD_BIND_REQUEST) { + DPRINTF(("si_listen: bad request %ld\n", lst.cmd)); + return EINVAL; + } + + /* + * We are making assumptions again... + */ + la.s = fd; + DPRINTF(("SI_LISTEN: fileno %d backlog = %d\n", fd, 5)); + la.backlog = 5; + + if ((error = sys_listen(td, &la)) != 0) { + DPRINTF(("SI_LISTEN: listen failed %d\n", error)); + return error; + } + + st->s_cmd = SVR4_TI__ACCEPT_WAIT; + lst.cmd = SVR4_TI_BIND_REPLY; + + switch (st->s_family) { + case AF_INET: + /* XXX: Fill the length here */ + break; + + case AF_LOCAL: + lst.len = 140; + lst.pad[28] = 0x00000000; /* magic again */ + lst.pad[29] = 0x00000800; /* magic again */ + lst.pad[30] = 0x80001400; /* magic again */ + break; + + default: + DPRINTF(("SI_LISTEN: Unsupported address family %d\n", + st->s_family)); + return ENOSYS; + } + + + if ((error = copyout(&lst, ioc->buf, ioc->len)) != 0) + return error; + + return 0; +} + + +static int +si_getudata(fp, fd, ioc, td) + struct file *fp; + int fd; + struct svr4_strioctl *ioc; + struct thread *td; +{ + int error; + struct svr4_si_udata ud; + + if (sizeof(ud) != ioc->len) { + DPRINTF(("SI_GETUDATA: Wrong size %d != %d\n", + sizeof(ud), ioc->len)); + return EINVAL; + } + + if ((error = copyin(ioc->buf, &ud, sizeof(ud))) != 0) + return error; + + getparm(fp, &ud.sockparms); + + switch (ud.sockparms.family) { + case AF_INET: + DPRINTF(("getudata_inet\n")); + ud.tidusize = 16384; + ud.tsdusize = 16384; + ud.addrsize = sizeof(struct svr4_sockaddr_in); + if (ud.sockparms.type == SVR4_SOCK_STREAM) + ud.etsdusize = 1; + else + ud.etsdusize = 0; + ud.optsize = 0; + break; + + case AF_LOCAL: + DPRINTF(("getudata_local\n")); + ud.tidusize = 65536; + ud.tsdusize = 128; + ud.addrsize = 128; + ud.etsdusize = 128; + ud.optsize = 128; + break; + + default: + DPRINTF(("SI_GETUDATA: Unsupported address family %d\n", + ud.sockparms.family)); + return ENOSYS; + } + + + ud.servtype = ud.sockparms.type; + DPRINTF(("ud.servtype = %d\n", ud.servtype)); + /* XXX: Fixme */ + ud.so_state = 0; + ud.so_options = 0; + return copyout(&ud, ioc->buf, sizeof(ud)); +} + + +static int +si_shutdown(fp, fd, ioc, td) + struct file *fp; + int fd; + struct svr4_strioctl *ioc; + struct thread *td; +{ + int error; + struct shutdown_args ap; + + if (ioc->len != sizeof(ap.how)) { + DPRINTF(("SI_SHUTDOWN: Wrong size %d != %d\n", + sizeof(ap.how), ioc->len)); + return EINVAL; + } + + if ((error = copyin(ioc->buf, &ap.how, ioc->len)) != 0) + return error; + + ap.s = fd; + + return sys_shutdown(td, &ap); +} + + +static int +sockmod(fp, fd, ioc, td) + struct file *fp; + int fd; + struct svr4_strioctl *ioc; + struct thread *td; +{ + switch (ioc->cmd) { + case SVR4_SI_OGETUDATA: + DPRINTF(("SI_OGETUDATA\n")); + return si_ogetudata(fp, fd, ioc, td); + + case SVR4_SI_SHUTDOWN: + DPRINTF(("SI_SHUTDOWN\n")); + return si_shutdown(fp, fd, ioc, td); + + case SVR4_SI_LISTEN: + DPRINTF(("SI_LISTEN\n")); + return si_listen(fp, fd, ioc, td); + + case SVR4_SI_SETMYNAME: + DPRINTF(("SI_SETMYNAME\n")); + return 0; + + case SVR4_SI_SETPEERNAME: + DPRINTF(("SI_SETPEERNAME\n")); + return 0; + + case SVR4_SI_GETINTRANSIT: + DPRINTF(("SI_GETINTRANSIT\n")); + return 0; + + case SVR4_SI_TCL_LINK: + DPRINTF(("SI_TCL_LINK\n")); + return 0; + + case SVR4_SI_TCL_UNLINK: + DPRINTF(("SI_TCL_UNLINK\n")); + return 0; + + case SVR4_SI_SOCKPARAMS: + DPRINTF(("SI_SOCKPARAMS\n")); + return si_sockparams(fp, fd, ioc, td); + + case SVR4_SI_GETUDATA: + DPRINTF(("SI_GETUDATA\n")); + return si_getudata(fp, fd, ioc, td); + + default: + DPRINTF(("Unknown sockmod ioctl %lx\n", ioc->cmd)); + return 0; + + } +} + + +static int +ti_getinfo(fp, fd, ioc, td) + struct file *fp; + int fd; + struct svr4_strioctl *ioc; + struct thread *td; +{ + int error; + struct svr4_infocmd info; + + memset(&info, 0, sizeof(info)); + + if (ioc->len < 0 || ioc->len > sizeof(info)) + return EINVAL; + + if ((error = copyin(ioc->buf, &info, ioc->len)) != 0) + return error; + + if (info.cmd != SVR4_TI_INFO_REQUEST) + return EINVAL; + + info.cmd = SVR4_TI_INFO_REPLY; + info.tsdu = 0; + info.etsdu = 1; + info.cdata = -2; + info.ddata = -2; + info.addr = 16; + info.opt = -1; + info.tidu = 16384; + info.serv = 2; + info.current = 0; + info.provider = 2; + + ioc->len = sizeof(info); + if ((error = copyout(&info, ioc->buf, ioc->len)) != 0) + return error; + + return 0; +} + + +static int +ti_bind(fp, fd, ioc, td) + struct file *fp; + int fd; + struct svr4_strioctl *ioc; + struct thread *td; +{ + int error; + struct svr4_strm *st = svr4_stream_get(fp); + struct sockaddr_in sain; + struct sockaddr_un saun; + struct sockaddr *skp; + int sasize; + struct svr4_strmcmd bnd; + + if (st == NULL) { + DPRINTF(("ti_bind: bad file descriptor\n")); + return EINVAL; + } + + if (ioc->len < 0 || ioc->len > sizeof(bnd)) + return EINVAL; + + if ((error = copyin(ioc->buf, &bnd, ioc->len)) != 0) + return error; + + if (bnd.cmd != SVR4_TI_OLD_BIND_REQUEST) { + DPRINTF(("ti_bind: bad request %ld\n", bnd.cmd)); + return EINVAL; + } + + switch (st->s_family) { + case AF_INET: + skp = (struct sockaddr *)&sain; + sasize = sizeof(sain); + + if (bnd.offs == 0) + goto error; + + netaddr_to_sockaddr_in(&sain, &bnd); + + DPRINTF(("TI_BIND: fam %d, port %d, addr %x\n", + sain.sin_family, sain.sin_port, + sain.sin_addr.s_addr)); + break; + + case AF_LOCAL: + skp = (struct sockaddr *)&saun; + sasize = sizeof(saun); + if (bnd.offs == 0) + goto error; + + netaddr_to_sockaddr_un(&saun, &bnd); + + if (saun.sun_path[0] == '\0') + goto error; + + DPRINTF(("TI_BIND: fam %d, path %s\n", + saun.sun_family, saun.sun_path)); + + if ((error = clean_pipe(td, saun.sun_path)) != 0) + return error; + + bnd.pad[28] = 0x00001000; /* magic again */ + break; + + default: + DPRINTF(("TI_BIND: Unsupported address family %d\n", + st->s_family)); + return ENOSYS; + } + + DPRINTF(("TI_BIND: fileno %d\n", fd)); + + if ((error = kern_bind(td, fd, skp)) != 0) { + DPRINTF(("TI_BIND: bind failed %d\n", error)); + return error; + } + goto reply; + +error: + memset(&bnd, 0, sizeof(bnd)); + bnd.len = sasize + 4; + bnd.offs = 0x10; /* XXX */ + +reply: + bnd.cmd = SVR4_TI_BIND_REPLY; + + if ((error = copyout(&bnd, ioc->buf, ioc->len)) != 0) + return error; + + return 0; +} + + +static int +timod(fp, fd, ioc, td) + struct file *fp; + int fd; + struct svr4_strioctl *ioc; + struct thread *td; +{ + switch (ioc->cmd) { + case SVR4_TI_GETINFO: + DPRINTF(("TI_GETINFO\n")); + return ti_getinfo(fp, fd, ioc, td); + + case SVR4_TI_OPTMGMT: + DPRINTF(("TI_OPTMGMT\n")); + return 0; + + case SVR4_TI_BIND: + DPRINTF(("TI_BIND\n")); + return ti_bind(fp, fd, ioc, td); + + case SVR4_TI_UNBIND: + DPRINTF(("TI_UNBIND\n")); + return 0; + + default: + DPRINTF(("Unknown timod ioctl %lx\n", ioc->cmd)); + return 0; + } +} + + +int +svr4_stream_ti_ioctl(fp, td, retval, fd, cmd, dat) + struct file *fp; + struct thread *td; + register_t *retval; + int fd; + u_long cmd; + caddr_t dat; +{ + struct svr4_strbuf skb, *sub = (struct svr4_strbuf *) dat; + struct svr4_strm *st = svr4_stream_get(fp); + int error; + struct sockaddr *sa; + socklen_t sasize, oldsasize; + struct svr4_strmcmd sc; + + DPRINTF(("svr4_stream_ti_ioctl\n")); + + if (st == NULL) + return EINVAL; + + sc.offs = 0x10; + + if ((error = copyin(sub, &skb, sizeof(skb))) != 0) { + DPRINTF(("ti_ioctl: error copying in strbuf\n")); + return error; + } + + switch (st->s_family) { + case AF_INET: + sasize = sizeof(struct sockaddr_in); + break; + + case AF_LOCAL: + sasize = sizeof(struct sockaddr_un); + break; + + default: + DPRINTF(("ti_ioctl: Unsupported address family %d\n", + st->s_family)); + return ENOSYS; + } + oldsasize = sasize; + + switch (cmd) { + case SVR4_TI_GETMYNAME: + DPRINTF(("TI_GETMYNAME\n")); + { + error = kern_getsockname(td, fd, &sa, &sasize); + if (error) { + DPRINTF(("ti_ioctl: getsockname error\n")); + return error; + } + } + break; + + case SVR4_TI_GETPEERNAME: + DPRINTF(("TI_GETPEERNAME\n")); + { + error = kern_getpeername(td, fd, &sa, &sasize); + if (error) { + DPRINTF(("ti_ioctl: getpeername error\n")); + return error; + } + } + break; + + case SVR4_TI_SETMYNAME: + DPRINTF(("TI_SETMYNAME\n")); + return 0; + + case SVR4_TI_SETPEERNAME: + DPRINTF(("TI_SETPEERNAME\n")); + return 0; + default: + DPRINTF(("ti_ioctl: Unknown ioctl %lx\n", cmd)); + return ENOSYS; + } + + if (sasize < 0 || sasize > oldsasize) { + free(sa, M_SONAME); + return EINVAL; + } + + switch (st->s_family) { + case AF_INET: + sockaddr_to_netaddr_in(&sc, (struct sockaddr_in *)sa); + skb.len = sasize; + break; + + case AF_LOCAL: + sockaddr_to_netaddr_un(&sc, (struct sockaddr_un *)sa); + skb.len = sasize + 4; + break; + + default: + free(sa, M_SONAME); + return ENOSYS; + } + free(sa, M_SONAME); + + if ((error = copyout(SVR4_ADDROF(&sc), skb.buf, sasize)) != 0) { + DPRINTF(("ti_ioctl: error copying out socket data\n")); + return error; + } + + + if ((error = copyout(&skb, sub, sizeof(skb))) != 0) { + DPRINTF(("ti_ioctl: error copying out strbuf\n")); + return error; + } + + return error; +} + + + + +static int +i_nread(fp, td, retval, fd, cmd, dat) + struct file *fp; + struct thread *td; + register_t *retval; + int fd; + u_long cmd; + caddr_t dat; +{ + int error; + int nread = 0; + + /* + * We are supposed to return the message length in nread, and the + * number of messages in retval. We don't have the notion of number + * of stream messages, so we just find out if we have any bytes waiting + * for us, and if we do, then we assume that we have at least one + * message waiting for us. + */ + if ((error = fo_ioctl(fp, FIONREAD, (caddr_t) &nread, td->td_ucred, + td)) != 0) + return error; + + if (nread != 0) + *retval = 1; + else + *retval = 0; + + return copyout(&nread, dat, sizeof(nread)); +} + +static int +i_fdinsert(fp, td, retval, fd, cmd, dat) + struct file *fp; + struct thread *td; + register_t *retval; + int fd; + u_long cmd; + caddr_t dat; +{ + /* + * Major hack again here. We assume that we are using this to + * implement accept(2). If that is the case, we have already + * called accept, and we have stored the file descriptor in + * afd. We find the file descriptor that the code wants to use + * in fd insert, and then we dup2() our accepted file descriptor + * to it. + */ + int error; + struct svr4_strm *st = svr4_stream_get(fp); + struct svr4_strfdinsert fdi; + struct dup2_args d2p; + + if (st == NULL) { + DPRINTF(("fdinsert: bad file type\n")); + return EINVAL; + } + + mtx_lock(&Giant); + if (st->s_afd == -1) { + DPRINTF(("fdinsert: accept fd not found\n")); + mtx_unlock(&Giant); + return ENOENT; + } + + if ((error = copyin(dat, &fdi, sizeof(fdi))) != 0) { + DPRINTF(("fdinsert: copyin failed %d\n", error)); + mtx_unlock(&Giant); + return error; + } + + d2p.from = st->s_afd; + d2p.to = fdi.fd; + + if ((error = sys_dup2(td, &d2p)) != 0) { + DPRINTF(("fdinsert: dup2(%d, %d) failed %d\n", + st->s_afd, fdi.fd, error)); + mtx_unlock(&Giant); + return error; + } + + if ((error = kern_close(td, st->s_afd)) != 0) { + DPRINTF(("fdinsert: close(%d) failed %d\n", + st->s_afd, error)); + mtx_unlock(&Giant); + return error; + } + + st->s_afd = -1; + mtx_unlock(&Giant); + + *retval = 0; + return 0; +} + + +static int +_i_bind_rsvd(fp, td, retval, fd, cmd, dat) + struct file *fp; + struct thread *td; + register_t *retval; + int fd; + u_long cmd; + caddr_t dat; +{ + struct mkfifo_args ap; + + /* + * This is a supposed to be a kernel and library only ioctl. + * It gets called before ti_bind, when we have a unix + * socket, to physically create the socket transport and + * ``reserve'' it. I don't know how this get reserved inside + * the kernel, but we are going to create it nevertheless. + */ + ap.path = dat; + ap.mode = S_IFIFO; + + return sys_mkfifo(td, &ap); +} + +static int +_i_rele_rsvd(fp, td, retval, fd, cmd, dat) + struct file *fp; + struct thread *td; + register_t *retval; + int fd; + u_long cmd; + caddr_t dat; +{ + struct unlink_args ap; + + /* + * This is a supposed to be a kernel and library only ioctl. + * I guess it is supposed to release the socket. + */ + ap.path = dat; + + return sys_unlink(td, &ap); +} + +static int +i_str(fp, td, retval, fd, cmd, dat) + struct file *fp; + struct thread *td; + register_t *retval; + int fd; + u_long cmd; + caddr_t dat; +{ + int error; + struct svr4_strioctl ioc; + + if ((error = copyin(dat, &ioc, sizeof(ioc))) != 0) + return error; + +#ifdef DEBUG_SVR4 + if ((error = show_ioc(">", &ioc)) != 0) + return error; +#endif /* DEBUG_SVR4 */ + + switch (ioc.cmd & 0xff00) { + case SVR4_SIMOD: + if ((error = sockmod(fp, fd, &ioc, td)) != 0) + return error; + break; + + case SVR4_TIMOD: + if ((error = timod(fp, fd, &ioc, td)) != 0) + return error; + break; + + default: + DPRINTF(("Unimplemented module %c %ld\n", + (char) (cmd >> 8), cmd & 0xff)); + return 0; + } + +#ifdef DEBUG_SVR4 + if ((error = show_ioc("<", &ioc)) != 0) + return error; +#endif /* DEBUG_SVR4 */ + return copyout(&ioc, dat, sizeof(ioc)); +} + +static int +i_setsig(fp, td, retval, fd, cmd, dat) + struct file *fp; + struct thread *td; + register_t *retval; + int fd; + u_long cmd; + caddr_t dat; +{ + /* + * This is the best we can do for now; we cannot generate + * signals only for specific events so the signal mask gets + * ignored; we save it just to pass it to a possible I_GETSIG... + * + * We alse have to fix the O_ASYNC fcntl bit, so the + * process will get SIGPOLLs. + */ + int error; + register_t oflags, flags; + struct svr4_strm *st = svr4_stream_get(fp); + + if (st == NULL) { + DPRINTF(("i_setsig: bad file descriptor\n")); + return EINVAL; + } + /* get old status flags */ + error = kern_fcntl(td, fd, F_GETFL, 0); + if (error) + return (error); + + oflags = td->td_retval[0]; + + /* update the flags */ + mtx_lock(&Giant); + if (dat != NULL) { + int mask; + + flags = oflags | O_ASYNC; + if ((error = copyin(dat, &mask, sizeof(mask))) != 0) { + DPRINTF(("i_setsig: bad eventmask pointer\n")); + return error; + } + if (mask & SVR4_S_ALLMASK) { + DPRINTF(("i_setsig: bad eventmask data %x\n", mask)); + return EINVAL; + } + st->s_eventmask = mask; + } + else { + flags = oflags & ~O_ASYNC; + st->s_eventmask = 0; + } + mtx_unlock(&Giant); + + /* set the new flags, if changed */ + if (flags != oflags) { + error = kern_fcntl(td, fd, F_SETFL, flags); + if (error) + return (error); + flags = td->td_retval[0]; + } + + /* set up SIGIO receiver if needed */ + if (dat != NULL) + return (kern_fcntl(td, fd, F_SETOWN, td->td_proc->p_pid)); + return 0; +} + +static int +i_getsig(fp, td, retval, fd, cmd, dat) + struct file *fp; + struct thread *td; + register_t *retval; + int fd; + u_long cmd; + caddr_t dat; +{ + int error, eventmask; + + if (dat != NULL) { + struct svr4_strm *st = svr4_stream_get(fp); + + if (st == NULL) { + DPRINTF(("i_getsig: bad file descriptor\n")); + return EINVAL; + } + mtx_lock(&Giant); + eventmask = st->s_eventmask; + mtx_unlock(&Giant); + if ((error = copyout(&eventmask, dat, + sizeof(eventmask))) != 0) { + DPRINTF(("i_getsig: bad eventmask pointer\n")); + return error; + } + } + return 0; +} + +int +svr4_stream_ioctl(fp, td, retval, fd, cmd, dat) + struct file *fp; + struct thread *td; + register_t *retval; + int fd; + u_long cmd; + caddr_t dat; +{ + *retval = 0; + + /* + * All the following stuff assumes "sockmod" is pushed... + */ + switch (cmd) { + case SVR4_I_NREAD: + DPRINTF(("I_NREAD\n")); + return i_nread(fp, td, retval, fd, cmd, dat); + + case SVR4_I_PUSH: + DPRINTF(("I_PUSH %p\n", dat)); +#if defined(DEBUG_SVR4) + show_strbuf((struct svr4_strbuf *)dat); +#endif + return 0; + + case SVR4_I_POP: + DPRINTF(("I_POP\n")); + return 0; + + case SVR4_I_LOOK: + DPRINTF(("I_LOOK\n")); + return 0; + + case SVR4_I_FLUSH: + DPRINTF(("I_FLUSH\n")); + return 0; + + case SVR4_I_SRDOPT: + DPRINTF(("I_SRDOPT\n")); + return 0; + + case SVR4_I_GRDOPT: + DPRINTF(("I_GRDOPT\n")); + return 0; + + case SVR4_I_STR: + DPRINTF(("I_STR\n")); + return i_str(fp, td, retval, fd, cmd, dat); + + case SVR4_I_SETSIG: + DPRINTF(("I_SETSIG\n")); + return i_setsig(fp, td, retval, fd, cmd, dat); + + case SVR4_I_GETSIG: + DPRINTF(("I_GETSIG\n")); + return i_getsig(fp, td, retval, fd, cmd, dat); + + case SVR4_I_FIND: + DPRINTF(("I_FIND\n")); + /* + * Here we are not pushing modules really, we just + * pretend all are present + */ + *retval = 0; + return 0; + + case SVR4_I_LINK: + DPRINTF(("I_LINK\n")); + return 0; + + case SVR4_I_UNLINK: + DPRINTF(("I_UNLINK\n")); + return 0; + + case SVR4_I_ERECVFD: + DPRINTF(("I_ERECVFD\n")); + return 0; + + case SVR4_I_PEEK: + DPRINTF(("I_PEEK\n")); + return 0; + + case SVR4_I_FDINSERT: + DPRINTF(("I_FDINSERT\n")); + return i_fdinsert(fp, td, retval, fd, cmd, dat); + + case SVR4_I_SENDFD: + DPRINTF(("I_SENDFD\n")); + return 0; + + case SVR4_I_RECVFD: + DPRINTF(("I_RECVFD\n")); + return 0; + + case SVR4_I_SWROPT: + DPRINTF(("I_SWROPT\n")); + return 0; + + case SVR4_I_GWROPT: + DPRINTF(("I_GWROPT\n")); + return 0; + + case SVR4_I_LIST: + DPRINTF(("I_LIST\n")); + return 0; + + case SVR4_I_PLINK: + DPRINTF(("I_PLINK\n")); + return 0; + + case SVR4_I_PUNLINK: + DPRINTF(("I_PUNLINK\n")); + return 0; + + case SVR4_I_SETEV: + DPRINTF(("I_SETEV\n")); + return 0; + + case SVR4_I_GETEV: + DPRINTF(("I_GETEV\n")); + return 0; + + case SVR4_I_STREV: + DPRINTF(("I_STREV\n")); + return 0; + + case SVR4_I_UNSTREV: + DPRINTF(("I_UNSTREV\n")); + return 0; + + case SVR4_I_FLUSHBAND: + DPRINTF(("I_FLUSHBAND\n")); + return 0; + + case SVR4_I_CKBAND: + DPRINTF(("I_CKBAND\n")); + return 0; + + case SVR4_I_GETBAND: + DPRINTF(("I_GETBANK\n")); + return 0; + + case SVR4_I_ATMARK: + DPRINTF(("I_ATMARK\n")); + return 0; + + case SVR4_I_SETCLTIME: + DPRINTF(("I_SETCLTIME\n")); + return 0; + + case SVR4_I_GETCLTIME: + DPRINTF(("I_GETCLTIME\n")); + return 0; + + case SVR4_I_CANPUT: + DPRINTF(("I_CANPUT\n")); + return 0; + + case SVR4__I_BIND_RSVD: + DPRINTF(("_I_BIND_RSVD\n")); + return _i_bind_rsvd(fp, td, retval, fd, cmd, dat); + + case SVR4__I_RELE_RSVD: + DPRINTF(("_I_RELE_RSVD\n")); + return _i_rele_rsvd(fp, td, retval, fd, cmd, dat); + + default: + DPRINTF(("unimpl cmd = %lx\n", cmd)); + break; + } + + return 0; +} + + + +int +svr4_sys_putmsg(td, uap) + struct thread *td; + struct svr4_sys_putmsg_args *uap; +{ + struct file *fp; + int error; + + if ((error = fget(td, uap->fd, CAP_SEND, &fp)) != 0) { +#ifdef DEBUG_SVR4 + uprintf("putmsg: bad fp\n"); +#endif + return EBADF; + } + error = svr4_do_putmsg(td, uap, fp); + fdrop(fp, td); + return (error); +} + +static int +svr4_do_putmsg(td, uap, fp) + struct thread *td; + struct svr4_sys_putmsg_args *uap; + struct file *fp; +{ + struct svr4_strbuf dat, ctl; + struct svr4_strmcmd sc; + struct sockaddr_in sain; + struct sockaddr_un saun; + struct sockaddr *sa; + int sasize, *retval; + struct svr4_strm *st; + int error; + + retval = td->td_retval; + +#ifdef DEBUG_SVR4 + show_msg(">putmsg", uap->fd, uap->ctl, + uap->dat, uap->flags); +#endif /* DEBUG_SVR4 */ + + if (uap->ctl != NULL) { + if ((error = copyin(uap->ctl, &ctl, sizeof(ctl))) != 0) { +#ifdef DEBUG_SVR4 + uprintf("putmsg: copyin(): %d\n", error); +#endif + return error; + } + } + else + ctl.len = -1; + + if (uap->dat != NULL) { + if ((error = copyin(uap->dat, &dat, sizeof(dat))) != 0) { +#ifdef DEBUG_SVR4 + uprintf("putmsg: copyin(): %d (2)\n", error); +#endif + return error; + } + } + else + dat.len = -1; + + /* + * Only for sockets for now. + */ + if ((st = svr4_stream_get(fp)) == NULL) { + DPRINTF(("putmsg: bad file type\n")); + return EINVAL; + } + + if (ctl.len < 0 || ctl.len > sizeof(sc)) { + DPRINTF(("putmsg: Bad control size %d != %d\n", ctl.len, + sizeof(struct svr4_strmcmd))); + return EINVAL; + } + + if ((error = copyin(ctl.buf, &sc, ctl.len)) != 0) + return error; + + switch (st->s_family) { + case AF_INET: + if (sc.len != sizeof(sain)) { + if (sc.cmd == SVR4_TI_DATA_REQUEST) { + struct write_args wa; + + /* Solaris seems to use sc.cmd = 3 to + * send "expedited" data. telnet uses + * this for options processing, sending EOF, + * etc. I'm sure other things use it too. + * I don't have any documentation + * on it, so I'm making a guess that this + * is how it works. newton@atdot.dotat.org XXX + */ + DPRINTF(("sending expedited data ??\n")); + wa.fd = uap->fd; + wa.buf = dat.buf; + wa.nbyte = dat.len; + return sys_write(td, &wa); + } + DPRINTF(("putmsg: Invalid inet length %ld\n", sc.len)); + return EINVAL; + } + netaddr_to_sockaddr_in(&sain, &sc); + sa = (struct sockaddr *)&sain; + sasize = sizeof(sain); + if (sain.sin_family != st->s_family) + error = EINVAL; + break; + + case AF_LOCAL: + if (ctl.len == 8) { + /* We are doing an accept; succeed */ + DPRINTF(("putmsg: Do nothing\n")); + *retval = 0; + return 0; + } + else { + /* Maybe we've been given a device/inode pair */ + dev_t *dev = SVR4_ADDROF(&sc); + ino_t *ino = (ino_t *) &dev[1]; + if (svr4_find_socket(td, fp, *dev, *ino, &saun) != 0) { + /* I guess we have it by name */ + netaddr_to_sockaddr_un(&saun, &sc); + } + sa = (struct sockaddr *)&saun; + sasize = sizeof(saun); + } + break; + + default: + DPRINTF(("putmsg: Unsupported address family %d\n", + st->s_family)); + return ENOSYS; + } + + mtx_lock(&Giant); + st->s_cmd = sc.cmd; + mtx_unlock(&Giant); + switch (sc.cmd) { + case SVR4_TI_CONNECT_REQUEST: /* connect */ + { + + return (kern_connect(td, uap->fd, sa)); + } + + case SVR4_TI_SENDTO_REQUEST: /* sendto */ + { + struct msghdr msg; + struct iovec aiov; + + msg.msg_name = sa; + msg.msg_namelen = sasize; + msg.msg_iov = &aiov; + msg.msg_iovlen = 1; + msg.msg_control = 0; + msg.msg_flags = 0; + aiov.iov_base = dat.buf; + aiov.iov_len = dat.len; + error = kern_sendit(td, uap->fd, &msg, uap->flags, + NULL, UIO_USERSPACE); + DPRINTF(("sendto_request error: %d\n", error)); + *retval = 0; + return error; + } + + default: + DPRINTF(("putmsg: Unimplemented command %lx\n", sc.cmd)); + return ENOSYS; + } +} + +int +svr4_sys_getmsg(td, uap) + struct thread *td; + struct svr4_sys_getmsg_args *uap; +{ + struct file *fp; + int error; + + if ((error = fget(td, uap->fd, CAP_RECV, &fp)) != 0) { +#ifdef DEBUG_SVR4 + uprintf("getmsg: bad fp\n"); +#endif + return EBADF; + } + error = svr4_do_getmsg(td, uap, fp); + fdrop(fp, td); + return (error); +} + +int +svr4_do_getmsg(td, uap, fp) + struct thread *td; + struct svr4_sys_getmsg_args *uap; + struct file *fp; +{ + struct svr4_strbuf dat, ctl; + struct svr4_strmcmd sc; + int error, *retval; + struct msghdr msg; + struct iovec aiov; + struct sockaddr_in sain; + struct sockaddr_un saun; + struct sockaddr *sa; + socklen_t sasize; + struct svr4_strm *st; + struct file *afp; + int fl; + + retval = td->td_retval; + error = 0; + afp = NULL; + + memset(&sc, 0, sizeof(sc)); + +#ifdef DEBUG_SVR4 + show_msg(">getmsg", uap->fd, uap->ctl, + uap->dat, 0); +#endif /* DEBUG_SVR4 */ + + if (uap->ctl != NULL) { + if ((error = copyin(uap->ctl, &ctl, sizeof(ctl))) != 0) + return error; + if (ctl.len < 0) + return EINVAL; + } + else { + ctl.len = -1; + ctl.maxlen = 0; + } + + if (uap->dat != NULL) { + if ((error = copyin(uap->dat, &dat, sizeof(dat))) != 0) + return error; + } + else { + dat.len = -1; + dat.maxlen = 0; + } + + /* + * Only for sockets for now. + */ + if ((st = svr4_stream_get(fp)) == NULL) { + DPRINTF(("getmsg: bad file type\n")); + return EINVAL; + } + + if (ctl.maxlen == -1 || dat.maxlen == -1) { + DPRINTF(("getmsg: Cannot handle -1 maxlen (yet)\n")); + return ENOSYS; + } + + switch (st->s_family) { + case AF_INET: + sasize = sizeof(sain); + break; + + case AF_LOCAL: + sasize = sizeof(saun); + break; + + default: + DPRINTF(("getmsg: Unsupported address family %d\n", + st->s_family)); + return ENOSYS; + } + + mtx_lock(&Giant); + switch (st->s_cmd) { + case SVR4_TI_CONNECT_REQUEST: + DPRINTF(("getmsg: TI_CONNECT_REQUEST\n")); + /* + * We do the connect in one step, so the putmsg should + * have gotten the error. + */ + sc.cmd = SVR4_TI_OK_REPLY; + sc.len = 0; + + ctl.len = 8; + dat.len = -1; + fl = 1; + st->s_cmd = sc.cmd; + break; + + case SVR4_TI_OK_REPLY: + DPRINTF(("getmsg: TI_OK_REPLY\n")); + /* + * We are immediately after a connect reply, so we send + * a connect verification. + */ + + error = kern_getpeername(td, uap->fd, &sa, &sasize); + if (error) { + mtx_unlock(&Giant); + DPRINTF(("getmsg: getpeername failed %d\n", error)); + return error; + } + + sc.cmd = SVR4_TI_CONNECT_REPLY; + sc.pad[0] = 0x4; + sc.offs = 0x18; + sc.pad[1] = 0x14; + sc.pad[2] = 0x04000402; + + switch (st->s_family) { + case AF_INET: + sc.len = sasize; + sockaddr_to_netaddr_in(&sc, (struct sockaddr_in *)sa); + break; + + case AF_LOCAL: + sc.len = sasize + 4; + sockaddr_to_netaddr_un(&sc, (struct sockaddr_un *)sa); + break; + + default: + mtx_unlock(&Giant); + free(sa, M_SONAME); + return ENOSYS; + } + free(sa, M_SONAME); + + ctl.len = 40; + dat.len = -1; + fl = 0; + st->s_cmd = sc.cmd; + break; + + case SVR4_TI__ACCEPT_OK: + DPRINTF(("getmsg: TI__ACCEPT_OK\n")); + /* + * We do the connect in one step, so the putmsg should + * have gotten the error. + */ + sc.cmd = SVR4_TI_OK_REPLY; + sc.len = 1; + + ctl.len = 8; + dat.len = -1; + fl = 1; + st->s_cmd = SVR4_TI__ACCEPT_WAIT; + break; + + case SVR4_TI__ACCEPT_WAIT: + DPRINTF(("getmsg: TI__ACCEPT_WAIT\n")); + /* + * We are after a listen, so we try to accept... + */ + + error = kern_accept(td, uap->fd, &sa, &sasize, &afp); + if (error) { + mtx_unlock(&Giant); + DPRINTF(("getmsg: accept failed %d\n", error)); + return error; + } + + st->s_afd = *retval; + + DPRINTF(("getmsg: Accept fd = %d\n", st->s_afd)); + + sc.cmd = SVR4_TI_ACCEPT_REPLY; + sc.offs = 0x18; + sc.pad[0] = 0x0; + + switch (st->s_family) { + case AF_INET: + sc.pad[1] = 0x28; + sockaddr_to_netaddr_in(&sc, (struct sockaddr_in *)&sa); + ctl.len = 40; + sc.len = sasize; + break; + + case AF_LOCAL: + sc.pad[1] = 0x00010000; + sc.pad[2] = 0xf6bcdaa0; /* I don't know what that is */ + sc.pad[3] = 0x00010000; + ctl.len = 134; + sc.len = sasize + 4; + break; + + default: + fdclose(td->td_proc->p_fd, afp, st->s_afd, td); + fdrop(afp, td); + st->s_afd = -1; + mtx_unlock(&Giant); + free(sa, M_SONAME); + return ENOSYS; + } + free(sa, M_SONAME); + + dat.len = -1; + fl = 0; + st->s_cmd = SVR4_TI__ACCEPT_OK; + break; + + case SVR4_TI_SENDTO_REQUEST: + DPRINTF(("getmsg: TI_SENDTO_REQUEST\n")); + if (ctl.maxlen > 36 && ctl.len < 36) + ctl.len = 36; + + if (ctl.len > sizeof(sc)) + ctl.len = sizeof(sc); + + if ((error = copyin(ctl.buf, &sc, ctl.len)) != 0) { + mtx_unlock(&Giant); + return error; + } + + switch (st->s_family) { + case AF_INET: + sa = (struct sockaddr *)&sain; + sockaddr_to_netaddr_in(&sc, &sain); + break; + + case AF_LOCAL: + sa = (struct sockaddr *)&saun; + sockaddr_to_netaddr_un(&sc, &saun); + break; + + default: + mtx_unlock(&Giant); + return ENOSYS; + } + + msg.msg_name = sa; + msg.msg_namelen = sasize; + msg.msg_iov = &aiov; + msg.msg_iovlen = 1; + msg.msg_control = 0; + aiov.iov_base = dat.buf; + aiov.iov_len = dat.maxlen; + msg.msg_flags = 0; + + error = kern_recvit(td, uap->fd, &msg, UIO_SYSSPACE, NULL); + + if (error) { + mtx_unlock(&Giant); + DPRINTF(("getmsg: recvit failed %d\n", error)); + return error; + } + + sc.cmd = SVR4_TI_RECVFROM_IND; + + switch (st->s_family) { + case AF_INET: + sc.len = sasize; + sockaddr_to_netaddr_in(&sc, &sain); + break; + + case AF_LOCAL: + sc.len = sasize + 4; + sockaddr_to_netaddr_un(&sc, &saun); + break; + + default: + mtx_unlock(&Giant); + return ENOSYS; + } + + dat.len = *retval; + fl = 0; + st->s_cmd = sc.cmd; + break; + + default: + st->s_cmd = sc.cmd; + if (st->s_cmd == SVR4_TI_CONNECT_REQUEST) { + struct read_args ra; + + /* More weirdness: Again, I can't find documentation + * to back this up, but when a process does a generic + * "getmsg()" call it seems that the command field is + * zero and the length of the data area is zero. I + * think processes expect getmsg() to fill in dat.len + * after reading at most dat.maxlen octets from the + * stream. Since we're using sockets I can let + * read() look after it and frob return values + * appropriately (or inappropriately :-) + * -- newton@atdot.dotat.org XXX + */ + ra.fd = uap->fd; + ra.buf = dat.buf; + ra.nbyte = dat.maxlen; + if ((error = sys_read(td, &ra)) != 0) { + mtx_unlock(&Giant); + return error; + } + dat.len = *retval; + *retval = 0; + st->s_cmd = SVR4_TI_SENDTO_REQUEST; + break; + } + mtx_unlock(&Giant); + DPRINTF(("getmsg: Unknown state %x\n", st->s_cmd)); + return EINVAL; + } + + if (uap->ctl) { + if (ctl.len > sizeof(sc)) + ctl.len = sizeof(sc); + if (ctl.len != -1) + error = copyout(&sc, ctl.buf, ctl.len); + + if (error == 0) + error = copyout(&ctl, uap->ctl, sizeof(ctl)); + } + + if (uap->dat) { + if (error == 0) + error = copyout(&dat, uap->dat, sizeof(dat)); + } + + if (uap->flags) { /* XXX: Need translation */ + if (error == 0) + error = copyout(&fl, uap->flags, sizeof(fl)); + } + + if (error) { + if (afp) { + fdclose(td->td_proc->p_fd, afp, st->s_afd, td); + fdrop(afp, td); + st->s_afd = -1; + } + mtx_unlock(&Giant); + return (error); + } + mtx_unlock(&Giant); + if (afp) + fdrop(afp, td); + + *retval = 0; + +#ifdef DEBUG_SVR4 + show_msg("<getmsg", uap->fd, uap->ctl, + uap->dat, fl); +#endif /* DEBUG_SVR4 */ + return error; +} + +int svr4_sys_send(td, uap) + struct thread *td; + struct svr4_sys_send_args *uap; +{ + struct sendto_args sta; + + sta.s = uap->s; + sta.buf = uap->buf; + sta.len = uap->len; + sta.flags = uap->flags; + sta.to = NULL; + sta.tolen = 0; + + return (sys_sendto(td, &sta)); +} + +int svr4_sys_recv(td, uap) + struct thread *td; + struct svr4_sys_recv_args *uap; +{ + struct recvfrom_args rfa; + + rfa.s = uap->s; + rfa.buf = uap->buf; + rfa.len = uap->len; + rfa.flags = uap->flags; + rfa.from = NULL; + rfa.fromlenaddr = NULL; + + return (sys_recvfrom(td, &rfa)); +} + +/* + * XXX This isn't necessary, but it's handy for inserting debug code into + * sendto(). Let's leave it here for now... + */ +int +svr4_sys_sendto(td, uap) + struct thread *td; + struct svr4_sys_sendto_args *uap; +{ + struct sendto_args sa; + + sa.s = uap->s; + sa.buf = uap->buf; + sa.len = uap->len; + sa.flags = uap->flags; + sa.to = (caddr_t)uap->to; + sa.tolen = uap->tolen; + + DPRINTF(("calling sendto()\n")); + return sys_sendto(td, &sa); +} + diff --git a/sys/compat/svr4/svr4_stropts.h b/sys/compat/svr4/svr4_stropts.h new file mode 100644 index 0000000..a96c24d --- /dev/null +++ b/sys/compat/svr4/svr4_stropts.h @@ -0,0 +1,179 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_STROPTS_H_ +#define _SVR4_STROPTS_H_ + + +struct svr4_strbuf { + int maxlen; + int len; + char *buf; +}; + +#define SVR4_STR ('S' << 8) +#define SVR4_I_NREAD (SVR4_STR| 1) +#define SVR4_I_PUSH (SVR4_STR| 2) +#define SVR4_I_POP (SVR4_STR| 3) +#define SVR4_I_LOOK (SVR4_STR| 4) +#define SVR4_I_FLUSH (SVR4_STR| 5) +#define SVR4_I_SRDOPT (SVR4_STR| 6) +#define SVR4_I_GRDOPT (SVR4_STR| 7) +#define SVR4_I_STR (SVR4_STR| 8) +#define SVR4_I_SETSIG (SVR4_STR| 9) +#define SVR4_I_GETSIG (SVR4_STR|10) +#define SVR4_I_FIND (SVR4_STR|11) +#define SVR4_I_LINK (SVR4_STR|12) +#define SVR4_I_UNLINK (SVR4_STR|13) +#define SVR4_I_ERECVFD (SVR4_STR|14) +#define SVR4_I_PEEK (SVR4_STR|15) +#define SVR4_I_FDINSERT (SVR4_STR|16) +#define SVR4_I_SENDFD (SVR4_STR|17) +#define SVR4_I_RECVFD (SVR4_STR|18) +#define SVR4_I_SWROPT (SVR4_STR|19) +#define SVR4_I_GWROPT (SVR4_STR|20) +#define SVR4_I_LIST (SVR4_STR|21) +#define SVR4_I_PLINK (SVR4_STR|22) +#define SVR4_I_PUNLINK (SVR4_STR|23) +#define SVR4_I_SETEV (SVR4_STR|24) +#define SVR4_I_GETEV (SVR4_STR|25) +#define SVR4_I_STREV (SVR4_STR|26) +#define SVR4_I_UNSTREV (SVR4_STR|27) +#define SVR4_I_FLUSHBAND (SVR4_STR|28) +#define SVR4_I_CKBAND (SVR4_STR|29) +#define SVR4_I_GETBAND (SVR4_STR|30) +#define SVR4_I_ATMARK (SVR4_STR|31) +#define SVR4_I_SETCLTIME (SVR4_STR|32) +#define SVR4_I_GETCLTIME (SVR4_STR|33) +#define SVR4_I_CANPUT (SVR4_STR|34) + +/* + * The following two ioctls are OS specific and + * undocumented. + */ +#define SVR4__I_BIND_RSVD (SVR4_STR|242) +#define SVR4__I_RELE_RSVD (SVR4_STR|243) + +/* + * Service type definitions + */ +#define SVR4_T_COTS 1 /* Connection-orieted */ +#define SVR4_T_COTS_ORD 2 /* Local connection-oriented */ +#define SVR4_T_CLTS 3 /* Connectionless */ + +/* Struct passed for SVR4_I_STR */ +struct svr4_strioctl { + u_long cmd; + int timeout; + int len; + char *buf; +}; + +/* + * Bits for I_{G,S}ETSIG + */ +#define SVR4_S_INPUT 0x0001 /* any message on read queue no HIPRI */ +#define SVR4_S_HIPRI 0x0002 /* high prio message on read queue */ +#define SVR4_S_OUTPUT 0x0004 /* write queue has free space */ +#define SVR4_S_MSG 0x0008 /* signal message in read queue head */ +#define SVR4_S_ERROR 0x0010 /* error message in read queue head */ +#define SVR4_S_HANGUP 0x0020 /* hangup message in read queue head */ +#define SVR4_S_RDNORM 0x0040 /* normal message on read queue */ +#define SVR4_S_WRNORM S_OUTPUT /* write queue has free space */ +#define SVR4_S_RDBAND 0x0080 /* out of band message on read queue */ +#define SVR4_S_WRBAND 0x0100 /* write queue has free space for oob */ +#define SVR4_S_BANDURG 0x0200 /* generate SIGURG instead of SIGPOLL */ +#define SVR4_S_ALLMASK 0x03ff /* all events mask */ + +/* + * Our internal state for the stream + * For now we keep almost nothing... In the future we can keep more + * streams state. + * + * Locking key: + * r - Read only field only set during creation + * G - Giant + */ +struct svr4_strm { + int s_family; /* (r) socket family */ + int s_cmd; /* (G) last getmsg reply or putmsg request */ + int s_afd; /* (G) last accepted fd; [for fd_insert] */ + int s_eventmask; /* (G) state info from I_SETSIG et al */ +}; + +/* + * The following structures are determined empirically. + */ +struct svr4_strmcmd { + long cmd; /* command ? */ + long len; /* Address len */ + long offs; /* Address offset */ + long pad[61]; +}; + +struct svr4_infocmd { + long cmd; + long tsdu; + long etsdu; + long cdata; + long ddata; + long addr; + long opt; + long tidu; + long serv; + long current; + long provider; +}; + +struct svr4_strfdinsert { + struct svr4_strbuf ctl; + struct svr4_strbuf data; + long flags; + int fd; + int offset; +}; + +struct svr4_netaddr_in { + u_short family; + u_short port; + u_long addr; +}; + +struct svr4_netaddr_un { + u_short family; + char path[1]; +}; + +#define SVR4_ADDROF(sc) (void *) (((char *) (sc)) + (sc)->offs) +#define SVR4_C_ADDROF(sc) (const void *) (((const char *) (sc)) + (sc)->offs) + +struct svr4_strm *svr4_stream_get(struct file *fp); + +#endif /* !_SVR4_STROPTS */ diff --git a/sys/compat/svr4/svr4_syscall.h b/sys/compat/svr4/svr4_syscall.h new file mode 100644 index 0000000..1500591 --- /dev/null +++ b/sys/compat/svr4/svr4_syscall.h @@ -0,0 +1,147 @@ +/* + * System call numbers. + * + * DO NOT EDIT-- this file is automatically generated. + * $FreeBSD$ + * created from FreeBSD: head/sys/compat/svr4/syscalls.master 227691 2011-11-19 06:35:15Z ed + */ + +#define SVR4_SYS_exit 1 +#define SVR4_SYS_fork 2 +#define SVR4_SYS_read 3 +#define SVR4_SYS_write 4 +#define SVR4_SYS_svr4_sys_open 5 +#define SVR4_SYS_close 6 +#define SVR4_SYS_svr4_sys_wait 7 +#define SVR4_SYS_svr4_sys_creat 8 +#define SVR4_SYS_link 9 +#define SVR4_SYS_unlink 10 +#define SVR4_SYS_svr4_sys_execv 11 +#define SVR4_SYS_chdir 12 +#define SVR4_SYS_svr4_sys_time 13 +#define SVR4_SYS_svr4_sys_mknod 14 +#define SVR4_SYS_chmod 15 +#define SVR4_SYS_chown 16 +#define SVR4_SYS_svr4_sys_break 17 +#define SVR4_SYS_svr4_sys_stat 18 +#define SVR4_SYS_lseek 19 +#define SVR4_SYS_getpid 20 +#define SVR4_SYS_setuid 23 +#define SVR4_SYS_getuid 24 +#define SVR4_SYS_svr4_sys_alarm 27 +#define SVR4_SYS_svr4_sys_fstat 28 +#define SVR4_SYS_svr4_sys_pause 29 +#define SVR4_SYS_svr4_sys_utime 30 +#define SVR4_SYS_svr4_sys_access 33 +#define SVR4_SYS_svr4_sys_nice 34 +#define SVR4_SYS_sync 36 +#define SVR4_SYS_svr4_sys_kill 37 +#define SVR4_SYS_svr4_sys_pgrpsys 39 +#define SVR4_SYS_dup 41 +#define SVR4_SYS_pipe 42 +#define SVR4_SYS_svr4_sys_times 43 +#define SVR4_SYS_setgid 46 +#define SVR4_SYS_getgid 47 +#define SVR4_SYS_svr4_sys_signal 48 +#define SVR4_SYS_svr4_sys_msgsys 49 +#define SVR4_SYS_svr4_sys_sysarch 50 +#define SVR4_SYS_svr4_sys_shmsys 52 +#define SVR4_SYS_svr4_sys_semsys 53 +#define SVR4_SYS_svr4_sys_ioctl 54 +#define SVR4_SYS_svr4_sys_utssys 57 +#define SVR4_SYS_fsync 58 +#define SVR4_SYS_svr4_sys_execve 59 +#define SVR4_SYS_umask 60 +#define SVR4_SYS_chroot 61 +#define SVR4_SYS_svr4_sys_fcntl 62 +#define SVR4_SYS_svr4_sys_ulimit 63 +#define SVR4_SYS_rmdir 79 +#define SVR4_SYS_mkdir 80 +#define SVR4_SYS_svr4_sys_getdents 81 +#define SVR4_SYS_svr4_sys_getmsg 85 +#define SVR4_SYS_svr4_sys_putmsg 86 +#define SVR4_SYS_svr4_sys_poll 87 +#define SVR4_SYS_svr4_sys_lstat 88 +#define SVR4_SYS_symlink 89 +#define SVR4_SYS_readlink 90 +#define SVR4_SYS_getgroups 91 +#define SVR4_SYS_setgroups 92 +#define SVR4_SYS_fchmod 93 +#define SVR4_SYS_fchown 94 +#define SVR4_SYS_svr4_sys_sigprocmask 95 +#define SVR4_SYS_svr4_sys_sigsuspend 96 +#define SVR4_SYS_svr4_sys_sigaltstack 97 +#define SVR4_SYS_svr4_sys_sigaction 98 +#define SVR4_SYS_svr4_sys_sigpending 99 +#define SVR4_SYS_svr4_sys_context 100 +#define SVR4_SYS_svr4_sys_statvfs 103 +#define SVR4_SYS_svr4_sys_fstatvfs 104 +#define SVR4_SYS_svr4_sys_waitsys 107 +#define SVR4_SYS_svr4_sys_hrtsys 109 +#define SVR4_SYS_svr4_sys_pathconf 113 +#define SVR4_SYS_svr4_sys_mmap 115 +#define SVR4_SYS_mprotect 116 +#define SVR4_SYS_munmap 117 +#define SVR4_SYS_svr4_sys_fpathconf 118 +#define SVR4_SYS_vfork 119 +#define SVR4_SYS_fchdir 120 +#define SVR4_SYS_readv 121 +#define SVR4_SYS_writev 122 +#define SVR4_SYS_svr4_sys_xstat 123 +#define SVR4_SYS_svr4_sys_lxstat 124 +#define SVR4_SYS_svr4_sys_fxstat 125 +#define SVR4_SYS_svr4_sys_xmknod 126 +#define SVR4_SYS_svr4_sys_setrlimit 128 +#define SVR4_SYS_svr4_sys_getrlimit 129 +#define SVR4_SYS_lchown 130 +#define SVR4_SYS_svr4_sys_memcntl 131 +#define SVR4_SYS_rename 134 +#define SVR4_SYS_svr4_sys_uname 135 +#define SVR4_SYS_setegid 136 +#define SVR4_SYS_svr4_sys_sysconfig 137 +#define SVR4_SYS_adjtime 138 +#define SVR4_SYS_svr4_sys_systeminfo 139 +#define SVR4_SYS_seteuid 141 +#define SVR4_SYS_svr4_sys_fchroot 153 +#define SVR4_SYS_svr4_sys_utimes 154 +#define SVR4_SYS_svr4_sys_vhangup 155 +#define SVR4_SYS_svr4_sys_gettimeofday 156 +#define SVR4_SYS_getitimer 157 +#define SVR4_SYS_setitimer 158 +#define SVR4_SYS_svr4_sys_llseek 175 +#define SVR4_SYS_svr4_sys_acl 185 +#define SVR4_SYS_svr4_sys_auditsys 186 +#define SVR4_SYS_nanosleep 199 +#define SVR4_SYS_svr4_sys_facl 200 +#define SVR4_SYS_setreuid 202 +#define SVR4_SYS_setregid 203 +#define SVR4_SYS_svr4_sys_resolvepath 209 +#define SVR4_SYS_svr4_sys_getdents64 213 +#define SVR4_SYS_svr4_sys_mmap64 214 +#define SVR4_SYS_svr4_sys_stat64 215 +#define SVR4_SYS_svr4_sys_lstat64 216 +#define SVR4_SYS_svr4_sys_fstat64 217 +#define SVR4_SYS_svr4_sys_statvfs64 218 +#define SVR4_SYS_svr4_sys_fstatvfs64 219 +#define SVR4_SYS_svr4_sys_setrlimit64 220 +#define SVR4_SYS_svr4_sys_getrlimit64 221 +#define SVR4_SYS_svr4_sys_creat64 224 +#define SVR4_SYS_svr4_sys_open64 225 +#define SVR4_SYS_svr4_sys_socket 230 +#define SVR4_SYS_socketpair 231 +#define SVR4_SYS_bind 232 +#define SVR4_SYS_listen 233 +#define SVR4_SYS_accept 234 +#define SVR4_SYS_connect 235 +#define SVR4_SYS_shutdown 236 +#define SVR4_SYS_svr4_sys_recv 237 +#define SVR4_SYS_recvfrom 238 +#define SVR4_SYS_recvmsg 239 +#define SVR4_SYS_svr4_sys_send 240 +#define SVR4_SYS_sendmsg 241 +#define SVR4_SYS_svr4_sys_sendto 242 +#define SVR4_SYS_getpeername 243 +#define SVR4_SYS_getsockname 244 +#define SVR4_SYS_getsockopt 245 +#define SVR4_SYS_setsockopt 246 +#define SVR4_SYS_MAXSYSCALL 250 diff --git a/sys/compat/svr4/svr4_syscallnames.c b/sys/compat/svr4/svr4_syscallnames.c new file mode 100644 index 0000000..dffc0cd --- /dev/null +++ b/sys/compat/svr4/svr4_syscallnames.c @@ -0,0 +1,260 @@ +/* + * System call names. + * + * DO NOT EDIT-- this file is automatically generated. + * $FreeBSD$ + * created from FreeBSD: head/sys/compat/svr4/syscalls.master 227691 2011-11-19 06:35:15Z ed + */ + +const char *svr4_syscallnames[] = { + "#0", /* 0 = unused */ + "exit", /* 1 = exit */ + "fork", /* 2 = fork */ + "read", /* 3 = read */ + "write", /* 4 = write */ + "svr4_sys_open", /* 5 = svr4_sys_open */ + "close", /* 6 = close */ + "svr4_sys_wait", /* 7 = svr4_sys_wait */ + "svr4_sys_creat", /* 8 = svr4_sys_creat */ + "link", /* 9 = link */ + "unlink", /* 10 = unlink */ + "svr4_sys_execv", /* 11 = svr4_sys_execv */ + "chdir", /* 12 = chdir */ + "svr4_sys_time", /* 13 = svr4_sys_time */ + "svr4_sys_mknod", /* 14 = svr4_sys_mknod */ + "chmod", /* 15 = chmod */ + "chown", /* 16 = chown */ + "svr4_sys_break", /* 17 = svr4_sys_break */ + "svr4_sys_stat", /* 18 = svr4_sys_stat */ + "lseek", /* 19 = lseek */ + "getpid", /* 20 = getpid */ + "#21", /* 21 = old_mount */ + "#22", /* 22 = sysv_umount */ + "setuid", /* 23 = setuid */ + "getuid", /* 24 = getuid */ + "#25", /* 25 = stime */ + "#26", /* 26 = ptrace */ + "svr4_sys_alarm", /* 27 = svr4_sys_alarm */ + "svr4_sys_fstat", /* 28 = svr4_sys_fstat */ + "svr4_sys_pause", /* 29 = svr4_sys_pause */ + "svr4_sys_utime", /* 30 = svr4_sys_utime */ + "#31", /* 31 = stty */ + "#32", /* 32 = gtty */ + "svr4_sys_access", /* 33 = svr4_sys_access */ + "svr4_sys_nice", /* 34 = svr4_sys_nice */ + "#35", /* 35 = statfs */ + "sync", /* 36 = sync */ + "svr4_sys_kill", /* 37 = svr4_sys_kill */ + "#38", /* 38 = fstatfs */ + "svr4_sys_pgrpsys", /* 39 = svr4_sys_pgrpsys */ + "#40", /* 40 = xenix */ + "dup", /* 41 = dup */ + "pipe", /* 42 = pipe */ + "svr4_sys_times", /* 43 = svr4_sys_times */ + "#44", /* 44 = profil */ + "#45", /* 45 = plock */ + "setgid", /* 46 = setgid */ + "getgid", /* 47 = getgid */ + "svr4_sys_signal", /* 48 = svr4_sys_signal */ + "svr4_sys_msgsys", /* 49 = svr4_sys_msgsys */ + "svr4_sys_sysarch", /* 50 = svr4_sys_sysarch */ + "#51", /* 51 = acct */ + "svr4_sys_shmsys", /* 52 = svr4_sys_shmsys */ + "svr4_sys_semsys", /* 53 = svr4_sys_semsys */ + "svr4_sys_ioctl", /* 54 = svr4_sys_ioctl */ + "#55", /* 55 = uadmin */ + "#56", /* 56 = exch */ + "svr4_sys_utssys", /* 57 = svr4_sys_utssys */ + "fsync", /* 58 = fsync */ + "svr4_sys_execve", /* 59 = svr4_sys_execve */ + "umask", /* 60 = umask */ + "chroot", /* 61 = chroot */ + "svr4_sys_fcntl", /* 62 = svr4_sys_fcntl */ + "svr4_sys_ulimit", /* 63 = svr4_sys_ulimit */ + "#64", /* 64 = reserved */ + "#65", /* 65 = reserved */ + "#66", /* 66 = reserved */ + "#67", /* 67 = reserved */ + "#68", /* 68 = reserved */ + "#69", /* 69 = reserved */ + "#70", /* 70 = advfs */ + "#71", /* 71 = unadvfs */ + "#72", /* 72 = rmount */ + "#73", /* 73 = rumount */ + "#74", /* 74 = rfstart */ + "#75", /* 75 = sigret */ + "#76", /* 76 = rdebug */ + "#77", /* 77 = rfstop */ + "#78", /* 78 = rfsys */ + "rmdir", /* 79 = rmdir */ + "mkdir", /* 80 = mkdir */ + "svr4_sys_getdents", /* 81 = svr4_sys_getdents */ + "#82", /* 82 = libattach */ + "#83", /* 83 = libdetach */ + "#84", /* 84 = sysfs */ + "svr4_sys_getmsg", /* 85 = svr4_sys_getmsg */ + "svr4_sys_putmsg", /* 86 = svr4_sys_putmsg */ + "svr4_sys_poll", /* 87 = svr4_sys_poll */ + "svr4_sys_lstat", /* 88 = svr4_sys_lstat */ + "symlink", /* 89 = symlink */ + "readlink", /* 90 = readlink */ + "getgroups", /* 91 = getgroups */ + "setgroups", /* 92 = setgroups */ + "fchmod", /* 93 = fchmod */ + "fchown", /* 94 = fchown */ + "svr4_sys_sigprocmask", /* 95 = svr4_sys_sigprocmask */ + "svr4_sys_sigsuspend", /* 96 = svr4_sys_sigsuspend */ + "svr4_sys_sigaltstack", /* 97 = svr4_sys_sigaltstack */ + "svr4_sys_sigaction", /* 98 = svr4_sys_sigaction */ + "svr4_sys_sigpending", /* 99 = svr4_sys_sigpending */ + "svr4_sys_context", /* 100 = svr4_sys_context */ + "#101", /* 101 = evsys */ + "#102", /* 102 = evtrapret */ + "svr4_sys_statvfs", /* 103 = svr4_sys_statvfs */ + "svr4_sys_fstatvfs", /* 104 = svr4_sys_fstatvfs */ + "#105", /* 105 = whoknows */ + "#106", /* 106 = nfssvc */ + "svr4_sys_waitsys", /* 107 = svr4_sys_waitsys */ + "#108", /* 108 = sigsendsys */ + "svr4_sys_hrtsys", /* 109 = svr4_sys_hrtsys */ + "#110", /* 110 = acancel */ + "#111", /* 111 = async */ + "#112", /* 112 = priocntlsys */ + "svr4_sys_pathconf", /* 113 = svr4_sys_pathconf */ + "#114", /* 114 = mincore */ + "svr4_sys_mmap", /* 115 = svr4_sys_mmap */ + "mprotect", /* 116 = mprotect */ + "munmap", /* 117 = munmap */ + "svr4_sys_fpathconf", /* 118 = svr4_sys_fpathconf */ + "vfork", /* 119 = vfork */ + "fchdir", /* 120 = fchdir */ + "readv", /* 121 = readv */ + "writev", /* 122 = writev */ + "svr4_sys_xstat", /* 123 = svr4_sys_xstat */ + "svr4_sys_lxstat", /* 124 = svr4_sys_lxstat */ + "svr4_sys_fxstat", /* 125 = svr4_sys_fxstat */ + "svr4_sys_xmknod", /* 126 = svr4_sys_xmknod */ + "#127", /* 127 = clocal */ + "svr4_sys_setrlimit", /* 128 = svr4_sys_setrlimit */ + "svr4_sys_getrlimit", /* 129 = svr4_sys_getrlimit */ + "lchown", /* 130 = lchown */ + "svr4_sys_memcntl", /* 131 = svr4_sys_memcntl */ + "#132", /* 132 = getpmsg */ + "#133", /* 133 = putpmsg */ + "rename", /* 134 = rename */ + "svr4_sys_uname", /* 135 = svr4_sys_uname */ + "setegid", /* 136 = setegid */ + "svr4_sys_sysconfig", /* 137 = svr4_sys_sysconfig */ + "adjtime", /* 138 = adjtime */ + "svr4_sys_systeminfo", /* 139 = svr4_sys_systeminfo */ + "#140", /* 140 = notused */ + "seteuid", /* 141 = seteuid */ + "#142", /* 142 = vtrace */ + "#143", /* 143 = { */ + "#144", /* 144 = sigtimedwait */ + "#145", /* 145 = lwp_info */ + "#146", /* 146 = yield */ + "#147", /* 147 = lwp_sema_wait */ + "#148", /* 148 = lwp_sema_post */ + "#149", /* 149 = lwp_sema_trywait */ + "#150", /* 150 = notused */ + "#151", /* 151 = notused */ + "#152", /* 152 = modctl */ + "svr4_sys_fchroot", /* 153 = svr4_sys_fchroot */ + "svr4_sys_utimes", /* 154 = svr4_sys_utimes */ + "svr4_sys_vhangup", /* 155 = svr4_sys_vhangup */ + "svr4_sys_gettimeofday", /* 156 = svr4_sys_gettimeofday */ + "getitimer", /* 157 = getitimer */ + "setitimer", /* 158 = setitimer */ + "#159", /* 159 = lwp_create */ + "#160", /* 160 = lwp_exit */ + "#161", /* 161 = lwp_suspend */ + "#162", /* 162 = lwp_continue */ + "#163", /* 163 = lwp_kill */ + "#164", /* 164 = lwp_self */ + "#165", /* 165 = lwp_getprivate */ + "#166", /* 166 = lwp_setprivate */ + "#167", /* 167 = lwp_wait */ + "#168", /* 168 = lwp_mutex_unlock */ + "#169", /* 169 = lwp_mutex_lock */ + "#170", /* 170 = lwp_cond_wait */ + "#171", /* 171 = lwp_cond_signal */ + "#172", /* 172 = lwp_cond_broadcast */ + "#173", /* 173 = { */ + "#174", /* 174 = { */ + "svr4_sys_llseek", /* 175 = svr4_sys_llseek */ + "#176", /* 176 = inst_sync */ + "#177", /* 177 = whoknows */ + "#178", /* 178 = kaio */ + "#179", /* 179 = whoknows */ + "#180", /* 180 = whoknows */ + "#181", /* 181 = whoknows */ + "#182", /* 182 = whoknows */ + "#183", /* 183 = whoknows */ + "#184", /* 184 = tsolsys */ + "svr4_sys_acl", /* 185 = svr4_sys_acl */ + "svr4_sys_auditsys", /* 186 = svr4_sys_auditsys */ + "#187", /* 187 = processor_bind */ + "#188", /* 188 = processor_info */ + "#189", /* 189 = p_online */ + "#190", /* 190 = sigqueue */ + "#191", /* 191 = clock_gettime */ + "#192", /* 192 = clock_settime */ + "#193", /* 193 = clock_getres */ + "#194", /* 194 = timer_create */ + "#195", /* 195 = timer_delete */ + "#196", /* 196 = timer_settime */ + "#197", /* 197 = timer_gettime */ + "#198", /* 198 = timer_overrun */ + "nanosleep", /* 199 = nanosleep */ + "svr4_sys_facl", /* 200 = svr4_sys_facl */ + "#201", /* 201 = door */ + "setreuid", /* 202 = setreuid */ + "setregid", /* 203 = setregid */ + "#204", /* 204 = install_utrap */ + "#205", /* 205 = signotify */ + "#206", /* 206 = schedctl */ + "#207", /* 207 = pset */ + "#208", /* 208 = whoknows */ + "svr4_sys_resolvepath", /* 209 = svr4_sys_resolvepath */ + "#210", /* 210 = signotifywait */ + "#211", /* 211 = lwp_sigredirect */ + "#212", /* 212 = lwp_alarm */ + "svr4_sys_getdents64", /* 213 = svr4_sys_getdents64 */ + "svr4_sys_mmap64", /* 214 = svr4_sys_mmap64 */ + "svr4_sys_stat64", /* 215 = svr4_sys_stat64 */ + "svr4_sys_lstat64", /* 216 = svr4_sys_lstat64 */ + "svr4_sys_fstat64", /* 217 = svr4_sys_fstat64 */ + "svr4_sys_statvfs64", /* 218 = svr4_sys_statvfs64 */ + "svr4_sys_fstatvfs64", /* 219 = svr4_sys_fstatvfs64 */ + "svr4_sys_setrlimit64", /* 220 = svr4_sys_setrlimit64 */ + "svr4_sys_getrlimit64", /* 221 = svr4_sys_getrlimit64 */ + "#222", /* 222 = pread64 */ + "#223", /* 223 = pwrite64 */ + "svr4_sys_creat64", /* 224 = svr4_sys_creat64 */ + "svr4_sys_open64", /* 225 = svr4_sys_open64 */ + "#226", /* 226 = rpcsys */ + "#227", /* 227 = whoknows */ + "#228", /* 228 = whoknows */ + "#229", /* 229 = whoknows */ + "svr4_sys_socket", /* 230 = svr4_sys_socket */ + "socketpair", /* 231 = socketpair */ + "bind", /* 232 = bind */ + "listen", /* 233 = listen */ + "accept", /* 234 = accept */ + "connect", /* 235 = connect */ + "shutdown", /* 236 = shutdown */ + "svr4_sys_recv", /* 237 = svr4_sys_recv */ + "recvfrom", /* 238 = recvfrom */ + "recvmsg", /* 239 = recvmsg */ + "svr4_sys_send", /* 240 = svr4_sys_send */ + "sendmsg", /* 241 = sendmsg */ + "svr4_sys_sendto", /* 242 = svr4_sys_sendto */ + "getpeername", /* 243 = getpeername */ + "getsockname", /* 244 = getsockname */ + "getsockopt", /* 245 = getsockopt */ + "setsockopt", /* 246 = setsockopt */ + "#247", /* 247 = sockconfig */ + "#248", /* 248 = { */ + "#249", /* 249 = { */ +}; diff --git a/sys/compat/svr4/svr4_sysconfig.h b/sys/compat/svr4/svr4_sysconfig.h new file mode 100644 index 0000000..4a26545 --- /dev/null +++ b/sys/compat/svr4/svr4_sysconfig.h @@ -0,0 +1,78 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1995 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_SYSCONFIG_H_ +#define _SVR4_SYSCONFIG_H_ + +#define SVR4_CONFIG_UNUSED_1 0x01 +#define SVR4_CONFIG_NGROUPS 0x02 +#define SVR4_CONFIG_CHILD_MAX 0x03 +#define SVR4_CONFIG_OPEN_FILES 0x04 +#define SVR4_CONFIG_POSIX_VER 0x05 +#define SVR4_CONFIG_PAGESIZE 0x06 +#define SVR4_CONFIG_CLK_TCK 0x07 +#define SVR4_CONFIG_XOPEN_VER 0x08 +#define SVR4_CONFIG_UNUSED_9 0x09 +#define SVR4_CONFIG_PROF_TCK 0x0a +#define SVR4_CONFIG_NPROC_CONF 0x0b +#define SVR4_CONFIG_NPROC_ONLN 0x0c +#define SVR4_CONFIG_AIO_LISTIO_MAX 0x0d +#define SVR4_CONFIG_AIO_MAX 0x0e +#define SVR4_CONFIG_AIO_PRIO_DELTA_MAX 0x0f +#define SVR4_CONFIG_DELAYTIMER_MAX 0x10 +#define SVR4_CONFIG_MQ_OPEN_MAX 0x11 +#define SVR4_CONFIG_MQ_PRIO_MAX 0x12 +#define SVR4_CONFIG_RTSIG_MAX 0x13 +#define SVR4_CONFIG_SEM_NSEMS_MAX 0x14 +#define SVR4_CONFIG_SEM_VALUE_MAX 0x15 +#define SVR4_CONFIG_SIGQUEUE_MAX 0x16 +#define SVR4_CONFIG_SIGRT_MIN 0x17 +#define SVR4_CONFIG_SIGRT_MAX 0x18 +#define SVR4_CONFIG_TIMER_MAX 0x19 +#define SVR4_CONFIG_PHYS_PAGES 0x1a +#define SVR4_CONFIG_AVPHYS_PAGES 0x1b +#define SVR4_CONFIG_COHERENCY 0x1c +#define SVR4_CONFIG_SPLIT_CACHE 0x1d +#define SVR4_CONFIG_ICACHESZ 0x1e +#define SVR4_CONFIG_DCACHESZ 0x1f +#define SVR4_CONFIG_ICACHELINESZ 0x20 +#define SVR4_CONFIG_DCACHELINESZ 0x21 +#define SVR4_CONFIG_ICACHEBLKSZ 0x22 +#define SVR4_CONFIG_DCACHEBLKSZ 0x23 +#define SVR4_CONFIG_DCACHETBLKSZ 0x24 +#define SVR4_CONFIG_ICACHE_ASSOC 0x25 +#define SVR4_CONFIG_DCACHE_ASSOC 0x26 +#define SVR4_CONFIG_UNUSED_2 0x27 +#define SVR4_CONFIG_UNUSED_3 0x28 +#define SVR4_CONFIG_UNUSED_4 0x29 +#define SVR4_CONFIG_MAXPID 0x2a +#define SVR4_CONFIG_STACK_PROT 0x2b + +#endif /* !_SVR4_SYSCONFIG_H_ */ diff --git a/sys/compat/svr4/svr4_sysent.c b/sys/compat/svr4/svr4_sysent.c new file mode 100644 index 0000000..1b18501 --- /dev/null +++ b/sys/compat/svr4/svr4_sysent.c @@ -0,0 +1,272 @@ +/* + * System call switch table. + * + * DO NOT EDIT-- this file is automatically generated. + * $FreeBSD$ + * created from FreeBSD: head/sys/compat/svr4/syscalls.master 227691 2011-11-19 06:35:15Z ed + */ + +#include <sys/types.h> +#include <sys/sysent.h> +#include <sys/sysproto.h> +#include <netinet/in.h> +#include <compat/svr4/svr4.h> +#include <compat/svr4/svr4_types.h> +#include <compat/svr4/svr4_signal.h> +#include <compat/svr4/svr4_proto.h> + +#define AS(name) (sizeof(struct name) / sizeof(register_t)) + +/* The casts are bogus but will do for now. */ +struct sysent svr4_sysent[] = { + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 0 = unused */ + { AS(sys_exit_args), (sy_call_t *)sys_sys_exit, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 1 = exit */ + { 0, (sy_call_t *)sys_fork, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 2 = fork */ + { AS(read_args), (sy_call_t *)sys_read, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 3 = read */ + { AS(write_args), (sy_call_t *)sys_write, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 4 = write */ + { AS(svr4_sys_open_args), (sy_call_t *)svr4_sys_open, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 5 = svr4_sys_open */ + { AS(close_args), (sy_call_t *)sys_close, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 6 = close */ + { AS(svr4_sys_wait_args), (sy_call_t *)svr4_sys_wait, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 7 = svr4_sys_wait */ + { AS(svr4_sys_creat_args), (sy_call_t *)svr4_sys_creat, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 8 = svr4_sys_creat */ + { AS(link_args), (sy_call_t *)sys_link, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 9 = link */ + { AS(unlink_args), (sy_call_t *)sys_unlink, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 10 = unlink */ + { AS(svr4_sys_execv_args), (sy_call_t *)svr4_sys_execv, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 11 = svr4_sys_execv */ + { AS(chdir_args), (sy_call_t *)sys_chdir, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 12 = chdir */ + { AS(svr4_sys_time_args), (sy_call_t *)svr4_sys_time, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 13 = svr4_sys_time */ + { AS(svr4_sys_mknod_args), (sy_call_t *)svr4_sys_mknod, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 14 = svr4_sys_mknod */ + { AS(chmod_args), (sy_call_t *)sys_chmod, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 15 = chmod */ + { AS(chown_args), (sy_call_t *)sys_chown, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 16 = chown */ + { AS(svr4_sys_break_args), (sy_call_t *)svr4_sys_break, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 17 = svr4_sys_break */ + { AS(svr4_sys_stat_args), (sy_call_t *)svr4_sys_stat, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 18 = svr4_sys_stat */ + { AS(lseek_args), (sy_call_t *)sys_lseek, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 19 = lseek */ + { 0, (sy_call_t *)sys_getpid, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 20 = getpid */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 21 = old_mount */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 22 = sysv_umount */ + { AS(setuid_args), (sy_call_t *)sys_setuid, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 23 = setuid */ + { 0, (sy_call_t *)sys_getuid, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 24 = getuid */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 25 = stime */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 26 = ptrace */ + { AS(svr4_sys_alarm_args), (sy_call_t *)svr4_sys_alarm, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 27 = svr4_sys_alarm */ + { AS(svr4_sys_fstat_args), (sy_call_t *)svr4_sys_fstat, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 28 = svr4_sys_fstat */ + { 0, (sy_call_t *)svr4_sys_pause, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 29 = svr4_sys_pause */ + { AS(svr4_sys_utime_args), (sy_call_t *)svr4_sys_utime, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 30 = svr4_sys_utime */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 31 = stty */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 32 = gtty */ + { AS(svr4_sys_access_args), (sy_call_t *)svr4_sys_access, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 33 = svr4_sys_access */ + { AS(svr4_sys_nice_args), (sy_call_t *)svr4_sys_nice, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 34 = svr4_sys_nice */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 35 = statfs */ + { 0, (sy_call_t *)sys_sync, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 36 = sync */ + { AS(svr4_sys_kill_args), (sy_call_t *)svr4_sys_kill, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 37 = svr4_sys_kill */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 38 = fstatfs */ + { AS(svr4_sys_pgrpsys_args), (sy_call_t *)svr4_sys_pgrpsys, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 39 = svr4_sys_pgrpsys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 40 = xenix */ + { AS(dup_args), (sy_call_t *)sys_dup, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 41 = dup */ + { 0, (sy_call_t *)sys_pipe, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 42 = pipe */ + { AS(svr4_sys_times_args), (sy_call_t *)svr4_sys_times, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 43 = svr4_sys_times */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 44 = profil */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 45 = plock */ + { AS(setgid_args), (sy_call_t *)sys_setgid, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 46 = setgid */ + { 0, (sy_call_t *)sys_getgid, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 47 = getgid */ + { AS(svr4_sys_signal_args), (sy_call_t *)svr4_sys_signal, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 48 = svr4_sys_signal */ + { AS(svr4_sys_msgsys_args), (sy_call_t *)svr4_sys_msgsys, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 49 = svr4_sys_msgsys */ + { AS(svr4_sys_sysarch_args), (sy_call_t *)svr4_sys_sysarch, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 50 = svr4_sys_sysarch */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 51 = acct */ + { AS(svr4_sys_shmsys_args), (sy_call_t *)svr4_sys_shmsys, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 52 = svr4_sys_shmsys */ + { AS(svr4_sys_semsys_args), (sy_call_t *)svr4_sys_semsys, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 53 = svr4_sys_semsys */ + { AS(svr4_sys_ioctl_args), (sy_call_t *)svr4_sys_ioctl, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 54 = svr4_sys_ioctl */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 55 = uadmin */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 56 = exch */ + { AS(svr4_sys_utssys_args), (sy_call_t *)svr4_sys_utssys, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 57 = svr4_sys_utssys */ + { AS(fsync_args), (sy_call_t *)sys_fsync, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 58 = fsync */ + { AS(svr4_sys_execve_args), (sy_call_t *)svr4_sys_execve, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 59 = svr4_sys_execve */ + { AS(umask_args), (sy_call_t *)sys_umask, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 60 = umask */ + { AS(chroot_args), (sy_call_t *)sys_chroot, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 61 = chroot */ + { AS(svr4_sys_fcntl_args), (sy_call_t *)svr4_sys_fcntl, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 62 = svr4_sys_fcntl */ + { AS(svr4_sys_ulimit_args), (sy_call_t *)svr4_sys_ulimit, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 63 = svr4_sys_ulimit */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 64 = reserved */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 65 = reserved */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 66 = reserved */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 67 = reserved */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 68 = reserved */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 69 = reserved */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 70 = advfs */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 71 = unadvfs */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 72 = rmount */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 73 = rumount */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 74 = rfstart */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 75 = sigret */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 76 = rdebug */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 77 = rfstop */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 78 = rfsys */ + { AS(rmdir_args), (sy_call_t *)sys_rmdir, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 79 = rmdir */ + { AS(mkdir_args), (sy_call_t *)sys_mkdir, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 80 = mkdir */ + { AS(svr4_sys_getdents_args), (sy_call_t *)svr4_sys_getdents, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 81 = svr4_sys_getdents */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 82 = libattach */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 83 = libdetach */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 84 = sysfs */ + { AS(svr4_sys_getmsg_args), (sy_call_t *)svr4_sys_getmsg, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 85 = svr4_sys_getmsg */ + { AS(svr4_sys_putmsg_args), (sy_call_t *)svr4_sys_putmsg, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 86 = svr4_sys_putmsg */ + { AS(svr4_sys_poll_args), (sy_call_t *)svr4_sys_poll, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 87 = svr4_sys_poll */ + { AS(svr4_sys_lstat_args), (sy_call_t *)svr4_sys_lstat, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 88 = svr4_sys_lstat */ + { AS(symlink_args), (sy_call_t *)sys_symlink, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 89 = symlink */ + { AS(readlink_args), (sy_call_t *)sys_readlink, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 90 = readlink */ + { AS(getgroups_args), (sy_call_t *)sys_getgroups, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 91 = getgroups */ + { AS(setgroups_args), (sy_call_t *)sys_setgroups, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 92 = setgroups */ + { AS(fchmod_args), (sy_call_t *)sys_fchmod, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 93 = fchmod */ + { AS(fchown_args), (sy_call_t *)sys_fchown, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 94 = fchown */ + { AS(svr4_sys_sigprocmask_args), (sy_call_t *)svr4_sys_sigprocmask, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 95 = svr4_sys_sigprocmask */ + { AS(svr4_sys_sigsuspend_args), (sy_call_t *)svr4_sys_sigsuspend, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 96 = svr4_sys_sigsuspend */ + { AS(svr4_sys_sigaltstack_args), (sy_call_t *)svr4_sys_sigaltstack, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 97 = svr4_sys_sigaltstack */ + { AS(svr4_sys_sigaction_args), (sy_call_t *)svr4_sys_sigaction, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 98 = svr4_sys_sigaction */ + { AS(svr4_sys_sigpending_args), (sy_call_t *)svr4_sys_sigpending, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 99 = svr4_sys_sigpending */ + { AS(svr4_sys_context_args), (sy_call_t *)svr4_sys_context, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 100 = svr4_sys_context */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 101 = evsys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 102 = evtrapret */ + { AS(svr4_sys_statvfs_args), (sy_call_t *)svr4_sys_statvfs, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 103 = svr4_sys_statvfs */ + { AS(svr4_sys_fstatvfs_args), (sy_call_t *)svr4_sys_fstatvfs, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 104 = svr4_sys_fstatvfs */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 105 = whoknows */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 106 = nfssvc */ + { AS(svr4_sys_waitsys_args), (sy_call_t *)svr4_sys_waitsys, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 107 = svr4_sys_waitsys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 108 = sigsendsys */ + { AS(svr4_sys_hrtsys_args), (sy_call_t *)svr4_sys_hrtsys, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 109 = svr4_sys_hrtsys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 110 = acancel */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 111 = async */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 112 = priocntlsys */ + { AS(svr4_sys_pathconf_args), (sy_call_t *)svr4_sys_pathconf, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 113 = svr4_sys_pathconf */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 114 = mincore */ + { AS(svr4_sys_mmap_args), (sy_call_t *)svr4_sys_mmap, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 115 = svr4_sys_mmap */ + { AS(mprotect_args), (sy_call_t *)sys_mprotect, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 116 = mprotect */ + { AS(munmap_args), (sy_call_t *)sys_munmap, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 117 = munmap */ + { AS(svr4_sys_fpathconf_args), (sy_call_t *)svr4_sys_fpathconf, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 118 = svr4_sys_fpathconf */ + { 0, (sy_call_t *)sys_vfork, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 119 = vfork */ + { AS(fchdir_args), (sy_call_t *)sys_fchdir, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 120 = fchdir */ + { AS(readv_args), (sy_call_t *)sys_readv, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 121 = readv */ + { AS(writev_args), (sy_call_t *)sys_writev, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 122 = writev */ + { AS(svr4_sys_xstat_args), (sy_call_t *)svr4_sys_xstat, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 123 = svr4_sys_xstat */ + { AS(svr4_sys_lxstat_args), (sy_call_t *)svr4_sys_lxstat, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 124 = svr4_sys_lxstat */ + { AS(svr4_sys_fxstat_args), (sy_call_t *)svr4_sys_fxstat, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 125 = svr4_sys_fxstat */ + { AS(svr4_sys_xmknod_args), (sy_call_t *)svr4_sys_xmknod, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 126 = svr4_sys_xmknod */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 127 = clocal */ + { AS(svr4_sys_setrlimit_args), (sy_call_t *)svr4_sys_setrlimit, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 128 = svr4_sys_setrlimit */ + { AS(svr4_sys_getrlimit_args), (sy_call_t *)svr4_sys_getrlimit, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 129 = svr4_sys_getrlimit */ + { AS(lchown_args), (sy_call_t *)sys_lchown, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 130 = lchown */ + { AS(svr4_sys_memcntl_args), (sy_call_t *)svr4_sys_memcntl, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 131 = svr4_sys_memcntl */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 132 = getpmsg */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 133 = putpmsg */ + { AS(rename_args), (sy_call_t *)sys_rename, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 134 = rename */ + { AS(svr4_sys_uname_args), (sy_call_t *)svr4_sys_uname, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 135 = svr4_sys_uname */ + { AS(setegid_args), (sy_call_t *)sys_setegid, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 136 = setegid */ + { AS(svr4_sys_sysconfig_args), (sy_call_t *)svr4_sys_sysconfig, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 137 = svr4_sys_sysconfig */ + { AS(adjtime_args), (sy_call_t *)sys_adjtime, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 138 = adjtime */ + { AS(svr4_sys_systeminfo_args), (sy_call_t *)svr4_sys_systeminfo, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 139 = svr4_sys_systeminfo */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 140 = notused */ + { AS(seteuid_args), (sy_call_t *)sys_seteuid, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 141 = seteuid */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 142 = vtrace */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 143 = { */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 144 = sigtimedwait */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 145 = lwp_info */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 146 = yield */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 147 = lwp_sema_wait */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 148 = lwp_sema_post */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 149 = lwp_sema_trywait */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 150 = notused */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 151 = notused */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 152 = modctl */ + { AS(svr4_sys_fchroot_args), (sy_call_t *)svr4_sys_fchroot, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 153 = svr4_sys_fchroot */ + { AS(svr4_sys_utimes_args), (sy_call_t *)svr4_sys_utimes, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 154 = svr4_sys_utimes */ + { 0, (sy_call_t *)svr4_sys_vhangup, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 155 = svr4_sys_vhangup */ + { AS(svr4_sys_gettimeofday_args), (sy_call_t *)svr4_sys_gettimeofday, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 156 = svr4_sys_gettimeofday */ + { AS(getitimer_args), (sy_call_t *)sys_getitimer, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 157 = getitimer */ + { AS(setitimer_args), (sy_call_t *)sys_setitimer, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 158 = setitimer */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 159 = lwp_create */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 160 = lwp_exit */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 161 = lwp_suspend */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 162 = lwp_continue */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 163 = lwp_kill */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 164 = lwp_self */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 165 = lwp_getprivate */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 166 = lwp_setprivate */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 167 = lwp_wait */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 168 = lwp_mutex_unlock */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 169 = lwp_mutex_lock */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 170 = lwp_cond_wait */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 171 = lwp_cond_signal */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 172 = lwp_cond_broadcast */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 173 = { */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 174 = { */ + { AS(svr4_sys_llseek_args), (sy_call_t *)svr4_sys_llseek, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 175 = svr4_sys_llseek */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 176 = inst_sync */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 177 = whoknows */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 178 = kaio */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 179 = whoknows */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 180 = whoknows */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 181 = whoknows */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 182 = whoknows */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 183 = whoknows */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 184 = tsolsys */ + { AS(svr4_sys_acl_args), (sy_call_t *)svr4_sys_acl, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 185 = svr4_sys_acl */ + { AS(svr4_sys_auditsys_args), (sy_call_t *)svr4_sys_auditsys, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 186 = svr4_sys_auditsys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 187 = processor_bind */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 188 = processor_info */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 189 = p_online */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 190 = sigqueue */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 191 = clock_gettime */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 192 = clock_settime */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 193 = clock_getres */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 194 = timer_create */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 195 = timer_delete */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 196 = timer_settime */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 197 = timer_gettime */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 198 = timer_overrun */ + { AS(nanosleep_args), (sy_call_t *)sys_nanosleep, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 199 = nanosleep */ + { AS(svr4_sys_facl_args), (sy_call_t *)svr4_sys_facl, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 200 = svr4_sys_facl */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 201 = door */ + { AS(setreuid_args), (sy_call_t *)sys_setreuid, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 202 = setreuid */ + { AS(setregid_args), (sy_call_t *)sys_setregid, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 203 = setregid */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 204 = install_utrap */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 205 = signotify */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 206 = schedctl */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 207 = pset */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 208 = whoknows */ + { AS(svr4_sys_resolvepath_args), (sy_call_t *)svr4_sys_resolvepath, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 209 = svr4_sys_resolvepath */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 210 = signotifywait */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 211 = lwp_sigredirect */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 212 = lwp_alarm */ + { AS(svr4_sys_getdents64_args), (sy_call_t *)svr4_sys_getdents64, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 213 = svr4_sys_getdents64 */ + { AS(svr4_sys_mmap64_args), (sy_call_t *)svr4_sys_mmap64, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 214 = svr4_sys_mmap64 */ + { AS(svr4_sys_stat64_args), (sy_call_t *)svr4_sys_stat64, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 215 = svr4_sys_stat64 */ + { AS(svr4_sys_lstat64_args), (sy_call_t *)svr4_sys_lstat64, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 216 = svr4_sys_lstat64 */ + { AS(svr4_sys_fstat64_args), (sy_call_t *)svr4_sys_fstat64, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 217 = svr4_sys_fstat64 */ + { AS(svr4_sys_statvfs64_args), (sy_call_t *)svr4_sys_statvfs64, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 218 = svr4_sys_statvfs64 */ + { AS(svr4_sys_fstatvfs64_args), (sy_call_t *)svr4_sys_fstatvfs64, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 219 = svr4_sys_fstatvfs64 */ + { AS(svr4_sys_setrlimit64_args), (sy_call_t *)svr4_sys_setrlimit64, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 220 = svr4_sys_setrlimit64 */ + { AS(svr4_sys_getrlimit64_args), (sy_call_t *)svr4_sys_getrlimit64, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 221 = svr4_sys_getrlimit64 */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 222 = pread64 */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 223 = pwrite64 */ + { AS(svr4_sys_creat64_args), (sy_call_t *)svr4_sys_creat64, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 224 = svr4_sys_creat64 */ + { AS(svr4_sys_open64_args), (sy_call_t *)svr4_sys_open64, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 225 = svr4_sys_open64 */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 226 = rpcsys */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 227 = whoknows */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 228 = whoknows */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 229 = whoknows */ + { AS(svr4_sys_socket_args), (sy_call_t *)svr4_sys_socket, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 230 = svr4_sys_socket */ + { AS(socketpair_args), (sy_call_t *)sys_socketpair, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 231 = socketpair */ + { AS(bind_args), (sy_call_t *)sys_bind, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 232 = bind */ + { AS(listen_args), (sy_call_t *)sys_listen, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 233 = listen */ + { AS(accept_args), (sy_call_t *)sys_accept, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 234 = accept */ + { AS(connect_args), (sy_call_t *)sys_connect, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 235 = connect */ + { AS(shutdown_args), (sy_call_t *)sys_shutdown, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 236 = shutdown */ + { AS(svr4_sys_recv_args), (sy_call_t *)svr4_sys_recv, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 237 = svr4_sys_recv */ + { AS(recvfrom_args), (sy_call_t *)sys_recvfrom, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 238 = recvfrom */ + { AS(recvmsg_args), (sy_call_t *)sys_recvmsg, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 239 = recvmsg */ + { AS(svr4_sys_send_args), (sy_call_t *)svr4_sys_send, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 240 = svr4_sys_send */ + { AS(sendmsg_args), (sy_call_t *)sys_sendmsg, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 241 = sendmsg */ + { AS(svr4_sys_sendto_args), (sy_call_t *)svr4_sys_sendto, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 242 = svr4_sys_sendto */ + { AS(getpeername_args), (sy_call_t *)sys_getpeername, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 243 = getpeername */ + { AS(getsockname_args), (sy_call_t *)sys_getsockname, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 244 = getsockname */ + { AS(getsockopt_args), (sy_call_t *)sys_getsockopt, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 245 = getsockopt */ + { AS(setsockopt_args), (sy_call_t *)sys_setsockopt, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 246 = setsockopt */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 247 = sockconfig */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 248 = { */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 249 = { */ +}; diff --git a/sys/compat/svr4/svr4_systeminfo.h b/sys/compat/svr4/svr4_systeminfo.h new file mode 100644 index 0000000..2d5288e --- /dev/null +++ b/sys/compat/svr4/svr4_systeminfo.h @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_SYSTEMINFO_H_ +#define _SVR4_SYSTEMINFO_H_ + +#define SVR4_SI_SYSNAME 1 +#define SVR4_SI_HOSTNAME 2 +#define SVR4_SI_RELEASE 3 +#define SVR4_SI_VERSION 4 +#define SVR4_SI_MACHINE 5 +#define SVR4_SI_ARCHITECTURE 6 +#define SVR4_SI_HW_SERIAL 7 +#define SVR4_SI_HW_PROVIDER 8 +#define SVR4_SI_SRPC_DOMAIN 9 +#define SVR4_SI_SET_HOSTNAME 258 +#define SVR4_SI_SET_SRPC_DOMAIN 265 +#define SVR4_SI_SET_KERB_REALM 266 +#define SVR4_SI_KERB_REALM 267 +#define SVR4_SI_PLATFORM 513 +#define SVR4_SI_ISALIST 514 + +#endif /* !_SVR4_SYSTEMINFO_H_ */ diff --git a/sys/compat/svr4/svr4_sysvec.c b/sys/compat/svr4/svr4_sysvec.c new file mode 100644 index 0000000..561a838 --- /dev/null +++ b/sys/compat/svr4/svr4_sysvec.c @@ -0,0 +1,314 @@ +/*- + * Copyright (c) 1998 Mark Newton + * 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 Christos Zoulas. + * 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 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$"); + +/* XXX we use functions that might not exist. */ +#include "opt_compat.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/sysent.h> +#include <sys/imgact.h> +#include <sys/imgact_elf.h> +#include <sys/fcntl.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/namei.h> +#include <sys/socket.h> +#include <sys/syscallsubr.h> +#include <sys/vnode.h> +#include <vm/vm.h> +#include <sys/exec.h> +#include <sys/kernel.h> +#include <machine/cpu.h> +#include <netinet/in.h> + +#include <compat/svr4/svr4.h> +#include <compat/svr4/svr4_types.h> +#include <compat/svr4/svr4_syscall.h> +#include <compat/svr4/svr4_signal.h> +#include <compat/svr4/svr4_socket.h> +#include <compat/svr4/svr4_sockio.h> +#include <compat/svr4/svr4_errno.h> +#include <compat/svr4/svr4_proto.h> +#include <compat/svr4/svr4_siginfo.h> +#include <compat/svr4/svr4_util.h> + +int bsd_to_svr4_errno[ELAST+1] = { + 0, + SVR4_EPERM, + SVR4_ENOENT, + SVR4_ESRCH, + SVR4_EINTR, + SVR4_EIO, + SVR4_ENXIO, + SVR4_E2BIG, + SVR4_ENOEXEC, + SVR4_EBADF, + SVR4_ECHILD, + SVR4_EDEADLK, + SVR4_ENOMEM, + SVR4_EACCES, + SVR4_EFAULT, + SVR4_ENOTBLK, + SVR4_EBUSY, + SVR4_EEXIST, + SVR4_EXDEV, + SVR4_ENODEV, + SVR4_ENOTDIR, + SVR4_EISDIR, + SVR4_EINVAL, + SVR4_ENFILE, + SVR4_EMFILE, + SVR4_ENOTTY, + SVR4_ETXTBSY, + SVR4_EFBIG, + SVR4_ENOSPC, + SVR4_ESPIPE, + SVR4_EROFS, + SVR4_EMLINK, + SVR4_EPIPE, + SVR4_EDOM, + SVR4_ERANGE, + SVR4_EAGAIN, + SVR4_EINPROGRESS, + SVR4_EALREADY, + SVR4_ENOTSOCK, + SVR4_EDESTADDRREQ, + SVR4_EMSGSIZE, + SVR4_EPROTOTYPE, + SVR4_ENOPROTOOPT, + SVR4_EPROTONOSUPPORT, + SVR4_ESOCKTNOSUPPORT, + SVR4_EOPNOTSUPP, + SVR4_EPFNOSUPPORT, + SVR4_EAFNOSUPPORT, + SVR4_EADDRINUSE, + SVR4_EADDRNOTAVAIL, + SVR4_ENETDOWN, + SVR4_ENETUNREACH, + SVR4_ENETRESET, + SVR4_ECONNABORTED, + SVR4_ECONNRESET, + SVR4_ENOBUFS, + SVR4_EISCONN, + SVR4_ENOTCONN, + SVR4_ESHUTDOWN, + SVR4_ETOOMANYREFS, + SVR4_ETIMEDOUT, + SVR4_ECONNREFUSED, + SVR4_ELOOP, + SVR4_ENAMETOOLONG, + SVR4_EHOSTDOWN, + SVR4_EHOSTUNREACH, + SVR4_ENOTEMPTY, + SVR4_EPROCLIM, + SVR4_EUSERS, + SVR4_EDQUOT, + SVR4_ESTALE, + SVR4_EREMOTE, + SVR4_EBADRPC, + SVR4_ERPCMISMATCH, + SVR4_EPROGUNAVAIL, + SVR4_EPROGMISMATCH, + SVR4_EPROCUNAVAIL, + SVR4_ENOLCK, + SVR4_ENOSYS, + SVR4_EFTYPE, + SVR4_EAUTH, + SVR4_ENEEDAUTH, + SVR4_EIDRM, + SVR4_ENOMSG, +}; + + +static int svr4_fixup(register_t **stack_base, struct image_params *imgp); + +extern struct sysent svr4_sysent[]; +#undef szsigcode +#undef sigcode + +extern int svr4_szsigcode; +extern char svr4_sigcode[]; + +struct sysentvec svr4_sysvec = { + .sv_size = SVR4_SYS_MAXSYSCALL, + .sv_table = svr4_sysent, + .sv_mask = 0xff, + .sv_sigsize = SVR4_NSIG-1, /* NB: signal trans table indexed with signno-1 */ + .sv_sigtbl = bsd_to_svr4_sig+1, + .sv_errsize = ELAST, /* ELAST */ + .sv_errtbl = bsd_to_svr4_errno, + .sv_transtrap = NULL, + .sv_fixup = svr4_fixup, + .sv_sendsig = svr4_sendsig, + .sv_sigcode = svr4_sigcode, + .sv_szsigcode = &svr4_szsigcode, + .sv_prepsyscall = NULL, + .sv_name = "SVR4", + .sv_coredump = elf32_coredump, + .sv_imgact_try = NULL, + .sv_minsigstksz = SVR4_MINSIGSTKSZ, + .sv_pagesize = PAGE_SIZE, + .sv_minuser = VM_MIN_ADDRESS, + .sv_maxuser = VM_MAXUSER_ADDRESS, + .sv_usrstack = USRSTACK, + .sv_psstrings = PS_STRINGS, + .sv_stackprot = VM_PROT_ALL, + .sv_copyout_strings = exec_copyout_strings, + .sv_setregs = exec_setregs, + .sv_fixlimit = NULL, + .sv_maxssiz = NULL, + .sv_flags = SV_ABI_UNDEF | SV_IA32 | SV_ILP32, + .sv_set_syscall_retval = cpu_set_syscall_retval, + .sv_fetch_syscall_args = cpu_fetch_syscall_args, + .sv_syscallnames = NULL, + .sv_schedtail = NULL, +}; + +const char svr4_emul_path[] = "/compat/svr4"; + +Elf32_Brandinfo svr4_brand = { + .brand = ELFOSABI_SYSV, + .machine = EM_386, /* XXX only implemented for x86 so far. */ + .compat_3_brand = "SVR4", + .emul_path = svr4_emul_path, + .interp_path = "/lib/libc.so.1", + .sysvec = &svr4_sysvec, + .interp_newpath = NULL, + .brand_note = NULL, + .flags = 0 +}; + +static int +svr4_fixup(register_t **stack_base, struct image_params *imgp) +{ + Elf32_Auxargs *args; + register_t *pos; + + KASSERT(curthread->td_proc == imgp->proc, + ("unsafe svr4_fixup(), should be curproc")); + args = (Elf32_Auxargs *)imgp->auxargs; + pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2); + + if (args->execfd != -1) + AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); + AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); + AUXARGS_ENTRY(pos, AT_PHENT, args->phent); + AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); + AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); + AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); + AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); + AUXARGS_ENTRY(pos, AT_BASE, args->base); + AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid); + AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid); + AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid); + AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid); + AUXARGS_ENTRY(pos, AT_NULL, 0); + + free(imgp->auxargs, M_TEMP); + imgp->auxargs = NULL; + + (*stack_base)--; + **stack_base = (register_t)imgp->args->argc; + return 0; +} + +/* + * 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 +svr4_emul_find(struct thread *td, char *path, enum uio_seg pathseg, + char **pbuf, int create) +{ + + return (kern_alternate_path(td, svr4_emul_path, path, pathseg, pbuf, + create, AT_FDCWD)); +} + +static int +svr4_elf_modevent(module_t mod, int type, void *data) +{ + int error; + + error = 0; + + switch(type) { + case MOD_LOAD: + if (elf32_insert_brand_entry(&svr4_brand) < 0) { + printf("cannot insert svr4 elf brand handler\n"); + error = EINVAL; + break; + } + if (bootverbose) + printf("svr4 ELF exec handler installed\n"); + svr4_sockcache_init(); + break; + case MOD_UNLOAD: + /* Only allow the emulator to be removed if it isn't in use. */ + if (elf32_brand_inuse(&svr4_brand) != 0) { + error = EBUSY; + } else if (elf32_remove_brand_entry(&svr4_brand) < 0) { + error = EINVAL; + } + + if (error) { + printf("Could not deinstall ELF interpreter entry (error %d)\n", + error); + break; + } + if (bootverbose) + printf("svr4 ELF exec handler removed\n"); + svr4_sockcache_destroy(); + break; + default: + return (EOPNOTSUPP); + break; + } + return error; +} + +static moduledata_t svr4_elf_mod = { + "svr4elf", + svr4_elf_modevent, + 0 +}; +DECLARE_MODULE_TIED(svr4elf, svr4_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); +MODULE_DEPEND(svr4elf, streams, 1, 1, 1); diff --git a/sys/compat/svr4/svr4_termios.c b/sys/compat/svr4/svr4_termios.c new file mode 100644 index 0000000..8195a41 --- /dev/null +++ b/sys/compat/svr4/svr4_termios.c @@ -0,0 +1,612 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/proc.h> +#include <sys/systm.h> +#include <sys/file.h> +#include <sys/filedesc.h> +#include <sys/tty.h> + +#include <sys/sysproto.h> + +#include <compat/svr4/svr4.h> +#include <compat/svr4/svr4_util.h> +#include <compat/svr4/svr4_ioctl.h> +#include <compat/svr4/svr4_termios.h> + +#ifndef __CONCAT3 +# if __STDC__ +# define __CONCAT3(a,b,c) a ## b ## c +# else +# define __CONCAT3(a,b,c) a/**/b/**/c +# endif +#endif + +static u_long bsd_to_svr4_speed(u_long, u_long); +static u_long svr4_to_bsd_speed(u_long, u_long); +static void svr4_to_bsd_termios(const struct svr4_termios *, + struct termios *, int); +static void bsd_to_svr4_termios(const struct termios *, + struct svr4_termios *); +static void svr4_termio_to_termios(const struct svr4_termio *, + struct svr4_termios *); +static void svr4_termios_to_termio(const struct svr4_termios *, + struct svr4_termio *); +#ifdef DEBUG_SVR4 +static void print_svr4_termios(const struct svr4_termios *); +static void print_bsd_termios(const struct termios *); +#endif /* DEBUG_SVR4 */ + +#define undefined_char(a,b) /**/ +#define undefined_flag1(f,a,b) /**/ +#define undefined_flag2(f,a,b,c1,t1,c2,t2) /**/ +#define undefined_flag4(f,a,b,c1,t1,c2,t2,c3,t3,c4,t4) /**/ + +#define svr4_to_bsd_char(a,b) \ + if (new || __CONCAT3(SVR4_,a,b) < SVR4_NCC) { \ + if (st->c_cc[__CONCAT3(SVR4_,a,b)] == SVR4_POSIX_VDISABLE) \ + bt->c_cc[__CONCAT(a,b)] = _POSIX_VDISABLE; \ + else \ + bt->c_cc[__CONCAT(a,b)] = st->c_cc[__CONCAT3(SVR4_,a,b)]; \ + } + +#define svr4_to_bsd_flag1(f,a,b) \ + if (new || __CONCAT3(SVR4_,a,b) < 0200000) { \ + if (st->f & __CONCAT3(SVR4_,a,b)) \ + bt->f |= __CONCAT(a,b); \ + else \ + bt->f &= ~__CONCAT(a,b); \ + } + +#define svr4_to_bsd_flag2(f,a,b,c1,t1,c2,t2) \ + if (new || __CONCAT3(SVR4_,a,b) < 0200000) { \ + bt->f &= ~__CONCAT(a,b); \ + switch (st->f & __CONCAT3(SVR4_,a,b)) { \ + case __CONCAT3(SVR4_,c1,t1): bt->f |= __CONCAT(c1,t1); break; \ + case __CONCAT3(SVR4_,c2,t2): bt->f |= __CONCAT(c2,t2); break; \ + } \ + } + +#define svr4_to_bsd_flag4(f,a,b,c1,t1,c2,t2,c3,t3,c4,t4) \ + if (new || __CONCAT3(SVR4_,a,b) < 0200000) { \ + bt->f &= ~__CONCAT(a,b); \ + switch (st->f & __CONCAT3(SVR4_,a,b)) { \ + case __CONCAT3(SVR4_,c1,t1): bt->f |= __CONCAT(c1,t1); break; \ + case __CONCAT3(SVR4_,c2,t2): bt->f |= __CONCAT(c2,t2); break; \ + case __CONCAT3(SVR4_,c3,t3): bt->f |= __CONCAT(c3,t3); break; \ + case __CONCAT3(SVR4_,c4,t4): bt->f |= __CONCAT(c4,t4); break; \ + } \ + } + + +#define bsd_to_svr4_char(a,b) \ + if (bt->c_cc[__CONCAT(a,b)] == _POSIX_VDISABLE) \ + st->c_cc[__CONCAT3(SVR4_,a,b)] = SVR4_POSIX_VDISABLE; \ + else \ + st->c_cc[__CONCAT3(SVR4_,a,b)] = bt->c_cc[__CONCAT(a,b)] + +#define bsd_to_svr4_flag1(f,a,b) \ + if (bt->f & __CONCAT(a,b)) \ + st->f |= __CONCAT3(SVR4_,a,b); \ + else \ + st->f &= ~__CONCAT3(SVR4_,a,b) + +#define bsd_to_svr4_flag2(f,a,b,c1,t1,c2,t2) \ + st->f &= ~__CONCAT(a,b); \ + switch (bt->f & __CONCAT(a,b)) { \ + case __CONCAT(c1,t1): st->f |= __CONCAT3(SVR4_,c1,t1); break; \ + case __CONCAT(c2,t2): st->f |= __CONCAT3(SVR4_,c2,t2); break; \ + } + +#define bsd_to_svr4_flag4(f,a,b,c1,t1,c2,t2,c3,t3,c4,t4) \ + st->f &= ~__CONCAT(a,b); \ + switch (bt->f & __CONCAT(a,b)) { \ + case __CONCAT(c1,t1): st->f |= __CONCAT3(SVR4_,c1,t1); break; \ + case __CONCAT(c2,t2): st->f |= __CONCAT3(SVR4_,c2,t2); break; \ + case __CONCAT(c3,t3): st->f |= __CONCAT3(SVR4_,c3,t3); break; \ + case __CONCAT(c4,t4): st->f |= __CONCAT3(SVR4_,c4,t4); break; \ + } + +#ifdef DEBUG_SVR4 +static void +print_svr4_termios(st) + const struct svr4_termios *st; +{ + int i; + DPRINTF(("SVR4\niflag=%lo oflag=%lo cflag=%lo lflag=%lo\n", + st->c_iflag, st->c_oflag, st->c_cflag, st->c_lflag)); + DPRINTF(("cc: ")); + for (i = 0; i < SVR4_NCCS; i++) + DPRINTF(("%o ", st->c_cc[i])); + DPRINTF(("\n")); +} + + +static void +print_bsd_termios(bt) + const struct termios *bt; +{ + int i; + uprintf("BSD\niflag=%o oflag=%o cflag=%o lflag=%o\n", + bt->c_iflag, bt->c_oflag, bt->c_cflag, bt->c_lflag); + uprintf("cc: "); + for (i = 0; i < NCCS; i++) + uprintf("%o ", bt->c_cc[i]); + uprintf("\n"); +} +#endif /* DEBUG_SVR4 */ + +static u_long +bsd_to_svr4_speed(sp, mask) + u_long sp; + u_long mask; +{ + switch (sp) { +#undef getval +#define getval(a,b) case __CONCAT(a,b): sp = __CONCAT3(SVR4_,a,b) + getval(B,0); + getval(B,50); + getval(B,75); + getval(B,110); + getval(B,134); + getval(B,150); + getval(B,200); + getval(B,300); + getval(B,600); + getval(B,1200); + getval(B,1800); + getval(B,2400); + getval(B,4800); + getval(B,9600); + getval(B,19200); + getval(B,38400); + getval(B,57600); + getval(B,115200); + default: sp = SVR4_B9600; /* XXX */ + } + + while ((mask & 1) == 0) { + mask >>= 1; + sp <<= 1; + } + + return sp; +} + + +static u_long +svr4_to_bsd_speed(sp, mask) + u_long sp; + u_long mask; +{ + while ((mask & 1) == 0) { + mask >>= 1; + sp >>= 1; + } + + switch (sp & mask) { +#undef getval +#define getval(a,b) case __CONCAT3(SVR4_,a,b): return __CONCAT(a,b) + getval(B,0); + getval(B,50); + getval(B,75); + getval(B,110); + getval(B,134); + getval(B,150); + getval(B,200); + getval(B,300); + getval(B,600); + getval(B,1200); + getval(B,1800); + getval(B,2400); + getval(B,4800); + getval(B,9600); + getval(B,19200); + getval(B,38400); + getval(B,57600); + getval(B,115200); + default: return B9600; /* XXX */ + } +} + + +static void +svr4_to_bsd_termios(st, bt, new) + const struct svr4_termios *st; + struct termios *bt; + int new; +{ + /* control characters */ + /* + * We process VMIN and VTIME first, + * because they are shared with VEOF and VEOL + */ + svr4_to_bsd_char(V,MIN); + svr4_to_bsd_char(V,TIME); + + svr4_to_bsd_char(V,INTR); + svr4_to_bsd_char(V,QUIT); + svr4_to_bsd_char(V,ERASE); + svr4_to_bsd_char(V,KILL); + svr4_to_bsd_char(V,EOF); + svr4_to_bsd_char(V,EOL); + svr4_to_bsd_char(V,EOL2); + undefined_char(V,SWTCH); + svr4_to_bsd_char(V,START); + svr4_to_bsd_char(V,STOP); + svr4_to_bsd_char(V,SUSP); + svr4_to_bsd_char(V,DSUSP); + svr4_to_bsd_char(V,REPRINT); + svr4_to_bsd_char(V,DISCARD); + svr4_to_bsd_char(V,WERASE); + svr4_to_bsd_char(V,LNEXT); + + /* Input modes */ + svr4_to_bsd_flag1(c_iflag,I,GNBRK); + svr4_to_bsd_flag1(c_iflag,B,RKINT); + svr4_to_bsd_flag1(c_iflag,I,GNPAR); + svr4_to_bsd_flag1(c_iflag,P,ARMRK); + svr4_to_bsd_flag1(c_iflag,I,NPCK); + svr4_to_bsd_flag1(c_iflag,I,STRIP); + svr4_to_bsd_flag1(c_iflag,I,NLCR); + svr4_to_bsd_flag1(c_iflag,I,GNCR); + svr4_to_bsd_flag1(c_iflag,I,CRNL); + undefined_flag1(c_iflag,I,UCLC); + svr4_to_bsd_flag1(c_iflag,I,XON); + svr4_to_bsd_flag1(c_iflag,I,XANY); + svr4_to_bsd_flag1(c_iflag,I,XOFF); + svr4_to_bsd_flag1(c_iflag,I,MAXBEL); + undefined_flag1(c_iflag,D,OSMODE); + + /* Output modes */ + svr4_to_bsd_flag1(c_oflag,O,POST); + undefined_flag1(c_oflag,O,LCUC); + svr4_to_bsd_flag1(c_oflag,O,NLCR); + undefined_flag1(c_oflag,O,CRNL); + undefined_flag1(c_oflag,O,NOCR); + undefined_flag1(c_oflag,O,NLRET); + undefined_flag1(c_oflag,O,FILL); + undefined_flag1(c_oflag,O,FDEL); + undefined_flag2(c_oflag,N,LDLY,N,L0,N,L1); + undefined_flag4(c_oflag,C,RDLY,C,R0,C,R1,C,R2,C,R3); + undefined_flag4(c_oflag,T,ABDLY,T,AB0,T,AB1,T,AB2,T,AB3); + undefined_flag2(c_oflag,B,SDLY,B,S0,B,S1); + undefined_flag2(c_oflag,V,TDLY,V,T0,V,T1); + undefined_flag2(c_oflag,F,FDLY,F,F0,F,F1); + undefined_flag1(c_oflag,P,AGEOUT); + undefined_flag1(c_oflag,W,RAP); + + /* Control modes */ + bt->c_ospeed = svr4_to_bsd_speed(st->c_cflag, SVR4_CBAUD); + svr4_to_bsd_flag4(c_cflag,C,SIZE,C,S5,C,S6,C,S7,C,S8) + svr4_to_bsd_flag1(c_cflag,C,STOPB); + svr4_to_bsd_flag1(c_cflag,C,READ); + svr4_to_bsd_flag1(c_cflag,P,ARENB); + svr4_to_bsd_flag1(c_cflag,P,ARODD); + svr4_to_bsd_flag1(c_cflag,H,UPCL); + svr4_to_bsd_flag1(c_cflag,C,LOCAL); + undefined_flag1(c_cflag,R,CV1EN); + undefined_flag1(c_cflag,X,MT1EN); + undefined_flag1(c_cflag,L,OBLK); + undefined_flag1(c_cflag,X,CLUDE); + bt->c_ispeed = svr4_to_bsd_speed(st->c_cflag, SVR4_CIBAUD); + undefined_flag1(c_cflag,P,AREXT); + + /* line discipline modes */ + svr4_to_bsd_flag1(c_lflag,I,SIG); + svr4_to_bsd_flag1(c_lflag,I,CANON); + undefined_flag1(c_lflag,X,CASE); + svr4_to_bsd_flag1(c_lflag,E,CHO); + svr4_to_bsd_flag1(c_lflag,E,CHOE); + svr4_to_bsd_flag1(c_lflag,E,CHOK); + svr4_to_bsd_flag1(c_lflag,E,CHONL); + svr4_to_bsd_flag1(c_lflag,N,OFLSH); + svr4_to_bsd_flag1(c_lflag,T,OSTOP); + svr4_to_bsd_flag1(c_lflag,E,CHOCTL); + svr4_to_bsd_flag1(c_lflag,E,CHOPRT); + svr4_to_bsd_flag1(c_lflag,E,CHOKE); + undefined_flag1(c_lflag,D,EFECHO); + svr4_to_bsd_flag1(c_lflag,F,LUSHO); + svr4_to_bsd_flag1(c_lflag,P,ENDIN); + svr4_to_bsd_flag1(c_lflag,I,EXTEN); +} + + +static void +bsd_to_svr4_termios(bt, st) + const struct termios *bt; + struct svr4_termios *st; +{ + /* control characters */ + /* + * We process VMIN and VTIME first, + * because they are shared with VEOF and VEOL + */ + bsd_to_svr4_char(V,MIN); + bsd_to_svr4_char(V,TIME); + bsd_to_svr4_char(V,INTR); + bsd_to_svr4_char(V,QUIT); + bsd_to_svr4_char(V,ERASE); + bsd_to_svr4_char(V,KILL); + bsd_to_svr4_char(V,EOF); + bsd_to_svr4_char(V,EOL); + bsd_to_svr4_char(V,EOL2); + undefined_char(V,SWTCH); + bsd_to_svr4_char(V,START); + bsd_to_svr4_char(V,STOP); + bsd_to_svr4_char(V,SUSP); + bsd_to_svr4_char(V,DSUSP); + bsd_to_svr4_char(V,REPRINT); + bsd_to_svr4_char(V,DISCARD); + bsd_to_svr4_char(V,WERASE); + bsd_to_svr4_char(V,LNEXT); + + /* Input modes */ + bsd_to_svr4_flag1(c_iflag,I,GNBRK); + bsd_to_svr4_flag1(c_iflag,B,RKINT); + bsd_to_svr4_flag1(c_iflag,I,GNPAR); + bsd_to_svr4_flag1(c_iflag,P,ARMRK); + bsd_to_svr4_flag1(c_iflag,I,NPCK); + bsd_to_svr4_flag1(c_iflag,I,STRIP); + bsd_to_svr4_flag1(c_iflag,I,NLCR); + bsd_to_svr4_flag1(c_iflag,I,GNCR); + bsd_to_svr4_flag1(c_iflag,I,CRNL); + undefined_flag1(c_iflag,I,UCLC); + bsd_to_svr4_flag1(c_iflag,I,XON); + bsd_to_svr4_flag1(c_iflag,I,XANY); + bsd_to_svr4_flag1(c_iflag,I,XOFF); + bsd_to_svr4_flag1(c_iflag,I,MAXBEL); + undefined_flag1(c_iflag,D,OSMODE); + + /* Output modes */ + bsd_to_svr4_flag1(c_oflag,O,POST); + undefined_flag1(c_oflag,O,LCUC); + bsd_to_svr4_flag1(c_oflag,O,NLCR); + undefined_flag1(c_oflag,O,CRNL); + undefined_flag1(c_oflag,O,NOCR); + undefined_flag1(c_oflag,O,NLRET); + undefined_flag1(c_oflag,O,FILL); + undefined_flag1(c_oflag,O,FDEL); + undefined_flag2(c_oflag,N,LDLY,N,L0,N,L1); + undefined_flag4(c_oflag,C,RDLY,C,R0,C,R1,C,R2,C,R3); + undefined_flag4(c_oflag,T,ABDLY,T,AB0,T,AB1,T,AB2,T,AB3); + undefined_flag2(c_oflag,B,SDLY,B,S0,B,S1); + undefined_flag2(c_oflag,V,TDLY,V,T0,V,T1); + undefined_flag2(c_oflag,F,FDLY,F,F0,F,F1); + undefined_flag1(c_oflag,P,AGEOUT); + undefined_flag1(c_oflag,W,RAP); + + /* Control modes */ + st->c_cflag &= ~SVR4_CBAUD; + st->c_cflag |= bsd_to_svr4_speed(bt->c_ospeed, SVR4_CBAUD); + bsd_to_svr4_flag4(c_cflag,C,SIZE,C,S5,C,S6,C,S7,C,S8) + bsd_to_svr4_flag1(c_cflag,C,STOPB); + bsd_to_svr4_flag1(c_cflag,C,READ); + bsd_to_svr4_flag1(c_cflag,P,ARENB); + bsd_to_svr4_flag1(c_cflag,P,ARODD); + bsd_to_svr4_flag1(c_cflag,H,UPCL); + bsd_to_svr4_flag1(c_cflag,C,LOCAL); + undefined_flag1(c_cflag,R,CV1EN); + undefined_flag1(c_cflag,X,MT1EN); + undefined_flag1(c_cflag,L,OBLK); + undefined_flag1(c_cflag,X,CLUDE); + st->c_cflag &= ~SVR4_CIBAUD; + st->c_cflag |= bsd_to_svr4_speed(bt->c_ispeed, SVR4_CIBAUD); + + undefined_flag1(c_oflag,P,AREXT); + + /* line discipline modes */ + bsd_to_svr4_flag1(c_lflag,I,SIG); + bsd_to_svr4_flag1(c_lflag,I,CANON); + undefined_flag1(c_lflag,X,CASE); + bsd_to_svr4_flag1(c_lflag,E,CHO); + bsd_to_svr4_flag1(c_lflag,E,CHOE); + bsd_to_svr4_flag1(c_lflag,E,CHOK); + bsd_to_svr4_flag1(c_lflag,E,CHONL); + bsd_to_svr4_flag1(c_lflag,N,OFLSH); + bsd_to_svr4_flag1(c_lflag,T,OSTOP); + bsd_to_svr4_flag1(c_lflag,E,CHOCTL); + bsd_to_svr4_flag1(c_lflag,E,CHOPRT); + bsd_to_svr4_flag1(c_lflag,E,CHOKE); + undefined_flag1(c_lflag,D,EFECHO); + bsd_to_svr4_flag1(c_lflag,F,LUSHO); + bsd_to_svr4_flag1(c_lflag,P,ENDIN); + bsd_to_svr4_flag1(c_lflag,I,EXTEN); +} + + +static void +svr4_termio_to_termios(t, ts) + const struct svr4_termio *t; + struct svr4_termios *ts; +{ + int i; + + ts->c_iflag = (svr4_tcflag_t) t->c_iflag; + ts->c_oflag = (svr4_tcflag_t) t->c_oflag; + ts->c_cflag = (svr4_tcflag_t) t->c_cflag; + ts->c_lflag = (svr4_tcflag_t) t->c_lflag; + + for (i = 0; i < SVR4_NCC; i++) + ts->c_cc[i] = (svr4_cc_t) t->c_cc[i]; +} + + +static void +svr4_termios_to_termio(ts, t) + const struct svr4_termios *ts; + struct svr4_termio *t; +{ + int i; + + t->c_iflag = (u_short) ts->c_iflag; + t->c_oflag = (u_short) ts->c_oflag; + t->c_cflag = (u_short) ts->c_cflag; + t->c_lflag = (u_short) ts->c_lflag; + t->c_line = 0; /* XXX */ + + for (i = 0; i < SVR4_NCC; i++) + t->c_cc[i] = (u_char) ts->c_cc[i]; +} + +int +svr4_term_ioctl(fp, td, retval, fd, cmd, data) + struct file *fp; + struct thread *td; + register_t *retval; + int fd; + u_long cmd; + caddr_t data; +{ + struct termios bt; + struct svr4_termios st; + struct svr4_termio t; + int error, new; + + *retval = 0; + + DPRINTF(("TERM ioctl %lx\n", cmd)); + + switch (cmd) { + case SVR4_TCGETA: + case SVR4_TCGETS: + DPRINTF(("ioctl(TCGET%c);\n", cmd == SVR4_TCGETA ? 'A' : 'S')); + if ((error = fo_ioctl(fp, TIOCGETA, (caddr_t) &bt, + td->td_ucred, td)) != 0) + return error; + + memset(&st, 0, sizeof(st)); + bsd_to_svr4_termios(&bt, &st); + +#ifdef DEBUG_SVR4 + print_bsd_termios(&bt); + print_svr4_termios(&st); +#endif /* DEBUG_SVR4 */ + + if (cmd == SVR4_TCGETA) { + svr4_termios_to_termio(&st, &t); + return copyout(&t, data, sizeof(t)); + } + else { + return copyout(&st, data, sizeof(st)); + } + + case SVR4_TCSETA: + case SVR4_TCSETS: + case SVR4_TCSETAW: + case SVR4_TCSETSW: + case SVR4_TCSETAF: + case SVR4_TCSETSF: + DPRINTF(("TCSET{A,S,AW,SW,AF,SF}\n")); + /* get full BSD termios so we don't lose information */ + if ((error = fo_ioctl(fp, TIOCGETA, (caddr_t) &bt, + td->td_ucred, td)) != 0) + return error; + + switch (cmd) { + case SVR4_TCSETS: + case SVR4_TCSETSW: + case SVR4_TCSETSF: + if ((error = copyin(data, &st, sizeof(st))) != 0) + return error; + new = 1; + break; + + case SVR4_TCSETA: + case SVR4_TCSETAW: + case SVR4_TCSETAF: + if ((error = copyin(data, &t, sizeof(t))) != 0) + return error; + + svr4_termio_to_termios(&t, &st); + new = 0; + break; + + default: + return EINVAL; + } + + svr4_to_bsd_termios(&st, &bt, new); + + switch (cmd) { + case SVR4_TCSETA: + case SVR4_TCSETS: + DPRINTF(("ioctl(TCSET[A|S]);\n")); + cmd = TIOCSETA; + break; + case SVR4_TCSETAW: + case SVR4_TCSETSW: + DPRINTF(("ioctl(TCSET[A|S]W);\n")); + cmd = TIOCSETAW; + break; + case SVR4_TCSETAF: + case SVR4_TCSETSF: + DPRINTF(("ioctl(TCSET[A|S]F);\n")); + cmd = TIOCSETAF; + break; + } + +#ifdef DEBUG_SVR4 + print_bsd_termios(&bt); + print_svr4_termios(&st); +#endif /* DEBUG_SVR4 */ + + return fo_ioctl(fp, cmd, (caddr_t) &bt, td->td_ucred, td); + + case SVR4_TIOCGWINSZ: + DPRINTF(("TIOCGWINSZ\n")); + { + struct svr4_winsize ws; + + error = fo_ioctl(fp, TIOCGWINSZ, (caddr_t) &ws, + td->td_ucred, td); + if (error) + return error; + return copyout(&ws, data, sizeof(ws)); + } + + case SVR4_TIOCSWINSZ: + DPRINTF(("TIOCSWINSZ\n")); + { + struct svr4_winsize ws; + + if ((error = copyin(data, &ws, sizeof(ws))) != 0) + return error; + return fo_ioctl(fp, TIOCSWINSZ, (caddr_t) &ws, + td->td_ucred, td); + } + + default: + DPRINTF(("teleport to STREAMS ioctls...\n")); + return svr4_stream_ti_ioctl(fp, td, retval, fd, cmd, data); + } +} diff --git a/sys/compat/svr4/svr4_termios.h b/sys/compat/svr4/svr4_termios.h new file mode 100644 index 0000000..c2b0c54 --- /dev/null +++ b/sys/compat/svr4/svr4_termios.h @@ -0,0 +1,224 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_TERMIOS_H_ +#define _SVR4_TERMIOS_H_ + +#define SVR4_POSIX_VDISABLE 0 +#define SVR4_NCC 8 +#define SVR4_NCCS 19 + +typedef u_long svr4_tcflag_t; +typedef u_char svr4_cc_t; +typedef u_long svr4_speed_t; + +struct svr4_termios { + svr4_tcflag_t c_iflag; + svr4_tcflag_t c_oflag; + svr4_tcflag_t c_cflag; + svr4_tcflag_t c_lflag; + svr4_cc_t c_cc[SVR4_NCCS]; +}; + +struct svr4_termio { + u_short c_iflag; + u_short c_oflag; + u_short c_cflag; + u_short c_lflag; + char c_line; + u_char c_cc[SVR4_NCC]; +}; + +/* control characters */ +#define SVR4_VINTR 0 +#define SVR4_VQUIT 1 +#define SVR4_VERASE 2 +#define SVR4_VKILL 3 +#define SVR4_VEOF 4 +#define SVR4_VEOL 5 +#define SVR4_VEOL2 6 +#define SVR4_VMIN 4 +#define SVR4_VTIME 5 +#define SVR4_VSWTCH 7 +#define SVR4_VSTART 8 +#define SVR4_VSTOP 9 +#define SVR4_VSUSP 10 +#define SVR4_VDSUSP 11 +#define SVR4_VREPRINT 12 +#define SVR4_VDISCARD 13 +#define SVR4_VWERASE 14 +#define SVR4_VLNEXT 15 + +/* Input modes */ +#define SVR4_IGNBRK 00000001 +#define SVR4_BRKINT 00000002 +#define SVR4_IGNPAR 00000004 +#define SVR4_PARMRK 00000010 +#define SVR4_INPCK 00000020 +#define SVR4_ISTRIP 00000040 +#define SVR4_INLCR 00000100 +#define SVR4_IGNCR 00000200 +#define SVR4_ICRNL 00000400 +#define SVR4_IUCLC 00001000 +#define SVR4_IXON 00002000 +#define SVR4_IXANY 00004000 +#define SVR4_IXOFF 00010000 +#define SVR4_IMAXBEL 00020000 +#define SVR4_DOSMODE 00100000 + +/* Output modes */ +#define SVR4_OPOST 00000001 +#define SVR4_OLCUC 00000002 +#define SVR4_ONLCR 00000004 +#define SVR4_OCRNL 00000010 +#define SVR4_ONOCR 00000020 +#define SVR4_ONLRET 00000040 +#define SVR4_OFILL 00000100 +#define SVR4_OFDEL 00000200 +#define SVR4_NLDLY 00000400 +#define SVR4_NL0 00000000 +#define SVR4_NL1 00000400 +#define SVR4_CRDLY 00003000 +#define SVR4_CR0 00000000 +#define SVR4_CR1 00001000 +#define SVR4_CR2 00002000 +#define SVR4_CR3 00003000 +#define SVR4_TABDLY 00014000 +#define SVR4_TAB0 00000000 +#define SVR4_TAB1 00004000 +#define SVR4_TAB2 00010000 +#define SVR4_TAB3 00014000 +#define SVR4_XTABS 00014000 +#define SVR4_BSDLY 00020000 +#define SVR4_BS0 00000000 +#define SVR4_BS1 00020000 +#define SVR4_VTDLY 00040000 +#define SVR4_VT0 00000000 +#define SVR4_VT1 00040000 +#define SVR4_FFDLY 00100000 +#define SVR4_FF0 00000000 +#define SVR4_FF1 00100000 +#define SVR4_PAGEOUT 00200000 +#define SVR4_WRAP 00400000 + +/* Control modes */ +#define SVR4_CBAUD 00000017 +#define SVR4_CSIZE 00000060 +#define SVR4_CS5 00000000 +#define SVR4_CS6 00000200 +#define SVR4_CS7 00000040 +#define SVR4_CS8 00000006 +#define SVR4_CSTOPB 00000100 +#define SVR4_CREAD 00000200 +#define SVR4_PARENB 00000400 +#define SVR4_PARODD 00001000 +#define SVR4_HUPCL 00002000 +#define SVR4_CLOCAL 00004000 +#define SVR4_RCV1EN 00010000 +#define SVR4_XMT1EN 00020000 +#define SVR4_LOBLK 00040000 +#define SVR4_XCLUDE 00100000 +#define SVR4_CIBAUD 03600000 +#define SVR4_PAREXT 04000000 + +/* line discipline modes */ +#define SVR4_ISIG 00000001 +#define SVR4_ICANON 00000002 +#define SVR4_XCASE 00000004 +#define SVR4_ECHO 00000010 +#define SVR4_ECHOE 00000020 +#define SVR4_ECHOK 00000040 +#define SVR4_ECHONL 00000100 +#define SVR4_NOFLSH 00000200 +#define SVR4_TOSTOP 00000400 +#define SVR4_ECHOCTL 00001000 +#define SVR4_ECHOPRT 00002000 +#define SVR4_ECHOKE 00004000 +#define SVR4_DEFECHO 00010000 +#define SVR4_FLUSHO 00020000 +#define SVR4_PENDIN 00040000 +#define SVR4_IEXTEN 00100000 + +#define SVR4_TIOC ('T' << 8) + +#define SVR4_TCGETA (SVR4_TIOC| 1) +#define SVR4_TCSETA (SVR4_TIOC| 2) +#define SVR4_TCSETAW (SVR4_TIOC| 3) +#define SVR4_TCSETAF (SVR4_TIOC| 4) +#define SVR4_TCSBRK (SVR4_TIOC| 5) +#define SVR4_TCXONC (SVR4_TIOC| 6) +#define SVR4_TCFLSH (SVR4_TIOC| 7) +#define SVR4_TIOCKBON (SVR4_TIOC| 8) +#define SVR4_TIOCKBOF (SVR4_TIOC| 9) +#define SVR4_KBENABLED (SVR4_TIOC|10) +#define SVR4_TCGETS (SVR4_TIOC|13) +#define SVR4_TCSETS (SVR4_TIOC|14) +#define SVR4_TCSETSW (SVR4_TIOC|15) +#define SVR4_TCSETSF (SVR4_TIOC|16) +#define SVR4_TCDSET (SVR4_TIOC|32) +#define SVR4_RTS_TOG (SVR4_TIOC|33) +#define SVR4_TCGETSC (SVR4_TIOC|34) +#define SVR4_TCSETSC (SVR4_TIOC|35) +#define SVR4_TCMOUSE (SVR4_TIOC|36) +#define SVR4_TIOCGWINSZ (SVR4_TIOC|104) +#define SVR4_TIOCSWINSZ (SVR4_TIOC|103) + +struct svr4_winsize { + u_short ws_row; + u_short ws_col; + u_short ws_xpixel; + u_short ws_ypixel; +}; + +#define SVR4_B0 0 +#define SVR4_B50 1 +#define SVR4_B75 2 +#define SVR4_B110 3 +#define SVR4_B134 4 +#define SVR4_B150 5 +#define SVR4_B200 6 +#define SVR4_B300 7 +#define SVR4_B600 8 +#define SVR4_B1200 9 +#define SVR4_B1800 10 +#define SVR4_B2400 11 +#define SVR4_B4800 12 +#define SVR4_B9600 13 +#define SVR4_B19200 14 +#define SVR4_B38400 15 +#define SVR4_B57600 16 +#define SVR4_B76800 17 +#define SVR4_B115200 18 +#define SVR4_B153600 19 +#define SVR4_B230400 20 +#define SVR4_B307200 21 +#define SVR4_B460800 22 + +#endif /* !_SVR4_TERMIOS_H_ */ diff --git a/sys/compat/svr4/svr4_time.h b/sys/compat/svr4/svr4_time.h new file mode 100644 index 0000000..0be9823 --- /dev/null +++ b/sys/compat/svr4/svr4_time.h @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_TIME_H_ +#define _SVR4_TIME_H_ + +#include <sys/time.h> + +struct svr4_utimbuf { + time_t actime; + time_t modtime; +}; + +#endif /* !_SVR4_TIME_H_ */ diff --git a/sys/compat/svr4/svr4_timod.h b/sys/compat/svr4/svr4_timod.h new file mode 100644 index 0000000..e295a4c --- /dev/null +++ b/sys/compat/svr4/svr4_timod.h @@ -0,0 +1,87 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_TIMOD_H_ +#define _SVR4_TIMOD_H_ + +#define SVR4_TIMOD ('T' << 8) +#define SVR4_TI_GETINFO (SVR4_TIMOD|140) +#define SVR4_TI_OPTMGMT (SVR4_TIMOD|141) +#define SVR4_TI_BIND (SVR4_TIMOD|142) +#define SVR4_TI_UNBIND (SVR4_TIMOD|143) +#define SVR4_TI_GETMYNAME (SVR4_TIMOD|144) +#define SVR4_TI_GETPEERNAME (SVR4_TIMOD|145) +#define SVR4_TI_SETMYNAME (SVR4_TIMOD|146) +#define SVR4_TI_SETPEERNAME (SVR4_TIMOD|147) +#define SVR4_TI_SYNC (SVR4_TIMOD|148) +#define SVR4_TI_GETADDRS (SVR4_TIMOD|149) + +#define SVR4_TI_CONNECT_REQUEST 0x00 +#define SVR4_TI_CONNECT_RESPONSE 0x01 +#define SVR4_TI_DISCONNECT_REQUEST 0x02 +#define SVR4_TI_DATA_REQUEST 0x03 +#define SVR4_TI_EXPDATA_REQUEST 0x04 +#define SVR4_TI_INFO_REQUEST 0x05 +#define SVR4_TI_OLD_BIND_REQUEST 0x06 +#define SVR4_TI_UNBIND_REQUEST 0x07 +#define SVR4_TI_SENDTO_REQUEST 0x08 +#define SVR4_TI_OLD_OPTMGMT_REQUEST 0x09 +#define SVR4_TI_ORDREL_REQUEST 0x0a + +#define SVR4_TI_ACCEPT_REPLY 0x0b +#define SVR4_TI_CONNECT_REPLY 0x0c +#define SVR4_TI_DISCONNECT_IND 0x0d +#define SVR4_TI_DATA_IND 0x0e +#define SVR4_TI_EXPDATA_IND 0x0f +#define SVR4_TI_INFO_REPLY 0x10 +#define SVR4_TI_BIND_REPLY 0x11 +#define SVR4_TI_ERROR_REPLY 0x12 +#define SVR4_TI_OK_REPLY 0x13 +#define SVR4_TI_RECVFROM_IND 0x14 +#define SVR4_TI_RECVFROM_ERROR_IND 0x15 +#define SVR4_TI_OPTMGMT_REPLY 0x16 +#define SVR4_TI_ORDREL_IND 0x17 + +#define SVR4_TI_ADDRESS_REQUEST 0x18 +#define SVR4_TI_ADDRESS_REPLY 0x19 + +#define SVR4_TI_BIND_REQUEST 0x20 +#define SVR4_TI_OPTMGMT_REQUEST 0x21 + +#define SVR4_TI__ACCEPT_WAIT 0x10000001 +#define SVR4_TI__ACCEPT_OK 0x10000002 + +struct svr4_netbuf { + u_int maxlen; + u_int len; + char *buf; +}; + +#endif /* !_SVR4_TIMOD_H_ */ diff --git a/sys/compat/svr4/svr4_types.h b/sys/compat/svr4/svr4_types.h new file mode 100644 index 0000000..e4f51b5 --- /dev/null +++ b/sys/compat/svr4/svr4_types.h @@ -0,0 +1,81 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_TYPES_H_ +#define _SVR4_TYPES_H_ + +typedef u_quad_t svr4_ino64_t; +typedef quad_t svr4_off64_t; +typedef quad_t svr4_blkcnt64_t; +typedef u_quad_t svr4_fsblkcnt64_t; + +typedef long svr4_off_t; +typedef u_long svr4_dev_t; +typedef u_long svr4_ino_t; +typedef u_long svr4_mode_t; +typedef u_long svr4_nlink_t; +typedef long svr4_uid_t; +typedef long svr4_gid_t; +typedef long svr4_daddr_t; +typedef long svr4_pid_t; +typedef long svr4_time_t; +typedef long svr4_blkcnt_t; +typedef u_long svr4_fsblkcnt_t; +typedef char *svr4_caddr_t; +typedef u_int svr4_size_t; + +typedef short svr4_o_dev_t; +typedef short svr4_o_pid_t; +typedef u_short svr4_o_ino_t; +typedef u_short svr4_o_mode_t; +typedef short svr4_o_nlink_t; +typedef u_short svr4_o_uid_t; +typedef u_short svr4_o_gid_t; +typedef long svr4_clock_t; +typedef int svr4_key_t; + +typedef struct timespec svr4_timestruc_t; + +#define svr4_omajor(x) ((int32_t)((((x) & 0x7f00) >> 8))) +#define svr4_ominor(x) ((int32_t)((((x) & 0x00ff) >> 0))) +#define svr4_omakedev(x,y) ((svr4_o_dev_t)((((x) << 8) & 0x7f00) | \ + (((y) << 0) & 0x00ff))) + +#define svr4_to_bsd_odev_t(d) makedev(svr4_omajor(d), svr4_ominor(d)) +#define bsd_to_svr4_odev_t(d) svr4_omakedev(major(d), minor(d)) + +#define svr4_major(x) ((int32_t)((((x) & 0xfffc0000) >> 18))) +#define svr4_minor(x) ((int32_t)((((x) & 0x0003ffff) >> 0))) +#define svr4_makedev(x,y) ((svr4_dev_t)((((x) << 18) & 0xfffc0000) | \ + (((y) << 0) & 0x0003ffff))) +#define svr4_to_bsd_dev_t(d) makedev(svr4_major(d), svr4_minor(d)) +#define bsd_to_svr4_dev_t(d) svr4_makedev(major(d), minor(d)) + +#endif /* !_SVR4_TYPES_H_ */ diff --git a/sys/compat/svr4/svr4_ucontext.h b/sys/compat/svr4/svr4_ucontext.h new file mode 100644 index 0000000..24cb5a1 --- /dev/null +++ b/sys/compat/svr4/svr4_ucontext.h @@ -0,0 +1,74 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_UCONTEXT_H_ +#define _SVR4_UCONTEXT_H_ + +/* + * Machine context + */ + +#define SVR4_UC_SIGMASK 0x01 +#define SVR4_UC_STACK 0x02 + +#define SVR4_UC_CPU 0x04 +#define SVR4_UC_FPU 0x08 +#define SVR4_UC_WEITEK 0x10 + +#define SVR4_UC_MCONTEXT (SVR4_UC_CPU|SVR4_UC_FPU|SVR4_UC_WEITEK) + +#define SVR4_UC_ALL (SVR4_UC_SIGMASK|SVR4_UC_STACK|SVR4_UC_MCONTEXT) + +typedef struct svr4_ucontext { + u_long uc_flags; + /* struct svr4_ucontext *uc_link;*/ + void *uc_link; + svr4_sigset_t uc_sigmask; + struct svr4_sigaltstack uc_stack; + svr4_mcontext_t uc_mcontext; + long uc_pad[5]; +} svr4_ucontext_t; + +#define SVR4_UC_GETREGSET 0 +#define SVR4_UC_SETREGSET 1 + +/* + * Signal frame + */ +struct svr4_sigframe { + int sf_signum; + union svr4_siginfo *sf_sip; + struct svr4_ucontext *sf_ucp; + sig_t sf_handler; + struct svr4_ucontext sf_uc; + union svr4_siginfo sf_si; +}; + +#endif /* !_SVR4_UCONTEXT_H_ */ diff --git a/sys/compat/svr4/svr4_ulimit.h b/sys/compat/svr4/svr4_ulimit.h new file mode 100644 index 0000000..d636c01 --- /dev/null +++ b/sys/compat/svr4/svr4_ulimit.h @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_ULIMIT_H_ +#define _SVR4_ULIMIT_H_ + +#define SVR4_GFILLIM 1 +#define SVR4_SFILLIM 2 +#define SVR4_GMEMLIM 3 +#define SVR4_GDESLIM 4 +#define SVR4_GTXTOFF 64 + + +#endif /* !_SVR4_ULIMIT_H_ */ diff --git a/sys/compat/svr4/svr4_ustat.h b/sys/compat/svr4/svr4_ustat.h new file mode 100644 index 0000000..3b9ade1 --- /dev/null +++ b/sys/compat/svr4/svr4_ustat.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_USTAT_H_ +#define _SVR4_USTAT_H_ + +#include <compat/svr4/svr4_types.h> + +struct svr4_ustat { + svr4_daddr_t f_tfree; + svr4_ino_t f_tinode; + char f_fname[6]; + char f_fpack[6]; +}; + +#endif /* !_SVR4_USTAT_H_ */ diff --git a/sys/compat/svr4/svr4_util.h b/sys/compat/svr4/svr4_util.h new file mode 100644 index 0000000..4cbf230 --- /dev/null +++ b/sys/compat/svr4/svr4_util.h @@ -0,0 +1,64 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_UTIL_H_ +#define _SVR4_UTIL_H_ + +/*#include <compat/common/compat_util.h>*/ +#include <vm/vm.h> +#include <vm/vm_param.h> +#include <vm/pmap.h> +#include <machine/vmparam.h> +#include <sys/exec.h> +#include <sys/sysent.h> +#include <sys/cdefs.h> +#include <sys/uio.h> + +#ifdef DEBUG_SVR4 +#define DPRINTF(a) uprintf a; +#else +#define DPRINTF(a) +#endif + +int svr4_emul_find(struct thread *, char *, enum uio_seg, char **, int); + +#define CHECKALT(td, upath, pathp, i) \ + do { \ + int _error; \ + \ + _error = svr4_emul_find(td, upath, UIO_USERSPACE, pathp, i); \ + if (*(pathp) == NULL) \ + return (_error); \ + } while (0) + +#define CHECKALTEXIST(td, upath, pathp) CHECKALT(td, upath, pathp, 0) +#define CHECKALTCREAT(td, upath, pathp) CHECKALT(td, upath, pathp, 1) + +#endif /* !_SVR4_UTIL_H_ */ diff --git a/sys/compat/svr4/svr4_utsname.h b/sys/compat/svr4/svr4_utsname.h new file mode 100644 index 0000000..7179575 --- /dev/null +++ b/sys/compat/svr4/svr4_utsname.h @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_UTSNAME_H_ +#define _SVR4_UTSNAME_H_ + +#include <compat/svr4/svr4_types.h> + +struct svr4_utsname { + char sysname[257]; + char nodename[257]; + char release[257]; + char version[257]; + char machine[257]; +}; + +#endif /* !_SVR4_UTSNAME_H_ */ diff --git a/sys/compat/svr4/svr4_wait.h b/sys/compat/svr4/svr4_wait.h new file mode 100644 index 0000000..0ce5db7 --- /dev/null +++ b/sys/compat/svr4/svr4_wait.h @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 1998 Mark Newton + * Copyright (c) 1994 Christos Zoulas + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SVR4_WAIT_H_ +#define _SVR4_WAIT_H_ + + +#define SVR4_P_PID 0 +#define SVR4_P_PPID 1 +#define SVR4_P_PGID 2 +#define SVR4_P_SID 3 +#define SVR4_P_CID 4 +#define SVR4_P_UID 5 +#define SVR4_P_GID 6 +#define SVR4_P_ALL 7 + +#define SVR4_WEXITED 0x01 +#define SVR4_WTRAPPED 0x02 +#define SVR4_WSTOPPED 0x04 +#define SVR4_WCONTINUED 0x08 +#define SVR4_WUNDEF1 0x10 +#define SVR4_WUNDEF2 0x20 +#define SVR4_WNOHANG 0x40 +#define SVR4_WNOWAIT 0x80 + +#define SVR4_WOPTMASK (SVR4_WEXITED|SVR4_WTRAPPED|SVR4_WSTOPPED|\ + SVR4_WCONTINUED|SVR4_WNOHANG|SVR4_WNOWAIT) + +#endif /* !_SVR4_WAIT_H_ */ diff --git a/sys/compat/svr4/syscalls.conf b/sys/compat/svr4/syscalls.conf new file mode 100644 index 0000000..84e0783 --- /dev/null +++ b/sys/compat/svr4/syscalls.conf @@ -0,0 +1,11 @@ +# $FreeBSD$ +sysnames="svr4_syscallnames.c" +sysproto="svr4_proto.h" +sysproto_h=_SVR4_SYSPROTO_H_ +syshdr="svr4_syscall.h" +syssw="svr4_sysent.c" +sysmk="/dev/null" +syscallprefix="SVR4_SYS_" +switchname="svr4_sysent" +namesname="svr4_syscallnames" +systrace="/dev/null" diff --git a/sys/compat/svr4/syscalls.master b/sys/compat/svr4/syscalls.master new file mode 100644 index 0000000..0997ab7 --- /dev/null +++ b/sys/compat/svr4/syscalls.master @@ -0,0 +1,396 @@ + $FreeBSD$ +; from: @(#)syscalls.master 8.1 (Berkeley) 7/19/93 +; +; System call name/number master file (or rather, slave, from SVR4). +; Processed to create svr4_sysent.c, svr4_syscalls.c and svr4_syscall.h. + +; Columns: number type nargs 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 +; name psuedo-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 +; OBSOL obsolete, not included in system, only specifies name +; UNIMPL not implemented, placeholder only + +; #ifdef's, etc. may be included, and are copied to the output files. + +#include <sys/types.h> +#include <sys/sysent.h> +#include <sys/sysproto.h> +#include <netinet/in.h> + +#include <compat/svr4/svr4.h> +#include <compat/svr4/svr4_types.h> +#include <compat/svr4/svr4_signal.h> +#include <compat/svr4/svr4_proto.h> + +0 AUE_NULL UNIMPL unused +1 AUE_NULL NOPROTO { void sys_exit(int rval); } exit \ + sys_exit_args void +2 AUE_NULL NOPROTO { int fork(void); } +3 AUE_NULL NOPROTO { int read(int fd, char *buf, u_int nbyte); } +4 AUE_NULL NOPROTO { int write(int fd, char *buf, u_int nbyte); } +5 AUE_NULL STD { int svr4_sys_open(char *path, int flags, \ + int mode); } +6 AUE_NULL NOPROTO { int close(int fd); } +7 AUE_NULL STD { int svr4_sys_wait(int *status); } +8 AUE_NULL STD { int svr4_sys_creat(char *path, int mode); } +9 AUE_NULL NOPROTO { int link(char *path, char *link); } +10 AUE_NULL NOPROTO { int unlink(char *path); } +11 AUE_NULL STD { int svr4_sys_execv(char *path, char **argp); } +12 AUE_NULL NOPROTO { int chdir(char *path); } +13 AUE_NULL STD { int svr4_sys_time(time_t *t); } +14 AUE_NULL STD { int svr4_sys_mknod(char* path, int mode, int dev); } +15 AUE_NULL NOPROTO { int chmod(char *path, int mode); } +16 AUE_NULL NOPROTO { int chown(char *path, uid_t uid, gid_t gid); } +17 AUE_NULL STD { int svr4_sys_break(caddr_t nsize); } +18 AUE_NULL STD { int svr4_sys_stat(char* path, \ + struct svr4_stat* ub); } +19 AUE_NULL NOPROTO { int lseek(int filedes, off_t *offset, \ + int whence); } +20 AUE_NULL NOPROTO { pid_t getpid(void); } +21 AUE_NULL UNIMPL old_mount +22 AUE_NULL UNIMPL sysv_umount +23 AUE_NULL NOPROTO { int setuid(uid_t uid); } +24 AUE_NULL NOPROTO { uid_t getuid(void); } +25 AUE_NULL UNIMPL stime +26 AUE_NULL UNIMPL ptrace +27 AUE_NULL STD { int svr4_sys_alarm(unsigned sec); } +28 AUE_NULL STD { int svr4_sys_fstat(int fd, \ + struct svr4_stat *sb); } +29 AUE_NULL STD { int svr4_sys_pause(void); } +30 AUE_NULL STD { int svr4_sys_utime(char *path, \ + struct svr4_utimbuf *ubuf); } +31 AUE_NULL UNIMPL stty +32 AUE_NULL UNIMPL gtty +33 AUE_NULL STD { int svr4_sys_access(char *path, \ + int amode); } +34 AUE_NULL STD { int svr4_sys_nice(int prio); } +35 AUE_NULL UNIMPL statfs +36 AUE_NULL NOPROTO { int sync(void); } +37 AUE_NULL STD { int svr4_sys_kill(int pid, int signum); } +38 AUE_NULL UNIMPL fstatfs +39 AUE_NULL STD { int svr4_sys_pgrpsys(int cmd, int pid, \ + int pgid); } +40 AUE_NULL UNIMPL xenix +41 AUE_NULL NOPROTO { int dup(u_int fd); } +42 AUE_NULL NOPROTO { int pipe(void); } +43 AUE_NULL STD { int svr4_sys_times(struct tms *tp); } +44 AUE_NULL UNIMPL profil +45 AUE_NULL UNIMPL plock +46 AUE_NULL NOPROTO { int setgid(gid_t gid); } +47 AUE_NULL NOPROTO { gid_t getgid(void); } +48 AUE_NULL STD { int svr4_sys_signal(int signum, \ + svr4_sig_t handler); } +49 AUE_NULL STD { int svr4_sys_msgsys(int what, int a2, \ + int a3, int a4, int a5); } +50 AUE_NULL STD { int svr4_sys_sysarch(int op, void *a1); } +51 AUE_NULL UNIMPL acct +52 AUE_NULL STD { int svr4_sys_shmsys(int what, int a2, \ + int a3, int a4, int a5); } +53 AUE_NULL STD { int svr4_sys_semsys(int what, int a2, \ + int a3, int a4, int a5); } +54 AUE_NULL STD { int svr4_sys_ioctl(int fd, u_long com, \ + caddr_t data); } +55 AUE_NULL UNIMPL uadmin +56 AUE_NULL UNIMPL exch +57 AUE_NULL STD { int svr4_sys_utssys(void *a1, void *a2, \ + int sel, void *a3); } +58 AUE_NULL NOPROTO { int fsync(int fd); } +59 AUE_NULL STD { int svr4_sys_execve(char *path, \ + char **argp, char **envp); } +60 AUE_NULL NOPROTO { int umask(int newmask); } +61 AUE_NULL NOPROTO { int chroot(char *path); } +62 AUE_NULL STD { int svr4_sys_fcntl(int fd, int cmd, \ + char *arg); } +63 AUE_NULL STD { int svr4_sys_ulimit(int cmd, \ + long newlimit); } +64 AUE_NULL UNIMPL reserved +65 AUE_NULL UNIMPL reserved +66 AUE_NULL UNIMPL reserved +67 AUE_NULL UNIMPL reserved +68 AUE_NULL UNIMPL reserved +69 AUE_NULL UNIMPL reserved +70 AUE_NULL UNIMPL advfs +71 AUE_NULL UNIMPL unadvfs +72 AUE_NULL UNIMPL rmount +73 AUE_NULL UNIMPL rumount +74 AUE_NULL UNIMPL rfstart +75 AUE_NULL UNIMPL sigret +76 AUE_NULL UNIMPL rdebug +77 AUE_NULL UNIMPL rfstop +78 AUE_NULL UNIMPL rfsys +79 AUE_NULL NOPROTO { int rmdir(char *path); } +80 AUE_NULL NOPROTO { int mkdir(char *path, int mode); } +81 AUE_NULL STD { int svr4_sys_getdents(int fd, char *buf, \ + int nbytes); } +82 AUE_NULL UNIMPL libattach +83 AUE_NULL UNIMPL libdetach +84 AUE_NULL UNIMPL sysfs +85 AUE_NULL STD { int svr4_sys_getmsg(int fd, \ + struct svr4_strbuf *ctl, \ + struct svr4_strbuf *dat, int *flags); } +86 AUE_NULL STD { int svr4_sys_putmsg(int fd, \ + struct svr4_strbuf *ctl, \ + struct svr4_strbuf *dat, int flags); } +87 AUE_NULL STD { int svr4_sys_poll(struct pollfd *fds, \ + unsigned int nfds, int timeout); } +88 AUE_NULL STD { int svr4_sys_lstat(char *path, \ + struct svr4_stat *ub); } +89 AUE_NULL NOPROTO { int symlink(char *path, char *link); } +90 AUE_NULL NOPROTO { int readlink(char *path, char *buf, \ + int count); } +91 AUE_NULL NOPROTO { int getgroups(u_int gidsetsize, \ + gid_t *gidset); } +92 AUE_NULL NOPROTO { int setgroups(u_int gidsetsize, \ + gid_t *gidset); } +93 AUE_NULL NOPROTO { int fchmod(int fd, int mode); } +94 AUE_NULL NOPROTO { int fchown(int fd, int uid, int gid); } +95 AUE_NULL STD { int svr4_sys_sigprocmask(int how, \ + svr4_sigset_t *set, \ + svr4_sigset_t *oset); } +96 AUE_NULL STD { int svr4_sys_sigsuspend( \ + svr4_sigset_t *ss); } +97 AUE_NULL STD { int svr4_sys_sigaltstack( \ + struct svr4_sigaltstack *nss, \ + struct svr4_sigaltstack *oss); } +98 AUE_NULL STD { int svr4_sys_sigaction(int signum, \ + struct svr4_sigaction *nsa, \ + struct svr4_sigaction *osa); } +99 AUE_NULL STD { int svr4_sys_sigpending(int what, \ + svr4_sigset_t *mask); } +100 AUE_NULL STD { int svr4_sys_context(int func, \ + struct svr4_ucontext *uc); } +101 AUE_NULL UNIMPL evsys +102 AUE_NULL UNIMPL evtrapret +103 AUE_NULL STD { int svr4_sys_statvfs(char *path, \ + struct svr4_statvfs *fs); } +104 AUE_NULL STD { int svr4_sys_fstatvfs(int fd, \ + struct svr4_statvfs *fs); } +105 AUE_NULL UNIMPL whoknows +106 AUE_NULL UNIMPL nfssvc +107 AUE_NULL STD { int svr4_sys_waitsys(int grp, int id, \ + union svr4_siginfo *info, int options); } +108 AUE_NULL UNIMPL sigsendsys +109 AUE_NULL STD { int svr4_sys_hrtsys(int cmd, int fun, \ + int sub, void *rv1, void *rv2); } +110 AUE_NULL UNIMPL acancel +111 AUE_NULL UNIMPL async +112 AUE_NULL UNIMPL priocntlsys +113 AUE_NULL STD { int svr4_sys_pathconf(char *path, \ + int name); } +114 AUE_NULL UNIMPL mincore +115 AUE_NULL STD { caddr_t svr4_sys_mmap(caddr_t addr, \ + svr4_size_t len, int prot, int flags, \ + int fd, svr4_off_t pos); } +116 AUE_NULL NOPROTO { int mprotect(void *addr, int len, \ + int prot); } +117 AUE_NULL NOPROTO { int munmap(void *addr, int len); } +118 AUE_NULL STD { int svr4_sys_fpathconf(int fd, int name); } +119 AUE_NULL NOPROTO { int vfork(void); } +120 AUE_NULL NOPROTO { int fchdir(int fd); } +121 AUE_NULL NOPROTO { int readv(int fd, struct iovec *iovp, \ + u_int iovcnt); } +122 AUE_NULL NOPROTO { int writev(int fd, struct iovec *iovp, \ + u_int iovcnt); } +123 AUE_NULL STD { int svr4_sys_xstat(int two, char *path, \ + struct svr4_xstat *ub); } +124 AUE_NULL STD { int svr4_sys_lxstat(int two, char *path, \ + struct svr4_xstat *ub); } +125 AUE_NULL STD { int svr4_sys_fxstat(int two, int fd, \ + struct svr4_xstat *sb); } +126 AUE_NULL STD { int svr4_sys_xmknod(int two, char *path, \ + svr4_mode_t mode, svr4_dev_t dev); } +127 AUE_NULL UNIMPL clocal +128 AUE_NULL STD { int svr4_sys_setrlimit(int which, \ + const struct svr4_rlimit *rlp); } +129 AUE_NULL STD { int svr4_sys_getrlimit(int which, \ + struct svr4_rlimit *rlp); } +130 AUE_NULL NOPROTO { int lchown(char *path, uid_t uid, \ + gid_t gid); } +131 AUE_NULL STD { int svr4_sys_memcntl(void * addr, \ + svr4_size_t len, int cmd, void * arg, \ + int attr, int mask); } +132 AUE_NULL UNIMPL getpmsg +133 AUE_NULL UNIMPL putpmsg +134 AUE_NULL NOPROTO { int rename(char *from, char *to); } +135 AUE_NULL STD { int svr4_sys_uname( \ + struct svr4_utsname* name, int dummy); } +136 AUE_NULL NOPROTO { int setegid(gid_t egid); } +137 AUE_NULL STD { int svr4_sys_sysconfig(int name); } +138 AUE_NULL NOPROTO { int adjtime(struct timeval *delta, \ + struct timeval *olddelta); } +139 AUE_NULL STD { long svr4_sys_systeminfo(int what, \ + char *buf, long len); } +140 AUE_NULL UNIMPL notused +141 AUE_NULL NOPROTO { int seteuid(uid_t euid); } +142 AUE_NULL UNIMPL vtrace +; fork1 +143 AUE_NULL UNIMPL { int fork(void); } +144 AUE_NULL UNIMPL sigtimedwait +145 AUE_NULL UNIMPL lwp_info +146 AUE_NULL UNIMPL yield +147 AUE_NULL UNIMPL lwp_sema_wait +148 AUE_NULL UNIMPL lwp_sema_post +149 AUE_NULL UNIMPL lwp_sema_trywait +150 AUE_NULL UNIMPL notused +151 AUE_NULL UNIMPL notused +152 AUE_NULL UNIMPL modctl +153 AUE_NULL STD { int svr4_sys_fchroot(int fd); } +154 AUE_NULL STD { int svr4_sys_utimes(char *path, \ + struct timeval *tptr); } +155 AUE_NULL STD { int svr4_sys_vhangup(void); } +156 AUE_NULL STD { int svr4_sys_gettimeofday( \ + struct timeval *tp); } +157 AUE_NULL NOPROTO { int getitimer(u_int which, \ + struct itimerval *itv); } +158 AUE_NULL NOPROTO { int setitimer(u_int which, \ + struct itimerval *itv, \ + struct itimerval *oitv); } +159 AUE_NULL UNIMPL lwp_create +160 AUE_NULL UNIMPL lwp_exit +161 AUE_NULL UNIMPL lwp_suspend +162 AUE_NULL UNIMPL lwp_continue +163 AUE_NULL UNIMPL lwp_kill +164 AUE_NULL UNIMPL lwp_self +165 AUE_NULL UNIMPL lwp_getprivate +166 AUE_NULL UNIMPL lwp_setprivate +167 AUE_NULL UNIMPL lwp_wait +168 AUE_NULL UNIMPL lwp_mutex_unlock +169 AUE_NULL UNIMPL lwp_mutex_lock +170 AUE_NULL UNIMPL lwp_cond_wait +171 AUE_NULL UNIMPL lwp_cond_signal +172 AUE_NULL UNIMPL lwp_cond_broadcast +173 AUE_NULL UNIMPL { ssize_t svr4_sys_pread(int fd, void *buf, \ + size_t nbyte, svr4_off_t off); } +174 AUE_NULL UNIMPL { ssize_t svr4_sys_pwrite(int fd, \ + const void *buf, size_t nbyte, \ + svr4_off_t off); } +175 AUE_NULL STD { svr4_off64_t svr4_sys_llseek(int fd, \ + long offset1, long offset2, int whence); } +176 AUE_NULL UNIMPL inst_sync +177 AUE_NULL UNIMPL whoknows +178 AUE_NULL UNIMPL kaio +179 AUE_NULL UNIMPL whoknows +180 AUE_NULL UNIMPL whoknows +181 AUE_NULL UNIMPL whoknows +182 AUE_NULL UNIMPL whoknows +183 AUE_NULL UNIMPL whoknows +184 AUE_NULL UNIMPL tsolsys +185 AUE_NULL STD { int svr4_sys_acl(char *path, int cmd, \ + int num, struct svr4_aclent *buf); } +186 AUE_NULL STD { int svr4_sys_auditsys(int code, int a1, \ + int a2, int a3, int a4, int a5); } +187 AUE_NULL UNIMPL processor_bind +188 AUE_NULL UNIMPL processor_info +189 AUE_NULL UNIMPL p_online +190 AUE_NULL UNIMPL sigqueue +191 AUE_NULL UNIMPL clock_gettime +192 AUE_NULL UNIMPL clock_settime +193 AUE_NULL UNIMPL clock_getres +194 AUE_NULL UNIMPL timer_create +195 AUE_NULL UNIMPL timer_delete +196 AUE_NULL UNIMPL timer_settime +197 AUE_NULL UNIMPL timer_gettime +198 AUE_NULL UNIMPL timer_overrun +199 AUE_NULL NOPROTO { int nanosleep( \ + const struct timespec *rqtp, \ + struct timespec *rmtp); } +200 AUE_NULL STD { int svr4_sys_facl(int fd, int cmd, \ + int num, struct svr4_aclent *buf); } +201 AUE_NULL UNIMPL door +202 AUE_NULL NOPROTO { int setreuid(int ruid, int euid); } +203 AUE_NULL NOPROTO { int setregid(int rgid, int egid); } +204 AUE_NULL UNIMPL install_utrap +205 AUE_NULL UNIMPL signotify +206 AUE_NULL UNIMPL schedctl +207 AUE_NULL UNIMPL pset +208 AUE_NULL UNIMPL whoknows +209 AUE_NULL STD { int svr4_sys_resolvepath(const char *path, \ + char *buf, size_t bufsiz); } +210 AUE_NULL UNIMPL signotifywait +211 AUE_NULL UNIMPL lwp_sigredirect +212 AUE_NULL UNIMPL lwp_alarm +213 AUE_NULL STD { int svr4_sys_getdents64(int fd, \ + struct svr4_dirent64 *dp, int nbytes); } +;213 AUE_NULL UNIMPL getdents64 +214 AUE_NULL STD { caddr_t svr4_sys_mmap64(void *addr, \ + svr4_size_t len, int prot, int flags, \ + int fd, svr4_off64_t pos); } +215 AUE_NULL STD { int svr4_sys_stat64(char *path, \ + struct svr4_stat64 *sb); } +216 AUE_NULL STD { int svr4_sys_lstat64(char *path, \ + struct svr4_stat64 *sb); } +217 AUE_NULL STD { int svr4_sys_fstat64(int fd, \ + struct svr4_stat64 *sb); } +218 AUE_NULL STD { int svr4_sys_statvfs64(char *path, \ + struct svr4_statvfs64 *fs); } +219 AUE_NULL STD { int svr4_sys_fstatvfs64(int fd, \ + struct svr4_statvfs64 *fs); } +220 AUE_NULL STD { int svr4_sys_setrlimit64(int which, \ + const struct svr4_rlimit64 *rlp); } +221 AUE_NULL STD { int svr4_sys_getrlimit64(int which, \ + struct svr4_rlimit64 *rlp); } +222 AUE_NULL UNIMPL pread64 +223 AUE_NULL UNIMPL pwrite64 +224 AUE_NULL STD { int svr4_sys_creat64(char *path, \ + int mode); } +225 AUE_NULL STD { int svr4_sys_open64(char *path, int flags, \ + int mode); } +226 AUE_NULL UNIMPL rpcsys +227 AUE_NULL UNIMPL whoknows +228 AUE_NULL UNIMPL whoknows +229 AUE_NULL UNIMPL whoknows +230 AUE_NULL STD { int svr4_sys_socket(int domain, int type, \ + int protocol); } +231 AUE_NULL NOPROTO { int socketpair(int domain, int type, \ + int protocol, int *rsv); } +232 AUE_NULL NOPROTO { int bind(int s, \ + const struct sockaddr *name, \ + int namelen); } +233 AUE_NULL NOPROTO { int listen(int s, int backlog); } +234 AUE_NULL NOPROTO { int accept(int s, struct sockaddr *name, \ + int *anamelen); } +235 AUE_NULL NOPROTO { int connect(int s, \ + const struct sockaddr *name, \ + int namelen); } +236 AUE_NULL NOPROTO { int shutdown(int s, int how); } +237 AUE_NULL STD { int svr4_sys_recv(int s, caddr_t buf, \ + int len, int flags); } +238 AUE_NULL NOPROTO { ssize_t recvfrom(int s, void *buf, \ + size_t len, int flags, \ + struct sockaddr *from, \ + int *fromlenaddr); } +239 AUE_NULL NOPROTO { ssize_t recvmsg(int s, struct msghdr *msg, \ + int flags); } +240 AUE_NULL STD { int svr4_sys_send(int s, caddr_t buf, \ + int len, int flags); } +241 AUE_NULL NOPROTO { ssize_t sendmsg(int s, \ + const struct msghdr *msg, int flags); } +242 AUE_NULL STD { ssize_t svr4_sys_sendto(int s, void *buf, \ + size_t len, int flags, \ + struct sockaddr *to, int tolen); } +243 AUE_NULL NOPROTO { int getpeername(int fdes, \ + struct sockaddr *asa, int *alen); } +244 AUE_NULL NOPROTO { int getsockname(int fdes, \ + struct sockaddr *asa, int *alen); } +245 AUE_NULL NOPROTO { int getsockopt(int s, int level, int name, \ + void *val, int *avalsize); } +246 AUE_NULL NOPROTO { int setsockopt(int s, int level, int name, \ + const void *val, int valsize); } +247 AUE_NULL UNIMPL sockconfig +248 AUE_NULL UNIMPL { int ntp_gettime(struct ntptimeval *ntvp); } +249 AUE_NULL UNIMPL { int ntp_adjtime(struct timex *tp); } diff --git a/sys/compat/x86bios/x86bios.c b/sys/compat/x86bios/x86bios.c new file mode 100644 index 0000000..32b9929 --- /dev/null +++ b/sys/compat/x86bios/x86bios.c @@ -0,0 +1,853 @@ +/*- + * 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, NULL, + "x86bios debugging"); +static int x86bios_trace_call; +TUNABLE_INT("debug.x86bios.call", &x86bios_trace_call); +SYSCTL_INT(_debug_x86bios, OID_AUTO, call, CTLFLAG_RW, &x86bios_trace_call, 0, + "Trace far function calls"); +static int x86bios_trace_int; +TUNABLE_INT("debug.x86bios.int", &x86bios_trace_int); +SYSCTL_INT(_debug_x86bios, OID_AUTO, int, CTLFLAG_RW, &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; + 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(&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(&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) +{ + + free(x86bios_map, M_DEVBUF); + if (x86bios_ivt != NULL) +#ifdef X86BIOS_NATIVE_ARCH + pmap_unmapbios((vm_offset_t)x86bios_ivt, X86BIOS_IVT_SIZE); +#else + free(x86bios_ivt, M_DEVBUF); +#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); +} + +static __inline int +x86bios_map_mem(void) +{ + + x86bios_map = malloc(sizeof(*x86bios_map) * X86BIOS_PAGES, M_DEVBUF, + M_WAITOK | M_ZERO); + +#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_ZERO | M_WAITOK); +#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_WAITOK, + X86BIOS_RAM_BASE, x86bios_rom_phys, X86BIOS_PAGE_SIZE, 0); + 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 0000000..491367d --- /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 compatability. + */ + +#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_ */ |