Skip to content

Commit 1e160b9

Browse files
committed
simx86: handle PM far calls via Sim_helper()
Which can separate calls to selector checks and sets, so all exceptions can be checked and then the old CS:EIP is pushed before the new CS:EIP is set.
1 parent ef05c7b commit 1e160b9

File tree

4 files changed

+57
-14
lines changed

4 files changed

+57
-14
lines changed

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2977,6 +2977,14 @@ static __inline__ void SetCPU_WL(int m, signed char o, unsigned long v)
29772977
unsigned int __res = sim_read_dword(LONG_SS + sp); \
29782978
sp += 4; sp &= TheCPU.StackMask; __res; })
29792979

2980+
#define PUSHw(sp,w) ({ \
2981+
sp -= 2; sp &= TheCPU.StackMask; \
2982+
sim_write_word(LONG_SS + sp, w); })
2983+
2984+
#define PUSHl(sp,l) ({ \
2985+
sp -= 4; sp &= TheCPU.StackMask; \
2986+
sim_write_dword(LONG_SS + sp, l); })
2987+
29802988
/* This generic helper function is called from JIT generated code and from
29812989
* Gen_sim to simulate hard-to-compile and rarely used ops.
29822990
* parameters:
@@ -3093,6 +3101,33 @@ static unsigned int _Sim_helper(unsigned int mem_ref, unsigned int data, int mod
30933101
inum, _AX, _CS, _IP);
30943102
break;
30953103
}
3104+
/*9a*/ case CALLl: { /* restartable */
3105+
unsigned int oldcs = TheCPU.cs;
3106+
unsigned int oldeip = arg;
3107+
unsigned int newcs = data;
3108+
unsigned int sp;
3109+
int e = SetSegProt_check(Ofs_CS, newcs);
3110+
if (e > 0)
3111+
break;
3112+
sp = rESP;
3113+
if (mode&DATA16) {
3114+
PUSHw(sp,oldcs);
3115+
PUSHw(sp,oldeip);
3116+
}
3117+
else {
3118+
PUSHl(sp,oldcs);
3119+
PUSHl(sp,oldeip);
3120+
}
3121+
if (debug_level('e')>2) {
3122+
dbug_printf("CALL_FAR: ret=%04x:%08x\n calling: cs=%04x\n",
3123+
oldcs,oldeip,newcs);
3124+
}
3125+
rESP = sp | (rESP&~TheCPU.StackMask);
3126+
// -1 means cached, nothing to set
3127+
if (e == 0)
3128+
SetSegProt_set(Ofs_CS, data);
3129+
break;
3130+
}
30963131
/*ca*/ case RETlisp:
30973132
/*cb*/ case RETl:
30983133
/*cf*/ case IRET: { /* restartable */

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

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -295,16 +295,16 @@ static unsigned int JumpGen(unsigned int P2, unsigned int Interp_LONG_CS,
295295
break;
296296
case CALLl: { /* call far */
297297
unsigned short jcs = FetchW(P2 + pskip - 2);
298-
Gen(L_IMM_R1, mode|DATA16, jcs);
299-
if (REALADDR())
298+
Gen(L_IMM_R1, mode&~DATA16, jcs);
299+
if (REALADDR()) {
300300
AddrGen(A_SR_SH4, mode, Ofs_CS, Ofs_XCS);
301-
else
302-
/* check if new cs is valid, load if so */
303-
AddrGen(A_SR_PROT, mode, Ofs_CS, P2);
304-
/* ok, now push old cs (returned by A_SR_*):eip */
305-
Gen(O_PUSH, mode);
306-
if (!REALADDR()) {
307-
Gen(O_PUSHI, mode, d_nt);
301+
/* ok, now push old cs (returned by A_SR_SH4):eip */
302+
Gen(O_PUSH, mode);
303+
/* fall through */
304+
}
305+
else {
306+
/* handle PM far calls via Sim_helper() */
307+
Gen(O_SIM, mode, opc, d_nt, P2);
308308
/* transfer to new PC (indirect jmp) */
309309
Gen(L_IMM_R1, mode, d_t);
310310
Gen(JMP_INDIRECT, mode);
@@ -2185,13 +2185,19 @@ intop3b: { int op = ArOpsFR[D_MO(opc)];
21852185
Gen(L_LXS2, _mode);
21862186
if (REALADDR())
21872187
AddrGen(A_SR_SH4, _mode, Ofs_CS, Ofs_XCS);
2188-
else
2188+
else if (REG1==Ofs_BP) /* PM JMP */
21892189
AddrGen(A_SR_PROT, _mode, Ofs_CS, P0);
21902190
if (REG1==Ofs_BX) {
21912191
/* ok, now push old cs:eip */
21922192
oip = PC + len - Interp_LONG_CS;
2193-
Gen(O_PUSH, _mode);
2194-
Gen(O_PUSHI, _mode, oip);
2193+
if (REALADDR()) {
2194+
Gen(O_PUSH, _mode);
2195+
Gen(O_PUSHI, _mode, oip);
2196+
}
2197+
else {
2198+
/* handle PM far calls via Sim_helper() */
2199+
Gen(O_SIM, _mode, CALLl, oip, P0);
2200+
}
21952201
}
21962202
Gen(L_DI_R1, _mode);
21972203
PC = JumpGen(PC, Interp_LONG_CS, _mode,

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ static int _SetSegProt_check(int ofs, unsigned long sel)
195195
return 0;
196196
}
197197

198-
static int SetSegProt_check(int ofs, unsigned long sel)
198+
int SetSegProt_check(int ofs, unsigned long sel)
199199
{
200200
int e = _SetSegProt_check(ofs, sel);
201201
if (e > 0) {
@@ -205,7 +205,7 @@ static int SetSegProt_check(int ofs, unsigned long sel)
205205
return e;
206206
}
207207

208-
static void SetSegProt_set(int ofs, unsigned long sel)
208+
void SetSegProt_set(int ofs, unsigned long sel)
209209
{
210210
static char buf[4];
211211
unsigned short wFlags = GetSelectorFlags(sel);

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,8 @@ typedef struct {
228228
//
229229
extern unsigned char e_ofsseg(int ofs);
230230
//
231+
int SetSegProt_check(int ofs, unsigned long sel);
232+
void SetSegProt_set(int ofs, unsigned long sel);
231233
void SetSegProt(int ofs, unsigned long sel);
232234
int SetSegProt_helper(unsigned short sv, int ofs);
233235
int SetSegReal(unsigned short sel, int ofs);

0 commit comments

Comments
 (0)