1 #ifdef HAVE_XORG_CONFIG_H
2 #include <xorg-config.h>
3 #endif
4 
5 #include <errno.h>
6 #include <string.h>
7 
8 #include "xf86.h"
9 #include "xf86_OSproc.h"
10 #include "xf86Pci.h"
11 #include "compiler.h"
12 #define _INT10_PRIVATE
13 #include "xf86int10.h"
14 
15 #define REG pInt
16 
17 #ifdef _VM86_LINUX
18 #include "int10Defines.h"
19 
20 static int vm86_rep(struct vm86_struct *ptr);
21 static struct vm86_struct vm86_s;
22 
23 Bool
xf86Int10ExecSetup(xf86Int10InfoPtr pInt)24 xf86Int10ExecSetup(xf86Int10InfoPtr pInt)
25 {
26 #define VM86S ((struct vm86_struct *)pInt->cpuRegs)
27 
28     pInt->cpuRegs = &vm86_s;
29     VM86S->flags = 0;
30     VM86S->screen_bitmap = 0;
31     VM86S->cpu_type = CPU_586;
32     memset(&VM86S->int_revectored, 0xff, sizeof(VM86S->int_revectored));
33     memset(&VM86S->int21_revectored, 0xff, sizeof(VM86S->int21_revectored));
34     return TRUE;
35 }
36 
37 /* get the linear address */
38 #define LIN_PREF_SI ((pref_seg << 4) + X86_SI)
39 #define LWECX       ((prefix66 ^ prefix67) ? X86_ECX : X86_CX)
40 #define LWECX_ZERO  {if (prefix66 ^ prefix67) X86_ECX = 0; else X86_CX = 0;}
41 #define DF (1 << 10)
42 
43 /* vm86 fault handling */
44 static Bool
vm86_GP_fault(xf86Int10InfoPtr pInt)45 vm86_GP_fault(xf86Int10InfoPtr pInt)
46 {
47     unsigned char *csp, *lina;
48     CARD32 org_eip;
49     int pref_seg;
50     int done, is_rep, prefix66, prefix67;
51 
52     csp = lina = SEG_ADR((unsigned char *), X86_CS, IP);
53 
54     is_rep = 0;
55     prefix66 = prefix67 = 0;
56     pref_seg = -1;
57 
58     /* eat up prefixes */
59     done = 0;
60     do {
61         switch (MEM_RB(pInt, (int) csp++)) {
62         case 0x66:             /* operand prefix */
63             prefix66 = 1;
64             break;
65         case 0x67:             /* address prefix */
66             prefix67 = 1;
67             break;
68         case 0x2e:             /* CS */
69             pref_seg = X86_CS;
70             break;
71         case 0x3e:             /* DS */
72             pref_seg = X86_DS;
73             break;
74         case 0x26:             /* ES */
75             pref_seg = X86_ES;
76             break;
77         case 0x36:             /* SS */
78             pref_seg = X86_SS;
79             break;
80         case 0x65:             /* GS */
81             pref_seg = X86_GS;
82             break;
83         case 0x64:             /* FS */
84             pref_seg = X86_FS;
85             break;
86         case 0xf0:             /* lock */
87             break;
88         case 0xf2:             /* repnz */
89         case 0xf3:             /* rep */
90             is_rep = 1;
91             break;
92         default:
93             done = 1;
94         }
95     } while (!done);
96     csp--;                      /* oops one too many */
97     org_eip = X86_EIP;
98     X86_IP += (csp - lina);
99 
100     switch (MEM_RB(pInt, (int) csp)) {
101     case 0x6c:                 /* insb */
102         /* NOTE: ES can't be overwritten; prefixes 66,67 should use esi,edi,ecx
103          * but is anyone using extended regs in real mode? */
104         /* WARNING: no test for DI wrapping! */
105         X86_EDI += port_rep_inb(pInt, X86_DX, SEG_EADR((CARD32), X86_ES, DI),
106                                 X86_FLAGS & DF, is_rep ? LWECX : 1);
107         if (is_rep)
108             LWECX_ZERO;
109         X86_IP++;
110         break;
111 
112     case 0x6d:                 /* (rep) insw / insd */
113         /* NOTE: ES can't be overwritten */
114         /* WARNING: no test for _DI wrapping! */
115         if (prefix66) {
116             X86_DI += port_rep_inl(pInt, X86_DX, SEG_ADR((CARD32), X86_ES, DI),
117                                    X86_EFLAGS & DF, is_rep ? LWECX : 1);
118         }
119         else {
120             X86_DI += port_rep_inw(pInt, X86_DX, SEG_ADR((CARD32), X86_ES, DI),
121                                    X86_FLAGS & DF, is_rep ? LWECX : 1);
122         }
123         if (is_rep)
124             LWECX_ZERO;
125         X86_IP++;
126         break;
127 
128     case 0x6e:                 /* (rep) outsb */
129         if (pref_seg < 0)
130             pref_seg = X86_DS;
131         /* WARNING: no test for _SI wrapping! */
132         X86_SI += port_rep_outb(pInt, X86_DX, (CARD32) LIN_PREF_SI,
133                                 X86_FLAGS & DF, is_rep ? LWECX : 1);
134         if (is_rep)
135             LWECX_ZERO;
136         X86_IP++;
137         break;
138 
139     case 0x6f:                 /* (rep) outsw / outsd */
140         if (pref_seg < 0)
141             pref_seg = X86_DS;
142         /* WARNING: no test for _SI wrapping! */
143         if (prefix66) {
144             X86_SI += port_rep_outl(pInt, X86_DX, (CARD32) LIN_PREF_SI,
145                                     X86_EFLAGS & DF, is_rep ? LWECX : 1);
146         }
147         else {
148             X86_SI += port_rep_outw(pInt, X86_DX, (CARD32) LIN_PREF_SI,
149                                     X86_FLAGS & DF, is_rep ? LWECX : 1);
150         }
151         if (is_rep)
152             LWECX_ZERO;
153         X86_IP++;
154         break;
155 
156     case 0xe5:                 /* inw xx, inl xx */
157         if (prefix66)
158             X86_EAX = x_inl(csp[1]);
159         else
160             X86_AX = x_inw(csp[1]);
161         X86_IP += 2;
162         break;
163 
164     case 0xe4:                 /* inb xx */
165         X86_AL = x_inb(csp[1]);
166         X86_IP += 2;
167         break;
168 
169     case 0xed:                 /* inw dx, inl dx */
170         if (prefix66)
171             X86_EAX = x_inl(X86_DX);
172         else
173             X86_AX = x_inw(X86_DX);
174         X86_IP += 1;
175         break;
176 
177     case 0xec:                 /* inb dx */
178         X86_AL = x_inb(X86_DX);
179         X86_IP += 1;
180         break;
181 
182     case 0xe7:                 /* outw xx */
183         if (prefix66)
184             x_outl(csp[1], X86_EAX);
185         else
186             x_outw(csp[1], X86_AX);
187         X86_IP += 2;
188         break;
189 
190     case 0xe6:                 /* outb xx */
191         x_outb(csp[1], X86_AL);
192         X86_IP += 2;
193         break;
194 
195     case 0xef:                 /* outw dx */
196         if (prefix66)
197             x_outl(X86_DX, X86_EAX);
198         else
199             x_outw(X86_DX, X86_AX);
200         X86_IP += 1;
201         break;
202 
203     case 0xee:                 /* outb dx */
204         x_outb(X86_DX, X86_AL);
205         X86_IP += 1;
206         break;
207 
208     case 0xf4:
209         DebugF("hlt at %p\n", lina);
210         return FALSE;
211 
212     case 0x0f:
213         xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR,
214                    "CPU 0x0f Trap at CS:EIP=0x%4.4x:0x%8.8lx\n", X86_CS,
215                    X86_EIP);
216         goto op0ferr;
217 
218     default:
219         xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR, "unknown reason for exception\n");
220 
221  op0ferr:
222         dump_registers(pInt);
223         stack_trace(pInt);
224         dump_code(pInt);
225         xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR, "cannot continue\n");
226         return FALSE;
227     }                           /* end of switch() */
228     return TRUE;
229 }
230 
231 static int
do_vm86(xf86Int10InfoPtr pInt)232 do_vm86(xf86Int10InfoPtr pInt)
233 {
234     int retval;
235 
236     retval = vm86_rep(VM86S);
237 
238     switch (VM86_TYPE(retval)) {
239     case VM86_UNKNOWN:
240         if (!vm86_GP_fault(pInt))
241             return 0;
242         break;
243     case VM86_STI:
244         xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR, "vm86_sti :-((\n");
245         dump_registers(pInt);
246         dump_code(pInt);
247         stack_trace(pInt);
248         return 0;
249     case VM86_INTx:
250         pInt->num = VM86_ARG(retval);
251         if (!int_handler(pInt)) {
252             xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR,
253                        "Unknown vm86_int: 0x%X\n\n", VM86_ARG(retval));
254             dump_registers(pInt);
255             dump_code(pInt);
256             stack_trace(pInt);
257             return 0;
258         }
259         /* I'm not sure yet what to do if we can handle ints */
260         break;
261     case VM86_SIGNAL:
262         return 1;
263         /*
264          * we used to warn here and bail out - but now the sigio stuff
265          * always fires signals at us. So we just ignore them for now.
266          */
267         xf86DrvMsg(pInt->pScrn->scrnIndex, X_WARNING, "received signal\n");
268         return 0;
269     default:
270         xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR, "unknown type(0x%x)=0x%x\n",
271                    VM86_ARG(retval), VM86_TYPE(retval));
272         dump_registers(pInt);
273         dump_code(pInt);
274         stack_trace(pInt);
275         return 0;
276     }
277 
278     return 1;
279 }
280 
281 void
xf86ExecX86int10(xf86Int10InfoPtr pInt)282 xf86ExecX86int10(xf86Int10InfoPtr pInt)
283 {
284     int sig = setup_int(pInt);
285 
286     if (int_handler(pInt))
287         while (do_vm86(pInt)) {
288         };
289 
290     finish_int(pInt, sig);
291 }
292 
293 static int
vm86_rep(struct vm86_struct * ptr)294 vm86_rep(struct vm86_struct *ptr)
295 {
296     int __res;
297 
298 #ifdef __PIC__
299     /* When compiling with -fPIC, we can't use asm constraint "b" because
300        %ebx is already taken by gcc. */
301     __asm__ __volatile__("pushl %%ebx\n\t"
302                          "push %%gs\n\t"
303                          "movl %2,%%ebx\n\t"
304                          "movl %1,%%eax\n\t"
305                          "int $0x80\n\t" "pop %%gs\n\t" "popl %%ebx":"=a"(__res)
306                          :"n"((int) 113), "r"((struct vm86_struct *) ptr));
307 #else
308     __asm__ __volatile__("push %%gs\n\t"
309                          "int $0x80\n\t"
310                          "pop %%gs":"=a"(__res):"a"((int) 113),
311                          "b"((struct vm86_struct *) ptr));
312 #endif
313 
314     if (__res < 0) {
315         errno = -__res;
316         __res = -1;
317     }
318     else
319         errno = 0;
320     return __res;
321 }
322 
323 #endif
324