]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/blob - src/hwinfo/src/int10/i10_v86.c
Kleiner netter neuer Versuch.
[people/teissler/ipfire-2.x.git] / src / hwinfo / src / int10 / i10_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 <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))
182
183 static int
184 vm86_GP_fault(void)
185 {
186 unsigned char *csp, *lina;
187 CARD32 org_eip;
188 int pref_seg;
189 int done,is_rep,prefix66,prefix67;
190
191
192 csp = lina = SEG_ADR((unsigned char *), cs, ip);
193 #ifdef V86BIOS_DEBUG
194 printf("exception: \n");
195 dump_code();
196 #endif
197
198 is_rep = 0;
199 prefix66 = prefix67 = 0;
200 pref_seg = -1;
201
202 /* eat up prefixes */
203 done = 0;
204 do {
205 switch (*(csp++)) {
206 case 0x66: /* operand prefix */ prefix66=1; break;
207 case 0x67: /* address prefix */ prefix67=1; break;
208 case 0x2e: /* CS */ pref_seg=CPU_REG(cs); break;
209 case 0x3e: /* DS */ pref_seg=CPU_REG(ds); break;
210 case 0x26: /* ES */ pref_seg=CPU_REG(es); break;
211 case 0x36: /* SS */ pref_seg=CPU_REG(ss); break;
212 case 0x65: /* GS */ pref_seg=CPU_REG(gs); break;
213 case 0x64: /* FS */ pref_seg=CPU_REG(fs); break;
214 case 0xf2: /* repnz */
215 case 0xf3: /* rep */ is_rep=1; break;
216 default: done=1;
217 }
218 } while (!done);
219 csp--; /* oops one too many */
220 org_eip = CPU_REG(eip);
221 CPU_REG_LW(eip) += (csp - lina);
222
223 switch (*csp) {
224
225 case 0x6c: /* insb */
226 /* NOTE: ES can't be overwritten; prefixes 66,67 should use esi,edi,ecx
227 * but is anyone using extended regs in real mode? */
228 /* WARNING: no test for DI wrapping! */
229 CPU_REG_LW(edi) += port_rep_inb(CPU_REG_LW(edx),
230 SEG_ADR((CARD8 *),es,di),
231 CPU_REG_LW(eflags)&DF,
232 (is_rep? LWECX:1));
233 if (is_rep) LWECX = 0;
234 CPU_REG_LW(eip)++;
235 break;
236
237 case 0x6d: /* (rep) insw / insd */
238 /* NOTE: ES can't be overwritten */
239 /* WARNING: no test for _DI wrapping! */
240 if (prefix66) {
241 CPU_REG_LW(edi) += port_rep_inl(CPU_REG_LW(edx),
242 SEG_ADR((CARD32 *),es,di),
243 CPU_REG_LW(eflags)&DF,
244 (is_rep? LWECX:1));
245 }
246 else {
247 CPU_REG_LW(edi) += port_rep_inw(CPU_REG_LW(edx),
248 SEG_ADR((CARD16 *),es,di),
249 CPU_REG_LW(eflags)&DF,
250 (is_rep? LWECX:1));
251 }
252 if (is_rep) LWECX = 0;
253 CPU_REG_LW(eip)++;
254 break;
255
256 case 0x6e: /* (rep) outsb */
257 if (pref_seg < 0) pref_seg = CPU_REG_LW(ds);
258 /* WARNING: no test for _SI wrapping! */
259 CPU_REG_LW(esi) += port_rep_outb(CPU_REG_LW(edx),(CARD8*)INT2PTR(LIN_PREF_SI),
260 CPU_REG_LW(eflags)&DF,
261 (is_rep? LWECX:1));
262 if (is_rep) LWECX = 0;
263 CPU_REG_LW(eip)++;
264 break;
265
266 case 0x6f: /* (rep) outsw / outsd */
267 if (pref_seg < 0) pref_seg = CPU_REG_LW(ds);
268 /* WARNING: no test for _SI wrapping! */
269 if (prefix66) {
270 CPU_REG_LW(esi) += port_rep_outl(CPU_REG_LW(edx),
271 (CARD32 *)INT2PTR(LIN_PREF_SI),
272 CPU_REG_LW(eflags)&DF,
273 (is_rep? LWECX:1));
274 }
275 else {
276 CPU_REG_LW(esi) += port_rep_outw(CPU_REG_LW(edx),
277 (CARD16 *)INT2PTR(LIN_PREF_SI),
278 CPU_REG_LW(eflags)&DF,
279 (is_rep? LWECX:1));
280 }
281 if (is_rep) LWECX = 0;
282 CPU_REG_LW(eip)++;
283 break;
284
285 case 0xe5: /* inw xx, inl xx */
286 if (prefix66) CPU_REG(eax) = P.inl((int) csp[1]);
287 else CPU_REG_LW(eax) = P.inw((int) csp[1]);
288 CPU_REG_LW(eip) += 2;
289 break;
290 case 0xe4: /* inb xx */
291 CPU_REG_LW(eax) &= ~(CARD32)0xff;
292 CPU_REG_LB(ax) |= P.inb((int) csp[1]);
293 CPU_REG_LW(eip) += 2;
294 break;
295 case 0xed: /* inw dx, inl dx */
296 if (prefix66) CPU_REG(eax) = P.inl(CPU_REG_LW(edx));
297 else CPU_REG_LW(eax) = P.inw(CPU_REG_LW(edx));
298 CPU_REG_LW(eip) += 1;
299 break;
300 case 0xec: /* inb dx */
301 CPU_REG_LW(eax) &= ~(CARD32)0xff;
302 CPU_REG_LB(ax) |= P.inb(CPU_REG_LW(edx));
303 CPU_REG_LW(eip) += 1;
304 break;
305
306 case 0xe7: /* outw xx */
307 if (prefix66) P.outl((int)csp[1], CPU_REG(eax));
308 else P.outw((int)csp[1], CPU_REG_LW(eax));
309 CPU_REG_LW(eip) += 2;
310 break;
311 case 0xe6: /* outb xx */
312 P.outb((int) csp[1], CPU_REG_LB(ax));
313 CPU_REG_LW(eip) += 2;
314 break;
315 case 0xef: /* outw dx */
316 if (prefix66) P.outl(CPU_REG_LW(edx), CPU_REG(eax));
317 else P.outw(CPU_REG_LW(edx), CPU_REG_LW(eax));
318 CPU_REG_LW(eip) += 1;
319 break;
320 case 0xee: /* outb dx */
321 P.outb(CPU_REG_LW(edx), CPU_REG_LB(ax));
322 CPU_REG_LW(eip) += 1;
323 break;
324
325 case 0xf4:
326 #ifdef V86BIOS_DEBUG
327 printf("hlt at %p\n", lina);
328 #endif
329 return 0;
330
331 case 0x0f:
332 log_err("CPU 0x0f Trap at eip=0x%lx\n",CPU_REG(eip));
333 goto op0ferr;
334 break;
335
336 case 0xf0: /* lock */
337 default:
338 log_err("unknown reason for exception\n");
339 log_registers();
340 op0ferr:
341 log_err("cannot continue\n");
342 return 0;
343 } /* end of switch() */
344 return 1;
345 }
346
347 static int
348 vm86_do_int(int num)
349 {
350 int val;
351 struct regs86 regs;
352
353 /* try to run bios interrupt */
354
355 /* if not installed fall back */
356 #define COPY(x) regs.x = CPU_REG(x)
357 #define COPY_R(x) CPU_REG(x) = regs.x
358
359 COPY(eax);
360 COPY(ebx);
361 COPY(ecx);
362 COPY(edx);
363 COPY(esi);
364 COPY(edi);
365 COPY(ebp);
366 COPY(eip);
367 COPY(esp);
368 COPY(cs);
369 COPY(ss);
370 COPY(ds);
371 COPY(es);
372 COPY(fs);
373 COPY(gs);
374 COPY(eflags);
375
376 if (!(val = int_handler(num,&regs)))
377 if (!(val = run_bios_int(num,&regs)))
378 return val;
379
380 COPY_R(eax);
381 COPY_R(ebx);
382 COPY_R(ecx);
383 COPY_R(edx);
384 COPY_R(esi);
385 COPY_R(edi);
386 COPY_R(ebp);
387 COPY_R(eip);
388 COPY_R(esp);
389 COPY_R(cs);
390 COPY_R(ss);
391 COPY_R(ds);
392 COPY_R(es);
393 COPY_R(fs);
394 COPY_R(gs);
395 COPY_R(eflags);
396
397 return val;
398 #undef COPY
399 #undef COPY_R
400 }
401
402 #ifdef __i386__
403
404 static int
405 vm86_rep(struct vm86_struct *ptr)
406 {
407
408 int __res;
409
410 /* stay away from %ebx */
411 __asm__ __volatile__("push %%ebx\n\tmov %%ecx,%%ebx\n\tpush %%gs\n\tint $0x80\n\tpop %%gs\n\tpop %%ebx\n"
412 :"=a" (__res):"a" ((int)113),
413 "c" ((struct vm86_struct *)ptr));
414
415 if ((__res) < 0) {
416 errno = -__res;
417 __res=-1;
418 }
419 else errno = 0;
420 return __res;
421 }
422
423 #endif
424
425 #ifdef __i386__
426
427 #define pushw(base, ptr, val) \
428 __asm__ __volatile__( \
429 "decw %w0\n\t" \
430 "movb %h2,(%1,%0)\n\t" \
431 "decw %w0\n\t" \
432 "movb %b2,(%1,%0)" \
433 : "=r" (ptr) \
434 : "r" (base), "q" (val), "0" (ptr))
435
436 #else
437
438 #define pushw(base, ptr, val) { \
439 ptr = ((ptr) - 1) & 0xffff; \
440 *((unsigned char *)(base) + (ptr)) = (val) >> 8; \
441 ptr = ((ptr) - 1) & 0xffff; \
442 *((unsigned char *)(base) + (ptr)) = (val); \
443 }
444
445 #endif
446
447 int
448 run_bios_int(int num, struct regs86 *regs)
449 {
450 CARD16 *ssp;
451 CARD32 sp;
452 CARD32 eflags;
453
454 #ifdef V86BIOS_DEBUG
455 static int firsttime = 1;
456 #endif
457 /* check if bios vector is initialized */
458 if (((CARD16*)0)[(num<<1)+1] == 0x0000) { /* SYS_BIOS_SEG ?*/
459 return 0;
460 }
461
462 #ifdef V86BIOS_DEBUG
463 if (firsttime) {
464 dprint(0,0x3D0);
465 firsttime = 0;
466 }
467 #endif
468
469 ssp = (CARD16*)INT2PTR(CPU_REG(ss)<<4);
470 sp = (CARD32) CPU_REG_LW(esp);
471
472 eflags = regs->eflags;
473 eflags = ((eflags & VIF_MASK) != 0)
474 ? (eflags | IF_MASK) : (eflags & ~(CARD32) IF_MASK);
475 pushw(ssp, sp, eflags);
476 pushw(ssp, sp, regs->cs);
477 pushw(ssp, sp, (CARD16)regs->eip);
478 regs->esp -= 6;
479 regs->cs = ((CARD16 *) 0)[(num << 1) + 1];
480 regs->eip = (regs->eip & 0xFFFF0000) | ((CARD16 *) 0)[num << 1];
481 #ifdef V86BIOS_DEBUG
482 dump_code();
483 #endif
484 regs->eflags = regs->eflags
485 & ~(VIF_MASK | TF_MASK | IF_MASK | NT_MASK);
486 return 1;
487 }
488
489 CARD32
490 getIntVect(int num)
491 {
492 return ((CARD32*)0)[num];
493 }
494
495 CARD32
496 getIP(void)
497 {
498 return (CPU_REG(cs) << 4) + CPU_REG(eip);
499 }
500
501 void log_registers()
502 {
503 log_err(
504 " eax %08x, ebx %08x, ecx %08x, edx %08x\n"
505 " esi %08x, edi %08x, ebp %08x, esp %08x\n"
506 " ds %04x, es %04x, fs %04x, gs %04x, ss %04x\n"
507 " cs:eip %04x:%08x\n",
508 (unsigned) CPU_REG(eax), (unsigned) CPU_REG(ebx), (unsigned) CPU_REG(ecx), (unsigned) CPU_REG(edx),
509 (unsigned) CPU_REG(esi), (unsigned) CPU_REG(edi), (unsigned) CPU_REG(ebp), (unsigned) CPU_REG(esp),
510 (unsigned) CPU_REG(ds), (unsigned) CPU_REG(es),
511 (unsigned) CPU_REG(fs), (unsigned) CPU_REG(gs), (unsigned) CPU_REG(ss),
512 (unsigned) CPU_REG(cs), (unsigned) CPU_REG(eip)
513 );
514 }
515