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: 87*ce29856aSMickaël Salaün break; 88e04c989eSMickaël Salaün case ORIG_EAX: 89*ce29856aSMickaël Salaün /* Update the syscall number. */ 90*ce29856aSMickaël Salaün UPT_SYSCALL_NR(&child->thread.regs.regs) = value; 915c48b108SAl Viro break; 925c48b108SAl Viro case FS: 935c48b108SAl Viro if (value && (value & 3) != 3) 945c48b108SAl Viro return -EIO; 955c48b108SAl Viro break; 965c48b108SAl Viro case GS: 975c48b108SAl Viro if (value && (value & 3) != 3) 985c48b108SAl Viro return -EIO; 995c48b108SAl Viro break; 1005c48b108SAl Viro case DS: 1015c48b108SAl Viro case ES: 1025c48b108SAl Viro if (value && (value & 3) != 3) 1035c48b108SAl Viro return -EIO; 1045c48b108SAl Viro value &= 0xffff; 1055c48b108SAl Viro break; 1065c48b108SAl Viro case SS: 1075c48b108SAl Viro case CS: 1085c48b108SAl Viro if ((value & 3) != 3) 1095c48b108SAl Viro return -EIO; 1105c48b108SAl Viro value &= 0xffff; 1115c48b108SAl Viro break; 1125c48b108SAl Viro case EFL: 1135c48b108SAl Viro value &= FLAG_MASK; 1145c48b108SAl Viro child->thread.regs.regs.gp[HOST_EFLAGS] |= value; 1155c48b108SAl Viro return 0; 1165c48b108SAl Viro default : 1175c48b108SAl Viro panic("Bad register in putreg() : %d\n", regno); 1185c48b108SAl Viro } 1195c48b108SAl Viro child->thread.regs.regs.gp[reg_offsets[regno]] = value; 1205c48b108SAl Viro return 0; 1215c48b108SAl Viro } 1225c48b108SAl Viro 1235c48b108SAl Viro int poke_user(struct task_struct *child, long addr, long data) 1245c48b108SAl Viro { 1255c48b108SAl Viro if ((addr & 3) || addr < 0) 1265c48b108SAl Viro return -EIO; 1275c48b108SAl Viro 1285c48b108SAl Viro if (addr < MAX_REG_OFFSET) 1295c48b108SAl Viro return putreg(child, addr, data); 1305c48b108SAl Viro else if ((addr >= offsetof(struct user, u_debugreg[0])) && 1315c48b108SAl Viro (addr <= offsetof(struct user, u_debugreg[7]))) { 1325c48b108SAl Viro addr -= offsetof(struct user, u_debugreg[0]); 1335c48b108SAl Viro addr = addr >> 2; 1345c48b108SAl Viro if ((addr == 4) || (addr == 5)) 1355c48b108SAl Viro return -EIO; 1365c48b108SAl Viro child->thread.arch.debugregs[addr] = data; 1375c48b108SAl Viro return 0; 1385c48b108SAl Viro } 1395c48b108SAl Viro return -EIO; 1405c48b108SAl Viro } 1415c48b108SAl Viro 1425c48b108SAl Viro unsigned long getreg(struct task_struct *child, int regno) 1435c48b108SAl Viro { 1445c48b108SAl Viro unsigned long mask = ~0UL; 1455c48b108SAl Viro 1465c48b108SAl Viro regno >>= 2; 1475c48b108SAl Viro switch (regno) { 1485c48b108SAl Viro case FS: 1495c48b108SAl Viro case GS: 1505c48b108SAl Viro case DS: 1515c48b108SAl Viro case ES: 1525c48b108SAl Viro case SS: 1535c48b108SAl Viro case CS: 1545c48b108SAl Viro mask = 0xffff; 1555c48b108SAl Viro break; 1565c48b108SAl Viro case EIP: 1575c48b108SAl Viro case UESP: 1585c48b108SAl Viro case EAX: 1595c48b108SAl Viro case EBX: 1605c48b108SAl Viro case ECX: 1615c48b108SAl Viro case EDX: 1625c48b108SAl Viro case ESI: 1635c48b108SAl Viro case EDI: 1645c48b108SAl Viro case EBP: 1655c48b108SAl Viro case EFL: 166e04c989eSMickaël Salaün case ORIG_EAX: 1675c48b108SAl Viro break; 1685c48b108SAl Viro default: 1695c48b108SAl Viro panic("Bad register in getreg() : %d\n", regno); 1705c48b108SAl Viro } 1715c48b108SAl Viro return mask & child->thread.regs.regs.gp[reg_offsets[regno]]; 1725c48b108SAl Viro } 1735c48b108SAl Viro 1745c48b108SAl Viro /* read the word at location addr in the USER area. */ 1755c48b108SAl Viro int peek_user(struct task_struct *child, long addr, long data) 1765c48b108SAl Viro { 1775c48b108SAl Viro unsigned long tmp; 1785c48b108SAl Viro 1795c48b108SAl Viro if ((addr & 3) || addr < 0) 1805c48b108SAl Viro return -EIO; 1815c48b108SAl Viro 1825c48b108SAl Viro tmp = 0; /* Default return condition */ 1835c48b108SAl Viro if (addr < MAX_REG_OFFSET) { 1845c48b108SAl Viro tmp = getreg(child, addr); 1855c48b108SAl Viro } 1865c48b108SAl Viro else if ((addr >= offsetof(struct user, u_debugreg[0])) && 1875c48b108SAl Viro (addr <= offsetof(struct user, u_debugreg[7]))) { 1885c48b108SAl Viro addr -= offsetof(struct user, u_debugreg[0]); 1895c48b108SAl Viro addr = addr >> 2; 1905c48b108SAl Viro tmp = child->thread.arch.debugregs[addr]; 1915c48b108SAl Viro } 1925c48b108SAl Viro return put_user(tmp, (unsigned long __user *) data); 1935c48b108SAl Viro } 1945c48b108SAl Viro 1955c48b108SAl Viro static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) 1965c48b108SAl Viro { 1975c48b108SAl Viro int err, n, cpu = ((struct thread_info *) child->stack)->cpu; 1985c48b108SAl Viro struct user_i387_struct fpregs; 1995c48b108SAl Viro 200a78ff111SEli Cooper err = save_i387_registers(userspace_pid[cpu], 201a78ff111SEli Cooper (unsigned long *) &fpregs); 2025c48b108SAl Viro if (err) 2035c48b108SAl Viro return err; 2045c48b108SAl Viro 2055c48b108SAl Viro n = copy_to_user(buf, &fpregs, sizeof(fpregs)); 2065c48b108SAl Viro if(n > 0) 2075c48b108SAl Viro return -EFAULT; 2085c48b108SAl Viro 2095c48b108SAl Viro return n; 2105c48b108SAl Viro } 2115c48b108SAl Viro 2125c48b108SAl Viro static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) 2135c48b108SAl Viro { 2145c48b108SAl Viro int n, cpu = ((struct thread_info *) child->stack)->cpu; 2155c48b108SAl Viro struct user_i387_struct fpregs; 2165c48b108SAl Viro 2175c48b108SAl Viro n = copy_from_user(&fpregs, buf, sizeof(fpregs)); 2185c48b108SAl Viro if (n > 0) 2195c48b108SAl Viro return -EFAULT; 2205c48b108SAl Viro 221a78ff111SEli Cooper return restore_i387_registers(userspace_pid[cpu], 2225c48b108SAl Viro (unsigned long *) &fpregs); 2235c48b108SAl Viro } 2245c48b108SAl Viro 2255c48b108SAl Viro static int get_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child) 2265c48b108SAl Viro { 2275c48b108SAl Viro int err, n, cpu = ((struct thread_info *) child->stack)->cpu; 2285c48b108SAl Viro struct user_fxsr_struct fpregs; 2295c48b108SAl Viro 2305c48b108SAl Viro err = save_fpx_registers(userspace_pid[cpu], (unsigned long *) &fpregs); 2315c48b108SAl Viro if (err) 2325c48b108SAl Viro return err; 2335c48b108SAl Viro 2345c48b108SAl Viro n = copy_to_user(buf, &fpregs, sizeof(fpregs)); 2355c48b108SAl Viro if(n > 0) 2365c48b108SAl Viro return -EFAULT; 2375c48b108SAl Viro 2385c48b108SAl Viro return n; 2395c48b108SAl Viro } 2405c48b108SAl Viro 2415c48b108SAl Viro static int set_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child) 2425c48b108SAl Viro { 2435c48b108SAl Viro int n, cpu = ((struct thread_info *) child->stack)->cpu; 2445c48b108SAl Viro struct user_fxsr_struct fpregs; 2455c48b108SAl Viro 2465c48b108SAl Viro n = copy_from_user(&fpregs, buf, sizeof(fpregs)); 2475c48b108SAl Viro if (n > 0) 2485c48b108SAl Viro return -EFAULT; 2495c48b108SAl Viro 2505c48b108SAl Viro return restore_fpx_registers(userspace_pid[cpu], 2515c48b108SAl Viro (unsigned long *) &fpregs); 2525c48b108SAl Viro } 2535c48b108SAl Viro 2545c48b108SAl Viro long subarch_ptrace(struct task_struct *child, long request, 2555c48b108SAl Viro unsigned long addr, unsigned long data) 2565c48b108SAl Viro { 2575c48b108SAl Viro int ret = -EIO; 2585c48b108SAl Viro void __user *datap = (void __user *) data; 2595c48b108SAl Viro switch (request) { 2605c48b108SAl Viro case PTRACE_GETFPREGS: /* Get the child FPU state. */ 2615c48b108SAl Viro ret = get_fpregs(datap, child); 2625c48b108SAl Viro break; 2635c48b108SAl Viro case PTRACE_SETFPREGS: /* Set the child FPU state. */ 2645c48b108SAl Viro ret = set_fpregs(datap, child); 2655c48b108SAl Viro break; 2665c48b108SAl Viro case PTRACE_GETFPXREGS: /* Get the child FPU state. */ 2675c48b108SAl Viro ret = get_fpxregs(datap, child); 2685c48b108SAl Viro break; 2695c48b108SAl Viro case PTRACE_SETFPXREGS: /* Set the child FPU state. */ 2705c48b108SAl Viro ret = set_fpxregs(datap, child); 2715c48b108SAl Viro break; 2725c48b108SAl Viro default: 2735c48b108SAl Viro ret = -EIO; 2745c48b108SAl Viro } 2755c48b108SAl Viro return ret; 2765c48b108SAl Viro } 277