Fix <return> key (somehow we get a control keystate).
[wine] / miscemu / instr.c
1 /*
2  * Emulation of priviledged instructions
3  *
4  * Copyright 1995 Alexandre Julliard
5  */
6
7 #include "wine/winuser16.h"
8 #include "ldt.h"
9 #include "global.h"
10 #include "module.h"
11 #include "dosexe.h"
12 #include "miscemu.h"
13 #include "sig_context.h"
14 #include "selectors.h"
15 #include "debugtools.h"
16
17 DECLARE_DEBUG_CHANNEL(int)
18 DECLARE_DEBUG_CHANNEL(io)
19
20
21 #define IS_V86(context) (EFL_sig(context)&V86_FLAG)
22 #define IS_SEL_32(context,seg) \
23    (IS_V86(context) ? FALSE : IS_SELECTOR_32BIT(seg))
24
25 #define STACK_sig(context) \
26    (IS_SEL_32(context,SS_sig(context)) ? ESP_sig(context) : (DWORD)SP_sig(context))
27
28 #define ADD_STACK_sig(context,offset) \
29    do { if (IS_SEL_32(context,SS_sig(context))) ESP_sig(context) += (offset); \
30         else SP_sig(context) += (offset); } while(0)
31
32 #define MAKE_PTR(seg,off) \
33    (IS_SELECTOR_SYSTEM(seg) ? (void *)(off) : PTR_SEG_OFF_TO_LIN(seg,off))
34
35 #define MK_PTR(context,seg,off) \
36    (IS_V86(context) ? DOSMEM_MapRealToLinear(MAKELONG(off,seg)) \
37                     : MAKE_PTR(seg,off))
38
39 #define STACK_PTR(context) \
40    (IS_V86(context) ? DOSMEM_MapRealToLinear(MAKELONG(SP_sig(context),SS_sig(context))) : \
41     (IS_SELECTOR_SYSTEM(SS_sig(context)) ? (void *)ESP_sig(context) : \
42      (PTR_SEG_OFF_TO_LIN(SS_sig(context),STACK_sig(context)))))
43
44 /* For invalid registers fixup */
45 extern DWORD CallFrom16_Start,CallFrom16_End;
46 extern DWORD CALLTO16_Start,CALLTO16_End;
47
48
49 /***********************************************************************
50  *           INSTR_ReplaceSelector
51  *
52  * Try to replace an invalid selector by a valid one.
53  * The only selector where it is allowed to do "mov ax,40;mov es,ax"
54  * is the so called 'bimodal' selector 0x40, which points to the BIOS
55  * data segment. Used by (at least) Borland products (and programs compiled 
56  * using Borland products).
57  *
58  * See Undocumented Windows, Chapter 5, __0040.
59  */
60 static BOOL INSTR_ReplaceSelector( SIGCONTEXT *context, WORD *sel )
61 {
62     if ( IS_SELECTOR_SYSTEM(CS_sig(context)) )
63         if (    ( EIP_sig(context) >= (DWORD)&CallFrom16_Start &&
64                   EIP_sig(context) <  (DWORD)&CallFrom16_End )
65              || ( EIP_sig(context) >= (DWORD)&CALLTO16_Start &&
66                   EIP_sig(context) <  (DWORD)&CALLTO16_End ) )
67         {
68             /* Saved selector may have become invalid when the relay code */
69             /* tries to restore it. We simply clear it. */
70             *sel = 0;
71             return TRUE;
72         }
73
74     if (*sel == 0x40)
75     {
76         static WORD sys_timer = 0;
77         if (!sys_timer)
78             sys_timer = CreateSystemTimer( 55, DOSMEM_Tick );
79         *sel = DOSMEM_BiosDataSeg;
80         return TRUE;
81     }
82     if (!IS_SELECTOR_SYSTEM(*sel) && !IS_SELECTOR_FREE(*sel))
83         ERR_(int)("Got protection fault on valid selector, maybe your kernel is too old?\n" );
84     return FALSE;  /* Can't replace selector, crashdump */
85 }
86
87
88 /***********************************************************************
89  *           INSTR_GetOperandAddr
90  *
91  * Return the address of an instruction operand (from the mod/rm byte).
92  */
93 static BYTE *INSTR_GetOperandAddr( SIGCONTEXT *context, BYTE *instr,
94                                    int long_addr, int segprefix, int *len )
95 {
96     int mod, rm, base, index = 0, ss = 0, seg = 0, off;
97
98 #define GET_VAL(val,type) \
99     { *val = *(type *)instr; instr += sizeof(type); *len += sizeof(type); }
100
101     *len = 0;
102     GET_VAL( &mod, BYTE );
103     rm = mod & 7;
104     mod >>= 6;
105
106     if (mod == 3)
107     {
108         switch(rm)
109         {
110         case 0: return (BYTE *)&EAX_sig(context);
111         case 1: return (BYTE *)&ECX_sig(context);
112         case 2: return (BYTE *)&EDX_sig(context);
113         case 3: return (BYTE *)&EBX_sig(context);
114         case 4: return (BYTE *)&ESP_sig(context);
115         case 5: return (BYTE *)&EBP_sig(context);
116         case 6: return (BYTE *)&ESI_sig(context);
117         case 7: return (BYTE *)&EDI_sig(context);
118         }
119     }
120
121     if (long_addr)
122     {
123         if (rm == 4)
124         {
125             BYTE sib;
126             GET_VAL( &sib, BYTE );
127             rm = sib & 7;
128             ss = sib >> 6;
129             switch(sib >> 3)
130             {
131             case 0: index = EAX_sig(context); break;
132             case 1: index = ECX_sig(context); break;
133             case 2: index = EDX_sig(context); break;
134             case 3: index = EBX_sig(context); break;
135             case 4: index = 0; break;
136             case 5: index = EBP_sig(context); break;
137             case 6: index = ESI_sig(context); break;
138             case 7: index = EDI_sig(context); break;
139             }
140         }
141
142         switch(rm)
143         {
144         case 0: base = EAX_sig(context); seg = DS_sig(context); break;
145         case 1: base = ECX_sig(context); seg = DS_sig(context); break;
146         case 2: base = EDX_sig(context); seg = DS_sig(context); break;
147         case 3: base = EBX_sig(context); seg = DS_sig(context); break;
148         case 4: base = ESP_sig(context); seg = SS_sig(context); break;
149         case 5: base = EBP_sig(context); seg = SS_sig(context); break;
150         case 6: base = ESI_sig(context); seg = DS_sig(context); break;
151         case 7: base = EDI_sig(context); seg = DS_sig(context); break;
152         }
153         switch (mod)
154         {
155         case 0:
156             if (rm == 5)  /* special case: ds:(disp32) */
157             {
158                 GET_VAL( &base, DWORD );
159                 seg = DS_sig(context);
160             }
161             break;
162
163         case 1:  /* 8-bit disp */
164             GET_VAL( &off, BYTE );
165             base += (signed char)off;
166             break;
167
168         case 2:  /* 32-bit disp */
169             GET_VAL( &off, DWORD );
170             base += (signed long)off;
171             break;
172         }
173     }
174     else  /* short address */
175     {
176         switch(rm)
177         {
178         case 0:  /* ds:(bx,si) */
179             base = BX_sig(context) + SI_sig(context);
180             seg  = DS_sig(context);
181             break;
182         case 1:  /* ds:(bx,di) */
183             base = BX_sig(context) + DI_sig(context);
184             seg  = DS_sig(context);
185             break;
186         case 2:  /* ss:(bp,si) */
187             base = BP_sig(context) + SI_sig(context);
188             seg  = SS_sig(context);
189             break;
190         case 3:  /* ss:(bp,di) */
191             base = BP_sig(context) + DI_sig(context);
192             seg  = SS_sig(context);
193             break;
194         case 4:  /* ds:(si) */
195             base = SI_sig(context);
196             seg  = DS_sig(context);
197             break;
198         case 5:  /* ds:(di) */
199             base = DI_sig(context);
200             seg  = DS_sig(context);
201             break;
202         case 6:  /* ss:(bp) */
203             base = BP_sig(context);
204             seg  = SS_sig(context);
205             break;
206         case 7:  /* ds:(bx) */
207             base = BX_sig(context);
208             seg  = DS_sig(context);
209             break;
210         }
211
212         switch(mod)
213         {
214         case 0:
215             if (rm == 6)  /* special case: ds:(disp16) */
216             {
217                 GET_VAL( &base, WORD );
218                 seg  = DS_sig(context);
219             }
220             break;
221
222         case 1:  /* 8-bit disp */
223             GET_VAL( &off, BYTE );
224             base += (signed char)off;
225             break;
226
227         case 2:  /* 16-bit disp */
228             GET_VAL( &off, WORD );
229             base += (signed short)off;
230             break;
231         }
232         base &= 0xffff;
233     }
234     if (segprefix != -1) seg = segprefix;
235
236     /* Make sure the segment and offset are valid */
237     if (IS_SELECTOR_SYSTEM(seg)) return (BYTE *)(base + (index << ss));
238     if (((seg & 7) != 7) || IS_SELECTOR_FREE(seg)) return NULL;
239     if (GET_SEL_LIMIT(seg) < (base + (index << ss))) return NULL;
240     return (BYTE *)PTR_SEG_OFF_TO_LIN( seg, (base + (index << ss)) );
241 #undef GET_VAL
242 }
243
244
245 /***********************************************************************
246  *           INSTR_EmulateLDS
247  *
248  * Emulate the LDS (and LES,LFS,etc.) instruction.
249  */
250 static BOOL INSTR_EmulateLDS( SIGCONTEXT *context, BYTE *instr, int long_op,
251                                 int long_addr, int segprefix, int *len )
252 {
253     WORD seg;
254     BYTE *regmodrm = instr + 1 + (*instr == 0x0f);
255     BYTE *addr = INSTR_GetOperandAddr( context, regmodrm,
256                                        long_addr, segprefix, len );
257     if (!addr)
258         return FALSE;  /* Unable to emulate it */
259     seg = *(WORD *)(addr + (long_op ? 4 : 2));
260
261     if (!INSTR_ReplaceSelector( context, &seg ))
262         return FALSE;  /* Unable to emulate it */
263
264     /* Now store the offset in the correct register */
265
266     switch((*regmodrm >> 3) & 7)
267     {
268     case 0:
269         if (long_op) EAX_sig(context) = *(DWORD *)addr;
270         else AX_sig(context) = *(WORD *)addr;
271         break;
272     case 1:
273         if (long_op) ECX_sig(context) = *(DWORD *)addr;
274         else CX_sig(context) = *(WORD *)addr;
275         break;
276     case 2:
277         if (long_op) EDX_sig(context) = *(DWORD *)addr;
278         else DX_sig(context) = *(WORD *)addr;
279         break;
280     case 3:
281         if (long_op) EBX_sig(context) = *(DWORD *)addr;
282         else BX_sig(context) = *(WORD *)addr;
283         break;
284     case 4:
285         if (long_op) ESP_sig(context) = *(DWORD *)addr;
286         else SP_sig(context) = *(WORD *)addr;
287         break;
288     case 5:
289         if (long_op) EBP_sig(context) = *(DWORD *)addr;
290         else BP_sig(context) = *(WORD *)addr;
291         break;
292     case 6:
293         if (long_op) ESI_sig(context) = *(DWORD *)addr;
294         else SI_sig(context) = *(WORD *)addr;
295         break;
296     case 7:
297         if (long_op) EDI_sig(context) = *(DWORD *)addr;
298         else DI_sig(context) = *(WORD *)addr;
299         break;
300     }
301
302     /* Store the correct segment in the segment register */
303
304     switch(*instr)
305     {
306     case 0xc4: ES_sig(context) = seg; break;  /* les */
307     case 0xc5: DS_sig(context) = seg; break;  /* lds */
308     case 0x0f: switch(instr[1])
309                {
310                case 0xb2: SS_sig(context) = seg; break;  /* lss */
311 #ifdef FS_sig
312                case 0xb4: FS_sig(context) = seg; break;  /* lfs */
313 #endif
314 #ifdef GS_sig
315                case 0xb5: GS_sig(context) = seg; break;  /* lgs */
316 #endif
317                }
318                break;
319     }
320
321     /* Add the opcode size to the total length */
322
323     *len += 1 + (*instr == 0x0f);
324     return TRUE;
325 }
326
327
328 /***********************************************************************
329  *           INSTR_EmulateInstruction
330  *
331  * Emulate a priviledged instruction. Returns TRUE if emulation successful.
332  */
333 BOOL INSTR_EmulateInstruction( SIGCONTEXT *context )
334 {
335     int prefix, segprefix, prefixlen, len, repX, long_op, long_addr;
336     SEGPTR gpHandler;
337     BYTE *instr;
338
339     long_op = long_addr = IS_SEL_32(context,CS_sig(context));
340     instr = (BYTE *)MK_PTR(context,CS_sig(context),EIP_sig(context));
341     if (!instr) return FALSE;
342
343     /* First handle any possible prefix */
344
345     segprefix = -1;  /* no prefix */
346     prefix = 1;
347     repX = 0;
348     prefixlen = 0;
349     while(prefix)
350     {
351         switch(*instr)
352         {
353         case 0x2e:
354             segprefix = CS_sig(context);
355             break;
356         case 0x36:
357             segprefix = SS_sig(context);
358             break;
359         case 0x3e:
360             segprefix = DS_sig(context);
361             break;
362         case 0x26:
363             segprefix = ES_sig(context);
364             break;
365 #ifdef FS_sig
366         case 0x64:
367             segprefix = FS_sig(context);
368             break;
369 #endif
370 #ifdef GS_sig
371         case 0x65:
372             segprefix = GS_sig(context);
373             break;
374 #endif
375         case 0x66:
376             long_op = !long_op;  /* opcode size prefix */
377             break;
378         case 0x67:
379             long_addr = !long_addr;  /* addr size prefix */
380             break;
381         case 0xf0:  /* lock */
382             break;
383         case 0xf2:  /* repne */
384             repX = 1;
385             break;
386         case 0xf3:  /* repe */
387             repX = 2;
388             break;
389         default:
390             prefix = 0;  /* no more prefixes */
391             break;
392         }
393         if (prefix)
394         {
395             instr++;
396             prefixlen++;
397         }
398     }
399
400     /* Now look at the actual instruction */
401
402     switch(*instr)
403     {
404         case 0x07: /* pop es */
405         case 0x17: /* pop ss */
406         case 0x1f: /* pop ds */
407             {
408                 WORD seg = *(WORD *)STACK_PTR( context );
409                 if (INSTR_ReplaceSelector( context, &seg ))
410                 {
411                     switch(*instr)
412                     {
413                     case 0x07: ES_sig(context) = seg; break;
414                     case 0x17: SS_sig(context) = seg; break;
415                     case 0x1f: DS_sig(context) = seg; break;
416                     }
417                     ADD_STACK_sig(context, long_op ? 4 : 2);
418                     EIP_sig(context) += prefixlen + 1;
419                     return TRUE;
420                 }
421             }
422             break;  /* Unable to emulate it */
423
424         case 0x0f: /* extended instruction */
425             switch(instr[1])
426             {
427             case 0x22: /* mov eax, crX */
428                 switch (instr[2]) {
429                 case 0xc0:
430                         fprintf(stderr,"mov eax,cr0 at 0x%08lx, EAX=0x%08lx\n",
431                                 EIP_sig(context),EAX_sig(context)
432                         );
433                         EIP_sig(context) += prefixlen+3;
434                         return TRUE;
435                 default:
436                         break; /*fallthrough to bad instruction handling */
437                 }
438                 break; /*fallthrough to bad instruction handling */
439             case 0x20: /* mov crX, eax */
440                 switch (instr[2]) {
441                 case 0xe0: /* mov cr4, eax */
442                     /* CR4 register . See linux/arch/i386/mm/init.c, X86_CR4_ defs
443                      * bit 0: VME       Virtual Mode Exception ?
444                      * bit 1: PVI       Protected mode Virtual Interrupt
445                      * bit 2: TSD       Timestamp disable
446                      * bit 3: DE        Debugging extensions
447                      * bit 4: PSE       Page size extensions
448                      * bit 5: PAE   Physical address extension
449                      * bit 6: MCE       Machine check enable
450                      * bit 7: PGE   Enable global pages
451                      * bit 8: PCE       Enable performance counters at IPL3
452                      */
453                     fprintf(stderr,"mov cr4,eax at 0x%08lx\n",EIP_sig(context));
454                     EAX_sig(context) = 0;
455                     EIP_sig(context) += prefixlen+3;
456                     return TRUE;
457                 case 0xc0: /* mov cr0, eax */
458                     fprintf(stderr,"mov cr0,eax at 0x%08lx\n",EIP_sig(context));
459                     EAX_sig(context) = 0x10; /* FIXME: set more bits ? */
460                     EIP_sig(context) += prefixlen+3;
461                     return TRUE;
462                 default: /* fallthrough to illegal instruction */
463                     break;
464                 }
465                 /* fallthrough to illegal instruction */
466                 break;
467 #ifdef FS_sig
468             case 0xa1: /* pop fs */
469                 {
470                     WORD seg = *(WORD *)STACK_PTR( context );
471                     if (INSTR_ReplaceSelector( context, &seg ))
472                     {
473                         FS_sig(context) = seg;
474                         ADD_STACK_sig(context, long_op ? 4 : 2);
475                         EIP_sig(context) += prefixlen + 2;
476                         return TRUE;
477                     }
478                 }
479                 break;
480 #endif  /* FS_sig */
481
482 #ifdef GS_sig
483             case 0xa9: /* pop gs */
484                 {
485                     WORD seg = *(WORD *)STACK_PTR( context );
486                     if (INSTR_ReplaceSelector( context, &seg ))
487                     {
488                         GS_sig(context) = seg;
489                         ADD_STACK_sig(context, long_op ? 4 : 2);
490                         EIP_sig(context) += prefixlen + 2;
491                         return TRUE;
492                     }
493                 }
494                 break;
495 #endif  /* GS_sig */
496
497             case 0xb2: /* lss addr,reg */
498 #ifdef FS_sig
499             case 0xb4: /* lfs addr,reg */
500 #endif
501 #ifdef GS_sig
502             case 0xb5: /* lgs addr,reg */
503 #endif
504                 if (INSTR_EmulateLDS( context, instr, long_op,
505                                       long_addr, segprefix, &len ))
506                 {
507                     EIP_sig(context) += prefixlen + len;
508                     return TRUE;
509                 }
510                 break;
511             }
512             break;  /* Unable to emulate it */
513
514         case 0x6c: /* insb     */
515         case 0x6d: /* insw/d   */
516         case 0x6e: /* outsb    */
517         case 0x6f: /* outsw/d  */
518             {
519               int typ = *instr;  /* Just in case it's overwritten.  */
520               int outp = (typ >= 0x6e);
521               unsigned long count = repX ?
522                           (long_addr ? ECX_sig(context) : CX_sig(context)) : 1;
523               int opsize = (typ & 1) ? (long_op ? 4 : 2) : 1;
524               int step = (EFL_sig(context) & 0x400) ? -opsize : +opsize;
525               int seg = outp ? DS_sig(context) : ES_sig(context);  /* FIXME: is this right? */
526
527               if (outp)
528                 /* FIXME: Check segment readable.  */
529                 (void)0;
530               else
531                 /* FIXME: Check segment writeable.  */
532                 (void)0;
533
534               if (repX)
535               {
536                 if (long_addr)
537                   ECX_sig(context) = 0;
538                 else
539                   CX_sig(context) = 0;
540               }
541
542               while (count-- > 0)
543                 {
544                   void *data;
545                   if (outp)
546                   {
547                       data = MK_PTR(context, seg,
548                                long_addr ? ESI_sig(context) : SI_sig(context));
549                       if (long_addr) ESI_sig(context) += step;
550                       else SI_sig(context) += step;
551                   }
552                   else
553                   {
554                       data = MK_PTR(context, seg,
555                                long_addr ? EDI_sig(context) : DI_sig(context));
556                       if (long_addr) EDI_sig(context) += step;
557                       else DI_sig(context) += step;
558                   }
559                   
560                   switch (typ)
561                   {
562                     case 0x6c:
563                       *((BYTE *)data) = IO_inport( DX_sig(context), 1);
564                       TRACE_(io)("0x%x < %02x @ %04x:%04x\n", DX_sig(context),
565                         *((BYTE *)data), CS_sig(context), IP_sig(context));
566                       break;
567                     case 0x6d:
568                       if (long_op)
569                       {
570                         *((DWORD *)data) = IO_inport( DX_sig(context), 4);
571                         TRACE_(io)("0x%x < %08lx @ %04x:%04x\n", DX_sig(context),
572                           *((DWORD *)data), CS_sig(context), IP_sig(context));
573                       }
574                       else
575                       {
576                         *((WORD *)data) = IO_inport( DX_sig(context), 2);
577                         TRACE_(io)("0x%x < %04x @ %04x:%04x\n", DX_sig(context),
578                           *((WORD *)data), CS_sig(context), IP_sig(context));
579                       }
580                       break;
581                     case 0x6e:
582                         IO_outport( DX_sig(context), 1, *((BYTE *)data));
583                         TRACE_(io)("0x%x > %02x @ %04x:%04x\n", DX_sig(context),
584                           *((BYTE *)data), CS_sig(context), IP_sig(context));
585                         break;
586                     case 0x6f:
587                         if (long_op)
588                         {
589                             IO_outport( DX_sig(context), 4, *((DWORD *)data));
590                             TRACE_(io)("0x%x > %08lx @ %04x:%04x\n", DX_sig(context),
591                               *((DWORD *)data), CS_sig(context), IP_sig(context)); 
592                         }
593                         else
594                         {
595                             IO_outport( DX_sig(context), 2, *((WORD *)data));
596                             TRACE_(io)("0x%x > %04x @ %04x:%04x\n", DX_sig(context),
597                               *((WORD *)data), CS_sig(context), IP_sig(context));
598                         }
599                         break;
600                     }
601                 }
602               EIP_sig(context) += prefixlen + 1;
603             }
604             return TRUE;
605
606         case 0x8e: /* mov XX,segment_reg */
607             {
608                 WORD seg;
609                 BYTE *addr = INSTR_GetOperandAddr(context, instr + 1,
610                                                   long_addr, segprefix, &len );
611                 if (!addr)
612                     break;  /* Unable to emulate it */
613                 seg = *(WORD *)addr;
614                 if (!INSTR_ReplaceSelector( context, &seg ))
615                     break;  /* Unable to emulate it */
616
617                 switch((instr[1] >> 3) & 7)
618                 {
619                 case 0:
620                     ES_sig(context) = seg;
621                     EIP_sig(context) += prefixlen + len + 1;
622                     return TRUE;
623                 case 1:  /* cs */
624                     break;
625                 case 2:
626                     SS_sig(context) = seg;
627                     EIP_sig(context) += prefixlen + len + 1;
628                     return TRUE;
629                 case 3:
630                     DS_sig(context) = seg;
631                     EIP_sig(context) += prefixlen + len + 1;
632                     return TRUE;
633                 case 4:
634 #ifdef FS_sig
635                     FS_sig(context) = seg;
636                     EIP_sig(context) += prefixlen + len + 1;
637                     return TRUE;
638 #endif
639                 case 5:
640 #ifdef GS_sig
641                     GS_sig(context) = seg;
642                     EIP_sig(context) += prefixlen + len + 1;
643                     return TRUE;
644 #endif
645                 case 6:  /* unused */
646                 case 7:  /* unused */
647                     break;
648                 }
649             }
650             break;  /* Unable to emulate it */
651
652         case 0xc4: /* les addr,reg */
653         case 0xc5: /* lds addr,reg */
654             if (INSTR_EmulateLDS( context, instr, long_op,
655                                   long_addr, segprefix, &len ))
656             {
657                 EIP_sig(context) += prefixlen + len;
658                 return TRUE;
659             }
660             break;  /* Unable to emulate it */
661             
662         case 0xcd: /* int <XX> */
663             if (long_op)
664             {
665                 ERR_(int)("int xx from 32-bit code is not supported.\n");
666                 break;  /* Unable to emulate it */
667             }
668             else
669             {
670                 FARPROC16 addr = INT_GetPMHandler( instr[1] );
671                 WORD *stack = (WORD *)STACK_PTR( context );
672                 /* Push the flags and return address on the stack */
673                 *(--stack) = FL_sig(context);
674                 *(--stack) = CS_sig(context);
675                 *(--stack) = IP_sig(context) + prefixlen + 2;
676                 ADD_STACK_sig(context, -3 * sizeof(WORD));
677                 /* Jump to the interrupt handler */
678                 CS_sig(context)  = HIWORD(addr);
679                 EIP_sig(context) = LOWORD(addr);
680             }
681             return TRUE;
682
683         case 0xcf: /* iret */
684             if (long_op)
685             {
686                 DWORD *stack = (DWORD *)STACK_PTR( context );
687                 EIP_sig(context) = *stack++;
688                 CS_sig(context)  = *stack++;
689                 EFL_sig(context) = *stack;
690                 ADD_STACK_sig(context, 3*sizeof(DWORD));  /* Pop the return address and flags */
691             }
692             else
693             {
694                 WORD *stack = (WORD *)STACK_PTR( context );
695                 EIP_sig(context) = *stack++;
696                 CS_sig(context)  = *stack++;
697                 FL_sig(context)  = *stack;
698                 ADD_STACK_sig(context, 3*sizeof(WORD));  /* Pop the return address and flags */
699             }
700             return TRUE;
701
702         case 0xe4: /* inb al,XX */
703             AL_sig(context) = IO_inport( instr[1], 1 );
704             TRACE_(io)("0x%x < %02x @ %04x:%04x\n", instr[1],
705                 AL_sig(context), CS_sig(context), IP_sig(context));
706             EIP_sig(context) += prefixlen + 2;
707             return TRUE;
708
709         case 0xe5: /* in (e)ax,XX */
710             if (long_op)
711             {
712                 EAX_sig(context) = IO_inport( instr[1], 4 );
713                 TRACE_(io)("0x%x < %08lx @ %04x:%04x\n", instr[1],
714                     EAX_sig(context), CS_sig(context), IP_sig(context));
715             }
716             else
717             {
718                 AX_sig(context) = IO_inport( instr[1], 2 );
719                 TRACE_(io)("0x%x < %04x @ %04x:%04x\n", instr[1],
720                     AX_sig(context), CS_sig(context), IP_sig(context));
721             }
722             EIP_sig(context) += prefixlen + 2;
723             return TRUE;
724
725         case 0xe6: /* outb XX,al */
726             IO_outport( instr[1], 1, AL_sig(context) );
727             TRACE_(io)("0x%x > %02x @ %04x:%04x\n", instr[1],
728                 AL_sig(context), CS_sig(context), IP_sig(context));
729             EIP_sig(context) += prefixlen + 2;
730             return TRUE;
731
732         case 0xe7: /* out XX,(e)ax */
733             if (long_op)
734             {
735                 IO_outport( instr[1], 4, EAX_sig(context) );
736                 TRACE_(io)("0x%x > %08lx @ %04x:%04x\n", instr[1],
737                     EAX_sig(context), CS_sig(context), IP_sig(context));
738             }
739             else
740             {
741                 IO_outport( instr[1], 2, AX_sig(context) );
742                 TRACE_(io)("0x%x > %04x @ %04x:%04x\n", instr[1],
743                     AX_sig(context), CS_sig(context), IP_sig(context));
744             }
745             EIP_sig(context) += prefixlen + 2;
746             return TRUE;
747
748         case 0xec: /* inb al,dx */
749             AL_sig(context) = IO_inport( DX_sig(context), 1 );
750             TRACE_(io)("0x%x < %02x @ %04x:%04x\n", DX_sig(context),
751                 AL_sig(context), CS_sig(context), IP_sig(context));
752             EIP_sig(context) += prefixlen + 1;
753             return TRUE;
754
755         case 0xed: /* in (e)ax,dx */
756             if (long_op)
757             {
758                 EAX_sig(context) = IO_inport( DX_sig(context), 4 );
759                 TRACE_(io)("0x%x < %08lx @ %04x:%04x\n", DX_sig(context),
760                     EAX_sig(context), CS_sig(context), IP_sig(context));
761             }
762             else
763             {
764                 AX_sig(context) = IO_inport( DX_sig(context), 2 );
765                 TRACE_(io)("0x%x < %04x @ %04x:%04x\n", DX_sig(context),
766                     AX_sig(context), CS_sig(context), IP_sig(context));
767             }
768             EIP_sig(context) += prefixlen + 1;
769             return TRUE;
770
771         case 0xee: /* outb dx,al */
772             IO_outport( DX_sig(context), 1, AL_sig(context) );
773             TRACE_(io)("0x%x > %02x @ %04x:%04x\n", DX_sig(context),
774                 AL_sig(context), CS_sig(context), IP_sig(context));
775             EIP_sig(context) += prefixlen + 1;
776             return TRUE;
777       
778         case 0xef: /* out dx,(e)ax */
779             if (long_op)
780             {
781                 IO_outport( DX_sig(context), 4, EAX_sig(context) );
782                 TRACE_(io)("0x%x > %08lx @ %04x:%04x\n", DX_sig(context),
783                     EAX_sig(context), CS_sig(context), IP_sig(context));
784             }
785             else
786             {
787                 IO_outport( DX_sig(context), 2, AX_sig(context) );
788                 TRACE_(io)("0x%x > %04x @ %04x:%04x\n", DX_sig(context),
789                     AX_sig(context), CS_sig(context), IP_sig(context));
790             }
791             EIP_sig(context) += prefixlen + 1;
792             return TRUE;
793
794         case 0xfa: /* cli, ignored */
795             EIP_sig(context) += prefixlen + 1;
796             return TRUE;
797
798         case 0xfb: /* sti, ignored */
799             EIP_sig(context) += prefixlen + 1;
800             return TRUE;
801     }
802
803
804     /* Check for Win16 __GP handler */
805     gpHandler = HasGPHandler16( PTR_SEG_OFF_TO_SEGPTR( CS_sig(context),
806                                                      EIP_sig(context) ) );
807     if (gpHandler)
808     {
809         WORD *stack = (WORD *)STACK_PTR( context );
810         *--stack = CS_sig(context);
811         *--stack = EIP_sig(context);
812         ADD_STACK_sig(context, -2*sizeof(WORD));
813
814         CS_sig(context) = SELECTOROF( gpHandler );
815         EIP_sig(context) = OFFSETOF( gpHandler );
816         return TRUE;
817     }
818
819     MESSAGE("Unexpected Windows program segfault"
820                     " - opcode = %x\n", *instr);
821     return FALSE;  /* Unable to emulate it */
822 }