Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / xfree86 / os-support / linux / int10 / vm86 / linux_vm86.c
CommitLineData
a09e091a
JB
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
20static int vm86_rep(struct vm86_struct *ptr);
21static struct vm86_struct vm86_s;
22
23Bool
24xf86Int10ExecSetup(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 */
44static Bool
45vm86_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
231static int
232do_vm86(xf86Int10InfoPtr pInt)
233{
234 int retval, signo;
235
236 xf86InterceptSignals(&signo);
237 retval = vm86_rep(VM86S);
238 xf86InterceptSignals(NULL);
239
240 if (signo >= 0) {
241 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR,
242 "vm86() syscall generated signal %d.\n", signo);
243 dump_registers(pInt);
244 dump_code(pInt);
245 stack_trace(pInt);
246 return 0;
247 }
248
249 switch (VM86_TYPE(retval)) {
250 case VM86_UNKNOWN:
251 if (!vm86_GP_fault(pInt))
252 return 0;
253 break;
254 case VM86_STI:
255 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR, "vm86_sti :-((\n");
256 dump_registers(pInt);
257 dump_code(pInt);
258 stack_trace(pInt);
259 return 0;
260 case VM86_INTx:
261 pInt->num = VM86_ARG(retval);
262 if (!int_handler(pInt)) {
263 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR,
264 "Unknown vm86_int: 0x%X\n\n", VM86_ARG(retval));
265 dump_registers(pInt);
266 dump_code(pInt);
267 stack_trace(pInt);
268 return 0;
269 }
270 /* I'm not sure yet what to do if we can handle ints */
271 break;
272 case VM86_SIGNAL:
273 return 1;
274 /*
275 * we used to warn here and bail out - but now the sigio stuff
276 * always fires signals at us. So we just ignore them for now.
277 */
278 xf86DrvMsg(pInt->pScrn->scrnIndex, X_WARNING, "received signal\n");
279 return 0;
280 default:
281 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR, "unknown type(0x%x)=0x%x\n",
282 VM86_ARG(retval), VM86_TYPE(retval));
283 dump_registers(pInt);
284 dump_code(pInt);
285 stack_trace(pInt);
286 return 0;
287 }
288
289 return 1;
290}
291
292void
293xf86ExecX86int10(xf86Int10InfoPtr pInt)
294{
295 int sig = setup_int(pInt);
296
297 if (int_handler(pInt))
298 while (do_vm86(pInt)) {
299 };
300
301 finish_int(pInt, sig);
302}
303
304static int
305vm86_rep(struct vm86_struct *ptr)
306{
307 int __res;
308
309#ifdef __PIC__
310 /* When compiling with -fPIC, we can't use asm constraint "b" because
311 %ebx is already taken by gcc. */
312 __asm__ __volatile__("pushl %%ebx\n\t"
313 "push %%gs\n\t"
314 "movl %2,%%ebx\n\t"
315 "movl %1,%%eax\n\t"
316 "int $0x80\n\t" "pop %%gs\n\t" "popl %%ebx":"=a"(__res)
317 :"n"((int) 113), "r"((struct vm86_struct *) ptr));
318#else
319 __asm__ __volatile__("push %%gs\n\t"
320 "int $0x80\n\t"
321 "pop %%gs":"=a"(__res):"a"((int) 113),
322 "b"((struct vm86_struct *) ptr));
323#endif
324
325 if (__res < 0) {
326 errno = -__res;
327 __res = -1;
328 }
329 else
330 errno = 0;
331 return __res;
332}
333
334#endif