sys_ia32.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,384 行 · 第 1/3 页

C
1,384
字号
	struct timeval ktv;	struct timespec kts;	struct timezone ktz; 	if (tv) {		if (get_tv32(&ktv, tv))			return -EFAULT;		kts.tv_sec = ktv.tv_sec;		kts.tv_nsec = ktv.tv_usec * NSEC_PER_USEC;	}	if (tz) {		if (copy_from_user(&ktz, tz, sizeof(ktz)))			return -EFAULT;	}	return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);}struct linux32_dirent {	u32	d_ino;	u32	d_off;	u16	d_reclen;	char	d_name[1];};struct old_linux32_dirent {	u32	d_ino;	u32	d_offset;	u16	d_namlen;	char	d_name[1];};struct getdents32_callback {	struct linux32_dirent __user * current_dir;	struct linux32_dirent __user * previous;	int count;	int error;};struct readdir32_callback {	struct old_linux32_dirent __user * dirent;	int count;};static intfilldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino,	   unsigned int d_type){	struct linux32_dirent __user * dirent;	struct getdents32_callback * buf = (struct getdents32_callback *) __buf;	int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 2, 4);	buf->error = -EINVAL;	/* only used if we fail.. */	if (reclen > buf->count)		return -EINVAL;	dirent = buf->previous;	if (dirent)		put_user(offset, &dirent->d_off);	dirent = buf->current_dir;	buf->previous = dirent;	put_user(ino, &dirent->d_ino);	put_user(reclen, &dirent->d_reclen);	copy_to_user(dirent->d_name, name, namlen);	put_user(0, dirent->d_name + namlen);	put_user(d_type, (char __user *)dirent + reclen - 1); 	dirent = ((void __user *)dirent) + reclen;	buf->current_dir = dirent;	buf->count -= reclen;	return 0;}asmlinkage longsys32_getdents (unsigned int fd, void __user * dirent, unsigned int count){	struct file * file;	struct linux32_dirent __user * lastdirent;	struct getdents32_callback buf;	int error;	error = -EBADF;	file = fget(fd);	if (!file)		goto out;	buf.current_dir = (struct linux32_dirent __user *) dirent;	buf.previous = NULL;	buf.count = count;	buf.error = 0;	error = vfs_readdir(file, filldir32, &buf);	if (error < 0)		goto out_putf;	error = buf.error;	lastdirent = buf.previous;	if (lastdirent) {		put_user(file->f_pos, &lastdirent->d_off);		error = count - buf.count;	}out_putf:	fput(file);out:	return error;}static intfillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t ino, unsigned d_type){	struct readdir32_callback * buf = (struct readdir32_callback *) __buf;	struct old_linux32_dirent __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 longsys32_oldreaddir (unsigned int fd, void __user * dirent, unsigned int count){	int error;	struct file * file;	struct readdir32_callback buf;	error = -EBADF;	file = fget(fd);	if (!file)		goto out;	buf.count = 0;	buf.dirent = dirent;	error = vfs_readdir(file, fillonedir32, &buf);	if (error >= 0)		error = buf.count;	fput(file);out:	return error;}struct sel_arg_struct {	unsigned int n;	unsigned int inp;	unsigned int outp;	unsigned int exp;	unsigned int tvp;};asmlinkage longsys32_old_select(struct sel_arg_struct __user *arg){	struct sel_arg_struct a;	if (copy_from_user(&a, arg, sizeof(a)))		return -EFAULT;	return compat_sys_select(a.n, compat_ptr(a.inp), compat_ptr(a.outp),				 compat_ptr(a.exp), compat_ptr(a.tvp));}/* * sys_time() can be implemented in user-level using * sys_gettimeofday().  x86-64 did this but i386 Linux did not * so we have to implement this system call here. */asmlinkage long sys32_time(int __user * tloc){	int i;	struct timeval tv;	do_gettimeofday(&tv);	i = tv.tv_sec;	if (tloc) {		if (put_user(i,tloc))			i = -EFAULT;	}	return i;}extern asmlinkage longcompat_sys_wait4(compat_pid_t pid, compat_uint_t * stat_addr, int options,		 struct compat_rusage *ru);asmlinkage longsys32_waitpid(compat_pid_t pid, unsigned int *stat_addr, int options){	return compat_sys_wait4(pid, stat_addr, options, NULL);}int sys32_ni_syscall(int call){ 	struct task_struct *me = current;	static char lastcomm[8];	if (strcmp(lastcomm, me->comm)) {	printk(KERN_INFO "IA32 syscall %d from %s not implemented\n", call,	       current->comm);		strcpy(lastcomm, me->comm); 	} 	return -ENOSYS;	       } /* 32-bit timeval and related flotsam.  */asmlinkage longsys32_sysfs(int option, u32 arg1, u32 arg2){	return sys_sysfs(option, arg1, arg2);}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(u32)-sizeof(int)];};asmlinkage longsys32_sysinfo(struct sysinfo32 __user *info){	struct sysinfo s;	int ret;	mm_segment_t old_fs = get_fs ();	int bitcount = 0;		set_fs (KERNEL_DS);	ret = sys_sysinfo(&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;	}	if (verify_area(VERIFY_WRITE, info, sizeof(struct sysinfo32)) ||	    __put_user (s.uptime, &info->uptime) ||	    __put_user (s.loads[0], &info->loads[0]) ||	    __put_user (s.loads[1], &info->loads[1]) ||	    __put_user (s.loads[2], &info->loads[2]) ||	    __put_user (s.totalram, &info->totalram) ||	    __put_user (s.freeram, &info->freeram) ||	    __put_user (s.sharedram, &info->sharedram) ||	    __put_user (s.bufferram, &info->bufferram) ||	    __put_user (s.totalswap, &info->totalswap) ||	    __put_user (s.freeswap, &info->freeswap) ||	    __put_user (s.procs, &info->procs) ||	    __put_user (s.totalhigh, &info->totalhigh) || 	    __put_user (s.freehigh, &info->freehigh) ||	    __put_user (s.mem_unit, &info->mem_unit))		return -EFAULT;	return 0;}                asmlinkage longsys32_sched_rr_get_interval(compat_pid_t pid, struct compat_timespec __user *interval){	struct timespec t;	int ret;	mm_segment_t old_fs = get_fs ();		set_fs (KERNEL_DS);	ret = sys_sched_rr_get_interval(pid, &t);	set_fs (old_fs);	if (put_compat_timespec(&t, interval))		return -EFAULT;	return ret;}asmlinkage longsys32_rt_sigpending(compat_sigset_t __user *set, compat_size_t sigsetsize){	sigset_t s;	compat_sigset_t s32;	int ret;	mm_segment_t old_fs = get_fs();			set_fs (KERNEL_DS);	ret = sys_rt_sigpending(&s, sigsetsize);	set_fs (old_fs);	if (!ret) {		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 (set, &s32, sizeof(compat_sigset_t)))			return -EFAULT;	}	return ret;}asmlinkage longsys32_rt_sigtimedwait(compat_sigset_t __user *uthese, siginfo_t32 __user *uinfo,		      struct compat_timespec __user *uts, compat_size_t sigsetsize){	sigset_t s;	compat_sigset_t s32;	struct timespec t;	int ret;	mm_segment_t old_fs = get_fs();	siginfo_t info;			if (copy_from_user (&s32, uthese, sizeof(compat_sigset_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);	}	if (uts && get_compat_timespec(&t, uts))		return -EFAULT;	if (uinfo) {		/* stop data leak to user space in case of structure fill mismatch		 * between sys_rt_sigtimedwait & ia32_copy_siginfo_to_user.		 */		memset(&info, 0, sizeof(info));	}	set_fs (KERNEL_DS);	ret = sys_rt_sigtimedwait(&s, uinfo ? &info : NULL, uts ? &t : NULL,			sigsetsize);	set_fs (old_fs);	if (ret >= 0 && uinfo) {		if (ia32_copy_siginfo_to_user(uinfo, &info))			return -EFAULT;	}	return ret;}asmlinkage longsys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 __user *uinfo){	siginfo_t info;	int ret;	mm_segment_t old_fs = get_fs();		if (ia32_copy_siginfo_from_user(&info, uinfo))		return -EFAULT;	set_fs (KERNEL_DS);	ret = sys_rt_sigqueueinfo(pid, sig, &info);	set_fs (old_fs);	return ret;}/* These are here just in case some old ia32 binary calls it. */asmlinkage longsys32_pause(void){	current->state = TASK_INTERRUPTIBLE;	schedule();	return -ERESTARTNOHAND;}struct sysctl_ia32 {	unsigned int	name;	int		nlen;	unsigned int	oldval;	unsigned int	oldlenp;	unsigned int	newval;	unsigned int	newlen;	unsigned int	__unused[4];};asmlinkage longsys32_sysctl(struct sysctl_ia32 __user *args32){#ifndef CONFIG_SYSCTL	return -ENOSYS; #else	struct sysctl_ia32 a32;	mm_segment_t old_fs = get_fs ();	void *oldvalp, *newvalp;	size_t oldlen;	int *namep;	long ret;	extern int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,		     void *newval, size_t newlen);	if (copy_from_user(&a32, args32, sizeof (a32)))		return -EFAULT;	/*	 * We need to pre-validate these because we have to disable address checking	 * before calling do_sysctl() because of OLDLEN but we can't run the risk of the	 * user specifying bad addresses here.  Well, since we're dealing with 32 bit	 * addresses, we KNOW that access_ok() will always succeed, so this is an	 * expensive NOP, but so what...	 */	namep = (int *) A(a32.name);	oldvalp = (void *) A(a32.oldval);	newvalp = (void *) A(a32.newval);	if ((oldvalp && get_user(oldlen, (int __user *)compat_ptr(a32.oldlenp)))	    || !access_ok(VERIFY_WRITE, namep, 0)	    || !access_ok(VERIFY_WRITE, oldvalp, 0)	    || !access_ok(VERIFY_WRITE, newvalp, 0))		return -EFAULT;	set_fs(KERNEL_DS);	lock_kernel();	ret = do_sysctl(namep, a32.nlen, oldvalp, &oldlen, newvalp, (size_t) a32.newlen);	unlock_kernel();	set_fs(old_fs);	if (oldvalp && put_user (oldlen, (int __user *)compat_ptr(a32.oldlenp)))		return -EFAULT;	return ret;#endif}/* warning: next two assume little endian */ asmlinkage longsys32_pread(unsigned int fd, char __user *ubuf, u32 count, u32 poslo, u32 poshi){	return sys_pread64(fd, ubuf, count,			 ((loff_t)AA(poshi) << 32) | AA(poslo));}asmlinkage longsys32_pwrite(unsigned int fd, char __user *ubuf, u32 count, u32 poslo, u32 poshi){	return sys_pwrite64(fd, ubuf, count,			  ((loff_t)AA(poshi) << 32) | AA(poslo));}asmlinkage longsys32_personality(unsigned long personality)

⌨️ 快捷键说明

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