]>
Commit | Line | Data |
---|---|---|
c7de829c WD |
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 "debug.h" | |
24 | #include <sys/vm86.h> | |
25 | #include <unistd.h> | |
26 | #include <errno.h> | |
27 | #include <asm/unistd.h> | |
28 | #include <stdio.h> | |
29 | #include <string.h> | |
30 | #include <signal.h> | |
31 | #include <setjmp.h> | |
32 | #include "v86bios.h" | |
33 | #include "AsmMacros.h" | |
34 | ||
35 | struct vm86_struct vm86s; | |
36 | ||
37 | static int vm86_GP_fault(void); | |
38 | static int vm86_do_int(int num); | |
39 | static void dump_code(void); | |
40 | static void dump_registers(void); | |
41 | static void stack_trace(void); | |
42 | static int vm86_rep(struct vm86_struct *ptr); | |
43 | ||
44 | #define CPU_REG(x) (vm86s.regs.##x) | |
45 | #define CPU_REG_LW(reg) (*((CARD16 *)&CPU_REG(reg))) | |
46 | #define CPU_REG_HW(reg) (*((CARD16 *)&CPU_REG(reg) + 1)) | |
47 | #define CPU_REG_LB(reg) (*(CARD8 *)&CPU_REG(e##reg)) | |
48 | #define SEG_ADR(type, seg, reg) type((CPU_REG_LW(seg) << 4) \ | |
8bde7f77 | 49 | + CPU_REG_LW(e##reg)) |
c7de829c WD |
50 | #define DF (1 << 10) |
51 | ||
52 | struct pio P; | |
53 | ||
54 | ||
55 | void | |
8bde7f77 | 56 | setup_io(void) |
c7de829c WD |
57 | { |
58 | if (!Config.PrintPort && !Config.IoStatistics) { | |
59 | P.inb = (CARD8(*)(CARD16))inb; | |
60 | P.inw = (CARD16(*)(CARD16))inw; | |
61 | P.inl = (CARD32(*)(CARD16))inl; | |
62 | P.outb = (void(*)(CARD16,CARD8))outb; | |
63 | P.outw = (void(*)(CARD16,CARD16))outw; | |
64 | P.outl = (void(*)(CARD16,CARD32))outl; | |
65 | } else { | |
66 | P.inb = p_inb; | |
67 | P.inw = p_inw; | |
68 | P.inl = p_inl; | |
69 | P.outb = p_outb; | |
70 | P.outw = p_outw; | |
71 | P.outl = p_outl; | |
72 | } | |
73 | } | |
74 | ||
8bde7f77 | 75 | |
c7de829c WD |
76 | static void |
77 | setup_vm86(unsigned long bios_start, i86biosRegsPtr regs) | |
78 | { | |
79 | CARD32 eip; | |
80 | CARD16 cs; | |
8bde7f77 | 81 | |
c7de829c WD |
82 | vm86s.flags = VM86_SCREEN_BITMAP; |
83 | vm86s.flags = 0; | |
84 | vm86s.screen_bitmap = 0; | |
85 | vm86s.cpu_type = CPU_586; | |
86 | memset(&vm86s.int_revectored, 0xff,sizeof(vm86s.int_revectored)) ; | |
87 | memset(&vm86s.int21_revectored, 0xff,sizeof(vm86s.int21_revectored)) ; | |
88 | ||
89 | eip = bios_start & 0xFFFF; | |
90 | cs = (bios_start & 0xFF0000) >> 4; | |
8bde7f77 | 91 | |
c7de829c WD |
92 | CPU_REG(eax) = regs->ax; |
93 | CPU_REG(ebx) = regs->bx; | |
94 | CPU_REG(ecx) = regs->cx; | |
95 | CPU_REG(edx) = regs->dx; | |
96 | CPU_REG(esi) = 0; | |
97 | CPU_REG(edi) = regs->di; | |
98 | CPU_REG(ebp) = 0; | |
99 | CPU_REG(eip) = eip; | |
8bde7f77 | 100 | CPU_REG(cs) = cs; |
c7de829c WD |
101 | CPU_REG(esp) = 0x100; |
102 | CPU_REG(ss) = 0x30; /* This is the standard pc bios stack */ | |
103 | CPU_REG(es) = regs->es; | |
104 | CPU_REG(ds) = 0x40; /* standard pc ds */ | |
105 | CPU_REG(fs) = 0; | |
106 | CPU_REG(gs) = 0; | |
107 | CPU_REG(eflags) |= (VIF_MASK | VIP_MASK); | |
108 | } | |
109 | ||
110 | void | |
111 | collect_bios_regs(i86biosRegsPtr regs) | |
112 | { | |
113 | regs->ax = CPU_REG(eax); | |
114 | regs->bx = CPU_REG(ebx); | |
115 | regs->cx = CPU_REG(ecx); | |
116 | regs->dx = CPU_REG(edx); | |
117 | regs->es = CPU_REG(es); | |
118 | regs->ds = CPU_REG(ds); | |
119 | regs->di = CPU_REG(edi); | |
120 | regs->si = CPU_REG(esi); | |
121 | } | |
122 | ||
123 | static int | |
124 | do_vm86(void) | |
125 | { | |
126 | int retval; | |
8bde7f77 | 127 | |
c7de829c WD |
128 | #ifdef V86BIOS_DEBUG |
129 | dump_registers(); | |
130 | #endif | |
8bde7f77 WD |
131 | /* retval = SYS_vm86old(&vm86s); */ |
132 | /* retval = syscall(SYS_vm86old,&vm86s); */ | |
c7de829c WD |
133 | |
134 | retval = vm86_rep(&vm86s); | |
8bde7f77 | 135 | |
c7de829c WD |
136 | switch (VM86_TYPE(retval)) { |
137 | case VM86_UNKNOWN: | |
8bde7f77 WD |
138 | if (!vm86_GP_fault()) return 0; |
139 | break; | |
c7de829c | 140 | case VM86_STI: |
8bde7f77 WD |
141 | fprintf(stderr,"vm86_sti :-((\n"); |
142 | stack_trace(); | |
143 | dump_code(); | |
144 | return 0; | |
c7de829c | 145 | case VM86_INTx: |
8bde7f77 WD |
146 | if (!vm86_do_int(VM86_ARG(retval))) { |
147 | fprintf(stderr,"\nUnknown vm86_int: %X\n\n",VM86_ARG(retval)); | |
148 | dump_registers(); | |
149 | return 0; | |
150 | } | |
151 | /* I'm not sure yet what to do if we can handle ints */ | |
152 | break; | |
c7de829c | 153 | case VM86_SIGNAL: |
8bde7f77 WD |
154 | fprintf(stderr,"received signal\n"); |
155 | return 0; | |
c7de829c | 156 | default: |
8bde7f77 WD |
157 | fprintf(stderr,"unknown type(0x%x)=0x%x\n", |
158 | VM86_ARG(retval),VM86_TYPE(retval)); | |
159 | dump_registers(); | |
160 | dump_code(); | |
161 | stack_trace(); | |
162 | return 0; | |
c7de829c | 163 | } |
8bde7f77 | 164 | |
c7de829c WD |
165 | return 1; |
166 | } | |
167 | ||
168 | static jmp_buf x86_esc; | |
169 | static void | |
170 | vmexit(int unused) | |
171 | { | |
172 | longjmp(x86_esc,1); | |
173 | } | |
174 | ||
175 | void | |
176 | do_x86(unsigned long bios_start, i86biosRegsPtr regs) | |
177 | { | |
178 | static void (*org_handler)(int); | |
8bde7f77 | 179 | |
c7de829c WD |
180 | setup_vm86(bios_start, regs); |
181 | if (setjmp(x86_esc) == 0) { | |
8bde7f77 WD |
182 | org_handler = signal(2,vmexit); |
183 | while(do_vm86()) {}; | |
184 | signal(2,org_handler); | |
185 | collect_bios_regs(regs); | |
c7de829c | 186 | } else { |
8bde7f77 WD |
187 | signal(2,org_handler); |
188 | printf("interrupted at 0x%x\n",((CARD16)CPU_REG(cs)) << 4 | |
189 | | (CARD16)CPU_REG(eip)); | |
c7de829c WD |
190 | } |
191 | } | |
192 | ||
193 | /* get the linear address */ | |
194 | #define LIN_PREF_SI ((pref_seg << 4) + CPU_REG_LW(esi)) | |
195 | ||
196 | #define LWECX (prefix66 ^ prefix67 ? CPU_REG(ecx) : CPU_REG_LW(ecx)) | |
197 | ||
198 | static int | |
199 | vm86_GP_fault(void) | |
200 | { | |
201 | unsigned char *csp, *lina; | |
202 | CARD32 org_eip; | |
203 | int pref_seg; | |
204 | int done,is_rep,prefix66,prefix67; | |
205 | ||
206 | ||
207 | csp = lina = SEG_ADR((unsigned char *), cs, ip); | |
208 | #ifdef V86BIOS_DEBUG | |
209 | printf("exception: \n"); | |
210 | dump_code(); | |
211 | #endif | |
212 | ||
213 | is_rep = 0; | |
214 | prefix66 = prefix67 = 0; | |
215 | pref_seg = -1; | |
216 | ||
217 | /* eat up prefixes */ | |
218 | done = 0; | |
219 | do { | |
8bde7f77 WD |
220 | switch (*(csp++)) { |
221 | case 0x66: /* operand prefix */ prefix66=1; break; | |
222 | case 0x67: /* address prefix */ prefix67=1; break; | |
223 | case 0x2e: /* CS */ pref_seg=CPU_REG(cs); break; | |
224 | case 0x3e: /* DS */ pref_seg=CPU_REG(ds); break; | |
225 | case 0x26: /* ES */ pref_seg=CPU_REG(es); break; | |
226 | case 0x36: /* SS */ pref_seg=CPU_REG(ss); break; | |
227 | case 0x65: /* GS */ pref_seg=CPU_REG(gs); break; | |
228 | case 0x64: /* FS */ pref_seg=CPU_REG(fs); break; | |
229 | case 0xf2: /* repnz */ | |
230 | case 0xf3: /* rep */ is_rep=1; break; | |
231 | default: done=1; | |
232 | } | |
c7de829c WD |
233 | } while (!done); |
234 | csp--; /* oops one too many */ | |
235 | org_eip = CPU_REG(eip); | |
236 | CPU_REG_LW(eip) += (csp - lina); | |
237 | ||
238 | switch (*csp) { | |
239 | ||
240 | case 0x6c: /* insb */ | |
8bde7f77 WD |
241 | /* NOTE: ES can't be overwritten; prefixes 66,67 should use esi,edi,ecx |
242 | * but is anyone using extended regs in real mode? */ | |
243 | /* WARNING: no test for DI wrapping! */ | |
244 | CPU_REG_LW(edi) += port_rep_inb(CPU_REG_LW(edx), | |
245 | SEG_ADR((CARD8 *),es,di), | |
246 | CPU_REG_LW(eflags)&DF, | |
247 | (is_rep? LWECX:1)); | |
248 | if (is_rep) LWECX = 0; | |
249 | CPU_REG_LW(eip)++; | |
250 | break; | |
c7de829c WD |
251 | |
252 | case 0x6d: /* (rep) insw / insd */ | |
8bde7f77 WD |
253 | /* NOTE: ES can't be overwritten */ |
254 | /* WARNING: no test for _DI wrapping! */ | |
255 | if (prefix66) { | |
256 | CPU_REG_LW(edi) += port_rep_inl(CPU_REG_LW(edx), | |
257 | SEG_ADR((CARD32 *),es,di), | |
258 | CPU_REG_LW(eflags)&DF, | |
259 | (is_rep? LWECX:1)); | |
260 | } | |
261 | else { | |
262 | CPU_REG_LW(edi) += port_rep_inw(CPU_REG_LW(edx), | |
263 | SEG_ADR((CARD16 *),es,di), | |
264 | CPU_REG_LW(eflags)&DF, | |
265 | (is_rep? LWECX:1)); | |
266 | } | |
267 | if (is_rep) LWECX = 0; | |
268 | CPU_REG_LW(eip)++; | |
269 | break; | |
c7de829c WD |
270 | |
271 | case 0x6e: /* (rep) outsb */ | |
8bde7f77 WD |
272 | if (pref_seg < 0) pref_seg = CPU_REG_LW(ds); |
273 | /* WARNING: no test for _SI wrapping! */ | |
274 | CPU_REG_LW(esi) += port_rep_outb(CPU_REG_LW(edx),(CARD8*)LIN_PREF_SI, | |
275 | CPU_REG_LW(eflags)&DF, | |
276 | (is_rep? LWECX:1)); | |
277 | if (is_rep) LWECX = 0; | |
278 | CPU_REG_LW(eip)++; | |
279 | break; | |
c7de829c WD |
280 | |
281 | case 0x6f: /* (rep) outsw / outsd */ | |
8bde7f77 WD |
282 | if (pref_seg < 0) pref_seg = CPU_REG_LW(ds); |
283 | /* WARNING: no test for _SI wrapping! */ | |
284 | if (prefix66) { | |
285 | CPU_REG_LW(esi) += port_rep_outl(CPU_REG_LW(edx), | |
286 | (CARD32 *)LIN_PREF_SI, | |
287 | CPU_REG_LW(eflags)&DF, | |
288 | (is_rep? LWECX:1)); | |
289 | } | |
290 | else { | |
291 | CPU_REG_LW(esi) += port_rep_outw(CPU_REG_LW(edx), | |
292 | (CARD16 *)LIN_PREF_SI, | |
293 | CPU_REG_LW(eflags)&DF, | |
294 | (is_rep? LWECX:1)); | |
295 | } | |
296 | if (is_rep) LWECX = 0; | |
297 | CPU_REG_LW(eip)++; | |
298 | break; | |
c7de829c WD |
299 | |
300 | case 0xe5: /* inw xx, inl xx */ | |
8bde7f77 WD |
301 | if (prefix66) CPU_REG(eax) = P.inl((int) csp[1]); |
302 | else CPU_REG_LW(eax) = P.inw((int) csp[1]); | |
303 | CPU_REG_LW(eip) += 2; | |
304 | break; | |
c7de829c | 305 | case 0xe4: /* inb xx */ |
8bde7f77 WD |
306 | CPU_REG_LW(eax) &= ~(CARD32)0xff; |
307 | CPU_REG_LB(ax) |= P.inb((int) csp[1]); | |
308 | CPU_REG_LW(eip) += 2; | |
309 | break; | |
c7de829c | 310 | case 0xed: /* inw dx, inl dx */ |
8bde7f77 WD |
311 | if (prefix66) CPU_REG(eax) = P.inl(CPU_REG_LW(edx)); |
312 | else CPU_REG_LW(eax) = P.inw(CPU_REG_LW(edx)); | |
313 | CPU_REG_LW(eip) += 1; | |
314 | break; | |
c7de829c | 315 | case 0xec: /* inb dx */ |
8bde7f77 WD |
316 | CPU_REG_LW(eax) &= ~(CARD32)0xff; |
317 | CPU_REG_LB(ax) |= P.inb(CPU_REG_LW(edx)); | |
318 | CPU_REG_LW(eip) += 1; | |
319 | break; | |
c7de829c WD |
320 | |
321 | case 0xe7: /* outw xx */ | |
8bde7f77 WD |
322 | if (prefix66) P.outl((int)csp[1], CPU_REG(eax)); |
323 | else P.outw((int)csp[1], CPU_REG_LW(eax)); | |
324 | CPU_REG_LW(eip) += 2; | |
325 | break; | |
c7de829c | 326 | case 0xe6: /* outb xx */ |
8bde7f77 WD |
327 | P.outb((int) csp[1], CPU_REG_LB(ax)); |
328 | CPU_REG_LW(eip) += 2; | |
329 | break; | |
c7de829c | 330 | case 0xef: /* outw dx */ |
8bde7f77 WD |
331 | if (prefix66) P.outl(CPU_REG_LW(edx), CPU_REG(eax)); |
332 | else P.outw(CPU_REG_LW(edx), CPU_REG_LW(eax)); | |
333 | CPU_REG_LW(eip) += 1; | |
334 | break; | |
c7de829c | 335 | case 0xee: /* outb dx */ |
8bde7f77 WD |
336 | P.outb(CPU_REG_LW(edx), CPU_REG_LB(ax)); |
337 | CPU_REG_LW(eip) += 1; | |
338 | break; | |
c7de829c WD |
339 | |
340 | case 0xf4: | |
341 | #ifdef V86BIOS_DEBUG | |
8bde7f77 | 342 | printf("hlt at %p\n", lina); |
c7de829c | 343 | #endif |
8bde7f77 | 344 | return 0; |
c7de829c | 345 | |
8bde7f77 WD |
346 | case 0x0f: |
347 | fprintf(stderr,"CPU 0x0f Trap at eip=0x%lx\n",CPU_REG(eip)); | |
348 | goto op0ferr; | |
349 | break; | |
c7de829c WD |
350 | |
351 | case 0xf0: /* lock */ | |
352 | default: | |
8bde7f77 WD |
353 | fprintf(stderr,"unknown reason for exception\n"); |
354 | dump_registers(); | |
355 | stack_trace(); | |
c7de829c | 356 | op0ferr: |
8bde7f77 WD |
357 | dump_code(); |
358 | fprintf(stderr,"cannot continue\n"); | |
359 | return 0; | |
c7de829c WD |
360 | } /* end of switch() */ |
361 | return 1; | |
362 | } | |
363 | ||
364 | static int | |
365 | vm86_do_int(int num) | |
366 | { | |
367 | int val; | |
368 | struct regs86 regs; | |
369 | ||
370 | i_printf("int 0x%x received: ax:0x%lx",num,CPU_REG(eax)); | |
371 | if (Config.PrintIp) | |
8bde7f77 | 372 | i_printf(" at: 0x%x\n",getIP()); |
c7de829c | 373 | else |
8bde7f77 | 374 | i_printf("\n"); |
c7de829c WD |
375 | |
376 | /* try to run bios interrupt */ | |
8bde7f77 | 377 | |
c7de829c WD |
378 | /* if not installed fall back */ |
379 | #define COPY(x) regs.##x = CPU_REG(x) | |
380 | #define COPY_R(x) CPU_REG(x) = regs.##x | |
8bde7f77 | 381 | |
c7de829c WD |
382 | COPY(eax); |
383 | COPY(ebx); | |
384 | COPY(ecx); | |
385 | COPY(edx); | |
386 | COPY(esi); | |
387 | COPY(edi); | |
388 | COPY(ebp); | |
389 | COPY(eip); | |
390 | COPY(esp); | |
391 | COPY(cs); | |
392 | COPY(ss); | |
393 | COPY(ds); | |
394 | COPY(es); | |
395 | COPY(fs); | |
396 | COPY(gs); | |
397 | COPY(eflags); | |
398 | ||
399 | if (!(val = int_handler(num,®s))) | |
8bde7f77 WD |
400 | if (!(val = run_bios_int(num,®s))) |
401 | return val; | |
402 | ||
c7de829c WD |
403 | COPY_R(eax); |
404 | COPY_R(ebx); | |
405 | COPY_R(ecx); | |
406 | COPY_R(edx); | |
407 | COPY_R(esi); | |
408 | COPY_R(edi); | |
409 | COPY_R(ebp); | |
410 | COPY_R(eip); | |
411 | COPY_R(esp); | |
412 | COPY_R(cs); | |
413 | COPY_R(ss); | |
414 | COPY_R(ds); | |
415 | COPY_R(es); | |
416 | COPY_R(fs); | |
417 | COPY_R(gs); | |
418 | COPY_R(eflags); | |
419 | ||
420 | return val; | |
421 | #undef COPY | |
422 | #undef COPY_R | |
423 | } | |
424 | ||
425 | static void | |
426 | dump_code(void) | |
427 | { | |
428 | int i; | |
429 | unsigned char *lina = SEG_ADR((unsigned char *), cs, ip); | |
430 | ||
431 | fprintf(stderr,"code at 0x%8.8x: ",(CARD32)lina); | |
8bde7f77 WD |
432 | for (i=0; i<0x10; i++) |
433 | fprintf(stderr,"%2.2x ",*(lina + i)); | |
c7de829c | 434 | fprintf(stderr,"\n "); |
8bde7f77 WD |
435 | for (; i<0x20; i++) |
436 | fprintf(stderr,"%2.2x ",*(lina + i)); | |
c7de829c WD |
437 | fprintf(stderr,"\n"); |
438 | } | |
439 | ||
440 | #define PRINT(x) fprintf(stderr,#x":%4.4x ",CPU_REG_LW(x)) | |
441 | #define PRINT_FLAGS(x) fprintf(stderr,#x":%8.8x ",CPU_REG_LW(x)) | |
442 | static void | |
443 | dump_registers(void) | |
444 | { | |
445 | PRINT(eip); | |
446 | PRINT(eax); | |
447 | PRINT(ebx); | |
448 | PRINT(ecx); | |
449 | PRINT(edx); | |
450 | PRINT(esi); | |
451 | PRINT(edi); | |
452 | PRINT(ebp); | |
453 | fprintf(stderr,"\n"); | |
454 | PRINT(esp); | |
455 | PRINT(cs); | |
456 | PRINT(ss); | |
457 | PRINT(es); | |
458 | PRINT(ds); | |
459 | PRINT(fs); | |
460 | PRINT(gs); | |
461 | PRINT_FLAGS(eflags); | |
462 | fprintf(stderr,"\n"); | |
463 | } | |
464 | ||
465 | static void | |
466 | stack_trace(void) | |
467 | { | |
468 | int i; | |
8bde7f77 | 469 | unsigned char *stack = SEG_ADR((unsigned char *), ss, sp); |
c7de829c WD |
470 | |
471 | fprintf(stderr,"stack at 0x%8.8lx:\n",(unsigned long)stack); | |
8bde7f77 WD |
472 | for (i=0; i < 0x10; i++) |
473 | fprintf(stderr,"%2.2x ",*(stack + i)); | |
c7de829c | 474 | fprintf(stderr,"\n"); |
8bde7f77 | 475 | |
c7de829c WD |
476 | } |
477 | ||
478 | static int | |
8bde7f77 | 479 | vm86_rep(struct vm86_struct *ptr) |
c7de829c WD |
480 | { |
481 | ||
482 | int __res; | |
483 | ||
484 | __asm__ __volatile__("int $0x80\n" | |
8bde7f77 WD |
485 | :"=a" (__res):"a" ((int)113), |
486 | "b" ((struct vm86_struct *)ptr)); | |
487 | ||
488 | if ((__res) < 0) { | |
489 | errno = -__res; | |
490 | __res=-1; | |
491 | } | |
492 | else errno = 0; | |
493 | return __res; | |
c7de829c WD |
494 | } |
495 | ||
496 | #define pushw(base, ptr, val) \ | |
497 | __asm__ __volatile__( \ | |
8bde7f77 WD |
498 | "decw %w0\n\t" \ |
499 | "movb %h2,(%1,%0)\n\t" \ | |
500 | "decw %w0\n\t" \ | |
501 | "movb %b2,(%1,%0)" \ | |
502 | : "=r" (ptr) \ | |
503 | : "r" (base), "q" (val), "0" (ptr)) | |
c7de829c WD |
504 | |
505 | int | |
506 | run_bios_int(int num, struct regs86 *regs) | |
507 | { | |
508 | CARD16 *ssp; | |
509 | CARD32 sp; | |
510 | CARD32 eflags; | |
511 | ||
512 | #ifdef V86BIOS_DEBUG | |
513 | static int firsttime = 1; | |
514 | #endif | |
515 | /* check if bios vector is initialized */ | |
516 | if (((CARD16*)0)[(num<<1)+1] == 0x0000) { /* SYS_BIOS_SEG ?*/ | |
517 | #ifdef V86BIOS_DEBUG | |
8bde7f77 | 518 | i_printf("card BIOS not loaded\n"); |
c7de829c | 519 | #endif |
8bde7f77 | 520 | return 0; |
c7de829c | 521 | } |
8bde7f77 | 522 | |
c7de829c WD |
523 | #ifdef V86BIOS_DEBUG |
524 | if (firsttime) { | |
8bde7f77 WD |
525 | dprint(0,0x3D0); |
526 | firsttime = 0; | |
c7de829c WD |
527 | } |
528 | #endif | |
8bde7f77 | 529 | |
c7de829c WD |
530 | i_printf("calling card BIOS at: "); |
531 | ssp = (CARD16*)(CPU_REG(ss)<<4); | |
532 | sp = (CARD32) CPU_REG_LW(esp); | |
533 | ||
534 | eflags = regs->eflags; | |
535 | eflags = ((eflags & VIF_MASK) != 0) | |
8bde7f77 | 536 | ? (eflags | IF_MASK) : (eflags & ~(CARD32) IF_MASK); |
c7de829c WD |
537 | pushw(ssp, sp, eflags); |
538 | pushw(ssp, sp, regs->cs); | |
539 | pushw(ssp, sp, (CARD16)regs->eip); | |
540 | regs->esp -= 6; | |
541 | regs->cs = ((CARD16 *) 0)[(num << 1) + 1]; | |
542 | regs->eip = (regs->eip & 0xFFFF0000) | ((CARD16 *) 0)[num << 1]; | |
543 | i_printf("0x%x:%lx\n",regs->cs,regs->eip); | |
544 | #ifdef V86BIOS_DEBUG | |
545 | dump_code(); | |
546 | #endif | |
547 | regs->eflags = regs->eflags | |
8bde7f77 | 548 | & ~(VIF_MASK | TF_MASK | IF_MASK | NT_MASK); |
c7de829c WD |
549 | return 1; |
550 | } | |
551 | ||
552 | CARD32 | |
553 | getIntVect(int num) | |
554 | { | |
555 | return ((CARD32*)0)[num]; | |
556 | } | |
557 | ||
558 | CARD32 | |
559 | getIP(void) | |
560 | { | |
561 | return (CPU_REG(cs) << 4) + CPU_REG(eip); | |
562 | } |