📄 sys_ia32.c
字号:
child_regs->r13 = value; break; case PT_EAX: case PT_ORIG_EAX: child_regs->r8 = value; break; case PT_EIP: child_regs->cr_iip = value; break; case PT_UESP: child_regs->r12 = value; break; case PT_EFL: child->thread.eflag = value; break; case PT_DS: case PT_ES: case PT_FS: case PT_GS: case PT_SS: if (value != __USER_DS) printk("setregs:try to set invalid segment register %d = %x\n", regno, value); break; case PT_CS: if (value != __USER_CS) printk("setregs:try to set invalid segment register %d = %x\n", regno, value); break; default: printk("getregs:unknown register %d\n", regno); break; }}static inline voidia32f2ia64f(void *dst, void *src){ __asm__ ("ldfe f6=[%1] ;;\n\t" "stf.spill [%0]=f6" : : "r"(dst), "r"(src)); return;}static inline voidia64f2ia32f(void *dst, void *src){ __asm__ ("ldf.fill f6=[%1] ;;\n\t" "stfe [%0]=f6" : : "r"(dst), "r"(src)); return;}voidput_fpreg(int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp, int tos){ struct _fpreg_ia32 *f; char buf[32]; f = (struct _fpreg_ia32 *)(((unsigned long)buf + 15) & ~15); if ((regno += tos) >= 8) regno -= 8; switch (regno) { case 0: ia64f2ia32f(f, &ptp->f8); break; case 1: ia64f2ia32f(f, &ptp->f9); break; case 2: case 3: case 4: case 5: case 6: case 7: ia64f2ia32f(f, &swp->f10 + (regno - 2)); break; } __copy_to_user(reg, f, sizeof(*reg)); return;}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: case 3: case 4: case 5: case 6: case 7: __copy_from_user(&swp->f10 + (regno - 2), reg, sizeof(*reg)); break; } return;}intsave_ia32_fpstate(struct task_struct *tsk, struct _fpstate_ia32 *save){ struct switch_stack *swp; struct pt_regs *ptp; int i, tos; if (!access_ok(VERIFY_WRITE, save, sizeof(*save))) return(-EIO); __put_user(tsk->thread.fcr, &save->cw); __put_user(tsk->thread.fsr, &save->sw); __put_user(tsk->thread.fsr >> 32, &save->tag); __put_user(tsk->thread.fir, &save->ipoff); __put_user(__USER_CS, &save->cssel); __put_user(tsk->thread.fdr, &save->dataoff); __put_user(__USER_DS, &save->datasel); /* * 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) & 3; for (i = 0; i < 8; i++) put_fpreg(i, &save->_st[i], ptp, swp, tos); return(0);}intrestore_ia32_fpstate(struct task_struct *tsk, struct _fpstate_ia32 *save){ struct switch_stack *swp; struct pt_regs *ptp; int i, tos, ret; int fsrlo, fsrhi; if (!access_ok(VERIFY_READ, save, sizeof(*save))) return(-EIO); ret = __get_user(tsk->thread.fcr, (unsigned int *)&save->cw); ret |= __get_user(fsrlo, (unsigned int *)&save->sw); ret |= __get_user(fsrhi, (unsigned int *)&save->tag); tsk->thread.fsr = ((long)fsrhi << 32) | (long)fsrlo; ret |= __get_user(tsk->thread.fir, (unsigned int *)&save->ipoff); ret |= __get_user(tsk->thread.fdr, (unsigned int *)&save->dataoff); /* * 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) & 3; for (i = 0; i < 8; i++) get_fpreg(i, &save->_st[i], ptp, swp, tos); return(ret ? -EFAULT : 0);}asmlinkage long sys_ptrace(long, pid_t, unsigned long, unsigned long, long, long, long, long, long);/* * 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 (long request, pid_t pid, unsigned long addr, unsigned long data, long arg4, long arg5, long arg6, long arg7, long stack){ struct pt_regs *regs = (struct pt_regs *) &stack; struct task_struct *child; long i, ret; unsigned int value; 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); read_unlock(&tasklist_lock); if (!child) goto out; ret = -EPERM; if (pid == 1) /* no messing around with init! */ goto out; if (request == PTRACE_ATTACH) { ret = sys_ptrace(request, pid, addr, data, arg4, arg5, arg6, arg7, stack); goto out; } ret = -ESRCH; if (!(child->ptrace & PT_PTRACED)) goto out; if (child->state != TASK_STOPPED) { if (request != PTRACE_KILL) goto out; } if (child->p_pptr != current) goto out; 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 *)data); else ret = -EIO; goto out; case PTRACE_POKETEXT: case PTRACE_POKEDATA: /* write the word at location addr */ ret = ia32_poke(regs, child, addr, (unsigned int)data); goto out; case PTRACE_PEEKUSR: /* read word at addr in USER area */ ret = 0; break; case PTRACE_POKEUSR: /* write word at addr in USER area */ ret = 0; break; case IA32_PTRACE_GETREGS: if (!access_ok(VERIFY_WRITE, (int *)data, 17*sizeof(int))) { ret = -EIO; break; } for ( i = 0; i < 17*sizeof(int); i += sizeof(int) ) { __put_user(getreg(child, i),(unsigned int *) data); data += sizeof(int); } ret = 0; break; case IA32_PTRACE_SETREGS: { unsigned int tmp; if (!access_ok(VERIFY_READ, (int *)data, 17*sizeof(int))) { ret = -EIO; break; } for ( i = 0; i < 17*sizeof(int); i += sizeof(int) ) { __get_user(tmp, (unsigned int *) data); putreg(child, i, tmp); data += sizeof(int); } ret = 0; break; } case IA32_PTRACE_GETFPREGS: ret = save_ia32_fpstate(child, (struct _fpstate_ia32 *)data); break; case IA32_PTRACE_SETFPREGS: ret = restore_ia32_fpstate(child, (struct _fpstate_ia32 *)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 */ unlock_kernel(); ret = sys_ptrace(request, pid, addr, data, arg4, arg5, arg6, arg7, stack); return(ret); default: ret = -EIO; break; } out: unlock_kernel(); return ret;}static inline intget_flock32(struct flock *kfl, struct flock32 *ufl){ int err; err = get_user(kfl->l_type, &ufl->l_type); err |= __get_user(kfl->l_whence, &ufl->l_whence); err |= __get_user(kfl->l_start, &ufl->l_start); err |= __get_user(kfl->l_len, &ufl->l_len); err |= __get_user(kfl->l_pid, &ufl->l_pid); return err;}static inline intput_flock32(struct flock *kfl, struct flock32 *ufl){ int err; err = __put_user(kfl->l_type, &ufl->l_type); err |= __put_user(kfl->l_whence, &ufl->l_whence); err |= __put_user(kfl->l_start, &ufl->l_start); err |= __put_user(kfl->l_len, &ufl->l_len); err |= __put_user(kfl->l_pid, &ufl->l_pid); return err;}extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg);asmlinkage longsys32_fcntl(unsigned int fd, unsigned int cmd, int arg){ struct flock f; mm_segment_t old_fs; long ret; switch (cmd) { case F_GETLK: case F_SETLK: case F_SETLKW: if(cmd != F_GETLK && get_flock32(&f, (struct flock32 *)((long)arg))) return -EFAULT; old_fs = get_fs(); set_fs(KERNEL_DS); ret = sys_fcntl(fd, cmd, (unsigned long)&f); set_fs(old_fs); if(cmd == F_GETLK && put_flock32(&f, (struct flock32 *)((long)arg))) return -EFAULT; return ret; default: /* * `sys_fcntl' lies about arg, for the F_SETOWN * sub-function arg can have a negative value. */ return sys_fcntl(fd, cmd, (unsigned long)((long)arg)); }}asmlinkage longsys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact){ struct k_sigaction new_ka, old_ka; int ret; if (act) { old_sigset32_t mask; ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler); ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); ret |= __get_user(mask, &act->sa_mask); if (ret) return ret; siginitset(&new_ka.sa.sa_mask, mask); } ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); if (!ret && oact) { ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler); ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); } return ret;}asmlinkage long sys_ni_syscall(void);asmlinkage longsys32_ni_syscall(int dummy0, int dummy1, int dummy2, int dummy3, int dummy4, int dummy5, int dummy6, int dummy7, int stack){ struct pt_regs *regs = (struct pt_regs *)&stack; printk("IA32 syscall #%d issued, maybe we should implement it\n", (int)regs->r1); return(sys_ni_syscall());}/* * The IA64 maps 4 I/O ports for each 4K page */#define IOLEN ((65536 / 4) * 4096)asmlinkage longsys_iopl (int level, long arg1, long arg2, long arg3){ 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? */ __asm__ __volatile__("mov %0=ar.eflag ;;" : "=r"(old)); if (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(¤t->mm->mmap_sem); lock_kernel(); addr = do_mmap_pgoff(file, IA32_IOBASE, IOLEN, PROT_READ|PROT_WRITE, MAP_SHARED, (ia64_iobase & ~PAGE_OFFSET) >> PAGE_SHIFT); unlock_kernel(); up(¤t->mm->mmap_sem); if (addr >= 0) { __asm__ __volatile__("mov ar.k0=%0 ;;" :: "r"(addr)); old = (old & ~0x3000) | (level << 12); __asm__ __volatile__("mov ar.eflag=%0 ;;" :: "r"(old)); } fput(file); sys_close(fd); return 0;}asmlinkage longsys_ioperm (unsigned long from, unsigned long 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(sys_iopl(3, 0, 0, 0));}typedef struct { unsigned int ss_sp; unsigned int ss_flags; unsigned int ss_size;} ia32_stack_t;asmlinkage longsys32_sigaltstack (const 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, (void *)A(uss32), sizeof(ia32_stack_t))) return(-EFAULT); uss.ss_sp = (void *) (long) buf32.ss_sp; uss.ss_flags = buf32.ss_flags; uss.ss_size = buf32.ss_size; set_fs(KERNEL_DS); ret = do_sigaltstack(uss32 ? &uss : NULL, &uoss, pt->r12); set_fs(old_fs); 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((void*)A(uoss32), &buf32, sizeof(ia32_stack_t))) return(-EFAULT); } return(ret);}asmlinkage intsys_pause (void){ current->state = TASK_INTERRUPTIBLE; schedule(); return -ERESTARTNOHAND;}#ifdef NOTYET /* UNTESTED FOR IA64 FROM HERE DOWN *//* In order to reduce some races, while at the same time doing additional * checking and hopefully speeding things up, we copy filenames to the * kernel data space before using them.. * * POSIX.1 2.4: an empty pathname is invalid (ENOENT). */static inline intdo_getname32(const char *filename, char *page){ int retval; /* 32bit pointer will be always far below TASK_SIZE :)) */ retval = strncpy_from_user((char *)page, (char *)filename, PAGE_SIZE); if (retval > 0) { if (retval < PAGE_SIZE)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -