sys_ia32.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 2,641 行 · 第 1/5 页
C
2,641 行
break; case 4: case 5: case 6: case 7: ia64f2ia32f(f, &swp->f12 + (regno - 4)); break; } copy_to_user(reg, f, sizeof(*reg));}static voidget_fpreg (int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp, int tos){ if ((regno += tos) >= 8) regno -= 8; switch (regno) { case 0: copy_from_user(&ptp->f8, reg, sizeof(*reg)); break; case 1: copy_from_user(&ptp->f9, reg, sizeof(*reg)); break; case 2: copy_from_user(&ptp->f10, reg, sizeof(*reg)); break; case 3: copy_from_user(&ptp->f11, reg, sizeof(*reg)); break; case 4: case 5: case 6: case 7: copy_from_user(&swp->f12 + (regno - 4), reg, sizeof(*reg)); break; } return;}intsave_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct *save){ struct switch_stack *swp; struct pt_regs *ptp; int i, tos; if (!access_ok(VERIFY_WRITE, save, sizeof(*save))) return -EFAULT; __put_user(tsk->thread.fcr & 0xffff, &save->cwd); __put_user(tsk->thread.fsr & 0xffff, &save->swd); __put_user((tsk->thread.fsr>>16) & 0xffff, &save->twd); __put_user(tsk->thread.fir, &save->fip); __put_user((tsk->thread.fir>>32) & 0xffff, &save->fcs); __put_user(tsk->thread.fdr, &save->foo); __put_user((tsk->thread.fdr>>32) & 0xffff, &save->fos); /* * Stack frames start with 16-bytes of temp space */ swp = (struct switch_stack *)(tsk->thread.ksp + 16); ptp = ia64_task_regs(tsk); tos = (tsk->thread.fsr >> 11) & 7; for (i = 0; i < 8; i++) put_fpreg(i, &save->st_space[i], ptp, swp, tos); return 0;}static intrestore_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct *save){ struct switch_stack *swp; struct pt_regs *ptp; int i, tos; unsigned int fsrlo, fsrhi, num32; if (!access_ok(VERIFY_READ, save, sizeof(*save))) return(-EFAULT); __get_user(num32, (unsigned int *)&save->cwd); tsk->thread.fcr = (tsk->thread.fcr & (~0x1f3f)) | (num32 & 0x1f3f); __get_user(fsrlo, (unsigned int *)&save->swd); __get_user(fsrhi, (unsigned int *)&save->twd); num32 = (fsrhi << 16) | fsrlo; tsk->thread.fsr = (tsk->thread.fsr & (~0xffffffff)) | num32; __get_user(num32, (unsigned int *)&save->fip); tsk->thread.fir = (tsk->thread.fir & (~0xffffffff)) | num32; __get_user(num32, (unsigned int *)&save->foo); tsk->thread.fdr = (tsk->thread.fdr & (~0xffffffff)) | num32; /* * Stack frames start with 16-bytes of temp space */ swp = (struct switch_stack *)(tsk->thread.ksp + 16); ptp = ia64_task_regs(tsk); tos = (tsk->thread.fsr >> 11) & 7; for (i = 0; i < 8; i++) get_fpreg(i, &save->st_space[i], ptp, swp, tos); return 0;}intsave_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct *save){ struct switch_stack *swp; struct pt_regs *ptp; int i, tos; unsigned long mxcsr=0; unsigned long num128[2]; if (!access_ok(VERIFY_WRITE, save, sizeof(*save))) return -EFAULT; __put_user(tsk->thread.fcr & 0xffff, &save->cwd); __put_user(tsk->thread.fsr & 0xffff, &save->swd); __put_user((tsk->thread.fsr>>16) & 0xffff, &save->twd); __put_user(tsk->thread.fir, &save->fip); __put_user((tsk->thread.fir>>32) & 0xffff, &save->fcs); __put_user(tsk->thread.fdr, &save->foo); __put_user((tsk->thread.fdr>>32) & 0xffff, &save->fos); /* * Stack frames start with 16-bytes of temp space */ swp = (struct switch_stack *)(tsk->thread.ksp + 16); ptp = ia64_task_regs(tsk); tos = (tsk->thread.fsr >> 11) & 7; for (i = 0; i < 8; i++) put_fpreg(i, (struct _fpreg_ia32 *)&save->st_space[4*i], ptp, swp, tos); mxcsr = ((tsk->thread.fcr>>32) & 0xff80) | ((tsk->thread.fsr>>32) & 0x3f); __put_user(mxcsr & 0xffff, &save->mxcsr); for (i = 0; i < 8; i++) { memcpy(&(num128[0]), &(swp->f16) + i*2, sizeof(unsigned long)); memcpy(&(num128[1]), &(swp->f17) + i*2, sizeof(unsigned long)); copy_to_user(&save->xmm_space[0] + 4*i, num128, sizeof(struct _xmmreg_ia32)); } return 0;}static intrestore_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct *save){ struct switch_stack *swp; struct pt_regs *ptp; int i, tos; unsigned int fsrlo, fsrhi, num32; int mxcsr; unsigned long num64; unsigned long num128[2]; if (!access_ok(VERIFY_READ, save, sizeof(*save))) return(-EFAULT); __get_user(num32, (unsigned int *)&save->cwd); tsk->thread.fcr = (tsk->thread.fcr & (~0x1f3f)) | (num32 & 0x1f3f); __get_user(fsrlo, (unsigned int *)&save->swd); __get_user(fsrhi, (unsigned int *)&save->twd); num32 = (fsrhi << 16) | fsrlo; tsk->thread.fsr = (tsk->thread.fsr & (~0xffffffff)) | num32; __get_user(num32, (unsigned int *)&save->fip); tsk->thread.fir = (tsk->thread.fir & (~0xffffffff)) | num32; __get_user(num32, (unsigned int *)&save->foo); tsk->thread.fdr = (tsk->thread.fdr & (~0xffffffff)) | num32; /* * Stack frames start with 16-bytes of temp space */ swp = (struct switch_stack *)(tsk->thread.ksp + 16); ptp = ia64_task_regs(tsk); tos = (tsk->thread.fsr >> 11) & 7; for (i = 0; i < 8; i++) get_fpreg(i, (struct _fpreg_ia32 *)&save->st_space[4*i], ptp, swp, tos); __get_user(mxcsr, (unsigned int *)&save->mxcsr); num64 = mxcsr & 0xff10; tsk->thread.fcr = (tsk->thread.fcr & (~0xff1000000000)) | (num64<<32); num64 = mxcsr & 0x3f; tsk->thread.fsr = (tsk->thread.fsr & (~0x3f00000000)) | (num64<<32); for (i = 0; i < 8; i++) { copy_from_user(num128, &save->xmm_space[0] + 4*i, sizeof(struct _xmmreg_ia32)); memcpy(&(swp->f16) + i*2, &(num128[0]), sizeof(unsigned long)); memcpy(&(swp->f17) + i*2, &(num128[1]), sizeof(unsigned long)); } return 0;}/* * Note that the IA32 version of `ptrace' calls the IA64 routine for * many of the requests. This will only work for requests that do * not need access to the calling processes `pt_regs' which is located * at the address of `stack'. Once we call the IA64 `sys_ptrace' then * the address of `stack' will not be the address of the `pt_regs'. */asmlinkage longsys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data, long arg4, long arg5, long arg6, long arg7, long stack){ struct pt_regs *regs = (struct pt_regs *) &stack; struct task_struct *child; unsigned int value, tmp; long i, ret; lock_kernel(); if (request == PTRACE_TRACEME) { ret = sys_ptrace(request, pid, addr, data, arg4, arg5, arg6, arg7, stack); goto out; } ret = -ESRCH; read_lock(&tasklist_lock); child = find_task_by_pid(pid); if (child) get_task_struct(child); read_unlock(&tasklist_lock); if (!child) goto out; ret = -EPERM; if (pid == 1) /* no messing around with init! */ goto out_tsk; if (request == PTRACE_ATTACH) { ret = sys_ptrace(request, pid, addr, data, arg4, arg5, arg6, arg7, stack); goto out_tsk; } ret = ptrace_check_attach(child, request == PTRACE_KILL); if (ret < 0) goto out_tsk; switch (request) { case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: /* read word at location addr */ ret = ia32_peek(regs, child, addr, &value); if (ret == 0) ret = put_user(value, (unsigned int *) A(data)); else ret = -EIO; goto out_tsk; case PTRACE_POKETEXT: case PTRACE_POKEDATA: /* write the word at location addr */ ret = ia32_poke(regs, child, addr, data); goto out_tsk; case PTRACE_PEEKUSR: /* read word at addr in USER area */ ret = -EIO; if ((addr & 3) || addr > 17*sizeof(int)) break; tmp = getreg(child, addr); if (!put_user(tmp, (unsigned int *) A(data))) ret = 0; break; case PTRACE_POKEUSR: /* write word at addr in USER area */ ret = -EIO; if ((addr & 3) || addr > 17*sizeof(int)) break; putreg(child, addr, data); ret = 0; break; case IA32_PTRACE_GETREGS: if (!access_ok(VERIFY_WRITE, (int *) A(data), 17*sizeof(int))) { ret = -EIO; break; } for (i = 0; i < (int) (17*sizeof(int)); i += sizeof(int) ) { put_user(getreg(child, i), (unsigned int *) A(data)); data += sizeof(int); } ret = 0; break; case IA32_PTRACE_SETREGS: if (!access_ok(VERIFY_READ, (int *) A(data), 17*sizeof(int))) { ret = -EIO; break; } for (i = 0; i < (int) (17*sizeof(int)); i += sizeof(int) ) { get_user(tmp, (unsigned int *) A(data)); putreg(child, i, tmp); data += sizeof(int); } ret = 0; break; case IA32_PTRACE_GETFPREGS: ret = save_ia32_fpstate(child, (struct ia32_user_i387_struct *) A(data)); break; case IA32_PTRACE_GETFPXREGS: ret = save_ia32_fpxstate(child, (struct ia32_user_fxsr_struct *) A(data)); break; case IA32_PTRACE_SETFPREGS: ret = restore_ia32_fpstate(child, (struct ia32_user_i387_struct *) A(data)); break; case IA32_PTRACE_SETFPXREGS: ret = restore_ia32_fpxstate(child, (struct ia32_user_fxsr_struct *) A(data)); break; case PTRACE_SYSCALL: /* continue, stop after next syscall */ case PTRACE_CONT: /* restart after signal. */ case PTRACE_KILL: case PTRACE_SINGLESTEP: /* execute chile for one instruction */ case PTRACE_DETACH: /* detach a process */ ret = sys_ptrace(request, pid, addr, data, arg4, arg5, arg6, arg7, stack); break; default: ret = ptrace_request(child, request, addr, data); break; } out_tsk: put_task_struct(child); out: unlock_kernel(); return ret;}/* * The IA64 maps 4 I/O ports for each 4K page */#define IOLEN ((65536 / 4) * 4096)asmlinkage longsys32_iopl (int level){ extern unsigned long ia64_iobase; int fd; struct file * file; unsigned int old; unsigned long addr; mm_segment_t old_fs = get_fs (); if (level != 3) return(-EINVAL); /* Trying to gain more privileges? */ old = ia64_getreg(_IA64_REG_AR_EFLAG); if ((unsigned int) level > ((old >> 12) & 3)) { if (!capable(CAP_SYS_RAWIO)) return -EPERM; } set_fs(KERNEL_DS); fd = sys_open("/dev/mem", O_SYNC | O_RDWR, 0); set_fs(old_fs); if (fd < 0) return fd; file = fget(fd); if (file == NULL) { sys_close(fd); return(-EFAULT); } down_write(¤t->mm->mmap_sem); addr = do_mmap_pgoff(file, IA32_IOBASE, IOLEN, PROT_READ|PROT_WRITE, MAP_SHARED, (ia64_iobase & ~PAGE_OFFSET) >> PAGE_SHIFT); up_write(¤t->mm->mmap_sem); if (addr >= 0) { old = (old & ~0x3000) | (level << 12); ia64_setreg(_IA64_REG_AR_EFLAG, old); } fput(file); sys_close(fd); return 0;}asmlinkage longsys32_ioperm (unsigned int from, unsigned int num, int on){ /* * Since IA64 doesn't have permission bits we'd have to go to * a lot of trouble to simulate them in software. There's * no point, only trusted programs can make this call so we'll * just turn it into an iopl call and let the process have * access to all I/O ports. * * XXX proper ioperm() support should be emulated by * manipulating the page protections... */ return sys32_iopl(3);}typedef struct { unsigned int ss_sp; unsigned int ss_flags; unsigned int ss_size;} ia32_stack_t;asmlinkage longsys32_sigaltstack (ia32_stack_t *uss32, ia32_stack_t *uoss32, long arg2, long arg3, long arg4, long arg5, long arg6, long arg7, long stack){ struct pt_regs *pt = (struct pt_regs *) &stack; stack_t uss, uoss; ia32_stack_t buf32; int ret; mm_segment_t old_fs = get_fs(); if (uss32) { if (copy_from_user(&buf32, uss32, sizeof(ia32_stack_t))) return -EFAULT; uss.ss_sp = (void *) (long) buf32.ss_sp; uss.ss_flags = buf32.ss_flags; /* MINSIGSTKSZ is different for ia32 vs ia64. We lie here to pass the check and set it to the user requested value later */ if ((buf32.ss_flags != SS_DISABLE) && (buf32.ss_size < MINSIGSTKSZ_IA32)) { ret = -ENOMEM; goto out; } uss.ss_size = MINSIGSTKSZ; } set_fs(KERNEL_DS); ret = do_sigaltstack(uss32 ? &uss : NULL, &uoss, pt->r12); current->sas_ss_size = buf32.ss_size; set_fs(old_fs);out: if (ret < 0) return(ret); if (uoss32) { buf32.ss_sp = (long) uoss.ss_sp; buf32.ss_flags = uoss.ss_flags; buf32.ss_size = uoss.ss_size; if (copy_to_user(uoss32, &buf32, sizeof(ia32_stack_t))) return -EFAULT; } return ret;}asmlinkage intsys32_pause (void){ current->state = TASK_INTERRUPTIBLE; schedule(); return -ERESTARTNOHAND;}asmlinkage intsys32_msync (unsigned int start, unsigned int len, int flags){ unsigned int addr; if (OFFSET4K(start)) return -EINVAL; addr = PAGE_START(start); return sys_msync(addr, len + (start - addr), flags);}struct sysctl32 { unsigned int name; int nlen; unsigned int oldval; unsigned int oldlenp; unsigned int newval; unsigned int newlen; unsigned int __unused[4];};asmlinkage longsys32_sysctl (struct sysctl32 *args){#ifdef CONFIG_SYSCTL struct sysctl32 a32; mm_segment_t old_fs = get_fs (); void *oldvalp, *newvalp; size_t oldlen; int *namep; long ret; if (copy_from_user(&a32, args, sizeof(a32))) return -EFAULT; /* * We need to pre-validate these because we have to disable address checking * before calling do_sysctl() because of OLDLEN but we can't run the risk of the * user specifying bad addresses here. Well, since we're dealing with 32 bit * addresses, we KNOW that access_ok() will always succeed, so this is an * expensive NOP, but so what... */ namep = (int *) A(a32.name); oldvalp = (void *) A(a32.oldval); newvalp = (void *) A(a32.newval); if ((oldvalp && get_user(oldlen, (int *) A(a32.oldlenp))) || !access_ok(VERIFY_WRITE, namep, 0) || !access_ok(VERIFY_WRITE, oldvalp, 0) || !access_ok(VERIFY_WRITE, newvalp, 0)) return -EFAULT; set_fs(KERNEL_DS); lock_kernel(); ret = do_sysctl(namep, a32.nlen, oldvalp, &oldlen, newvalp, (size_t) a32.newlen); unlock_kernel(); set_fs(old_fs); if (oldvalp && put_user (oldlen, (int *) A(a32.oldlenp))) return -EFAULT; return ret;#else return -ENOSYS;#endif}asmlinkage longsys32_newuname (struct new_utsname *name){ int ret = sys_newuname(name); if (!ret) if (copy_to_user(name->machine, "i686\0\0\0", 8)) ret = -EFAULT; return ret;}asmlinkage longsys32_getresuid16 (u16 *ruid, u16 *euid, u16 *suid)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?