Skip to content

Commit 9504366

Browse files
committed
simx86: handle FPU SIGILL properly
When an undefined FPU instruction was encountered, we got TheCPU.err=-96 and a fatal exit. Moreover, this meant Close() could return NULL, which is not always checked. Handle this properly by checking in advance for illegal FPU instructions.
1 parent 8219e84 commit 9504366

File tree

7 files changed

+130
-28
lines changed

7 files changed

+130
-28
lines changed

src/base/emu-i386/simx86/codegen-sim.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -477,10 +477,7 @@ static unsigned int Gen_sim(const IGen *IG, dosaddr_t mem_ref)
477477
unsigned char exop = (unsigned char)IG->p0;
478478
int reg = IG->p1;
479479
GTRACE2("O_FPOP",exop,reg);
480-
if (Fp87_op(exop, reg, mem_ref)) {
481-
TheCPU.err2 = -96;
482-
P0 = FindPC((const unsigned char *)IG);
483-
}
480+
Fp87_op(exop, reg, mem_ref);
484481
int exs = TheCPU.fpus & 0x7f;
485482
if (debug_level('e')>3) {
486483
e_printf(" %s\n", e_trace_fp());

src/base/emu-i386/simx86/codegen-x86.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -327,12 +327,8 @@ static unsigned char *CodeGen_x86(unsigned char *CodePtr, unsigned char *BaseGen
327327
// andl $0x3f,%%eax
328328
G3(0x3fe083,Cp);
329329
break;
330-
case O_FOP: {
331-
unsigned char *p = Fp87_op_x86(CodePtr, IG->p0, IG->p1);
332-
if (p == NULL)
333-
TheCPU.err = -96;
334-
else Cp = p;
335-
}
330+
case O_FOP:
331+
Cp = Fp87_op_x86(Cp, IG->p0, IG->p1);
336332
break;
337333

338334
case L_REG: {

src/base/emu-i386/simx86/codegen.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -537,9 +537,6 @@ TNode *Close(unsigned int PC, unsigned int Interp_LONG_CS, int mode)
537537
}
538538

539539
GenCodeBuf = ProduceCode(PC, I0);
540-
/* check for fatal error */
541-
if (TheCPU.err < 0)
542-
return NULL;
543540

544541
NodesParsed++;
545542
#if PROFILE

src/base/emu-i386/simx86/codegen.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,8 @@ int NewIMeta(int npc, int *rc);
269269
extern int CurrIMeta;
270270
extern void Gen(int op, int mode, ...);
271271
extern void AddrGen(int op, int mode, ...);
272-
extern int (*Fp87_op)(int exop, int reg, unsigned mem_ref);
272+
extern void (*Fp87_op)(int exop, int reg, unsigned mem_ref);
273+
extern int Fp87_illegal_op(int exop, int reg);
273274
TNode *Close(unsigned int PC, unsigned int Interp_LONGCS, int mode);
274275
extern unsigned char * (*CodeGen)(unsigned char *CodePtr,
275276
unsigned char *BaseGenBuf, const IGen *IG);

src/base/emu-i386/simx86/fp87-sim.c

Lines changed: 113 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include <math.h>
3838
#include "dos2linux.h"
3939
#include "emu86.h"
40+
#include "utilities.h"
4041
#include "codegen.h"
4142
#include "codegen-sim.h"
4243
#ifndef HAVE___FLOAT80
@@ -74,8 +75,8 @@
7475
#define M_LOG2El 1.442695040888963407359924681001892137L
7576
#endif
7677

77-
int (*Fp87_op)(int exop, int reg, unsigned mem_ref);
78-
static int Fp87_op_sim(int exop, int reg, unsigned mem_ref);
78+
void (*Fp87_op)(int exop, int reg, unsigned mem_ref);
79+
static void Fp87_op_sim(int exop, int reg, unsigned mem_ref);
7980

8081
static long double WFR0, WFR1;
8182

@@ -256,7 +257,7 @@ static void write_long_double(dosaddr_t addr, long double ld)
256257
sim_write_word(addr+8, x.u32[2]);
257258
}
258259

259-
static int Fp87_op_sim(int exop, int reg, unsigned mem_ref)
260+
static void Fp87_op_sim(int exop, int reg, unsigned mem_ref)
260261
{
261262
// 42 DA 11000nnn FCMOVB st(0),st(n)
262263
// 43 DB 11000nnn FCMOVNB st(0),st(n)
@@ -1176,9 +1177,116 @@ fcom00: TheCPU.fpus &= ~(FPUS_C0 | FPUS_C2 | FPUS_C3);
11761177

11771178
/*xx*/ default:
11781179
fp_notok:
1179-
return -1;
1180+
// should be caught by Fp87_illegal_op
1181+
dosemu_error("Unknown FPop %x.%d\n", exop, reg);
11801182
}
11811183
fp_ok:
1182-
return 0;
11831184
}
11841185

1186+
int Fp87_illegal_op(int exop, int reg)
1187+
{
1188+
e_printf("FPop %x.%d\n", exop, reg);
1189+
1190+
switch(exop) {
1191+
// 09 D9 xx001nnn undefined
1192+
/*09*/ case 0x09:
1193+
1194+
// 0B DB xx001nnn FISTTP dw // SSE3 capable CPUs
1195+
// 0D DD xx001nnn FISTTP qw // SSE3 capable CPUs
1196+
// 0F DF xx001nnn FISTTP w // SSE3 capable CPUs
1197+
case 0x0b: case 0x0d: case 0x0f:
1198+
1199+
// 23 DB xx100nnn undefined
1200+
// 2D DD xx101nnn undefined
1201+
// 33 DB xx110nnn undefined
1202+
case 0x23: case 0x2d: case 0x33:
1203+
1204+
// 42 DA 11000nnn FCMOVB st(0),st(n) (CPUID)
1205+
// 43 DB 11000nnn FCMOVNB st(0),st(n) (CPUID)
1206+
// 4A DA 11001nnn FCMOVE st(0),st(n) (CPUID)
1207+
// 4B DB 11001nnn FCMOVNE st(0),st(n) (CPUID)
1208+
case 0x42: case 0x43: case 0x4a: case 0x4b:
1209+
break;
1210+
1211+
// 51 D9 11010nnn 51.0=FNOP, others undefined
1212+
/*51*/ case 0x51:
1213+
if (reg==0) goto fp_ok;
1214+
break;
1215+
1216+
// 52 DA 11010nnn FCMOVBE st(0),st(n) (CPUID)
1217+
// 53 DB 11010nnn FCMOVNBE st(0),st(n) (CPUID)
1218+
// 5A DA 11011nnn FCMOVU st(0),st(n) (CPUID)
1219+
// 5B DB 11011nnn FCMOVNU st(0),st(n) (CPUID)
1220+
case 0x52: case 0x53: case 0x5a: case 0x5b:
1221+
break;
1222+
1223+
// 5E DE 11011nnn 5E.1 = FCOMPP, others undefined
1224+
if (reg==1) goto fp_ok;
1225+
break;
1226+
1227+
case 0x5e:
1228+
1229+
// 61 D9 11100nnn 0,1,4,5 valid, others undefined
1230+
case 0x61:
1231+
switch(reg) {
1232+
case 0: /* FCHS */
1233+
case 1: /* FABS */
1234+
case 4: /* FTST */
1235+
case 5: /* FXAM */
1236+
goto fp_ok;
1237+
default:
1238+
break;
1239+
}
1240+
break;
1241+
1242+
// 62 DA 11100nnn invalid
1243+
case 0x62:
1244+
1245+
// 63 DB 11000nnn 63.5, 63.6, 63.7 are invalid
1246+
/*63*/ case 0x63:
1247+
if (reg < 5) goto fp_ok;
1248+
break;
1249+
1250+
// 67 DF 11100nnn 67.0=FNSTSW AX, others undefined
1251+
case 0x67:
1252+
if (reg==0) goto fp_ok;
1253+
break;
1254+
1255+
// 69 D9 11101nnn <7 defined, 7 invalid
1256+
case 0x69:
1257+
if (reg!=7) goto fp_ok;
1258+
break;
1259+
1260+
// 6A DA 11101nnn 6A.1=FUCOMPP, others undefined
1261+
case 0x6a:
1262+
if (reg==1) goto fp_ok;
1263+
break;
1264+
1265+
// 6B DB 11101nnn FUCOMI (CPUID)
1266+
// 6F DF 11101nnn FUCOMIP (CPUID)
1267+
case 0x6b: case 0x6f:
1268+
1269+
// 72 DA 11110nnn undefined
1270+
/*72*/ case 0x72:
1271+
1272+
// 73 DB 11110nnn FCOMI (CPUID)
1273+
/*73*/ case 0x73:
1274+
1275+
// 75 DD 11110nnn undefined
1276+
/*75*/ case 0x75:
1277+
1278+
// 77 DF 11110nnn FCOMIP (CPUID)
1279+
/*77*/ case 0x77:
1280+
1281+
// 7A DA 11111nnn undefined
1282+
// 7B DB 11111nnn undefined
1283+
// 7D DD 11111nnn undefined
1284+
// 7F DF 11111nnn undefined
1285+
case 0x7a: case 0x7b: case 0x7d: case 0x7f:
1286+
break;
1287+
1288+
default:
1289+
fp_ok: return 0;
1290+
}
1291+
return 1;
1292+
}

src/base/emu-i386/simx86/fp87-x86.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@
3636
#include "emu86.h"
3737

3838
#include "codegen-x86.h"
39+
#include "utilities.h"
3940

40-
static int Fp87_op_x86_sim(int exop, int reg, unsigned mem_ref);
41+
static void Fp87_op_x86_sim(int exop, int reg, unsigned mem_ref);
4142

4243
/*
4344
* Only mask bits 0-5 of the control word (fpuc),
@@ -450,13 +451,14 @@ unsigned char *Fp87_op_x86(unsigned char *CodePtr, int exop, int reg)
450451

451452
/*xx*/ default:
452453
fp_notok:
453-
return NULL;
454+
// should be caught by Fp87_illegal_op
455+
dosemu_error("Unknown FPop %x.%d\n", exop, reg);
454456
}
455457
fp_ok:
456458
return Cp;
457459
}
458460

459-
static int Fp87_op_x86_sim(int exop, int reg, unsigned mem_ref)
461+
static void Fp87_op_x86_sim(int exop, int reg, unsigned mem_ref)
460462
{
461463
e_printf("FPop %x.%d\n", exop, reg);
462464
if (TheCPU.fpstate) {
@@ -569,7 +571,7 @@ static int Fp87_op_x86_sim(int exop, int reg, unsigned mem_ref)
569571
break;
570572

571573
/*xx*/ default:
572-
return -1;
574+
// should be caught by Fp87_illegal_op
575+
dosemu_error("Unknown FPop %x.%d\n", exop, reg);
573576
}
574-
return 0;
575577
}

src/base/emu-i386/simx86/interp.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2831,11 +2831,12 @@ intop3b: { int op = ArOpsFR[D_MO(opc)];
28312831
}
28322832
}
28332833
b &= 7;
2834+
if (Fp87_illegal_op(exop, b)) {
2835+
CODE_FLUSH();
2836+
goto illegal_op;
2837+
}
28342838
if (sim) {
2835-
if (Fp87_op(exop,b,TheCPU.mem_ref)) {
2836-
TheCPU.err = -96;
2837-
return P0;
2838-
}
2839+
Fp87_op(exop,b,TheCPU.mem_ref);
28392840
}
28402841
else
28412842
Gen(O_FOP, _mode, exop, b);

0 commit comments

Comments
 (0)