📄 compat_linux.c
字号:
task_unlock(current); current->thread.fp_regs.fpc=0; __asm__ __volatile__ ("sr 0,0\n\t" "sfpc 0,0\n\t" : : :"0"); } putname(filename);out: return error;}#ifdef CONFIG_MODULESasmlinkage longsys32_init_module(void __user *umod, unsigned long len, const char __user *uargs){ return sys_init_module(umod, len, uargs);}asmlinkage longsys32_delete_module(const char __user *name_user, unsigned int flags){ return sys_delete_module(name_user, flags);}#else /* CONFIG_MODULES */asmlinkage longsys32_init_module(void __user *umod, unsigned long len, const char __user *uargs){ return -ENOSYS;}asmlinkage longsys32_delete_module(const char __user *name_user, unsigned int flags){ return -ENOSYS;}#endif /* CONFIG_MODULES *//* Translations due to time_t size differences. Which affects all sorts of things, like timeval and itimerval. */extern struct timezone sys_tz;asmlinkage long sys32_gettimeofday(struct compat_timeval *tv, struct timezone *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;}static inline long get_ts32(struct timespec *o, struct compat_timeval *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;}asmlinkage long sys32_settimeofday(struct compat_timeval *tv, struct timezone *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);}/* These are here just in case some old sparc32 binary calls it. */asmlinkage long sys32_pause(void){ current->state = TASK_INTERRUPTIBLE; schedule(); return -ERESTARTNOHAND;}asmlinkage long sys32_pread64(unsigned int fd, char *ubuf, size_t count, u32 poshi, u32 poslo){ if ((compat_ssize_t) count < 0) return -EINVAL; return sys_pread64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));}asmlinkage long sys32_pwrite64(unsigned int fd, const char *ubuf, size_t count, u32 poshi, u32 poslo){ if ((compat_ssize_t) count < 0) return -EINVAL; return sys_pwrite64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));}asmlinkage compat_ssize_t sys32_readahead(int fd, u32 offhi, u32 offlo, s32 count){ return sys_readahead(fd, ((loff_t)AA(offhi) << 32) | AA(offlo), count);}asmlinkage long sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset, size_t count){ mm_segment_t old_fs = get_fs(); int ret; off_t of; if (offset && get_user(of, offset)) return -EFAULT; set_fs(KERNEL_DS); ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count); set_fs(old_fs); if (offset && put_user(of, offset)) return -EFAULT; return ret;}asmlinkage long sys32_sendfile64(int out_fd, int in_fd, compat_loff_t *offset, s32 count){ mm_segment_t old_fs = get_fs(); int ret; loff_t lof; if (offset && get_user(lof, offset)) return -EFAULT; set_fs(KERNEL_DS); ret = sys_sendfile64(out_fd, in_fd, offset ? &lof : NULL, count); set_fs(old_fs); if (offset && put_user(lof, offset)) return -EFAULT; return ret;}/* 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 *);asmlinkage long sys32_adjtimex(struct timex32 *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); 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;}#ifdef CONFIG_SYSCTLstruct __sysctl_args32 { u32 name; int nlen; u32 oldval; u32 oldlenp; u32 newval; u32 newlen; u32 __unused[4];};asmlinkage long sys32_sysctl(struct __sysctl_args32 *args){ struct __sysctl_args32 tmp; int error; size_t oldlen, *oldlenp = NULL; unsigned long addr = (((long)&args->__unused[0]) + 7) & ~7; if (copy_from_user(&tmp, args, sizeof(tmp))) return -EFAULT; if (tmp.oldval && tmp.oldlenp) { /* Duh, this is ugly and might not work if sysctl_args is in read-only memory, but do_sysctl does indirectly a lot of uaccess in both directions and we'd have to basically copy the whole sysctl.c here, and glibc's __sysctl uses rw memory for the structure anyway. */ if (get_user(oldlen, (u32 *)A(tmp.oldlenp)) || put_user(oldlen, (size_t *)addr)) return -EFAULT; oldlenp = (size_t *)addr; } lock_kernel(); error = do_sysctl((int *)A(tmp.name), tmp.nlen, (void *)A(tmp.oldval), oldlenp, (void *)A(tmp.newval), tmp.newlen); unlock_kernel(); if (oldlenp) { if (!error) { if (get_user(oldlen, (size_t *)addr) || put_user(oldlen, (u32 *)A(tmp.oldlenp))) error = -EFAULT; } copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused)); } return error;}#endifstruct stat64_emu31 { unsigned long long st_dev; unsigned int __pad1;#define STAT64_HAS_BROKEN_ST_INO 1 u32 __st_ino; unsigned int st_mode; unsigned int st_nlink; u32 st_uid; u32 st_gid; unsigned long long st_rdev; unsigned int __pad3; long st_size; u32 st_blksize; unsigned char __pad4[4]; u32 __pad5; /* future possible st_blocks high bits */ u32 st_blocks; /* Number 512-byte blocks allocated. */ u32 st_atime; u32 __pad6; u32 st_mtime; u32 __pad7; u32 st_ctime; u32 __pad8; /* will be high 32 bits of ctime someday */ unsigned long st_ino;}; static int cp_stat64(struct stat64_emu31 *ubuf, struct kstat *stat){ struct stat64_emu31 tmp; memset(&tmp, 0, sizeof(tmp)); tmp.st_dev = huge_encode_dev(stat->dev); tmp.st_ino = stat->ino; tmp.__st_ino = (u32)stat->ino; tmp.st_mode = stat->mode; tmp.st_nlink = (unsigned int)stat->nlink; tmp.st_uid = stat->uid; tmp.st_gid = stat->gid; tmp.st_rdev = huge_encode_dev(stat->rdev); tmp.st_size = stat->size; tmp.st_blksize = (u32)stat->blksize; tmp.st_blocks = (u32)stat->blocks; tmp.st_atime = (u32)stat->atime.tv_sec; tmp.st_mtime = (u32)stat->mtime.tv_sec; tmp.st_ctime = (u32)stat->ctime.tv_sec; return copy_to_user(ubuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; }asmlinkage long sys32_stat64(char * filename, struct stat64_emu31 * statbuf){ struct kstat stat; int ret = vfs_stat(filename, &stat); if (!ret) ret = cp_stat64(statbuf, &stat); return ret;}asmlinkage long sys32_lstat64(char * filename, struct stat64_emu31 * statbuf){ struct kstat stat; int ret = vfs_lstat(filename, &stat); if (!ret) ret = cp_stat64(statbuf, &stat); return ret;}asmlinkage long sys32_fstat64(unsigned long fd, struct stat64_emu31 * statbuf){ struct kstat stat; int ret = vfs_fstat(fd, &stat); if (!ret) ret = cp_stat64(statbuf, &stat); return ret;}/* * 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_emu31 { u32 addr; u32 len; u32 prot; u32 flags; u32 fd; u32 offset;};/* common code for old and new mmaps */static inline long do_mmap2( unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff){ struct file * file = NULL; unsigned long error = -EBADF; flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); if (!(flags & MAP_ANONYMOUS)) { file = fget(fd); if (!file) goto out; } down_write(¤t->mm->mmap_sem); error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); if (!IS_ERR((void *) error) && error + len >= 0x80000000ULL) { /* Result is out of bounds. */ do_munmap(current->mm, addr, len); error = -ENOMEM; } up_write(¤t->mm->mmap_sem); if (file) fput(file);out: return error;}asmlinkage unsigned longold32_mmap(struct mmap_arg_struct_emu31 *arg){ struct mmap_arg_struct_emu31 a; int error = -EFAULT; if (copy_from_user(&a, arg, sizeof(a))) goto out; error = -EINVAL; if (a.offset & ~PAGE_MASK) goto out; error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); out: return error;}asmlinkage long sys32_mmap2(struct mmap_arg_struct_emu31 *arg){ struct mmap_arg_struct_emu31 a; int error = -EFAULT; if (copy_from_user(&a, arg, sizeof(a))) goto out; error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);out: return error;}asmlinkage long sys32_read(unsigned int fd, char * buf, size_t count){ if ((compat_ssize_t) count < 0) return -EINVAL; return sys_read(fd, buf, count);}asmlinkage long sys32_write(unsigned int fd, char * buf, size_t count){ if ((compat_ssize_t) count < 0) return -EINVAL; return sys_write(fd, buf, count);}asmlinkage long sys32_clone(struct pt_regs regs){ unsigned long clone_flags; unsigned long newsp; int *parent_tidptr, *child_tidptr; clone_flags = regs.gprs[3] & 0xffffffffUL; newsp = regs.orig_gpr2 & 0x7fffffffUL; parent_tidptr = (int *) (regs.gprs[4] & 0x7fffffffUL); child_tidptr = (int *) (regs.gprs[5] & 0x7fffffffUL); if (!newsp) newsp = regs.gprs[15]; return do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr);}/* * Wrapper function for sys_timer_create. */extern asmlinkage longsys_timer_create(clockid_t, struct sigevent *, timer_t *);asmlinkage longsys32_timer_create(clockid_t which_clock, struct compat_sigevent *se32, timer_t *timer_id){ struct sigevent se; timer_t ktimer_id; mm_segment_t old_fs; long ret; if (se32 == NULL) return sys_timer_create(which_clock, NULL, timer_id); if (get_compat_sigevent(&se, se32)) return -EFAULT; old_fs = get_fs(); set_fs(KERNEL_DS); ret = sys_timer_create(which_clock, &se, &ktimer_id); set_fs(old_fs); if (!ret) ret = put_user (ktimer_id, timer_id); return ret;}/* * 31 bit emulation wrapper functions for sys_fadvise64/fadvise64_64. * These need to rewrite the advise values for POSIX_FADV_{DONTNEED,NOREUSE} * because the 31 bit values differ from the 64 bit values. */asmlinkage longsys32_fadvise64(int fd, loff_t offset, size_t len, int advise){ if (advise == 4) advise = POSIX_FADV_DONTNEED; else if (advise == 5) advise = POSIX_FADV_NOREUSE; return sys_fadvise64(fd, offset, len, advise);}struct fadvise64_64_args { int fd; long long offset; long long len; int advice;};asmlinkage longsys32_fadvise64_64(struct fadvise64_64_args __user *args){ struct fadvise64_64_args a; if ( copy_from_user(&a, args, sizeof(a)) ) return -EFAULT; if (a.advice == 4) a.advice = POSIX_FADV_DONTNEED; else if (a.advice == 5) a.advice = POSIX_FADV_NOREUSE; return sys_fadvise64_64(a.fd, a.offset, a.len, a.advice);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -