⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sys_ia32.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * 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> * * These routines maintain argument size conversion between 32bit and 64bit * environment. */#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/malloc.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 <asm/types.h>#include <asm/uaccess.h>#include <asm/semaphore.h>#include <asm/ipc.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)))extern asmlinkage long sys_execve (char *, char **, char **, struct pt_regs *);extern asmlinkage long sys_munmap (unsigned long, size_t len);extern asmlinkage long sys_mprotect (unsigned long, size_t, unsigned long);static intnargs(unsigned int arg, char **ap){	int n, err, addr;	n = 0;	do {		err = get_user(addr, (int *)A(arg));		if (err)			return err;		if (ap) {		/* no access_ok needed, we allocated */			err = __put_user((char *)A(addr), ap++);			if (err)				return err;		}		arg += sizeof(unsigned int);		n++;	} while (addr);	return(n - 1);}asmlinkage longsys32_execve(char *filename,unsigned int argv,unsigned int envp,int dummy3,int dummy4,int dummy5,int dummy6,int dummy7,int stack){	struct pt_regs *regs = (struct pt_regs *)&stack;	char **av, **ae;	int na, ne, len;	long r;	na = nargs(argv, NULL);	if (na < 0)		return(na);	ne = nargs(envp, NULL);	if (ne < 0)		return(ne);	len = (na + ne + 2) * sizeof(*av);	/*	 *  kmalloc won't work because the `sys_exec' code will attempt	 *  to do a `get_user' on the arg list and `get_user' will fail	 *  on a kernel address (simplifies `get_user').  Instead we	 *  do an mmap to get a user address.  Note that since a successful	 *  `execve' frees all current memory we only have to do an	 *  `munmap' if the `execve' failes.	 */	down(&current->mm->mmap_sem);	av = (char **) do_mmap_pgoff(0, 0UL, len, PROT_READ | PROT_WRITE,				     MAP_PRIVATE | MAP_ANONYMOUS, 0);	up(&current->mm->mmap_sem);	if (IS_ERR(av))		return (long)av;	ae = av + na + 1;	r = __put_user(0, (av + na));	if (r)		goto out;	r = __put_user(0, (ae + ne));	if (r)		goto out;	r = nargs(argv, av);	if (r < 0)		goto out;	r = nargs(envp, ae);	if (r < 0)		goto out;	r = sys_execve(filename, av, ae, regs);	if (r < 0)out:		sys_munmap((unsigned long) av, len);	return(r);}static inline intputstat(struct stat32 *ubuf, struct stat *kbuf){	int err;		err = put_user (kbuf->st_dev, &ubuf->st_dev);	err |= __put_user (kbuf->st_ino, &ubuf->st_ino);	err |= __put_user (kbuf->st_mode, &ubuf->st_mode);	err |= __put_user (kbuf->st_nlink, &ubuf->st_nlink);	err |= __put_user (kbuf->st_uid, &ubuf->st_uid);	err |= __put_user (kbuf->st_gid, &ubuf->st_gid);	err |= __put_user (kbuf->st_rdev, &ubuf->st_rdev);	err |= __put_user (kbuf->st_size, &ubuf->st_size);	err |= __put_user (kbuf->st_atime, &ubuf->st_atime);	err |= __put_user (kbuf->st_mtime, &ubuf->st_mtime);	err |= __put_user (kbuf->st_ctime, &ubuf->st_ctime);	err |= __put_user (kbuf->st_blksize, &ubuf->st_blksize);	err |= __put_user (kbuf->st_blocks, &ubuf->st_blocks);	return err;}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;}#define ALIGN4K(a)	(((a) + 0xfff) & ~0xfff)#define OFFSET4K(a)	((a) & 0xfff)unsigned longdo_mmap_fake(struct file *file, unsigned long addr, unsigned long len,	unsigned long prot, unsigned long flags, loff_t off){	struct inode *inode;	void *front, *back;	unsigned long baddr;	int r;	char c;	if (OFFSET4K(addr) || OFFSET4K(off))		return -EINVAL;	prot |= PROT_WRITE;	front = NULL;	back = NULL;	if ((baddr = (addr & PAGE_MASK)) != addr && get_user(c, (char *)baddr) == 0) {		front = kmalloc(addr - baddr, GFP_KERNEL);		__copy_user(front, (void *)baddr, addr - baddr);	}	if (addr && ((addr + len) & ~PAGE_MASK) && get_user(c, (char *)(addr + len)) == 0) {		back = kmalloc(PAGE_SIZE - ((addr + len) & ~PAGE_MASK), GFP_KERNEL);		__copy_user(back, (char *)addr + len, PAGE_SIZE - ((addr + len) & ~PAGE_MASK));	}	down(&current->mm->mmap_sem);	r = do_mmap(0, baddr, len + (addr - baddr), prot, flags | MAP_ANONYMOUS, 0);	up(&current->mm->mmap_sem);	if (r < 0)		return(r);	if (addr == 0)		addr = r;	if (back) {		__copy_user((char *)addr + len, back, PAGE_SIZE - ((addr + len) & ~PAGE_MASK));		kfree(back);	}	if (front) {		__copy_user((void *)baddr, front, addr - baddr);		kfree(front);	}	if (flags & MAP_ANONYMOUS) {		clear_user((char *)addr, len);		return(addr);	}	if (!file)		return -EINVAL;	inode = file->f_dentry->d_inode;	if (!inode->i_fop)		return -EINVAL;	if (!file->f_op->read)		return -EINVAL;	r = file->f_op->read(file, (char *)addr, len, &off);	return (r < 0) ? -EINVAL : addr;}longia32_do_mmap (struct file *file, unsigned int addr, unsigned int len, unsigned int prot,	      unsigned int flags, unsigned int fd, unsigned int offset){	long error = -EFAULT;	unsigned int poff;	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);	prot |= PROT_EXEC; 	if ((flags & MAP_FIXED) && ((addr & ~PAGE_MASK) || (offset & ~PAGE_MASK))) 		error = do_mmap_fake(file, addr, len, prot, flags, (loff_t)offset);	else { 		poff = offset & PAGE_MASK; 		len += offset - poff; 		down(&current->mm->mmap_sem); 		error = do_mmap_pgoff(file, addr, len, prot, flags, poff >> PAGE_SHIFT);  		up(&current->mm->mmap_sem); 		if (!IS_ERR((void *) error)) 			error += offset - poff; 	}	return error;}/* * 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;	long retval;	if (copy_from_user(&a, arg, sizeof(a)))		return -EFAULT;	if (!(a.flags & MAP_ANONYMOUS)) {		file = fget(a.fd);		if (!file)			return -EBADF;	}	retval = ia32_do_mmap(file, a.addr, a.len, a.prot, a.flags, a.fd, a.offset);	if (file)		fput(file);	return retval;}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_mprotect(unsigned long start, size_t len, unsigned long prot){	if (prot == 0)		return(0);	len += start & ~PAGE_MASK;	if ((start & ~PAGE_MASK) && (prot & PROT_WRITE))		prot |= PROT_EXEC;	return(sys_mprotect(start & PAGE_MASK, len & PAGE_MASK, prot));}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) {		ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler);		ret |= __copy_from_user(&set32, &act->sa_mask,					sizeof(sigset32_t));		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 |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);				if (ret)			return -EFAULT;	}	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);	if (!ret && oact) {		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];		}		ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler);		ret |= __copy_to_user(&oact->sa_mask, &set32,				      sizeof(sigset32_t));		ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);	}	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 inline intput_statfs (struct statfs32 *ubuf, struct statfs *kbuf){	int err;		err = put_user (kbuf->f_type, &ubuf->f_type);	err |= __put_user (kbuf->f_bsize, &ubuf->f_bsize);	err |= __put_user (kbuf->f_blocks, &ubuf->f_blocks);	err |= __put_user (kbuf->f_bfree, &ubuf->f_bfree);	err |= __put_user (kbuf->f_bavail, &ubuf->f_bavail);	err |= __put_user (kbuf->f_files, &ubuf->f_files);	err |= __put_user (kbuf->f_ffree, &ubuf->f_ffree);	err |= __put_user (kbuf->f_namelen, &ubuf->f_namelen);	err |= __put_user (kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]);	err |= __put_user (kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]);	return err;}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;	return ret;}struct timeval32{    int tv_sec, tv_usec;};struct itimerval32{    struct timeval32 it_interval;    struct timeval32 it_value;};static inline longget_tv32(struct timeval *o, struct timeval32 *i){	return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||		(__get_user(o->tv_sec, &i->tv_sec) |		 __get_user(o->tv_usec, &i->tv_usec)));	return ENOSYS;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -