Commit | Line | Data |
---|---|---|
a09e091a JB |
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 $ |