]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - src/hwinfo/src/int10/i10_v86.c
hwinfo in den Installer gebracht.
[people/pmueller/ipfire-2.x.git] / src / hwinfo / src / int10 / i10_v86.c
CommitLineData
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
37extern int emu_vm86(struct vm86_struct *vm, unsigned debug);
38
39#define INT2PTR(a) ((a) + (unsigned char *) 0)
40
41void log_err(char *format, ...) __attribute__ ((format (printf, 1, 2)));
42
43struct vm86_struct vm86s;
44
45static int vm86_GP_fault(void);
46static int vm86_do_int(int num);
47#ifdef __i386__
48static int vm86_rep(struct vm86_struct *ptr);
49#endif
50void 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
59struct pio P;
60
61void
62setup_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
73static void
74setup_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
107void
108collect_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
120static 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
170void
171do_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
184static int
185vm86_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
348static int
349vm86_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,&regs)))
378 if (!(val = run_bios_int(num,&regs)))
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
405static int
406vm86_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
448int
449run_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
490CARD32
491getIntVect(int num)
492{
493 return ((CARD32*)0)[num];
494}
495
496CARD32
497getIP(void)
498{
499 return (CPU_REG(cs) << 4) + CPU_REG(eip);
500}
501
502void 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