]> git.ipfire.org Git - people/ms/u-boot.git/blame - board/MAI/bios_emulator/scitech/src/v86bios/v86.c
USB: This patch fix readl in ohci swap reg access.
[people/ms/u-boot.git] / board / MAI / bios_emulator / scitech / src / v86bios / v86.c
CommitLineData
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
35struct vm86_struct vm86s;
36
37static int vm86_GP_fault(void);
38static int vm86_do_int(int num);
39static void dump_code(void);
40static void dump_registers(void);
41static void stack_trace(void);
42static 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
52struct pio P;
53
54
55void
8bde7f77 56setup_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
76static void
77setup_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
110void
111collect_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
123static int
124do_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
168static jmp_buf x86_esc;
169static void
170vmexit(int unused)
171{
172 longjmp(x86_esc,1);
173}
174
175void
176do_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
198static int
199vm86_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
364static int
365vm86_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,&regs)))
8bde7f77
WD
400 if (!(val = run_bios_int(num,&regs)))
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
425static void
426dump_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))
442static void
443dump_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
465static void
466stack_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
478static int
8bde7f77 479vm86_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
505int
506run_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
552CARD32
553getIntVect(int num)
554{
555 return ((CARD32*)0)[num];
556}
557
558CARD32
559getIP(void)
560{
561 return (CPU_REG(cs) << 4) + CPU_REG(eip);
562}