1 // SPDX-License-Identifier: GPL-2.0
2 /*---------------------------------------------------------------------------+
3 | fpu_entry.c |
4 | |
5 | The entry functions for wm-FPU-emu |
6 | |
7 | Copyright (C) 1992,1993,1994,1996,1997 |
8 | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
9 | E-mail billm@suburbia.net |
10 | |
11 | See the files "README" and "COPYING" for further copyright and warranty |
12 | information. |
13 | |
14 +---------------------------------------------------------------------------*/
15
16 /*---------------------------------------------------------------------------+
17 | Note: |
18 | The file contains code which accesses user memory. |
19 | Emulator static data may change when user memory is accessed, due to |
20 | other processes using the emulator while swapping is in progress. |
21 +---------------------------------------------------------------------------*/
22
23 /*---------------------------------------------------------------------------+
24 | math_emulate(), restore_i387_soft() and save_i387_soft() are the only |
25 | entry points for wm-FPU-emu. |
26 +---------------------------------------------------------------------------*/
27
28 #include <linux/signal.h>
29 #include <linux/regset.h>
30
31 #include <linux/uaccess.h>
32 #include <asm/traps.h>
33 #include <asm/user.h>
34 #include <asm/fpu/api.h>
35
36 #include "fpu_system.h"
37 #include "fpu_emu.h"
38 #include "exception.h"
39 #include "control_w.h"
40 #include "status_w.h"
41
42 #define __BAD__ FPU_illegal /* Illegal on an 80486, causes SIGILL */
43
44 /* fcmovCC and f(u)comi(p) are enabled if CPUID(1).EDX(15) "cmov" is set */
45
46 /* WARNING: "u" entries are not documented by Intel in their 80486 manual
47 and may not work on FPU clones or later Intel FPUs.
48 Changes to support them provided by Linus Torvalds. */
49
50 static FUNC const st_instr_table[64] = {
51 /* Opcode: d8 d9 da db */
52 /* dc dd de df */
53 /* c0..7 */ fadd__, fld_i_, fcmovb, fcmovnb,
54 /* c0..7 */ fadd_i, ffree_, faddp_, ffreep,/*u*/
55 /* c8..f */ fmul__, fxch_i, fcmove, fcmovne,
56 /* c8..f */ fmul_i, fxch_i,/*u*/ fmulp_, fxch_i,/*u*/
57 /* d0..7 */ fcom_st, fp_nop, fcmovbe, fcmovnbe,
58 /* d0..7 */ fcom_st,/*u*/ fst_i_, fcompst,/*u*/ fstp_i,/*u*/
59 /* d8..f */ fcompst, fstp_i,/*u*/ fcmovu, fcmovnu,
60 /* d8..f */ fcompst,/*u*/ fstp_i, fcompp, fstp_i,/*u*/
61 /* e0..7 */ fsub__, FPU_etc, __BAD__, finit_,
62 /* e0..7 */ fsubri, fucom_, fsubrp, fstsw_,
63 /* e8..f */ fsubr_, fconst, fucompp, fucomi_,
64 /* e8..f */ fsub_i, fucomp, fsubp_, fucomip,
65 /* f0..7 */ fdiv__, FPU_triga, __BAD__, fcomi_,
66 /* f0..7 */ fdivri, __BAD__, fdivrp, fcomip,
67 /* f8..f */ fdivr_, FPU_trigb, __BAD__, __BAD__,
68 /* f8..f */ fdiv_i, __BAD__, fdivp_, __BAD__,
69 };
70
71 #define _NONE_ 0 /* Take no special action */
72 #define _REG0_ 1 /* Need to check for not empty st(0) */
73 #define _REGI_ 2 /* Need to check for not empty st(0) and st(rm) */
74 #define _REGi_ 0 /* Uses st(rm) */
75 #define _PUSH_ 3 /* Need to check for space to push onto stack */
76 #define _null_ 4 /* Function illegal or not implemented */
77 #define _REGIi 5 /* Uses st(0) and st(rm), result to st(rm) */
78 #define _REGIp 6 /* Uses st(0) and st(rm), result to st(rm) then pop */
79 #define _REGIc 0 /* Compare st(0) and st(rm) */
80 #define _REGIn 0 /* Uses st(0) and st(rm), but handle checks later */
81
82 static u_char const type_table[64] = {
83 /* Opcode: d8 d9 da db dc dd de df */
84 /* c0..7 */ _REGI_, _NONE_, _REGIn, _REGIn, _REGIi, _REGi_, _REGIp, _REGi_,
85 /* c8..f */ _REGI_, _REGIn, _REGIn, _REGIn, _REGIi, _REGI_, _REGIp, _REGI_,
86 /* d0..7 */ _REGIc, _NONE_, _REGIn, _REGIn, _REGIc, _REG0_, _REGIc, _REG0_,
87 /* d8..f */ _REGIc, _REG0_, _REGIn, _REGIn, _REGIc, _REG0_, _REGIc, _REG0_,
88 /* e0..7 */ _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
89 /* e8..f */ _REGI_, _NONE_, _REGIc, _REGIc, _REGIi, _REGIc, _REGIp, _REGIc,
90 /* f0..7 */ _REGI_, _NONE_, _null_, _REGIc, _REGIi, _null_, _REGIp, _REGIc,
91 /* f8..f */ _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
92 };
93
94 #ifdef RE_ENTRANT_CHECKING
95 u_char emulating = 0;
96 #endif /* RE_ENTRANT_CHECKING */
97
98 static int valid_prefix(u_char *Byte, u_char __user ** fpu_eip,
99 overrides * override);
100
math_emulate(struct math_emu_info * info)101 void math_emulate(struct math_emu_info *info)
102 {
103 u_char FPU_modrm, byte1;
104 unsigned short code;
105 fpu_addr_modes addr_modes;
106 int unmasked;
107 FPU_REG loaded_data;
108 FPU_REG *st0_ptr;
109 u_char loaded_tag, st0_tag;
110 void __user *data_address;
111 struct address data_sel_off;
112 struct address entry_sel_off;
113 unsigned long code_base = 0;
114 unsigned long code_limit = 0; /* Initialized to stop compiler warnings */
115 struct desc_struct code_descriptor;
116
117 #ifdef RE_ENTRANT_CHECKING
118 if (emulating) {
119 printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
120 }
121 RE_ENTRANT_CHECK_ON;
122 #endif /* RE_ENTRANT_CHECKING */
123
124 FPU_info = info;
125
126 FPU_ORIG_EIP = FPU_EIP;
127
128 if ((FPU_EFLAGS & 0x00020000) != 0) {
129 /* Virtual 8086 mode */
130 addr_modes.default_mode = VM86;
131 FPU_EIP += code_base = FPU_CS << 4;
132 code_limit = code_base + 0xffff; /* Assumes code_base <= 0xffff0000 */
133 } else if (FPU_CS == __USER_CS && FPU_DS == __USER_DS) {
134 addr_modes.default_mode = 0;
135 } else if (FPU_CS == __KERNEL_CS) {
136 printk("math_emulate: %04x:%08lx\n", FPU_CS, FPU_EIP);
137 panic("Math emulation needed in kernel");
138 } else {
139
140 if ((FPU_CS & 4) != 4) { /* Must be in the LDT */
141 /* Can only handle segmented addressing via the LDT
142 for now, and it must be 16 bit */
143 printk("FPU emulator: Unsupported addressing mode\n");
144 math_abort(FPU_info, SIGILL);
145 }
146
147 code_descriptor = FPU_get_ldt_descriptor(FPU_CS);
148 if (code_descriptor.d) {
149 /* The above test may be wrong, the book is not clear */
150 /* Segmented 32 bit protected mode */
151 addr_modes.default_mode = SEG32;
152 } else {
153 /* 16 bit protected mode */
154 addr_modes.default_mode = PM16;
155 }
156 FPU_EIP += code_base = seg_get_base(&code_descriptor);
157 code_limit = seg_get_limit(&code_descriptor) + 1;
158 code_limit *= seg_get_granularity(&code_descriptor);
159 code_limit += code_base - 1;
160 if (code_limit < code_base)
161 code_limit = 0xffffffff;
162 }
163
164 FPU_lookahead = !(FPU_EFLAGS & X86_EFLAGS_TF);
165
166 if (!valid_prefix(&byte1, (u_char __user **) & FPU_EIP,
167 &addr_modes.override)) {
168 RE_ENTRANT_CHECK_OFF;
169 printk
170 ("FPU emulator: Unknown prefix byte 0x%02x, probably due to\n"
171 "FPU emulator: self-modifying code! (emulation impossible)\n",
172 byte1);
173 RE_ENTRANT_CHECK_ON;
174 EXCEPTION(EX_INTERNAL | 0x126);
175 math_abort(FPU_info, SIGILL);
176 }
177
178 do_another_FPU_instruction:
179
180 no_ip_update = 0;
181
182 FPU_EIP++; /* We have fetched the prefix and first code bytes. */
183
184 if (addr_modes.default_mode) {
185 /* This checks for the minimum instruction bytes.
186 We also need to check any extra (address mode) code access. */
187 if (FPU_EIP > code_limit)
188 math_abort(FPU_info, SIGSEGV);
189 }
190
191 if ((byte1 & 0xf8) != 0xd8) {
192 if (byte1 == FWAIT_OPCODE) {
193 if (partial_status & SW_Summary)
194 goto do_the_FPU_interrupt;
195 else
196 goto FPU_fwait_done;
197 }
198 #ifdef PARANOID
199 EXCEPTION(EX_INTERNAL | 0x128);
200 math_abort(FPU_info, SIGILL);
201 #endif /* PARANOID */
202 }
203
204 RE_ENTRANT_CHECK_OFF;
205 FPU_code_access_ok(1);
206 FPU_get_user(FPU_modrm, (u_char __user *) FPU_EIP);
207 RE_ENTRANT_CHECK_ON;
208 FPU_EIP++;
209
210 if (partial_status & SW_Summary) {
211 /* Ignore the error for now if the current instruction is a no-wait
212 control instruction */
213 /* The 80486 manual contradicts itself on this topic,
214 but a real 80486 uses the following instructions:
215 fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex.
216 */
217 code = (FPU_modrm << 8) | byte1;
218 if (!((((code & 0xf803) == 0xe003) || /* fnclex, fninit, fnstsw */
219 (((code & 0x3003) == 0x3001) && /* fnsave, fnstcw, fnstenv,
220 fnstsw */
221 ((code & 0xc000) != 0xc000))))) {
222 /*
223 * We need to simulate the action of the kernel to FPU
224 * interrupts here.
225 */
226 do_the_FPU_interrupt:
227
228 FPU_EIP = FPU_ORIG_EIP; /* Point to current FPU instruction. */
229
230 RE_ENTRANT_CHECK_OFF;
231 current->thread.trap_nr = X86_TRAP_MF;
232 current->thread.error_code = 0;
233 send_sig(SIGFPE, current, 1);
234 return;
235 }
236 }
237
238 entry_sel_off.offset = FPU_ORIG_EIP;
239 entry_sel_off.selector = FPU_CS;
240 entry_sel_off.opcode = (byte1 << 8) | FPU_modrm;
241 entry_sel_off.empty = 0;
242
243 FPU_rm = FPU_modrm & 7;
244
245 if (FPU_modrm < 0300) {
246 /* All of these instructions use the mod/rm byte to get a data address */
247
248 if ((addr_modes.default_mode & SIXTEEN)
249 ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX))
250 data_address =
251 FPU_get_address_16(FPU_modrm, &FPU_EIP,
252 &data_sel_off, addr_modes);
253 else
254 data_address =
255 FPU_get_address(FPU_modrm, &FPU_EIP, &data_sel_off,
256 addr_modes);
257
258 if (addr_modes.default_mode) {
259 if (FPU_EIP - 1 > code_limit)
260 math_abort(FPU_info, SIGSEGV);
261 }
262
263 if (!(byte1 & 1)) {
264 unsigned short status1 = partial_status;
265
266 st0_ptr = &st(0);
267 st0_tag = FPU_gettag0();
268
269 /* Stack underflow has priority */
270 if (NOT_EMPTY_ST0) {
271 if (addr_modes.default_mode & PROTECTED) {
272 /* This table works for 16 and 32 bit protected mode */
273 if (access_limit <
274 data_sizes_16[(byte1 >> 1) & 3])
275 math_abort(FPU_info, SIGSEGV);
276 }
277
278 unmasked = 0; /* Do this here to stop compiler warnings. */
279 switch ((byte1 >> 1) & 3) {
280 case 0:
281 unmasked =
282 FPU_load_single((float __user *)
283 data_address,
284 &loaded_data);
285 loaded_tag = unmasked & 0xff;
286 unmasked &= ~0xff;
287 break;
288 case 1:
289 loaded_tag =
290 FPU_load_int32((long __user *)
291 data_address,
292 &loaded_data);
293 break;
294 case 2:
295 unmasked =
296 FPU_load_double((double __user *)
297 data_address,
298 &loaded_data);
299 loaded_tag = unmasked & 0xff;
300 unmasked &= ~0xff;
301 break;
302 case 3:
303 default: /* Used here to suppress gcc warnings. */
304 loaded_tag =
305 FPU_load_int16((short __user *)
306 data_address,
307 &loaded_data);
308 break;
309 }
310
311 /* No more access to user memory, it is safe
312 to use static data now */
313
314 /* NaN operands have the next priority. */
315 /* We have to delay looking at st(0) until after
316 loading the data, because that data might contain an SNaN */
317 if (((st0_tag == TAG_Special) && isNaN(st0_ptr))
318 || ((loaded_tag == TAG_Special)
319 && isNaN(&loaded_data))) {
320 /* Restore the status word; we might have loaded a
321 denormal. */
322 partial_status = status1;
323 if ((FPU_modrm & 0x30) == 0x10) {
324 /* fcom or fcomp */
325 EXCEPTION(EX_Invalid);
326 setcc(SW_C3 | SW_C2 | SW_C0);
327 if ((FPU_modrm & 0x08)
328 && (control_word &
329 CW_Invalid))
330 FPU_pop(); /* fcomp, masked, so we pop. */
331 } else {
332 if (loaded_tag == TAG_Special)
333 loaded_tag =
334 FPU_Special
335 (&loaded_data);
336 #ifdef PECULIAR_486
337 /* This is not really needed, but gives behaviour
338 identical to an 80486 */
339 if ((FPU_modrm & 0x28) == 0x20)
340 /* fdiv or fsub */
341 real_2op_NaN
342 (&loaded_data,
343 loaded_tag, 0,
344 &loaded_data);
345 else
346 #endif /* PECULIAR_486 */
347 /* fadd, fdivr, fmul, or fsubr */
348 real_2op_NaN
349 (&loaded_data,
350 loaded_tag, 0,
351 st0_ptr);
352 }
353 goto reg_mem_instr_done;
354 }
355
356 if (unmasked && !((FPU_modrm & 0x30) == 0x10)) {
357 /* Is not a comparison instruction. */
358 if ((FPU_modrm & 0x38) == 0x38) {
359 /* fdivr */
360 if ((st0_tag == TAG_Zero) &&
361 ((loaded_tag == TAG_Valid)
362 || (loaded_tag ==
363 TAG_Special
364 &&
365 isdenormal
366 (&loaded_data)))) {
367 if (FPU_divide_by_zero
368 (0,
369 getsign
370 (&loaded_data))
371 < 0) {
372 /* We use the fact here that the unmasked
373 exception in the loaded data was for a
374 denormal operand */
375 /* Restore the state of the denormal op bit */
376 partial_status
377 &=
378 ~SW_Denorm_Op;
379 partial_status
380 |=
381 status1 &
382 SW_Denorm_Op;
383 } else
384 setsign(st0_ptr,
385 getsign
386 (&loaded_data));
387 }
388 }
389 goto reg_mem_instr_done;
390 }
391
392 switch ((FPU_modrm >> 3) & 7) {
393 case 0: /* fadd */
394 clear_C1();
395 FPU_add(&loaded_data, loaded_tag, 0,
396 control_word);
397 break;
398 case 1: /* fmul */
399 clear_C1();
400 FPU_mul(&loaded_data, loaded_tag, 0,
401 control_word);
402 break;
403 case 2: /* fcom */
404 FPU_compare_st_data(&loaded_data,
405 loaded_tag);
406 break;
407 case 3: /* fcomp */
408 if (!FPU_compare_st_data
409 (&loaded_data, loaded_tag)
410 && !unmasked)
411 FPU_pop();
412 break;
413 case 4: /* fsub */
414 clear_C1();
415 FPU_sub(LOADED | loaded_tag,
416 (int)&loaded_data,
417 control_word);
418 break;
419 case 5: /* fsubr */
420 clear_C1();
421 FPU_sub(REV | LOADED | loaded_tag,
422 (int)&loaded_data,
423 control_word);
424 break;
425 case 6: /* fdiv */
426 clear_C1();
427 FPU_div(LOADED | loaded_tag,
428 (int)&loaded_data,
429 control_word);
430 break;
431 case 7: /* fdivr */
432 clear_C1();
433 if (st0_tag == TAG_Zero)
434 partial_status = status1; /* Undo any denorm tag,
435 zero-divide has priority. */
436 FPU_div(REV | LOADED | loaded_tag,
437 (int)&loaded_data,
438 control_word);
439 break;
440 }
441 } else {
442 if ((FPU_modrm & 0x30) == 0x10) {
443 /* The instruction is fcom or fcomp */
444 EXCEPTION(EX_StackUnder);
445 setcc(SW_C3 | SW_C2 | SW_C0);
446 if ((FPU_modrm & 0x08)
447 && (control_word & CW_Invalid))
448 FPU_pop(); /* fcomp */
449 } else
450 FPU_stack_underflow();
451 }
452 reg_mem_instr_done:
453 operand_address = data_sel_off;
454 } else {
455 if (!(no_ip_update =
456 FPU_load_store(((FPU_modrm & 0x38) | (byte1 & 6))
457 >> 1, addr_modes, data_address))) {
458 operand_address = data_sel_off;
459 }
460 }
461
462 } else {
463 /* None of these instructions access user memory */
464 u_char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
465
466 #ifdef PECULIAR_486
467 /* This is supposed to be undefined, but a real 80486 seems
468 to do this: */
469 operand_address.offset = 0;
470 operand_address.selector = FPU_DS;
471 #endif /* PECULIAR_486 */
472
473 st0_ptr = &st(0);
474 st0_tag = FPU_gettag0();
475 switch (type_table[(int)instr_index]) {
476 case _NONE_: /* also _REGIc: _REGIn */
477 break;
478 case _REG0_:
479 if (!NOT_EMPTY_ST0) {
480 FPU_stack_underflow();
481 goto FPU_instruction_done;
482 }
483 break;
484 case _REGIi:
485 if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) {
486 FPU_stack_underflow_i(FPU_rm);
487 goto FPU_instruction_done;
488 }
489 break;
490 case _REGIp:
491 if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) {
492 FPU_stack_underflow_pop(FPU_rm);
493 goto FPU_instruction_done;
494 }
495 break;
496 case _REGI_:
497 if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) {
498 FPU_stack_underflow();
499 goto FPU_instruction_done;
500 }
501 break;
502 case _PUSH_: /* Only used by the fld st(i) instruction */
503 break;
504 case _null_:
505 FPU_illegal();
506 goto FPU_instruction_done;
507 default:
508 EXCEPTION(EX_INTERNAL | 0x111);
509 goto FPU_instruction_done;
510 }
511 (*st_instr_table[(int)instr_index]) ();
512
513 FPU_instruction_done:
514 ;
515 }
516
517 if (!no_ip_update)
518 instruction_address = entry_sel_off;
519
520 FPU_fwait_done:
521
522 #ifdef DEBUG
523 RE_ENTRANT_CHECK_OFF;
524 FPU_printall();
525 RE_ENTRANT_CHECK_ON;
526 #endif /* DEBUG */
527
528 if (FPU_lookahead && !need_resched()) {
529 FPU_ORIG_EIP = FPU_EIP - code_base;
530 if (valid_prefix(&byte1, (u_char __user **) & FPU_EIP,
531 &addr_modes.override))
532 goto do_another_FPU_instruction;
533 }
534
535 if (addr_modes.default_mode)
536 FPU_EIP -= code_base;
537
538 RE_ENTRANT_CHECK_OFF;
539 }
540
541 /* Support for prefix bytes is not yet complete. To properly handle
542 all prefix bytes, further changes are needed in the emulator code
543 which accesses user address space. Access to separate segments is
544 important for msdos emulation. */
valid_prefix(u_char * Byte,u_char __user ** fpu_eip,overrides * override)545 static int valid_prefix(u_char *Byte, u_char __user **fpu_eip,
546 overrides * override)
547 {
548 u_char byte;
549 u_char __user *ip = *fpu_eip;
550
551 *override = (overrides) {
552 0, 0, PREFIX_DEFAULT}; /* defaults */
553
554 RE_ENTRANT_CHECK_OFF;
555 FPU_code_access_ok(1);
556 FPU_get_user(byte, ip);
557 RE_ENTRANT_CHECK_ON;
558
559 while (1) {
560 switch (byte) {
561 case ADDR_SIZE_PREFIX:
562 override->address_size = ADDR_SIZE_PREFIX;
563 goto do_next_byte;
564
565 case OP_SIZE_PREFIX:
566 override->operand_size = OP_SIZE_PREFIX;
567 goto do_next_byte;
568
569 case PREFIX_CS:
570 override->segment = PREFIX_CS_;
571 goto do_next_byte;
572 case PREFIX_ES:
573 override->segment = PREFIX_ES_;
574 goto do_next_byte;
575 case PREFIX_SS:
576 override->segment = PREFIX_SS_;
577 goto do_next_byte;
578 case PREFIX_FS:
579 override->segment = PREFIX_FS_;
580 goto do_next_byte;
581 case PREFIX_GS:
582 override->segment = PREFIX_GS_;
583 goto do_next_byte;
584 case PREFIX_DS:
585 override->segment = PREFIX_DS_;
586 goto do_next_byte;
587
588 /* lock is not a valid prefix for FPU instructions,
589 let the cpu handle it to generate a SIGILL. */
590 /* case PREFIX_LOCK: */
591
592 /* rep.. prefixes have no meaning for FPU instructions */
593 case PREFIX_REPE:
594 case PREFIX_REPNE:
595
596 do_next_byte:
597 ip++;
598 RE_ENTRANT_CHECK_OFF;
599 FPU_code_access_ok(1);
600 FPU_get_user(byte, ip);
601 RE_ENTRANT_CHECK_ON;
602 break;
603 case FWAIT_OPCODE:
604 *Byte = byte;
605 return 1;
606 default:
607 if ((byte & 0xf8) == 0xd8) {
608 *Byte = byte;
609 *fpu_eip = ip;
610 return 1;
611 } else {
612 /* Not a valid sequence of prefix bytes followed by
613 an FPU instruction. */
614 *Byte = byte; /* Needed for error message. */
615 return 0;
616 }
617 }
618 }
619 }
620
math_abort(struct math_emu_info * info,unsigned int signal)621 void math_abort(struct math_emu_info *info, unsigned int signal)
622 {
623 FPU_EIP = FPU_ORIG_EIP;
624 current->thread.trap_nr = X86_TRAP_MF;
625 current->thread.error_code = 0;
626 send_sig(signal, current, 1);
627 RE_ENTRANT_CHECK_OFF;
628 __asm__("movl %0,%%esp ; ret": :"g"(((long)info) - 4));
629 #ifdef PARANOID
630 printk("ERROR: wm-FPU-emu math_abort failed!\n");
631 #endif /* PARANOID */
632 }
633
634 #define S387 ((struct swregs_state *)s387)
635 #define sstatus_word() \
636 ((S387->swd & ~SW_Top & 0xffff) | ((S387->ftop << SW_Top_Shift) & SW_Top))
637
fpregs_soft_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)638 int fpregs_soft_set(struct task_struct *target,
639 const struct user_regset *regset,
640 unsigned int pos, unsigned int count,
641 const void *kbuf, const void __user *ubuf)
642 {
643 struct swregs_state *s387 = &target->thread.fpu.fpstate->regs.soft;
644 void *space = s387->st_space;
645 int ret;
646 int offset, other, i, tags, regnr, tag, newtop;
647
648 RE_ENTRANT_CHECK_OFF;
649 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, s387, 0,
650 offsetof(struct swregs_state, st_space));
651 RE_ENTRANT_CHECK_ON;
652
653 if (ret)
654 return ret;
655
656 S387->ftop = (S387->swd >> SW_Top_Shift) & 7;
657 offset = (S387->ftop & 7) * 10;
658 other = 80 - offset;
659
660 RE_ENTRANT_CHECK_OFF;
661
662 /* Copy all registers in stack order. */
663 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
664 space + offset, 0, other);
665 if (!ret && offset)
666 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
667 space, 0, offset);
668
669 RE_ENTRANT_CHECK_ON;
670
671 /* The tags may need to be corrected now. */
672 tags = S387->twd;
673 newtop = S387->ftop;
674 for (i = 0; i < 8; i++) {
675 regnr = (i + newtop) & 7;
676 if (((tags >> ((regnr & 7) * 2)) & 3) != TAG_Empty) {
677 /* The loaded data over-rides all other cases. */
678 tag =
679 FPU_tagof((FPU_REG *) ((u_char *) S387->st_space +
680 10 * regnr));
681 tags &= ~(3 << (regnr * 2));
682 tags |= (tag & 3) << (regnr * 2);
683 }
684 }
685 S387->twd = tags;
686
687 return ret;
688 }
689
fpregs_soft_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)690 int fpregs_soft_get(struct task_struct *target,
691 const struct user_regset *regset,
692 struct membuf to)
693 {
694 struct swregs_state *s387 = &target->thread.fpu.fpstate->regs.soft;
695 const void *space = s387->st_space;
696 int offset = (S387->ftop & 7) * 10, other = 80 - offset;
697
698 RE_ENTRANT_CHECK_OFF;
699
700 #ifdef PECULIAR_486
701 S387->cwd &= ~0xe080;
702 /* An 80486 sets nearly all of the reserved bits to 1. */
703 S387->cwd |= 0xffff0040;
704 S387->swd = sstatus_word() | 0xffff0000;
705 S387->twd |= 0xffff0000;
706 S387->fcs &= ~0xf8000000;
707 S387->fos |= 0xffff0000;
708 #endif /* PECULIAR_486 */
709
710 membuf_write(&to, s387, offsetof(struct swregs_state, st_space));
711 membuf_write(&to, space + offset, other);
712 membuf_write(&to, space, offset);
713
714 RE_ENTRANT_CHECK_ON;
715
716 return 0;
717 }
718