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