Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / xfree86 / int10 / generic.c
1 /*
2 * XFree86 int10 module
3 * execute BIOS int 10h calls in x86 real mode environment
4 * Copyright 1999 Egbert Eich
5 */
6 #ifdef HAVE_XORG_CONFIG_H
7 #include <xorg-config.h>
8 #endif
9
10 #include <string.h>
11 #include <unistd.h>
12
13 #include "xf86.h"
14 #include "xf86_OSproc.h"
15 #include "compiler.h"
16 #define _INT10_PRIVATE
17 #include "xf86int10.h"
18 #include "int10Defines.h"
19 #include "Pci.h"
20
21 #define ALLOC_ENTRIES(x) ((V_RAM / x) - 1)
22
23 static CARD8 read_b(xf86Int10InfoPtr pInt, int addr);
24 static CARD16 read_w(xf86Int10InfoPtr pInt, int addr);
25 static CARD32 read_l(xf86Int10InfoPtr pInt, int addr);
26 static void write_b(xf86Int10InfoPtr pInt, int addr, CARD8 val);
27 static void write_w(xf86Int10InfoPtr pInt, int addr, CARD16 val);
28 static void write_l(xf86Int10InfoPtr pInt, int addr, CARD32 val);
29
30 /*
31 * the emulator cannot pass a pointer to the current xf86Int10InfoRec
32 * to the memory access functions therefore store it here.
33 */
34
35 typedef struct {
36 int shift;
37 int entries;
38 void *base;
39 void *vRam;
40 int highMemory;
41 void *sysMem;
42 char *alloc;
43 } genericInt10Priv;
44
45 #define INTPriv(x) ((genericInt10Priv*)x->private)
46
47 int10MemRec genericMem = {
48 read_b,
49 read_w,
50 read_l,
51 write_b,
52 write_w,
53 write_l
54 };
55
56 static void MapVRam(xf86Int10InfoPtr pInt);
57 static void UnmapVRam(xf86Int10InfoPtr pInt);
58
59 #ifdef _PC
60 #define GET_HIGH_BASE(x) (((V_BIOS + (x) + getpagesize() - 1)/getpagesize()) \
61 * getpagesize())
62 #endif
63
64 static void *sysMem = NULL;
65
66 xf86Int10InfoPtr
67 xf86ExtendedInitInt10(int entityIndex, int Flags)
68 {
69 xf86Int10InfoPtr pInt;
70 void *base = 0;
71 void *vbiosMem = 0;
72 void *options = NULL;
73 legacyVGARec vga;
74 ScrnInfoPtr pScrn;
75
76 pScrn = xf86FindScreenForEntity(entityIndex);
77
78 options = xf86HandleInt10Options(pScrn, entityIndex);
79
80 if (int10skip(options)) {
81 free(options);
82 return NULL;
83 }
84
85 pInt = (xf86Int10InfoPtr) xnfcalloc(1, sizeof(xf86Int10InfoRec));
86 pInt->entityIndex = entityIndex;
87 if (!xf86Int10ExecSetup(pInt))
88 goto error0;
89 pInt->mem = &genericMem;
90 pInt->private = (pointer) xnfcalloc(1, sizeof(genericInt10Priv));
91 INTPriv(pInt)->alloc = (pointer) xnfcalloc(1, ALLOC_ENTRIES(getpagesize()));
92 pInt->pScrn = pScrn;
93 base = INTPriv(pInt)->base = xnfalloc(SYS_BIOS);
94
95 /* FIXME: Shouldn't this be a failure case? Leaving dev as NULL seems like
96 * FIXME: an error
97 */
98 pInt->dev = xf86GetPciInfoForEntity(entityIndex);
99
100 /*
101 * we need to map video RAM MMIO as some chipsets map mmio
102 * registers into this range.
103 */
104 MapVRam(pInt);
105 #ifdef _PC
106 if (!sysMem)
107 pci_device_map_legacy(pInt->dev, V_BIOS, BIOS_SIZE + SYS_BIOS - V_BIOS,
108 PCI_DEV_MAP_FLAG_WRITABLE, &sysMem);
109 INTPriv(pInt)->sysMem = sysMem;
110
111 if (xf86ReadBIOS(0, 0, base, LOW_PAGE_SIZE) < 0) {
112 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Cannot read int vect\n");
113 goto error1;
114 }
115
116 /*
117 * Retrieve everything between V_BIOS and SYS_BIOS as some system BIOSes
118 * have executable code there.
119 */
120 memset((char *) base + V_BIOS, 0, SYS_BIOS - V_BIOS);
121 INTPriv(pInt)->highMemory = V_BIOS;
122
123 if (xf86IsEntityPrimary(entityIndex) && !(initPrimary(options))) {
124 if (!xf86int10GetBiosSegment(pInt, (unsigned char *) sysMem - V_BIOS))
125 goto error1;
126
127 set_return_trap(pInt);
128
129 pInt->Flags = Flags & (SET_BIOS_SCRATCH | RESTORE_BIOS_SCRATCH);
130 if (!(pInt->Flags & SET_BIOS_SCRATCH))
131 pInt->Flags &= ~RESTORE_BIOS_SCRATCH;
132 xf86Int10SaveRestoreBIOSVars(pInt, TRUE);
133
134 }
135 else {
136 const BusType location_type = xf86int10GetBiosLocationType(pInt);
137 int bios_location = V_BIOS;
138
139 reset_int_vect(pInt);
140 set_return_trap(pInt);
141
142 switch (location_type) {
143 case BUS_PCI:{
144 int err;
145 struct pci_device *rom_device =
146 xf86GetPciInfoForEntity(pInt->entityIndex);
147
148 vbiosMem = (unsigned char *) base + bios_location;
149 err = pci_device_read_rom(rom_device, vbiosMem);
150 if (err) {
151 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Cannot read V_BIOS (3) %s\n",
152 strerror(err));
153 goto error1;
154 }
155 INTPriv(pInt)->highMemory = GET_HIGH_BASE(rom_device->rom_size);
156 break;
157 }
158 default:
159 goto error1;
160 }
161 pInt->BIOSseg = V_BIOS >> 4;
162 pInt->num = 0xe6;
163 LockLegacyVGA(pInt, &vga);
164 xf86ExecX86int10(pInt);
165 UnlockLegacyVGA(pInt, &vga);
166 }
167 #else
168 if (!sysMem) {
169 sysMem = xnfalloc(BIOS_SIZE);
170 setup_system_bios(sysMem);
171 }
172 INTPriv(pInt)->sysMem = sysMem;
173 setup_int_vect(pInt);
174 set_return_trap(pInt);
175
176 /* Retrieve the entire legacy video BIOS segment. This can be upto
177 * 128KiB.
178 */
179 vbiosMem = (char *) base + V_BIOS;
180 memset(vbiosMem, 0, 2 * V_BIOS_SIZE);
181 if (pci_device_read_rom(pInt->dev, vbiosMem) != 0
182 || pInt->dev->rom_size < V_BIOS_SIZE) {
183 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
184 "Unable to retrieve all of segment 0x0C0000.\n");
185 }
186
187 /*
188 * If this adapter is the primary, use its post-init BIOS (if we can find
189 * it).
190 */
191 {
192 int bios_location = V_BIOS;
193 Bool done = FALSE;
194
195 vbiosMem = (unsigned char *) base + bios_location;
196
197 if (xf86IsEntityPrimary(entityIndex)) {
198 if (int10_check_bios(pScrn->scrnIndex, bios_location >> 4, vbiosMem))
199 done = TRUE;
200 else
201 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
202 "No legacy BIOS found -- trying PCI\n");
203 }
204 if (!done) {
205 int err;
206 struct pci_device *rom_device =
207 xf86GetPciInfoForEntity(pInt->entityIndex);
208
209 err = pci_device_read_rom(rom_device, vbiosMem);
210 if (err) {
211 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Cannot read V_BIOS (5) %s\n",
212 strerror(err));
213 goto error1;
214 }
215 }
216 }
217
218 pInt->BIOSseg = V_BIOS >> 4;
219 pInt->num = 0xe6;
220 LockLegacyVGA(pInt, &vga);
221 xf86ExecX86int10(pInt);
222 UnlockLegacyVGA(pInt, &vga);
223 #endif
224 free(options);
225 return pInt;
226
227 error1:
228 free(base);
229 UnmapVRam(pInt);
230 free(INTPriv(pInt)->alloc);
231 free(pInt->private);
232 error0:
233 free(pInt);
234 free(options);
235
236 return NULL;
237 }
238
239 static void
240 MapVRam(xf86Int10InfoPtr pInt)
241 {
242 int pagesize = getpagesize();
243 int size = ((VRAM_SIZE + pagesize - 1) / pagesize) * pagesize;
244
245 pci_device_map_legacy(pInt->dev, V_RAM, size, PCI_DEV_MAP_FLAG_WRITABLE,
246 &(INTPriv(pInt)->vRam));
247 pInt->io = pci_legacy_open_io(pInt->dev, 0, 64 * 1024);
248 }
249
250 static void
251 UnmapVRam(xf86Int10InfoPtr pInt)
252 {
253 int pagesize = getpagesize();
254 int size = ((VRAM_SIZE + pagesize - 1) / pagesize) * pagesize;
255
256 pci_device_unmap_legacy(pInt->dev, INTPriv(pInt)->vRam, size);
257 pci_device_close_io(pInt->dev, pInt->io);
258 pInt->io = NULL;
259 }
260
261 Bool
262 MapCurrentInt10(xf86Int10InfoPtr pInt)
263 {
264 /* nothing to do here */
265 return TRUE;
266 }
267
268 void
269 xf86FreeInt10(xf86Int10InfoPtr pInt)
270 {
271 if (!pInt)
272 return;
273 #if defined (_PC)
274 xf86Int10SaveRestoreBIOSVars(pInt, FALSE);
275 #endif
276 if (Int10Current == pInt)
277 Int10Current = NULL;
278 free(INTPriv(pInt)->base);
279 UnmapVRam(pInt);
280 free(INTPriv(pInt)->alloc);
281 free(pInt->private);
282 free(pInt);
283 }
284
285 void *
286 xf86Int10AllocPages(xf86Int10InfoPtr pInt, int num, int *off)
287 {
288 int pagesize = getpagesize();
289 int num_pages = ALLOC_ENTRIES(pagesize);
290 int i, j;
291
292 for (i = 0; i < (num_pages - num); i++) {
293 if (INTPriv(pInt)->alloc[i] == 0) {
294 for (j = i; j < (num + i); j++)
295 if (INTPriv(pInt)->alloc[j] != 0)
296 break;
297 if (j == (num + i))
298 break;
299 i += num;
300 }
301 }
302 if (i == (num_pages - num))
303 return NULL;
304
305 for (j = i; j < (i + num); j++)
306 INTPriv(pInt)->alloc[j] = 1;
307
308 *off = (i + 1) * pagesize;
309
310 return (char *) INTPriv(pInt)->base + *off;
311 }
312
313 void
314 xf86Int10FreePages(xf86Int10InfoPtr pInt, void *pbase, int num)
315 {
316 int pagesize = getpagesize();
317 int first =
318 (((char *) pbase - (char *) INTPriv(pInt)->base) / pagesize) - 1;
319 int i;
320
321 for (i = first; i < (first + num); i++)
322 INTPriv(pInt)->alloc[i] = 0;
323 }
324
325 #define OFF(addr) ((addr) & 0xffff)
326 #if defined _PC
327 #define HIGH_OFFSET (INTPriv(pInt)->highMemory)
328 #define HIGH_BASE V_BIOS
329 #else
330 #define HIGH_OFFSET SYS_BIOS
331 #define HIGH_BASE SYS_BIOS
332 #endif
333 #define SYS(addr) ((addr) >= HIGH_OFFSET)
334 #define V_ADDR(addr) \
335 (SYS(addr) ? ((char*)INTPriv(pInt)->sysMem) + (addr - HIGH_BASE) \
336 : (((char*)(INTPriv(pInt)->base) + addr)))
337 #define VRAM_ADDR(addr) (addr - V_RAM)
338 #define VRAM_BASE (INTPriv(pInt)->vRam)
339
340 #define VRAM(addr) ((addr >= V_RAM) && (addr < (V_RAM + VRAM_SIZE)))
341 #define V_ADDR_RB(addr) \
342 (VRAM(addr)) ? MMIO_IN8((CARD8*)VRAM_BASE,VRAM_ADDR(addr)) \
343 : *(CARD8*) V_ADDR(addr)
344 #define V_ADDR_RW(addr) \
345 (VRAM(addr)) ? MMIO_IN16((CARD16*)VRAM_BASE,VRAM_ADDR(addr)) \
346 : ldw_u((pointer)V_ADDR(addr))
347 #define V_ADDR_RL(addr) \
348 (VRAM(addr)) ? MMIO_IN32((CARD32*)VRAM_BASE,VRAM_ADDR(addr)) \
349 : ldl_u((pointer)V_ADDR(addr))
350
351 #define V_ADDR_WB(addr,val) \
352 if(VRAM(addr)) \
353 MMIO_OUT8((CARD8*)VRAM_BASE,VRAM_ADDR(addr),val); \
354 else \
355 *(CARD8*) V_ADDR(addr) = val;
356 #define V_ADDR_WW(addr,val) \
357 if(VRAM(addr)) \
358 MMIO_OUT16((CARD16*)VRAM_BASE,VRAM_ADDR(addr),val); \
359 else \
360 stw_u((val),(pointer)(V_ADDR(addr)));
361
362 #define V_ADDR_WL(addr,val) \
363 if (VRAM(addr)) \
364 MMIO_OUT32((CARD32*)VRAM_BASE,VRAM_ADDR(addr),val); \
365 else \
366 stl_u(val,(pointer)(V_ADDR(addr)));
367
368 static CARD8
369 read_b(xf86Int10InfoPtr pInt, int addr)
370 {
371 return V_ADDR_RB(addr);
372 }
373
374 static CARD16
375 read_w(xf86Int10InfoPtr pInt, int addr)
376 {
377 #if X_BYTE_ORDER == X_LITTLE_ENDIAN
378 if (OFF(addr + 1) > 0)
379 return V_ADDR_RW(addr);
380 #endif
381 return V_ADDR_RB(addr) | (V_ADDR_RB(addr + 1) << 8);
382 }
383
384 static CARD32
385 read_l(xf86Int10InfoPtr pInt, int addr)
386 {
387 #if X_BYTE_ORDER == X_LITTLE_ENDIAN
388 if (OFF(addr + 3) > 2)
389 return V_ADDR_RL(addr);
390 #endif
391 return V_ADDR_RB(addr) |
392 (V_ADDR_RB(addr + 1) << 8) |
393 (V_ADDR_RB(addr + 2) << 16) | (V_ADDR_RB(addr + 3) << 24);
394 }
395
396 static void
397 write_b(xf86Int10InfoPtr pInt, int addr, CARD8 val)
398 {
399 V_ADDR_WB(addr, val);
400 }
401
402 static void
403 write_w(xf86Int10InfoPtr pInt, int addr, CARD16 val)
404 {
405 #if X_BYTE_ORDER == X_LITTLE_ENDIAN
406 if (OFF(addr + 1) > 0) {
407 V_ADDR_WW(addr, val);
408 }
409 #endif
410 V_ADDR_WB(addr, val);
411 V_ADDR_WB(addr + 1, val >> 8);
412 }
413
414 static void
415 write_l(xf86Int10InfoPtr pInt, int addr, CARD32 val)
416 {
417 #if X_BYTE_ORDER == X_LITTLE_ENDIAN
418 if (OFF(addr + 3) > 2) {
419 V_ADDR_WL(addr, val);
420 }
421 #endif
422 V_ADDR_WB(addr, val);
423 V_ADDR_WB(addr + 1, val >> 8);
424 V_ADDR_WB(addr + 2, val >> 16);
425 V_ADDR_WB(addr + 3, val >> 24);
426 }
427
428 pointer
429 xf86int10Addr(xf86Int10InfoPtr pInt, CARD32 addr)
430 {
431 return V_ADDR(addr);
432 }