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> 87c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 9*3f17fed2SBenjamin Berg #include <linux/regset.h> 10da028d5eSRichard Weinberger #include <asm/ptrace-abi.h> 11dbba7f70SAl Viro #include <registers.h> 1237185b33SAl Viro #include <skas.h> 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 /* determines which flags the user has access to. */ 285c48b108SAl Viro /* 1 = access 0 = no access */ 295c48b108SAl Viro #define FLAG_MASK 0x00044dd5 305c48b108SAl Viro 315c48b108SAl Viro static const int reg_offsets[] = { 323579a389SAl Viro [EBX] = HOST_BX, 333579a389SAl Viro [ECX] = HOST_CX, 343579a389SAl Viro [EDX] = HOST_DX, 353579a389SAl Viro [ESI] = HOST_SI, 363579a389SAl Viro [EDI] = HOST_DI, 373579a389SAl Viro [EBP] = HOST_BP, 383579a389SAl Viro [EAX] = HOST_AX, 395c48b108SAl Viro [DS] = HOST_DS, 405c48b108SAl Viro [ES] = HOST_ES, 415c48b108SAl Viro [FS] = HOST_FS, 425c48b108SAl Viro [GS] = HOST_GS, 435c48b108SAl Viro [EIP] = HOST_IP, 445c48b108SAl Viro [CS] = HOST_CS, 455c48b108SAl Viro [EFL] = HOST_EFLAGS, 465c48b108SAl Viro [UESP] = HOST_SP, 475c48b108SAl Viro [SS] = HOST_SS, 48e04c989eSMickaël Salaün [ORIG_EAX] = HOST_ORIG_AX, 495c48b108SAl Viro }; 505c48b108SAl Viro 515c48b108SAl Viro int putreg(struct task_struct *child, int regno, unsigned long value) 525c48b108SAl Viro { 535c48b108SAl Viro regno >>= 2; 545c48b108SAl Viro switch (regno) { 555c48b108SAl Viro case EBX: 565c48b108SAl Viro case ECX: 575c48b108SAl Viro case EDX: 585c48b108SAl Viro case ESI: 595c48b108SAl Viro case EDI: 605c48b108SAl Viro case EBP: 615c48b108SAl Viro case EAX: 625c48b108SAl Viro case EIP: 635c48b108SAl Viro case UESP: 64ce29856aSMickaël Salaün break; 65e04c989eSMickaël Salaün case ORIG_EAX: 66ce29856aSMickaël Salaün /* Update the syscall number. */ 67ce29856aSMickaël Salaün UPT_SYSCALL_NR(&child->thread.regs.regs) = value; 685c48b108SAl Viro break; 695c48b108SAl Viro case FS: 705c48b108SAl Viro if (value && (value & 3) != 3) 715c48b108SAl Viro return -EIO; 725c48b108SAl Viro break; 735c48b108SAl Viro case GS: 745c48b108SAl Viro if (value && (value & 3) != 3) 755c48b108SAl Viro return -EIO; 765c48b108SAl Viro break; 775c48b108SAl Viro case DS: 785c48b108SAl Viro case ES: 795c48b108SAl Viro if (value && (value & 3) != 3) 805c48b108SAl Viro return -EIO; 815c48b108SAl Viro value &= 0xffff; 825c48b108SAl Viro break; 835c48b108SAl Viro case SS: 845c48b108SAl Viro case CS: 855c48b108SAl Viro if ((value & 3) != 3) 865c48b108SAl Viro return -EIO; 875c48b108SAl Viro value &= 0xffff; 885c48b108SAl Viro break; 895c48b108SAl Viro case EFL: 905c48b108SAl Viro value &= FLAG_MASK; 915c48b108SAl Viro child->thread.regs.regs.gp[HOST_EFLAGS] |= value; 925c48b108SAl Viro return 0; 935c48b108SAl Viro default : 945c48b108SAl Viro panic("Bad register in putreg() : %d\n", regno); 955c48b108SAl Viro } 965c48b108SAl Viro child->thread.regs.regs.gp[reg_offsets[regno]] = value; 975c48b108SAl Viro return 0; 985c48b108SAl Viro } 995c48b108SAl Viro 1005c48b108SAl Viro int poke_user(struct task_struct *child, long addr, long data) 1015c48b108SAl Viro { 1025c48b108SAl Viro if ((addr & 3) || addr < 0) 1035c48b108SAl Viro return -EIO; 1045c48b108SAl Viro 1055c48b108SAl Viro if (addr < MAX_REG_OFFSET) 1065c48b108SAl Viro return putreg(child, addr, data); 1075c48b108SAl Viro else if ((addr >= offsetof(struct user, u_debugreg[0])) && 1085c48b108SAl Viro (addr <= offsetof(struct user, u_debugreg[7]))) { 1095c48b108SAl Viro addr -= offsetof(struct user, u_debugreg[0]); 1105c48b108SAl Viro addr = addr >> 2; 1115c48b108SAl Viro if ((addr == 4) || (addr == 5)) 1125c48b108SAl Viro return -EIO; 1135c48b108SAl Viro child->thread.arch.debugregs[addr] = data; 1145c48b108SAl Viro return 0; 1155c48b108SAl Viro } 1165c48b108SAl Viro return -EIO; 1175c48b108SAl Viro } 1185c48b108SAl Viro 1195c48b108SAl Viro unsigned long getreg(struct task_struct *child, int regno) 1205c48b108SAl Viro { 1215c48b108SAl Viro unsigned long mask = ~0UL; 1225c48b108SAl Viro 1235c48b108SAl Viro regno >>= 2; 1245c48b108SAl Viro switch (regno) { 1255c48b108SAl Viro case FS: 1265c48b108SAl Viro case GS: 1275c48b108SAl Viro case DS: 1285c48b108SAl Viro case ES: 1295c48b108SAl Viro case SS: 1305c48b108SAl Viro case CS: 1315c48b108SAl Viro mask = 0xffff; 1325c48b108SAl Viro break; 1335c48b108SAl Viro case EIP: 1345c48b108SAl Viro case UESP: 1355c48b108SAl Viro case EAX: 1365c48b108SAl Viro case EBX: 1375c48b108SAl Viro case ECX: 1385c48b108SAl Viro case EDX: 1395c48b108SAl Viro case ESI: 1405c48b108SAl Viro case EDI: 1415c48b108SAl Viro case EBP: 1425c48b108SAl Viro case EFL: 143e04c989eSMickaël Salaün case ORIG_EAX: 1445c48b108SAl Viro break; 1455c48b108SAl Viro default: 1465c48b108SAl Viro panic("Bad register in getreg() : %d\n", regno); 1475c48b108SAl Viro } 1485c48b108SAl Viro return mask & child->thread.regs.regs.gp[reg_offsets[regno]]; 1495c48b108SAl Viro } 1505c48b108SAl Viro 1515c48b108SAl Viro /* read the word at location addr in the USER area. */ 1525c48b108SAl Viro int peek_user(struct task_struct *child, long addr, long data) 1535c48b108SAl Viro { 1545c48b108SAl Viro unsigned long tmp; 1555c48b108SAl Viro 1565c48b108SAl Viro if ((addr & 3) || addr < 0) 1575c48b108SAl Viro return -EIO; 1585c48b108SAl Viro 1595c48b108SAl Viro tmp = 0; /* Default return condition */ 1605c48b108SAl Viro if (addr < MAX_REG_OFFSET) { 1615c48b108SAl Viro tmp = getreg(child, addr); 1625c48b108SAl Viro } 1635c48b108SAl Viro else if ((addr >= offsetof(struct user, u_debugreg[0])) && 1645c48b108SAl Viro (addr <= offsetof(struct user, u_debugreg[7]))) { 1655c48b108SAl Viro addr -= offsetof(struct user, u_debugreg[0]); 1665c48b108SAl Viro addr = addr >> 2; 1675c48b108SAl Viro tmp = child->thread.arch.debugregs[addr]; 1685c48b108SAl Viro } 1695c48b108SAl Viro return put_user(tmp, (unsigned long __user *) data); 1705c48b108SAl Viro } 1715c48b108SAl Viro 1725c48b108SAl Viro long subarch_ptrace(struct task_struct *child, long request, 1735c48b108SAl Viro unsigned long addr, unsigned long data) 1745c48b108SAl Viro { 1755c48b108SAl Viro int ret = -EIO; 1765c48b108SAl Viro void __user *datap = (void __user *) data; 1775c48b108SAl Viro switch (request) { 1785c48b108SAl Viro case PTRACE_GETFPREGS: /* Get the child FPU state. */ 179*3f17fed2SBenjamin Berg return copy_regset_to_user(child, task_user_regset_view(child), 180*3f17fed2SBenjamin Berg REGSET_FP_LEGACY, 181*3f17fed2SBenjamin Berg 0, sizeof(struct user_i387_struct), 182*3f17fed2SBenjamin Berg datap); 1835c48b108SAl Viro case PTRACE_SETFPREGS: /* Set the child FPU state. */ 184*3f17fed2SBenjamin Berg return copy_regset_from_user(child, task_user_regset_view(child), 185*3f17fed2SBenjamin Berg REGSET_FP_LEGACY, 186*3f17fed2SBenjamin Berg 0, sizeof(struct user_i387_struct), 187*3f17fed2SBenjamin Berg datap); 1885c48b108SAl Viro case PTRACE_GETFPXREGS: /* Get the child FPU state. */ 189*3f17fed2SBenjamin Berg return copy_regset_to_user(child, task_user_regset_view(child), 190*3f17fed2SBenjamin Berg REGSET_FP, 191*3f17fed2SBenjamin Berg 0, sizeof(struct user_fxsr_struct), 192*3f17fed2SBenjamin Berg datap); 1935c48b108SAl Viro case PTRACE_SETFPXREGS: /* Set the child FPU state. */ 194*3f17fed2SBenjamin Berg return copy_regset_from_user(child, task_user_regset_view(child), 195*3f17fed2SBenjamin Berg REGSET_FP, 196*3f17fed2SBenjamin Berg 0, sizeof(struct user_fxsr_struct), 197*3f17fed2SBenjamin Berg datap); 1985c48b108SAl Viro default: 1995c48b108SAl Viro ret = -EIO; 2005c48b108SAl Viro } 2015c48b108SAl Viro return ret; 2025c48b108SAl Viro } 203