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> 8*7c0f6ba6SLinus Torvalds #include <linux/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 */ 39f307ab6dSLorenzo Stoakes n = access_process_vm(current, addr, &instr, sizeof(instr), 40f307ab6dSLorenzo Stoakes FOLL_FORCE); 415c48b108SAl Viro if (n != sizeof(instr)) { 425c48b108SAl Viro printk(KERN_ERR "is_syscall : failed to read " 435c48b108SAl Viro "instruction from 0x%lx\n", addr); 445c48b108SAl Viro return 1; 455c48b108SAl Viro } 465c48b108SAl Viro } 475c48b108SAl Viro /* int 0x80 or sysenter */ 485c48b108SAl Viro return (instr == 0x80cd) || (instr == 0x340f); 495c48b108SAl Viro } 505c48b108SAl Viro 515c48b108SAl Viro /* determines which flags the user has access to. */ 525c48b108SAl Viro /* 1 = access 0 = no access */ 535c48b108SAl Viro #define FLAG_MASK 0x00044dd5 545c48b108SAl Viro 555c48b108SAl Viro static const int reg_offsets[] = { 563579a389SAl Viro [EBX] = HOST_BX, 573579a389SAl Viro [ECX] = HOST_CX, 583579a389SAl Viro [EDX] = HOST_DX, 593579a389SAl Viro [ESI] = HOST_SI, 603579a389SAl Viro [EDI] = HOST_DI, 613579a389SAl Viro [EBP] = HOST_BP, 623579a389SAl Viro [EAX] = HOST_AX, 635c48b108SAl Viro [DS] = HOST_DS, 645c48b108SAl Viro [ES] = HOST_ES, 655c48b108SAl Viro [FS] = HOST_FS, 665c48b108SAl Viro [GS] = HOST_GS, 675c48b108SAl Viro [EIP] = HOST_IP, 685c48b108SAl Viro [CS] = HOST_CS, 695c48b108SAl Viro [EFL] = HOST_EFLAGS, 705c48b108SAl Viro [UESP] = HOST_SP, 715c48b108SAl Viro [SS] = HOST_SS, 72e04c989eSMickaël Salaün [ORIG_EAX] = HOST_ORIG_AX, 735c48b108SAl Viro }; 745c48b108SAl Viro 755c48b108SAl Viro int putreg(struct task_struct *child, int regno, unsigned long value) 765c48b108SAl Viro { 775c48b108SAl Viro regno >>= 2; 785c48b108SAl Viro switch (regno) { 795c48b108SAl Viro case EBX: 805c48b108SAl Viro case ECX: 815c48b108SAl Viro case EDX: 825c48b108SAl Viro case ESI: 835c48b108SAl Viro case EDI: 845c48b108SAl Viro case EBP: 855c48b108SAl Viro case EAX: 865c48b108SAl Viro case EIP: 875c48b108SAl Viro case UESP: 88ce29856aSMickaël Salaün break; 89e04c989eSMickaël Salaün case ORIG_EAX: 90ce29856aSMickaël Salaün /* Update the syscall number. */ 91ce29856aSMickaël Salaün UPT_SYSCALL_NR(&child->thread.regs.regs) = value; 925c48b108SAl Viro break; 935c48b108SAl Viro case FS: 945c48b108SAl Viro if (value && (value & 3) != 3) 955c48b108SAl Viro return -EIO; 965c48b108SAl Viro break; 975c48b108SAl Viro case GS: 985c48b108SAl Viro if (value && (value & 3) != 3) 995c48b108SAl Viro return -EIO; 1005c48b108SAl Viro break; 1015c48b108SAl Viro case DS: 1025c48b108SAl Viro case ES: 1035c48b108SAl Viro if (value && (value & 3) != 3) 1045c48b108SAl Viro return -EIO; 1055c48b108SAl Viro value &= 0xffff; 1065c48b108SAl Viro break; 1075c48b108SAl Viro case SS: 1085c48b108SAl Viro case CS: 1095c48b108SAl Viro if ((value & 3) != 3) 1105c48b108SAl Viro return -EIO; 1115c48b108SAl Viro value &= 0xffff; 1125c48b108SAl Viro break; 1135c48b108SAl Viro case EFL: 1145c48b108SAl Viro value &= FLAG_MASK; 1155c48b108SAl Viro child->thread.regs.regs.gp[HOST_EFLAGS] |= value; 1165c48b108SAl Viro return 0; 1175c48b108SAl Viro default : 1185c48b108SAl Viro panic("Bad register in putreg() : %d\n", regno); 1195c48b108SAl Viro } 1205c48b108SAl Viro child->thread.regs.regs.gp[reg_offsets[regno]] = value; 1215c48b108SAl Viro return 0; 1225c48b108SAl Viro } 1235c48b108SAl Viro 1245c48b108SAl Viro int poke_user(struct task_struct *child, long addr, long data) 1255c48b108SAl Viro { 1265c48b108SAl Viro if ((addr & 3) || addr < 0) 1275c48b108SAl Viro return -EIO; 1285c48b108SAl Viro 1295c48b108SAl Viro if (addr < MAX_REG_OFFSET) 1305c48b108SAl Viro return putreg(child, addr, data); 1315c48b108SAl Viro else if ((addr >= offsetof(struct user, u_debugreg[0])) && 1325c48b108SAl Viro (addr <= offsetof(struct user, u_debugreg[7]))) { 1335c48b108SAl Viro addr -= offsetof(struct user, u_debugreg[0]); 1345c48b108SAl Viro addr = addr >> 2; 1355c48b108SAl Viro if ((addr == 4) || (addr == 5)) 1365c48b108SAl Viro return -EIO; 1375c48b108SAl Viro child->thread.arch.debugregs[addr] = data; 1385c48b108SAl Viro return 0; 1395c48b108SAl Viro } 1405c48b108SAl Viro return -EIO; 1415c48b108SAl Viro } 1425c48b108SAl Viro 1435c48b108SAl Viro unsigned long getreg(struct task_struct *child, int regno) 1445c48b108SAl Viro { 1455c48b108SAl Viro unsigned long mask = ~0UL; 1465c48b108SAl Viro 1475c48b108SAl Viro regno >>= 2; 1485c48b108SAl Viro switch (regno) { 1495c48b108SAl Viro case FS: 1505c48b108SAl Viro case GS: 1515c48b108SAl Viro case DS: 1525c48b108SAl Viro case ES: 1535c48b108SAl Viro case SS: 1545c48b108SAl Viro case CS: 1555c48b108SAl Viro mask = 0xffff; 1565c48b108SAl Viro break; 1575c48b108SAl Viro case EIP: 1585c48b108SAl Viro case UESP: 1595c48b108SAl Viro case EAX: 1605c48b108SAl Viro case EBX: 1615c48b108SAl Viro case ECX: 1625c48b108SAl Viro case EDX: 1635c48b108SAl Viro case ESI: 1645c48b108SAl Viro case EDI: 1655c48b108SAl Viro case EBP: 1665c48b108SAl Viro case EFL: 167e04c989eSMickaël Salaün case ORIG_EAX: 1685c48b108SAl Viro break; 1695c48b108SAl Viro default: 1705c48b108SAl Viro panic("Bad register in getreg() : %d\n", regno); 1715c48b108SAl Viro } 1725c48b108SAl Viro return mask & child->thread.regs.regs.gp[reg_offsets[regno]]; 1735c48b108SAl Viro } 1745c48b108SAl Viro 1755c48b108SAl Viro /* read the word at location addr in the USER area. */ 1765c48b108SAl Viro int peek_user(struct task_struct *child, long addr, long data) 1775c48b108SAl Viro { 1785c48b108SAl Viro unsigned long tmp; 1795c48b108SAl Viro 1805c48b108SAl Viro if ((addr & 3) || addr < 0) 1815c48b108SAl Viro return -EIO; 1825c48b108SAl Viro 1835c48b108SAl Viro tmp = 0; /* Default return condition */ 1845c48b108SAl Viro if (addr < MAX_REG_OFFSET) { 1855c48b108SAl Viro tmp = getreg(child, addr); 1865c48b108SAl Viro } 1875c48b108SAl Viro else if ((addr >= offsetof(struct user, u_debugreg[0])) && 1885c48b108SAl Viro (addr <= offsetof(struct user, u_debugreg[7]))) { 1895c48b108SAl Viro addr -= offsetof(struct user, u_debugreg[0]); 1905c48b108SAl Viro addr = addr >> 2; 1915c48b108SAl Viro tmp = child->thread.arch.debugregs[addr]; 1925c48b108SAl Viro } 1935c48b108SAl Viro return put_user(tmp, (unsigned long __user *) data); 1945c48b108SAl Viro } 1955c48b108SAl Viro 1965c48b108SAl Viro static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) 1975c48b108SAl Viro { 198d896fa20SLinus Torvalds int err, n, cpu = task_cpu(child); 1995c48b108SAl Viro struct user_i387_struct fpregs; 2005c48b108SAl Viro 201a78ff111SEli Cooper err = save_i387_registers(userspace_pid[cpu], 202a78ff111SEli Cooper (unsigned long *) &fpregs); 2035c48b108SAl Viro if (err) 2045c48b108SAl Viro return err; 2055c48b108SAl Viro 2065c48b108SAl Viro n = copy_to_user(buf, &fpregs, sizeof(fpregs)); 2075c48b108SAl Viro if(n > 0) 2085c48b108SAl Viro return -EFAULT; 2095c48b108SAl Viro 2105c48b108SAl Viro return n; 2115c48b108SAl Viro } 2125c48b108SAl Viro 2135c48b108SAl Viro static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) 2145c48b108SAl Viro { 215d896fa20SLinus Torvalds int n, cpu = task_cpu(child); 2165c48b108SAl Viro struct user_i387_struct fpregs; 2175c48b108SAl Viro 2185c48b108SAl Viro n = copy_from_user(&fpregs, buf, sizeof(fpregs)); 2195c48b108SAl Viro if (n > 0) 2205c48b108SAl Viro return -EFAULT; 2215c48b108SAl Viro 222a78ff111SEli Cooper return restore_i387_registers(userspace_pid[cpu], 2235c48b108SAl Viro (unsigned long *) &fpregs); 2245c48b108SAl Viro } 2255c48b108SAl Viro 2265c48b108SAl Viro static int get_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child) 2275c48b108SAl Viro { 228d896fa20SLinus Torvalds int err, n, cpu = task_cpu(child); 2295c48b108SAl Viro struct user_fxsr_struct fpregs; 2305c48b108SAl Viro 2315c48b108SAl Viro err = save_fpx_registers(userspace_pid[cpu], (unsigned long *) &fpregs); 2325c48b108SAl Viro if (err) 2335c48b108SAl Viro return err; 2345c48b108SAl Viro 2355c48b108SAl Viro n = copy_to_user(buf, &fpregs, sizeof(fpregs)); 2365c48b108SAl Viro if(n > 0) 2375c48b108SAl Viro return -EFAULT; 2385c48b108SAl Viro 2395c48b108SAl Viro return n; 2405c48b108SAl Viro } 2415c48b108SAl Viro 2425c48b108SAl Viro static int set_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child) 2435c48b108SAl Viro { 244d896fa20SLinus Torvalds int n, cpu = task_cpu(child); 2455c48b108SAl Viro struct user_fxsr_struct fpregs; 2465c48b108SAl Viro 2475c48b108SAl Viro n = copy_from_user(&fpregs, buf, sizeof(fpregs)); 2485c48b108SAl Viro if (n > 0) 2495c48b108SAl Viro return -EFAULT; 2505c48b108SAl Viro 2515c48b108SAl Viro return restore_fpx_registers(userspace_pid[cpu], 2525c48b108SAl Viro (unsigned long *) &fpregs); 2535c48b108SAl Viro } 2545c48b108SAl Viro 2555c48b108SAl Viro long subarch_ptrace(struct task_struct *child, long request, 2565c48b108SAl Viro unsigned long addr, unsigned long data) 2575c48b108SAl Viro { 2585c48b108SAl Viro int ret = -EIO; 2595c48b108SAl Viro void __user *datap = (void __user *) data; 2605c48b108SAl Viro switch (request) { 2615c48b108SAl Viro case PTRACE_GETFPREGS: /* Get the child FPU state. */ 2625c48b108SAl Viro ret = get_fpregs(datap, child); 2635c48b108SAl Viro break; 2645c48b108SAl Viro case PTRACE_SETFPREGS: /* Set the child FPU state. */ 2655c48b108SAl Viro ret = set_fpregs(datap, child); 2665c48b108SAl Viro break; 2675c48b108SAl Viro case PTRACE_GETFPXREGS: /* Get the child FPU state. */ 2685c48b108SAl Viro ret = get_fpxregs(datap, child); 2695c48b108SAl Viro break; 2705c48b108SAl Viro case PTRACE_SETFPXREGS: /* Set the child FPU state. */ 2715c48b108SAl Viro ret = set_fpxregs(datap, child); 2725c48b108SAl Viro break; 2735c48b108SAl Viro default: 2745c48b108SAl Viro ret = -EIO; 2755c48b108SAl Viro } 2765c48b108SAl Viro return ret; 2775c48b108SAl Viro } 278