]>
Commit | Line | Data |
---|---|---|
93afd047 MT |
1 | /* |
2 | * Copyright 1999 Egbert Eich | |
3 | * | |
4 | * Permission to use, copy, modify, distribute, and sell this software and its | |
5 | * documentation for any purpose is hereby granted without fee, provided that | |
6 | * the above copyright notice appear in all copies and that both that | |
7 | * copyright notice and this permission notice appear in supporting | |
8 | * documentation, and that the name of the authors not be used in | |
9 | * advertising or publicity pertaining to distribution of the software without | |
10 | * specific, written prior permission. The authors makes no representations | |
11 | * about the suitability of this software for any purpose. It is provided | |
12 | * "as is" without express or implied warranty. | |
13 | * | |
14 | * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | |
15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | |
16 | * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR | |
17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | |
18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | |
19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | |
20 | * PERFORMANCE OF THIS SOFTWARE. | |
21 | */ | |
22 | ||
23 | #include <unistd.h> | |
24 | #include <errno.h> | |
25 | #include <asm/unistd.h> | |
26 | #include <stdio.h> | |
27 | #include <string.h> | |
28 | #ifdef __i386__ | |
29 | #include <sys/vm86.h> | |
30 | #else | |
31 | #include "vm86_struct.h" | |
32 | #endif | |
33 | #include <signal.h> | |
34 | #include "v86bios.h" | |
35 | #include "AsmMacros.h" | |
36 | ||
37 | extern int emu_vm86(struct vm86_struct *vm, unsigned debug); | |
38 | ||
39 | #define INT2PTR(a) ((a) + (unsigned char *) 0) | |
40 | ||
41 | void log_err(char *format, ...) __attribute__ ((format (printf, 1, 2))); | |
42 | ||
43 | struct vm86_struct vm86s; | |
44 | ||
45 | static int vm86_GP_fault(void); | |
46 | static int vm86_do_int(int num); | |
47 | #ifdef __i386__ | |
48 | static int vm86_rep(struct vm86_struct *ptr); | |
49 | #endif | |
50 | void log_registers(void); | |
51 | ||
52 | #define CPU_REG(x) (vm86s.regs.x) | |
53 | #define CPU_REG_LW(reg) (*((CARD16 *)&CPU_REG(reg))) | |
54 | #define CPU_REG_HW(reg) (*((CARD16 *)&CPU_REG(reg) + 1)) | |
55 | #define CPU_REG_LB(reg) (*(CARD8 *)&CPU_REG(e##reg)) | |
56 | #define SEG_ADR(type, seg, reg) type((CPU_REG_LW(seg) << 4) + CPU_REG_LW(e##reg) + (unsigned char *) 0) | |
57 | #define DF (1 << 10) | |
58 | ||
59 | struct pio P; | |
60 | ||
61 | void | |
62 | setup_io(void) | |
63 | { | |
64 | P.inb = (CARD8(*)(CARD16))inb; | |
65 | P.inw = (CARD16(*)(CARD16))inw; | |
66 | P.inl = (CARD32(*)(CARD16))inl; | |
67 | P.outb = (void(*)(CARD16,CARD8))outb; | |
68 | P.outw = (void(*)(CARD16,CARD16))outw; | |
69 | P.outl = (void(*)(CARD16,CARD32))outl; | |
70 | } | |
71 | ||
72 | ||
73 | static void | |
74 | setup_vm86(unsigned long bios_start, i86biosRegsPtr regs) | |
75 | { | |
76 | CARD32 eip; | |
77 | CARD16 cs; | |
78 | ||
79 | vm86s.flags = VM86_SCREEN_BITMAP; | |
80 | vm86s.flags = 0; | |
81 | vm86s.screen_bitmap = 0; | |
82 | vm86s.cpu_type = CPU_586; | |
83 | memset(&vm86s.int_revectored, 0xff,sizeof(vm86s.int_revectored)) ; | |
84 | memset(&vm86s.int21_revectored, 0xff,sizeof(vm86s.int21_revectored)) ; | |
85 | ||
86 | eip = bios_start & 0xFFFF; | |
87 | cs = (bios_start & 0xFF0000) >> 4; | |
88 | ||
89 | CPU_REG(eax) = regs->ax; | |
90 | CPU_REG(ebx) = regs->bx; | |
91 | CPU_REG(ecx) = regs->cx; | |
92 | CPU_REG(edx) = regs->dx; | |
93 | CPU_REG(esi) = 0; | |
94 | CPU_REG(edi) = regs->di; | |
95 | CPU_REG(ebp) = 0; | |
96 | CPU_REG(eip) = eip; | |
97 | CPU_REG(cs) = cs; | |
98 | CPU_REG(esp) = 0x100; | |
99 | CPU_REG(ss) = 0x30; /* This is the standard pc bios stack */ | |
100 | CPU_REG(es) = regs->es; | |
101 | CPU_REG(ds) = 0x40; /* standard pc ds */ | |
102 | CPU_REG(fs) = 0; | |
103 | CPU_REG(gs) = 0; | |
104 | CPU_REG(eflags) |= (VIF_MASK | VIP_MASK); | |
105 | } | |
106 | ||
107 | void | |
108 | collect_bios_regs(i86biosRegsPtr regs) | |
109 | { | |
110 | regs->ax = CPU_REG(eax); | |
111 | regs->bx = CPU_REG(ebx); | |
112 | regs->cx = CPU_REG(ecx); | |
113 | regs->dx = CPU_REG(edx); | |
114 | regs->es = CPU_REG(es); | |
115 | regs->ds = CPU_REG(ds); | |
116 | regs->di = CPU_REG(edi); | |
117 | regs->si = CPU_REG(esi); | |
118 | } | |
119 | ||
120 | static int do_vm86(int cpuemu) | |
121 | { | |
122 | int retval; | |
123 | ||
124 | #ifdef V86BIOS_DEBUG | |
125 | dump_registers(); | |
126 | #endif | |
127 | ||
128 | #ifdef __i386__ | |
129 | if(cpuemu) { | |
130 | retval = emu_vm86(&vm86s, cpuemu & 2); | |
131 | } | |
132 | else { | |
133 | retval = vm86_rep(&vm86s); | |
134 | } | |
135 | #else | |
136 | retval = emu_vm86(&vm86s, cpuemu & 2); | |
137 | #endif | |
138 | ||
139 | switch (VM86_TYPE(retval)) { | |
140 | case VM86_UNKNOWN: | |
141 | if (!vm86_GP_fault()) | |
142 | return 0; | |
143 | break; | |
144 | case VM86_STI: | |
145 | log_err("vm86_sti :-((\n"); | |
146 | log_registers(); | |
147 | return 0; | |
148 | case VM86_INTx: | |
149 | if (!vm86_do_int(VM86_ARG(retval))) { | |
150 | log_err("Unknown vm86_int: %X\n",VM86_ARG(retval)); | |
151 | log_registers(); | |
152 | return 0; | |
153 | } | |
154 | /* I'm not sure yet what to do if we can handle ints */ | |
155 | break; | |
156 | case VM86_SIGNAL: | |
157 | log_err("VBE: received a signal!\n"); | |
158 | log_registers(); | |
159 | return 0; | |
160 | default: | |
161 | log_err("unknown type(0x%x)=0x%x\n", | |
162 | VM86_ARG(retval),VM86_TYPE(retval)); | |
163 | log_registers(); | |
164 | return 0; | |
165 | } | |
166 | ||
167 | return 1; | |
168 | } | |
169 | ||
170 | void | |
171 | do_x86(unsigned long bios_start, i86biosRegsPtr regs, int cpuemu) | |
172 | { | |
173 | setup_vm86(bios_start, regs); | |
174 | while(do_vm86(cpuemu)) {}; | |
175 | collect_bios_regs(regs); | |
176 | } | |
177 | ||
178 | /* get the linear address */ | |
179 | #define LIN_PREF_SI ((pref_seg << 4) + CPU_REG_LW(esi)) | |
180 | ||
181 | #define LWECX (prefix66 ^ prefix67 ? CPU_REG(ecx) : CPU_REG_LW(ecx)) | |
c5568d64 | 182 | #define SET_LWECX_ZERO (prefix66 ^ prefix67 ? (CPU_REG(ecx) = 0) : (CPU_REG_LW(ecx) = 0)) |
93afd047 MT |
183 | |
184 | static int | |
185 | vm86_GP_fault(void) | |
186 | { | |
187 | unsigned char *csp, *lina; | |
188 | CARD32 org_eip; | |
189 | int pref_seg; | |
190 | int done,is_rep,prefix66,prefix67; | |
191 | ||
192 | ||
193 | csp = lina = SEG_ADR((unsigned char *), cs, ip); | |
194 | #ifdef V86BIOS_DEBUG | |
195 | printf("exception: \n"); | |
196 | dump_code(); | |
197 | #endif | |
198 | ||
199 | is_rep = 0; | |
200 | prefix66 = prefix67 = 0; | |
201 | pref_seg = -1; | |
202 | ||
203 | /* eat up prefixes */ | |
204 | done = 0; | |
205 | do { | |
206 | switch (*(csp++)) { | |
207 | case 0x66: /* operand prefix */ prefix66=1; break; | |
208 | case 0x67: /* address prefix */ prefix67=1; break; | |
209 | case 0x2e: /* CS */ pref_seg=CPU_REG(cs); break; | |
210 | case 0x3e: /* DS */ pref_seg=CPU_REG(ds); break; | |
211 | case 0x26: /* ES */ pref_seg=CPU_REG(es); break; | |
212 | case 0x36: /* SS */ pref_seg=CPU_REG(ss); break; | |
213 | case 0x65: /* GS */ pref_seg=CPU_REG(gs); break; | |
214 | case 0x64: /* FS */ pref_seg=CPU_REG(fs); break; | |
215 | case 0xf2: /* repnz */ | |
216 | case 0xf3: /* rep */ is_rep=1; break; | |
217 | default: done=1; | |
218 | } | |
219 | } while (!done); | |
220 | csp--; /* oops one too many */ | |
221 | org_eip = CPU_REG(eip); | |
222 | CPU_REG_LW(eip) += (csp - lina); | |
223 | ||
224 | switch (*csp) { | |
225 | ||
226 | case 0x6c: /* insb */ | |
227 | /* NOTE: ES can't be overwritten; prefixes 66,67 should use esi,edi,ecx | |
228 | * but is anyone using extended regs in real mode? */ | |
229 | /* WARNING: no test for DI wrapping! */ | |
230 | CPU_REG_LW(edi) += port_rep_inb(CPU_REG_LW(edx), | |
231 | SEG_ADR((CARD8 *),es,di), | |
232 | CPU_REG_LW(eflags)&DF, | |
233 | (is_rep? LWECX:1)); | |
c5568d64 | 234 | if (is_rep) SET_LWECX_ZERO; |
93afd047 MT |
235 | CPU_REG_LW(eip)++; |
236 | break; | |
237 | ||
238 | case 0x6d: /* (rep) insw / insd */ | |
239 | /* NOTE: ES can't be overwritten */ | |
240 | /* WARNING: no test for _DI wrapping! */ | |
241 | if (prefix66) { | |
242 | CPU_REG_LW(edi) += port_rep_inl(CPU_REG_LW(edx), | |
243 | SEG_ADR((CARD32 *),es,di), | |
244 | CPU_REG_LW(eflags)&DF, | |
245 | (is_rep? LWECX:1)); | |
246 | } | |
247 | else { | |
248 | CPU_REG_LW(edi) += port_rep_inw(CPU_REG_LW(edx), | |
249 | SEG_ADR((CARD16 *),es,di), | |
250 | CPU_REG_LW(eflags)&DF, | |
251 | (is_rep? LWECX:1)); | |
252 | } | |
c5568d64 | 253 | if (is_rep) SET_LWECX_ZERO; |
93afd047 MT |
254 | CPU_REG_LW(eip)++; |
255 | break; | |
256 | ||
257 | case 0x6e: /* (rep) outsb */ | |
258 | if (pref_seg < 0) pref_seg = CPU_REG_LW(ds); | |
259 | /* WARNING: no test for _SI wrapping! */ | |
260 | CPU_REG_LW(esi) += port_rep_outb(CPU_REG_LW(edx),(CARD8*)INT2PTR(LIN_PREF_SI), | |
261 | CPU_REG_LW(eflags)&DF, | |
262 | (is_rep? LWECX:1)); | |
c5568d64 | 263 | if (is_rep) SET_LWECX_ZERO; |
93afd047 MT |
264 | CPU_REG_LW(eip)++; |
265 | break; | |
266 | ||
267 | case 0x6f: /* (rep) outsw / outsd */ | |
268 | if (pref_seg < 0) pref_seg = CPU_REG_LW(ds); | |
269 | /* WARNING: no test for _SI wrapping! */ | |
270 | if (prefix66) { | |
271 | CPU_REG_LW(esi) += port_rep_outl(CPU_REG_LW(edx), | |
272 | (CARD32 *)INT2PTR(LIN_PREF_SI), | |
273 | CPU_REG_LW(eflags)&DF, | |
274 | (is_rep? LWECX:1)); | |
275 | } | |
276 | else { | |
277 | CPU_REG_LW(esi) += port_rep_outw(CPU_REG_LW(edx), | |
278 | (CARD16 *)INT2PTR(LIN_PREF_SI), | |
279 | CPU_REG_LW(eflags)&DF, | |
280 | (is_rep? LWECX:1)); | |
281 | } | |
c5568d64 | 282 | if (is_rep) SET_LWECX_ZERO; |
93afd047 MT |
283 | CPU_REG_LW(eip)++; |
284 | break; | |
285 | ||
286 | case 0xe5: /* inw xx, inl xx */ | |
287 | if (prefix66) CPU_REG(eax) = P.inl((int) csp[1]); | |
288 | else CPU_REG_LW(eax) = P.inw((int) csp[1]); | |
289 | CPU_REG_LW(eip) += 2; | |
290 | break; | |
291 | case 0xe4: /* inb xx */ | |
292 | CPU_REG_LW(eax) &= ~(CARD32)0xff; | |
293 | CPU_REG_LB(ax) |= P.inb((int) csp[1]); | |
294 | CPU_REG_LW(eip) += 2; | |
295 | break; | |
296 | case 0xed: /* inw dx, inl dx */ | |
297 | if (prefix66) CPU_REG(eax) = P.inl(CPU_REG_LW(edx)); | |
298 | else CPU_REG_LW(eax) = P.inw(CPU_REG_LW(edx)); | |
299 | CPU_REG_LW(eip) += 1; | |
300 | break; | |
301 | case 0xec: /* inb dx */ | |
302 | CPU_REG_LW(eax) &= ~(CARD32)0xff; | |
303 | CPU_REG_LB(ax) |= P.inb(CPU_REG_LW(edx)); | |
304 | CPU_REG_LW(eip) += 1; | |
305 | break; | |
306 | ||
307 | case 0xe7: /* outw xx */ | |
308 | if (prefix66) P.outl((int)csp[1], CPU_REG(eax)); | |
309 | else P.outw((int)csp[1], CPU_REG_LW(eax)); | |
310 | CPU_REG_LW(eip) += 2; | |
311 | break; | |
312 | case 0xe6: /* outb xx */ | |
313 | P.outb((int) csp[1], CPU_REG_LB(ax)); | |
314 | CPU_REG_LW(eip) += 2; | |
315 | break; | |
316 | case 0xef: /* outw dx */ | |
317 | if (prefix66) P.outl(CPU_REG_LW(edx), CPU_REG(eax)); | |
318 | else P.outw(CPU_REG_LW(edx), CPU_REG_LW(eax)); | |
319 | CPU_REG_LW(eip) += 1; | |
320 | break; | |
321 | case 0xee: /* outb dx */ | |
322 | P.outb(CPU_REG_LW(edx), CPU_REG_LB(ax)); | |
323 | CPU_REG_LW(eip) += 1; | |
324 | break; | |
325 | ||
326 | case 0xf4: | |
327 | #ifdef V86BIOS_DEBUG | |
328 | printf("hlt at %p\n", lina); | |
329 | #endif | |
330 | return 0; | |
331 | ||
332 | case 0x0f: | |
333 | log_err("CPU 0x0f Trap at eip=0x%lx\n",CPU_REG(eip)); | |
334 | goto op0ferr; | |
335 | break; | |
336 | ||
337 | case 0xf0: /* lock */ | |
338 | default: | |
339 | log_err("unknown reason for exception\n"); | |
340 | log_registers(); | |
341 | op0ferr: | |
342 | log_err("cannot continue\n"); | |
343 | return 0; | |
344 | } /* end of switch() */ | |
345 | return 1; | |
346 | } | |
347 | ||
348 | static int | |
349 | vm86_do_int(int num) | |
350 | { | |
351 | int val; | |
352 | struct regs86 regs; | |
353 | ||
354 | /* try to run bios interrupt */ | |
355 | ||
356 | /* if not installed fall back */ | |
357 | #define COPY(x) regs.x = CPU_REG(x) | |
358 | #define COPY_R(x) CPU_REG(x) = regs.x | |
359 | ||
360 | COPY(eax); | |
361 | COPY(ebx); | |
362 | COPY(ecx); | |
363 | COPY(edx); | |
364 | COPY(esi); | |
365 | COPY(edi); | |
366 | COPY(ebp); | |
367 | COPY(eip); | |
368 | COPY(esp); | |
369 | COPY(cs); | |
370 | COPY(ss); | |
371 | COPY(ds); | |
372 | COPY(es); | |
373 | COPY(fs); | |
374 | COPY(gs); | |
375 | COPY(eflags); | |
376 | ||
377 | if (!(val = int_handler(num,®s))) | |
378 | if (!(val = run_bios_int(num,®s))) | |
379 | return val; | |
380 | ||
381 | COPY_R(eax); | |
382 | COPY_R(ebx); | |
383 | COPY_R(ecx); | |
384 | COPY_R(edx); | |
385 | COPY_R(esi); | |
386 | COPY_R(edi); | |
387 | COPY_R(ebp); | |
388 | COPY_R(eip); | |
389 | COPY_R(esp); | |
390 | COPY_R(cs); | |
391 | COPY_R(ss); | |
392 | COPY_R(ds); | |
393 | COPY_R(es); | |
394 | COPY_R(fs); | |
395 | COPY_R(gs); | |
396 | COPY_R(eflags); | |
397 | ||
398 | return val; | |
399 | #undef COPY | |
400 | #undef COPY_R | |
401 | } | |
402 | ||
403 | #ifdef __i386__ | |
404 | ||
405 | static int | |
406 | vm86_rep(struct vm86_struct *ptr) | |
407 | { | |
408 | ||
409 | int __res; | |
410 | ||
411 | /* stay away from %ebx */ | |
412 | __asm__ __volatile__("push %%ebx\n\tmov %%ecx,%%ebx\n\tpush %%gs\n\tint $0x80\n\tpop %%gs\n\tpop %%ebx\n" | |
413 | :"=a" (__res):"a" ((int)113), | |
414 | "c" ((struct vm86_struct *)ptr)); | |
415 | ||
416 | if ((__res) < 0) { | |
417 | errno = -__res; | |
418 | __res=-1; | |
419 | } | |
420 | else errno = 0; | |
421 | return __res; | |
422 | } | |
423 | ||
424 | #endif | |
425 | ||
426 | #ifdef __i386__ | |
427 | ||
428 | #define pushw(base, ptr, val) \ | |
429 | __asm__ __volatile__( \ | |
430 | "decw %w0\n\t" \ | |
431 | "movb %h2,(%1,%0)\n\t" \ | |
432 | "decw %w0\n\t" \ | |
433 | "movb %b2,(%1,%0)" \ | |
434 | : "=r" (ptr) \ | |
435 | : "r" (base), "q" (val), "0" (ptr)) | |
436 | ||
437 | #else | |
438 | ||
439 | #define pushw(base, ptr, val) { \ | |
440 | ptr = ((ptr) - 1) & 0xffff; \ | |
441 | *((unsigned char *)(base) + (ptr)) = (val) >> 8; \ | |
442 | ptr = ((ptr) - 1) & 0xffff; \ | |
443 | *((unsigned char *)(base) + (ptr)) = (val); \ | |
444 | } | |
445 | ||
446 | #endif | |
447 | ||
448 | int | |
449 | run_bios_int(int num, struct regs86 *regs) | |
450 | { | |
451 | CARD16 *ssp; | |
452 | CARD32 sp; | |
453 | CARD32 eflags; | |
454 | ||
455 | #ifdef V86BIOS_DEBUG | |
456 | static int firsttime = 1; | |
457 | #endif | |
458 | /* check if bios vector is initialized */ | |
459 | if (((CARD16*)0)[(num<<1)+1] == 0x0000) { /* SYS_BIOS_SEG ?*/ | |
460 | return 0; | |
461 | } | |
462 | ||
463 | #ifdef V86BIOS_DEBUG | |
464 | if (firsttime) { | |
465 | dprint(0,0x3D0); | |
466 | firsttime = 0; | |
467 | } | |
468 | #endif | |
469 | ||
470 | ssp = (CARD16*)INT2PTR(CPU_REG(ss)<<4); | |
471 | sp = (CARD32) CPU_REG_LW(esp); | |
472 | ||
473 | eflags = regs->eflags; | |
474 | eflags = ((eflags & VIF_MASK) != 0) | |
475 | ? (eflags | IF_MASK) : (eflags & ~(CARD32) IF_MASK); | |
476 | pushw(ssp, sp, eflags); | |
477 | pushw(ssp, sp, regs->cs); | |
478 | pushw(ssp, sp, (CARD16)regs->eip); | |
479 | regs->esp -= 6; | |
480 | regs->cs = ((CARD16 *) 0)[(num << 1) + 1]; | |
481 | regs->eip = (regs->eip & 0xFFFF0000) | ((CARD16 *) 0)[num << 1]; | |
482 | #ifdef V86BIOS_DEBUG | |
483 | dump_code(); | |
484 | #endif | |
485 | regs->eflags = regs->eflags | |
486 | & ~(VIF_MASK | TF_MASK | IF_MASK | NT_MASK); | |
487 | return 1; | |
488 | } | |
489 | ||
490 | CARD32 | |
491 | getIntVect(int num) | |
492 | { | |
493 | return ((CARD32*)0)[num]; | |
494 | } | |
495 | ||
496 | CARD32 | |
497 | getIP(void) | |
498 | { | |
499 | return (CPU_REG(cs) << 4) + CPU_REG(eip); | |
500 | } | |
501 | ||
502 | void log_registers() | |
503 | { | |
504 | log_err( | |
505 | " eax %08x, ebx %08x, ecx %08x, edx %08x\n" | |
506 | " esi %08x, edi %08x, ebp %08x, esp %08x\n" | |
507 | " ds %04x, es %04x, fs %04x, gs %04x, ss %04x\n" | |
508 | " cs:eip %04x:%08x\n", | |
509 | (unsigned) CPU_REG(eax), (unsigned) CPU_REG(ebx), (unsigned) CPU_REG(ecx), (unsigned) CPU_REG(edx), | |
510 | (unsigned) CPU_REG(esi), (unsigned) CPU_REG(edi), (unsigned) CPU_REG(ebp), (unsigned) CPU_REG(esp), | |
511 | (unsigned) CPU_REG(ds), (unsigned) CPU_REG(es), | |
512 | (unsigned) CPU_REG(fs), (unsigned) CPU_REG(gs), (unsigned) CPU_REG(ss), | |
513 | (unsigned) CPU_REG(cs), (unsigned) CPU_REG(eip) | |
514 | ); | |
515 | } | |
516 |