diff options
-rw-r--r-- | sys/alpha/linux/linux_ipc64.h | 133 | ||||
-rw-r--r-- | sys/compat/linux/linux_ioctl.c | 15 | ||||
-rw-r--r-- | sys/compat/linux/linux_ioctl.h | 9 | ||||
-rw-r--r-- | sys/compat/linux/linux_ipc.c | 308 | ||||
-rw-r--r-- | sys/compat/linux/linux_ipc.h | 9 | ||||
-rw-r--r-- | sys/i386/linux/linux_dummy.c | 2 | ||||
-rw-r--r-- | sys/i386/linux/linux_ipc64.h | 145 | ||||
-rw-r--r-- | sys/i386/linux/linux_machdep.c | 99 |
8 files changed, 669 insertions, 51 deletions
diff --git a/sys/alpha/linux/linux_ipc64.h b/sys/alpha/linux/linux_ipc64.h new file mode 100644 index 0000000..e91c4fd --- /dev/null +++ b/sys/alpha/linux/linux_ipc64.h @@ -0,0 +1,133 @@ +/*- + * Copyright (c) 2002 Maxim Sobolev <sobomax@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _ALPHA_LINUX_LINUX_IPC64_H_ +#define _ALPHA_LINUX_LINUX_IPC64_H_ + +/* + * The ipc64_perm structure for alpha architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 32-bit seq + * - 2 miscellaneous 64-bit values + */ + +struct l_ipc64_perm +{ + l_key_t key; + l_uid_t uid; + l_gid_t gid; + l_uid_t cuid; + l_gid_t cgid; + l_mode_t mode; + l_ushort seq; + l_ushort __pad1; + l_ulong __unused1; + l_ulong __unused2; +}; + +/* + * The msqid64_ds structure for alpha architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 2 miscellaneous 64-bit values + */ + +struct l_msqid64_ds { + struct l_ipc64_perm msg_perm; + 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_cbytes; /* current number of bytes on queue */ + l_ulong msg_qnum; /* number of messages in queue */ + l_ulong msg_qbytes; /* max number of bytes on queue */ + l_pid_t msg_lspid; /* pid of last msgsnd */ + l_pid_t msg_lrpid; /* last receive pid */ + l_ulong __unused1; + l_ulong __unused2; +}; + +/* + * The semid64_ds structure for alpha architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 2 miscellaneous 64-bit values + */ + +struct l_semid64_ds { + struct l_ipc64_perm sem_perm; /* permissions */ + l_time_t sem_otime; /* last semop time */ + l_time_t sem_ctime; /* last change time */ + l_ulong sem_nsems; /* no. of semaphores in array */ + l_ulong __unused1; + l_ulong __unused2; +}; + +/* + * The shmid64_ds structure for alpha architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 2 miscellaneous 64-bit values + */ + +struct l_shmid64_ds { + struct l_ipc64_perm shm_perm; /* operation perms */ + l_size_t shm_segsz; /* size of segment (bytes) */ + l_time_t shm_atime; /* last attach time */ + l_time_t shm_dtime; /* last detach time */ + l_time_t shm_ctime; /* last change time */ + l_pid_t shm_cpid; /* pid of creator */ + l_pid_t shm_lpid; /* pid of last operator */ + l_ulong shm_nattch; /* no. of current attaches */ + l_ulong __unused1; + l_ulong __unused2; +}; + +struct l_shminfo64 { + l_ulong shmmax; + l_ulong shmmin; + l_ulong shmmni; + l_ulong shmseg; + l_ulong shmall; + l_ulong __unused1; + l_ulong __unused2; + l_ulong __unused3; + l_ulong __unused4; +}; + +#endif /* !_ALPHA_LINUX_LINUX_IPC64_H_ */ diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c index 8ddd139..37cc872 100644 --- a/sys/compat/linux/linux_ioctl.c +++ b/sys/compat/linux/linux_ioctl.c @@ -61,6 +61,7 @@ #include <compat/linux/linux_util.h> 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_disk; static linux_ioctl_function_t linux_ioctl_socket; @@ -71,6 +72,8 @@ static linux_ioctl_function_t linux_ioctl_special; 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 disk_handler = @@ -85,6 +88,7 @@ static struct linux_ioctl_handler private_handler = { linux_ioctl_private, LINUX_IOCTL_PRIVATE_MIN, LINUX_IOCTL_PRIVATE_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, disk_handler); DATA_SET(linux_ioctl_handler_set, socket_handler); @@ -1473,6 +1477,13 @@ linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args) return (error); } +static int +linux_ioctl_vfat(struct thread *td, struct linux_ioctl_args *args) +{ + + return (ENOTTY); +} + /* * Sound related ioctls */ @@ -1560,6 +1571,10 @@ linux_ioctl_sound(struct thread *td, struct linux_ioctl_args *args) return (copyout(&version, (caddr_t)args->arg, sizeof(int))); } + case LINUX_SOUND_MIXER_READ_STEREODEVS: + args->cmd = SOUND_MIXER_READ_STEREODEVS; + return (ioctl(td, (struct ioctl_args *)args)); + case LINUX_SOUND_MIXER_READ_DEVMASK: args->cmd = SOUND_MIXER_READ_DEVMASK; return (ioctl(td, (struct ioctl_args *)args)); diff --git a/sys/compat/linux/linux_ioctl.h b/sys/compat/linux/linux_ioctl.h index 0d77e0d..ccee935 100644 --- a/sys/compat/linux/linux_ioctl.h +++ b/sys/compat/linux/linux_ioctl.h @@ -120,6 +120,14 @@ #define LINUX_DVD_HOST_SEND_RPC_STATE 11 /* + * 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 @@ -210,6 +218,7 @@ #define LINUX_SOUND_MIXER_WRITE_LINE2 0x4d0F #define LINUX_SOUND_MIXER_WRITE_LINE3 0x4d10 #define LINUX_OSS_GETVERSION 0x4d76 +#define LINUX_SOUND_MIXER_READ_STEREODEVS 0x4dfb #define LINUX_SOUND_MIXER_READ_DEVMASK 0x4dfe #define LINUX_SOUND_MIXER_WRITE_RECSRC 0x4dff #define LINUX_SNDCTL_DSP_RESET 0x5000 diff --git a/sys/compat/linux/linux_ipc.c b/sys/compat/linux/linux_ipc.c index cf3bf61..f977c57 100644 --- a/sys/compat/linux/linux_ipc.c +++ b/sys/compat/linux/linux_ipc.c @@ -32,11 +32,15 @@ #include <sys/systm.h> #include <sys/sysproto.h> #include <sys/proc.h> +#include <sys/msg.h> #include <sys/sem.h> #include <sys/shm.h> +#include <machine/limits.h> + #include <machine/../linux/linux.h> #include <machine/../linux/linux_proto.h> +#include <machine/../linux/linux_ipc64.h> #include <compat/linux/linux_ipc.h> #include <compat/linux/linux_util.h> @@ -126,6 +130,22 @@ bsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct l_ipc_perm *lpp) lpp->seq = bpp->seq; } +struct l_msqid_ds { + struct l_ipc_perm msg_perm; + struct l_msg *msg_first; /* first message on queue,unused */ + struct l_msg *msg_last; /* last message in queue,unused */ + l_time_t msg_stime; /* last msgsnd time */ + l_time_t msg_rtime; /* last msgrcv time */ + l_time_t msg_ctime; /* last change time */ + l_ulong msg_lcbytes; /* Reuse junk fields for 32 bit */ + l_ulong msg_lqbytes; /* ditto */ + l_ushort msg_cbytes; /* current number of bytes on queue */ + l_ushort msg_qnum; /* number of messages in queue */ + l_ushort msg_qbytes; /* max number of bytes on queue */ + l_pid_t msg_lspid; /* pid of last msgsnd */ + l_pid_t msg_lrpid; /* last receive pid */ +}; + struct l_semid_ds { struct l_ipc_perm sem_perm; l_time_t sem_otime; @@ -199,6 +219,223 @@ bsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct l_shmid_ds *lsp) lsp->private3 = bsp->shm_internal; /* this goes (yet) SOS */ } +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; + + 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) { @@ -223,6 +460,8 @@ linux_semget(struct thread *td, struct linux_semget_args *args) 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; @@ -254,7 +493,7 @@ linux_semctl(struct thread *td, struct linux_semctl_args *args) bsd_args.semnum = args->semnum; bsd_args.arg = unptr; - switch (args->cmd) { + switch (args->cmd & ~LINUX_IPC_64) { case LINUX_IPC_RMID: bsd_args.cmd = IPC_RMID; break; @@ -275,8 +514,8 @@ linux_semctl(struct thread *td, struct linux_semctl_args *args) break; case LINUX_IPC_SET: bsd_args.cmd = IPC_SET; - error = copyin((caddr_t)args->arg.buf, &linux_semid, - sizeof(linux_semid)); + error = linux_semid_pullup(args->cmd & LINUX_IPC_64, + &linux_semid, (caddr_t)args->arg.buf); if (error) return (error); unptr->buf = stackgap_alloc(&sg, sizeof(struct semid_ds)); @@ -284,7 +523,7 @@ linux_semctl(struct thread *td, struct linux_semctl_args *args) return __semctl(td, &bsd_args); case LINUX_IPC_STAT: case LINUX_SEM_STAT: - if( args->cmd == LINUX_IPC_STAT ) + if((args->cmd & ~LINUX_IPC_64) == LINUX_IPC_STAT) bsd_args.cmd = IPC_STAT; else bsd_args.cmd = SEM_STAT; @@ -295,14 +534,10 @@ linux_semctl(struct thread *td, struct linux_semctl_args *args) td->td_retval[0] = IXSEQ_TO_IPCID(bsd_args.semid, unptr->buf->sem_perm); bsd_to_linux_semid_ds(unptr->buf, &linux_semid); - return copyout(&linux_semid, (caddr_t)args->arg.buf, - sizeof(linux_semid)); + return (linux_semid_pushdown(args->cmd & LINUX_IPC_64, + &linux_semid, (caddr_t)args->arg.buf)); case LINUX_IPC_INFO: case LINUX_SEM_INFO: - error = copyin((caddr_t)args->arg.buf, &linux_seminfo, - sizeof(linux_seminfo) ); - if (error) - return error; bcopy(&seminfo, &linux_seminfo, sizeof(linux_seminfo) ); /* XXX BSD equivalent? #define used_semids 10 @@ -321,7 +556,8 @@ linux_semctl(struct thread *td, struct linux_semctl_args *args) case LINUX_SETALL: /* FALLTHROUGH */ default: - uprintf("linux: 'ipc' typ=%d not implemented\n", args->cmd); + uprintf("linux: 'ipc' typ=%d not implemented\n", + args->cmd & ~LINUX_IPC_64); return EINVAL; } return __semctl(td, &bsd_args); @@ -385,12 +621,32 @@ linux_msgctl(struct thread *td, struct linux_msgctl_args *args) struct msqid_ds *buf; } */ bsd_args; int error; + struct l_msqid_ds linux_msqid; + caddr_t sg = stackgap_init(); + error = linux_msqid_pullup(args->cmd & LINUX_IPC_64, + &linux_msqid, (caddr_t)args->buf); + if (error != 0) + return (error); + bsd_args.buf = (struct msqid_ds*)stackgap_alloc(&sg, + sizeof(struct l_msqid_ds)); bsd_args.msqid = args->msqid; - bsd_args.cmd = args->cmd; - bsd_args.buf = (struct msqid_ds *)args->buf; + bsd_args.cmd = args->cmd & ~LINUX_IPC_64; + if (bsd_args.cmd == LINUX_IPC_SET) + linux_to_bsd_msqid_ds(&linux_msqid, bsd_args.buf); + error = msgctl(td, &bsd_args); - return ((args->cmd == LINUX_IPC_RMID && error == EINVAL) ? 0 : error); + if (error != 0) + if (bsd_args.cmd != LINUX_IPC_RMID || error != EINVAL) + return (error); + + if (bsd_args.cmd == LINUX_IPC_STAT) { + bsd_to_linux_msqid_ds(bsd_args.buf, &linux_msqid); + return (linux_msqid_pushdown(args->cmd & LINUX_IPC_64, + &linux_msqid, (caddr_t)args->buf)); + } + + return (0); } int @@ -456,7 +712,7 @@ linux_shmctl(struct thread *td, struct linux_shmctl_args *args) int error; caddr_t sg = stackgap_init(); - switch (args->cmd) { + switch (args->cmd & ~LINUX_IPC_64) { case LINUX_IPC_INFO: bsd_args.shmid = args->shmid; @@ -465,7 +721,8 @@ linux_shmctl(struct thread *td, struct linux_shmctl_args *args) if ((error = shmctl(td, &bsd_args))) return error; bsd_to_linux_shminfo( (struct shminfo *)bsd_args.buf, &linux_shminfo ); - return copyout(&linux_shminfo, (caddr_t)args->buf, sizeof(shminfo)); + return (linux_shminfo_pushdown(args->cmd & LINUX_IPC_64, + &linux_shminfo, (caddr_t)args->buf)); case LINUX_SHM_INFO: bsd_args.shmid = args->shmid; @@ -483,7 +740,8 @@ linux_shmctl(struct thread *td, struct linux_shmctl_args *args) if ((error = shmctl(td, &bsd_args))) return error; bsd_to_linux_shmid_ds(bsd_args.buf, &linux_shmid); - return copyout(&linux_shmid, (caddr_t)args->buf, sizeof(linux_shmid)); + return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64, + &linux_shmid, (caddr_t)args->buf)); case LINUX_SHM_STAT: bsd_args.shmid = args->shmid; @@ -493,11 +751,13 @@ linux_shmctl(struct thread *td, struct linux_shmctl_args *args) return error; } bsd_to_linux_shmid_ds(bsd_args.buf, &linux_shmid); - return copyout(&linux_shmid, (caddr_t)args->buf, sizeof(linux_shmid)); + return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64, + &linux_shmid, (caddr_t)args->buf)); case LINUX_IPC_SET: - if ((error = copyin((caddr_t)args->buf, &linux_shmid, - sizeof(linux_shmid)))) + error = linux_shmid_pullup(args->cmd & LINUX_IPC_64, + &linux_shmid, (caddr_t)args->buf); + if (error != 0) return error; bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds)); linux_to_bsd_shmid_ds(&linux_shmid, bsd_args.buf); @@ -511,8 +771,9 @@ linux_shmctl(struct thread *td, struct linux_shmctl_args *args) if (args->buf == NULL) bsd_args.buf = NULL; else { - if ((error = copyin((caddr_t)args->buf, &linux_shmid, - sizeof(linux_shmid)))) + error = linux_shmid_pullup(args->cmd & LINUX_IPC_64, + &linux_shmid, (caddr_t)args->buf); + if (error != 0) return error; bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds)); linux_to_bsd_shmid_ds(&linux_shmid, bsd_args.buf); @@ -522,7 +783,8 @@ linux_shmctl(struct thread *td, struct linux_shmctl_args *args) case LINUX_SHM_LOCK: case LINUX_SHM_UNLOCK: default: - uprintf("linux: 'ipc' typ=%d not implemented\n", args->cmd); + uprintf("linux: 'ipc' typ=%d not implemented\n", + args->cmd & ~LINUX_IPC_64); return EINVAL; } } diff --git a/sys/compat/linux/linux_ipc.h b/sys/compat/linux/linux_ipc.h index 183afe1..33a85b7 100644 --- a/sys/compat/linux/linux_ipc.h +++ b/sys/compat/linux/linux_ipc.h @@ -31,6 +31,15 @@ #ifndef _LINUX_IPC_H_ #define _LINUX_IPC_H_ +/* + * 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. */ + #ifdef __i386__ struct linux_msgctl_args diff --git a/sys/i386/linux/linux_dummy.c b/sys/i386/linux/linux_dummy.c index 2d278e8..f94f88e 100644 --- a/sys/i386/linux/linux_dummy.c +++ b/sys/i386/linux/linux_dummy.c @@ -63,9 +63,7 @@ DUMMY(rt_sigqueueinfo); DUMMY(capget); DUMMY(capset); DUMMY(sendfile); -DUMMY(mmap2); DUMMY(truncate64); -DUMMY(ftruncate64); DUMMY(setfsuid); DUMMY(setfsgid); DUMMY(pivot_root); diff --git a/sys/i386/linux/linux_ipc64.h b/sys/i386/linux/linux_ipc64.h new file mode 100644 index 0000000..04ff5f4 --- /dev/null +++ b/sys/i386/linux/linux_ipc64.h @@ -0,0 +1,145 @@ +/*- + * Copyright (c) 2002 Maxim Sobolev <sobomax@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _I386_LINUX_LINUX_IPC64_H_ +#define _I386_LINUX_LINUX_IPC64_H_ + +/* + * The ipc64_perm structure for i386 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 32-bit mode_t and seq + * - 2 miscellaneous 32-bit values + */ + +struct l_ipc64_perm +{ + l_key_t key; + l_uid_t uid; + l_gid_t gid; + l_uid_t cuid; + l_gid_t cgid; + l_mode_t mode; + l_ushort __pad1; + l_ushort seq; + l_ushort __pad2; + l_ulong __unused1; + l_ulong __unused2; +}; + +/* + * The msqid64_ds structure for i386 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct l_msqid64_ds { + struct l_ipc64_perm msg_perm; + l_time_t msg_stime; /* last msgsnd time */ + l_ulong __unused1; + l_time_t msg_rtime; /* last msgrcv time */ + l_ulong __unused2; + l_time_t msg_ctime; /* last change time */ + l_ulong __unused3; + l_ulong msg_cbytes; /* current number of bytes on queue */ + l_ulong msg_qnum; /* number of messages in queue */ + l_ulong msg_qbytes; /* max number of bytes on queue */ + l_pid_t msg_lspid; /* pid of last msgsnd */ + l_pid_t msg_lrpid; /* last receive pid */ + l_ulong __unused4; + l_ulong __unused5; +}; + +/* + * The semid64_ds structure for i386 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct l_semid64_ds { + struct l_ipc64_perm sem_perm; /* permissions */ + l_time_t sem_otime; /* last semop time */ + l_ulong __unused1; + l_time_t sem_ctime; /* last change time */ + l_ulong __unused2; + l_ulong sem_nsems; /* no. of semaphores in array */ + l_ulong __unused3; + l_ulong __unused4; +}; + +/* + * The shmid64_ds structure for i386 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct l_shmid64_ds { + struct l_ipc64_perm shm_perm; /* operation perms */ + l_size_t shm_segsz; /* size of segment (bytes) */ + l_time_t shm_atime; /* last attach time */ + l_ulong __unused1; + l_time_t shm_dtime; /* last detach time */ + l_ulong __unused2; + l_time_t shm_ctime; /* last change time */ + l_ulong __unused3; + l_pid_t shm_cpid; /* pid of creator */ + l_pid_t shm_lpid; /* pid of last operator */ + l_ulong shm_nattch; /* no. of current attaches */ + l_ulong __unused4; + l_ulong __unused5; +}; + +struct l_shminfo64 { + l_ulong shmmax; + l_ulong shmmin; + l_ulong shmmni; + l_ulong shmseg; + l_ulong shmall; + l_ulong __unused1; + l_ulong __unused2; + l_ulong __unused3; + l_ulong __unused4; +}; + +#endif /* !_I386_LINUX_LINUX_IPC64_H_ */ diff --git a/sys/i386/linux/linux_machdep.c b/sys/i386/linux/linux_machdep.c index c468d89..8977c8d 100644 --- a/sys/i386/linux/linux_machdep.c +++ b/sys/i386/linux/linux_machdep.c @@ -385,19 +385,33 @@ struct l_mmap_argv { #define STACK_SIZE (2 * 1024 * 1024) #define GUARD_SIZE (4 * PAGE_SIZE) +static int linux_mmap_common(struct thread *, struct l_mmap_argv *); + +int +linux_mmap2(struct thread *td, struct linux_mmap2_args *args) +{ + struct l_mmap_argv linux_args; + +#ifdef DEBUG + if (ldebug(mmap2)) + printf(ARGS(mmap2, "%p, %d, %d, 0x%08x, %d, %d"), + (void *)args->addr, args->len, args->prot, + args->flags, args->fd, args->pgoff); +#endif + + linux_args.addr = (l_caddr_t)args->addr; + linux_args.len = args->len; + linux_args.prot = args->prot; + linux_args.flags = args->flags; + linux_args.fd = args->fd; + linux_args.pos = args->pgoff * PAGE_SIZE; + + return (linux_mmap_common(td, &linux_args)); +} + int linux_mmap(struct thread *td, struct linux_mmap_args *args) { - struct proc *p = td->td_proc; - struct mmap_args /* { - caddr_t addr; - size_t len; - int prot; - int flags; - int fd; - long pad; - off_t pos; - } */ bsd_args; int error; struct l_mmap_argv linux_args; @@ -408,22 +422,39 @@ linux_mmap(struct thread *td, struct linux_mmap_args *args) #ifdef DEBUG if (ldebug(mmap)) printf(ARGS(mmap, "%p, %d, %d, 0x%08x, %d, %d"), - (void *)linux_args.addr, linux_args.len, linux_args.prot, - linux_args.flags, linux_args.fd, linux_args.pos); + (void *)linux_args->addr, linux_args->len, linux_args->prot, + linux_args->flags, linux_args->fd, linux_args->pos); #endif + return (linux_mmap_common(td, &linux_args)); +} + +static int +linux_mmap_common(struct thread *td, struct l_mmap_argv *linux_args) +{ + struct proc *p = td->td_proc; + struct mmap_args /* { + caddr_t addr; + size_t len; + int prot; + int flags; + int fd; + long pad; + off_t pos; + } */ bsd_args; + bsd_args.flags = 0; - if (linux_args.flags & LINUX_MAP_SHARED) + if (linux_args->flags & LINUX_MAP_SHARED) bsd_args.flags |= MAP_SHARED; - if (linux_args.flags & LINUX_MAP_PRIVATE) + if (linux_args->flags & LINUX_MAP_PRIVATE) bsd_args.flags |= MAP_PRIVATE; - if (linux_args.flags & LINUX_MAP_FIXED) + if (linux_args->flags & LINUX_MAP_FIXED) bsd_args.flags |= MAP_FIXED; - if (linux_args.flags & LINUX_MAP_ANON) + if (linux_args->flags & LINUX_MAP_ANON) bsd_args.flags |= MAP_ANON; else bsd_args.flags |= MAP_NOSYNC; - if (linux_args.flags & LINUX_MAP_GROWSDOWN) { + if (linux_args->flags & LINUX_MAP_GROWSDOWN) { bsd_args.flags |= MAP_STACK; /* The linux MAP_GROWSDOWN option does not limit auto @@ -448,7 +479,7 @@ linux_mmap(struct thread *td, struct linux_mmap_args *args) */ /* This gives us TOS */ - bsd_args.addr = linux_args.addr + linux_args.len; + bsd_args.addr = linux_args->addr + linux_args->len; if (bsd_args.addr > p->p_vmspace->vm_maxsaddr) { /* Some linux apps will attempt to mmap @@ -472,8 +503,8 @@ linux_mmap(struct thread *td, struct linux_mmap_args *args) } /* This gives us our maximum stack size */ - if (linux_args.len > STACK_SIZE - GUARD_SIZE) - bsd_args.len = linux_args.len; + if (linux_args->len > STACK_SIZE - GUARD_SIZE) + bsd_args.len = linux_args->len; else bsd_args.len = STACK_SIZE - GUARD_SIZE; @@ -485,16 +516,16 @@ linux_mmap(struct thread *td, struct linux_mmap_args *args) */ bsd_args.addr -= bsd_args.len; } else { - bsd_args.addr = linux_args.addr; - bsd_args.len = linux_args.len; + bsd_args.addr = linux_args->addr; + bsd_args.len = linux_args->len; } - bsd_args.prot = linux_args.prot | PROT_READ; /* always required */ - if (linux_args.flags & LINUX_MAP_ANON) + bsd_args.prot = linux_args->prot | PROT_READ; /* always required */ + if (linux_args->flags & LINUX_MAP_ANON) bsd_args.fd = -1; else - bsd_args.fd = linux_args.fd; - bsd_args.pos = linux_args.pos; + bsd_args.fd = linux_args->fd; + bsd_args.pos = linux_args->pos; bsd_args.pad = 0; #ifdef DEBUG @@ -776,3 +807,19 @@ linux_sigaltstack(struct thread *td, struct linux_sigaltstack_args *uap) return (error); } + +int +linux_ftruncate64(struct thread *td, struct linux_ftruncate64_args *args) +{ + struct ftruncate_args sa; + +#ifdef DEBUG + if (ldebug(ftruncate64)) + printf(ARGS(ftruncate64, "%d, %d"), args->fd, args->length); +#endif + + sa.fd = args->fd; + sa.pad = 0; + sa.length = args->length; + return ftruncate(td, &sa); +} |