3 * execute BIOS int 10h calls in x86 real mode environment
4 * Copyright 1999 Egbert Eich
6 * Part of this code was inspired by the VBIOS POSTing code in DOSEMU
7 * developed by the "DOSEMU-Development-Team"
11 * To debug port accesses define PRINT_PORT to 1.
12 * Note! You also have to comment out ioperm()
13 * in xf86EnableIO(). Otherwise we won't trap
17 #ifdef HAVE_XORG_CONFIG_H
18 #include <xorg-config.h>
27 #include "xf86_OSproc.h"
29 #define _INT10_PRIVATE
30 #include "int10Defines.h"
31 #include "xf86int10.h"
33 #include "x86emu/x86emui.h"
36 static int pciCfg1in(CARD16 addr
, CARD32
*val
);
37 static int pciCfg1out(CARD16 addr
, CARD32 val
);
38 static int pciCfg1inw(CARD16 addr
, CARD16
*val
);
39 static int pciCfg1outw(CARD16 addr
, CARD16 val
);
40 static int pciCfg1inb(CARD16 addr
, CARD8
*val
);
41 static int pciCfg1outb(CARD16 addr
, CARD8 val
);
43 static void SetResetBIOSVars(xf86Int10InfoPtr pInt
, Bool set
);
48 static int pci_config_cycle
= 0;
51 setup_int(xf86Int10InfoPtr pInt
)
53 if (pInt
!= Int10Current
) {
54 if (!MapCurrentInt10(pInt
))
58 X86_EAX
= (CARD32
) pInt
->ax
;
59 X86_EBX
= (CARD32
) pInt
->bx
;
60 X86_ECX
= (CARD32
) pInt
->cx
;
61 X86_EDX
= (CARD32
) pInt
->dx
;
62 X86_ESI
= (CARD32
) pInt
->si
;
63 X86_EDI
= (CARD32
) pInt
->di
;
64 X86_EBP
= (CARD32
) pInt
->bp
;
65 X86_ESP
= 0x1000; X86_SS
= pInt
->stackseg
>> 4;
66 X86_EIP
= 0x0600; X86_CS
= 0x0; /* address of 'hlt' */
67 X86_DS
= 0x40; /* standard pc ds */
71 X86_EFLAGS
= X86_IF_MASK
| X86_IOPL_MASK
;
73 if (pInt
->Flags
& SET_BIOS_SCRATCH
)
74 SetResetBIOSVars(pInt
, TRUE
);
76 return xf86BlockSIGIO();
80 finish_int(xf86Int10InfoPtr pInt
, int sig
)
82 xf86UnblockSIGIO(sig
);
83 pInt
->ax
= (CARD32
) X86_EAX
;
84 pInt
->bx
= (CARD32
) X86_EBX
;
85 pInt
->cx
= (CARD32
) X86_ECX
;
86 pInt
->dx
= (CARD32
) X86_EDX
;
87 pInt
->si
= (CARD32
) X86_ESI
;
88 pInt
->di
= (CARD32
) X86_EDI
;
89 pInt
->es
= (CARD16
) X86_ES
;
90 pInt
->bp
= (CARD32
) X86_EBP
;
91 pInt
->flags
= (CARD32
) X86_FLAGS
;
93 if (pInt
->Flags
& RESTORE_BIOS_SCRATCH
)
94 SetResetBIOSVars(pInt
, FALSE
);
98 /* general software interrupt handler */
100 getIntVect(xf86Int10InfoPtr pInt
,int num
)
102 return MEM_RW(pInt
, num
<< 2) + (MEM_RW(pInt
, (num
<< 2) + 2) << 4);
106 pushw(xf86Int10InfoPtr pInt
, CARD16 val
)
109 MEM_WW(pInt
, ((CARD32
) X86_SS
<< 4) + X86_SP
, val
);
113 run_bios_int(int num
, xf86Int10InfoPtr pInt
)
117 /* check if bios vector is initialized */
118 if (MEM_RW(pInt
, (num
<< 2) + 2) == (SYS_BIOS
>> 4)) { /* SYS_BIOS_SEG ?*/
120 if (num
== 21 && X86_AH
== 0x4e) {
121 xf86DrvMsg(pInt
->scrnIndex
, X_NOTICE
,
122 "Failing Find-Matching-File on non-PC"
123 " (int 21, func 4e)\n");
128 xf86DrvMsgVerb(pInt
->scrnIndex
, X_NOT_IMPLEMENTED
, 2,
129 "Ignoring int 0x%02x call\n", num
);
130 if (xf86GetVerbosity() > 3) {
131 dump_registers(pInt
);
139 ErrorF("calling card BIOS at: ");
143 eflags
= eflags
| IF_MASK
;
144 X86_EFLAGS
= X86_EFLAGS
& ~(VIF_MASK
| TF_MASK
| IF_MASK
| NT_MASK
);
149 X86_CS
= MEM_RW(pInt
, (num
<< 2) + 2);
150 X86_IP
= MEM_RW(pInt
, num
<< 2);
152 ErrorF("0x%x:%lx\n", X86_CS
, X86_EIP
);
157 /* Debugging stuff */
159 dump_code(xf86Int10InfoPtr pInt
)
162 unsigned long lina
= SEG_ADR((CARD32
), X86_CS
, IP
);
164 xf86DrvMsgVerb(pInt
->scrnIndex
, X_INFO
, 3, "code at 0x%8.8lx:\n", lina
);
165 for (i
=0; i
<0x10; i
++)
166 xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt
, lina
+ i
));
167 xf86ErrorFVerb(3, "\n");
169 xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt
, lina
+ i
));
170 xf86ErrorFVerb(3, "\n");
174 dump_registers(xf86Int10InfoPtr pInt
)
176 xf86DrvMsgVerb(pInt
->scrnIndex
, X_INFO
, 3,
177 "EAX=0x%8.8lx, EBX=0x%8.8lx, ECX=0x%8.8lx, EDX=0x%8.8lx\n",
178 (unsigned long)X86_EAX
, (unsigned long)X86_EBX
,
179 (unsigned long)X86_ECX
, (unsigned long)X86_EDX
);
180 xf86DrvMsgVerb(pInt
->scrnIndex
, X_INFO
, 3,
181 "ESP=0x%8.8lx, EBP=0x%8.8lx, ESI=0x%8.8lx, EDI=0x%8.8lx\n",
182 (unsigned long)X86_ESP
, (unsigned long)X86_EBP
,
183 (unsigned long)X86_ESI
, (unsigned long)X86_EDI
);
184 xf86DrvMsgVerb(pInt
->scrnIndex
, X_INFO
, 3,
185 "CS=0x%4.4x, SS=0x%4.4x,"
186 " DS=0x%4.4x, ES=0x%4.4x, FS=0x%4.4x, GS=0x%4.4x\n",
187 X86_CS
, X86_SS
, X86_DS
, X86_ES
, X86_FS
, X86_GS
);
188 xf86DrvMsgVerb(pInt
->scrnIndex
, X_INFO
, 3,
189 "EIP=0x%8.8lx, EFLAGS=0x%8.8lx\n",
190 (unsigned long)X86_EIP
, (unsigned long)X86_EFLAGS
);
194 stack_trace(xf86Int10InfoPtr pInt
)
197 unsigned long stack
= SEG_ADR((CARD32
), X86_SS
, SP
);
198 unsigned long tail
= (CARD32
)((X86_SS
<< 4) + 0x1000);
200 if (stack
>= tail
) return;
202 xf86MsgVerb(X_INFO
, 3, "stack at 0x%8.8lx:\n", stack
);
203 for (; stack
< tail
; stack
++) {
204 xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt
, stack
));
207 xf86ErrorFVerb(3, "\n");
210 xf86ErrorFVerb(3, "\n");
214 port_rep_inb(xf86Int10InfoPtr pInt
,
215 CARD16 port
, CARD32 base
, int d_f
, CARD32 count
)
217 register int inc
= d_f
? -1 : 1;
219 if (PRINT_PORT
&& DEBUG_IO_TRACE())
220 ErrorF(" rep_insb(%#x) %d bytes at %8.8x %s\n",
221 port
, count
, base
, d_f
? "up" : "down");
223 MEM_WB(pInt
, dst
, x_inb(port
));
230 port_rep_inw(xf86Int10InfoPtr pInt
,
231 CARD16 port
, CARD32 base
, int d_f
, CARD32 count
)
233 register int inc
= d_f
? -2 : 2;
235 if (PRINT_PORT
&& DEBUG_IO_TRACE())
236 ErrorF(" rep_insw(%#x) %d bytes at %8.8x %s\n",
237 port
, count
, base
, d_f
? "up" : "down");
239 MEM_WW(pInt
, dst
, x_inw(port
));
246 port_rep_inl(xf86Int10InfoPtr pInt
,
247 CARD16 port
, CARD32 base
, int d_f
, CARD32 count
)
249 register int inc
= d_f
? -4 : 4;
251 if (PRINT_PORT
&& DEBUG_IO_TRACE())
252 ErrorF(" rep_insl(%#x) %d bytes at %8.8x %s\n",
253 port
, count
, base
, d_f
? "up" : "down");
255 MEM_WL(pInt
, dst
, x_inl(port
));
262 port_rep_outb(xf86Int10InfoPtr pInt
,
263 CARD16 port
, CARD32 base
, int d_f
, CARD32 count
)
265 register int inc
= d_f
? -1 : 1;
267 if (PRINT_PORT
&& DEBUG_IO_TRACE())
268 ErrorF(" rep_outb(%#x) %d bytes at %8.8x %s\n",
269 port
, count
, base
, d_f
? "up" : "down");
271 x_outb(port
, MEM_RB(pInt
, dst
));
278 port_rep_outw(xf86Int10InfoPtr pInt
,
279 CARD16 port
, CARD32 base
, int d_f
, CARD32 count
)
281 register int inc
= d_f
? -2 : 2;
283 if (PRINT_PORT
&& DEBUG_IO_TRACE())
284 ErrorF(" rep_outw(%#x) %d bytes at %8.8x %s\n",
285 port
, count
, base
, d_f
? "up" : "down");
287 x_outw(port
, MEM_RW(pInt
, dst
));
294 port_rep_outl(xf86Int10InfoPtr pInt
,
295 CARD16 port
, CARD32 base
, int d_f
, CARD32 count
)
297 register int inc
= d_f
? -4 : 4;
299 if (PRINT_PORT
&& DEBUG_IO_TRACE())
300 ErrorF(" rep_outl(%#x) %d bytes at %8.8x %s\n",
301 port
, count
, base
, d_f
? "up" : "down");
303 x_outl(port
, MEM_RL(pInt
, dst
));
315 Int10Current
->inb40time
++;
316 val
= (CARD8
)(Int10Current
->inb40time
>>
317 ((Int10Current
->inb40time
& 1) << 3));
318 if (PRINT_PORT
&& DEBUG_IO_TRACE())
319 ErrorF(" inb(%#x) = %2.2x\n", port
, val
);
321 } else if (port
< 0x0100) { /* Don't interfere with mainboard */
323 xf86DrvMsgVerb(Int10Current
->scrnIndex
, X_NOT_IMPLEMENTED
, 2,
324 "inb 0x%4.4x\n", port
);
325 if (xf86GetVerbosity() > 3) {
326 dump_registers(Int10Current
);
327 stack_trace(Int10Current
);
329 #endif /* __NOT_YET__ */
330 } else if (!pciCfg1inb(port
, &val
)) {
331 val
= inb(Int10Current
->ioBase
+ port
);
332 if (PRINT_PORT
&& DEBUG_IO_TRACE())
333 ErrorF(" inb(%#x) = %2.2x\n", port
, val
);
347 * Emulate a PC98's timer. Typical resolution is 3.26 usec.
348 * Approximate this by dividing by 3.
351 val
= (CARD16
)(tv
.tv_usec
/ 3);
352 } else if (!pciCfg1inw(port
, &val
)) {
353 val
= inw(Int10Current
->ioBase
+ port
);
354 if (PRINT_PORT
&& DEBUG_IO_TRACE())
355 ErrorF(" inw(%#x) = %4.4x\n", port
, val
);
361 x_outb(CARD16 port
, CARD8 val
)
363 if ((port
== 0x43) && (val
== 0)) {
366 * Emulate a PC's timer 0. Such timers typically have a resolution of
367 * some .838 usec per tick, but this can only provide 1 usec per tick.
368 * (Not that this matters much, given inherent emulation delays.) Use
369 * the bottom bit as a byte select. See inb(0x40) above.
372 Int10Current
->inb40time
= (CARD16
)(tv
.tv_usec
| 1);
373 if (PRINT_PORT
&& DEBUG_IO_TRACE())
374 ErrorF(" outb(%#x, %2.2x)\n", port
, val
);
376 } else if (port
< 0x0100) { /* Don't interfere with mainboard */
377 xf86DrvMsgVerb(Int10Current
->scrnIndex
, X_NOT_IMPLEMENTED
, 2,
378 "outb 0x%4.4x,0x%2.2x\n", port
, val
);
379 if (xf86GetVerbosity() > 3) {
380 dump_registers(Int10Current
);
381 stack_trace(Int10Current
);
383 #endif /* __NOT_YET__ */
384 } else if (!pciCfg1outb(port
, val
)) {
385 if (PRINT_PORT
&& DEBUG_IO_TRACE())
386 ErrorF(" outb(%#x, %2.2x)\n", port
, val
);
387 outb(Int10Current
->ioBase
+ port
, val
);
392 x_outw(CARD16 port
, CARD16 val
)
395 if (!pciCfg1outw(port
, val
)) {
396 if (PRINT_PORT
&& DEBUG_IO_TRACE())
397 ErrorF(" outw(%#x, %4.4x)\n", port
, val
);
398 outw(Int10Current
->ioBase
+ port
, val
);
407 if (!pciCfg1in(port
, &val
)) {
408 val
= inl(Int10Current
->ioBase
+ port
);
409 if (PRINT_PORT
&& DEBUG_IO_TRACE())
410 ErrorF(" inl(%#x) = %8.8x\n", port
, val
);
416 x_outl(CARD16 port
, CARD32 val
)
418 if (!pciCfg1out(port
, val
)) {
419 if (PRINT_PORT
&& DEBUG_IO_TRACE())
420 ErrorF(" outl(%#x, %8.8x)\n", port
, val
);
421 outl(Int10Current
->ioBase
+ port
, val
);
428 return (*Int10Current
->mem
->rb
)(Int10Current
, addr
);
434 return (*Int10Current
->mem
->rw
)(Int10Current
, addr
);
440 return (*Int10Current
->mem
->rl
)(Int10Current
, addr
);
444 Mem_wb(CARD32 addr
, CARD8 val
)
446 (*Int10Current
->mem
->wb
)(Int10Current
, addr
, val
);
450 Mem_ww(CARD32 addr
, CARD16 val
)
452 (*Int10Current
->mem
->ww
)(Int10Current
, addr
, val
);
456 Mem_wl(CARD32 addr
, CARD32 val
)
458 (*Int10Current
->mem
->wl
)(Int10Current
, addr
, val
);
461 static CARD32 PciCfg1Addr
= 0;
463 #define OFFSET(Cfg1Addr) (Cfg1Addr & 0xff)
466 pciCfg1in(CARD16 addr
, CARD32
*val
)
473 *val
= pciReadLong(Int10Current
->Tag
, OFFSET(PciCfg1Addr
));
474 if (PRINT_PORT
&& DEBUG_IO_TRACE())
475 ErrorF(" cfg_inl(%#x) = %8.8x\n", PciCfg1Addr
, *val
);
482 pciCfg1out(CARD16 addr
, CARD32 val
)
489 if (PRINT_PORT
&& DEBUG_IO_TRACE())
490 ErrorF(" cfg_outl(%#x, %8.8x)\n", PciCfg1Addr
, val
);
491 pciWriteLong(Int10Current
->Tag
, OFFSET(PciCfg1Addr
), val
);
498 pciCfg1inw(CARD16 addr
, CARD16
*val
)
502 if ((addr
>= 0xCF8) && (addr
<= 0xCFB)) {
503 shift
= (addr
- 0xCF8) * 8;
504 *val
= (PciCfg1Addr
>> shift
) & 0xffff;
507 if ((addr
>= 0xCFC) && (addr
<= 0xCFF)) {
508 offset
= addr
- 0xCFC;
509 *val
= pciReadWord(Int10Current
->Tag
, OFFSET(PciCfg1Addr
) + offset
);
510 if (PRINT_PORT
&& DEBUG_IO_TRACE())
511 ErrorF(" cfg_inw(%#x) = %4.4x\n", PciCfg1Addr
+ offset
, *val
);
518 pciCfg1outw(CARD16 addr
, CARD16 val
)
522 if ((addr
>= 0xCF8) && (addr
<= 0xCFB)) {
523 shift
= (addr
- 0xCF8) * 8;
524 PciCfg1Addr
&= ~(0xffff << shift
);
525 PciCfg1Addr
|= ((CARD32
) val
) << shift
;
528 if ((addr
>= 0xCFC) && (addr
<= 0xCFF)) {
529 offset
= addr
- 0xCFC;
530 if (PRINT_PORT
&& DEBUG_IO_TRACE())
531 ErrorF(" cfg_outw(%#x, %4.4x)\n", PciCfg1Addr
+ offset
, val
);
532 pciWriteWord(Int10Current
->Tag
, OFFSET(PciCfg1Addr
) + offset
, val
);
539 pciCfg1inb(CARD16 addr
, CARD8
*val
)
543 if ((addr
>= 0xCF8) && (addr
<= 0xCFB)) {
544 shift
= (addr
- 0xCF8) * 8;
545 *val
= (PciCfg1Addr
>> shift
) & 0xff;
548 if ((addr
>= 0xCFC) && (addr
<= 0xCFF)) {
549 offset
= addr
- 0xCFC;
550 *val
= pciReadByte(Int10Current
->Tag
, OFFSET(PciCfg1Addr
) + offset
);
551 if (PRINT_PORT
&& DEBUG_IO_TRACE())
552 ErrorF(" cfg_inb(%#x) = %2.2x\n", PciCfg1Addr
+ offset
, *val
);
559 pciCfg1outb(CARD16 addr
, CARD8 val
)
563 if ((addr
>= 0xCF8) && (addr
<= 0xCFB)) {
564 shift
= (addr
- 0xCF8) * 8;
565 PciCfg1Addr
&= ~(0xff << shift
);
566 PciCfg1Addr
|= ((CARD32
) val
) << shift
;
569 if ((addr
>= 0xCFC) && (addr
<= 0xCFF)) {
570 offset
= addr
- 0xCFC;
571 if (PRINT_PORT
&& DEBUG_IO_TRACE())
572 ErrorF(" cfg_outb(%#x, %2.2x)\n", PciCfg1Addr
+ offset
, val
);
573 pciWriteByte(Int10Current
->Tag
, OFFSET(PciCfg1Addr
) + offset
, val
);
580 bios_checksum(const CARD8
*start
, int size
)
590 * Lock/Unlock legacy VGA. Some Bioses try to be very clever and make
591 * an attempt to detect a legacy ISA card. If they find one they might
592 * act very strange: for example they might configure the card as a
593 * monochrome card. This might cause some drivers to choke.
594 * To avoid this we attempt legacy VGA by writing to all know VGA
595 * disable registers before we call the BIOS initialization and
596 * restore the original values afterwards. In beween we hold our
597 * breath. To get to a (possibly exising) ISA card need to disable
598 * our current PCI card.
601 * This is just for booting: we just want to catch pure
602 * legacy vga therefore we don't worry about mmio etc.
603 * This stuff should really go into vgaHW.c. However then
604 * the driver would have to load the vga-module prior to
608 LockLegacyVGA(xf86Int10InfoPtr pInt
, legacyVGAPtr vga
)
610 xf86SetCurrentAccess(FALSE
, xf86Screens
[pInt
->scrnIndex
]);
611 vga
->save_msr
= inb(pInt
->ioBase
+ 0x03CC);
612 vga
->save_vse
= inb(pInt
->ioBase
+ 0x03C3);
614 vga
->save_46e8
= inb(pInt
->ioBase
+ 0x46E8);
616 vga
->save_pos102
= inb(pInt
->ioBase
+ 0x0102);
617 outb(pInt
->ioBase
+ 0x03C2, ~(CARD8
)0x03 & vga
->save_msr
);
618 outb(pInt
->ioBase
+ 0x03C3, ~(CARD8
)0x01 & vga
->save_vse
);
620 outb(pInt
->ioBase
+ 0x46E8, ~(CARD8
)0x08 & vga
->save_46e8
);
622 outb(pInt
->ioBase
+ 0x0102, ~(CARD8
)0x01 & vga
->save_pos102
);
623 xf86SetCurrentAccess(TRUE
, xf86Screens
[pInt
->scrnIndex
]);
627 UnlockLegacyVGA(xf86Int10InfoPtr pInt
, legacyVGAPtr vga
)
629 xf86SetCurrentAccess(FALSE
, xf86Screens
[pInt
->scrnIndex
]);
630 outb(pInt
->ioBase
+ 0x0102, vga
->save_pos102
);
632 outb(pInt
->ioBase
+ 0x46E8, vga
->save_46e8
);
634 outb(pInt
->ioBase
+ 0x03C3, vga
->save_vse
);
635 outb(pInt
->ioBase
+ 0x03C2, vga
->save_msr
);
636 xf86SetCurrentAccess(TRUE
, xf86Screens
[pInt
->scrnIndex
]);
641 SetResetBIOSVars(xf86Int10InfoPtr pInt
, Bool set
)
643 int pagesize
= getpagesize();
644 unsigned char* base
= xf86MapVidMem(pInt
->scrnIndex
,
645 VIDMEM_MMIO
, 0, pagesize
);
649 for (i
= BIOS_SCRATCH_OFF
; i
< BIOS_SCRATCH_END
; i
++)
650 MEM_WW(pInt
, i
, *(base
+ i
));
652 for (i
= BIOS_SCRATCH_OFF
; i
< BIOS_SCRATCH_END
; i
++)
653 *(base
+ i
) = MEM_RW(pInt
, i
);
656 xf86UnMapVidMem(pInt
->scrnIndex
,base
,pagesize
);
660 xf86Int10SaveRestoreBIOSVars(xf86Int10InfoPtr pInt
, Bool save
)
662 int pagesize
= getpagesize();
666 if (!xf86IsEntityPrimary(pInt
->entityIndex
)
667 || (!save
&& !pInt
->BIOSScratch
))
670 base
= xf86MapVidMem(pInt
->scrnIndex
, VIDMEM_MMIO
, 0, pagesize
);
671 base
+= BIOS_SCRATCH_OFF
;
673 if ((pInt
->BIOSScratch
674 = xnfalloc(BIOS_SCRATCH_LEN
)))
675 for (i
= 0; i
< BIOS_SCRATCH_LEN
; i
++)
676 *(((char*)pInt
->BIOSScratch
+ i
)) = *(base
+ i
);
678 if (pInt
->BIOSScratch
) {
679 for (i
= 0; i
< BIOS_SCRATCH_LEN
; i
++)
680 *(base
+ i
) = *(pInt
->BIOSScratch
+ i
);
681 xfree(pInt
->BIOSScratch
);
682 pInt
->BIOSScratch
= NULL
;
686 xf86UnMapVidMem(pInt
->scrnIndex
,base
- BIOS_SCRATCH_OFF
,pagesize
);
691 xf86InitInt10(int entityIndex
)
693 return xf86ExtendedInitInt10(entityIndex
, 0);