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