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