Release 950620
[wine] / miscemu / instr.c
1 /*
2  * Emulation of priviledged instructions
3  *
4  * Copyright 1995 Alexandre Julliard
5  */
6
7 #include <stdio.h>
8 #include "windows.h"
9 #include "dos_fs.h"
10 #include "ldt.h"
11 #include "miscemu.h"
12 #include "registers.h"
13
14
15 static int do_int(int intnum, struct sigcontext_struct *context)
16 {
17         switch(intnum)
18         {
19               case 0x10: return do_int10(context);
20
21               case 0x11:  
22                 AX = DOS_GetEquipment();
23                 return 1;
24
25               case 0x12:               
26                 AX = 640;
27                 return 1;       /* get base mem size */                
28
29               case 0x13: return do_int13(context);
30               case 0x15: return do_int15(context);
31               case 0x16: return do_int16(context);
32               case 0x1a: return do_int1a(context);
33               case 0x21: return do_int21(context);
34
35               case 0x22:
36                 AX = 0x1234;
37                 BX = 0x5678;
38                 CX = 0x9abc;
39                 DX = 0xdef0;
40                 return 1;
41
42               case 0x25: return do_int25(context);
43               case 0x26: return do_int26(context);
44               case 0x2a: return do_int2a(context);
45               case 0x2f: return do_int2f(context);
46               case 0x31: return do_int31(context);
47               case 0x3d: return 1;
48               case 0x5c: return do_int5c(context);
49
50               default:
51                 fprintf(stderr,"int%02x: Unimplemented!\n", intnum);
52                 break;
53         }
54         return 0;
55 }
56
57
58 /***********************************************************************
59  *           INSTR_EmulateInstruction
60  *
61  * Emulate a priviledged instruction. Returns TRUE if emulation successful.
62  */
63 BOOL INSTR_EmulateInstruction( struct sigcontext_struct *context )
64 {
65     int prefix, segprefix, long_op, long_addr;
66     BYTE *instr = (BYTE *) PTR_SEG_OFF_TO_LIN( CS, IP );
67
68     /* First handle any possible prefix */
69
70     long_op = long_addr = (GET_SEL_FLAGS(CS) & LDT_FLAGS_32BIT) != 0;
71     segprefix = 0;  /* no prefix */
72     prefix = 1;
73     while(prefix)
74     {
75         switch(*instr)
76         {
77         case 0x2e:
78             segprefix = 1;  /* CS */
79             break;
80         case 0x36:
81             segprefix = 2;  /* SS */
82             break;
83         case 0x3e:
84             segprefix = 3;  /* DS */
85             break;
86         case 0x26:
87             segprefix = 4;  /* ES */
88             break;
89         case 0x64:
90             segprefix = 5;  /* FS */
91             break;
92         case 0x65:
93             segprefix = 6;  /* GS */
94             break;
95         case 0x66:
96             long_op = !long_op;  /* opcode size prefix */
97             break;
98         case 0x67:
99             long_addr = !long_addr;  /* addr size prefix */
100             break;
101         default:
102             prefix = 0;  /* no more prefixes */
103             break;
104         }
105         if (prefix)
106         {
107             instr++;
108             EIP++;
109         }
110     }
111
112     /* Now look at the actual instruction */
113
114     switch(*instr)
115     {
116       case 0xcd: /* int <XX> */
117             instr++;
118             if (!do_int(*instr, context))
119             {
120                 fprintf(stderr,"Unexpected Windows interrupt %x\n", *instr);
121                 return FALSE;
122             }
123             EIP += 2;  /* Bypass the int instruction */
124             break;
125
126       case 0xcf: /* iret */
127             if (long_op)
128             {
129                 /* FIXME: should check the stack 'big' bit */
130                 DWORD *stack = (WORD *)PTR_SEG_OFF_TO_LIN( SS, SP );
131                 EIP = *stack++;
132                 CS  = *stack++;
133                 EFL = *stack;
134                 SP += 3*sizeof(DWORD);  /* Pop the return address and flags */
135             }
136             else
137             {
138                 /* FIXME: should check the stack 'big' bit */
139                 WORD *stack = (WORD *)PTR_SEG_OFF_TO_LIN( SS, SP );
140                 EIP = *stack++;
141                 CS  = *stack++;
142                 EFL = (EFL & 0xffff0000) | *stack;
143                 SP += 3*sizeof(WORD);  /* Pop the return address and flags */
144             }
145             break;
146
147       case 0xe4: /* inb al,XX */
148             inportb_abs(context);
149             EIP += 2;
150             break;
151
152       case 0xe5: /* in ax,XX */
153             inport_abs( context, long_op );
154             EIP += 2;
155             break;
156
157       case 0xe6: /* outb XX,al */
158             outportb_abs(context);
159             EIP += 2;
160             break;
161
162       case 0xe7: /* out XX,ax */
163             outport_abs( context, long_op );
164             EIP += 2;
165             break;
166
167       case 0xec: /* inb al,dx */
168             inportb(context);
169             EIP++;
170             break;
171
172       case 0xed: /* in ax,dx */
173             inport( context, long_op );
174             EIP++;  
175             break;
176
177       case 0xee: /* outb dx,al */
178             outportb(context);
179             EIP++;
180             break;
181       
182       case 0xef: /* out dx,ax */
183             outport( context, long_op );
184             EIP++;
185             break;
186
187       case 0xfa: /* cli, ignored */
188             EIP++;
189             break;
190
191       case 0xfb: /* sti, ignored */
192             EIP++;
193             break;
194
195       default:
196             fprintf(stderr, "Unexpected Windows program segfault"
197                             " - opcode = %x\n", *instr);
198             return FALSE;  /* Unable to emulate it */
199     }
200     return TRUE;
201 }