Implement special selector pushing behavior and improve the opcode length heuristic for CS limit checks, fixes #4552.

This commit is contained in:
OBattler
2024-06-23 02:28:22 +02:00
parent 499a4e1d77
commit bbe035b62a
4 changed files with 62 additions and 12 deletions

View File

@@ -212,11 +212,11 @@ fetch_ea_16_long(uint32_t rmdat)
#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c)
#define CHECK_READ_CS(size) \
if ((cpu_state.pc < cpu_state.seg_cs.limit_low) || \
((cpu_state.pc + size - 1) > cpu_state.seg_cs.limit_high)) \
x86gpf("Limit check (READ)", 0); \
if (msw & 1 && !(cpu_state.eflags & VM_FLAG) && !(cpu_state.seg_cs.access & 0x80)) \
x86np("Read from seg not present", cpu_state.seg_cs.seg & 0xfffc); \
else if ((cpu_state.pc < cpu_state.seg_cs.limit_low) || \
((cpu_state.pc + size - 1) > cpu_state.seg_cs.limit_high)) \
x86gpf("Limit check (READ CS)", 0);
#include "386_ops.h"
@@ -261,7 +261,13 @@ exec386_2386(int32_t cycs)
fetchdat = fastreadl_fetch(cs + cpu_state.pc);
ol = opcode_length[fetchdat & 0xff];
CHECK_READ_CS(MIN(ol, 4));
if ((ol == 3) && opcode_has_modrm[fetchdat & 0xff] && (((fetchdat >> 14) & 0x03) == 0x03))
ol = 2;
if (cpu_16bitbus) {
CHECK_READ_CS(MIN(ol, 2));
} else {
CHECK_READ_CS(MIN(ol, 4));
}
ins_fetch_fault = cpu_386_check_instruction_fault();
/* Breakpoint fault has priority over other faults. */

View File

@@ -106,6 +106,28 @@ uint32_t backupregs[16];
x86seg _oldds;
int opcode_has_modrm[256] = {
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*00*/
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*10*/
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*20*/
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*30*/
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*40*/
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/
0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, /*60*/
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*70*/
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*80*/
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*90*/
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*a0*/
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*b0*/
1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*d0*/
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*e0*/
0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, /*f0*/
};
int opcode_length[256] = { 3, 3, 3, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 1, 3, /* 0x0x */
3, 3, 3, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, /* 0x1x */
3, 3, 3, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, /* 0x2x */

View File

@@ -449,6 +449,7 @@ get_ram_ptr(uint32_t a)
}
}
extern int opcode_has_modrm[256];
extern int opcode_length[256];
#ifdef OPS_286_386

View File

@@ -798,6 +798,27 @@ PUSHL(uint32_t v)
}
}
static void
PUSHL_SEL(uint32_t v)
{
if (cpu_16bitbus) {
PUSHW(v >> 16);
PUSHW(v & 0xffff);
} else {
if (stack32) {
writememw(ss, ESP - 4, v);
if (cpu_state.abrt)
return;
ESP -= 4;
} else {
writememw(ss, ((SP - 4) & 0xffff), v);
if (cpu_state.abrt)
return;
SP -= 4;
}
}
}
static uint16_t
POPW(void)
{
@@ -1092,7 +1113,7 @@ loadcscall(uint16_t seg)
x86seg_log("Type %04X\n", type);
if (type == 0x0c00) {
PUSHL(oldss);
PUSHL_SEL(oldss);
PUSHL(oldsp2);
if (cpu_state.abrt) {
SS = oldss;
@@ -1622,10 +1643,10 @@ pmodeint(int num, int soft)
cpl_override = 1;
if (type >= 0x0800) {
if (cpu_state.eflags & VM_FLAG) {
PUSHL(GS);
PUSHL(FS);
PUSHL(DS);
PUSHL(ES);
PUSHL_SEL(GS);
PUSHL_SEL(FS);
PUSHL_SEL(DS);
PUSHL_SEL(ES);
if (cpu_state.abrt)
return;
op_loadseg(0, &cpu_state.seg_ds);
@@ -1633,10 +1654,10 @@ pmodeint(int num, int soft)
op_loadseg(0, &cpu_state.seg_fs);
op_loadseg(0, &cpu_state.seg_gs);
}
PUSHL(oldss);
PUSHL_SEL(oldss);
PUSHL(oldsp);
PUSHL(cpu_state.flags | (cpu_state.eflags << 16));
PUSHL(CS);
PUSHL_SEL(CS);
PUSHL(cpu_state.pc);
if (cpu_state.abrt)
return;
@@ -1672,7 +1693,7 @@ pmodeint(int num, int soft)
}
if (type > 0x0800) {
PUSHL(cpu_state.flags | (cpu_state.eflags << 16));
PUSHL(CS);
PUSHL_SEL(CS);
PUSHL(cpu_state.pc);
if (cpu_state.abrt)
return;