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