2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
6 #include "linux/sched.h"
8 #include "asm/ptrace.h"
9 #include "asm/uaccess.h"
10 #include "ptrace_user.h"
11 #include "sysdep/sigcontext.h"
12 #include "sysdep/sc.h"
14 void arch_switch(void)
16 update_debugregs(current->thread.arch.debugregs_seq);
19 int is_syscall(unsigned long addr)
24 n = copy_from_user(&instr, (void *) addr, sizeof(instr));
26 printk("is_syscall : failed to read instruction from 0x%lu\n",
30 return(instr == 0x80cd);
33 /* determines which flags the user has access to. */
34 /* 1 = access 0 = no access */
35 #define FLAG_MASK 0x00044dd5
37 int putreg(struct task_struct *child, int regno, unsigned long value)
42 if (value && (value & 3) != 3)
44 PT_REGS_FS(&child->thread.regs) = value;
47 if (value && (value & 3) != 3)
49 PT_REGS_GS(&child->thread.regs) = value;
53 if (value && (value & 3) != 3)
65 value |= PT_REGS_EFLAGS(&child->thread.regs);
68 PT_REGS_SET(&child->thread.regs, regno, value);
72 unsigned long getreg(struct task_struct *child, int regno)
74 unsigned long retval = ~0UL;
87 retval &= PT_REG(&child->thread.regs, regno);
92 struct i387_fxsave_struct {
103 long st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
104 long xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */
109 * FPU tag word conversions.
112 static inline unsigned short twd_i387_to_fxsr( unsigned short twd )
114 unsigned int tmp; /* to avoid 16 bit prefixes in the code */
116 /* Transform each pair of bits into 01 (valid) or 00 (empty) */
118 tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
119 /* and move the valid bits to the lower byte. */
120 tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
121 tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
122 tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
126 static inline unsigned long twd_fxsr_to_i387( struct i387_fxsave_struct *fxsave )
128 struct _fpxreg *st = NULL;
129 unsigned long twd = (unsigned long) fxsave->twd;
131 unsigned long ret = 0xffff0000;
134 #define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16);
136 for ( i = 0 ; i < 8 ; i++ ) {
138 st = (struct _fpxreg *) FPREG_ADDR( fxsave, i );
140 switch ( st->exponent & 0x7fff ) {
142 tag = 2; /* Special */
145 if ( !st->significand[0] &&
146 !st->significand[1] &&
147 !st->significand[2] &&
148 !st->significand[3] ) {
151 tag = 2; /* Special */
155 if ( st->significand[3] & 0x8000 ) {
158 tag = 2; /* Special */
165 ret |= (tag << (2 * i));
172 * FXSR floating point environment conversions.
175 #ifdef CONFIG_MODE_TT
176 static inline int convert_fxsr_to_user_tt(struct _fpstate *buf,
177 struct pt_regs *regs)
179 struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
180 unsigned long env[7];
182 struct _fpxreg *from;
185 env[0] = (unsigned long)fxsave->cwd | 0xffff0000;
186 env[1] = (unsigned long)fxsave->swd | 0xffff0000;
187 env[2] = twd_fxsr_to_i387(fxsave);
188 env[3] = fxsave->fip;
189 env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16);
190 env[5] = fxsave->foo;
191 env[6] = fxsave->fos;
193 if ( __copy_to_user( buf, env, 7 * sizeof(unsigned long) ) )
197 from = (struct _fpxreg *) &fxsave->st_space[0];
198 for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
199 if ( __copy_to_user( to, from, sizeof(*to) ) )
206 static inline int convert_fxsr_to_user(struct _fpstate *buf,
207 struct pt_regs *regs)
209 return(CHOOSE_MODE(convert_fxsr_to_user_tt(buf, regs), 0));
212 #ifdef CONFIG_MODE_TT
213 static inline int convert_fxsr_from_user_tt(struct pt_regs *regs,
214 struct _fpstate *buf)
216 struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
217 unsigned long env[7];
222 if ( __copy_from_user( env, buf, 7 * sizeof(long) ) )
225 fxsave->cwd = (unsigned short)(env[0] & 0xffff);
226 fxsave->swd = (unsigned short)(env[1] & 0xffff);
227 fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff));
228 fxsave->fip = env[3];
229 fxsave->fop = (unsigned short)((env[4] & 0xffff0000) >> 16);
230 fxsave->fcs = (env[4] & 0xffff);
231 fxsave->foo = env[5];
232 fxsave->fos = env[6];
234 to = (struct _fpxreg *) &fxsave->st_space[0];
236 for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
237 if ( __copy_from_user( to, from, sizeof(*from) ) )
244 static inline int convert_fxsr_from_user(struct pt_regs *regs,
245 struct _fpstate *buf)
247 return(CHOOSE_MODE(convert_fxsr_from_user_tt(regs, buf), 0));
250 int get_fpregs(unsigned long buf, struct task_struct *child)
254 err = convert_fxsr_to_user((struct _fpstate *) buf,
255 &child->thread.regs);
256 if(err) return(-EFAULT);
260 int set_fpregs(unsigned long buf, struct task_struct *child)
264 err = convert_fxsr_from_user(&child->thread.regs,
265 (struct _fpstate *) buf);
266 if(err) return(-EFAULT);
270 #ifdef CONFIG_MODE_TT
271 int get_fpxregs_tt(unsigned long buf, struct task_struct *tsk)
273 struct pt_regs *regs = &tsk->thread.regs;
274 struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
277 err = __copy_to_user((void *) buf, fxsave,
278 sizeof(struct user_fxsr_struct));
279 if(err) return -EFAULT;
284 int get_fpxregs(unsigned long buf, struct task_struct *tsk)
286 return(CHOOSE_MODE(get_fpxregs_tt(buf, tsk), 0));
289 #ifdef CONFIG_MODE_TT
290 int set_fpxregs_tt(unsigned long buf, struct task_struct *tsk)
292 struct pt_regs *regs = &tsk->thread.regs;
293 struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
296 err = __copy_from_user(fxsave, (void *) buf,
297 sizeof(struct user_fxsr_struct) );
298 if(err) return -EFAULT;
303 int set_fpxregs(unsigned long buf, struct task_struct *tsk)
305 return(CHOOSE_MODE(set_fpxregs_tt(buf, tsk), 0));
309 int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
311 fpu->cwd = (((SC_FP_CW(PT_REGS_SC(regs)) & 0xffff) << 16) |
312 (SC_FP_SW(PT_REGS_SC(regs)) & 0xffff));
313 fpu->swd = SC_FP_CSSEL(PT_REGS_SC(regs)) & 0xffff;
314 fpu->twd = SC_FP_IPOFF(PT_REGS_SC(regs));
315 fpu->fip = SC_FP_CSSEL(PT_REGS_SC(regs)) & 0xffff;
316 fpu->fcs = SC_FP_DATAOFF(PT_REGS_SC(regs));
317 fpu->foo = SC_FP_DATASEL(PT_REGS_SC(regs));
319 memcpy(fpu->st_space, (void *) SC_FP_ST(PT_REGS_SC(regs)),
320 sizeof(fpu->st_space));
325 #ifdef CONFIG_MODE_TT
326 static inline void copy_fpu_fxsave_tt(struct pt_regs *regs,
327 struct user_i387_struct *buf)
329 struct i387_fxsave_struct *fpu = SC_FXSR_ENV(PT_REGS_SC(regs));
331 unsigned short *from;
334 memcpy( buf, fpu, 7 * sizeof(long) );
336 to = (unsigned short *) &buf->st_space[0];
337 from = (unsigned short *) &fpu->st_space[0];
338 for ( i = 0 ; i < 8 ; i++, to += 5, from += 8 ) {
339 memcpy( to, from, 5 * sizeof(unsigned short) );
344 static inline void copy_fpu_fxsave(struct pt_regs *regs,
345 struct user_i387_struct *buf)
347 (void) CHOOSE_MODE(copy_fpu_fxsave_tt(regs, buf), 0);
350 int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu )
352 copy_fpu_fxsave(regs, (struct user_i387_struct *) fpu);
357 * Overrides for Emacs so that we follow Linus's tabbing style.
358 * Emacs will notice this stuff at the end of the file and automatically
359 * adjust the settings for this buffer only. This must remain at the end
361 * ---------------------------------------------------------------------------
363 * c-file-style: "linux"