📄 sys_ia32.c
字号:
/* * sys_ia32.c: Conversion between 32bit and 64bit native syscalls. Based on * sys_sparc32 * * Copyright (C) 2000 VA Linux Co * Copyright (C) 2000 Don Dugger <n0ano@valinux.com> * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com> * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 2000 Hewlett-Packard Co. * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 2000,2001,2002 Andi Kleen, SuSE Labs (x86-64 port) * * These routines maintain argument size conversion between 32bit and 64bit * environment. In 2.5 most of this should be moved to a generic directory. * * This file assumes that there is a hole at the end of user address space. * * $Id: sys_ia32.c,v 1.54 2003/03/24 09:28:26 ak Exp $ */#include <linux/config.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/fs.h> #include <linux/file.h> #include <linux/signal.h>#include <linux/utime.h>#include <linux/resource.h>#include <linux/times.h>#include <linux/utsname.h>#include <linux/timex.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/sem.h>#include <linux/msg.h>#include <linux/mm.h>#include <linux/shm.h>#include <linux/slab.h>#include <linux/uio.h>#include <linux/nfs_fs.h>#include <linux/smb_fs.h>#include <linux/smb_mount.h>#include <linux/ncp_fs.h>#include <linux/quota.h>#include <linux/module.h>#include <linux/sunrpc/svc.h>#include <linux/nfsd/nfsd.h>#include <linux/nfsd/cache.h>#include <linux/nfsd/xdr.h>#include <linux/nfsd/syscall.h>#include <linux/poll.h>#include <linux/personality.h>#include <linux/stat.h>#include <linux/ipc.h>#include <linux/rwsem.h>#include <linux/binfmts.h>#include <linux/init.h>#include <asm/mman.h>#include <asm/types.h>#include <asm/uaccess.h>#include <asm/semaphore.h>#include <asm/ipc.h>#include <asm/atomic.h>#include <asm/ldt.h>#include <net/scm.h>#include <net/sock.h>#include <asm/ia32.h>#define A(__x) ((unsigned long)(__x))#define AA(__x) ((unsigned long)(__x))#define ROUND_UP(x,a) ((__typeof__(x))(((unsigned long)(x) + ((a) - 1)) & ~((a) - 1)))#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))#undef high2lowuid#undef high2lowgid#undef low2highuid#undef low2highgid#define high2lowuid(uid) ((uid) > 65535) ? (u16)overflowuid : (u16)(uid)#define high2lowgid(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid)#define low2highuid(uid) ((uid) == (u16)-1) ? (uid_t)-1 : (uid_t)(uid)#define low2highgid(gid) ((gid) == (u16)-1) ? (gid_t)-1 : (gid_t)(gid)extern int overflowuid,overflowgid; static intputstat(struct stat32 *ubuf, struct stat *kbuf){ if (verify_area(VERIFY_WRITE, ubuf, sizeof(struct stat32)) || __put_user (kbuf->st_dev, &ubuf->st_dev) || __put_user (kbuf->st_ino, &ubuf->st_ino) || __put_user (kbuf->st_mode, &ubuf->st_mode) || __put_user (kbuf->st_nlink, &ubuf->st_nlink) || __put_user (kbuf->st_uid, &ubuf->st_uid) || __put_user (kbuf->st_gid, &ubuf->st_gid) || __put_user (kbuf->st_rdev, &ubuf->st_rdev) || __put_user (kbuf->st_size, &ubuf->st_size) || __put_user (kbuf->st_atime, &ubuf->st_atime) || __put_user (kbuf->st_mtime, &ubuf->st_mtime) || __put_user (kbuf->st_ctime, &ubuf->st_ctime) || __put_user (kbuf->st_blksize, &ubuf->st_blksize) || __put_user (kbuf->st_blocks, &ubuf->st_blocks)) return -EFAULT; return 0;}extern asmlinkage long sys_newstat(char * filename, struct stat * statbuf);asmlinkage longsys32_newstat(char * filename, struct stat32 *statbuf){ int ret; struct stat s; mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_newstat(filename, &s); set_fs (old_fs); if (putstat (statbuf, &s)) return -EFAULT; return ret;}extern asmlinkage long sys_newlstat(char * filename, struct stat * statbuf);asmlinkage longsys32_newlstat(char * filename, struct stat32 *statbuf){ int ret; struct stat s; mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_newlstat(filename, &s); set_fs (old_fs); if (putstat (statbuf, &s)) return -EFAULT; return ret;}extern asmlinkage long sys_newfstat(unsigned int fd, struct stat * statbuf);asmlinkage longsys32_newfstat(unsigned int fd, struct stat32 *statbuf){ int ret; struct stat s; mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_newfstat(fd, &s); set_fs (old_fs); if (putstat (statbuf, &s)) return -EFAULT; return ret;}/* Another set for IA32/LFS -- x86_64 struct stat is different due to support for 64bit inode numbers. */static intputstat64(struct stat64 *ubuf, struct stat *kbuf){ if (verify_area(VERIFY_WRITE, ubuf, sizeof(struct stat64)) || __put_user (kbuf->st_dev, &ubuf->st_dev) || __put_user (kbuf->st_ino, &ubuf->__st_ino) || __put_user (kbuf->st_ino, &ubuf->st_ino) || __put_user (kbuf->st_mode, &ubuf->st_mode) || __put_user (kbuf->st_nlink, &ubuf->st_nlink) || __put_user (kbuf->st_uid, &ubuf->st_uid) || __put_user (kbuf->st_gid, &ubuf->st_gid) || __put_user (kbuf->st_rdev, &ubuf->st_rdev) || __put_user (kbuf->st_size, &ubuf->st_size) || __put_user (kbuf->st_atime, &ubuf->st_atime) || __put_user (kbuf->st_mtime, &ubuf->st_mtime) || __put_user (kbuf->st_ctime, &ubuf->st_ctime) || __put_user (kbuf->st_blksize, &ubuf->st_blksize) || __put_user (kbuf->st_blocks, &ubuf->st_blocks)) return -EFAULT; return 0;}asmlinkage longsys32_stat64(char * filename, struct stat64 *statbuf){ int ret; struct stat s; mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_newstat(filename, &s); set_fs (old_fs); if (putstat64 (statbuf, &s)) return -EFAULT; return ret;}asmlinkage longsys32_lstat64(char * filename, struct stat64 *statbuf){ int ret; struct stat s; mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_newlstat(filename, &s); set_fs (old_fs); if (putstat64 (statbuf, &s)) return -EFAULT; return ret;}asmlinkage longsys32_fstat64(unsigned int fd, struct stat64 *statbuf){ int ret; struct stat s; mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_newfstat(fd, &s); set_fs (old_fs); if (putstat64 (statbuf, &s)) return -EFAULT; return ret;}/* Don't set O_LARGEFILE implicitely. */asmlinkage long sys32_open(const char * filename, int flags, int mode){ char * tmp; int fd, error; tmp = getname(filename); fd = PTR_ERR(tmp); if (!IS_ERR(tmp)) { fd = get_unused_fd(); if (fd >= 0) { struct file *f = filp_open(tmp, flags, mode); error = PTR_ERR(f); if (IS_ERR(f)) goto out_error; fd_install(fd, f); }out: putname(tmp); } return fd;out_error: put_unused_fd(fd); fd = error; goto out;}/* * Linux/i386 didn't use to be able to handle more than * 4 system call parameters, so these system calls used a memory * block for parameter passing.. */struct mmap_arg_struct { unsigned int addr; unsigned int len; unsigned int prot; unsigned int flags; unsigned int fd; unsigned int offset;};asmlinkage longsys32_mmap(struct mmap_arg_struct *arg){ struct mmap_arg_struct a; struct file *file = NULL; unsigned long retval; struct mm_struct *mm ; if (copy_from_user(&a, arg, sizeof(a))) return -EFAULT; if (a.offset & ~PAGE_MASK) return -EINVAL; if (!(a.flags & MAP_ANONYMOUS)) { file = fget(a.fd); if (!file) return -EBADF; } if (a.prot & PROT_READ) a.prot |= PROT_EXEC; mm = current->mm; down_write(&mm->mmap_sem); retval = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, a.offset>>PAGE_SHIFT); if (file) fput(file); up_write(&mm->mmap_sem); return retval;}extern asmlinkage long sys_mprotect(unsigned long start,size_t len,unsigned long prot);asmlinkage long sys32_mprotect(unsigned long start, size_t len, unsigned long prot){ if (prot & PROT_READ) prot |= PROT_EXEC; return sys_mprotect(start,len,prot); }asmlinkage longsys32_pipe(int *fd){ int retval; int fds[2]; retval = do_pipe(fds); if (retval) goto out; if (copy_to_user(fd, fds, sizeof(fds))) retval = -EFAULT; out: return retval;}asmlinkage longsys32_rt_sigaction(int sig, struct sigaction32 *act, struct sigaction32 *oact, unsigned int sigsetsize){ struct k_sigaction new_ka, old_ka; int ret; sigset32_t set32; /* XXX: Don't preclude handling different sized sigset_t's. */ if (sigsetsize != sizeof(sigset32_t)) return -EINVAL; if (act) { if (verify_area(VERIFY_READ, act, sizeof(*act)) || __get_user((long)new_ka.sa.sa_handler, &act->sa_handler) || __get_user(new_ka.sa.sa_flags, &act->sa_flags) || __get_user((long)new_ka.sa.sa_restorer, &act->sa_restorer)|| __copy_from_user(&set32, &act->sa_mask, sizeof(sigset32_t))) return -EFAULT; /* FIXME: here we rely on _IA32_NSIG_WORS to be >= than _NSIG_WORDS << 1 */ switch (_NSIG_WORDS) { case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6] | (((long)set32.sig[7]) << 32); case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4] | (((long)set32.sig[5]) << 32); case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2] | (((long)set32.sig[3]) << 32); case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0] | (((long)set32.sig[1]) << 32); } } ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); if (!ret && oact) { /* FIXME: here we rely on _IA32_NSIG_WORS to be >= than _NSIG_WORDS << 1 */ switch (_NSIG_WORDS) { case 4: set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32); set32.sig[6] = old_ka.sa.sa_mask.sig[3]; case 3: set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32); set32.sig[4] = old_ka.sa.sa_mask.sig[2]; case 2: set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32); set32.sig[2] = old_ka.sa.sa_mask.sig[1]; case 1: set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32); set32.sig[0] = old_ka.sa.sa_mask.sig[0]; } if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || __put_user((long)old_ka.sa.sa_handler, &oact->sa_handler) || __put_user((long)old_ka.sa.sa_restorer, &oact->sa_restorer) || __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || __copy_to_user(&oact->sa_mask, &set32, sizeof(sigset32_t))) return -EFAULT; } return ret;}asmlinkage longsys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact){ struct k_sigaction new_ka, old_ka; int ret; if (act) { old_sigset32_t mask; if (verify_area(VERIFY_READ, act, sizeof(*act)) || __get_user((long)new_ka.sa.sa_handler, &act->sa_handler) || __get_user(new_ka.sa.sa_flags, &act->sa_flags) || __get_user((long)new_ka.sa.sa_restorer, &act->sa_restorer) || __get_user(mask, &act->sa_mask)) return -EFAULT; siginitset(&new_ka.sa.sa_mask, mask); } ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); if (!ret && oact) { if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || __put_user((long)old_ka.sa.sa_handler, &oact->sa_handler) || __put_user((long)old_ka.sa.sa_restorer, &oact->sa_restorer) || __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask)) return -EFAULT; } return ret;}extern asmlinkage long sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset, size_t sigsetsize);asmlinkage longsys32_rt_sigprocmask(int how, sigset32_t *set, sigset32_t *oset, unsigned int sigsetsize){ sigset_t s; sigset32_t s32; int ret; mm_segment_t old_fs = get_fs(); if (set) { if (copy_from_user (&s32, set, sizeof(sigset32_t))) return -EFAULT; switch (_NSIG_WORDS) { case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32); case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32); case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32); case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32); } } set_fs (KERNEL_DS); ret = sys_rt_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL, sigsetsize); set_fs (old_fs); if (ret) return ret; if (oset) { switch (_NSIG_WORDS) { case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3]; case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2]; case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1]; case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0]; } if (copy_to_user (oset, &s32, sizeof(sigset32_t))) return -EFAULT; } return 0;}static intput_statfs (struct statfs32 *ubuf, struct statfs *kbuf){ if (verify_area(VERIFY_WRITE, ubuf, sizeof(struct statfs32)) || __put_user (kbuf->f_type, &ubuf->f_type) || __put_user (kbuf->f_bsize, &ubuf->f_bsize) || __put_user (kbuf->f_blocks, &ubuf->f_blocks) || __put_user (kbuf->f_bfree, &ubuf->f_bfree) || __put_user (kbuf->f_bavail, &ubuf->f_bavail) || __put_user (kbuf->f_files, &ubuf->f_files) || __put_user (kbuf->f_ffree, &ubuf->f_ffree) || __put_user (kbuf->f_namelen, &ubuf->f_namelen) || __put_user (kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) || __put_user (kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1])) return -EFAULT; return 0;}extern asmlinkage long sys_statfs(const char * path, struct statfs * buf);asmlinkage longsys32_statfs(const char * path, struct statfs32 *buf){ int ret; struct statfs s; mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_statfs((const char *)path, &s); set_fs (old_fs); if (put_statfs(buf, &s)) return -EFAULT; return ret;}extern asmlinkage long sys_fstatfs(unsigned int fd, struct statfs * buf);asmlinkage longsys32_fstatfs(unsigned int fd, struct statfs32 *buf){ int ret; struct statfs s; mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_fstatfs(fd, &s); set_fs (old_fs); if (put_statfs(buf, &s)) return -EFAULT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -