]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/MAI/bios_emulator/scitech/src/v86bios/v86.c
* Patch by Thomas Frieden, 13 Nov 2002:
[karo-tx-uboot.git] / board / MAI / bios_emulator / scitech / src / v86bios / v86.c
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) \
49                                       + CPU_REG_LW(e##reg))
50 #define DF (1 << 10)
51
52 struct pio P;
53
54
55 void
56 setup_io(void) 
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
75     
76 static void
77 setup_vm86(unsigned long bios_start, i86biosRegsPtr regs)
78 {
79     CARD32 eip;
80     CARD16 cs;
81     
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;
91     
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;
100     CPU_REG(cs) = cs;               
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;
127     
128 #ifdef V86BIOS_DEBUG
129     dump_registers();
130 #endif
131 //    retval = SYS_vm86old(&vm86s);
132 //    retval = syscall(SYS_vm86old,&vm86s);
133
134     retval = vm86_rep(&vm86s);
135     
136     switch (VM86_TYPE(retval)) {
137     case VM86_UNKNOWN:
138         if (!vm86_GP_fault()) return 0;
139         break;
140     case VM86_STI:
141         fprintf(stderr,"vm86_sti :-((\n");
142         stack_trace();
143         dump_code();
144         return 0;
145     case VM86_INTx:
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;
153     case VM86_SIGNAL:
154         fprintf(stderr,"received signal\n");
155         return 0;
156     default:
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;
163     }
164     
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);
179     
180     setup_vm86(bios_start, regs);
181     if (setjmp(x86_esc) == 0) {
182         org_handler = signal(2,vmexit);
183         while(do_vm86()) {};
184         signal(2,org_handler);
185         collect_bios_regs(regs);
186     } else {
187         signal(2,org_handler);
188         printf("interrupted at 0x%x\n",((CARD16)CPU_REG(cs)) << 4
189            | (CARD16)CPU_REG(eip));
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 {
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         }
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 */
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;
251
252     case 0x6d:                  /* (rep) insw / insd */
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;
270
271     case 0x6e:                  /* (rep) outsb */
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;
280
281     case 0x6f:                  /* (rep) outsw / outsd */
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;
299
300     case 0xe5:                  /* inw xx, inl xx */
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;
305     case 0xe4:                  /* inb xx */
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;
310     case 0xed:                  /* inw dx, inl dx */
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;
315     case 0xec:                  /* inb dx */
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;
320
321     case 0xe7:                  /* outw xx */
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;
326     case 0xe6:                  /* outb xx */
327         P.outb((int) csp[1], CPU_REG_LB(ax));
328         CPU_REG_LW(eip) += 2;
329         break;
330     case 0xef:                  /* outw dx */
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;
335     case 0xee:                  /* outb dx */
336         P.outb(CPU_REG_LW(edx), CPU_REG_LB(ax));
337         CPU_REG_LW(eip) += 1;
338         break;
339
340     case 0xf4:
341 #ifdef V86BIOS_DEBUG
342         printf("hlt at %p\n", lina);
343 #endif
344         return 0;
345
346     case 0x0f: 
347         fprintf(stderr,"CPU 0x0f Trap at eip=0x%lx\n",CPU_REG(eip));
348         goto op0ferr; 
349         break;
350
351     case 0xf0:                  /* lock */
352     default:
353         fprintf(stderr,"unknown reason for exception\n");
354         dump_registers();
355         stack_trace();
356     op0ferr:
357         dump_code();
358         fprintf(stderr,"cannot continue\n");
359         return 0;
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)
372         i_printf(" at: 0x%x\n",getIP());
373     else
374         i_printf("\n");
375
376     /* try to run bios interrupt */
377     
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
381     
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)))
400         if (!(val = run_bios_int(num,&regs)))
401             return val;
402         
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);
432     for (i=0; i<0x10; i++) 
433         fprintf(stderr,"%2.2x ",*(lina + i));
434     fprintf(stderr,"\n                    ");
435     for (; i<0x20; i++) 
436         fprintf(stderr,"%2.2x ",*(lina + i));
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;
469     unsigned char *stack = SEG_ADR((unsigned char *), ss, sp);    
470
471     fprintf(stderr,"stack at 0x%8.8lx:\n",(unsigned long)stack);
472     for (i=0; i < 0x10; i++) 
473         fprintf(stderr,"%2.2x ",*(stack + i));
474     fprintf(stderr,"\n");
475     
476 }
477
478 static int
479 vm86_rep(struct vm86_struct *ptr) 
480 {
481
482     int __res;
483
484     __asm__ __volatile__("int $0x80\n"
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;
494 }
495
496 #define pushw(base, ptr, val) \
497 __asm__ __volatile__( \
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))
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
518         i_printf("card BIOS not loaded\n");
519 #endif
520         return 0;
521     }
522     
523 #ifdef V86BIOS_DEBUG
524     if (firsttime) {
525         dprint(0,0x3D0);
526         firsttime = 0;
527     }
528 #endif
529     
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)
536         ? (eflags | IF_MASK) : (eflags & ~(CARD32) IF_MASK);
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
548                        & ~(VIF_MASK | TF_MASK | IF_MASK | NT_MASK);
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 }