PageRenderTime 32ms CodeModel.GetById 18ms app.highlight 11ms RepoModel.GetById 0ms app.codeStats 0ms

/arch/x86/math-emu/load_store.c

https://bitbucket.org/thekraven/iscream_thunderc-2.6.35
C | 282 lines | 239 code | 13 blank | 30 comment | 30 complexity | 5355308d0a5d1853edcbca5405ac83b2 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
  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}