📄 sys_ia32.c
字号:
if (!(flags & MAP_ANONYMOUS)) { file = fget(a.fd); if (!file) return -EBADF; } addr = ia32_do_mmap(file, a.addr, a.len, a.prot, flags, a.offset); if (file) fput(file); return addr;}asmlinkage longsys32_mmap2 (unsigned int addr, unsigned int len, unsigned int prot, unsigned int flags, unsigned int fd, unsigned int pgoff){ struct file *file = NULL; unsigned long retval; flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); if (!(flags & MAP_ANONYMOUS)) { file = fget(fd); if (!file) return -EBADF; } retval = ia32_do_mmap(file, addr, len, prot, flags, (unsigned long) pgoff << IA32_PAGE_SHIFT); if (file) fput(file); return retval;}asmlinkage longsys32_munmap (unsigned int start, unsigned int len){ unsigned int end = start + len; long ret;#if PAGE_SHIFT <= IA32_PAGE_SHIFT ret = sys_munmap(start, end - start);#else if (start > end) return -EINVAL; start = PAGE_ALIGN(start); end = PAGE_START(end); if (start >= end) return 0; down(&ia32_mmap_sem); { ret = sys_munmap(start, end - start); } up(&ia32_mmap_sem);#endif return ret;}#if PAGE_SHIFT > IA32_PAGE_SHIFT/* * When mprotect()ing a partial page, we set the permission to the union of the old * settings and the new settings. In other words, it's only possible to make access to a * partial page less restrictive. */static longmprotect_subpage (unsigned long address, int new_prot){ int old_prot; if (new_prot == PROT_NONE) return 0; /* optimize case where nothing changes... */ old_prot = get_page_prot(address); return sys_mprotect(address, PAGE_SIZE, new_prot | old_prot);}#endif /* PAGE_SHIFT > IA32_PAGE_SHIFT */asmlinkage longsys32_mprotect (unsigned int start, unsigned int len, int prot){ unsigned long end = start + len;#if PAGE_SHIFT > IA32_PAGE_SHIFT long retval = 0;#endif prot = get_prot32(prot);#if PAGE_SHIFT <= IA32_PAGE_SHIFT return sys_mprotect(start, end - start, prot);#else if (OFFSET4K(start)) return -EINVAL; end = IA32_PAGE_ALIGN(end); if (end < start) return -EINVAL; down(&ia32_mmap_sem); { if (PAGE_OFF(start)) { /* start address is 4KB aligned but not page aligned. */ retval = mprotect_subpage(PAGE_START(start), prot); if (retval < 0) goto out; start = PAGE_ALIGN(start); if (start >= end) goto out; /* retval is already zero... */ } if (PAGE_OFF(end)) { /* end address is 4KB aligned but not page aligned. */ retval = mprotect_subpage(PAGE_START(end), prot); if (retval < 0) return retval; end = PAGE_START(end); } retval = sys_mprotect(start, end - start, prot); } out: up(&ia32_mmap_sem); return retval;#endif}asmlinkage longsys32_pipe (int *fd){ int retval; int fds[2]; retval = do_pipe(fds); if (retval) goto out; if (copy_to_user(fd, fds, sizeof(fds))) retval = -EFAULT; out: return retval;}static inline intput_statfs (struct statfs32 *ubuf, struct statfs *kbuf){ int err; if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf))) return -EFAULT; err = __put_user(kbuf->f_type, &ubuf->f_type); err |= __put_user(kbuf->f_bsize, &ubuf->f_bsize); err |= __put_user(kbuf->f_blocks, &ubuf->f_blocks); err |= __put_user(kbuf->f_bfree, &ubuf->f_bfree); err |= __put_user(kbuf->f_bavail, &ubuf->f_bavail); err |= __put_user(kbuf->f_files, &ubuf->f_files); err |= __put_user(kbuf->f_ffree, &ubuf->f_ffree); err |= __put_user(kbuf->f_namelen, &ubuf->f_namelen); err |= __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]); err |= __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]); return err;}extern asmlinkage long sys_statfs(const char * path, struct statfs * buf);asmlinkage longsys32_statfs (const char *path, struct statfs32 *buf){ int ret; struct statfs s; mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); ret = sys_statfs(path, &s); set_fs(old_fs); if (put_statfs(buf, &s)) return -EFAULT; return ret;}extern asmlinkage long sys_fstatfs(unsigned int fd, struct statfs * buf);asmlinkage longsys32_fstatfs (unsigned int fd, struct statfs32 *buf){ int ret; struct statfs s; mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); ret = sys_fstatfs(fd, &s); set_fs(old_fs); if (put_statfs(buf, &s)) return -EFAULT; return ret;}struct timeval32{ int tv_sec, tv_usec;};struct itimerval32{ struct timeval32 it_interval; struct timeval32 it_value;};static inline longget_tv32 (struct timeval *o, struct timeval32 *i){ return (!access_ok(VERIFY_READ, i, sizeof(*i)) || (__get_user(o->tv_sec, &i->tv_sec) | __get_user(o->tv_usec, &i->tv_usec)));}static inline longput_tv32 (struct timeval32 *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)));}static inline longget_it32 (struct itimerval *o, struct itimerval32 *i){ return (!access_ok(VERIFY_READ, i, sizeof(*i)) || (__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) | __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) | __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) | __get_user(o->it_value.tv_usec, &i->it_value.tv_usec)));}static inline longput_it32 (struct itimerval32 *o, struct itimerval *i){ return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) || (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) | __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) | __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) | __put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));}extern int do_getitimer (int which, struct itimerval *value);asmlinkage longsys32_getitimer (int which, struct itimerval32 *it){ struct itimerval kit; int error; error = do_getitimer(which, &kit); if (!error && put_it32(it, &kit)) error = -EFAULT; return error;}extern int do_setitimer (int which, struct itimerval *, struct itimerval *);asmlinkage longsys32_setitimer (int which, struct itimerval32 *in, struct itimerval32 *out){ struct itimerval kin, kout; int error; if (in) { if (get_it32(&kin, in)) return -EFAULT; } else memset(&kin, 0, sizeof(kin)); error = do_setitimer(which, &kin, out ? &kout : NULL); if (error || !out) return error; if (put_it32(out, &kout)) return -EFAULT; return 0;}asmlinkage unsigned longsys32_alarm (unsigned int seconds){ struct itimerval it_new, it_old; unsigned int oldalarm; it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0; it_new.it_value.tv_sec = seconds; it_new.it_value.tv_usec = 0; do_setitimer(ITIMER_REAL, &it_new, &it_old); oldalarm = it_old.it_value.tv_sec; /* ehhh.. We can't return 0 if we have an alarm pending.. */ /* And we'd better return too much than too little anyway */ if (it_old.it_value.tv_usec) oldalarm++; return oldalarm;}/* Translations due to time_t size differences. Which affects all sorts of things, like timeval and itimerval. */struct utimbuf_32 { int atime; int mtime;};extern asmlinkage long sys_utimes(char * filename, struct timeval * utimes);extern asmlinkage long sys_gettimeofday (struct timeval *tv, struct timezone *tz);asmlinkage longsys32_utime (char *filename, struct utimbuf_32 *times32){ mm_segment_t old_fs = get_fs(); struct timeval tv[2], *tvp; long ret; if (times32) { if (get_user(tv[0].tv_sec, ×32->atime)) return -EFAULT; tv[0].tv_usec = 0; if (get_user(tv[1].tv_sec, ×32->mtime)) return -EFAULT; tv[1].tv_usec = 0; set_fs(KERNEL_DS); tvp = tv; } else tvp = NULL; ret = sys_utimes(filename, tvp); set_fs(old_fs); return ret;}extern struct timezone sys_tz;extern int do_sys_settimeofday (struct timeval *tv, struct timezone *tz);asmlinkage longsys32_gettimeofday (struct timeval32 *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;}asmlinkage longsys32_settimeofday (struct timeval32 *tv, struct timezone *tz){ struct timeval ktv; struct timezone ktz; if (tv) { if (get_tv32(&ktv, tv)) return -EFAULT; } if (tz) { if (copy_from_user(&ktz, tz, sizeof(ktz))) return -EFAULT; } return do_sys_settimeofday(tv ? &ktv : NULL, tz ? &ktz : NULL);}struct getdents32_callback { struct linux32_dirent * current_dir; struct linux32_dirent * previous; int count; int error;};struct readdir32_callback { struct old_linux32_dirent * 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 * dirent; struct getdents32_callback * buf = (struct getdents32_callback *) __buf; int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1, 4); buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; buf->error = -EFAULT; /* only used if we fail.. */ dirent = buf->previous; if (dirent) if (put_user(offset, &dirent->d_off)) return -EFAULT; dirent = buf->current_dir; buf->previous = dirent; if (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)) return -EFAULT; ((char *) dirent) += reclen; buf->current_dir = dirent; buf->count -= reclen; return 0;}asmlinkage longsys32_getdents (unsigned int fd, struct linux32_dirent *dirent, unsigned int count){ struct file * file; struct linux32_dirent * lastdirent; struct getdents32_callback buf; int error; 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, filldir32, &buf); if (error < 0) goto out_putf; error = buf.error; lastdirent = buf.previous; if (lastdirent) { error = -EINVAL; if (put_user(file->f_pos, &lastdirent->d_off)) goto out_putf; 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 int d_type){ struct readdir32_callback * buf = (struct readdir32_callback *) __buf; struct old_linux32_dirent * dirent; if (buf->count) return -EINVAL; buf->count++; dirent = buf->dirent; if (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 -EFAULT; return 0;}asmlinkage longsys32_readdir (unsigned int fd, void *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;}/* * We can actually return ERESTARTSYS instead of EINTR, but I'd * like to be certain this leads to no problems. So I return * EINTR just for safety. * * Update: ERESTARTSYS breaks at least the xview clock binary, so * I'm trying ERESTARTNOHAND which restart only when you want to. */#define MAX_SELECT_SECONDS \ ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -