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

📄 sys_ia32.c

📁 上传linux-jx2410的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * sys_ia32.c: Conversion between 32bit and 64bit native syscalls. Derived from sys_sparc32.c. * * 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-2001 Hewlett-Packard Co *	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/sysctl.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 <asm/types.h>#include <asm/uaccess.h>#include <asm/semaphore.h>#include <net/scm.h>#include <net/sock.h>#include <asm/ia32.h>#define DEBUG	0#if DEBUG# define DBG(fmt...)	printk(KERN_DEBUG fmt)#else# define DBG(fmt...)#endif#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)))#define OFFSET4K(a)		((a) & 0xfff)#define PAGE_START(addr)	((addr) & PAGE_MASK)#define PAGE_OFF(addr)		((addr) & ~PAGE_MASK)extern asmlinkage long sys_execve (char *, char **, char **, struct pt_regs *);extern asmlinkage long sys_mprotect (unsigned long, size_t, unsigned long);extern asmlinkage long sys_munmap (unsigned long, size_t);extern unsigned long arch_get_unmapped_area (struct file *, unsigned long, unsigned long,					     unsigned long, unsigned long);/* forward declaration: */asmlinkage long sys32_mprotect (unsigned int, unsigned int, int);/* * Anything that modifies or inspects ia32 user virtual memory must hold this semaphore * while doing so. *//* XXX make per-mm: */static DECLARE_MUTEX(ia32_mmap_sem);static intnargs (unsigned int arg, char **ap){	unsigned int addr;	int n, err;	if (!arg)		return 0;	n = 0;	do {		err = get_user(addr, (unsigned int *)A(arg));		if (err)			return err;		if (ap)			*ap++ = (char *) A(addr);		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;	unsigned long old_map_base, old_task_size, tssd;	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);	av = kmalloc(len, GFP_KERNEL);	if (!av)		return -ENOMEM;	ae = av + na + 1;	av[na] = NULL;	ae[ne] = NULL;	r = nargs(argv, av);	if (r < 0)		goto out;	r = nargs(envp, ae);	if (r < 0)		goto out;	old_map_base  = current->thread.map_base;	old_task_size = current->thread.task_size;	tssd = ia64_get_kr(IA64_KR_TSSD);	/* we may be exec'ing a 64-bit process: reset map base, task-size, and io-base: */	current->thread.map_base  = DEFAULT_MAP_BASE;	current->thread.task_size = DEFAULT_TASK_SIZE;	ia64_set_kr(IA64_KR_IO_BASE, current->thread.old_iob);	ia64_set_kr(IA64_KR_TSSD, current->thread.old_k1);	set_fs(KERNEL_DS);	r = sys_execve(filename, av, ae, regs);	if (r < 0) {		/* oops, execve failed, switch back to old values... */		ia64_set_kr(IA64_KR_IO_BASE, IA32_IOBASE);		ia64_set_kr(IA64_KR_TSSD, tssd);		current->thread.map_base  = old_map_base;		current->thread.task_size = old_task_size;		set_fs(USER_DS);	/* establish new task-size as the address-limit */	  out:		kfree(av);	}	return r;}static inline intputstat (struct stat32 *ubuf, struct stat *kbuf){	int err;	if (clear_user(ubuf, sizeof(*ubuf)))		return 1;	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){	mm_segment_t old_fs = get_fs();	struct stat s;	int ret;	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){	mm_segment_t old_fs = get_fs();	struct stat s;	int ret;	set_fs(KERNEL_DS);	ret = sys_newfstat(fd, &s);	set_fs(old_fs);	if (putstat(statbuf, &s))		return -EFAULT;	return ret;}#if PAGE_SHIFT > IA32_PAGE_SHIFTstatic intget_page_prot (unsigned long addr){	struct vm_area_struct *vma = find_vma(current->mm, addr);	int prot = 0;	if (!vma || vma->vm_start > addr)		return 0;	if (vma->vm_flags & VM_READ)		prot |= PROT_READ;	if (vma->vm_flags & VM_WRITE)		prot |= PROT_WRITE;	if (vma->vm_flags & VM_EXEC)		prot |= PROT_EXEC;	return prot;}/* * Map a subpage by creating an anonymous page that contains the union of the old page and * the subpage. */static unsigned longmmap_subpage (struct file *file, unsigned long start, unsigned long end, int prot, int flags,	      loff_t off){	void *page = (void *) get_zeroed_page(GFP_KERNEL);	struct inode *inode;	unsigned long ret;	int old_prot = get_page_prot(start);	DBG("mmap_subpage(file=%p,start=0x%lx,end=0x%lx,prot=%x,flags=%x,off=0x%llx)\n",	    file, start, end, prot, flags, off);	if (!page)		return -ENOMEM;	if (old_prot)		copy_from_user(page, (void *) PAGE_START(start), PAGE_SIZE);	down_write(&current->mm->mmap_sem);	{		ret = do_mmap(0, PAGE_START(start), PAGE_SIZE, prot | PROT_WRITE,			      flags | MAP_FIXED | MAP_ANONYMOUS, 0);	}	up_write(&current->mm->mmap_sem);	if (IS_ERR((void *) ret))		goto out;	if (old_prot) {		/* copy back the old page contents.  */		if (PAGE_OFF(start))			copy_to_user((void *) PAGE_START(start), page, PAGE_OFF(start));		if (PAGE_OFF(end))			copy_to_user((void *) end, page + PAGE_OFF(end),				     PAGE_SIZE - PAGE_OFF(end));	}	if (!(flags & MAP_ANONYMOUS)) {		/* read the file contents */		inode = file->f_dentry->d_inode;		if (!inode->i_fop || !file->f_op->read		    || ((*file->f_op->read)(file, (char *) start, end - start, &off) < 0))		{			ret = -EINVAL;			goto out;		}	}	if (!(prot & PROT_WRITE))		ret = sys_mprotect(PAGE_START(start), PAGE_SIZE, prot | old_prot);  out:	free_page((unsigned long) page);	return ret;}static unsigned longemulate_mmap (struct file *file, unsigned long start, unsigned long len, int prot, int flags,	      loff_t off){	unsigned long tmp, end, pend, pstart, ret, is_congruent, fudge = 0;	struct inode *inode;	loff_t poff;	end = start + len;	pstart = PAGE_START(start);	pend = PAGE_ALIGN(end);	if (flags & MAP_FIXED) {		if (start > pstart) {			if (flags & MAP_SHARED)				printk(KERN_INFO				       "%s(%d): emulate_mmap() can't share head (addr=0x%lx)\n",				       current->comm, current->pid, start);			ret = mmap_subpage(file, start, min(PAGE_ALIGN(start), end), prot, flags,					   off);			if (IS_ERR((void *) ret))				return ret;			pstart += PAGE_SIZE;			if (pstart >= pend)				return start;	/* done */		}		if (end < pend) {			if (flags & MAP_SHARED)				printk(KERN_INFO				       "%s(%d): emulate_mmap() can't share tail (end=0x%lx)\n",				       current->comm, current->pid, end);			ret = mmap_subpage(file, max(start, PAGE_START(end)), end, prot, flags,					   (off + len) - PAGE_OFF(end));			if (IS_ERR((void *) ret))				return ret;			pend -= PAGE_SIZE;			if (pstart >= pend)				return start;	/* done */		}	} else {		/*		 * If a start address was specified, use it if the entire rounded out area		 * is available.		 */		if (start && !pstart)			fudge = 1;	/* handle case of mapping to range (0,PAGE_SIZE) */		tmp = arch_get_unmapped_area(file, pstart - fudge, pend - pstart, 0, flags);		if (tmp != pstart) {			pstart = tmp;			start = pstart + PAGE_OFF(off);	/* make start congruent with off */			end = start + len;			pend = PAGE_ALIGN(end);		}	}	poff = off + (pstart - start);	/* note: (pstart - start) may be negative */	is_congruent = (flags & MAP_ANONYMOUS) || (PAGE_OFF(poff) == 0);	if ((flags & MAP_SHARED) && !is_congruent)		printk(KERN_INFO "%s(%d): emulate_mmap() can't share contents of incongruent mmap "		       "(addr=0x%lx,off=0x%llx)\n", current->comm, current->pid, start, off);	DBG("mmap_body: mapping [0x%lx-0x%lx) %s with poff 0x%llx\n", pstart, pend,	    is_congruent ? "congruent" : "not congruent", poff);	down_write(&current->mm->mmap_sem);	{		if (!(flags & MAP_ANONYMOUS) && is_congruent)			ret = do_mmap(file, pstart, pend - pstart, prot, flags | MAP_FIXED, poff);		else			ret = do_mmap(0, pstart, pend - pstart,				      prot | ((flags & MAP_ANONYMOUS) ? 0 : PROT_WRITE),				      flags | MAP_FIXED | MAP_ANONYMOUS, 0);	}	up_write(&current->mm->mmap_sem);	if (IS_ERR((void *) ret))		return ret;	if (!is_congruent) {		/* read the file contents */		inode = file->f_dentry->d_inode;		if (!inode->i_fop || !file->f_op->read		    || ((*file->f_op->read)(file, (char *) pstart, pend - pstart, &poff) < 0))		{			sys_munmap(pstart, pend - pstart);			return -EINVAL;		}		if (!(prot & PROT_WRITE) && sys_mprotect(pstart, pend - pstart, prot) < 0)			return EINVAL;	}	return start;}#endif /* PAGE_SHIFT > IA32_PAGE_SHIFT */static inline unsigned intget_prot32 (unsigned int prot){	if (prot & PROT_WRITE)		/* on x86, PROT_WRITE implies PROT_READ which implies PROT_EEC */		prot |= PROT_READ | PROT_WRITE | PROT_EXEC;	else if (prot & (PROT_READ | PROT_EXEC))		/* on x86, there is no distinction between PROT_READ and PROT_EXEC */		prot |= (PROT_READ | PROT_EXEC);	return prot;}unsigned longia32_do_mmap (struct file *file, unsigned long addr, unsigned long len, int prot, int flags,	      loff_t offset){	DBG("ia32_do_mmap(file=%p,addr=0x%lx,len=0x%lx,prot=%x,flags=%x,offset=0x%llx)\n",	    file, addr, len, prot, flags, offset);	if (file && (!file->f_op || !file->f_op->mmap))		return -ENODEV;	len = IA32_PAGE_ALIGN(len);	if (len == 0)		return addr;	if (len > IA32_PAGE_OFFSET || addr > IA32_PAGE_OFFSET - len)		return -EINVAL;	if (OFFSET4K(offset))		return -EINVAL;	prot = get_prot32(prot);#if PAGE_SHIFT > IA32_PAGE_SHIFT	down(&ia32_mmap_sem);	{		addr = emulate_mmap(file, addr, len, prot, flags, offset);	}	up(&ia32_mmap_sem);#else	down_write(&current->mm->mmap_sem);	{		addr = do_mmap(file, addr, len, prot, flags, offset);	}	up_write(&current->mm->mmap_sem);#endif	DBG("ia32_do_mmap: returning 0x%lx\n", addr);	return addr;}/* * 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 addr;	int flags;	if (copy_from_user(&a, arg, sizeof(a)))		return -EFAULT;	if (OFFSET4K(a.offset))		return -EINVAL;	flags = a.flags;	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);

⌨️ 快捷键说明

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