diff options
Diffstat (limited to 'hw/xfree86/int10')
-rw-r--r-- | hw/xfree86/int10/INT10.HOWTO | 344 | ||||
-rw-r--r-- | hw/xfree86/int10/generic.c | 552 | ||||
-rw-r--r-- | hw/xfree86/int10/helper_exec.c | 603 | ||||
-rw-r--r-- | hw/xfree86/int10/helper_mem.c | 333 | ||||
-rw-r--r-- | hw/xfree86/int10/pci.c | 51 | ||||
-rw-r--r-- | hw/xfree86/int10/stub.c | 66 | ||||
-rw-r--r-- | hw/xfree86/int10/xf86int10.c | 787 | ||||
-rw-r--r-- | hw/xfree86/int10/xf86int10.h | 198 | ||||
-rw-r--r-- | hw/xfree86/int10/xf86int10module.c | 63 | ||||
-rw-r--r-- | hw/xfree86/int10/xf86x86emu.c | 88 | ||||
-rw-r--r-- | hw/xfree86/int10/xf86x86emu.h | 51 |
11 files changed, 3136 insertions, 0 deletions
diff --git a/hw/xfree86/int10/INT10.HOWTO b/hw/xfree86/int10/INT10.HOWTO new file mode 100644 index 000000000..bba0c774f --- /dev/null +++ b/hw/xfree86/int10/INT10.HOWTO @@ -0,0 +1,344 @@ + + INT10 X86 Real Mode executor + ============================= + + PRELIMINARY + +INT10 is a XFree86 module for soft-booting and executing real mode +int10 BIOS calls. The BIOS call code is largely untested, yet. + +1. Usage +======== + +To use the int10 module in a driver the header file +xfree86/os-support/int10/xf86int10.h must be included. + + a. Initialization + ----------------- + +The int10-executer gets initialized by calling: + + xf86Int10InfoPtr xf86InitInt10(int entityIndex); + +The function will soft-boot any non-primary device and return a +pointer to a xf86Int10InfoRec on success. If anything fails or if +int10 execution is disabled by an option in the device section NULL +will be returned. The driver should store this pointer for later +calls to other int10 module functions. + + b. Memory allocation + -------------------- + +To allocate memory in the real mode execution environment + + void * xf86Int10AllocPages(xf86Int10InfoPtr pInt,int num, int *off); + +can be called. It allocates num consecutive pagesize chunks. It +returns the address of the allocated area. off is set to its offset in +the real mode memory space. + + void xf86Int10FreePages(xf86Int10InfoPtr pInt, void *pbase, int num); + +Is used to free num pages beginning at pbase. + + c. Doing int10 BIOS calls + ------------------------- + +The BIOS call is executed by calling: + + void xf86ExecX86int10(xf86Int10InfoPtr pInt); + +The number of the interrupt (normally 10) and the initial values of +the ax, bx, cx, dx, si, di and es x86-CPU registers can be set in the +xf86Int10InfoRec passed to the function. On return this structure +contains the exit values of the registers listed above and the CPU +flag register. + + d. De-initializing + ----------------- + +If no further int10 calls are required for a certain chipset +the driver should call: + + void xf86FreeInt10(xf86Int10InfoPtr pInt); + +to free the memory allocated for real mode int10 calls. + + +2. Porting issues +================= + +The int10 real mode executor is designed to run on top of various x86 +CPU emulators as well as in vm86 mode of a real x86 CPU. If used with +a CPU emulator the emulator and CPU specific interfaces can be held +separate thus requiring minimal efforts to port the int10 module to +new platforms. Currently an interface to the x86emu real mode +emulator is provided. Since details of setting up and running the +vm86 mode is platform dependent both the platform dependent +environment and the emulation layer have to be ported. Several helper +functions are provided for that. + +A CPU emulator should meet certain requirements to be usable +for the INT10 executor: + +1. It must trap calls to intXX instructions and pass execution to an + external function which is allowed to modify CPU registers + including the instruction pointer (IP) before returning to the + emulator for continuing execution. When the external function is + called the IP must point to the instruction past the intXX call. + +2. The emulator should use externally provided functions to handle + PIO. + +3. The emulator should be able to use externally provided functions + to access memory from the real mode memory environment. Note, that + the vm86 mode usually requires one hunk of consecutive memory + starting at address 0 in the process virtual memory space. Thus if + this mode is to be used, the OS environment has to be able to provide + that, ie. it must be able to remap the processes virtual memory space + onto itself. If the emulator is able to handle memory access thru + externally provided functions the real mode process memory can be + located anywhere in the processes virtual memory. It does not even + have to be consecutive. + +4. The executor should terminate on encountering a 'hlt' instruction. + + +Functions to implement: + +To simplify development the code has been split into a general setup +part and an emulator specific one. A generic setup code is provided in +generic.c. It should be usable with any emulator satisfying the +conditions mentioned above. Therefore the following section on int10 +setup may be skipped when porting int10 to new emulator. + +If the vm86() is to be used no memory access functions can be used. +Therefore the layout of the real mode memory image has to meet certain +requirements. Therefore when porting to other platforms a new setup +code may have to be designed, too. The following section will give +guidelines how this may be done. A sample implementation using SysV +IPC to map the appropriate real mode memory image to address 0 in +virtual address space just prior to execution may be found in +xfree86/os-support/linux/int10/linux.c. + +On non-PC like platforms emulation of certain PC features such as +initialization of BIOS int vectors, sys_BIOS constants or PCI config +method 1 can be turned on by defining _PC. + +I. Setup Code +------------- + +This sets up the real mode memory image, calls the emulator to POST +the chipset if required and maintains memory allocations in real mode +address space. + +1. xf86Int10InfoPtr xf86InitInt10(int entityIndex); + +This function should first find the screen assigned to the entity +carrying entitiyIndex and then call + + Bool int10skip(ScrnInfoPtr pScrn) + +to find out if the user has requested not to initialize int10. If so +xf86InitInt10() should return NULL. Otherwise an xf86Int10InfoRec +should be allocated. This structure contains the following fields: + + a. int entityIndex - index of the entity whose BIOS is to be + executed. + b. int scrnIndex - index of the screen assigned the entity. + c. pointer cpuRegs - pointer to a emulator/vm86-mode private + structure. May hold cpu register values + for the emulator. + d. CARD16 BIOSseg - Video BIOS segment address. + e. pointer private - pointer to a os specific data structure. + f. struct _int10Mem* - pointer to a structure to hold the memory + access functions for use by an emulator. + g. int num - number of the int to be called. + h. int ax..es,flags - CPU register values to pass to int-call. + +The Init function should initialize a-f. To initialize the emulator +specific execute environment the function + + Bool xf86Int10ExecSetup(xf86Int10InfoPtr pInt) + +should be called. If this function returns FALSE any already allocated +memory should be freed and xf86Int10Init(0 should exit returning NULL. + +If the platform has a PC like system BIOS it may be copied to or +mapped into memory locations SYS_BIOS to SYS_SIZE-1 of the real mode +memory environment of this process. Otherwise the helper function: + +int setup_system_bios(CARD32 base_addr); + +may be called to set up a rudimentary system BIOS sufficient to be +used to boot video BIOSes. base_addr specifies the virtual address +corresponding to SYS_BIOS in the real mode environment. If a PC-like +int vector and BIOS data area is available it should be copied to 0 to +LOW_PAGE_SIZE of the entities real mode environment. In this case the +video interrupt related entries should be reset for all non-primary +cards by calling: + +void reset_int_vect(xf86Int10InfoPtr pInt); To initialize the + +correct video BIOS entry points the BIOS must be warm-booted. If no +PC-like int vector is available one can be set up by calling + +void setup_int_vect(xf86Int10InfoPtr pInt); + +In this case the video BIOS has to be warm-booted always. If the +video BIOS for this entity has been installed during boot it may be +mapped (or copied) directly to the correct address in the real mode +memory environment. Otherwise + +int mapPciRom(xf86Int10InfoPtr pInt, unsigned char * address); + +should be called to copy the BIOS image from PCI ROM. 'address' +specifies the address this image should be copied to. Sufficient space +to hold an entire BIOS image should be allocated prior to calling +mapPciRom(). This function will return the size of the BIOS image in +bytes if it was able to successfully copy the image and 0 +otherwise. To create a well defined point to exit the softbooter + +void set_return_trap(xf86Int10Ptr pInt); + +may be called. It sets up a 'hlt' instruction in the emulator memory +just above the BIOS variable area. Before entering real mode execution +this address will be pushed onto the return stack. If the BIOS needs +to be warm-booted this should be done before leaving xf86InitInt10() +by setting num in the xf86Int10InfoRec to 0xe6 and calling + +void xf86ExecX86int10(xf86Int10IfoPtr pInt); + +The implementation of this function will be discussed below. This +function should be wrapped by calls to void LockLegacyVGA(screen, +legacyVGAPtr vga); and void UnlockLegacyVGA(screen, legacyVGAPtr vga); +The struct vga is used to hold the state of the legacy VGA access +registers if a legacy VGA device exists. xf86InitInt10() should +return a pointer to the xf86Int10InfoRec allocated. + +2. Bool MapCurrentInt10(xf86Int10InfoPtr pInt); + +In case a platform specific mapping has to be performed to map the +memory allocated for the real mode memory environment into a specific +location prior to executing the x86 real mode code a function + + Bool MapCurrentInt10(xf86Int10InfoPtr pInt); + +has to be provided. It will be called by a helper function whenever +the active entity changes. If the vm86 mode is used it is most likely +that the 1MB real mode memory space located somewhere in the processes +virtual memory will have to be remapped to address 0 of the virtual +memory space. + +3. void xf86FreeInt10(xf86Int10InfoPtr pInt); + +To free all memory allocated for video BIOS calls of a specific entity +the function + + void xf86FreeInt10(xf86Int10InfoPtr pInt); + +should be provided. If the entity to be freed was mapped by +MapCurrentInt10() this mapping needs to be undone also. + +4. + void * xf86Int10AllocPages(xf86Int10InfoPtr pInt,int num, int *off) + void xf86Int10FreePages(xf86Int10InfoPtr pInt, void *pbase, int num) + +xf86Int10AllocPages() should allocate 'num' consecutive page-size +chunks of memory. In real mode memory space this range needs to occupy +consecutive addresses, too. The function must return the address of +this memory. The offset in real mode memory needs to be returned in +'off'. If no block of 'num' pages are available the function should +return NULL. + +xf86Int10FreePages() will free the 'num' pages starting at 'pbase'. +'num' is equal to the number of pages allocated by a single +xf86Int10AllocatePages() call. 'pbase' is the address of the range +previously returned by xf86Int10AllocatePages(). + +II. Emulator specific functions +------------------------------- + +1. Bool xf86Int10ExecSetup(xf86Int10InfoPtr pInt); + +This function will be called from xf86InitInt10(). It may be used to +set up the static emulator specific part of the real mode +environment. On success it should return TRUE. + +2. xf86ExecX86int10(xf86Int10InfoPtr pInt); + +This function gets called to execute an int call. It may call the +helper function: + + void setup_int(xf86Int10InfoPrt pInt); + +to copy the register values to the emulator specific locations and to +set up the non-static real mode execution environment. On return from +setup_int() 'Int10Current' holds a pointer to the current +xf86Int10InfoRec. + +It should start execution by calling + + Bool int_handler(xf86Int10InfoPtr pInt); + +and if this function returns TRUE it should call whatever necessary to +continue execution until a 'hlt' instruction is encountered. To copy +the resulting register values back to the xf86Int10InfoRec structure + + void finish_int(xf86Int10InfoPtr pInt); + +should be called. + +Helper functions are provided to aid the implementation of a vm86 +call: + + Bool vm86_GP_fault(xf86Int10InfoPtr pInt); + +This function handles instructions which cause a vm86 call to +trap. PIO access is handled by the in/out calls as defined in +compiler.h. Optionally the PIO instructions can be logged by defining +PRINT_PORT in xf86int10.h. This is meant for debugging purposes. + +Unknown instructions and 'hlt' cause vm86_GP_fault() to return +FALSE. Otherwise TRUE is returned. + +Note: This function is currently based on the Linux vm86 call. It +might have to be modified or even rewritten for other OS. So your +milage may vary. + +Functions to dump memory, code, xf86 CPU register values and stack are +also provided. Take a look at helper.c To view a memory range the +function + + void dprint(unsigned long start, unsigned long size) + +is provided. The use should be self explanatory. + +Register and memory access functions are provided in helper_mem.c. +The PIO register access functions can trap access to PCI config space +access register (config method 1) if _PC is not defined. + +A header file 'defines.h' is required to define OS/emulator specific +ways to access memory and xf86 CPU registers: Defines need to be +provided for memory byte/work/long read/write access +(MEM_RB(name,addr),MEM_RW(name,addr),MEM_RL(name,addr), +MEM_WB(name,addr,val),MEM_WL(name,addr,val),MEM_WL(name,addr,val)) of +the real mode memory environment. 'name' will contain a pointer to the +current xf86Int10InfoRec. Currently defines are available for +vm86-mode under Linux and x86emu. They may be activated by defining +_X86EMU or _VM86_LINUX respectively. + +Note: Emulators usually are not able to pass this pointer when calling +memory access functions. In this case a global variable should be +defined which can hold this pointer. This variable can be set in +MapCurrentInt10(). It also must be set in xf86InitInt10() if this +function calls the memory access functions either directly or by +calling xf86ExecX86int10(pInt). Defines to access the emulator +specific xf86 CPU register locations are also required: +X86_EAX,...,X86_EFLAGS for access of the full 32 bit registers, +X86_AX...X86_FLAGS for access of the 16 bit registers and +XF86_AL,XF86_BL,XF86_CL,XF86_DL to access the lower byte of the +AX,BX,CX and DX register. + + +$XFree86: xc/programs/Xserver/hw/xfree86/int10/INT10.HOWTO,v 1.3 2001/04/30 14:34:57 tsi Exp $ diff --git a/hw/xfree86/int10/generic.c b/hw/xfree86/int10/generic.c new file mode 100644 index 000000000..d481f000d --- /dev/null +++ b/hw/xfree86/int10/generic.c @@ -0,0 +1,552 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/int10/generic.c,v 1.25.2.1 2003/03/20 15:14:25 tsi Exp $ */ +/* + * XFree86 int10 module + * execute BIOS int 10h calls in x86 real mode environment + * Copyright 1999 Egbert Eich + */ +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "compiler.h" +#define _INT10_PRIVATE +#include "xf86int10.h" +#include "int10Defines.h" + +#define ALLOC_ENTRIES(x) ((V_RAM / x) - 1) + +static CARD8 read_b(xf86Int10InfoPtr pInt,int addr); +static CARD16 read_w(xf86Int10InfoPtr pInt,int addr); +static CARD32 read_l(xf86Int10InfoPtr pInt,int addr); +static void write_b(xf86Int10InfoPtr pInt,int addr, CARD8 val); +static void write_w(xf86Int10InfoPtr pInt,int addr, CARD16 val); +static void write_l(xf86Int10InfoPtr pInt,int addr, CARD32 val); + +/* + * the emulator cannot pass a pointer to the current xf86Int10InfoRec + * to the memory access functions therefore store it here. + */ + +typedef struct { + int shift; + int entries; + void* base; + void* vRam; + int highMemory; + void* sysMem; + char* alloc; +} genericInt10Priv; + +#define INTPriv(x) ((genericInt10Priv*)x->private) + +int10MemRec genericMem = { + read_b, + read_w, + read_l, + write_b, + write_w, + write_l +}; + +static void MapVRam(xf86Int10InfoPtr pInt); +static void UnmapVRam(xf86Int10InfoPtr pInt); +#ifdef _PC +#define GET_HIGH_BASE(x) (((V_BIOS + size + getpagesize() - 1)/getpagesize()) \ + * getpagesize()) +#endif + +static void *sysMem = NULL; + +xf86Int10InfoPtr +xf86InitInt10(int entityIndex) +{ + return xf86ExtendedInitInt10(entityIndex, 0); +} + +xf86Int10InfoPtr +xf86ExtendedInitInt10(int entityIndex, int Flags) +{ + xf86Int10InfoPtr pInt; + void* base = 0; + void* vbiosMem = 0; + void* options = NULL; + pciVideoPtr pvp; + int screen; + legacyVGARec vga; + xf86int10BiosLocation bios; + +#ifdef _PC + int size; + CARD32 cs; +#endif + + screen = (xf86FindScreenForEntity(entityIndex))->scrnIndex; + + options = xf86HandleInt10Options(xf86Screens[screen],entityIndex); + + if (int10skip(options)) { + xfree(options); + return NULL; + } + + pInt = (xf86Int10InfoPtr)xnfcalloc(1, sizeof(xf86Int10InfoRec)); + pInt->entityIndex = entityIndex; + if (!xf86Int10ExecSetup(pInt)) + goto error0; + pInt->mem = &genericMem; + pInt->private = (pointer)xnfcalloc(1, sizeof(genericInt10Priv)); + INTPriv(pInt)->alloc = (pointer)xnfcalloc(1, ALLOC_ENTRIES(getpagesize())); + pInt->scrnIndex = screen; + base = INTPriv(pInt)->base = xnfalloc(SYS_BIOS); + + pvp = xf86GetPciInfoForEntity(entityIndex); + if (pvp) pInt->Tag = ((pciConfigPtr)(pvp->thisCard))->tag; + + /* + * we need to map video RAM MMIO as some chipsets map mmio + * registers into this range. + */ + MapVRam(pInt); +#ifdef _PC + if (!sysMem) + sysMem = xf86MapVidMem(screen, VIDMEM_MMIO, V_BIOS, + BIOS_SIZE + SYS_BIOS - V_BIOS); + INTPriv(pInt)->sysMem = sysMem; + + if (xf86ReadBIOS(0, 0, base, LOW_PAGE_SIZE) < 0) { + xf86DrvMsg(screen, X_ERROR, "Cannot read int vect\n"); + goto error1; + } + + /* + * Retrieve everything between V_BIOS and SYS_BIOS as some system BIOSes + * have executable code there. Note that xf86ReadBIOS() can only read in + * 64kB at a time. + */ + (void)memset((char *)base + V_BIOS, 0, SYS_BIOS - V_BIOS); +#if 0 + for (cs = V_BIOS; cs < SYS_BIOS; cs += V_BIOS_SIZE) + if (xf86ReadBIOS(cs, 0, (unsigned char *)base + cs, V_BIOS_SIZE) < + V_BIOS_SIZE) + xf86DrvMsg(screen, X_WARNING, + "Unable to retrieve all of segment 0x%06X.\n", cs); +#endif + INTPriv(pInt)->highMemory = V_BIOS; + + xf86int10ParseBiosLocation(options,&bios); + + if (xf86IsEntityPrimary(entityIndex) + && !(initPrimary(options))) { + + if (bios.bus == BUS_ISA && bios.location.legacy) { + xf86DrvMsg(screen, X_CONFIG, + "Overriding BIOS location: 0x%lx\n", + bios.location.legacy); + cs = bios.location.legacy >> 4; +#define CHECK_V_SEGMENT_RANGE(x) \ + if ((x << 4) < V_BIOS) {\ + xf86DrvMsg(screen, X_ERROR, \ + "V_BIOS address 0x%x out of range\n",x << 4); \ + goto error1; \ + } + CHECK_V_SEGMENT_RANGE(cs); + vbiosMem = (unsigned char *)sysMem - V_BIOS + (cs << 4); + if (!int10_check_bios(screen, cs, vbiosMem)) { + xf86DrvMsg(screen, X_ERROR, + "No V_BIOS at specified address 0x%x\n",cs << 4); + goto error1; + } + } else { + if (bios.bus == BUS_PCI) { + xf86DrvMsg(screen, X_WARNING, + "Option BiosLocation for primary device ignored: " + "It points to PCI.\n"); + xf86DrvMsg(screen, X_WARNING, + "You must set Option InitPrimary also\n"); + } + + cs = MEM_RW(pInt,((0x10<<2)+2)); + CHECK_V_SEGMENT_RANGE(cs); + vbiosMem = (unsigned char *)sysMem - V_BIOS + (cs << 4); + if (!int10_check_bios(screen, cs, vbiosMem)) { + cs = MEM_RW(pInt, (0x42 << 2) + 2); + CHECK_V_SEGMENT_RANGE(cs); + vbiosMem = (unsigned char *)sysMem - V_BIOS + (cs << 4); + if (!int10_check_bios(screen, cs, vbiosMem)) { + cs = V_BIOS >> 4; + vbiosMem = (unsigned char *)sysMem - V_BIOS + (cs << 4); + if (!int10_check_bios(screen, cs, vbiosMem)) { + xf86DrvMsg(screen, X_ERROR, "No V_BIOS found\n"); + goto error1; + } + } + } + } + + xf86DrvMsg(screen, X_INFO, "Primary V_BIOS segment is: 0x%x\n", cs); + + set_return_trap(pInt); + pInt->BIOSseg = cs; + + pInt->Flags = Flags & (SET_BIOS_SCRATCH | RESTORE_BIOS_SCRATCH); + if (! (pInt->Flags & SET_BIOS_SCRATCH)) + pInt->Flags &= ~RESTORE_BIOS_SCRATCH; + xf86Int10SaveRestoreBIOSVars(pInt, TRUE); + + } else { + BusType location_type; + int bios_location = V_BIOS; + int pci_entity; + + EntityInfoPtr pEnt = xf86GetEntityInfo(pInt->entityIndex); + reset_int_vect(pInt); + set_return_trap(pInt); + + if (bios.bus != BUS_NONE) { + switch (location_type = bios.bus) { + case BUS_PCI: + xf86DrvMsg(screen,X_CONFIG,"Overriding bios location: " + "PCI:%i:%i%i\n",bios.location.pci.bus, + bios.location.pci.dev,bios.location.pci.func); + break; + case BUS_ISA: + bios_location = bios.location.legacy; + if (bios.location.legacy) + xf86DrvMsg(screen,X_CONFIG,"Overriding bios location: " + "Legacy:0x%x\n",bios.location.legacy); + else + xf86DrvMsg(screen,X_CONFIG,"Overriding bios location: " + "Legacy\n"); + break; + default: + break; + } + } else + location_type = pEnt->location.type; + + switch (location_type) { + case BUS_PCI: + vbiosMem = (unsigned char *)base + bios_location; + if (bios.bus == BUS_PCI) + pci_entity = xf86GetPciEntity(bios.location.pci.bus, + bios.location.pci.dev, + bios.location.pci.func); + else + pci_entity = pInt->entityIndex; + if (!(size = mapPciRom(pci_entity,(unsigned char *)(vbiosMem)))) { + xf86DrvMsg(screen,X_ERROR,"Cannot read V_BIOS (3)\n"); + goto error1; + } + INTPriv(pInt)->highMemory = GET_HIGH_BASE(size); + break; + case BUS_ISA: + vbiosMem = (unsigned char *)sysMem + bios_location; +#if 0 + (void)memset(vbiosMem, 0, V_BIOS_SIZE); + if (xf86ReadBIOS(bios_location, 0, vbiosMem, V_BIOS_SIZE) + < V_BIOS_SIZE) + xf86DrvMsg(screen, X_WARNING, + "Unable to retrieve all of segment 0x%x.\n",bios_location); +#endif + if (!int10_check_bios(screen, bios_location >> 4, vbiosMem)) { + xf86DrvMsg(screen,X_ERROR,"Cannot read V_BIOS (4)\n"); + goto error1; + } + default: + goto error1; + } + xfree(pEnt); + pInt->BIOSseg = V_BIOS >> 4; + pInt->num = 0xe6; + LockLegacyVGA(pInt, &vga); + xf86ExecX86int10(pInt); + UnlockLegacyVGA(pInt, &vga); + } +#else + if (!sysMem) { + sysMem = xnfalloc(BIOS_SIZE); + setup_system_bios(sysMem); + } + INTPriv(pInt)->sysMem = sysMem; + setup_int_vect(pInt); + set_return_trap(pInt); + + /* + * Retrieve two segments: one at V_BIOS, the other 64kB beyond the first. + * This'll catch any BIOS that might have been initialised before server + * entry. + */ + vbiosMem = (char *)base + V_BIOS; + (void)memset(vbiosMem, 0, 2 * V_BIOS_SIZE); + if (xf86ReadDomainMemory(pInt->Tag, V_BIOS, V_BIOS_SIZE, vbiosMem) < + V_BIOS_SIZE) + xf86DrvMsg(screen, X_WARNING, + "Unable to retrieve all of segment 0x0C0000.\n"); + else if ((((unsigned char *)vbiosMem)[0] == 0x55) && + (((unsigned char *)vbiosMem)[1] == 0xAA) && + (((unsigned char *)vbiosMem)[2] > 0x80)) + if (xf86ReadDomainMemory(pInt->Tag, V_BIOS + V_BIOS_SIZE, V_BIOS_SIZE, + (unsigned char *)vbiosMem + V_BIOS_SIZE) < V_BIOS_SIZE) + xf86DrvMsg(screen, X_WARNING, + "Unable to retrieve all of segment 0x0D0000.\n"); + + /* + * If this adapter is the primary, use its post-init BIOS (if we can find + * it). + */ + xf86int10ParseBiosLocation(options,&bios); + + { + int bios_location = V_BIOS; + Bool done = FALSE; + vbiosMem = (unsigned char *)base + bios_location; + + if ((bios.bus == BUS_ISA) + || (bios.bus != BUS_PCI && xf86IsEntityPrimary(entityIndex))) { + if (bios.bus == BUS_ISA && bios.location.legacy) { + xf86DrvMsg(screen, X_CONFIG,"Looking for legacy V_BIOS " + "at 0x%x for %sprimary device\n", + bios.location.legacy, + xf86IsEntityPrimary(entityIndex) ? "" : "non-"); + bios_location = bios.location.legacy; + vbiosMem = (unsigned char *)base + bios_location; + } + if (int10_check_bios(screen, bios_location >> 4, vbiosMem)) + done = TRUE; + else + xf86DrvMsg(screen,X_INFO, + "No legacy BIOS found -- trying PCI\n"); + } + if (!done) { + int pci_entity; + + if (bios.bus == BUS_PCI) { + xf86DrvMsg(screen,X_CONFIG,"Looking for BIOS at PCI:%i%i%i\n", + bios.location.pci.bus,bios.location.pci.dev, + bios.location.pci.func); + pci_entity = xf86GetPciEntity(bios.location.pci.bus, + bios.location.pci.dev, + bios.location.pci.func); + } else + pci_entity = pInt->entityIndex; + + if (!mapPciRom(pci_entity, vbiosMem)) { + xf86DrvMsg(screen, X_ERROR, "Cannot read V_BIOS (5)\n"); + goto error1; + } + } + + } + + pInt->BIOSseg = V_BIOS >> 4; + pInt->num = 0xe6; + LockLegacyVGA(pInt, &vga); + xf86ExecX86int10(pInt); + UnlockLegacyVGA(pInt, &vga); +#endif + xfree(options); + return pInt; + + error1: + xfree(base); + UnmapVRam(pInt); + xfree(INTPriv(pInt)->alloc); + xfree(pInt->private); + error0: + xfree(pInt); + xfree(options); + + return NULL; +} + +static void +MapVRam(xf86Int10InfoPtr pInt) +{ + int pagesize = getpagesize(); + int size = ((VRAM_SIZE + pagesize - 1) / pagesize) * pagesize; + + INTPriv(pInt)->vRam = xf86MapDomainMemory(pInt->scrnIndex, VIDMEM_MMIO, + pInt->Tag, V_RAM, size); + + pInt->ioBase = xf86Screens[pInt->scrnIndex]->domainIOBase; +} + +static void +UnmapVRam(xf86Int10InfoPtr pInt) +{ + int screen = pInt->scrnIndex; + int pagesize = getpagesize(); + int size = ((VRAM_SIZE + pagesize - 1)/pagesize) * pagesize; + + xf86UnMapVidMem(screen, INTPriv(pInt)->vRam, size); +} + +Bool +MapCurrentInt10(xf86Int10InfoPtr pInt) +{ + /* nothing to do here */ + return TRUE; +} + +void +xf86FreeInt10(xf86Int10InfoPtr pInt) +{ + if (!pInt) + return; +#if defined (_PC) + xf86Int10SaveRestoreBIOSVars(pInt, FALSE); +#endif + if (Int10Current == pInt) + Int10Current = NULL; + xfree(INTPriv(pInt)->base); + UnmapVRam(pInt); + xfree(INTPriv(pInt)->alloc); + xfree(pInt->private); + xfree(pInt); +} + +void * +xf86Int10AllocPages(xf86Int10InfoPtr pInt, int num, int *off) +{ + int pagesize = getpagesize(); + int num_pages = ALLOC_ENTRIES(pagesize); + int i,j; + + for (i = 0; i < (num_pages - num); i++) { + if (INTPriv(pInt)->alloc[i] == 0) { + for (j = i; j < (num + i); j++) + if (INTPriv(pInt)->alloc[j] != 0) + break; + if (j == (num + i)) + break; + i += num; + } + } + if (i == (num_pages - num)) + return NULL; + + for (j = i; j < (i + num); j++) + INTPriv(pInt)->alloc[j] = 1; + + *off = (i + 1) * pagesize; + + return (char *)INTPriv(pInt)->base + *off; +} + +void +xf86Int10FreePages(xf86Int10InfoPtr pInt, void *pbase, int num) +{ + int pagesize = getpagesize(); + int first = (((char *)pbase - (char *)INTPriv(pInt)->base) / pagesize) - 1; + int i; + + for (i = first; i < (first + num); i++) + INTPriv(pInt)->alloc[i] = 0; +} + +#define OFF(addr) ((addr) & 0xffff) +#if defined _PC +# define HIGH_OFFSET (INTPriv(pInt)->highMemory) +# define HIGH_BASE V_BIOS +#else +# define HIGH_OFFSET SYS_BIOS +# define HIGH_BASE SYS_BIOS +#endif +# define SYS(addr) ((addr) >= HIGH_OFFSET) +#define V_ADDR(addr) \ + (SYS(addr) ? ((char*)INTPriv(pInt)->sysMem) + (addr - HIGH_BASE) \ + : (((char*)(INTPriv(pInt)->base) + addr))) +#define VRAM_ADDR(addr) (addr - V_RAM) +#define VRAM_BASE (INTPriv(pInt)->vRam) + +#define VRAM(addr) ((addr >= V_RAM) && (addr < (V_RAM + VRAM_SIZE))) +#define V_ADDR_RB(addr) \ + (VRAM(addr)) ? MMIO_IN8((CARD8*)VRAM_BASE,VRAM_ADDR(addr)) \ + : *(CARD8*) V_ADDR(addr) +#define V_ADDR_RW(addr) \ + (VRAM(addr)) ? MMIO_IN16((CARD16*)VRAM_BASE,VRAM_ADDR(addr)) \ + : ldw_u((pointer)V_ADDR(addr)) +#define V_ADDR_RL(addr) \ + (VRAM(addr)) ? MMIO_IN32((CARD32*)VRAM_BASE,VRAM_ADDR(addr)) \ + : ldl_u((pointer)V_ADDR(addr)) + +#define V_ADDR_WB(addr,val) \ + if(VRAM(addr)) \ + MMIO_OUT8((CARD8*)VRAM_BASE,VRAM_ADDR(addr),val); \ + else \ + *(CARD8*) V_ADDR(addr) = val; +#define V_ADDR_WW(addr,val) \ + if(VRAM(addr)) \ + MMIO_OUT16((CARD16*)VRAM_BASE,VRAM_ADDR(addr),val); \ + else \ + stw_u((val),(pointer)(V_ADDR(addr))); + +#define V_ADDR_WL(addr,val) \ + if (VRAM(addr)) \ + MMIO_OUT32((CARD32*)VRAM_BASE,VRAM_ADDR(addr),val); \ + else \ + stl_u(val,(pointer)(V_ADDR(addr))); + +static CARD8 +read_b(xf86Int10InfoPtr pInt, int addr) +{ + return V_ADDR_RB(addr); +} + +static CARD16 +read_w(xf86Int10InfoPtr pInt, int addr) +{ +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + if (OFF(addr + 1) > 0) + return V_ADDR_RW(addr); +#endif + return V_ADDR_RB(addr) | (V_ADDR_RB(addr + 1) << 8); +} + +static CARD32 +read_l(xf86Int10InfoPtr pInt, int addr) +{ +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + if (OFF(addr + 3) > 2) + return V_ADDR_RL(addr); +#endif + return V_ADDR_RB(addr) | + (V_ADDR_RB(addr + 1) << 8) | + (V_ADDR_RB(addr + 2) << 16) | + (V_ADDR_RB(addr + 3) << 24); +} + +static void +write_b(xf86Int10InfoPtr pInt, int addr, CARD8 val) +{ + V_ADDR_WB(addr,val); +} + +static void +write_w(xf86Int10InfoPtr pInt, int addr, CARD16 val) +{ +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + if (OFF(addr + 1) > 0) + { V_ADDR_WW(addr, val); } +#endif + V_ADDR_WB(addr, val); + V_ADDR_WB(addr + 1, val >> 8); +} + +static void +write_l(xf86Int10InfoPtr pInt, int addr, CARD32 val) +{ +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + if (OFF(addr + 3) > 2) + { V_ADDR_WL(addr, val); } +#endif + V_ADDR_WB(addr, val); + V_ADDR_WB(addr + 1, val >> 8); + V_ADDR_WB(addr + 2, val >> 16); + V_ADDR_WB(addr + 3, val >> 24); +} + +pointer +xf86int10Addr(xf86Int10InfoPtr pInt, CARD32 addr) +{ + return V_ADDR(addr); +} diff --git a/hw/xfree86/int10/helper_exec.c b/hw/xfree86/int10/helper_exec.c new file mode 100644 index 000000000..2d6c0eb24 --- /dev/null +++ b/hw/xfree86/int10/helper_exec.c @@ -0,0 +1,603 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/int10/helper_exec.c,v 1.24 2002/11/25 21:05:49 tsi Exp $ */ +/* + * XFree86 int10 module + * execute BIOS int 10h calls in x86 real mode environment + * Copyright 1999 Egbert Eich + * + * Part of this is based on code taken from DOSEMU + * (C) Copyright 1992, ..., 1999 the "DOSEMU-Development-Team" + */ + +/* + * To debug port accesses define PRINT_PORT. + * Note! You also have to comment out ioperm() + * in xf86EnableIO(). Otherwise we won't trap + * on PIO. + */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "compiler.h" +#define _INT10_PRIVATE +#include "int10Defines.h" +#include "xf86int10.h" + +#if !defined (_PC) && !defined (_PC_PCI) +static int pciCfg1in(CARD16 addr, CARD32 *val); +static int pciCfg1out(CARD16 addr, CARD32 val); +#endif +#if defined (_PC) +static void SetResetBIOSVars(xf86Int10InfoPtr pInt, Bool set); +#endif + +#define REG pInt + +int +setup_int(xf86Int10InfoPtr pInt) +{ + if (pInt != Int10Current) { + if (!MapCurrentInt10(pInt)) + return -1; + Int10Current = pInt; + } + X86_EAX = (CARD32) pInt->ax; + X86_EBX = (CARD32) pInt->bx; + X86_ECX = (CARD32) pInt->cx; + X86_EDX = (CARD32) pInt->dx; + X86_ESI = (CARD32) pInt->si; + X86_EDI = (CARD32) pInt->di; + X86_EBP = (CARD32) pInt->bp; + X86_ESP = 0x1000; X86_SS = pInt->stackseg >> 4; + X86_EIP = 0x0600; X86_CS = 0x0; /* address of 'hlt' */ + X86_DS = 0x40; /* standard pc ds */ + X86_ES = pInt->es; + X86_FS = 0; + X86_GS = 0; + X86_EFLAGS = X86_IF_MASK | X86_IOPL_MASK; +#if defined (_PC) + if (pInt->flags & SET_BIOS_SCRATCH) + SetResetBIOSVars(pInt, TRUE); +#endif + return xf86BlockSIGIO(); +} + +void +finish_int(xf86Int10InfoPtr pInt, int sig) +{ + xf86UnblockSIGIO(sig); + pInt->ax = (CARD32) X86_EAX; + pInt->bx = (CARD32) X86_EBX; + pInt->cx = (CARD32) X86_ECX; + pInt->dx = (CARD32) X86_EDX; + pInt->si = (CARD32) X86_ESI; + pInt->di = (CARD32) X86_EDI; + pInt->es = (CARD16) X86_ES; + pInt->bp = (CARD32) X86_EBP; + pInt->flags = (CARD32) X86_FLAGS; +#if defined (_PC) + if (pInt->flags & RESTORE_BIOS_SCRATCH) + SetResetBIOSVars(pInt, FALSE); +#endif +} + +/* general software interrupt handler */ +CARD32 +getIntVect(xf86Int10InfoPtr pInt,int num) +{ + return MEM_RW(pInt, num << 2) + (MEM_RW(pInt, (num << 2) + 2) << 4); +} + +void +pushw(xf86Int10InfoPtr pInt, CARD16 val) +{ + X86_ESP -= 2; + MEM_WW(pInt, ((CARD32) X86_SS << 4) + X86_SP, val); +} + +int +run_bios_int(int num, xf86Int10InfoPtr pInt) +{ + CARD32 eflags; +#ifndef _PC + /* check if bios vector is initialized */ + if (MEM_RW(pInt, (num << 2) + 2) == (SYS_BIOS >> 4)) { /* SYS_BIOS_SEG ?*/ + + if (num == 21 && X86_AH == 0x4e) { + xf86DrvMsg(pInt->scrnIndex, X_NOTICE, + "Failing Find-Matching-File on non-PC" + " (int 21, func 4e)\n"); + X86_AX = 2; + SET_FLAG(F_CF); + return 1; + } else { + xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2, + "Ignoring int 0x%02x call\n", num); + if (xf86GetVerbosity() > 3) { + dump_registers(pInt); + stack_trace(pInt); + } + return 1; + } + } +#endif +#ifdef PRINT_INT + ErrorF("calling card BIOS at: "); +#endif + eflags = X86_EFLAGS; +#if 0 + eflags = eflags | IF_MASK; + X86_EFLAGS = X86_EFLAGS & ~(VIF_MASK | TF_MASK | IF_MASK | NT_MASK); +#endif + pushw(pInt, eflags); + pushw(pInt, X86_CS); + pushw(pInt, X86_IP); + X86_CS = MEM_RW(pInt, (num << 2) + 2); + X86_IP = MEM_RW(pInt, num << 2); +#ifdef PRINT_INT + ErrorF("0x%x:%lx\n", X86_CS, X86_EIP); +#endif + return 1; +} + +/* Debugging stuff */ +void +dump_code(xf86Int10InfoPtr pInt) +{ + int i; + CARD32 lina = SEG_ADR((CARD32), X86_CS, IP); + + xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, "code at 0x%8.8lx:\n", lina); + for (i=0; i<0x10; i++) + xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, lina + i)); + xf86ErrorFVerb(3, "\n"); + for (; i<0x20; i++) + xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, lina + i)); + xf86ErrorFVerb(3, "\n"); +} + +void +dump_registers(xf86Int10InfoPtr pInt) +{ + xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, + "EAX=0x%8.8x, EBX=0x%8.8x, ECX=0x%8.8x, EDX=0x%8.8x\n", + X86_EAX, X86_EBX, X86_ECX, X86_EDX); + xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, + "ESP=0x%8.8x, EBP=0x%8.8x, ESI=0x%8.8x, EDI=0x%8.8x\n", + X86_ESP, X86_EBP, X86_ESI, X86_EDI); + xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, + "CS=0x%4.4x, SS=0x%4.4x," + " DS=0x%4.4x, ES=0x%4.4x, FS=0x%4.4x, GS=0x%4.4x\n", + X86_CS, X86_SS, X86_DS, X86_ES, X86_FS, X86_GS); + xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, + "EIP=0x%8.8x, EFLAGS=0x%8.8x\n", X86_EIP, X86_EFLAGS); +} + +void +stack_trace(xf86Int10InfoPtr pInt) +{ + int i = 0; + CARD32 stack = SEG_ADR((CARD32), X86_SS, SP); + CARD32 tail = (CARD32)((X86_SS << 4) + 0x1000); + + if (stack >= tail) return; + + xf86MsgVerb(X_INFO, 3, "stack at 0x%8.8lx:\n", stack); + for (; stack < tail; stack++) { + xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, stack)); + i = (i + 1) % 0x10; + if (!i) + xf86ErrorFVerb(3, "\n"); + } + if (i) + xf86ErrorFVerb(3, "\n"); +} + +int +port_rep_inb(xf86Int10InfoPtr pInt, + CARD16 port, CARD32 base, int d_f, CARD32 count) +{ + register int inc = d_f ? -1 : 1; + CARD32 dst = base; +#ifdef PRINT_PORT + ErrorF(" rep_insb(%#x) %d bytes at %p %s\n", + port, count, base, d_f ? "up" : "down"); +#endif + while (count--) { + MEM_WB(pInt, dst, x_inb(port)); + dst += inc; + } + return dst - base; +} + +int +port_rep_inw(xf86Int10InfoPtr pInt, + CARD16 port, CARD32 base, int d_f, CARD32 count) +{ + register int inc = d_f ? -2 : 2; + CARD32 dst = base; +#ifdef PRINT_PORT + ErrorF(" rep_insw(%#x) %d bytes at %p %s\n", + port, count, base, d_f ? "up" : "down"); +#endif + while (count--) { + MEM_WW(pInt, dst, x_inw(port)); + dst += inc; + } + return dst - base; +} + +int +port_rep_inl(xf86Int10InfoPtr pInt, + CARD16 port, CARD32 base, int d_f, CARD32 count) +{ + register int inc = d_f ? -4 : 4; + CARD32 dst = base; +#ifdef PRINT_PORT + ErrorF(" rep_insl(%#x) %d bytes at %p %s\n", + port, count, base, d_f ? "up" : "down"); +#endif + while (count--) { + MEM_WL(pInt, dst, x_inl(port)); + dst += inc; + } + return dst - base; +} + +int +port_rep_outb(xf86Int10InfoPtr pInt, + CARD16 port, CARD32 base, int d_f, CARD32 count) +{ + register int inc = d_f ? -1 : 1; + CARD32 dst = base; +#ifdef PRINT_PORT + ErrorF(" rep_outb(%#x) %d bytes at %p %s\n", + port, count, base, d_f ? "up" : "down"); +#endif + while (count--) { + x_outb(port, MEM_RB(pInt, dst)); + dst += inc; + } + return dst - base; +} + +int +port_rep_outw(xf86Int10InfoPtr pInt, + CARD16 port, CARD32 base, int d_f, CARD32 count) +{ + register int inc = d_f ? -2 : 2; + CARD32 dst = base; +#ifdef PRINT_PORT + ErrorF(" rep_outw(%#x) %d bytes at %p %s\n", + port, count, base, d_f ? "up" : "down"); +#endif + while (count--) { + x_outw(port, MEM_RW(pInt, dst)); + dst += inc; + } + return dst - base; +} + +int +port_rep_outl(xf86Int10InfoPtr pInt, + CARD16 port, CARD32 base, int d_f, CARD32 count) +{ + register int inc = d_f ? -4 : 4; + CARD32 dst = base; +#ifdef PRINT_PORT + ErrorF(" rep_outl(%#x) %d bytes at %p %s\n", + port, count, base, d_f ? "up" : "down"); +#endif + while (count--) { + x_outl(port, MEM_RL(pInt, dst)); + dst += inc; + } + return dst - base; +} + +CARD8 +x_inb(CARD16 port) +{ + CARD8 val; + + if (port == 0x40) { + Int10Current->inb40time++; + val = (CARD8)(Int10Current->inb40time >> + ((Int10Current->inb40time & 1) << 3)); +#ifdef PRINT_PORT + ErrorF(" inb(%#x) = %2.2x\n", port, val); +#endif +#ifdef __NOT_YET__ + } else if (port < 0x0100) { /* Don't interfere with mainboard */ + val = 0; + xf86DrvMsgVerb(Int10Current->scrnIndex, X_NOT_IMPLEMENTED, 2, + "inb 0x%4.4x\n", port); + if (xf86GetVerbosity() > 3) { + dump_registers(Int10Current); + stack_trace(Int10Current); + } +#endif /* __NOT_YET__ */ + } else { + val = inb(Int10Current->ioBase + port); +#ifdef PRINT_PORT + ErrorF(" inb(%#x) = %2.2x\n", port, val); +#endif + } + return val; +} + +CARD16 +x_inw(CARD16 port) +{ + CARD16 val; + + if (port == 0x5c) { + /* + * Emulate a PC98's timer. Typical resolution is 3.26 usec. + * Approximate this by dividing by 3. + */ + long sec, usec; + (void)getsecs(&sec, &usec); + val = (CARD16)(usec / 3); + } else { + val = inw(Int10Current->ioBase + port); + } +#ifdef PRINT_PORT + ErrorF(" inw(%#x) = %4.4x\n", port, val); +#endif + return val; +} + +void +x_outb(CARD16 port, CARD8 val) +{ + if ((port == 0x43) && (val == 0)) { + /* + * Emulate a PC's timer 0. Such timers typically have a resolution of + * some .838 usec per tick, but this can only provide 1 usec per tick. + * (Not that this matters much, given inherent emulation delays.) Use + * the bottom bit as a byte select. See inb(0x40) above. + */ + long sec, usec; + (void) getsecs(&sec, &usec); + Int10Current->inb40time = (CARD16)(usec | 1); +#ifdef PRINT_PORT + ErrorF(" outb(%#x, %2.2x)\n", port, val); +#endif +#ifdef __NOT_YET__ + } else if (port < 0x0100) { /* Don't interfere with mainboard */ + xf86DrvMsgVerb(Int10Current->scrnIndex, X_NOT_IMPLEMENTED, 2, + "outb 0x%4.4x,0x%2.2x\n", port, val); + if (xf86GetVerbosity() > 3) { + dump_registers(Int10Current); + stack_trace(Int10Current); + } +#endif /* __NOT_YET__ */ + } else { +#ifdef PRINT_PORT + ErrorF(" outb(%#x, %2.2x)\n", port, val); +#endif + outb(Int10Current->ioBase + port, val); + } +} + +void +x_outw(CARD16 port, CARD16 val) +{ +#ifdef PRINT_PORT + ErrorF(" outw(%#x, %4.4x)\n", port, val); +#endif + + outw(Int10Current->ioBase + port, val); +} + +CARD32 +x_inl(CARD16 port) +{ + CARD32 val; + +#if !defined(_PC) && !defined(_PC_PCI) + if (!pciCfg1in(port, &val)) +#endif + val = inl(Int10Current->ioBase + port); + +#ifdef PRINT_PORT + ErrorF(" inl(%#x) = %8.8x\n", port, val); +#endif + return val; +} + +void +x_outl(CARD16 port, CARD32 val) +{ +#ifdef PRINT_PORT + ErrorF(" outl(%#x, %8.8x)\n", port, val); +#endif + +#if !defined(_PC) && !defined(_PC_PCI) + if (!pciCfg1out(port, val)) +#endif + outl(Int10Current->ioBase + port, val); +} + +CARD8 +Mem_rb(CARD32 addr) +{ + return (*Int10Current->mem->rb)(Int10Current, addr); +} + +CARD16 +Mem_rw(CARD32 addr) +{ + return (*Int10Current->mem->rw)(Int10Current, addr); +} + +CARD32 +Mem_rl(CARD32 addr) +{ + return (*Int10Current->mem->rl)(Int10Current, addr); +} + +void +Mem_wb(CARD32 addr, CARD8 val) +{ + (*Int10Current->mem->wb)(Int10Current, addr, val); +} + +void +Mem_ww(CARD32 addr, CARD16 val) +{ + (*Int10Current->mem->ww)(Int10Current, addr, val); +} + +void +Mem_wl(CARD32 addr, CARD32 val) +{ + (*Int10Current->mem->wl)(Int10Current, addr, val); +} + +#if !defined(_PC) && !defined(_PC_PCI) +static CARD32 PciCfg1Addr = 0; + +#define TAG(Cfg1Addr) (Cfg1Addr & 0xffff00) +#define OFFSET(Cfg1Addr) (Cfg1Addr & 0xff) + +static int +pciCfg1in(CARD16 addr, CARD32 *val) +{ + if (addr == 0xCF8) { + *val = PciCfg1Addr; + return 1; + } + if (addr == 0xCFC) { + *val = pciReadLong(TAG(PciCfg1Addr), OFFSET(PciCfg1Addr)); + return 1; + } + return 0; +} + +static int +pciCfg1out(CARD16 addr, CARD32 val) +{ + if (addr == 0xCF8) { + PciCfg1Addr = val; + return 1; + } + if (addr == 0xCFC) { + pciWriteLong(TAG(PciCfg1Addr), OFFSET(PciCfg1Addr),val); + return 1; + } + return 0; +} +#endif + +CARD8 +bios_checksum(CARD8 *start, int size) +{ + CARD8 sum = 0; + + while (size-- > 0) + sum += *start++; + return sum; +} + +/* + * Lock/Unlock legacy VGA. Some Bioses try to be very clever and make + * an attempt to detect a legacy ISA card. If they find one they might + * act very strange: for example they might configure the card as a + * monochrome card. This might cause some drivers to choke. + * To avoid this we attempt legacy VGA by writing to all know VGA + * disable registers before we call the BIOS initialization and + * restore the original values afterwards. In beween we hold our + * breath. To get to a (possibly exising) ISA card need to disable + * our current PCI card. + */ +/* + * This is just for booting: we just want to catch pure + * legacy vga therefore we don't worry about mmio etc. + * This stuff should really go into vgaHW.c. However then + * the driver would have to load the vga-module prior to + * doing int10. + */ +void +LockLegacyVGA(xf86Int10InfoPtr pInt, legacyVGAPtr vga) +{ + xf86SetCurrentAccess(FALSE, xf86Screens[pInt->scrnIndex]); + vga->save_msr = inb(pInt->ioBase + 0x03CC); + vga->save_vse = inb(pInt->ioBase + 0x03C3); +#ifndef __ia64__ + vga->save_46e8 = inb(pInt->ioBase + 0x46E8); +#endif + vga->save_pos102 = inb(pInt->ioBase + 0x0102); + outb(pInt->ioBase + 0x03C2, ~(CARD8)0x03 & vga->save_msr); + outb(pInt->ioBase + 0x03C3, ~(CARD8)0x01 & vga->save_vse); +#ifndef __ia64__ + outb(pInt->ioBase + 0x46E8, ~(CARD8)0x08 & vga->save_46e8); +#endif + outb(pInt->ioBase + 0x0102, ~(CARD8)0x01 & vga->save_pos102); + xf86SetCurrentAccess(TRUE, xf86Screens[pInt->scrnIndex]); +} + +void +UnlockLegacyVGA(xf86Int10InfoPtr pInt, legacyVGAPtr vga) +{ + xf86SetCurrentAccess(FALSE, xf86Screens[pInt->scrnIndex]); + outb(pInt->ioBase + 0x0102, vga->save_pos102); +#ifndef __ia64__ + outb(pInt->ioBase + 0x46E8, vga->save_46e8); +#endif + outb(pInt->ioBase + 0x03C3, vga->save_vse); + outb(pInt->ioBase + 0x03C2, vga->save_msr); + xf86SetCurrentAccess(TRUE, xf86Screens[pInt->scrnIndex]); +} + +#if defined (_PC) +static void +SetResetBIOSVars(xf86Int10InfoPtr pInt, Bool set) +{ + int pagesize = getpagesize(); + unsigned char* base = xf86MapVidMem(pInt->scrnIndex, + VIDMEM_MMIO, 0, pagesize); + int i; + + if (set) { + for (i = BIOS_SCRATCH_OFF; i < BIOS_SCRATCH_END; i++) + MEM_WW(pInt, i, *(base + i)); + } else { + for (i = BIOS_SCRATCH_OFF; i < BIOS_SCRATCH_END; i++) + *(base + i) = MEM_RW(pInt, i); + } + + xf86UnMapVidMem(pInt->scrnIndex,base,pagesize); +} + +void +xf86Int10SaveRestoreBIOSVars(xf86Int10InfoPtr pInt, Bool save) +{ + int pagesize = getpagesize(); + unsigned char* base; + int i; + + if (!xf86IsEntityPrimary(pInt->entityIndex) + || (!save && !pInt->BIOSScratch)) + return; + + base = xf86MapVidMem(pInt->scrnIndex, VIDMEM_MMIO, 0, pagesize); + base += BIOS_SCRATCH_OFF; + if (save) { + if ((pInt->BIOSScratch + = xnfalloc(BIOS_SCRATCH_LEN))) + for (i = 0; i < BIOS_SCRATCH_LEN; i++) + *(((char*)pInt->BIOSScratch + i)) = *(base + i); + } else { + if (pInt->BIOSScratch) { + for (i = 0; i < BIOS_SCRATCH_LEN; i++) + *(base + i) = *(pInt->BIOSScratch + i); + xfree(pInt->BIOSScratch); + pInt->BIOSScratch = NULL; + } + } + + xf86UnMapVidMem(pInt->scrnIndex,base - BIOS_SCRATCH_OFF ,pagesize); +} +#endif diff --git a/hw/xfree86/int10/helper_mem.c b/hw/xfree86/int10/helper_mem.c new file mode 100644 index 000000000..6de89c5d9 --- /dev/null +++ b/hw/xfree86/int10/helper_mem.c @@ -0,0 +1,333 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/int10/helper_mem.c,v 1.26 2002/11/25 14:05:01 eich Exp $ */ +/* + * XFree86 int10 module + * execute BIOS int 10h calls in x86 real mode environment + * Copyright 1999 Egbert Eich + */ +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "compiler.h" +#include "xf86Pci.h" +#define _INT10_PRIVATE +#if 0 +#include "int10Defines.h" +#endif +#include "xf86int10.h" + +#define REG pInt + +typedef enum { + OPT_NOINT10, + OPT_INIT_PRIMARY, + OPT_BIOS_LOCATION +} INT10Opts; + +static const OptionInfoRec INT10Options[] = { + {OPT_NOINT10, "NoINT10", OPTV_BOOLEAN, {0}, FALSE }, + {OPT_INIT_PRIMARY, "InitPrimary", OPTV_BOOLEAN, {0}, FALSE }, + {OPT_BIOS_LOCATION, "BiosLocation", OPTV_STRING, {0}, FALSE }, + { -1, NULL, OPTV_NONE, {0}, FALSE }, +}; + +#ifdef DEBUG +void +dprint(unsigned long start, unsigned long size) +{ + int i,j; + char *c = (char *)start; + + for (j = 0; j < (size >> 4); j++) { + char *d = c; + ErrorF("\n0x%lx: ",(unsigned long)c); + for (i = 0; i<16; i++) + ErrorF("%2.2x ",(unsigned char) (*(c++))); + c = d; + for (i = 0; i<16; i++) { + ErrorF("%c",((((CARD8)(*c)) > 32) && (((CARD8)(*c)) < 128)) ? + (unsigned char) (*(c)): '.'); + c++; + } + } + ErrorF("\n"); +} +#endif + +#ifndef _PC +/* + * here we are really paranoid about faking a "real" + * BIOS. Most of this information was pulled from + * dosemu. + */ +void +setup_int_vect(xf86Int10InfoPtr pInt) +{ + int i; + + /* let the int vects point to the SYS_BIOS seg */ + for (i = 0; i < 0x80; i++) { + MEM_WW(pInt, i << 2, 0); + MEM_WW(pInt, (i << 2) + 2, SYS_BIOS >> 4); + } + + reset_int_vect(pInt); + /* font tables default location (int 1F) */ + MEM_WW(pInt,0x1f<<2,0xfa6e); + + /* int 11 default location (Get Equipment Configuration) */ + MEM_WW(pInt, 0x11 << 2, 0xf84d); + /* int 12 default location (Get Conventional Memory Size) */ + MEM_WW(pInt, 0x12 << 2, 0xf841); + /* int 15 default location (I/O System Extensions) */ + MEM_WW(pInt, 0x15 << 2, 0xf859); + /* int 1A default location (RTC, PCI and others) */ + MEM_WW(pInt, 0x1a << 2, 0xff6e); + /* int 05 default location (Bound Exceeded) */ + MEM_WW(pInt, 0x05 << 2, 0xff54); + /* int 08 default location (Double Fault) */ + MEM_WW(pInt, 0x08 << 2, 0xfea5); + /* int 13 default location (Disk) */ + MEM_WW(pInt, 0x13 << 2, 0xec59); + /* int 0E default location (Page Fault) */ + MEM_WW(pInt, 0x0e << 2, 0xef57); + /* int 17 default location (Parallel Port) */ + MEM_WW(pInt, 0x17 << 2, 0xefd2); + /* fdd table default location (int 1e) */ + MEM_WW(pInt, 0x1e << 2, 0xefc7); + + /* Set Equipment flag to VGA */ + i = MEM_RB(pInt, 0x0410) & 0xCF; + MEM_WB(pInt, 0x0410, i); + /* XXX Perhaps setup more of the BDA here. See also int42(0x00). */ +} +#endif + +int +setup_system_bios(void *base_addr) +{ + char *base = (char *) base_addr; + + /* + * we trap the "industry standard entry points" to the BIOS + * and all other locations by filling them with "hlt" + * TODO: implement hlt-handler for these + */ + memset(base, 0xf4, 0x10000); + + /* set bios date */ + strcpy(base + 0x0FFF5, "06/11/99"); + /* set up eisa ident string */ + strcpy(base + 0x0FFD9, "PCI_ISA"); + /* write system model id for IBM-AT */ + *((unsigned char *)(base + 0x0FFFE)) = 0xfc; + + return 1; +} + +void +reset_int_vect(xf86Int10InfoPtr pInt) +{ + /* + * This table is normally located at 0xF000:0xF0A4. However, int 0x42, + * function 0 (Mode Set) expects it (or a copy) somewhere in the bottom + * 64kB. Note that because this data doesn't survive POST, int 0x42 should + * only be used during EGA/VGA BIOS initialisation. + */ + static const CARD8 VideoParms[] = { + /* Timing for modes 0x00 & 0x01 */ + 0x38, 0x28, 0x2d, 0x0a, 0x1f, 0x06, 0x19, 0x1c, + 0x02, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + /* Timing for modes 0x02 & 0x03 */ + 0x71, 0x50, 0x5a, 0x0a, 0x1f, 0x06, 0x19, 0x1c, + 0x02, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + /* Timing for modes 0x04, 0x05 & 0x06 */ + 0x38, 0x28, 0x2d, 0x0a, 0x7f, 0x06, 0x64, 0x70, + 0x02, 0x01, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + /* Timing for mode 0x07 */ + 0x61, 0x50, 0x52, 0x0f, 0x19, 0x06, 0x19, 0x19, + 0x02, 0x0d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + /* Display page lengths in little endian order */ + 0x00, 0x08, /* Modes 0x00 and 0x01 */ + 0x00, 0x10, /* Modes 0x02 and 0x03 */ + 0x00, 0x40, /* Modes 0x04 and 0x05 */ + 0x00, 0x40, /* Modes 0x06 and 0x07 */ + /* Number of columns for each mode */ + 40, 40, 80, 80, 40, 40, 80, 80, + /* CGA Mode register value for each mode */ + 0x2c, 0x28, 0x2d, 0x29, 0x2a, 0x2e, 0x1e, 0x29, + /* Padding */ + 0x00, 0x00, 0x00, 0x00 + }; + int i; + + for (i = 0; i < sizeof(VideoParms); i++) + MEM_WB(pInt, i + (0x1000 - sizeof(VideoParms)), VideoParms[i]); + MEM_WW(pInt, 0x1d << 2, 0x1000 - sizeof(VideoParms)); + MEM_WW(pInt, (0x1d << 2) + 2, 0); + + MEM_WW(pInt, 0x10 << 2, 0xf065); + MEM_WW(pInt, (0x10 << 2) + 2, SYS_BIOS >> 4); + MEM_WW(pInt, 0x42 << 2, 0xf065); + MEM_WW(pInt, (0x42 << 2) + 2, SYS_BIOS >> 4); + MEM_WW(pInt, 0x6D << 2, 0xf065); + MEM_WW(pInt, (0x6D << 2) + 2, SYS_BIOS >> 4); +} + +void +set_return_trap(xf86Int10InfoPtr pInt) +{ + /* + * Here we set the exit condition: We return when we encounter + * 'hlt' (=0xf4), which we locate at address 0x600 in x86 memory. + */ + MEM_WB(pInt, 0x0600, 0xf4); + + /* + * Allocate a segment for the stack + */ + xf86Int10AllocPages(pInt, 1, &pInt->stackseg); +} + +void * +xf86HandleInt10Options(ScrnInfoPtr pScrn, int entityIndex) +{ + EntityInfoPtr pEnt = xf86GetEntityInfo(entityIndex); + OptionInfoPtr options = NULL; + + if (pEnt->device) { + pointer configOptions = NULL; + + /* Check if xf86CollectOptions() has already been called */ + if (((pEnt->index < 0) || + !pScrn || + !(configOptions = pScrn->options)) && + pEnt->device) + configOptions = pEnt->device->options; + + if (configOptions) { + if (!(options = (OptionInfoPtr) xalloc(sizeof(INT10Options)))) + return NULL; + + (void)memcpy(options, INT10Options, sizeof(INT10Options)); + xf86ProcessOptions(pScrn->scrnIndex, configOptions, options); + } + } + xfree(pEnt); + + return options; +} + +Bool +int10skip(void* options) +{ + Bool noint10 = FALSE; + + if (!options) return FALSE; + + xf86GetOptValBool(options, OPT_NOINT10, &noint10); + return noint10; +} + +Bool +int10_check_bios(int scrnIndex, int codeSeg, unsigned char* vbiosMem) +{ + int size; + + if ((codeSeg & 0x1f) || /* Not 512-byte aligned otherwise */ + ((codeSeg << 4) < V_BIOS) || + ((codeSeg << 4) >= SYS_SIZE)) + return FALSE; + + if (xf86IsPc98()) + return FALSE; + + if ((*vbiosMem != 0x55) || (*(vbiosMem+1) != 0xAA) || !*(vbiosMem+2)) + return FALSE; + + size = *(vbiosMem + 2) * 512; + + if ((size + (codeSeg << 4)) > SYS_SIZE) + return FALSE; + + if (bios_checksum(vbiosMem, size)) + xf86DrvMsg(scrnIndex, X_WARNING, "Bad V_BIOS checksum\n"); + + return TRUE; +} + +Bool +initPrimary(void* options) +{ + Bool initPrimary = FALSE; + + if (!options) return FALSE; + + xf86GetOptValBool(options, OPT_INIT_PRIMARY, &initPrimary); + return initPrimary; +} + +/* + * xf86int10ParseBiosLocation(): allows to set the location of the + * BIOS. One may select a BIOS of another card for posting or the + * legacy V_BIOS range located at 0xc0000 or an alternative address + * (BUS_ISA). + * This is only useful under very special circumstances and should + * be used with extreme care. + */ +void +xf86int10ParseBiosLocation(void* options, + xf86int10BiosLocationPtr bios) +{ + char *s; + char *p; + char *str = NULL; + + if (options) + str = xf86GetOptValString(options,OPT_BIOS_LOCATION); + + bios->bus = BUS_NONE; + if (!str) + return; + + s = xstrdup(str); + p = strtok(s,":"); + if (xf86NameCmp(p,"pci") == 0) bios->bus = BUS_PCI; + else + if (xf86NameCmp(p,"primary") == 0) bios->bus = BUS_ISA; + + xfree(s); + + if (bios->bus == BUS_NONE) return; + + s = xstrdup(str); + p = strchr(s, ':'); + + switch (bios->bus) { + case BUS_ISA: + if (p) + bios->location.legacy = atoi(++p); + else + bios->location.legacy = 0; + break; + case BUS_PCI: + if (p) { + bios->location.pci.bus = atoi(++p); + if ((p = strchr(p, ':'))) { + bios->location.pci.dev = atoi(++p); + if ((p = strchr(p, ':'))) { + bios->location.pci.func = atoi(++p); + break; + } + } + } + /* fall through */ + bios->bus = BUS_NONE; + break; + default: + break; + } + xfree(s); +} + + + diff --git a/hw/xfree86/int10/pci.c b/hw/xfree86/int10/pci.c new file mode 100644 index 000000000..debd842e7 --- /dev/null +++ b/hw/xfree86/int10/pci.c @@ -0,0 +1,51 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/int10/pci.c,v 1.12 2002/04/04 14:05:51 eich Exp $ */ + +/* + * XFree86 int10 module + * execute BIOS int 10h calls in x86 real mode environment + * Copyright 1999 Egbert Eich + */ +#include "xf86Pci.h" +#include "xf86.h" +#include "xf86_ansic.h" +#define _INT10_PRIVATE +#include "xf86int10.h" + +int +mapPciRom(int pciEntity, unsigned char * address) +{ + PCITAG tag; + unsigned char *mem, *ptr; + int length; + + pciVideoPtr pvp = xf86GetPciInfoForEntity(pciEntity); + + if (pvp == NULL) { +#ifdef DEBUG + ErrorF("mapPciRom: no PCI info\n"); +#endif + return 0; + } + + tag = pciTag(pvp->bus,pvp->device,pvp->func); + length = 1 << pvp->biosSize; + + /* Read in entire PCI ROM */ + mem = ptr = xnfcalloc(length, 1); + length = xf86ReadPciBIOS(0, tag, -1, ptr, length); + if (length > 0) + memcpy(address, ptr, length); + /* unmap/close/disable PCI bios mem */ + xfree(mem); + +#ifdef DEBUG + if (!length) + ErrorF("mapPciRom: no BIOS found\n"); +#ifdef PRINT_PCI + else + dprint(address,0x20); +#endif +#endif + + return length; +} diff --git a/hw/xfree86/int10/stub.c b/hw/xfree86/int10/stub.c new file mode 100644 index 000000000..f6b38580c --- /dev/null +++ b/hw/xfree86/int10/stub.c @@ -0,0 +1,66 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/int10/stub.c,v 1.4 2002/04/04 14:05:51 eich Exp $ */ +/* + * XFree86 int10 module + * execute BIOS int 10h calls in x86 real mode environment + * Copyright 1999 Egbert Eich + */ +#include "xf86.h" +#include "xf86str.h" +#include "xf86_OSproc.h" +#define _INT10_PRIVATE +#include "xf86int10.h" + +xf86Int10InfoPtr +xf86InitInt10(int entityIndex) +{ + return xf86ExtendedInitInt10(entityIndex, 0); +} + +xf86Int10InfoPtr +xf86ExtendedInitInt10(int entityIndex, int Flags) +{ + return NULL; +} + +Bool +MapCurrentInt10(xf86Int10InfoPtr pInt) +{ + return FALSE; +} + +void +xf86FreeInt10(xf86Int10InfoPtr pInt) +{ + return; +} + +void * +xf86Int10AllocPages(xf86Int10InfoPtr pInt,int num, int *off) +{ + *off = 0; + return NULL; +} + +void +xf86Int10FreePages(xf86Int10InfoPtr pInt, void *pbase, int num) +{ + return; +} + +Bool +xf86Int10ExecSetup(xf86Int10InfoPtr pInt) +{ + return FALSE; +} + +void +xf86ExecX86int10(xf86Int10InfoPtr pInt) +{ + return; +} + +pointer +xf86int10Addr(xf86Int10InfoPtr pInt, CARD32 addr) +{ + return 0; +} diff --git a/hw/xfree86/int10/xf86int10.c b/hw/xfree86/int10/xf86int10.c new file mode 100644 index 000000000..d6c5d1f43 --- /dev/null +++ b/hw/xfree86/int10/xf86int10.c @@ -0,0 +1,787 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/int10/xf86int10.c,v 1.10.2.1 2003/03/21 22:29:59 tsi Exp $ */ +/* + * XFree86 int10 module + * execute BIOS int 10h calls in x86 real mode environment + * Copyright 1999 Egbert Eich + */ + +#include "xf86.h" +#include "xf86_ansic.h" +#include "compiler.h" +#define _INT10_PRIVATE +#include "xf86int10.h" +#include "int10Defines.h" + +#define REG pInt + +xf86Int10InfoPtr Int10Current = NULL; + +static int int1A_handler(xf86Int10InfoPtr pInt); +#ifndef _PC +static int int42_handler(xf86Int10InfoPtr pInt); +#endif +static int intE6_handler(xf86Int10InfoPtr pInt); +static PCITAG findPci(xf86Int10InfoPtr pInt, unsigned short bx); +static CARD32 pciSlotBX(pciVideoPtr pvp); + +int +int_handler(xf86Int10InfoPtr pInt) +{ + int num = pInt->num; + int ret = 0; + + switch (num) { +#ifndef _PC + case 0x10: + case 0x42: + case 0x6D: + if (getIntVect(pInt, num) == I_S_DEFAULT_INT_VECT) + ret = int42_handler(pInt); + break; +#endif + case 0x1A: + ret = int1A_handler(pInt); + break; + case 0xe6: + ret = intE6_handler(pInt); + break; + default: + break; + } + + if (!ret) + ret = run_bios_int(num, pInt); + + if (!ret) { + xf86DrvMsg(pInt->scrnIndex, X_ERROR, + "Halting on int 0x%2.2x!\n", num); + dump_registers(pInt); + stack_trace(pInt); + } + + return ret; +} + +#ifndef _PC +/* + * This is derived from a number of PC system BIOS'es. The intent here is to + * provide very primitive video support, before an EGA/VGA BIOS installs its + * own interrupt vector. Here, "Ignored" calls should remain so. "Not + * Implemented" denotes functionality that can be implemented should the need + * arise. What are "Not Implemented" throughout are video memory accesses. + * Also, very little input validity checking is done here. + */ +static int +int42_handler(xf86Int10InfoPtr pInt) +{ + switch (X86_AH) { + case 0x00: + /* Set Video Mode */ + /* Enter: AL = video mode number */ + /* Leave: Nothing */ + /* Implemented (except for clearing the screen) */ + { /* Localise */ + IOADDRESS ioport; + int i; + CARD16 int1d, regvals, tmp; + CARD8 mode, cgamode, cgacolour; + + /* + * Ignore all mode numbers but 0x00-0x13. Some systems also ignore + * 0x0B and 0x0C, but don't do that here. + */ + if (X86_AL > 0x13) + break; + + /* + * You didn't think that was really the mode set, did you? There + * are only so many slots in the video parameter table... + */ + mode = X86_AL; + ioport = 0x03D4; + switch (MEM_RB(pInt, 0x0410) & 0x30) { + case 0x30: /* MDA */ + mode = 0x07; /* Force mode to 0x07 */ + ioport = 0x03B4; + break; + case 0x10: /* CGA 40x25 */ + if (mode >= 0x07) + mode = 0x01; + break; + case 0x20: /* CGA 80x25 (MCGA?) */ + if (mode >= 0x07) + mode = 0x03; + break; + case 0x00: /* EGA/VGA */ + if (mode >= 0x07) /* Don't try MDA timings */ + mode = 0x01; /* !?!?! */ + break; + } + + /* Locate data in video parameter table */ + int1d = MEM_RW(pInt, 0x1d << 2); + regvals = ((mode >> 1) << 4) + int1d; + cgacolour = 0x30; + if (mode == 0x06) { + regvals -= 0x10; + cgacolour = 0x3F; + } + + /** Update BIOS Data Area **/ + + /* Video mode */ + MEM_WB(pInt, 0x0449, mode); + + /* Columns */ + tmp = MEM_RB(pInt, mode + int1d + 0x48); + MEM_WW(pInt, 0x044A, tmp); + + /* Page length */ + tmp = MEM_RW(pInt, (mode & 0x06) + int1d + 0x40); + MEM_WW(pInt, 0x044C, tmp); + + /* Start Address */ + MEM_WW(pInt, 0x044E, 0); + + /* Cursor positions, one for each display page */ + for (i = 0x0450; i < 0x0460; i += 2) + MEM_WW(pInt, i, 0); + + /* Cursor start & end scanlines */ + tmp = MEM_RB(pInt, regvals + 0x0B); + MEM_WB(pInt, 0x0460, tmp); + tmp = MEM_RB(pInt, regvals + 0x0A); + MEM_WB(pInt, 0x0461, tmp); + + /* Current display page number */ + MEM_WB(pInt, 0x0462, 0); + + /* CRTC I/O address */ + MEM_WW(pInt, 0x0463, ioport); + + /* CGA Mode register value */ + cgamode = MEM_RB(pInt, mode + int1d + 0x50); + MEM_WB(pInt, 0x0465, cgamode); + + /* CGA Colour register value */ + MEM_WB(pInt, 0x0466, cgacolour); + + /* Rows */ + MEM_WB(pInt, 0x0484, (25 - 1)); + + /* Remap I/O port number into its domain */ + ioport += pInt->ioBase; + + /* Programme the mode */ + outb(ioport + 4, cgamode & 0x37); /* Turn off screen */ + for (i = 0; i < 0x10; i++) { + tmp = MEM_RB(pInt, regvals + i); + outb(ioport, i); + outb(ioport + 1, tmp); + } + outb(ioport + 5, cgacolour); /* Select colour mode */ + outb(ioport + 4, cgamode); /* Turn on screen */ + } + break; + + case 0x01: + /* Set Cursor Type */ + /* Enter: CH = starting line for cursor */ + /* CL = ending line for cursor */ + /* Leave: Nothing */ + /* Implemented */ + { /* Localise */ + IOADDRESS ioport = MEM_RW(pInt, 0x0463) + pInt->ioBase; + + MEM_WB(pInt, 0x0460, X86_CL); + MEM_WB(pInt, 0x0461, X86_CH); + + outb(ioport, 0x0A); + outb(ioport + 1, X86_CH); + outb(ioport, 0x0B); + outb(ioport + 1, X86_CL); + } + break; + + case 0x02: + /* Set Cursor Position */ + /* Enter: BH = display page number */ + /* DH = row */ + /* DL = column */ + /* Leave: Nothing */ + /* Implemented */ + { /* Localise */ + IOADDRESS ioport; + CARD16 offset; + + MEM_WB(pInt, (X86_BH << 1) + 0x0450, X86_DL); + MEM_WB(pInt, (X86_BH << 1) + 0x0451, X86_DH); + + if (X86_BH != MEM_RB(pInt, 0x0462)) + break; + + offset = (X86_DH * MEM_RW(pInt, 0x044A)) + X86_DL; + offset += MEM_RW(pInt, 0x044E) << 1; + + ioport = MEM_RW(pInt, 0x0463) + pInt->ioBase; + outb(ioport, 0x0E); + outb(ioport + 1, offset >> 8); + outb(ioport, 0x0F); + outb(ioport + 1, offset & 0xFF); + } + break; + + case 0x03: + /* Get Cursor Position */ + /* Enter: BH = display page number */ + /* Leave: CH = starting line for cursor */ + /* CL = ending line for cursor */ + /* DH = row */ + /* DL = column */ + /* Implemented */ + { /* Localise */ + X86_CL = MEM_RB(pInt, 0x0460); + X86_CH = MEM_RB(pInt, 0x0461); + X86_DL = MEM_RB(pInt, (X86_BH << 1) + 0x0450); + X86_DH = MEM_RB(pInt, (X86_BH << 1) + 0x0451); + } + break; + + case 0x04: + /* Get Light Pen Position */ + /* Enter: Nothing */ + /* Leave: AH = 0x01 (down/triggered) or 0x00 (not) */ + /* BX = pixel column */ + /* CX = pixel row */ + /* DH = character row */ + /* DL = character column */ + /* Not Implemented */ + { /* Localise */ + xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2, + "int 0x%2.2x(AH=0x04) -- Get Light Pen Position\n", pInt->num); + if (xf86GetVerbosity() > 3) { + dump_registers(pInt); + stack_trace(pInt); + } + X86_AH = X86_BX = X86_CX = X86_DX = 0; + } + break; + + case 0x05: + /* Set Display Page */ + /* Enter: AL = display page number */ + /* Leave: Nothing */ + /* Implemented */ + { /* Localise */ + IOADDRESS ioport = MEM_RW(pInt, 0x0463) + pInt->ioBase; + CARD16 start; + CARD8 x, y; + + /* Calculate new start address */ + MEM_WB(pInt, 0x0462, X86_AL); + start = X86_AL * MEM_RW(pInt, 0x044C); + MEM_WW(pInt, 0x044E, start); + start <<= 1; + + /* Update start address */ + outb(ioport, 0x0C); + outb(ioport + 1, start >> 8); + outb(ioport, 0x0D); + outb(ioport + 1, start & 0xFF); + + /* Switch cursor position */ + y = MEM_RB(pInt, (X86_AL << 1) + 0x0450); + x = MEM_RB(pInt, (X86_AL << 1) + 0x0451); + start += (y * MEM_RW(pInt, 0x044A)) + x; + + /* Update cursor position */ + outb(ioport, 0x0E); + outb(ioport + 1, start >> 8); + outb(ioport, 0x0F); + outb(ioport + 1, start & 0xFF); + } + break; + + case 0x06: + /* Initialise or Scroll Window Up */ + /* Enter: AL = lines to scroll up */ + /* BH = attribute for blank */ + /* CH = upper y of window */ + /* CL = left x of window */ + /* DH = lower y of window */ + /* DL = right x of window */ + /* Leave: Nothing */ + /* Not Implemented */ + { /* Localise */ + xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2, + "int 0x%2.2x(AH=0x06) -- Initialise or Scroll Window Up\n", + pInt->num); + xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 3, + " AL=0x%2.2x, BH=0x%2.2x," + " CH=0x%2.2x, CL=0x%2.2x, DH=0x%2.2x, DL=0x%2.2x\n", + X86_AL, X86_BH, X86_CH, X86_CL, X86_DH, X86_DL); + if (xf86GetVerbosity() > 3) { + dump_registers(pInt); + stack_trace(pInt); + } + } + break; + + case 0x07: + /* Initialise or Scroll Window Down */ + /* Enter: AL = lines to scroll down */ + /* BH = attribute for blank */ + /* CH = upper y of window */ + /* CL = left x of window */ + /* DH = lower y of window */ + /* DL = right x of window */ + /* Leave: Nothing */ + /* Not Implemented */ + { /* Localise */ + xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2, + "int 0x%2.2x(AH=0x07) -- Initialise or Scroll Window Down\n", + pInt->num); + xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 3, + " AL=0x%2.2x, BH=0x%2.2x," + " CH=0x%2.2x, CL=0x%2.2x, DH=0x%2.2x, DL=0x%2.2x\n", + X86_AL, X86_BH, X86_CH, X86_CL, X86_DH, X86_DL); + if (xf86GetVerbosity() > 3) { + dump_registers(pInt); + stack_trace(pInt); + } + } + break; + + case 0x08: + /* Read Character and Attribute at Cursor */ + /* Enter: BH = display page number */ + /* Leave: AH = attribute */ + /* AL = character */ + /* Not Implemented */ + { /* Localise */ + xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2, + "int 0x%2.2x(AH=0x08) -- Read Character and Attribute at" + " Cursor\n", pInt->num); + xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 3, + "BH=0x%2.2x\n", X86_BH); + if (xf86GetVerbosity() > 3) { + dump_registers(pInt); + stack_trace(pInt); + } + X86_AX = 0; + } + break; + + case 0x09: + /* Write Character and Attribute at Cursor */ + /* Enter: AL = character */ + /* BH = display page number */ + /* BL = attribute (text) or colour (graphics) */ + /* CX = replication count */ + /* Leave: Nothing */ + /* Not Implemented */ + { /* Localise */ + xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2, + "int 0x%2.2x(AH=0x09) -- Write Character and Attribute at" + " Cursor\n", pInt->num); + xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 3, + "AL=0x%2.2x, BH=0x%2.2x, BL=0x%2.2x, CX=0x%4.4x\n", + X86_AL, X86_BH, X86_BL, X86_CX); + if (xf86GetVerbosity() > 3) { + dump_registers(pInt); + stack_trace(pInt); + } + } + break; + + case 0x0a: + /* Write Character at Cursor */ + /* Enter: AL = character */ + /* BH = display page number */ + /* BL = colour */ + /* CX = replication count */ + /* Leave: Nothing */ + /* Not Implemented */ + { /* Localise */ + xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2, + "int 0x%2.2x(AH=0x0A) -- Write Character at Cursor\n", + pInt->num); + xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 3, + "AL=0x%2.2x, BH=0x%2.2x, BL=0x%2.2x, CX=0x%4.4x\n", + X86_AL, X86_BH, X86_BL, X86_CX); + if (xf86GetVerbosity() > 3) { + dump_registers(pInt); + stack_trace(pInt); + } + } + break; + + case 0x0b: + /* Set Palette, Background or Border */ + /* Enter: BH = 0x00 or 0x01 */ + /* BL = colour or palette (respectively) */ + /* Leave: Nothing */ + /* Implemented */ + { /* Localise */ + IOADDRESS ioport = MEM_RW(pInt, 0x0463) + 5 + pInt->ioBase; + CARD8 cgacolour = MEM_RB(pInt, 0x0466); + + if (X86_BH) { + cgacolour &= 0xDF; + cgacolour |= (X86_BL & 0x01) << 5; + } else { + cgacolour &= 0xE0; + cgacolour |= X86_BL & 0x1F; + } + + MEM_WB(pInt, 0x0466, cgacolour); + outb(ioport, cgacolour); + } + break; + + case 0x0c: + /* Write Graphics Pixel */ + /* Enter: AL = pixel value */ + /* BH = display page number */ + /* CX = column */ + /* DX = row */ + /* Leave: Nothing */ + /* Not Implemented */ + { /* Localise */ + xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2, + "int 0x%2.2x(AH=0x0C) -- Write Graphics Pixel\n", pInt->num); + xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 3, + "AL=0x%2.2x, BH=0x%2.2x, CX=0x%4.4x, DX=0x%4.4x\n", + X86_AL, X86_BH, X86_CX, X86_DX); + if (xf86GetVerbosity() > 3) { + dump_registers(pInt); + stack_trace(pInt); + } + } + break; + + case 0x0d: + /* Read Graphics Pixel */ + /* Enter: BH = display page number */ + /* CX = column */ + /* DX = row */ + /* Leave: AL = pixel value */ + /* Not Implemented */ + { /* Localise */ + xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2, + "int 0x%2.2x(AH=0x0D) -- Read Graphics Pixel\n", pInt->num); + xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 3, + "BH=0x%2.2x, CX=0x%4.4x, DX=0x%4.4x\n", + X86_BH, X86_CX, X86_DX); + if (xf86GetVerbosity() > 3) { + dump_registers(pInt); + stack_trace(pInt); + } + X86_AL = 0; + } + break; + + case 0x0e: + /* Write Character in Teletype Mode */ + /* Enter: AL = character */ + /* BH = display page number */ + /* BL = foreground colour */ + /* Leave: Nothing */ + /* Not Implemented */ + /* WARNING: Emulation of BEL characters will require */ + /* emulation of RTC and PC speaker I/O. */ + /* Also, this recurses through int 0x10 */ + /* which might or might not have been */ + /* installed yet. */ + { /* Localise */ + xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2, + "int 0x%2.2x(AH=0x0E) -- Write Character in Teletype Mode\n", + pInt->num); + xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 3, + "AL=0x%2.2x, BH=0x%2.2x, BL=0x%2.2x\n", + X86_AL, X86_BH, X86_BL); + if (xf86GetVerbosity() > 3) { + dump_registers(pInt); + stack_trace(pInt); + } + } + break; + + case 0x0f: + /* Get Video Mode */ + /* Enter: Nothing */ + /* Leave: AH = number of columns */ + /* AL = video mode number */ + /* BH = display page number */ + /* Implemented */ + { /* Localise */ + X86_AH = MEM_RW(pInt, 0x044A); + X86_AL = MEM_RB(pInt, 0x0449); + X86_BH = MEM_RB(pInt, 0x0462); + } + break; + + case 0x10: + /* Colour Control (subfunction in AL) */ + /* Enter: Various */ + /* Leave: Various */ + /* Ignored */ + break; + + case 0x11: + /* Font Control (subfunction in AL) */ + /* Enter: Various */ + /* Leave: Various */ + /* Ignored */ + break; + + case 0x12: + /* Miscellaneous (subfunction in BL) */ + /* Enter: Various */ + /* Leave: Various */ + /* Ignored. Previous code here optionally allowed */ + /* the enabling and disabling of VGA, but no system */ + /* BIOS I've come across actually implements it. */ + break; + + case 0x13: + /* Write String in Teletype Mode */ + /* Enter: AL = write mode */ + /* BL = attribute (if (AL & 0x02) == 0) */ + /* CX = string length */ + /* DH = row */ + /* DL = column */ + /* ES:BP = string segment:offset */ + /* Leave: Nothing */ + /* Not Implemented */ + /* WARNING: Emulation of BEL characters will require */ + /* emulation of RTC and PC speaker I/O. */ + /* Also, this recurses through int 0x10 */ + /* which might or might not have been */ + /* installed yet. */ + { /* Localise */ + xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2, + "int 0x%2.2x(AH=0x13) -- Write String in Teletype Mode\n", + pInt->num); + xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 3, + "AL=0x%2.2x, BL=0x%2.2x, CX=0x%4.4x," + " DH=0x%2.2x, DL=0x%2.2x, ES:BP=0x%4.4x:0x%4.4x\n", + X86_AL, X86_BL, X86_CX, X86_DH, X86_DL, X86_ES, X86_BP); + if (xf86GetVerbosity() > 3) { + dump_registers(pInt); + stack_trace(pInt); + } + } + break; + + default: + /* Various extensions */ + /* Enter: Various */ + /* Leave: Various */ + /* Ignored */ + break; + } + + return 1; +} +#endif + +#define SUCCESSFUL 0x00 +#define DEVICE_NOT_FOUND 0x86 +#define BAD_REGISTER_NUMBER 0x87 + +static int +int1A_handler(xf86Int10InfoPtr pInt) +{ + PCITAG tag; + pciVideoPtr pvp; + + if (!(pvp = xf86GetPciInfoForEntity(pInt->entityIndex))) + return 0; /* oops */ + +#ifdef PRINT_INT + ErrorF("int 0x1a: ax=0x%x bx=0x%x cx=0x%x dx=0x%x di=0x%x es=0x%x\n", + X86_EAX, X86_EBX, X86_ECX, X86_EDX, X86_EDI, X86_ESI); +#endif + switch (X86_AX) { + case 0xb101: + X86_EAX &= 0xFF00; /* no config space/special cycle support */ + X86_EDX = 0x20494350; /* " ICP" */ + X86_EBX = 0x0210; /* Version 2.10 */ + X86_ECX &= 0xFF00; + X86_ECX |= (pciNumBuses & 0xFF); /* Max bus number in system */ + X86_EFLAGS &= ~((unsigned long)0x01); /* clear carry flag */ +#ifdef PRINT_INT + ErrorF("ax=0x%x dx=0x%x bx=0x%x cx=0x%x flags=0x%x\n", + X86_EAX, X86_EDX, X86_EBX, X86_ECX, X86_EFLAGS); +#endif + return 1; + case 0xb102: + if (X86_DX == pvp->vendor && X86_CX == pvp->chipType && X86_ESI == 0) { + X86_EAX = X86_AL | (SUCCESSFUL << 8); + X86_EFLAGS &= ~((unsigned long)0x01); /* clear carry flag */ + X86_EBX = pciSlotBX(pvp); + } +#ifdef SHOW_ALL_DEVICES + else + if ((pvp = xf86FindPciDeviceVendor(X86_EDX, X86_ECX, X86_ESI, pvp))) { + X86_EAX = X86_AL | (SUCCESSFUL << 8); + X86_EFLAGS &= ~((unsigned long)0x01); /* clear carry flag */ + X86_EBX = pciSlotBX(pvp); + } +#endif + else { + X86_EAX = X86_AL | (DEVICE_NOT_FOUND << 8); + X86_EFLAGS |= ((unsigned long)0x01); /* set carry flag */ + } +#ifdef PRINT_INT + ErrorF("ax=0x%x bx=0x%x flags=0x%x\n", X86_EAX, X86_EBX, X86_EFLAGS); +#endif + return 1; + case 0xb103: + if (X86_CL == pvp->interface && + X86_CH == pvp->subclass && + ((X86_ECX & 0xFFFF0000) >> 16) == pvp->class) { + X86_EAX = X86_AL | (SUCCESSFUL << 8); + X86_EBX = pciSlotBX(pvp); + X86_EFLAGS &= ~((unsigned long)0x01); /* clear carry flag */ + } +#ifdef SHOW_ALL_DEVICES + else if ((pvp = xf86FindPciClass(X86_CL, X86_CH, + (X86_ECX & 0xffff0000) >> 16, + X86_ESI, pvp))) { + X86_EAX = X86_AL | (SUCCESSFUL << 8); + X86_EFLAGS &= ~((unsigned long)0x01); /* clear carry flag */ + X86_EBX = pciSlotBX(pvp); + } +#endif + else { + X86_EAX = X86_AL | (DEVICE_NOT_FOUND << 8); + X86_EFLAGS |= ((unsigned long)0x01); /* set carry flag */ + } +#ifdef PRINT_INT + ErrorF("ax=0x%x flags=0x%x\n", X86_EAX, X86_EFLAGS); +#endif + return 1; + case 0xb108: + if ((tag = findPci(pInt, X86_EBX)) != PCI_NOT_FOUND) { + X86_CL = pciReadByte(tag, X86_EDI); + X86_EAX = X86_AL | (SUCCESSFUL << 8); + X86_EFLAGS &= ~((unsigned long)0x01); /* clear carry flag */ + } else { + X86_EAX = X86_AL | (BAD_REGISTER_NUMBER << 8); + X86_EFLAGS |= ((unsigned long)0x01); /* set carry flag */ + } +#ifdef PRINT_INT + ErrorF("ax=0x%x cx=0x%x flags=0x%x\n", X86_EAX, X86_ECX, X86_EFLAGS); +#endif + return 1; + case 0xb109: + if ((tag = findPci(pInt, X86_EBX)) != PCI_NOT_FOUND) { + X86_CX = pciReadWord(tag, X86_EDI); + X86_EAX = X86_AL | (SUCCESSFUL << 8); + X86_EFLAGS &= ~((unsigned long)0x01); /* clear carry flag */ + } else { + X86_EAX = X86_AL | (BAD_REGISTER_NUMBER << 8); + X86_EFLAGS |= ((unsigned long)0x01); /* set carry flag */ + } +#ifdef PRINT_INT + ErrorF("ax=0x%x cx=0x%x flags=0x%x\n", X86_EAX, X86_ECX, X86_EFLAGS); +#endif + return 1; + case 0xb10a: + if ((tag = findPci(pInt, X86_EBX)) != PCI_NOT_FOUND) { + X86_ECX = pciReadLong(tag, X86_EDI); + X86_EAX = X86_AL | (SUCCESSFUL << 8); + X86_EFLAGS &= ~((unsigned long)0x01); /* clear carry flag */ + } else { + X86_EAX = X86_AL | (BAD_REGISTER_NUMBER << 8); + X86_EFLAGS |= ((unsigned long)0x01); /* set carry flag */ + } +#ifdef PRINT_INT + ErrorF("ax=0x%x cx=0x%x flags=0x%x\n", X86_EAX, X86_ECX, X86_EFLAGS); +#endif + return 1; + case 0xb10b: + if ((tag = findPci(pInt, X86_EBX)) != PCI_NOT_FOUND) { + pciWriteByte(tag, X86_EDI, X86_CL); + X86_EAX = X86_AL | (SUCCESSFUL << 8); + X86_EFLAGS &= ~((unsigned long)0x01); /* clear carry flag */ + } else { + X86_EAX = X86_AL | (BAD_REGISTER_NUMBER << 8); + X86_EFLAGS |= ((unsigned long)0x01); /* set carry flag */ + } +#ifdef PRINT_INT + ErrorF("ax=0x%x flags=0x%x\n", X86_EAX, X86_EFLAGS); +#endif + return 1; + case 0xb10c: + if ((tag = findPci(pInt, X86_EBX)) != PCI_NOT_FOUND) { + pciWriteWord(tag, X86_EDI, X86_CX); + X86_EAX = X86_AL | (SUCCESSFUL << 8); + X86_EFLAGS &= ~((unsigned long)0x01); /* clear carry flag */ + } else { + X86_EAX = X86_AL | (BAD_REGISTER_NUMBER << 8); + X86_EFLAGS |= ((unsigned long)0x01); /* set carry flag */ + } +#ifdef PRINT_INT + ErrorF("ax=0x%x flags=0x%x\n", X86_EAX, X86_EFLAGS); +#endif + return 1; + case 0xb10d: + if ((tag = findPci(pInt, X86_EBX)) != PCI_NOT_FOUND) { + pciWriteLong(tag, X86_EDI, X86_ECX); + X86_EAX = X86_AL | (SUCCESSFUL << 8); + X86_EFLAGS &= ~((unsigned long)0x01); /* clear carry flag */ + } else { + X86_EAX = X86_AL | (BAD_REGISTER_NUMBER << 8); + X86_EFLAGS |= ((unsigned long)0x01); /* set carry flag */ + } +#ifdef PRINT_INT + ErrorF("ax=0x%x flags=0x%x\n", X86_EAX, X86_EFLAGS); +#endif + return 1; + default: + xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2, + "int 0x1a subfunction\n"); + dump_registers(pInt); + if (xf86GetVerbosity() > 3) + stack_trace(pInt); + return 0; + } +} + +static PCITAG +findPci(xf86Int10InfoPtr pInt, unsigned short bx) +{ + int bus = ((pInt->Tag >> 16) & ~0x00FF) | ((bx >> 8) & 0x00FF); + int dev = (bx >> 3) & 0x1F; + int func = bx & 0x7; + if (xf86IsPciDevPresent(bus, dev, func)) + return pciTag(bus, dev, func); + return PCI_NOT_FOUND; +} + +static CARD32 +pciSlotBX(pciVideoPtr pvp) +{ + return ((pvp->bus << 8) & 0x00FF00) | (pvp->device << 3) | (pvp->func); +} + +/* + * handle initialization + */ +static int +intE6_handler(xf86Int10InfoPtr pInt) +{ + pciVideoPtr pvp; + + if ((pvp = xf86GetPciInfoForEntity(pInt->entityIndex))) + X86_AX = (pvp->bus << 8) | (pvp->device << 3) | (pvp->func & 0x7); + pushw(pInt, X86_CS); + pushw(pInt, X86_IP); + X86_CS = pInt->BIOSseg; + X86_EIP = 0x0003; + X86_ES = 0; /* standard pc es */ + return 1; +} diff --git a/hw/xfree86/int10/xf86int10.h b/hw/xfree86/int10/xf86int10.h new file mode 100644 index 000000000..843902c5e --- /dev/null +++ b/hw/xfree86/int10/xf86int10.h @@ -0,0 +1,198 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/int10/xf86int10.h,v 1.24 2002/07/23 14:22:46 tsi Exp $ */ + +/* + * XFree86 int10 module + * execute BIOS int 10h calls in x86 real mode environment + * Copyright 1999 Egbert Eich + */ + +#ifndef _XF86INT10_H +#define _XF86INT10_H + +#include "Xmd.h" +#include "Xdefs.h" +#include "xf86Pci.h" + +#define SEG_ADDR(x) (((x) >> 4) & 0x00F000) +#define SEG_OFF(x) ((x) & 0x0FFFF) + +#define SET_BIOS_SCRATCH 0x1 +#define RESTORE_BIOS_SCRATCH 0x2 + +/* int10 info structure */ +typedef struct { + int entityIndex; + int scrnIndex; + pointer cpuRegs; + CARD16 BIOSseg; + CARD16 inb40time; + char * BIOSScratch; + int Flags; + pointer private; + struct _int10Mem* mem; + int num; + int ax; + int bx; + int cx; + int dx; + int si; + int di; + int es; + int bp; + int flags; + int stackseg; + PCITAG Tag; + IOADDRESS ioBase; +} xf86Int10InfoRec, *xf86Int10InfoPtr; + +typedef struct _int10Mem { + CARD8(*rb)(xf86Int10InfoPtr, int); + CARD16(*rw)(xf86Int10InfoPtr, int); + CARD32(*rl)(xf86Int10InfoPtr, int); + void(*wb)(xf86Int10InfoPtr, int, CARD8); + void(*ww)(xf86Int10InfoPtr, int, CARD16); + void(*wl)(xf86Int10InfoPtr, int, CARD32); +} int10MemRec, *int10MemPtr; + +typedef struct { + CARD8 save_msr; + CARD8 save_pos102; + CARD8 save_vse; + CARD8 save_46e8; +} legacyVGARec, *legacyVGAPtr; + +typedef struct { + BusType bus; + union { + struct { + int bus; + int dev; + int func; + } pci; + int legacy; + } location; +} xf86int10BiosLocation, *xf86int10BiosLocationPtr; + +/* OS dependent functions */ +xf86Int10InfoPtr xf86InitInt10(int entityIndex); +xf86Int10InfoPtr xf86ExtendedInitInt10(int entityIndex, int Flags); +void xf86FreeInt10(xf86Int10InfoPtr pInt); +void *xf86Int10AllocPages(xf86Int10InfoPtr pInt, int num, int *off); +void xf86Int10FreePages(xf86Int10InfoPtr pInt, void *pbase, int num); +pointer xf86int10Addr(xf86Int10InfoPtr pInt, CARD32 addr); + +/* x86 executor related functions */ +void xf86ExecX86int10(xf86Int10InfoPtr pInt); + +#ifdef _INT10_PRIVATE + +#define I_S_DEFAULT_INT_VECT 0xFF065 +#define SYS_SIZE 0x100000 +#define SYS_BIOS 0xF0000 +#if 1 +#define BIOS_SIZE 0x10000 +#else /* a bug in DGUX requires this - let's try it */ +#define BIOS_SIZE (0x10000 - 1) +#endif +#define LOW_PAGE_SIZE 0x600 +#define V_RAM 0xA0000 +#define VRAM_SIZE 0x20000 +#define V_BIOS_SIZE 0x10000 +#define V_BIOS 0xC0000 +#define BIOS_SCRATCH_OFF 0x449 +#define BIOS_SCRATCH_END 0x466 +#define BIOS_SCRATCH_LEN (BIOS_SCRATCH_END - BIOS_SCRATCH_OFF + 1) +#define HIGH_MEM V_BIOS +#define HIGH_MEM_SIZE (SYS_BIOS - HIGH_MEM) +#define SEG_ADR(type, seg, reg) type((seg << 4) + (X86_##reg)) +#define SEG_EADR(type, seg, reg) type((seg << 4) + (X86_E##reg)) + +#define X86_TF_MASK 0x00000100 +#define X86_IF_MASK 0x00000200 +#define X86_IOPL_MASK 0x00003000 +#define X86_NT_MASK 0x00004000 +#define X86_VM_MASK 0x00020000 +#define X86_AC_MASK 0x00040000 +#define X86_VIF_MASK 0x00080000 /* virtual interrupt flag */ +#define X86_VIP_MASK 0x00100000 /* virtual interrupt pending */ +#define X86_ID_MASK 0x00200000 + +#define MEM_RB(name, addr) (*name->mem->rb)(name, addr) +#define MEM_RW(name, addr) (*name->mem->rw)(name, addr) +#define MEM_RL(name, addr) (*name->mem->rl)(name, addr) +#define MEM_WB(name, addr, val) (*name->mem->wb)(name, addr, val) +#define MEM_WW(name, addr, val) (*name->mem->ww)(name, addr, val) +#define MEM_WL(name, addr, val) (*name->mem->wl)(name, addr, val) + +/* OS dependent functions */ +Bool MapCurrentInt10(xf86Int10InfoPtr pInt); +/* x86 executor related functions */ +Bool xf86Int10ExecSetup(xf86Int10InfoPtr pInt); + +/* int.c */ +extern xf86Int10InfoPtr Int10Current; +int int_handler(xf86Int10InfoPtr pInt); + +/* helper_exec.c */ +int setup_int(xf86Int10InfoPtr pInt); +void finish_int(xf86Int10InfoPtr, int sig); +CARD32 getIntVect(xf86Int10InfoPtr pInt, int num); +void pushw(xf86Int10InfoPtr pInt, CARD16 val); +int run_bios_int(int num, xf86Int10InfoPtr pInt); +void dump_code(xf86Int10InfoPtr pInt); +void dump_registers(xf86Int10InfoPtr pInt); +void stack_trace(xf86Int10InfoPtr pInt); +xf86Int10InfoPtr getInt10Rec(int entityIndex); +CARD8 bios_checksum(CARD8 *start, int size); +void LockLegacyVGA(xf86Int10InfoPtr pInt, legacyVGAPtr vga); +void UnlockLegacyVGA(xf86Int10InfoPtr pInt, legacyVGAPtr vga); +#if defined (_PC) +void xf86Int10SaveRestoreBIOSVars(xf86Int10InfoPtr pInt, Bool save); +#endif +int port_rep_inb(xf86Int10InfoPtr pInt, + CARD16 port, CARD32 base, int d_f, CARD32 count); +int port_rep_inw(xf86Int10InfoPtr pInt, + CARD16 port, CARD32 base, int d_f, CARD32 count); +int port_rep_inl(xf86Int10InfoPtr pInt, + CARD16 port, CARD32 base, int d_f, CARD32 count); +int port_rep_outb(xf86Int10InfoPtr pInt, + CARD16 port, CARD32 base, int d_f, CARD32 count); +int port_rep_outw(xf86Int10InfoPtr pInt, + CARD16 port, CARD32 base, int d_f, CARD32 count); +int port_rep_outl(xf86Int10InfoPtr pInt, + CARD16 port, CARD32 base, int d_f, CARD32 count); + +CARD8 x_inb(CARD16 port); +CARD16 x_inw(CARD16 port); +void x_outb(CARD16 port, CARD8 val); +void x_outw(CARD16 port, CARD16 val); +CARD32 x_inl(CARD16 port); +void x_outl(CARD16 port, CARD32 val); + +CARD8 Mem_rb(CARD32 addr); +CARD16 Mem_rw(CARD32 addr); +CARD32 Mem_rl(CARD32 addr); +void Mem_wb(CARD32 addr, CARD8 val); +void Mem_ww(CARD32 addr, CARD16 val); +void Mem_wl(CARD32 addr, CARD32 val); + +/* helper_mem.c */ +void setup_int_vect(xf86Int10InfoPtr pInt); +int setup_system_bios(void *base_addr); +void reset_int_vect(xf86Int10InfoPtr pInt); +void set_return_trap(xf86Int10InfoPtr pInt); +void * xf86HandleInt10Options(ScrnInfoPtr pScrn, int entityIndex); +Bool int10skip(void* options); +Bool int10_check_bios(int scrnIndex, int codeSeg, unsigned char* vbiosMem); +Bool initPrimary(void* options); +void xf86int10ParseBiosLocation(void* options, + xf86int10BiosLocationPtr bios); +#ifdef DEBUG +void dprint(unsigned long start, unsigned long size); +#endif + +/* pci.c */ +int mapPciRom(int pciEntity, unsigned char *address); + +#endif /* _INT10_PRIVATE */ +#endif /* _XF86INT10_H */ diff --git a/hw/xfree86/int10/xf86int10module.c b/hw/xfree86/int10/xf86int10module.c new file mode 100644 index 000000000..9e679ca6a --- /dev/null +++ b/hw/xfree86/int10/xf86int10module.c @@ -0,0 +1,63 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/int10/xf86int10module.c,v 1.2 2002/09/16 18:06:09 eich Exp $ */ +/* + * XFree86 int10 module + * execute BIOS int 10h calls in x86 real mode environment + * Copyright 1999 Egbert Eich + */ +#include "xf86.h" +#include "xf86str.h" +#include "xf86Pci.h" +#include "xf86int10.h" + + +#ifdef XFree86LOADER + + +#ifndef MOD_NAME +# define MOD_NAME int10 +#endif + +#define stringify(x) #x +#define STRING(x) stringify(x) +#define concat(x,y) x ## y +#define combine(a,b) concat(a,b) +#define NAME(x) combine(MOD_NAME,x) + +static MODULESETUPPROTO(NAME(Setup)); + +static XF86ModuleVersionInfo NAME(VersRec) = +{ + STRING(NAME( )), + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XF86_VERSION_CURRENT, + 1, 0, 0, + ABI_CLASS_VIDEODRV, /* needs the video driver ABI */ + ABI_VIDEODRV_VERSION, + MOD_CLASS_NONE, + {0,0,0,0} +}; + +XF86ModuleData NAME(ModuleData) = { &NAME(VersRec), NAME(Setup), NULL }; + +static pointer +NAME(Setup)(pointer module, pointer opts, int *errmaj, int *errmin) +{ + static Bool setupDone = FALSE; + + if (!setupDone) { + setupDone = TRUE; + /* + * Tell the loader about symbols from other modules that this module + * might refer to. + */ + } + /* + * The return value must be non-NULL on success even though there + * is no TearDownProc. + */ + return (pointer)1; +} + +#endif diff --git a/hw/xfree86/int10/xf86x86emu.c b/hw/xfree86/int10/xf86x86emu.c new file mode 100644 index 000000000..6998a0880 --- /dev/null +++ b/hw/xfree86/int10/xf86x86emu.c @@ -0,0 +1,88 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/int10/xf86x86emu.c,v 1.13 2002/09/16 18:06:09 eich Exp $ */ +/* + * XFree86 int10 module + * execute BIOS int 10h calls in x86 real mode environment + * Copyright 1999 Egbert Eich + */ +#include <x86emu.h> +#include "xf86.h" +#include "xf86_ansic.h" +#include "compiler.h" +#include "xf86_OSproc.h" +#include "xf86Pci.h" +#include "xf86_libc.h" +#define _INT10_PRIVATE +#include "xf86int10.h" +#include "int10Defines.h" + +#define M _X86EMU_env + +static void +x86emu_do_int(int num) +{ + Int10Current->num = num; + + if (!int_handler(Int10Current)) { + X86EMU_halt_sys(); + } +} + +void +xf86ExecX86int10(xf86Int10InfoPtr pInt) +{ + int sig = setup_int(pInt); + + if (sig < 0) + return; + + if (int_handler(pInt)) { + X86EMU_exec(); + } + + finish_int(pInt, sig); +} + +Bool +xf86Int10ExecSetup(xf86Int10InfoPtr pInt) +{ + int i; + X86EMU_intrFuncs intFuncs[256]; + X86EMU_pioFuncs pioFuncs = { + (&x_inb), + (&x_inw), + (&x_inl), + (&x_outb), + (&x_outw), + (&x_outl) + }; + + X86EMU_memFuncs memFuncs = { + (&Mem_rb), + (&Mem_rw), + (&Mem_rl), + (&Mem_wb), + (&Mem_ww), + (&Mem_wl) + }; + + X86EMU_setupMemFuncs(&memFuncs); + + pInt->cpuRegs = &M; + M.mem_base = 0; + M.mem_size = 1024*1024 + 1024; + X86EMU_setupPioFuncs(&pioFuncs); + + for (i=0;i<256;i++) + intFuncs[i] = x86emu_do_int; + X86EMU_setupIntrFuncs(intFuncs); + return TRUE; +} + +void +printk(const char *fmt, ...) +{ + va_list argptr; + va_start(argptr, fmt); + VErrorF(fmt, argptr); + va_end(argptr); +} diff --git a/hw/xfree86/int10/xf86x86emu.h b/hw/xfree86/int10/xf86x86emu.h new file mode 100644 index 000000000..67c37d5f4 --- /dev/null +++ b/hw/xfree86/int10/xf86x86emu.h @@ -0,0 +1,51 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/int10/xf86x86emu.h,v 1.2 2001/01/06 20:19:13 tsi Exp $ */ +/* + * XFree86 int10 module + * execute BIOS int 10h calls in x86 real mode environment + * Copyright 1999 Egbert Eich + */ +#ifndef XF86X86EMU_H_ +#define XF86X86EMU_H_ +#include <x86emu.h> + +#define M _X86EMU_env + +#define X86_EAX M.x86.R_EAX +#define X86_EBX M.x86.R_EBX +#define X86_ECX M.x86.R_ECX +#define X86_EDX M.x86.R_EDX +#define X86_ESI M.x86.R_ESI +#define X86_EDI M.x86.R_EDI +#define X86_EBP M.x86.R_EBP +#define X86_EIP M.x86.R_EIP +#define X86_ESP M.x86.R_ESP +#define X86_EFLAGS M.x86.R_EFLG + +#define X86_FLAGS M.x86.R_FLG +#define X86_AX M.x86.R_AX +#define X86_BX M.x86.R_BX +#define X86_CX M.x86.R_CX +#define X86_DX M.x86.R_DX +#define X86_SI M.x86.R_SI +#define X86_DI M.x86.R_DI +#define X86_BP M.x86.R_BP +#define X86_IP M.x86.R_IP +#define X86_SP M.x86.R_SP +#define X86_CS M.x86.R_CS +#define X86_DS M.x86.R_DS +#define X86_ES M.x86.R_ES +#define X86_SS M.x86.R_SS +#define X86_FS M.x86.R_FS +#define X86_GS M.x86.R_GS + +#define X86_AL M.x86.R_AL +#define X86_BL M.x86.R_BL +#define X86_CL M.x86.R_CL +#define X86_DL M.x86.R_DL + +#define X86_AH M.x86.R_AH +#define X86_BH M.x86.R_BH +#define X86_CH M.x86.R_CH +#define X86_DH M.x86.R_DH + +#endif |