sys_ppc32.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 1,312 行 · 第 1/3 页

C
1,312
字号
/* * sys_ppc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 2001 IBM * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) * * These routines maintain argument size conversion between 32bit and 64bit * environment. * *      This program is free software; you can redistribute it and/or *      modify it under the terms of the GNU General Public License *      as published by the Free Software Foundation; either version *      2 of the License, or (at your option) any later version. */#include <linux/config.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/fs.h> #include <linux/mm.h> #include <linux/file.h> #include <linux/signal.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/shm.h>#include <linux/slab.h>#include <linux/uio.h>#include <linux/aio.h>#include <linux/nfs_fs.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/filter.h>#include <linux/highmem.h>#include <linux/highuid.h>#include <linux/mman.h>#include <linux/ipv6.h>#include <linux/in.h>#include <linux/icmpv6.h>#include <linux/syscalls.h>#include <linux/unistd.h>#include <linux/sysctl.h>#include <linux/binfmts.h>#include <linux/dnotify.h>#include <linux/security.h>#include <linux/compat.h>#include <linux/ptrace.h>#include <linux/aio_abi.h>#include <linux/elf.h>#include <net/scm.h>#include <net/sock.h>#include <asm/ptrace.h>#include <asm/types.h>#include <asm/ipc.h>#include <asm/uaccess.h>#include <asm/unistd.h>#include <asm/semaphore.h>#include <asm/ppcdebug.h>#include <asm/time.h>#include <asm/ppc32.h>#include <asm/mmu_context.h>#include "pci.h"/* readdir & getdents */#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))#define ROUND_UP(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1))struct old_linux_dirent32 {	u32		d_ino;	u32		d_offset;	unsigned short	d_namlen;	char		d_name[1];};struct readdir_callback32 {	struct old_linux_dirent32 __user * dirent;	int count;};static int fillonedir(void * __buf, const char * name, int namlen,		                  off_t offset, ino_t ino, unsigned int d_type){	struct readdir_callback32 * buf = (struct readdir_callback32 *) __buf;	struct old_linux_dirent32 __user * dirent;	if (buf->count)		return -EINVAL;	buf->count++;	dirent = buf->dirent;	put_user(ino, &dirent->d_ino);	put_user(offset, &dirent->d_offset);	put_user(namlen, &dirent->d_namlen);	copy_to_user(dirent->d_name, name, namlen);	put_user(0, dirent->d_name + namlen);	return 0;}asmlinkage int old32_readdir(unsigned int fd, struct old_linux_dirent32 __user *dirent, unsigned int count){	int error = -EBADF;	struct file * file;	struct readdir_callback32 buf;	file = fget(fd);	if (!file)		goto out;	buf.count = 0;	buf.dirent = dirent;	error = vfs_readdir(file, (filldir_t)fillonedir, &buf);	if (error < 0)		goto out_putf;	error = buf.count;out_putf:	fput(file);out:	return error;}struct linux_dirent32 {	u32		d_ino;	u32		d_off;	unsigned short	d_reclen;	char		d_name[1];};struct getdents_callback32 {	struct linux_dirent32 __user * current_dir;	struct linux_dirent32 __user * previous;	int count;	int error;};static int filldir(void * __buf, const char * name, int namlen, off_t offset,		   ino_t ino, unsigned int d_type){	struct linux_dirent32 __user * dirent;	struct getdents_callback32 * buf = (struct getdents_callback32 *) __buf;	int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 2);	buf->error = -EINVAL;	/* only used if we fail.. */	if (reclen > buf->count)		return -EINVAL;	dirent = buf->previous;	if (dirent) {		if (__put_user(offset, &dirent->d_off))			goto efault;	}	dirent = buf->current_dir;	if (__put_user(ino, &dirent->d_ino))		goto efault;	if (__put_user(reclen, &dirent->d_reclen))		goto efault;	if (copy_to_user(dirent->d_name, name, namlen))		goto efault;	if (__put_user(0, dirent->d_name + namlen))		goto efault;	if (__put_user(d_type, (char __user *) dirent + reclen - 1))		goto efault;	buf->previous = dirent;	dirent = (void __user *)dirent + reclen;	buf->current_dir = dirent;	buf->count -= reclen;	return 0;efault:	buf->error = -EFAULT;	return -EFAULT;}asmlinkage long sys32_getdents(unsigned int fd, struct linux_dirent32 __user *dirent,		    unsigned int count){	struct file * file;	struct linux_dirent32 __user * lastdirent;	struct getdents_callback32 buf;	int error;	error = -EFAULT;	if (!access_ok(VERIFY_WRITE, dirent, count))		goto out;	error = -EBADF;	file = fget(fd);	if (!file)		goto out;	buf.current_dir = dirent;	buf.previous = NULL;	buf.count = count;	buf.error = 0;	error = vfs_readdir(file, (filldir_t)filldir, &buf);	if (error < 0)		goto out_putf;	error = buf.error;	lastdirent = buf.previous;	if (lastdirent) {		if (put_user(file->f_pos, &lastdirent->d_off))			error = -EFAULT;		else			error = count - buf.count;	}out_putf:	fput(file);out:	return error;}asmlinkage long ppc32_select(u32 n, compat_ulong_t __user *inp,		compat_ulong_t __user *outp, compat_ulong_t __user *exp,		compat_uptr_t tvp_x){	/* sign extend n */	return compat_sys_select((int)n, inp, outp, exp, compat_ptr(tvp_x));}int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf){	long err;	if (stat->size > MAX_NON_LFS || !new_valid_dev(stat->dev) ||	    !new_valid_dev(stat->rdev))		return -EOVERFLOW;	err  = verify_area(VERIFY_WRITE, statbuf, sizeof(*statbuf));	err |= __put_user(new_encode_dev(stat->dev), &statbuf->st_dev);	err |= __put_user(stat->ino, &statbuf->st_ino);	err |= __put_user(stat->mode, &statbuf->st_mode);	err |= __put_user(stat->nlink, &statbuf->st_nlink);	err |= __put_user(stat->uid, &statbuf->st_uid);	err |= __put_user(stat->gid, &statbuf->st_gid);	err |= __put_user(new_encode_dev(stat->rdev), &statbuf->st_rdev);	err |= __put_user(stat->size, &statbuf->st_size);	err |= __put_user(stat->atime.tv_sec, &statbuf->st_atime);	err |= __put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec);	err |= __put_user(stat->mtime.tv_sec, &statbuf->st_mtime);	err |= __put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec);	err |= __put_user(stat->ctime.tv_sec, &statbuf->st_ctime);	err |= __put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec);	err |= __put_user(stat->blksize, &statbuf->st_blksize);	err |= __put_user(stat->blocks, &statbuf->st_blocks);	err |= __put_user(0, &statbuf->__unused4[0]);	err |= __put_user(0, &statbuf->__unused4[1]);	return err;}/* Note: it is necessary to treat option as an unsigned int, * with the corresponding cast to a signed int to insure that the  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * and the register representation of a signed int (msr in 64-bit mode) is performed. */asmlinkage long sys32_sysfs(u32 option, u32 arg1, u32 arg2){	return sys_sysfs((int)option, arg1, arg2);}/* Handle adjtimex compatibility. */struct timex32 {	u32 modes;	s32 offset, freq, maxerror, esterror;	s32 status, constant, precision, tolerance;	struct compat_timeval time;	s32 tick;	s32 ppsfreq, jitter, shift, stabil;	s32 jitcnt, calcnt, errcnt, stbcnt;	s32  :32; s32  :32; s32  :32; s32  :32;	s32  :32; s32  :32; s32  :32; s32  :32;	s32  :32; s32  :32; s32  :32; s32  :32;};extern int do_adjtimex(struct timex *);extern void ppc_adjtimex(void);asmlinkage long sys32_adjtimex(struct timex32 __user *utp){	struct timex txc;	int ret;		memset(&txc, 0, sizeof(struct timex));	if(get_user(txc.modes, &utp->modes) ||	   __get_user(txc.offset, &utp->offset) ||	   __get_user(txc.freq, &utp->freq) ||	   __get_user(txc.maxerror, &utp->maxerror) ||	   __get_user(txc.esterror, &utp->esterror) ||	   __get_user(txc.status, &utp->status) ||	   __get_user(txc.constant, &utp->constant) ||	   __get_user(txc.precision, &utp->precision) ||	   __get_user(txc.tolerance, &utp->tolerance) ||	   __get_user(txc.time.tv_sec, &utp->time.tv_sec) ||	   __get_user(txc.time.tv_usec, &utp->time.tv_usec) ||	   __get_user(txc.tick, &utp->tick) ||	   __get_user(txc.ppsfreq, &utp->ppsfreq) ||	   __get_user(txc.jitter, &utp->jitter) ||	   __get_user(txc.shift, &utp->shift) ||	   __get_user(txc.stabil, &utp->stabil) ||	   __get_user(txc.jitcnt, &utp->jitcnt) ||	   __get_user(txc.calcnt, &utp->calcnt) ||	   __get_user(txc.errcnt, &utp->errcnt) ||	   __get_user(txc.stbcnt, &utp->stbcnt))		return -EFAULT;	ret = do_adjtimex(&txc);	/* adjust the conversion of TB to time of day to track adjtimex */	ppc_adjtimex();	if(put_user(txc.modes, &utp->modes) ||	   __put_user(txc.offset, &utp->offset) ||	   __put_user(txc.freq, &utp->freq) ||	   __put_user(txc.maxerror, &utp->maxerror) ||	   __put_user(txc.esterror, &utp->esterror) ||	   __put_user(txc.status, &utp->status) ||	   __put_user(txc.constant, &utp->constant) ||	   __put_user(txc.precision, &utp->precision) ||	   __put_user(txc.tolerance, &utp->tolerance) ||	   __put_user(txc.time.tv_sec, &utp->time.tv_sec) ||	   __put_user(txc.time.tv_usec, &utp->time.tv_usec) ||	   __put_user(txc.tick, &utp->tick) ||	   __put_user(txc.ppsfreq, &utp->ppsfreq) ||	   __put_user(txc.jitter, &utp->jitter) ||	   __put_user(txc.shift, &utp->shift) ||	   __put_user(txc.stabil, &utp->stabil) ||	   __put_user(txc.jitcnt, &utp->jitcnt) ||	   __put_user(txc.calcnt, &utp->calcnt) ||	   __put_user(txc.errcnt, &utp->errcnt) ||	   __put_user(txc.stbcnt, &utp->stbcnt))		ret = -EFAULT;	return ret;}/* These are here just in case some old sparc32 binary calls it. */asmlinkage long sys32_pause(void){	current->state = TASK_INTERRUPTIBLE;	schedule();		return -ERESTARTNOHAND;}static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i){	long usec;	if (!access_ok(VERIFY_READ, i, sizeof(*i)))		return -EFAULT;	if (__get_user(o->tv_sec, &i->tv_sec))		return -EFAULT;	if (__get_user(usec, &i->tv_usec))		return -EFAULT;	o->tv_nsec = usec * 1000;	return 0;}static inline long put_tv32(struct compat_timeval __user *o, struct timeval *i){	return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||		(__put_user(i->tv_sec, &o->tv_sec) |		 __put_user(i->tv_usec, &o->tv_usec)));}struct sysinfo32 {        s32 uptime;        u32 loads[3];        u32 totalram;        u32 freeram;        u32 sharedram;        u32 bufferram;        u32 totalswap;        u32 freeswap;        unsigned short procs;	unsigned short pad;	u32 totalhigh;	u32 freehigh;	u32 mem_unit;	char _f[20-2*sizeof(int)-sizeof(int)];};asmlinkage long sys32_sysinfo(struct sysinfo32 __user *info){	struct sysinfo s;	int ret, err;	int bitcount=0;	mm_segment_t old_fs = get_fs ();		/* The __user cast is valid due to set_fs() */	set_fs (KERNEL_DS);	ret = sys_sysinfo((struct sysinfo __user *)&s);	set_fs (old_fs);	/* Check to see if any memory value is too large for 32-bit and         * scale down if needed.         */	if ((s.totalram >> 32) || (s.totalswap >> 32)) {	    while (s.mem_unit < PAGE_SIZE) {		s.mem_unit <<= 1;		bitcount++;	    }	    s.totalram >>=bitcount;	    s.freeram >>= bitcount;	    s.sharedram >>= bitcount;	    s.bufferram >>= bitcount;	    s.totalswap >>= bitcount;	    s.freeswap >>= bitcount;	    s.totalhigh >>= bitcount;	    s.freehigh >>= bitcount;	}	err = put_user (s.uptime, &info->uptime);	err |= __put_user (s.loads[0], &info->loads[0]);	err |= __put_user (s.loads[1], &info->loads[1]);	err |= __put_user (s.loads[2], &info->loads[2]);	err |= __put_user (s.totalram, &info->totalram);	err |= __put_user (s.freeram, &info->freeram);

⌨️ 快捷键说明

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