• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/x86/math-emu/
1/*---------------------------------------------------------------------------+
2 |  load_store.c                                                             |
3 |                                                                           |
4 | This file contains most of the code to interpret the FPU instructions     |
5 | which load and store from user memory.                                    |
6 |                                                                           |
7 | Copyright (C) 1992,1993,1994,1997                                         |
8 |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
9 |                       Australia.  E-mail   billm@suburbia.net             |
10 |                                                                           |
11 |                                                                           |
12 +---------------------------------------------------------------------------*/
13
14/*---------------------------------------------------------------------------+
15 | Note:                                                                     |
16 |    The file contains code which accesses user memory.                     |
17 |    Emulator static data may change when user memory is accessed, due to   |
18 |    other processes using the emulator while swapping is in progress.      |
19 +---------------------------------------------------------------------------*/
20
21#include <asm/uaccess.h>
22
23#include "fpu_system.h"
24#include "exception.h"
25#include "fpu_emu.h"
26#include "status_w.h"
27#include "control_w.h"
28
29#define _NONE_ 0		/* st0_ptr etc not needed */
30#define _REG0_ 1		/* Will be storing st(0) */
31#define _PUSH_ 3		/* Need to check for space to push onto stack */
32#define _null_ 4		/* Function illegal or not implemented */
33
34#define pop_0()	{ FPU_settag0(TAG_Empty); top++; }
35
36static u_char const type_table[32] = {
37	_PUSH_, _PUSH_, _PUSH_, _PUSH_,
38	_null_, _null_, _null_, _null_,
39	_REG0_, _REG0_, _REG0_, _REG0_,
40	_REG0_, _REG0_, _REG0_, _REG0_,
41	_NONE_, _null_, _NONE_, _PUSH_,
42	_NONE_, _PUSH_, _null_, _PUSH_,
43	_NONE_, _null_, _NONE_, _REG0_,
44	_NONE_, _REG0_, _NONE_, _REG0_
45};
46
47u_char const data_sizes_16[32] = {
48	4, 4, 8, 2, 0, 0, 0, 0,
49	4, 4, 8, 2, 4, 4, 8, 2,
50	14, 0, 94, 10, 2, 10, 0, 8,
51	14, 0, 94, 10, 2, 10, 2, 8
52};
53
54static u_char const data_sizes_32[32] = {
55	4, 4, 8, 2, 0, 0, 0, 0,
56	4, 4, 8, 2, 4, 4, 8, 2,
57	28, 0, 108, 10, 2, 10, 0, 8,
58	28, 0, 108, 10, 2, 10, 2, 8
59};
60
61int FPU_load_store(u_char type, fpu_addr_modes addr_modes,
62		   void __user * data_address)
63{
64	FPU_REG loaded_data;
65	FPU_REG *st0_ptr;
66	u_char st0_tag = TAG_Empty;	/* This is just to stop a gcc warning. */
67	u_char loaded_tag;
68
69	st0_ptr = NULL;		/* Initialized just to stop compiler warnings. */
70
71	if (addr_modes.default_mode & PROTECTED) {
72		if (addr_modes.default_mode == SEG32) {
73			if (access_limit < data_sizes_32[type])
74				math_abort(FPU_info, SIGSEGV);
75		} else if (addr_modes.default_mode == PM16) {
76			if (access_limit < data_sizes_16[type])
77				math_abort(FPU_info, SIGSEGV);
78		}
79#ifdef PARANOID
80		else
81			EXCEPTION(EX_INTERNAL | 0x140);
82#endif /* PARANOID */
83	}
84
85	switch (type_table[type]) {
86	case _NONE_:
87		break;
88	case _REG0_:
89		st0_ptr = &st(0);	/* Some of these instructions pop after
90					   storing */
91		st0_tag = FPU_gettag0();
92		break;
93	case _PUSH_:
94		{
95			if (FPU_gettagi(-1) != TAG_Empty) {
96				FPU_stack_overflow();
97				return 0;
98			}
99			top--;
100			st0_ptr = &st(0);
101		}
102		break;
103	case _null_:
104		FPU_illegal();
105		return 0;
106#ifdef PARANOID
107	default:
108		EXCEPTION(EX_INTERNAL | 0x141);
109		return 0;
110#endif /* PARANOID */
111	}
112
113	switch (type) {
114	case 000:		/* fld m32real */
115		clear_C1();
116		loaded_tag =
117		    FPU_load_single((float __user *)data_address, &loaded_data);
118		if ((loaded_tag == TAG_Special)
119		    && isNaN(&loaded_data)
120		    && (real_1op_NaN(&loaded_data) < 0)) {
121			top++;
122			break;
123		}
124		FPU_copy_to_reg0(&loaded_data, loaded_tag);
125		break;
126	case 001:		/* fild m32int */
127		clear_C1();
128		loaded_tag =
129		    FPU_load_int32((long __user *)data_address, &loaded_data);
130		FPU_copy_to_reg0(&loaded_data, loaded_tag);
131		break;
132	case 002:		/* fld m64real */
133		clear_C1();
134		loaded_tag =
135		    FPU_load_double((double __user *)data_address,
136				    &loaded_data);
137		if ((loaded_tag == TAG_Special)
138		    && isNaN(&loaded_data)
139		    && (real_1op_NaN(&loaded_data) < 0)) {
140			top++;
141			break;
142		}
143		FPU_copy_to_reg0(&loaded_data, loaded_tag);
144		break;
145	case 003:		/* fild m16int */
146		clear_C1();
147		loaded_tag =
148		    FPU_load_int16((short __user *)data_address, &loaded_data);
149		FPU_copy_to_reg0(&loaded_data, loaded_tag);
150		break;
151	case 010:		/* fst m32real */
152		clear_C1();
153		FPU_store_single(st0_ptr, st0_tag,
154				 (float __user *)data_address);
155		break;
156	case 011:		/* fist m32int */
157		clear_C1();
158		FPU_store_int32(st0_ptr, st0_tag, (long __user *)data_address);
159		break;
160	case 012:		/* fst m64real */
161		clear_C1();
162		FPU_store_double(st0_ptr, st0_tag,
163				 (double __user *)data_address);
164		break;
165	case 013:		/* fist m16int */
166		clear_C1();
167		FPU_store_int16(st0_ptr, st0_tag, (short __user *)data_address);
168		break;
169	case 014:		/* fstp m32real */
170		clear_C1();
171		if (FPU_store_single
172		    (st0_ptr, st0_tag, (float __user *)data_address))
173			pop_0();	/* pop only if the number was actually stored
174					   (see the 80486 manual p16-28) */
175		break;
176	case 015:		/* fistp m32int */
177		clear_C1();
178		if (FPU_store_int32
179		    (st0_ptr, st0_tag, (long __user *)data_address))
180			pop_0();	/* pop only if the number was actually stored
181					   (see the 80486 manual p16-28) */
182		break;
183	case 016:		/* fstp m64real */
184		clear_C1();
185		if (FPU_store_double
186		    (st0_ptr, st0_tag, (double __user *)data_address))
187			pop_0();	/* pop only if the number was actually stored
188					   (see the 80486 manual p16-28) */
189		break;
190	case 017:		/* fistp m16int */
191		clear_C1();
192		if (FPU_store_int16
193		    (st0_ptr, st0_tag, (short __user *)data_address))
194			pop_0();	/* pop only if the number was actually stored
195					   (see the 80486 manual p16-28) */
196		break;
197	case 020:		/* fldenv  m14/28byte */
198		fldenv(addr_modes, (u_char __user *) data_address);
199		/* Ensure that the values just loaded are not changed by
200		   fix-up operations. */
201		return 1;
202	case 022:		/* frstor m94/108byte */
203		frstor(addr_modes, (u_char __user *) data_address);
204		/* Ensure that the values just loaded are not changed by
205		   fix-up operations. */
206		return 1;
207	case 023:		/* fbld m80dec */
208		clear_C1();
209		loaded_tag = FPU_load_bcd((u_char __user *) data_address);
210		FPU_settag0(loaded_tag);
211		break;
212	case 024:		/* fldcw */
213		RE_ENTRANT_CHECK_OFF;
214		FPU_access_ok(VERIFY_READ, data_address, 2);
215		FPU_get_user(control_word,
216			     (unsigned short __user *)data_address);
217		RE_ENTRANT_CHECK_ON;
218		if (partial_status & ~control_word & CW_Exceptions)
219			partial_status |= (SW_Summary | SW_Backward);
220		else
221			partial_status &= ~(SW_Summary | SW_Backward);
222#ifdef PECULIAR_486
223		control_word |= 0x40;	/* An 80486 appears to always set this bit */
224#endif /* PECULIAR_486 */
225		return 1;
226	case 025:		/* fld m80real */
227		clear_C1();
228		loaded_tag =
229		    FPU_load_extended((long double __user *)data_address, 0);
230		FPU_settag0(loaded_tag);
231		break;
232	case 027:		/* fild m64int */
233		clear_C1();
234		loaded_tag = FPU_load_int64((long long __user *)data_address);
235		if (loaded_tag == TAG_Error)
236			return 0;
237		FPU_settag0(loaded_tag);
238		break;
239	case 030:		/* fstenv  m14/28byte */
240		fstenv(addr_modes, (u_char __user *) data_address);
241		return 1;
242	case 032:		/* fsave */
243		fsave(addr_modes, (u_char __user *) data_address);
244		return 1;
245	case 033:		/* fbstp m80dec */
246		clear_C1();
247		if (FPU_store_bcd
248		    (st0_ptr, st0_tag, (u_char __user *) data_address))
249			pop_0();	/* pop only if the number was actually stored
250					   (see the 80486 manual p16-28) */
251		break;
252	case 034:		/* fstcw m16int */
253		RE_ENTRANT_CHECK_OFF;
254		FPU_access_ok(VERIFY_WRITE, data_address, 2);
255		FPU_put_user(control_word,
256			     (unsigned short __user *)data_address);
257		RE_ENTRANT_CHECK_ON;
258		return 1;
259	case 035:		/* fstp m80real */
260		clear_C1();
261		if (FPU_store_extended
262		    (st0_ptr, st0_tag, (long double __user *)data_address))
263			pop_0();	/* pop only if the number was actually stored
264					   (see the 80486 manual p16-28) */
265		break;
266	case 036:		/* fstsw m2byte */
267		RE_ENTRANT_CHECK_OFF;
268		FPU_access_ok(VERIFY_WRITE, data_address, 2);
269		FPU_put_user(status_word(),
270			     (unsigned short __user *)data_address);
271		RE_ENTRANT_CHECK_ON;
272		return 1;
273	case 037:		/* fistp m64int */
274		clear_C1();
275		if (FPU_store_int64
276		    (st0_ptr, st0_tag, (long long __user *)data_address))
277			pop_0();	/* pop only if the number was actually stored
278					   (see the 80486 manual p16-28) */
279		break;
280	}
281	return 0;
282}
283