📄 sys_ppc32.c
字号:
/* * 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 <asm/ptrace.h>#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/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/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/filter.h>#include <linux/highmem.h>#include <linux/highuid.h>#include <linux/mman.h>#include <linux/sysctl.h>#include <asm/types.h>#include <asm/ipc.h>#include <asm/uaccess.h>#include <asm/semaphore.h>#include <net/scm.h>#include <linux/elf.h>#include <asm/ppcdebug.h>#include <asm/time.h>#include <asm/ppc32.h>extern unsigned long wall_jiffies;#define USEC_PER_SEC (1000000)/* * These are the flags in the MSR that the user is allowed to change * by modifying the saved value of the MSR on the stack. SE and BE * should not be in this list since gdb may want to change these. I.e, * you should be able to step out of a signal handler to see what * instruction executes next after the signal handler completes. * Alternately, if you stepped into a signal handler, you should be * able to continue 'til the next breakpoint from within the signal * handler, even if the handler returns. */#define MSR_USERCHANGE (MSR_FE0 | MSR_FE1)extern asmlinkage long sys_utime(char * filename, struct utimbuf * times);struct utimbuf32 { __kernel_time_t32 actime, modtime;};asmlinkage long sys32_utime(char * filename, struct utimbuf32 *times){ struct utimbuf t; mm_segment_t old_fs; int ret; char *filenam; PPCDBG(PPCDBG_SYS32NI, "sys32_utime - running - filename=%s, times=%p - pid=%ld, comm=%s \n", filename, times, current->pid, current->comm); if (!times) return sys_utime(filename, NULL); if (get_user(t.actime, ×->actime) || __get_user(t.modtime, ×->modtime)) return -EFAULT; filenam = getname(filename); ret = PTR_ERR(filenam); if (!IS_ERR(filenam)) { old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_utime(filenam, &t); set_fs (old_fs); putname (filenam); } return ret;}struct iovec32 { u32 iov_base; __kernel_size_t32 iov_len; };typedef ssize_t (*IO_fn_t)(struct file *, char *, size_t, loff_t *);static long do_readv_writev32(int type, struct file *file, const struct iovec32 *vector, u32 count){ unsigned long tot_len; struct iovec iovstack[UIO_FASTIOV]; struct iovec *iov=iovstack, *ivp; struct inode *inode; long retval, i; IO_fn_t fn; /* First get the "struct iovec" from user memory and * verify all the pointers */ if (!count) return 0; if(verify_area(VERIFY_READ, vector, sizeof(struct iovec32)*count)) return -EFAULT; if (count > UIO_MAXIOV) return -EINVAL; if (count > UIO_FASTIOV) { iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL); if (!iov) return -ENOMEM; } tot_len = 0; i = count; ivp = iov; while(i > 0) { u32 len; u32 buf; __get_user(len, &vector->iov_len); __get_user(buf, &vector->iov_base); tot_len += len; ivp->iov_base = (void *)A(buf); ivp->iov_len = (__kernel_size_t) len; vector++; ivp++; i--; } inode = file->f_dentry->d_inode; /* VERIFY_WRITE actually means a read, as we write to user space */ retval = locks_verify_area((type == VERIFY_WRITE ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE), inode, file, file->f_pos, tot_len); if (retval) { if (iov != iovstack) kfree(iov); return retval; } /* Then do the actual IO. Note that sockets need to be handled * specially as they have atomicity guarantees and can handle * iovec's natively */ if (inode->i_sock) { int err; err = sock_readv_writev(type, inode, file, iov, count, tot_len); if (iov != iovstack) kfree(iov); return err; } if (!file->f_op) { if (iov != iovstack) kfree(iov); return -EINVAL; } /* VERIFY_WRITE actually means a read, as we write to user space */ fn = file->f_op->read; if (type == VERIFY_READ) fn = (IO_fn_t) file->f_op->write; ivp = iov; while (count > 0) { void * base; int len, nr; base = ivp->iov_base; len = ivp->iov_len; ivp++; count--; nr = fn(file, base, len, &file->f_pos); if (nr < 0) { if (retval) break; retval = nr; break; } retval += nr; if (nr != len) break; } if (iov != iovstack) kfree(iov); return retval;}asmlinkage long sys32_readv(u32 fd, struct iovec32 *vector, u32 count){ struct file *file; long ret = -EBADF; PPCDBG(PPCDBG_SYS32, "sys32_readv - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); file = fget(fd); if(!file) goto bad_file; if (file->f_op && (file->f_mode & FMODE_READ) && (file->f_op->readv || file->f_op->read)) ret = do_readv_writev32(VERIFY_WRITE, file, vector, count); fput(file);bad_file: PPCDBG(PPCDBG_SYS32, "sys32_readv - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); return ret;}asmlinkage long sys32_writev(u32 fd, struct iovec32 *vector, u32 count){ struct file *file; int ret = -EBADF; PPCDBG(PPCDBG_SYS32, "sys32_writev - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); file = fget(fd); if(!file) goto bad_file; if (file->f_op && (file->f_mode & FMODE_WRITE) && (file->f_op->writev || file->f_op->write)) ret = do_readv_writev32(VERIFY_READ, file, vector, count); fput(file);bad_file: PPCDBG(PPCDBG_SYS32, "sys32_writev - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); return ret;}static inline int get_flock(struct flock *kfl, struct flock32 *ufl){ int err; err = get_user(kfl->l_type, &ufl->l_type); err |= __get_user(kfl->l_whence, &ufl->l_whence); err |= __get_user(kfl->l_start, &ufl->l_start); err |= __get_user(kfl->l_len, &ufl->l_len); err |= __get_user(kfl->l_pid, &ufl->l_pid); return err;}static inline int put_flock(struct flock *kfl, struct flock32 *ufl){ int err; err = __put_user(kfl->l_type, &ufl->l_type); err |= __put_user(kfl->l_whence, &ufl->l_whence); err |= __put_user(kfl->l_start, &ufl->l_start); err |= __put_user(kfl->l_len, &ufl->l_len); err |= __put_user(kfl->l_pid, &ufl->l_pid); return err;}extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg);asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg){ switch (cmd) { case F_GETLK: case F_SETLK: case F_SETLKW: { struct flock f; mm_segment_t old_fs; long ret; if(get_flock(&f, (struct flock32 *)arg)) return -EFAULT; old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_fcntl(fd, cmd, (unsigned long)&f); set_fs (old_fs); if(put_flock(&f, (struct flock32 *)arg)) return -EFAULT; return ret; } default: return sys_fcntl(fd, cmd, (unsigned long)arg); }}struct ncp_mount_data32 { int version; unsigned int ncp_fd; __kernel_uid_t32 mounted_uid; __kernel_pid_t32 wdog_pid; unsigned char mounted_vol[NCP_VOLNAME_LEN + 1]; unsigned int time_out; unsigned int retry_count; unsigned int flags; __kernel_uid_t32 uid; __kernel_gid_t32 gid; __kernel_mode_t32 file_mode; __kernel_mode_t32 dir_mode;};static void *do_ncp_super_data_conv(void *raw_data){ struct ncp_mount_data *n = (struct ncp_mount_data *)raw_data; struct ncp_mount_data32 *n32 = (struct ncp_mount_data32 *)raw_data; n->dir_mode = n32->dir_mode; n->file_mode = n32->file_mode; n->gid = n32->gid; n->uid = n32->uid; memmove (n->mounted_vol, n32->mounted_vol, (sizeof (n32->mounted_vol) + 3 * sizeof (unsigned int))); n->wdog_pid = n32->wdog_pid; n->mounted_uid = n32->mounted_uid; return raw_data;}struct smb_mount_data32 { int version; __kernel_uid_t32 mounted_uid; __kernel_uid_t32 uid; __kernel_gid_t32 gid; __kernel_mode_t32 file_mode; __kernel_mode_t32 dir_mode;};static void *do_smb_super_data_conv(void *raw_data){ struct smb_mount_data *s = (struct smb_mount_data *)raw_data; struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data; s->version = s32->version; s->mounted_uid = s32->mounted_uid; s->uid = s32->uid; s->gid = s32->gid; s->file_mode = s32->file_mode; s->dir_mode = s32->dir_mode; return raw_data;}static int copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel){ int i; unsigned long page; struct vm_area_struct *vma; *kernel = 0; if(!user) return 0; vma = find_vma(current->mm, (unsigned long)user); if(!vma || (unsigned long)user < vma->vm_start) return -EFAULT; if(!(vma->vm_flags & VM_READ)) return -EFAULT; i = vma->vm_end - (unsigned long) user; if(PAGE_SIZE <= (unsigned long) i) i = PAGE_SIZE - 1; if(!(page = __get_free_page(GFP_KERNEL))) return -ENOMEM; if(copy_from_user((void *) page, user, i)) { free_page(page); return -EFAULT; } *kernel = page; return 0;}#define SMBFS_NAME "smbfs"#define NCPFS_NAME "ncpfs"asmlinkage long sys32_mount(char *dev_name, char *dir_name, char *type, unsigned long new_flags, u32 data){ unsigned long type_page = 0; unsigned long data_page = 0; unsigned long dev_page = 0; unsigned long dir_page = 0; int err, is_smb, is_ncp; PPCDBG(PPCDBG_SYS32, "sys32_mount - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); is_smb = is_ncp = 0; err = copy_mount_stuff_to_kernel((const void *)type, &type_page); if (err) goto out; if (!type_page) { err = -EINVAL; goto out; } is_smb = !strcmp((char *)type_page, SMBFS_NAME); is_ncp = !strcmp((char *)type_page, NCPFS_NAME); err = copy_mount_stuff_to_kernel((const void *)AA(data), &data_page); if (err) goto type_out; err = copy_mount_stuff_to_kernel(dev_name, &dev_page); if (err) goto data_out; err = copy_mount_stuff_to_kernel(dir_name, &dir_page); if (err) goto dev_out; if (!is_smb && !is_ncp) { lock_kernel(); err = do_mount((char*)dev_page, (char*)dir_page, (char*)type_page, new_flags, (char*)data_page); unlock_kernel(); } else { if (is_ncp) do_ncp_super_data_conv((void *)data_page); else do_smb_super_data_conv((void *)data_page); lock_kernel(); err = do_mount((char*)dev_page, (char*)dir_page, (char*)type_page, new_flags, (char*)data_page); unlock_kernel(); } free_page(dir_page);dev_out: free_page(dev_page);data_out: free_page(data_page);type_out: free_page(type_page);out: PPCDBG(PPCDBG_SYS32, "sys32_mount - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); return err;}struct dqblk32 { __u32 dqb_bhardlimit; __u32 dqb_bsoftlimit; __u32 dqb_curblocks; __u32 dqb_ihardlimit; __u32 dqb_isoftlimit; __u32 dqb_curinodes; __kernel_time_t32 dqb_btime; __kernel_time_t32 dqb_itime;}; extern asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr);/* Note: it is necessary to treat cmd and id 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 sys32_quotactl(u32 cmd_parm, const char *special, u32 id_parm, unsigned long addr){ int cmd = (int)cmd_parm; int id = (int)id_parm; int cmds = cmd >> SUBCMDSHIFT; int err; struct dqblk d; mm_segment_t old_fs; char *spec; PPCDBG(PPCDBG_SYS32, "sys32_quotactl - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); switch (cmds) { case Q_GETQUOTA: break; case Q_SETQUOTA: case Q_SETUSE: case Q_SETQLIM:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -