OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [x86_64/] [ia32/] [fpu32.c] - Blame information for rev 1275

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * Copyright 2002 Andi Kleen, SuSE Labs.
3
 * FXSAVE<->i387 conversion support. Based on code by Gareth Hughes.
4
 * This is used for ptrace, signals and coredumps in 32bit emulation.
5
 * $Id: fpu32.c,v 1.1.1.1 2004-04-15 01:36:39 phoenix Exp $
6
 */
7
 
8
#include <linux/sched.h>
9
#include <asm/sigcontext32.h>
10
#include <asm/processor.h>
11
#include <asm/uaccess.h>
12
#include <asm/i387.h>
13
 
14
static inline unsigned short twd_i387_to_fxsr(unsigned short twd)
15
{
16
        unsigned int tmp; /* to avoid 16 bit prefixes in the code */
17
 
18
        /* Transform each pair of bits into 01 (valid) or 00 (empty) */
19
        tmp = ~twd;
20
        tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
21
        /* and move the valid bits to the lower byte. */
22
        tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
23
        tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
24
        tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
25
        return tmp;
26
}
27
 
28
static inline unsigned long twd_fxsr_to_i387(struct i387_fxsave_struct *fxsave)
29
{
30
        struct _fpxreg *st = NULL;
31
        unsigned long twd = (unsigned long) fxsave->twd;
32
        unsigned long tag;
33
        unsigned long ret = 0xffff0000;
34
        int i;
35
 
36
#define FPREG_ADDR(f, n)        ((char *)&(f)->st_space + (n) * 16);
37
 
38
        for (i = 0 ; i < 8 ; i++) {
39
                if (twd & 0x1) {
40
                        st = (struct _fpxreg *) FPREG_ADDR( fxsave, i );
41
 
42
                        switch (st->exponent & 0x7fff) {
43
                        case 0x7fff:
44
                                tag = 2;                /* Special */
45
                                break;
46
                        case 0x0000:
47
                                if ( !st->significand[0] &&
48
                                     !st->significand[1] &&
49
                                     !st->significand[2] &&
50
                                     !st->significand[3] ) {
51
                                        tag = 1;        /* Zero */
52
                                } else {
53
                                        tag = 2;        /* Special */
54
                                }
55
                                break;
56
                        default:
57
                                if (st->significand[3] & 0x8000) {
58
                                        tag = 0; /* Valid */
59
                                } else {
60
                                        tag = 2;        /* Special */
61
                                }
62
                                break;
63
                        }
64
                } else {
65
                        tag = 3;                        /* Empty */
66
                }
67
                ret |= (tag << (2 * i));
68
                twd = twd >> 1;
69
        }
70
        return ret;
71
}
72
 
73
 
74
static inline int convert_fxsr_from_user(struct i387_fxsave_struct *fxsave,
75
                                         struct _fpstate_ia32 *buf)
76
{
77
        struct _fpxreg *to;
78
        struct _fpreg *from;
79
        int i;
80
        int err = 0;
81
        u32 v;
82
 
83
#define G(num,val) err |= __get_user(val, num + (u32 *)buf)
84
        G(0, fxsave->cwd);
85
        G(1, fxsave->swd);
86
        G(2, fxsave->twd);
87
        fxsave->twd = twd_i387_to_fxsr(fxsave->twd);
88
        G(3, fxsave->rip);
89
        G(4, v);
90
        fxsave->fop = v>>16;    /* cs ignored */
91
        G(5, fxsave->rdp);
92
        /* 6: ds ignored */
93
#undef G
94
        if (err)
95
                return -1;
96
 
97
        to = (struct _fpxreg *)&fxsave->st_space[0];
98
        from = &buf->_st[0];
99
        for (i = 0 ; i < 8 ; i++, to++, from++) {
100
                if (__copy_from_user(to, from, sizeof(*from)))
101
                        return -1;
102
        }
103
        return 0;
104
}
105
 
106
 
107
static inline int convert_fxsr_to_user(struct _fpstate_ia32 *buf,
108
                                       struct i387_fxsave_struct *fxsave,
109
                                       struct pt_regs *regs,
110
                                       struct task_struct *tsk)
111
{
112
        struct _fpreg *to;
113
        struct _fpxreg *from;
114
        int i;
115
        u16 cs,ds;
116
        int err = 0;
117
 
118
        if (tsk == current) {
119
                /* should be actually ds/cs at fpu exception time,
120
                   but that information is not available in 64bit mode. */
121
                asm("movw %%ds,%0 " : "=r" (ds));
122
                asm("movw %%cs,%0 " : "=r" (cs));
123
        } else { /* ptrace. task has stopped. */
124
                ds = tsk->thread.ds;
125
                cs = regs->cs;
126
        }
127
 
128
#define P(num,val) err |= __put_user(val, num + (u32 *)buf)
129
        P(0, (u32)fxsave->cwd | 0xffff0000);
130
        P(1, (u32)fxsave->swd | 0xffff0000);
131
        P(2, twd_fxsr_to_i387(fxsave));
132
        P(3, (u32)fxsave->rip);
133
        P(4,  cs | ((u32)fxsave->fop) << 16);
134
        P(5, fxsave->rdp);
135
        P(6, 0xffff0000 | ds);
136
#undef P
137
 
138
        if (err)
139
                return -1;
140
 
141
        to = &buf->_st[0];
142
        from = (struct _fpxreg *) &fxsave->st_space[0];
143
        for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
144
                if (__copy_to_user(to, from, sizeof(*to)))
145
                        return -1;
146
        }
147
        return 0;
148
}
149
 
150
int restore_i387_ia32(struct task_struct *tsk, struct _fpstate_ia32 *buf, int fsave)
151
{
152
        clear_fpu(tsk);
153
        if (!fsave) {
154
                if (__copy_from_user(&tsk->thread.i387.fxsave,
155
                                     &buf->_fxsr_env[0],
156
                                     sizeof(struct i387_fxsave_struct)))
157
                        return -1;
158
        tsk->thread.i387.fxsave.mxcsr &= 0xffbf;
159
        }
160
        tsk->used_math = 1;
161
        return convert_fxsr_from_user(&tsk->thread.i387.fxsave, buf);
162
}
163
 
164
int save_i387_ia32(struct task_struct *tsk,
165
                   struct _fpstate_ia32 *buf,
166
                   struct pt_regs *regs,
167
                   int fsave)
168
{
169
        int err = 0;
170
 
171
        init_fpu(tsk);
172
        if (convert_fxsr_to_user(buf, &tsk->thread.i387.fxsave, regs, tsk))
173
                return -1;
174
        if (fsave)
175
                return 0;
176
        err |= __put_user(tsk->thread.i387.fxsave.swd, &buf->status);
177
        if (fsave)
178
                return err ? -1 : 1;
179
        err |= __put_user(X86_FXSR_MAGIC, &buf->magic);
180
        err |= __copy_to_user(&buf->_fxsr_env[0], &tsk->thread.i387.fxsave,
181
                              sizeof(struct i387_fxsave_struct));
182
        return err ? -1 : 1;
183
}

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.