sys_ppc32.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 1,312 行 · 第 1/3 页
C
1,312 行
/* * 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/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/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/aio.h>#include <linux/nfs_fs.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/ipv6.h>#include <linux/in.h>#include <linux/icmpv6.h>#include <linux/syscalls.h>#include <linux/unistd.h>#include <linux/sysctl.h>#include <linux/binfmts.h>#include <linux/dnotify.h>#include <linux/security.h>#include <linux/compat.h>#include <linux/ptrace.h>#include <linux/aio_abi.h>#include <linux/elf.h>#include <net/scm.h>#include <net/sock.h>#include <asm/ptrace.h>#include <asm/types.h>#include <asm/ipc.h>#include <asm/uaccess.h>#include <asm/unistd.h>#include <asm/semaphore.h>#include <asm/ppcdebug.h>#include <asm/time.h>#include <asm/ppc32.h>#include <asm/mmu_context.h>#include "pci.h"/* readdir & getdents */#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))#define ROUND_UP(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1))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, ino_t ino, unsigned int d_type){ struct readdir_callback32 * buf = (struct readdir_callback32 *) __buf; struct old_linux_dirent32 __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 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;}struct linux_dirent32 { u32 d_ino; u32 d_off; unsigned short d_reclen; char d_name[1];};struct getdents_callback32 { struct linux_dirent32 __user * current_dir; struct linux_dirent32 __user * previous; int count; int error;};static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino, unsigned int d_type){ struct linux_dirent32 __user * dirent; struct getdents_callback32 * buf = (struct getdents_callback32 *) __buf; int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 2); buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; dirent = buf->previous; if (dirent) { if (__put_user(offset, &dirent->d_off)) goto efault; } dirent = buf->current_dir; if (__put_user(ino, &dirent->d_ino)) goto efault; if (__put_user(reclen, &dirent->d_reclen)) goto efault; if (copy_to_user(dirent->d_name, name, namlen)) goto efault; if (__put_user(0, dirent->d_name + namlen)) goto efault; if (__put_user(d_type, (char __user *) dirent + reclen - 1)) goto efault; buf->previous = dirent; dirent = (void __user *)dirent + reclen; buf->current_dir = dirent; buf->count -= reclen; return 0;efault: buf->error = -EFAULT; return -EFAULT;}asmlinkage long sys32_getdents(unsigned int fd, struct linux_dirent32 __user *dirent, unsigned int count){ struct file * file; struct linux_dirent32 __user * lastdirent; struct getdents_callback32 buf; int error; error = -EFAULT; if (!access_ok(VERIFY_WRITE, dirent, count)) goto out; 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, (filldir_t)filldir, &buf); if (error < 0) goto out_putf; error = buf.error; lastdirent = buf.previous; if (lastdirent) { if (put_user(file->f_pos, &lastdirent->d_off)) error = -EFAULT; else error = count - 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){ long err; if (stat->size > MAX_NON_LFS || !new_valid_dev(stat->dev) || !new_valid_dev(stat->rdev)) return -EOVERFLOW; err = verify_area(VERIFY_WRITE, statbuf, sizeof(*statbuf)); err |= __put_user(new_encode_dev(stat->dev), &statbuf->st_dev); err |= __put_user(stat->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 sys32_sysfs(u32 option, u32 arg1, u32 arg2){ return sys_sysfs((int)option, arg1, arg2);}/* 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 *);extern void ppc_adjtimex(void);asmlinkage long sys32_adjtimex(struct timex32 __user *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); /* adjust the conversion of TB to time of day to track adjtimex */ ppc_adjtimex(); 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;}/* These are here just in case some old sparc32 binary calls it. */asmlinkage long sys32_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)));}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(int)-sizeof(int)];};asmlinkage long sys32_sysinfo(struct sysinfo32 __user *info){ struct sysinfo s; int ret, err; int bitcount=0; mm_segment_t old_fs = get_fs (); /* The __user cast is valid due to set_fs() */ set_fs (KERNEL_DS); ret = sys_sysinfo((struct sysinfo __user *)&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; } err = put_user (s.uptime, &info->uptime); err |= __put_user (s.loads[0], &info->loads[0]); err |= __put_user (s.loads[1], &info->loads[1]); err |= __put_user (s.loads[2], &info->loads[2]); err |= __put_user (s.totalram, &info->totalram); err |= __put_user (s.freeram, &info->freeram);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?