1*4882a593Smuzhiyun 2*4882a593Smuzhiyun INT10 X86 Real Mode executor 3*4882a593Smuzhiyun ============================= 4*4882a593Smuzhiyun 5*4882a593Smuzhiyun PRELIMINARY 6*4882a593Smuzhiyun 7*4882a593SmuzhiyunINT10 is a XFree86 module for soft-booting and executing real mode 8*4882a593Smuzhiyunint10 BIOS calls. The BIOS call code is largely untested, yet. 9*4882a593Smuzhiyun 10*4882a593Smuzhiyun1. Usage 11*4882a593Smuzhiyun======== 12*4882a593Smuzhiyun 13*4882a593SmuzhiyunTo use the int10 module in a driver the header file 14*4882a593Smuzhiyunxfree86/os-support/int10/xf86int10.h must be included. 15*4882a593Smuzhiyun 16*4882a593Smuzhiyun a. Initialization 17*4882a593Smuzhiyun ----------------- 18*4882a593Smuzhiyun 19*4882a593SmuzhiyunThe int10-executer gets initialized by calling: 20*4882a593Smuzhiyun 21*4882a593Smuzhiyun xf86Int10InfoPtr xf86InitInt10(int entityIndex); 22*4882a593Smuzhiyun 23*4882a593SmuzhiyunThe function will soft-boot any non-primary device and return a 24*4882a593Smuzhiyunpointer to a xf86Int10InfoRec on success. If anything fails or if 25*4882a593Smuzhiyunint10 execution is disabled by an option in the device section NULL 26*4882a593Smuzhiyunwill be returned. The driver should store this pointer for later 27*4882a593Smuzhiyuncalls to other int10 module functions. 28*4882a593Smuzhiyun 29*4882a593Smuzhiyun b. Memory allocation 30*4882a593Smuzhiyun -------------------- 31*4882a593Smuzhiyun 32*4882a593SmuzhiyunTo allocate memory in the real mode execution environment 33*4882a593Smuzhiyun 34*4882a593Smuzhiyun void * xf86Int10AllocPages(xf86Int10InfoPtr pInt,int num, int *off); 35*4882a593Smuzhiyun 36*4882a593Smuzhiyuncan be called. It allocates num consecutive pagesize chunks. It 37*4882a593Smuzhiyunreturns the address of the allocated area. off is set to its offset in 38*4882a593Smuzhiyunthe real mode memory space. 39*4882a593Smuzhiyun 40*4882a593Smuzhiyun void xf86Int10FreePages(xf86Int10InfoPtr pInt, void *pbase, int num); 41*4882a593Smuzhiyun 42*4882a593SmuzhiyunIs used to free num pages beginning at pbase. 43*4882a593Smuzhiyun 44*4882a593Smuzhiyun c. Doing int10 BIOS calls 45*4882a593Smuzhiyun ------------------------- 46*4882a593Smuzhiyun 47*4882a593SmuzhiyunThe BIOS call is executed by calling: 48*4882a593Smuzhiyun 49*4882a593Smuzhiyun void xf86ExecX86int10(xf86Int10InfoPtr pInt); 50*4882a593Smuzhiyun 51*4882a593SmuzhiyunThe number of the interrupt (normally 10) and the initial values of 52*4882a593Smuzhiyunthe ax, bx, cx, dx, si, di and es x86-CPU registers can be set in the 53*4882a593Smuzhiyunxf86Int10InfoRec passed to the function. On return this structure 54*4882a593Smuzhiyuncontains the exit values of the registers listed above and the CPU 55*4882a593Smuzhiyunflag register. 56*4882a593Smuzhiyun 57*4882a593Smuzhiyun d. De-initializing 58*4882a593Smuzhiyun ----------------- 59*4882a593Smuzhiyun 60*4882a593SmuzhiyunIf no further int10 calls are required for a certain chipset 61*4882a593Smuzhiyunthe driver should call: 62*4882a593Smuzhiyun 63*4882a593Smuzhiyun void xf86FreeInt10(xf86Int10InfoPtr pInt); 64*4882a593Smuzhiyun 65*4882a593Smuzhiyunto free the memory allocated for real mode int10 calls. 66*4882a593Smuzhiyun 67*4882a593Smuzhiyun 68*4882a593Smuzhiyun2. Porting issues 69*4882a593Smuzhiyun================= 70*4882a593Smuzhiyun 71*4882a593SmuzhiyunThe int10 real mode executor is designed to run on top of various x86 72*4882a593SmuzhiyunCPU emulators as well as in vm86 mode of a real x86 CPU. If used with 73*4882a593Smuzhiyuna CPU emulator the emulator and CPU specific interfaces can be held 74*4882a593Smuzhiyunseparate thus requiring minimal efforts to port the int10 module to 75*4882a593Smuzhiyunnew platforms. Currently an interface to the x86emu real mode 76*4882a593Smuzhiyunemulator is provided. Since details of setting up and running the 77*4882a593Smuzhiyunvm86 mode is platform dependent both the platform dependent 78*4882a593Smuzhiyunenvironment and the emulation layer have to be ported. Several helper 79*4882a593Smuzhiyunfunctions are provided for that. 80*4882a593Smuzhiyun 81*4882a593SmuzhiyunA CPU emulator should meet certain requirements to be usable 82*4882a593Smuzhiyunfor the INT10 executor: 83*4882a593Smuzhiyun 84*4882a593Smuzhiyun1. It must trap calls to intXX instructions and pass execution to an 85*4882a593Smuzhiyun external function which is allowed to modify CPU registers 86*4882a593Smuzhiyun including the instruction pointer (IP) before returning to the 87*4882a593Smuzhiyun emulator for continuing execution. When the external function is 88*4882a593Smuzhiyun called the IP must point to the instruction past the intXX call. 89*4882a593Smuzhiyun 90*4882a593Smuzhiyun2. The emulator should use externally provided functions to handle 91*4882a593Smuzhiyun PIO. 92*4882a593Smuzhiyun 93*4882a593Smuzhiyun3. The emulator should be able to use externally provided functions 94*4882a593Smuzhiyun to access memory from the real mode memory environment. Note, that 95*4882a593Smuzhiyun the vm86 mode usually requires one hunk of consecutive memory 96*4882a593Smuzhiyun starting at address 0 in the process virtual memory space. Thus if 97*4882a593Smuzhiyun this mode is to be used, the OS environment has to be able to provide 98*4882a593Smuzhiyun that, ie. it must be able to remap the processes virtual memory space 99*4882a593Smuzhiyun onto itself. If the emulator is able to handle memory access thru 100*4882a593Smuzhiyun externally provided functions the real mode process memory can be 101*4882a593Smuzhiyun located anywhere in the processes virtual memory. It does not even 102*4882a593Smuzhiyun have to be consecutive. 103*4882a593Smuzhiyun 104*4882a593Smuzhiyun4. The executor should terminate on encountering a 'hlt' instruction. 105*4882a593Smuzhiyun 106*4882a593Smuzhiyun 107*4882a593SmuzhiyunFunctions to implement: 108*4882a593Smuzhiyun 109*4882a593SmuzhiyunTo simplify development the code has been split into a general setup 110*4882a593Smuzhiyunpart and an emulator specific one. A generic setup code is provided in 111*4882a593Smuzhiyungeneric.c. It should be usable with any emulator satisfying the 112*4882a593Smuzhiyunconditions mentioned above. Therefore the following section on int10 113*4882a593Smuzhiyunsetup may be skipped when porting int10 to new emulator. 114*4882a593Smuzhiyun 115*4882a593SmuzhiyunIf the vm86() is to be used no memory access functions can be used. 116*4882a593SmuzhiyunTherefore the layout of the real mode memory image has to meet certain 117*4882a593Smuzhiyunrequirements. Therefore when porting to other platforms a new setup 118*4882a593Smuzhiyuncode may have to be designed, too. The following section will give 119*4882a593Smuzhiyunguidelines how this may be done. A sample implementation using SysV 120*4882a593SmuzhiyunIPC to map the appropriate real mode memory image to address 0 in 121*4882a593Smuzhiyunvirtual address space just prior to execution may be found in 122*4882a593Smuzhiyunxfree86/os-support/linux/int10/linux.c. 123*4882a593Smuzhiyun 124*4882a593SmuzhiyunOn non-PC like platforms emulation of certain PC features such as 125*4882a593Smuzhiyuninitialization of BIOS int vectors, sys_BIOS constants or PCI config 126*4882a593Smuzhiyunmethod 1 can be turned on by defining _PC. 127*4882a593Smuzhiyun 128*4882a593SmuzhiyunI. Setup Code 129*4882a593Smuzhiyun------------- 130*4882a593Smuzhiyun 131*4882a593SmuzhiyunThis sets up the real mode memory image, calls the emulator to POST 132*4882a593Smuzhiyunthe chipset if required and maintains memory allocations in real mode 133*4882a593Smuzhiyunaddress space. 134*4882a593Smuzhiyun 135*4882a593Smuzhiyun1. xf86Int10InfoPtr xf86InitInt10(int entityIndex); 136*4882a593Smuzhiyun 137*4882a593SmuzhiyunThis function should first find the screen assigned to the entity 138*4882a593Smuzhiyuncarrying entitiyIndex and then call 139*4882a593Smuzhiyun 140*4882a593Smuzhiyun Bool int10skip(ScrnInfoPtr pScrn) 141*4882a593Smuzhiyun 142*4882a593Smuzhiyunto find out if the user has requested not to initialize int10. If so 143*4882a593Smuzhiyunxf86InitInt10() should return NULL. Otherwise an xf86Int10InfoRec 144*4882a593Smuzhiyunshould be allocated. This structure contains the following fields: 145*4882a593Smuzhiyun 146*4882a593Smuzhiyun a. int entityIndex - index of the entity whose BIOS is to be 147*4882a593Smuzhiyun executed. 148*4882a593Smuzhiyun b. int scrnIndex - index of the screen assigned the entity. 149*4882a593Smuzhiyun c. pointer cpuRegs - pointer to a emulator/vm86-mode private 150*4882a593Smuzhiyun structure. May hold cpu register values 151*4882a593Smuzhiyun for the emulator. 152*4882a593Smuzhiyun d. CARD16 BIOSseg - Video BIOS segment address. 153*4882a593Smuzhiyun e. pointer private - pointer to a os specific data structure. 154*4882a593Smuzhiyun f. struct _int10Mem* - pointer to a structure to hold the memory 155*4882a593Smuzhiyun access functions for use by an emulator. 156*4882a593Smuzhiyun g. int num - number of the int to be called. 157*4882a593Smuzhiyun h. int ax..es,flags - CPU register values to pass to int-call. 158*4882a593Smuzhiyun 159*4882a593SmuzhiyunThe Init function should initialize a-f. To initialize the emulator 160*4882a593Smuzhiyunspecific execute environment the function 161*4882a593Smuzhiyun 162*4882a593Smuzhiyun Bool xf86Int10ExecSetup(xf86Int10InfoPtr pInt) 163*4882a593Smuzhiyun 164*4882a593Smuzhiyunshould be called. If this function returns FALSE any already allocated 165*4882a593Smuzhiyunmemory should be freed and xf86Int10Init(0 should exit returning NULL. 166*4882a593Smuzhiyun 167*4882a593SmuzhiyunIf the platform has a PC like system BIOS it may be copied to or 168*4882a593Smuzhiyunmapped into memory locations SYS_BIOS to SYS_SIZE-1 of the real mode 169*4882a593Smuzhiyunmemory environment of this process. Otherwise the helper function: 170*4882a593Smuzhiyun 171*4882a593Smuzhiyunint setup_system_bios(CARD32 base_addr); 172*4882a593Smuzhiyun 173*4882a593Smuzhiyunmay be called to set up a rudimentary system BIOS sufficient to be 174*4882a593Smuzhiyunused to boot video BIOSes. base_addr specifies the virtual address 175*4882a593Smuzhiyuncorresponding to SYS_BIOS in the real mode environment. If a PC-like 176*4882a593Smuzhiyunint vector and BIOS data area is available it should be copied to 0 to 177*4882a593SmuzhiyunLOW_PAGE_SIZE of the entities real mode environment. In this case the 178*4882a593Smuzhiyunvideo interrupt related entries should be reset for all non-primary 179*4882a593Smuzhiyuncards by calling: 180*4882a593Smuzhiyun 181*4882a593Smuzhiyunvoid reset_int_vect(xf86Int10InfoPtr pInt); To initialize the 182*4882a593Smuzhiyun 183*4882a593Smuzhiyuncorrect video BIOS entry points the BIOS must be warm-booted. If no 184*4882a593SmuzhiyunPC-like int vector is available one can be set up by calling 185*4882a593Smuzhiyun 186*4882a593Smuzhiyunvoid setup_int_vect(xf86Int10InfoPtr pInt); 187*4882a593Smuzhiyun 188*4882a593SmuzhiyunIn this case the video BIOS has to be warm-booted always. If the 189*4882a593Smuzhiyunvideo BIOS for this entity has been installed during boot it may be 190*4882a593Smuzhiyunmapped (or copied) directly to the correct address in the real mode 191*4882a593Smuzhiyunmemory environment. Otherwise 192*4882a593Smuzhiyun 193*4882a593Smuzhiyunint mapPciRom(xf86Int10InfoPtr pInt, unsigned char * address); 194*4882a593Smuzhiyun 195*4882a593Smuzhiyunshould be called to copy the BIOS image from PCI ROM. 'address' 196*4882a593Smuzhiyunspecifies the address this image should be copied to. Sufficient space 197*4882a593Smuzhiyunto hold an entire BIOS image should be allocated prior to calling 198*4882a593SmuzhiyunmapPciRom(). This function will return the size of the BIOS image in 199*4882a593Smuzhiyunbytes if it was able to successfully copy the image and 0 200*4882a593Smuzhiyunotherwise. To create a well defined point to exit the softbooter 201*4882a593Smuzhiyun 202*4882a593Smuzhiyunvoid set_return_trap(xf86Int10Ptr pInt); 203*4882a593Smuzhiyun 204*4882a593Smuzhiyunmay be called. It sets up a 'hlt' instruction in the emulator memory 205*4882a593Smuzhiyunjust above the BIOS variable area. Before entering real mode execution 206*4882a593Smuzhiyunthis address will be pushed onto the return stack. If the BIOS needs 207*4882a593Smuzhiyunto be warm-booted this should be done before leaving xf86InitInt10() 208*4882a593Smuzhiyunby setting num in the xf86Int10InfoRec to 0xe6 and calling 209*4882a593Smuzhiyun 210*4882a593Smuzhiyunvoid xf86ExecX86int10(xf86Int10IfoPtr pInt); 211*4882a593Smuzhiyun 212*4882a593SmuzhiyunThe implementation of this function will be discussed below. This 213*4882a593Smuzhiyunfunction should be wrapped by calls to void LockLegacyVGA(screen, 214*4882a593SmuzhiyunlegacyVGAPtr vga); and void UnlockLegacyVGA(screen, legacyVGAPtr vga); 215*4882a593SmuzhiyunThe struct vga is used to hold the state of the legacy VGA access 216*4882a593Smuzhiyunregisters if a legacy VGA device exists. xf86InitInt10() should 217*4882a593Smuzhiyunreturn a pointer to the xf86Int10InfoRec allocated. 218*4882a593Smuzhiyun 219*4882a593Smuzhiyun2. Bool MapCurrentInt10(xf86Int10InfoPtr pInt); 220*4882a593Smuzhiyun 221*4882a593SmuzhiyunIn case a platform specific mapping has to be performed to map the 222*4882a593Smuzhiyunmemory allocated for the real mode memory environment into a specific 223*4882a593Smuzhiyunlocation prior to executing the x86 real mode code a function 224*4882a593Smuzhiyun 225*4882a593Smuzhiyun Bool MapCurrentInt10(xf86Int10InfoPtr pInt); 226*4882a593Smuzhiyun 227*4882a593Smuzhiyunhas to be provided. It will be called by a helper function whenever 228*4882a593Smuzhiyunthe active entity changes. If the vm86 mode is used it is most likely 229*4882a593Smuzhiyunthat the 1MB real mode memory space located somewhere in the processes 230*4882a593Smuzhiyunvirtual memory will have to be remapped to address 0 of the virtual 231*4882a593Smuzhiyunmemory space. 232*4882a593Smuzhiyun 233*4882a593Smuzhiyun3. void xf86FreeInt10(xf86Int10InfoPtr pInt); 234*4882a593Smuzhiyun 235*4882a593SmuzhiyunTo free all memory allocated for video BIOS calls of a specific entity 236*4882a593Smuzhiyunthe function 237*4882a593Smuzhiyun 238*4882a593Smuzhiyun void xf86FreeInt10(xf86Int10InfoPtr pInt); 239*4882a593Smuzhiyun 240*4882a593Smuzhiyunshould be provided. If the entity to be freed was mapped by 241*4882a593SmuzhiyunMapCurrentInt10() this mapping needs to be undone also. 242*4882a593Smuzhiyun 243*4882a593Smuzhiyun4. 244*4882a593Smuzhiyun void * xf86Int10AllocPages(xf86Int10InfoPtr pInt,int num, int *off) 245*4882a593Smuzhiyun void xf86Int10FreePages(xf86Int10InfoPtr pInt, void *pbase, int num) 246*4882a593Smuzhiyun 247*4882a593Smuzhiyunxf86Int10AllocPages() should allocate 'num' consecutive page-size 248*4882a593Smuzhiyunchunks of memory. In real mode memory space this range needs to occupy 249*4882a593Smuzhiyunconsecutive addresses, too. The function must return the address of 250*4882a593Smuzhiyunthis memory. The offset in real mode memory needs to be returned in 251*4882a593Smuzhiyun'off'. If no block of 'num' pages are available the function should 252*4882a593Smuzhiyunreturn NULL. 253*4882a593Smuzhiyun 254*4882a593Smuzhiyunxf86Int10FreePages() will free the 'num' pages starting at 'pbase'. 255*4882a593Smuzhiyun'num' is equal to the number of pages allocated by a single 256*4882a593Smuzhiyunxf86Int10AllocatePages() call. 'pbase' is the address of the range 257*4882a593Smuzhiyunpreviously returned by xf86Int10AllocatePages(). 258*4882a593Smuzhiyun 259*4882a593SmuzhiyunII. Emulator specific functions 260*4882a593Smuzhiyun------------------------------- 261*4882a593Smuzhiyun 262*4882a593Smuzhiyun1. Bool xf86Int10ExecSetup(xf86Int10InfoPtr pInt); 263*4882a593Smuzhiyun 264*4882a593SmuzhiyunThis function will be called from xf86InitInt10(). It may be used to 265*4882a593Smuzhiyunset up the static emulator specific part of the real mode 266*4882a593Smuzhiyunenvironment. On success it should return TRUE. 267*4882a593Smuzhiyun 268*4882a593Smuzhiyun2. xf86ExecX86int10(xf86Int10InfoPtr pInt); 269*4882a593Smuzhiyun 270*4882a593SmuzhiyunThis function gets called to execute an int call. It may call the 271*4882a593Smuzhiyunhelper function: 272*4882a593Smuzhiyun 273*4882a593Smuzhiyun void setup_int(xf86Int10InfoPrt pInt); 274*4882a593Smuzhiyun 275*4882a593Smuzhiyunto copy the register values to the emulator specific locations and to 276*4882a593Smuzhiyunset up the non-static real mode execution environment. On return from 277*4882a593Smuzhiyunsetup_int() 'Int10Current' holds a pointer to the current 278*4882a593Smuzhiyunxf86Int10InfoRec. 279*4882a593Smuzhiyun 280*4882a593SmuzhiyunIt should start execution by calling 281*4882a593Smuzhiyun 282*4882a593Smuzhiyun Bool int_handler(xf86Int10InfoPtr pInt); 283*4882a593Smuzhiyun 284*4882a593Smuzhiyunand if this function returns TRUE it should call whatever necessary to 285*4882a593Smuzhiyuncontinue execution until a 'hlt' instruction is encountered. To copy 286*4882a593Smuzhiyunthe resulting register values back to the xf86Int10InfoRec structure 287*4882a593Smuzhiyun 288*4882a593Smuzhiyun void finish_int(xf86Int10InfoPtr pInt); 289*4882a593Smuzhiyun 290*4882a593Smuzhiyunshould be called. 291*4882a593Smuzhiyun 292*4882a593SmuzhiyunHelper functions are provided to aid the implementation of a vm86 293*4882a593Smuzhiyuncall: 294*4882a593Smuzhiyun 295*4882a593Smuzhiyun Bool vm86_GP_fault(xf86Int10InfoPtr pInt); 296*4882a593Smuzhiyun 297*4882a593SmuzhiyunThis function handles instructions which cause a vm86 call to 298*4882a593Smuzhiyuntrap. PIO access is handled by the in/out calls as defined in 299*4882a593Smuzhiyuncompiler.h. Optionally the PIO instructions can be logged by defining 300*4882a593SmuzhiyunPRINT_PORT in xf86int10.h. This is meant for debugging purposes. 301*4882a593Smuzhiyun 302*4882a593SmuzhiyunUnknown instructions and 'hlt' cause vm86_GP_fault() to return 303*4882a593SmuzhiyunFALSE. Otherwise TRUE is returned. 304*4882a593Smuzhiyun 305*4882a593SmuzhiyunNote: This function is currently based on the Linux vm86 call. It 306*4882a593Smuzhiyunmight have to be modified or even rewritten for other OS. So your 307*4882a593Smuzhiyunmilage may vary. 308*4882a593Smuzhiyun 309*4882a593SmuzhiyunFunctions to dump memory, code, xf86 CPU register values and stack are 310*4882a593Smuzhiyunalso provided. Take a look at helper.c To view a memory range the 311*4882a593Smuzhiyunfunction 312*4882a593Smuzhiyun 313*4882a593Smuzhiyun void dprint(unsigned long start, unsigned long size) 314*4882a593Smuzhiyun 315*4882a593Smuzhiyunis provided. The use should be self explanatory. 316*4882a593Smuzhiyun 317*4882a593SmuzhiyunRegister and memory access functions are provided in helper_mem.c. 318*4882a593SmuzhiyunThe PIO register access functions can trap access to PCI config space 319*4882a593Smuzhiyunaccess register (config method 1) if _PC is not defined. 320*4882a593Smuzhiyun 321*4882a593SmuzhiyunA header file 'defines.h' is required to define OS/emulator specific 322*4882a593Smuzhiyunways to access memory and xf86 CPU registers: Defines need to be 323*4882a593Smuzhiyunprovided for memory byte/work/long read/write access 324*4882a593Smuzhiyun(MEM_RB(name,addr),MEM_RW(name,addr),MEM_RL(name,addr), 325*4882a593SmuzhiyunMEM_WB(name,addr,val),MEM_WL(name,addr,val),MEM_WL(name,addr,val)) of 326*4882a593Smuzhiyunthe real mode memory environment. 'name' will contain a pointer to the 327*4882a593Smuzhiyuncurrent xf86Int10InfoRec. Currently defines are available for 328*4882a593Smuzhiyunvm86-mode under Linux and x86emu. They may be activated by defining 329*4882a593Smuzhiyun_X86EMU or _VM86_LINUX respectively. 330*4882a593Smuzhiyun 331*4882a593SmuzhiyunNote: Emulators usually are not able to pass this pointer when calling 332*4882a593Smuzhiyunmemory access functions. In this case a global variable should be 333*4882a593Smuzhiyundefined which can hold this pointer. This variable can be set in 334*4882a593SmuzhiyunMapCurrentInt10(). It also must be set in xf86InitInt10() if this 335*4882a593Smuzhiyunfunction calls the memory access functions either directly or by 336*4882a593Smuzhiyuncalling xf86ExecX86int10(pInt). Defines to access the emulator 337*4882a593Smuzhiyunspecific xf86 CPU register locations are also required: 338*4882a593SmuzhiyunX86_EAX,...,X86_EFLAGS for access of the full 32 bit registers, 339*4882a593SmuzhiyunX86_AX...X86_FLAGS for access of the 16 bit registers and 340*4882a593SmuzhiyunXF86_AL,XF86_BL,XF86_CL,XF86_DL to access the lower byte of the 341*4882a593SmuzhiyunAX,BX,CX and DX register. 342*4882a593Smuzhiyun 343*4882a593Smuzhiyun 344*4882a593Smuzhiyun$XFree86: xc/programs/Xserver/hw/xfree86/int10/INT10.HOWTO,v 1.2 2000/02/08 13:13:22 eich Exp $ 345