sys_ia32.c
来自「该文件是rt_linux」· C语言 代码 · 共 2,528 行 · 第 1/5 页
C
2,528 行
extern int sys_ustat(dev_t, struct ustat *);int sys32_ustat(dev_t dev, struct ustat32 *u32p){ struct ustat u; mm_segment_t seg; int ret; seg = get_fs(); set_fs(KERNEL_DS); ret = sys_ustat(dev,&u); set_fs(seg); if (ret >= 0) { if (!access_ok(VERIFY_WRITE,u32p,sizeof(struct ustat32)) || __put_user((__u32) u.f_tfree, &u32p->f_tfree) || __put_user((__u32) u.f_tinode, &u32p->f_tfree) || __copy_to_user(&u32p->f_fname, u.f_fname, sizeof(u.f_fname)) || __copy_to_user(&u32p->f_fpack, u.f_fpack, sizeof(u.f_fpack))) ret = -EFAULT; } return ret;} static int nargs(u32 src, char **dst) { int cnt; u32 val; cnt = 0; do { int ret = get_user(val, (__u32 *)(u64)src); if (ret) return ret; if (dst) dst[cnt] = (char *)(u64)val; cnt++; src += 4; if (cnt >= (MAX_ARG_PAGES*PAGE_SIZE)/sizeof(void*)) return -E2BIG; } while(val); if (dst) dst[cnt-1] = 0; return cnt; } int sys32_execve(char *name, u32 argv, u32 envp, struct pt_regs regs){ mm_segment_t oldseg; char **buf; int na,ne; int ret; unsigned sz; na = nargs(argv, NULL); if (na < 0) return -EFAULT; ne = nargs(envp, NULL); if (ne < 0) return -EFAULT; sz = (na+ne)*sizeof(void *); if (sz > PAGE_SIZE) buf = vmalloc(sz); else buf = kmalloc(sz, GFP_KERNEL); if (!buf) return -ENOMEM; ret = nargs(argv, buf); if (ret < 0) goto free; ret = nargs(envp, buf + na); if (ret < 0) goto free; name = getname(name); ret = PTR_ERR(name); if (IS_ERR(name)) goto free; oldseg = get_fs(); set_fs(KERNEL_DS); ret = do_execve(name, buf, buf+na, ®s); set_fs(oldseg); if (ret == 0) current->ptrace &= ~PT_DTRACE; putname(name); free: if (sz > PAGE_SIZE) vfree(buf); else kfree(buf); return ret; } asmlinkage int sys32_fork(struct pt_regs regs){ return do_fork(SIGCHLD, regs.rsp, ®s, 0);}asmlinkage int sys32_clone(unsigned int clone_flags, unsigned int newsp, struct pt_regs regs){ if (!newsp) newsp = regs.rsp; return do_fork(clone_flags, newsp, ®s, 0);}/* * This is trivial, and on the face of it looks like it * could equally well be done in user mode. * * Not so, for quite unobvious reasons - register pressure. * In user mode vfork() cannot have a stack frame, and if * done by calling the "clone()" system call directly, you * do not have enough call-clobbered registers to hold all * the information you need. */asmlinkage int sys32_vfork(struct pt_regs regs){ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, ®s, 0);}/* * Some system calls that need sign extended arguments. This could be done by a generic wrapper. */ extern off_t sys_lseek (unsigned int fd, off_t offset, unsigned int origin);int sys32_lseek (unsigned int fd, int offset, unsigned int whence){ return sys_lseek(fd, offset, whence);}extern int sys_kill(pid_t pid, int sig); int sys32_kill(int pid, int sig){ return sys_kill(pid, sig);} #if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)/* Stuff for NFS server syscalls... */struct nfsctl_svc32 { u16 svc32_port; s32 svc32_nthreads;};struct nfsctl_client32 { s8 cl32_ident[NFSCLNT_IDMAX+1]; s32 cl32_naddr; struct in_addr cl32_addrlist[NFSCLNT_ADDRMAX]; s32 cl32_fhkeytype; s32 cl32_fhkeylen; u8 cl32_fhkey[NFSCLNT_KEYMAX];};struct nfsctl_export32 { s8 ex32_client[NFSCLNT_IDMAX+1]; s8 ex32_path[NFS_MAXPATHLEN+1]; __kernel_dev_t32 ex32_dev; __kernel_ino_t32 ex32_ino; s32 ex32_flags; __kernel_uid_t32 ex32_anon_uid; __kernel_gid_t32 ex32_anon_gid;};struct nfsctl_uidmap32 { u32 ug32_ident; /* char * */ __kernel_uid_t32 ug32_uidbase; s32 ug32_uidlen; u32 ug32_udimap; /* uid_t * */ __kernel_uid_t32 ug32_gidbase; s32 ug32_gidlen; u32 ug32_gdimap; /* gid_t * */};struct nfsctl_fhparm32 { struct sockaddr gf32_addr; __kernel_dev_t32 gf32_dev; __kernel_ino_t32 gf32_ino; s32 gf32_version;};struct nfsctl_fdparm32 { struct sockaddr gd32_addr; s8 gd32_path[NFS_MAXPATHLEN+1]; s32 gd32_version;};struct nfsctl_fsparm32 { struct sockaddr gd32_addr; s8 gd32_path[NFS_MAXPATHLEN+1]; s32 gd32_maxlen;};struct nfsctl_arg32 { s32 ca32_version; /* safeguard */ union { struct nfsctl_svc32 u32_svc; struct nfsctl_client32 u32_client; struct nfsctl_export32 u32_export; struct nfsctl_uidmap32 u32_umap; struct nfsctl_fhparm32 u32_getfh; struct nfsctl_fdparm32 u32_getfd; struct nfsctl_fsparm32 u32_getfs; } u;#define ca32_svc u.u32_svc#define ca32_client u.u32_client#define ca32_export u.u32_export#define ca32_umap u.u32_umap#define ca32_getfh u.u32_getfh#define ca32_getfd u.u32_getfd#define ca32_getfs u.u32_getfs#define ca32_authd u.u32_authd};union nfsctl_res32 { __u8 cr32_getfh[NFS_FHSIZE]; struct knfsd_fh cr32_getfs;};static int nfs_svc32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32){ int err; err = get_user(karg->ca_version, &arg32->ca32_version); err |= __get_user(karg->ca_svc.svc_port, &arg32->ca32_svc.svc32_port); err |= __get_user(karg->ca_svc.svc_nthreads, &arg32->ca32_svc.svc32_nthreads); return err;}static int nfs_clnt32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32){ int err; err = get_user(karg->ca_version, &arg32->ca32_version); err |= copy_from_user(&karg->ca_client.cl_ident[0], &arg32->ca32_client.cl32_ident[0], NFSCLNT_IDMAX); err |= __get_user(karg->ca_client.cl_naddr, &arg32->ca32_client.cl32_naddr); err |= copy_from_user(&karg->ca_client.cl_addrlist[0], &arg32->ca32_client.cl32_addrlist[0], (sizeof(struct in_addr) * NFSCLNT_ADDRMAX)); err |= __get_user(karg->ca_client.cl_fhkeytype, &arg32->ca32_client.cl32_fhkeytype); err |= __get_user(karg->ca_client.cl_fhkeylen, &arg32->ca32_client.cl32_fhkeylen); err |= copy_from_user(&karg->ca_client.cl_fhkey[0], &arg32->ca32_client.cl32_fhkey[0], NFSCLNT_KEYMAX); return err;}static int nfs_exp32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32){ int err; err = get_user(karg->ca_version, &arg32->ca32_version); err |= copy_from_user(&karg->ca_export.ex_client[0], &arg32->ca32_export.ex32_client[0], NFSCLNT_IDMAX); err |= copy_from_user(&karg->ca_export.ex_path[0], &arg32->ca32_export.ex32_path[0], NFS_MAXPATHLEN); err |= __get_user(karg->ca_export.ex_dev, &arg32->ca32_export.ex32_dev); err |= __get_user(karg->ca_export.ex_ino, &arg32->ca32_export.ex32_ino); err |= __get_user(karg->ca_export.ex_flags, &arg32->ca32_export.ex32_flags); err |= __get_user(karg->ca_export.ex_anon_uid, &arg32->ca32_export.ex32_anon_uid); err |= __get_user(karg->ca_export.ex_anon_gid, &arg32->ca32_export.ex32_anon_gid); karg->ca_export.ex_anon_uid = high2lowuid(karg->ca_export.ex_anon_uid); karg->ca_export.ex_anon_gid = high2lowgid(karg->ca_export.ex_anon_gid); return err;}static int nfs_uud32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32){ u32 uaddr; int i; int err; memset(karg, 0, sizeof(*karg)); if(get_user(karg->ca_version, &arg32->ca32_version)) return -EFAULT; karg->ca_umap.ug_ident = (char *)get_free_page(GFP_USER); if(!karg->ca_umap.ug_ident) return -ENOMEM; err = get_user(uaddr, &arg32->ca32_umap.ug32_ident); if(strncpy_from_user(karg->ca_umap.ug_ident, (char *)A(uaddr), PAGE_SIZE) <= 0) return -EFAULT; err |= __get_user(karg->ca_umap.ug_uidbase, &arg32->ca32_umap.ug32_uidbase); err |= __get_user(karg->ca_umap.ug_uidlen, &arg32->ca32_umap.ug32_uidlen); err |= __get_user(uaddr, &arg32->ca32_umap.ug32_udimap); if (err) return -EFAULT; karg->ca_umap.ug_udimap = kmalloc((sizeof(uid_t) * karg->ca_umap.ug_uidlen), GFP_USER); if(!karg->ca_umap.ug_udimap) return -ENOMEM; for(i = 0; i < karg->ca_umap.ug_uidlen; i++) err |= __get_user(karg->ca_umap.ug_udimap[i], &(((__kernel_uid_t32 *)A(uaddr))[i])); err |= __get_user(karg->ca_umap.ug_gidbase, &arg32->ca32_umap.ug32_gidbase); err |= __get_user(karg->ca_umap.ug_uidlen, &arg32->ca32_umap.ug32_gidlen); err |= __get_user(uaddr, &arg32->ca32_umap.ug32_gdimap); if (err) return -EFAULT; karg->ca_umap.ug_gdimap = kmalloc((sizeof(gid_t) * karg->ca_umap.ug_uidlen), GFP_USER); if(!karg->ca_umap.ug_gdimap) return -ENOMEM; for(i = 0; i < karg->ca_umap.ug_gidlen; i++) err |= __get_user(karg->ca_umap.ug_gdimap[i], &(((__kernel_gid_t32 *)A(uaddr))[i])); return err;}static int nfs_getfh32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32){ int err; err = get_user(karg->ca_version, &arg32->ca32_version); err |= copy_from_user(&karg->ca_getfh.gf_addr, &arg32->ca32_getfh.gf32_addr, (sizeof(struct sockaddr))); err |= __get_user(karg->ca_getfh.gf_dev, &arg32->ca32_getfh.gf32_dev); err |= __get_user(karg->ca_getfh.gf_ino, &arg32->ca32_getfh.gf32_ino); err |= __get_user(karg->ca_getfh.gf_version, &arg32->ca32_getfh.gf32_version); return err;}static int nfs_getfd32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32){ int err; err = get_user(karg->ca_version, &arg32->ca32_version); err |= copy_from_user(&karg->ca_getfd.gd_addr, &arg32->ca32_getfd.gd32_addr, (sizeof(struct sockaddr))); err |= copy_from_user(&karg->ca_getfd.gd_path, &arg32->ca32_getfd.gd32_path, (NFS_MAXPATHLEN+1)); err |= get_user(karg->ca_getfd.gd_version, &arg32->ca32_getfd.gd32_version); return err;}static int nfs_getfs32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32){ int err; err = get_user(karg->ca_version, &arg32->ca32_version); err |= copy_from_user(&karg->ca_getfs.gd_addr, &arg32->ca32_getfs.gd32_addr, (sizeof(struct sockaddr))); err |= copy_from_user(&karg->ca_getfs.gd_path, &arg32->ca32_getfs.gd32_path, (NFS_MAXPATHLEN+1)); err |= get_user(karg->ca_getfs.gd_maxlen, &arg32->ca32_getfs.gd32_maxlen); return err;}/* This really doesn't need translations, we are only passing * back a union which contains opaque nfs file handle data. */static int nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res32){ return copy_to_user(res32, kres, sizeof(*res32));}int asmlinkage sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32){ struct nfsctl_arg *karg = NULL; union nfsctl_res *kres = NULL; mm_segment_t oldfs; int err; karg = kmalloc(sizeof(*karg), GFP_USER); if(!karg) return -ENOMEM; if(res32) { kres = kmalloc(sizeof(*kres), GFP_USER); if(!kres) { kfree(karg); return -ENOMEM; } } switch(cmd) { case NFSCTL_SVC: err = nfs_svc32_trans(karg, arg32); break; case NFSCTL_ADDCLIENT: err = nfs_clnt32_trans(karg, arg32); break; case NFSCTL_DELCLIENT: err = nfs_clnt32_trans(karg, arg32); break; case NFSCTL_EXPORT: case NFSCTL_UNEXPORT: err = nfs_exp32_trans(karg, arg32); break; /* This one is unimplemented, be we're ready for it. */ case NFSCTL_UGIDUPDATE: err = nfs_uud32_trans(karg, arg32); break; case NFSCTL_GETFH: err = nfs_getfh32_trans(karg, arg32); break; case NFSCTL_GETFD: err = nfs_getfd32_trans(karg, arg32); break; case NFSCTL_GETFS: err = nfs_getfs32_trans(karg, arg32); break; default: err = -EINVAL; break; } if(err) goto done; oldfs = get_fs(); set_fs(KERNEL_DS); err = sys_nfsservctl(cmd, karg, kres); set_fs(oldfs); if (err) goto done; if((cmd == NFSCTL_GETFH) || (cmd == NFSCTL_GETFD) || (cmd == NFSCTL_GETFS)) err = nfs_getfh32_res_trans(kres, res32);done: if(karg) { if(cmd == NFSCTL_UGIDUPDATE) { if(karg->ca_umap.ug_ident) kfree(karg->ca_umap.ug_ident); if(karg->ca_umap.ug_udimap) kfree(karg->ca_umap.ug_udimap); if(karg->ca_umap.ug_gdimap) kfree(karg->ca_umap.ug_gdimap); } kfree(karg); } if(kres) kfree(kres); return err;}#else /* !NFSD */extern asmlinkage long sys_ni_syscall(void);int asmlinkage sys32_nfsservctl(int cmd, void *notused, void *notused2){ return sys_ni_syscall();}#endifint sys32_module_warning(void){ static long warn_time = -(60*HZ); if (time_before(warn_time + 60*HZ,jiffies) && strcmp(current->comm,"klogd")) { printk(KERN_INFO "%s: 32bit modutils not supported on 64bit kernel\n", current->comm); warn_time = jiffies; } return -ENOSYS ;} struct exec_domain ia32_exec_domain = { name: "linux/x86", pers_low: PER_LINUX32, pers_high: PER_LINUX32,}; static int __init ia32_init (void){ printk("IA32 emulation $Id: sys_ia32.c,v 1.42 2002/09/17 15:23:41 ak Exp $\n"); ia32_exec_domain.signal_map = default_exec_domain.signal_map; ia32_exec_domain.signal_invmap = default_exec_domain.signal_invmap; register_exec_domain(&ia32_exec_domain); return 0;}__initcall(ia32_init);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?