Removed some of the XXX_reg macros now that we are using the standard
[wine] / memory / instr.c
1 /*
2  * Emulation of priviledged instructions
3  *
4  * Copyright 1995 Alexandre Julliard
5  */
6
7 #include "windef.h"
8 #include "wingdi.h"
9 #include "wine/winuser16.h"
10 #include "ldt.h"
11 #include "global.h"
12 #include "module.h"
13 #include "miscemu.h"
14 #include "selectors.h"
15 #include "debugtools.h"
16
17 DEFAULT_DEBUG_CHANNEL(int);
18 DECLARE_DEBUG_CHANNEL(io);
19
20 #ifdef __i386__
21
22 inline static void add_stack( CONTEXT86 *context, int offset )
23 {
24     if (ISV86(context) || !IS_SELECTOR_32BIT(context->SegSs))
25         ADD_LOWORD( context->Esp, offset );
26     else
27         context->Esp += offset;
28 }
29
30 inline static void *make_ptr( CONTEXT86 *context, DWORD seg, DWORD off, int long_addr )
31 {
32     if (ISV86(context)) return PTR_REAL_TO_LIN( seg, off );
33     if (IS_SELECTOR_SYSTEM(seg)) return (void *)off;
34     if (!long_addr) off = LOWORD(off);
35     return PTR_SEG_OFF_TO_LIN( seg, off );
36 }
37
38 inline static void *get_stack( CONTEXT86 *context )
39 {
40     if (ISV86(context))
41         return PTR_REAL_TO_LIN( context->SegSs, context->Esp );
42     if (IS_SELECTOR_SYSTEM(context->SegSs))
43         return (void *)context->Esp;
44     if (IS_SELECTOR_32BIT(context->SegSs))
45         return PTR_SEG_OFF_TO_LIN( context->SegSs, context->Esp );
46     return PTR_SEG_OFF_TO_LIN( context->SegSs, LOWORD(context->Esp) );
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( CONTEXT86 *context, WORD *sel )
61 {
62     extern char Call16_Start, Call16_End;
63
64     if (IS_SELECTOR_SYSTEM(context->SegCs))
65         if (    (char *)context->Eip >= &Call16_Start 
66              && (char *)context->Eip <  &Call16_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("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( CONTEXT86 *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 *)&context->Eax;
111         case 1: return (BYTE *)&context->Ecx;
112         case 2: return (BYTE *)&context->Edx;
113         case 3: return (BYTE *)&context->Ebx;
114         case 4: return (BYTE *)&context->Esp;
115         case 5: return (BYTE *)&context->Ebp;
116         case 6: return (BYTE *)&context->Esi;
117         case 7: return (BYTE *)&context->Edi;
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 = context->Eax; break;
132             case 1: index = context->Ecx; break;
133             case 2: index = context->Edx; break;
134             case 3: index = context->Ebx; break;
135             case 4: index = 0; break;
136             case 5: index = context->Ebp; break;
137             case 6: index = context->Esi; break;
138             case 7: index = context->Edi; break;
139             }
140         }
141
142         switch(rm)
143         {
144         case 0: base = context->Eax; seg = context->SegDs; break;
145         case 1: base = context->Ecx; seg = context->SegDs; break;
146         case 2: base = context->Edx; seg = context->SegDs; break;
147         case 3: base = context->Ebx; seg = context->SegDs; break;
148         case 4: base = context->Esp; seg = context->SegSs; break;
149         case 5: base = context->Ebp; seg = context->SegSs; break;
150         case 6: base = context->Esi; seg = context->SegDs; break;
151         case 7: base = context->Edi; seg = context->SegDs; 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 = context->SegDs;
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 = LOWORD(context->Ebx) + LOWORD(context->Esi);
180             seg  = context->SegDs;
181             break;
182         case 1:  /* ds:(bx,di) */
183             base = LOWORD(context->Ebx) + LOWORD(context->Edi);
184             seg  = context->SegDs;
185             break;
186         case 2:  /* ss:(bp,si) */
187             base = LOWORD(context->Ebp) + LOWORD(context->Esi);
188             seg  = context->SegSs;
189             break;
190         case 3:  /* ss:(bp,di) */
191             base = LOWORD(context->Ebp) + LOWORD(context->Edi);
192             seg  = context->SegSs;
193             break;
194         case 4:  /* ds:(si) */
195             base = LOWORD(context->Esi);
196             seg  = context->SegDs;
197             break;
198         case 5:  /* ds:(di) */
199             base = LOWORD(context->Edi);
200             seg  = context->SegDs;
201             break;
202         case 6:  /* ss:(bp) */
203             base = LOWORD(context->Ebp);
204             seg  = context->SegSs;
205             break;
206         case 7:  /* ds:(bx) */
207             base = LOWORD(context->Ebx);
208             seg  = context->SegDs;
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  = context->SegDs;
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( CONTEXT86 *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) context->Eax = *(DWORD *)addr;
270         else SET_LOWORD(context->Eax,*(WORD *)addr);
271         break;
272     case 1:
273         if (long_op) context->Ecx = *(DWORD *)addr;
274         else SET_LOWORD(context->Ecx,*(WORD *)addr);
275         break;
276     case 2:
277         if (long_op) context->Edx = *(DWORD *)addr;
278         else SET_LOWORD(context->Edx,*(WORD *)addr);
279         break;
280     case 3:
281         if (long_op) context->Ebx = *(DWORD *)addr;
282         else SET_LOWORD(context->Ebx,*(WORD *)addr);
283         break;
284     case 4:
285         if (long_op) context->Esp = *(DWORD *)addr;
286         else SET_LOWORD(context->Esp,*(WORD *)addr);
287         break;
288     case 5:
289         if (long_op) context->Ebp = *(DWORD *)addr;
290         else SET_LOWORD(context->Ebp,*(WORD *)addr);
291         break;
292     case 6:
293         if (long_op) context->Esi = *(DWORD *)addr;
294         else SET_LOWORD(context->Esi,*(WORD *)addr);
295         break;
296     case 7:
297         if (long_op) context->Edi = *(DWORD *)addr;
298         else SET_LOWORD(context->Edi,*(WORD *)addr);
299         break;
300     }
301
302     /* Store the correct segment in the segment register */
303
304     switch(*instr)
305     {
306     case 0xc4: context->SegEs = seg; break;  /* les */
307     case 0xc5: context->SegDs = seg; break;  /* lds */
308     case 0x0f: switch(instr[1])
309                {
310                case 0xb2: context->SegSs = seg; break;  /* lss */
311                case 0xb4: context->SegFs = seg; break;  /* lfs */
312                case 0xb5: context->SegGs = seg; break;  /* lgs */
313                }
314                break;
315     }
316
317     /* Add the opcode size to the total length */
318
319     *len += 1 + (*instr == 0x0f);
320     return TRUE;
321 }
322
323 /***********************************************************************
324  *           INSTR_inport
325  *
326  * input on a I/O port
327  */
328 static DWORD INSTR_inport( WORD port, int size, CONTEXT86 *context )
329 {
330     DWORD res = IO_inport( port, size );
331     if (TRACE_ON(io))
332     {
333         switch(size)
334         {
335         case 1:
336             DPRINTF( "0x%x < %02x @ %04x:%04x\n", port, LOBYTE(res),
337                      (WORD)context->SegCs, LOWORD(context->Eip));
338             break;
339         case 2:
340             DPRINTF( "0x%x < %04x @ %04x:%04x\n", port, LOWORD(res),
341                      (WORD)context->SegCs, LOWORD(context->Eip));
342             break;
343         case 4:
344             DPRINTF( "0x%x < %08lx @ %04x:%04x\n", port, res,
345                      (WORD)context->SegCs, LOWORD(context->Eip));
346             break;
347         }
348     }
349     return res;
350 }
351
352
353 /***********************************************************************
354  *           INSTR_outport
355  *
356  * output on a I/O port
357  */
358 static void INSTR_outport( WORD port, int size, DWORD val, CONTEXT86 *context )
359 {
360     IO_outport( port, size, val );
361     if (TRACE_ON(io))
362     {
363         switch(size)
364         {
365         case 1:
366             DPRINTF("0x%x > %02x @ %04x:%04x\n", port, LOBYTE(val),
367                     (WORD)context->SegCs, LOWORD(context->Eip));
368             break;
369         case 2:
370             DPRINTF("0x%x > %04x @ %04x:%04x\n", port, LOWORD(val),
371                     (WORD)context->SegCs, LOWORD(context->Eip));
372             break;
373         case 4:
374             DPRINTF("0x%x > %08lx @ %04x:%04x\n", port, val,
375                     (WORD)context->SegCs, LOWORD(context->Eip));
376             break;
377         }
378     }
379 }
380
381
382 /***********************************************************************
383  *           INSTR_EmulateInstruction
384  *
385  * Emulate a priviledged instruction. Returns TRUE if emulation successful.
386  */
387 BOOL INSTR_EmulateInstruction( CONTEXT86 *context )
388 {
389     int prefix, segprefix, prefixlen, len, repX, long_op, long_addr;
390     SEGPTR gpHandler;
391     BYTE *instr;
392
393     long_op = long_addr = (!ISV86(context) && IS_SELECTOR_32BIT(context->SegCs));
394     instr = make_ptr( context, context->SegCs, context->Eip, TRUE );
395     if (!instr) return FALSE;
396
397     /* First handle any possible prefix */
398
399     segprefix = -1;  /* no prefix */
400     prefix = 1;
401     repX = 0;
402     prefixlen = 0;
403     while(prefix)
404     {
405         switch(*instr)
406         {
407         case 0x2e:
408             segprefix = context->SegCs;
409             break;
410         case 0x36:
411             segprefix = context->SegSs;
412             break;
413         case 0x3e:
414             segprefix = context->SegDs;
415             break;
416         case 0x26:
417             segprefix = context->SegEs;
418             break;
419         case 0x64:
420             segprefix = context->SegFs;
421             break;
422         case 0x65:
423             segprefix = context->SegGs;
424             break;
425         case 0x66:
426             long_op = !long_op;  /* opcode size prefix */
427             break;
428         case 0x67:
429             long_addr = !long_addr;  /* addr size prefix */
430             break;
431         case 0xf0:  /* lock */
432             break;
433         case 0xf2:  /* repne */
434             repX = 1;
435             break;
436         case 0xf3:  /* repe */
437             repX = 2;
438             break;
439         default:
440             prefix = 0;  /* no more prefixes */
441             break;
442         }
443         if (prefix)
444         {
445             instr++;
446             prefixlen++;
447         }
448     }
449
450     /* Now look at the actual instruction */
451
452     switch(*instr)
453     {
454         case 0x07: /* pop es */
455         case 0x17: /* pop ss */
456         case 0x1f: /* pop ds */
457             {
458                 WORD seg = *(WORD *)get_stack( context );
459                 if (INSTR_ReplaceSelector( context, &seg ))
460                 {
461                     switch(*instr)
462                     {
463                     case 0x07: context->SegEs = seg; break;
464                     case 0x17: context->SegSs = seg; break;
465                     case 0x1f: context->SegDs = seg; break;
466                     }
467                     add_stack(context, long_op ? 4 : 2);
468                     context->Eip += prefixlen + 1;
469                     return TRUE;
470                 }
471             }
472             break;  /* Unable to emulate it */
473
474         case 0x0f: /* extended instruction */
475             switch(instr[1])
476             {
477             case 0x22: /* mov eax, crX */
478                 switch (instr[2]) {
479                 case 0xc0:
480                         ERR("mov eax,cr0 at 0x%08lx, EAX=0x%08lx\n",
481                             context->Eip,context->Eax );
482                         context->Eip += prefixlen+3;
483                         return TRUE;
484                 default:
485                         break; /*fallthrough to bad instruction handling */
486                 }
487                 break; /*fallthrough to bad instruction handling */
488             case 0x20: /* mov crX, eax */
489                 switch (instr[2]) {
490                 case 0xe0: /* mov cr4, eax */
491                     /* CR4 register . See linux/arch/i386/mm/init.c, X86_CR4_ defs
492                      * bit 0: VME       Virtual Mode Exception ?
493                      * bit 1: PVI       Protected mode Virtual Interrupt
494                      * bit 2: TSD       Timestamp disable
495                      * bit 3: DE        Debugging extensions
496                      * bit 4: PSE       Page size extensions
497                      * bit 5: PAE   Physical address extension
498                      * bit 6: MCE       Machine check enable
499                      * bit 7: PGE   Enable global pages
500                      * bit 8: PCE       Enable performance counters at IPL3
501                      */
502                     ERR("mov cr4,eax at 0x%08lx\n",context->Eip);
503                     context->Eax = 0;
504                     context->Eip += prefixlen+3;
505                     return TRUE;
506                 case 0xc0: /* mov cr0, eax */
507                     ERR("mov cr0,eax at 0x%08lx\n",context->Eip);
508                     context->Eax = 0x10; /* FIXME: set more bits ? */
509                     context->Eip += prefixlen+3;
510                     return TRUE;
511                 default: /* fallthrough to illegal instruction */
512                     break;
513                 }
514                 /* fallthrough to illegal instruction */
515                 break;
516             case 0xa1: /* pop fs */
517                 {
518                     WORD seg = *(WORD *)get_stack( context );
519                     if (INSTR_ReplaceSelector( context, &seg ))
520                     {
521                         context->SegFs = seg;
522                         add_stack(context, long_op ? 4 : 2);
523                         context->Eip += prefixlen + 2;
524                         return TRUE;
525                     }
526                 }
527                 break;
528             case 0xa9: /* pop gs */
529                 {
530                     WORD seg = *(WORD *)get_stack( context );
531                     if (INSTR_ReplaceSelector( context, &seg ))
532                     {
533                         context->SegGs = seg;
534                         add_stack(context, long_op ? 4 : 2);
535                         context->Eip += prefixlen + 2;
536                         return TRUE;
537                     }
538                 }
539                 break;
540             case 0xb2: /* lss addr,reg */
541             case 0xb4: /* lfs addr,reg */
542             case 0xb5: /* lgs addr,reg */
543                 if (INSTR_EmulateLDS( context, instr, long_op,
544                                       long_addr, segprefix, &len ))
545                 {
546                     context->Eip += prefixlen + len;
547                     return TRUE;
548                 }
549                 break;
550             }
551             break;  /* Unable to emulate it */
552
553         case 0x6c: /* insb     */
554         case 0x6d: /* insw/d   */
555         case 0x6e: /* outsb    */
556         case 0x6f: /* outsw/d  */
557             {
558               int typ = *instr;  /* Just in case it's overwritten.  */
559               int outp = (typ >= 0x6e);
560               unsigned long count = repX ?
561                           (long_addr ? context->Ecx : LOWORD(context->Ecx)) : 1;
562               int opsize = (typ & 1) ? (long_op ? 4 : 2) : 1;
563               int step = (context->EFlags & 0x400) ? -opsize : +opsize;
564               int seg = outp ? context->SegDs : context->SegEs;  /* FIXME: is this right? */
565
566               if (outp)
567                 /* FIXME: Check segment readable.  */
568                 (void)0;
569               else
570                 /* FIXME: Check segment writeable.  */
571                 (void)0;
572
573               if (repX)
574               {
575                 if (long_addr) context->Ecx = 0;
576                 else SET_LOWORD(context->Ecx,0);
577               }
578
579               while (count-- > 0)
580                 {
581                   void *data;
582                   WORD dx = LOWORD(context->Edx);
583                   if (outp)
584                   {
585                       data = make_ptr( context, seg, context->Esi, long_addr );
586                       if (long_addr) context->Esi += step;
587                       else ADD_LOWORD(context->Esi,step);
588                   }
589                   else
590                   {
591                       data = make_ptr( context, seg, context->Edi, long_addr );
592                       if (long_addr) context->Edi += step;
593                       else ADD_LOWORD(context->Edi,step);
594                   }
595                   
596                   switch (typ)
597                   {
598                     case 0x6c:
599                       *(BYTE *)data = INSTR_inport( dx, 1, context );
600                       break;
601                     case 0x6d:
602                       if (long_op)
603                           *(DWORD *)data = INSTR_inport( dx, 4, context );
604                       else
605                           *(WORD *)data = INSTR_inport( dx, 2, context );
606                       break;
607                     case 0x6e:
608                         INSTR_outport( dx, 1, *(BYTE *)data, context );
609                         break;
610                     case 0x6f:
611                         if (long_op)
612                             INSTR_outport( dx, 4, *(DWORD *)data, context );
613                         else
614                             INSTR_outport( dx, 2, *(WORD *)data, context );
615                         break;
616                     }
617                 }
618               context->Eip += prefixlen + 1;
619             }
620             return TRUE;
621
622         case 0x8e: /* mov XX,segment_reg */
623             {
624                 WORD seg;
625                 BYTE *addr = INSTR_GetOperandAddr(context, instr + 1,
626                                                   long_addr, segprefix, &len );
627                 if (!addr)
628                     break;  /* Unable to emulate it */
629                 seg = *(WORD *)addr;
630                 if (!INSTR_ReplaceSelector( context, &seg ))
631                     break;  /* Unable to emulate it */
632
633                 switch((instr[1] >> 3) & 7)
634                 {
635                 case 0:
636                     context->SegEs = seg;
637                     context->Eip += prefixlen + len + 1;
638                     return TRUE;
639                 case 1:  /* cs */
640                     break;
641                 case 2:
642                     context->SegSs = seg;
643                     context->Eip += prefixlen + len + 1;
644                     return TRUE;
645                 case 3:
646                     context->SegDs = seg;
647                     context->Eip += prefixlen + len + 1;
648                     return TRUE;
649                 case 4:
650                     context->SegFs = seg;
651                     context->Eip += prefixlen + len + 1;
652                     return TRUE;
653                 case 5:
654                     context->SegGs = seg;
655                     context->Eip += prefixlen + len + 1;
656                     return TRUE;
657                 case 6:  /* unused */
658                 case 7:  /* unused */
659                     break;
660                 }
661             }
662             break;  /* Unable to emulate it */
663
664         case 0xc4: /* les addr,reg */
665         case 0xc5: /* lds addr,reg */
666             if (INSTR_EmulateLDS( context, instr, long_op,
667                                   long_addr, segprefix, &len ))
668             {
669                 context->Eip += prefixlen + len;
670                 return TRUE;
671             }
672             break;  /* Unable to emulate it */
673             
674         case 0xcd: /* int <XX> */
675             if (long_op)
676             {
677                 ERR("int xx from 32-bit code is not supported.\n");
678                 break;  /* Unable to emulate it */
679             }
680             else
681             {
682                 FARPROC16 addr = INT_GetPMHandler( instr[1] );
683                 WORD *stack = get_stack( context );
684                 if (!addr)
685                 {
686                     FIXME("no handler for interrupt %02x, ignoring it\n", instr[1]);
687                     context->Eip += prefixlen + 2;
688                     return TRUE;
689                 }
690                 /* Push the flags and return address on the stack */
691                 *(--stack) = LOWORD(context->EFlags);
692                 *(--stack) = context->SegCs;
693                 *(--stack) = LOWORD(context->Eip) + prefixlen + 2;
694                 add_stack(context, -3 * sizeof(WORD));
695                 /* Jump to the interrupt handler */
696                 context->SegCs  = HIWORD(addr);
697                 context->Eip = LOWORD(addr);
698             }
699             return TRUE;
700
701         case 0xcf: /* iret */
702             if (long_op)
703             {
704                 DWORD *stack = get_stack( context );
705                 context->Eip = *stack++;
706                 context->SegCs  = *stack++;
707                 context->EFlags = *stack;
708                 add_stack(context, 3*sizeof(DWORD));  /* Pop the return address and flags */
709             }
710             else
711             {
712                 WORD *stack = get_stack( context );
713                 context->Eip = *stack++;
714                 context->SegCs  = *stack++;
715                 SET_LOWORD(context->EFlags,*stack);
716                 add_stack(context, 3*sizeof(WORD));  /* Pop the return address and flags */
717             }
718             return TRUE;
719
720         case 0xe4: /* inb al,XX */
721             SET_LOBYTE(context->Eax,INSTR_inport( instr[1], 1, context ));
722             context->Eip += prefixlen + 2;
723             return TRUE;
724
725         case 0xe5: /* in (e)ax,XX */
726             if (long_op)
727                 context->Eax = INSTR_inport( instr[1], 4, context );
728             else
729                 SET_LOWORD(context->Eax, INSTR_inport( instr[1], 2, context ));
730             context->Eip += prefixlen + 2;
731             return TRUE;
732
733         case 0xe6: /* outb XX,al */
734             INSTR_outport( instr[1], 1, LOBYTE(context->Eax), context );
735             context->Eip += prefixlen + 2;
736             return TRUE;
737
738         case 0xe7: /* out XX,(e)ax */
739             if (long_op)
740                 INSTR_outport( instr[1], 4, context->Eax, context );
741             else
742                 INSTR_outport( instr[1], 2, LOWORD(context->Eax), context );
743             context->Eip += prefixlen + 2;
744             return TRUE;
745
746         case 0xec: /* inb al,dx */
747             SET_LOBYTE(context->Eax, INSTR_inport( LOWORD(context->Edx), 1, context ) );
748             context->Eip += prefixlen + 1;
749             return TRUE;
750
751         case 0xed: /* in (e)ax,dx */
752             if (long_op)
753                 context->Eax = INSTR_inport( LOWORD(context->Edx), 4, context );
754             else
755                 SET_LOWORD(context->Eax, INSTR_inport( LOWORD(context->Edx), 2, context ));
756             context->Eip += prefixlen + 1;
757             return TRUE;
758
759         case 0xee: /* outb dx,al */
760             INSTR_outport( LOWORD(context->Edx), 1, LOBYTE(context->Eax), context );
761             context->Eip += prefixlen + 1;
762             return TRUE;
763
764         case 0xef: /* out dx,(e)ax */
765             if (long_op)
766                 INSTR_outport( LOWORD(context->Edx), 4, context->Eax, context );
767             else
768                 INSTR_outport( LOWORD(context->Edx), 2, LOWORD(context->Eax), context );
769             context->Eip += prefixlen + 1;
770             return TRUE;
771
772         case 0xfa: /* cli, ignored */
773             context->Eip += prefixlen + 1;
774             return TRUE;
775
776         case 0xfb: /* sti, ignored */
777             context->Eip += prefixlen + 1;
778             return TRUE;
779     }
780
781
782     /* Check for Win16 __GP handler */
783     gpHandler = HasGPHandler16( PTR_SEG_OFF_TO_SEGPTR( context->SegCs, context->Eip ) );
784     if (gpHandler)
785     {
786         WORD *stack = get_stack( context );
787         *--stack = context->SegCs;
788         *--stack = context->Eip;
789         add_stack(context, -2*sizeof(WORD));
790
791         context->SegCs = SELECTOROF( gpHandler );
792         context->Eip   = OFFSETOF( gpHandler );
793         return TRUE;
794     }
795     return FALSE;  /* Unable to emulate it */
796 }
797
798 #endif  /* __i386__ */