15c48b108SAl Viro /* 25c48b108SAl Viro * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 35c48b108SAl Viro * Licensed under the GPL 45c48b108SAl Viro */ 55c48b108SAl Viro 637185b33SAl Viro #include <linux/mm.h> 737185b33SAl Viro #include <linux/sched.h> 837185b33SAl Viro #include <asm/uaccess.h> 9da028d5eSRichard Weinberger #include <asm/ptrace-abi.h> 1037185b33SAl Viro #include <skas.h> 115c48b108SAl Viro 125c48b108SAl Viro extern int arch_switch_tls(struct task_struct *to); 135c48b108SAl Viro 145c48b108SAl Viro void arch_switch_to(struct task_struct *to) 155c48b108SAl Viro { 165c48b108SAl Viro int err = arch_switch_tls(to); 175c48b108SAl Viro if (!err) 185c48b108SAl Viro return; 195c48b108SAl Viro 205c48b108SAl Viro if (err != -EINVAL) 215c48b108SAl Viro printk(KERN_WARNING "arch_switch_tls failed, errno %d, " 225c48b108SAl Viro "not EINVAL\n", -err); 235c48b108SAl Viro else 245c48b108SAl Viro printk(KERN_WARNING "arch_switch_tls failed, errno = EINVAL\n"); 255c48b108SAl Viro } 265c48b108SAl Viro 275c48b108SAl Viro int is_syscall(unsigned long addr) 285c48b108SAl Viro { 295c48b108SAl Viro unsigned short instr; 305c48b108SAl Viro int n; 315c48b108SAl Viro 325c48b108SAl Viro n = copy_from_user(&instr, (void __user *) addr, sizeof(instr)); 335c48b108SAl Viro if (n) { 345c48b108SAl Viro /* access_process_vm() grants access to vsyscall and stub, 355c48b108SAl Viro * while copy_from_user doesn't. Maybe access_process_vm is 365c48b108SAl Viro * slow, but that doesn't matter, since it will be called only 375c48b108SAl Viro * in case of singlestepping, if copy_from_user failed. 385c48b108SAl Viro */ 395c48b108SAl Viro n = access_process_vm(current, addr, &instr, sizeof(instr), 0); 405c48b108SAl Viro if (n != sizeof(instr)) { 415c48b108SAl Viro printk(KERN_ERR "is_syscall : failed to read " 425c48b108SAl Viro "instruction from 0x%lx\n", addr); 435c48b108SAl Viro return 1; 445c48b108SAl Viro } 455c48b108SAl Viro } 465c48b108SAl Viro /* int 0x80 or sysenter */ 475c48b108SAl Viro return (instr == 0x80cd) || (instr == 0x340f); 485c48b108SAl Viro } 495c48b108SAl Viro 505c48b108SAl Viro /* determines which flags the user has access to. */ 515c48b108SAl Viro /* 1 = access 0 = no access */ 525c48b108SAl Viro #define FLAG_MASK 0x00044dd5 535c48b108SAl Viro 545c48b108SAl Viro static const int reg_offsets[] = { 553579a389SAl Viro [EBX] = HOST_BX, 563579a389SAl Viro [ECX] = HOST_CX, 573579a389SAl Viro [EDX] = HOST_DX, 583579a389SAl Viro [ESI] = HOST_SI, 593579a389SAl Viro [EDI] = HOST_DI, 603579a389SAl Viro [EBP] = HOST_BP, 613579a389SAl Viro [EAX] = HOST_AX, 625c48b108SAl Viro [DS] = HOST_DS, 635c48b108SAl Viro [ES] = HOST_ES, 645c48b108SAl Viro [FS] = HOST_FS, 655c48b108SAl Viro [GS] = HOST_GS, 665c48b108SAl Viro [EIP] = HOST_IP, 675c48b108SAl Viro [CS] = HOST_CS, 685c48b108SAl Viro [EFL] = HOST_EFLAGS, 695c48b108SAl Viro [UESP] = HOST_SP, 705c48b108SAl Viro [SS] = HOST_SS, 71e04c989eSMickaël Salaün [ORIG_EAX] = HOST_ORIG_AX, 725c48b108SAl Viro }; 735c48b108SAl Viro 745c48b108SAl Viro int putreg(struct task_struct *child, int regno, unsigned long value) 755c48b108SAl Viro { 765c48b108SAl Viro regno >>= 2; 775c48b108SAl Viro switch (regno) { 785c48b108SAl Viro case EBX: 795c48b108SAl Viro case ECX: 805c48b108SAl Viro case EDX: 815c48b108SAl Viro case ESI: 825c48b108SAl Viro case EDI: 835c48b108SAl Viro case EBP: 845c48b108SAl Viro case EAX: 855c48b108SAl Viro case EIP: 865c48b108SAl Viro case UESP: 87e04c989eSMickaël Salaün case ORIG_EAX: 885c48b108SAl Viro break; 895c48b108SAl Viro case FS: 905c48b108SAl Viro if (value && (value & 3) != 3) 915c48b108SAl Viro return -EIO; 925c48b108SAl Viro break; 935c48b108SAl Viro case GS: 945c48b108SAl Viro if (value && (value & 3) != 3) 955c48b108SAl Viro return -EIO; 965c48b108SAl Viro break; 975c48b108SAl Viro case DS: 985c48b108SAl Viro case ES: 995c48b108SAl Viro if (value && (value & 3) != 3) 1005c48b108SAl Viro return -EIO; 1015c48b108SAl Viro value &= 0xffff; 1025c48b108SAl Viro break; 1035c48b108SAl Viro case SS: 1045c48b108SAl Viro case CS: 1055c48b108SAl Viro if ((value & 3) != 3) 1065c48b108SAl Viro return -EIO; 1075c48b108SAl Viro value &= 0xffff; 1085c48b108SAl Viro break; 1095c48b108SAl Viro case EFL: 1105c48b108SAl Viro value &= FLAG_MASK; 1115c48b108SAl Viro child->thread.regs.regs.gp[HOST_EFLAGS] |= value; 1125c48b108SAl Viro return 0; 1135c48b108SAl Viro default : 1145c48b108SAl Viro panic("Bad register in putreg() : %d\n", regno); 1155c48b108SAl Viro } 1165c48b108SAl Viro child->thread.regs.regs.gp[reg_offsets[regno]] = value; 1175c48b108SAl Viro return 0; 1185c48b108SAl Viro } 1195c48b108SAl Viro 1205c48b108SAl Viro int poke_user(struct task_struct *child, long addr, long data) 1215c48b108SAl Viro { 1225c48b108SAl Viro if ((addr & 3) || addr < 0) 1235c48b108SAl Viro return -EIO; 1245c48b108SAl Viro 1255c48b108SAl Viro if (addr < MAX_REG_OFFSET) 1265c48b108SAl Viro return putreg(child, addr, data); 1275c48b108SAl Viro else if ((addr >= offsetof(struct user, u_debugreg[0])) && 1285c48b108SAl Viro (addr <= offsetof(struct user, u_debugreg[7]))) { 1295c48b108SAl Viro addr -= offsetof(struct user, u_debugreg[0]); 1305c48b108SAl Viro addr = addr >> 2; 1315c48b108SAl Viro if ((addr == 4) || (addr == 5)) 1325c48b108SAl Viro return -EIO; 1335c48b108SAl Viro child->thread.arch.debugregs[addr] = data; 1345c48b108SAl Viro return 0; 1355c48b108SAl Viro } 1365c48b108SAl Viro return -EIO; 1375c48b108SAl Viro } 1385c48b108SAl Viro 1395c48b108SAl Viro unsigned long getreg(struct task_struct *child, int regno) 1405c48b108SAl Viro { 1415c48b108SAl Viro unsigned long mask = ~0UL; 1425c48b108SAl Viro 1435c48b108SAl Viro regno >>= 2; 1445c48b108SAl Viro switch (regno) { 1455c48b108SAl Viro case FS: 1465c48b108SAl Viro case GS: 1475c48b108SAl Viro case DS: 1485c48b108SAl Viro case ES: 1495c48b108SAl Viro case SS: 1505c48b108SAl Viro case CS: 1515c48b108SAl Viro mask = 0xffff; 1525c48b108SAl Viro break; 1535c48b108SAl Viro case EIP: 1545c48b108SAl Viro case UESP: 1555c48b108SAl Viro case EAX: 1565c48b108SAl Viro case EBX: 1575c48b108SAl Viro case ECX: 1585c48b108SAl Viro case EDX: 1595c48b108SAl Viro case ESI: 1605c48b108SAl Viro case EDI: 1615c48b108SAl Viro case EBP: 1625c48b108SAl Viro case EFL: 163e04c989eSMickaël Salaün case ORIG_EAX: 1645c48b108SAl Viro break; 1655c48b108SAl Viro default: 1665c48b108SAl Viro panic("Bad register in getreg() : %d\n", regno); 1675c48b108SAl Viro } 1685c48b108SAl Viro return mask & child->thread.regs.regs.gp[reg_offsets[regno]]; 1695c48b108SAl Viro } 1705c48b108SAl Viro 1715c48b108SAl Viro /* read the word at location addr in the USER area. */ 1725c48b108SAl Viro int peek_user(struct task_struct *child, long addr, long data) 1735c48b108SAl Viro { 1745c48b108SAl Viro unsigned long tmp; 1755c48b108SAl Viro 1765c48b108SAl Viro if ((addr & 3) || addr < 0) 1775c48b108SAl Viro return -EIO; 1785c48b108SAl Viro 1795c48b108SAl Viro tmp = 0; /* Default return condition */ 1805c48b108SAl Viro if (addr < MAX_REG_OFFSET) { 1815c48b108SAl Viro tmp = getreg(child, addr); 1825c48b108SAl Viro } 1835c48b108SAl Viro else if ((addr >= offsetof(struct user, u_debugreg[0])) && 1845c48b108SAl Viro (addr <= offsetof(struct user, u_debugreg[7]))) { 1855c48b108SAl Viro addr -= offsetof(struct user, u_debugreg[0]); 1865c48b108SAl Viro addr = addr >> 2; 1875c48b108SAl Viro tmp = child->thread.arch.debugregs[addr]; 1885c48b108SAl Viro } 1895c48b108SAl Viro return put_user(tmp, (unsigned long __user *) data); 1905c48b108SAl Viro } 1915c48b108SAl Viro 1925c48b108SAl Viro static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) 1935c48b108SAl Viro { 1945c48b108SAl Viro int err, n, cpu = ((struct thread_info *) child->stack)->cpu; 1955c48b108SAl Viro struct user_i387_struct fpregs; 1965c48b108SAl Viro 197*a78ff111SEli Cooper err = save_i387_registers(userspace_pid[cpu], 198*a78ff111SEli Cooper (unsigned long *) &fpregs); 1995c48b108SAl Viro if (err) 2005c48b108SAl Viro return err; 2015c48b108SAl Viro 2025c48b108SAl Viro n = copy_to_user(buf, &fpregs, sizeof(fpregs)); 2035c48b108SAl Viro if(n > 0) 2045c48b108SAl Viro return -EFAULT; 2055c48b108SAl Viro 2065c48b108SAl Viro return n; 2075c48b108SAl Viro } 2085c48b108SAl Viro 2095c48b108SAl Viro static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) 2105c48b108SAl Viro { 2115c48b108SAl Viro int n, cpu = ((struct thread_info *) child->stack)->cpu; 2125c48b108SAl Viro struct user_i387_struct fpregs; 2135c48b108SAl Viro 2145c48b108SAl Viro n = copy_from_user(&fpregs, buf, sizeof(fpregs)); 2155c48b108SAl Viro if (n > 0) 2165c48b108SAl Viro return -EFAULT; 2175c48b108SAl Viro 218*a78ff111SEli Cooper return restore_i387_registers(userspace_pid[cpu], 2195c48b108SAl Viro (unsigned long *) &fpregs); 2205c48b108SAl Viro } 2215c48b108SAl Viro 2225c48b108SAl Viro static int get_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child) 2235c48b108SAl Viro { 2245c48b108SAl Viro int err, n, cpu = ((struct thread_info *) child->stack)->cpu; 2255c48b108SAl Viro struct user_fxsr_struct fpregs; 2265c48b108SAl Viro 2275c48b108SAl Viro err = save_fpx_registers(userspace_pid[cpu], (unsigned long *) &fpregs); 2285c48b108SAl Viro if (err) 2295c48b108SAl Viro return err; 2305c48b108SAl Viro 2315c48b108SAl Viro n = copy_to_user(buf, &fpregs, sizeof(fpregs)); 2325c48b108SAl Viro if(n > 0) 2335c48b108SAl Viro return -EFAULT; 2345c48b108SAl Viro 2355c48b108SAl Viro return n; 2365c48b108SAl Viro } 2375c48b108SAl Viro 2385c48b108SAl Viro static int set_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child) 2395c48b108SAl Viro { 2405c48b108SAl Viro int n, cpu = ((struct thread_info *) child->stack)->cpu; 2415c48b108SAl Viro struct user_fxsr_struct fpregs; 2425c48b108SAl Viro 2435c48b108SAl Viro n = copy_from_user(&fpregs, buf, sizeof(fpregs)); 2445c48b108SAl Viro if (n > 0) 2455c48b108SAl Viro return -EFAULT; 2465c48b108SAl Viro 2475c48b108SAl Viro return restore_fpx_registers(userspace_pid[cpu], 2485c48b108SAl Viro (unsigned long *) &fpregs); 2495c48b108SAl Viro } 2505c48b108SAl Viro 2515c48b108SAl Viro long subarch_ptrace(struct task_struct *child, long request, 2525c48b108SAl Viro unsigned long addr, unsigned long data) 2535c48b108SAl Viro { 2545c48b108SAl Viro int ret = -EIO; 2555c48b108SAl Viro void __user *datap = (void __user *) data; 2565c48b108SAl Viro switch (request) { 2575c48b108SAl Viro case PTRACE_GETFPREGS: /* Get the child FPU state. */ 2585c48b108SAl Viro ret = get_fpregs(datap, child); 2595c48b108SAl Viro break; 2605c48b108SAl Viro case PTRACE_SETFPREGS: /* Set the child FPU state. */ 2615c48b108SAl Viro ret = set_fpregs(datap, child); 2625c48b108SAl Viro break; 2635c48b108SAl Viro case PTRACE_GETFPXREGS: /* Get the child FPU state. */ 2645c48b108SAl Viro ret = get_fpxregs(datap, child); 2655c48b108SAl Viro break; 2665c48b108SAl Viro case PTRACE_SETFPXREGS: /* Set the child FPU state. */ 2675c48b108SAl Viro ret = set_fpxregs(datap, child); 2685c48b108SAl Viro break; 2695c48b108SAl Viro default: 2705c48b108SAl Viro ret = -EIO; 2715c48b108SAl Viro } 2725c48b108SAl Viro return ret; 2735c48b108SAl Viro } 274