• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3  * Licensed under the GPL
4  */
5 
6 #include "linux/mm.h"
7 #include "linux/sched.h"
8 #include "asm/uaccess.h"
9 #include "skas.h"
10 
11 extern int arch_switch_tls(struct task_struct *to);
12 
arch_switch_to(struct task_struct * to)13 void arch_switch_to(struct task_struct *to)
14 {
15 	int err = arch_switch_tls(to);
16 	if (!err)
17 		return;
18 
19 	if (err != -EINVAL)
20 		printk(KERN_WARNING "arch_switch_tls failed, errno %d, "
21 		       "not EINVAL\n", -err);
22 	else
23 		printk(KERN_WARNING "arch_switch_tls failed, errno = EINVAL\n");
24 }
25 
is_syscall(unsigned long addr)26 int is_syscall(unsigned long addr)
27 {
28 	unsigned short instr;
29 	int n;
30 
31 	n = copy_from_user(&instr, (void __user *) addr, sizeof(instr));
32 	if (n) {
33 		/* access_process_vm() grants access to vsyscall and stub,
34 		 * while copy_from_user doesn't. Maybe access_process_vm is
35 		 * slow, but that doesn't matter, since it will be called only
36 		 * in case of singlestepping, if copy_from_user failed.
37 		 */
38 		n = access_process_vm(current, addr, &instr, sizeof(instr), 0);
39 		if (n != sizeof(instr)) {
40 			printk(KERN_ERR "is_syscall : failed to read "
41 			       "instruction from 0x%lx\n", addr);
42 			return 1;
43 		}
44 	}
45 	/* int 0x80 or sysenter */
46 	return (instr == 0x80cd) || (instr == 0x340f);
47 }
48 
49 /* determines which flags the user has access to. */
50 /* 1 = access 0 = no access */
51 #define FLAG_MASK 0x00044dd5
52 
putreg(struct task_struct * child,int regno,unsigned long value)53 int putreg(struct task_struct *child, int regno, unsigned long value)
54 {
55 	regno >>= 2;
56 	switch (regno) {
57 	case FS:
58 		if (value && (value & 3) != 3)
59 			return -EIO;
60 		PT_REGS_FS(&child->thread.regs) = value;
61 		return 0;
62 	case GS:
63 		if (value && (value & 3) != 3)
64 			return -EIO;
65 		PT_REGS_GS(&child->thread.regs) = value;
66 		return 0;
67 	case DS:
68 	case ES:
69 		if (value && (value & 3) != 3)
70 			return -EIO;
71 		value &= 0xffff;
72 		break;
73 	case SS:
74 	case CS:
75 		if ((value & 3) != 3)
76 			return -EIO;
77 		value &= 0xffff;
78 		break;
79 	case EFL:
80 		value &= FLAG_MASK;
81 		value |= PT_REGS_EFLAGS(&child->thread.regs);
82 		break;
83 	}
84 	PT_REGS_SET(&child->thread.regs, regno, value);
85 	return 0;
86 }
87 
poke_user(struct task_struct * child,long addr,long data)88 int poke_user(struct task_struct *child, long addr, long data)
89 {
90 	if ((addr & 3) || addr < 0)
91 		return -EIO;
92 
93 	if (addr < MAX_REG_OFFSET)
94 		return putreg(child, addr, data);
95 	else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
96 		 (addr <= offsetof(struct user, u_debugreg[7]))) {
97 		addr -= offsetof(struct user, u_debugreg[0]);
98 		addr = addr >> 2;
99 		if ((addr == 4) || (addr == 5))
100 			return -EIO;
101 		child->thread.arch.debugregs[addr] = data;
102 		return 0;
103 	}
104 	return -EIO;
105 }
106 
getreg(struct task_struct * child,int regno)107 unsigned long getreg(struct task_struct *child, int regno)
108 {
109 	unsigned long retval = ~0UL;
110 
111 	regno >>= 2;
112 	switch (regno) {
113 	case FS:
114 	case GS:
115 	case DS:
116 	case ES:
117 	case SS:
118 	case CS:
119 		retval = 0xffff;
120 		/* fall through */
121 	default:
122 		retval &= PT_REG(&child->thread.regs, regno);
123 	}
124 	return retval;
125 }
126 
127 /* read the word at location addr in the USER area. */
peek_user(struct task_struct * child,long addr,long data)128 int peek_user(struct task_struct *child, long addr, long data)
129 {
130 	unsigned long tmp;
131 
132 	if ((addr & 3) || addr < 0)
133 		return -EIO;
134 
135 	tmp = 0;  /* Default return condition */
136 	if (addr < MAX_REG_OFFSET) {
137 		tmp = getreg(child, addr);
138 	}
139 	else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
140 		 (addr <= offsetof(struct user, u_debugreg[7]))) {
141 		addr -= offsetof(struct user, u_debugreg[0]);
142 		addr = addr >> 2;
143 		tmp = child->thread.arch.debugregs[addr];
144 	}
145 	return put_user(tmp, (unsigned long __user *) data);
146 }
147 
get_fpregs(struct user_i387_struct __user * buf,struct task_struct * child)148 int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
149 {
150 	int err, n, cpu = ((struct thread_info *) child->stack)->cpu;
151 	struct user_i387_struct fpregs;
152 
153 	err = save_fp_registers(userspace_pid[cpu], (unsigned long *) &fpregs);
154 	if (err)
155 		return err;
156 
157 	n = copy_to_user(buf, &fpregs, sizeof(fpregs));
158 	if(n > 0)
159 		return -EFAULT;
160 
161 	return n;
162 }
163 
set_fpregs(struct user_i387_struct __user * buf,struct task_struct * child)164 int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
165 {
166 	int n, cpu = ((struct thread_info *) child->stack)->cpu;
167 	struct user_i387_struct fpregs;
168 
169 	n = copy_from_user(&fpregs, buf, sizeof(fpregs));
170 	if (n > 0)
171 		return -EFAULT;
172 
173 	return restore_fp_registers(userspace_pid[cpu],
174 				    (unsigned long *) &fpregs);
175 }
176 
get_fpxregs(struct user_fxsr_struct __user * buf,struct task_struct * child)177 int get_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child)
178 {
179 	int err, n, cpu = ((struct thread_info *) child->stack)->cpu;
180 	struct user_fxsr_struct fpregs;
181 
182 	err = save_fpx_registers(userspace_pid[cpu], (unsigned long *) &fpregs);
183 	if (err)
184 		return err;
185 
186 	n = copy_to_user(buf, &fpregs, sizeof(fpregs));
187 	if(n > 0)
188 		return -EFAULT;
189 
190 	return n;
191 }
192 
set_fpxregs(struct user_fxsr_struct __user * buf,struct task_struct * child)193 int set_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child)
194 {
195 	int n, cpu = ((struct thread_info *) child->stack)->cpu;
196 	struct user_fxsr_struct fpregs;
197 
198 	n = copy_from_user(&fpregs, buf, sizeof(fpregs));
199 	if (n > 0)
200 		return -EFAULT;
201 
202 	return restore_fpx_registers(userspace_pid[cpu],
203 				     (unsigned long *) &fpregs);
204 }
205 
subarch_ptrace(struct task_struct * child,long request,long addr,long data)206 long subarch_ptrace(struct task_struct *child, long request, long addr,
207 		    long data)
208 {
209 	return -EIO;
210 }
211