sys_ppc32.c

来自「linux 内核源代码」· C语言 代码 · 共 829 行 · 第 1/2 页

C
829
字号
/* * 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/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/smp.h>#include <linux/smp_lock.h>#include <linux/sem.h>#include <linux/msg.h>#include <linux/shm.h>#include <linux/poll.h>#include <linux/personality.h>#include <linux/stat.h>#include <linux/mman.h>#include <linux/in.h>#include <linux/syscalls.h>#include <linux/unistd.h>#include <linux/sysctl.h>#include <linux/binfmts.h>#include <linux/security.h>#include <linux/compat.h>#include <linux/ptrace.h>#include <linux/elf.h>#include <linux/ipc.h>#include <asm/ptrace.h>#include <asm/types.h>#include <asm/uaccess.h>#include <asm/unistd.h>#include <asm/semaphore.h>#include <asm/time.h>#include <asm/mmu_context.h>#include <asm/ppc-pci.h>#include <asm/syscalls.h>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, u64 ino, unsigned int d_type){	struct readdir_callback32 * buf = (struct readdir_callback32 *) __buf;	struct old_linux_dirent32 __user * dirent;	ino_t d_ino;	if (buf->count)		return -EINVAL;	d_ino = ino;	if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)		return -EOVERFLOW;	buf->count++;	dirent = buf->dirent;	put_user(d_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;}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){	compat_ino_t ino;	long err;	if (stat->size > MAX_NON_LFS || !new_valid_dev(stat->dev) ||	    !new_valid_dev(stat->rdev))		return -EOVERFLOW;	ino = stat->ino;	if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)		return -EOVERFLOW;	err  = access_ok(VERIFY_WRITE, statbuf, sizeof(*statbuf)) ? 0 : -EFAULT;	err |= __put_user(new_encode_dev(stat->dev), &statbuf->st_dev);	err |= __put_user(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 compat_sys_sysfs(u32 option, u32 arg1, u32 arg2){	return sys_sysfs((int)option, arg1, arg2);}asmlinkage long compat_sys_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)));}/* Translations due to time_t size differences.  Which affects all   sorts of things, like timeval and itimerval.  */extern struct timezone sys_tz;asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz){	if (tv) {		struct timeval ktv;		do_gettimeofday(&ktv);		if (put_tv32(tv, &ktv))			return -EFAULT;	}	if (tz) {		if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))			return -EFAULT;	}		return 0;}asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz){	struct timespec kts;	struct timezone ktz;	 	if (tv) {		if (get_ts32(&kts, tv))			return -EFAULT;	}	if (tz) {		if (copy_from_user(&ktz, tz, sizeof(ktz)))			return -EFAULT;	}	return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);}#ifdef CONFIG_SYSVIPClong compat_sys_ipc(u32 call, u32 first, u32 second, u32 third, compat_uptr_t ptr,	       u32 fifth){	int version;	version = call >> 16; /* hack for backward compatibility */	call &= 0xffff;	switch (call) {	case SEMTIMEDOP:		if (fifth)			/* sign extend semid */			return compat_sys_semtimedop((int)first,						     compat_ptr(ptr), second,						     compat_ptr(fifth));		/* else fall through for normal semop() */	case SEMOP:		/* struct sembuf is the same on 32 and 64bit :)) */		/* sign extend semid */		return sys_semtimedop((int)first, compat_ptr(ptr), second,				      NULL);	case SEMGET:		/* sign extend key, nsems */		return sys_semget((int)first, (int)second, third);	case SEMCTL:		/* sign extend semid, semnum */		return compat_sys_semctl((int)first, (int)second, third,					 compat_ptr(ptr));	case MSGSND:		/* sign extend msqid */		return compat_sys_msgsnd((int)first, (int)second, third,					 compat_ptr(ptr));	case MSGRCV:		/* sign extend msqid, msgtyp */		return compat_sys_msgrcv((int)first, second, (int)fifth,					 third, version, compat_ptr(ptr));	case MSGGET:		/* sign extend key */		return sys_msgget((int)first, second);	case MSGCTL:		/* sign extend msqid */		return compat_sys_msgctl((int)first, second, compat_ptr(ptr));	case SHMAT:		/* sign extend shmid */		return compat_sys_shmat((int)first, second, third, version,					compat_ptr(ptr));	case SHMDT:		return sys_shmdt(compat_ptr(ptr));	case SHMGET:		/* sign extend key_t */		return sys_shmget((int)first, second, third);	case SHMCTL:		/* sign extend shmid */		return compat_sys_shmctl((int)first, second, compat_ptr(ptr));	default:		return -ENOSYS;	}	return -ENOSYS;}#endif/* Note: it is necessary to treat out_fd and in_fd as unsigned ints,  * 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 compat_sys_sendfile(u32 out_fd, u32 in_fd, compat_off_t __user * offset, u32 count){	mm_segment_t old_fs = get_fs();	int ret;	off_t of;	off_t __user *up;	if (offset && get_user(of, offset))		return -EFAULT;	/* The __user pointer cast is valid because of the set_fs() */			set_fs(KERNEL_DS);	up = offset ? (off_t __user *) &of : NULL;	ret = sys_sendfile((int)out_fd, (int)in_fd, up, count);	set_fs(old_fs);		if (offset && put_user(of, offset))		return -EFAULT;			return ret;}asmlinkage int compat_sys_sendfile64(int out_fd, int in_fd, compat_loff_t __user *offset, s32 count){	mm_segment_t old_fs = get_fs();	int ret;	loff_t lof;	loff_t __user *up;		if (offset && get_user(lof, offset))		return -EFAULT;			/* The __user pointer cast is valid because of the set_fs() */			set_fs(KERNEL_DS);	up = offset ? (loff_t __user *) &lof : NULL;	ret = sys_sendfile64(out_fd, in_fd, up, count);	set_fs(old_fs);		if (offset && put_user(lof, offset))		return -EFAULT;			return ret;}long compat_sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,		  unsigned long a3, unsigned long a4, unsigned long a5,		  struct pt_regs *regs){	int error;	char * filename;		filename = getname((char __user *) a0);	error = PTR_ERR(filename);	if (IS_ERR(filename))		goto out;	flush_fp_to_thread(current);	flush_altivec_to_thread(current);	error = compat_do_execve(filename, compat_ptr(a1), compat_ptr(a2), regs);	if (error == 0) {		task_lock(current);		current->ptrace &= ~PT_DTRACE;		task_unlock(current);	}	putname(filename);out:	return error;}/* 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 compat_sys_prctl(u32 option, u32 arg2, u32 arg3, u32 arg4, u32 arg5){	return sys_prctl((int)option,			 (unsigned long) arg2,			 (unsigned long) arg3,			 (unsigned long) arg4,			 (unsigned long) arg5);}/* Note: it is necessary to treat pid 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 compat_sys_sched_rr_get_interval(u32 pid, struct compat_timespec __user *interval){	struct timespec t;	int ret;	mm_segment_t old_fs = get_fs ();	/* The __user pointer cast is valid because of the set_fs() */	set_fs (KERNEL_DS);	ret = sys_sched_rr_get_interval((int)pid, (struct timespec __user *) &t);	set_fs (old_fs);	if (put_compat_timespec(&t, interval))		return -EFAULT;	return ret;}

⌨️ 快捷键说明

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