1 /*
2 * linux specific part of the int10 module
3 * Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2008 Egbert Eich
4 */
5 #ifdef HAVE_XORG_CONFIG_H
6 #include <xorg-config.h>
7 #endif
8
9 #include "xf86.h"
10 #include "xf86_OSproc.h"
11 #include "xf86Pci.h"
12 #include "compiler.h"
13 #define _INT10_PRIVATE
14 #include "xf86int10.h"
15 #ifdef __sparc__
16 #define DEV_MEM "/dev/fb"
17 #else
18 #define DEV_MEM "/dev/mem"
19 #endif
20 #define ALLOC_ENTRIES(x) ((V_RAM / x) - 1)
21 #define SHMERRORPTR (void *)(-1)
22
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <sys/mman.h>
26 #include <sys/ipc.h>
27 #include <sys/shm.h>
28 #include <unistd.h>
29 #include <string.h>
30
31 static int counter = 0;
32 static unsigned long int10Generation = 0;
33
34 static CARD8 read_b(xf86Int10InfoPtr pInt, int addr);
35 static CARD16 read_w(xf86Int10InfoPtr pInt, int addr);
36 static CARD32 read_l(xf86Int10InfoPtr pInt, int addr);
37 static void write_b(xf86Int10InfoPtr pInt, int addr, CARD8 val);
38 static void write_w(xf86Int10InfoPtr pInt, int addr, CARD16 val);
39 static void write_l(xf86Int10InfoPtr pInt, int addr, CARD32 val);
40
41 int10MemRec linuxMem = {
42 read_b,
43 read_w,
44 read_l,
45 write_b,
46 write_w,
47 write_l
48 };
49
50 typedef struct {
51 int lowMem;
52 int highMem;
53 char *base;
54 char *base_high;
55 char *alloc;
56 } linuxInt10Priv;
57
58 #if defined DoSubModules
59
60 typedef enum {
61 INT10_NOT_LOADED,
62 INT10_LOADED_VM86,
63 INT10_LOADED_X86EMU,
64 INT10_LOAD_FAILED
65 } Int10LinuxSubModuleState;
66
67 static Int10LinuxSubModuleState loadedSubModule = INT10_NOT_LOADED;
68
69 static Int10LinuxSubModuleState int10LinuxLoadSubModule(ScrnInfoPtr pScrn);
70
71 #endif /* DoSubModules */
72
73 static Bool
readLegacy(struct pci_device * dev,unsigned char * buf,int base,int len)74 readLegacy(struct pci_device *dev, unsigned char *buf, int base, int len)
75 {
76 void *map;
77
78 if (pci_device_map_legacy(dev, base, len, 0, &map))
79 return FALSE;
80
81 memcpy(buf, map, len);
82 pci_device_unmap_legacy(dev, man, len);
83
84 return TRUE;
85 }
86
87 xf86Int10InfoPtr
xf86ExtendedInitInt10(int entityIndex,int Flags)88 xf86ExtendedInitInt10(int entityIndex, int Flags)
89 {
90 xf86Int10InfoPtr pInt = NULL;
91 int screen;
92 int fd;
93 static void *vidMem = NULL;
94 static void *sysMem = NULL;
95 void *vMem = NULL;
96 void *options = NULL;
97 int low_mem;
98 int high_mem = -1;
99 char *base = SHMERRORPTR;
100 char *base_high = SHMERRORPTR;
101 int pagesize;
102 memType cs;
103 legacyVGARec vga;
104 Bool videoBiosMapped = FALSE;
105 ScrnInfoPtr pScrn;
106 if (int10Generation != serverGeneration) {
107 counter = 0;
108 int10Generation = serverGeneration;
109 }
110
111 pScrn = xf86FindScreenForEntity(entityIndex);
112 screen = pScrn->scrnIndex;
113
114 options = xf86HandleInt10Options(pScrn, entityIndex);
115
116 if (int10skip(options)) {
117 free(options);
118 return NULL;
119 }
120
121 #if defined DoSubModules
122 if (loadedSubModule == INT10_NOT_LOADED)
123 loadedSubModule = int10LinuxLoadSubModule(pScrn);
124
125 if (loadedSubModule == INT10_LOAD_FAILED)
126 return NULL;
127 #endif
128
129 if ((!vidMem) || (!sysMem)) {
130 if ((fd = open(DEV_MEM, O_RDWR, 0)) >= 0) {
131 if (!sysMem) {
132 DebugF("Mapping sys bios area\n");
133 if ((sysMem = mmap((void *) (SYS_BIOS), BIOS_SIZE,
134 PROT_READ | PROT_EXEC,
135 MAP_SHARED | MAP_FIXED, fd, SYS_BIOS))
136 == MAP_FAILED) {
137 xf86DrvMsg(screen, X_ERROR, "Cannot map SYS BIOS\n");
138 close(fd);
139 goto error0;
140 }
141 }
142 if (!vidMem) {
143 DebugF("Mapping VRAM area\n");
144 if ((vidMem = mmap((void *) (V_RAM), VRAM_SIZE,
145 PROT_READ | PROT_WRITE | PROT_EXEC,
146 MAP_SHARED | MAP_FIXED, fd, V_RAM))
147 == MAP_FAILED) {
148 xf86DrvMsg(screen, X_ERROR, "Cannot map V_RAM\n");
149 close(fd);
150 goto error0;
151 }
152 }
153 close(fd);
154 }
155 else {
156 xf86DrvMsg(screen, X_ERROR, "Cannot open %s\n", DEV_MEM);
157 goto error0;
158 }
159 }
160
161 pInt = (xf86Int10InfoPtr) xnfcalloc(1, sizeof(xf86Int10InfoRec));
162 pInt->pScrn = pScrn;
163 pInt->entityIndex = entityIndex;
164 pInt->dev = xf86GetPciInfoForEntity(entityIndex);
165
166 if (!xf86Int10ExecSetup(pInt))
167 goto error0;
168 pInt->mem = &linuxMem;
169 pagesize = getpagesize();
170 pInt->private = (void *) xnfcalloc(1, sizeof(linuxInt10Priv));
171 ((linuxInt10Priv *) pInt->private)->alloc =
172 (void *) xnfcalloc(1, ALLOC_ENTRIES(pagesize));
173
174 if (!xf86IsEntityPrimary(entityIndex)) {
175 DebugF("Mapping high memory area\n");
176 if ((high_mem = shmget(counter++, HIGH_MEM_SIZE,
177 IPC_CREAT | SHM_R | SHM_W)) == -1) {
178 if (errno == ENOSYS)
179 xf86DrvMsg(screen, X_ERROR, "shmget error\n Please reconfigure"
180 " your kernel to include System V IPC support\n");
181 else
182 xf86DrvMsg(screen, X_ERROR,
183 "shmget(highmem) error: %s\n", strerror(errno));
184 goto error1;
185 }
186 }
187 else {
188 DebugF("Mapping Video BIOS\n");
189 videoBiosMapped = TRUE;
190 if ((fd = open(DEV_MEM, O_RDWR, 0)) >= 0) {
191 if ((vMem = mmap((void *) (V_BIOS), SYS_BIOS - V_BIOS,
192 PROT_READ | PROT_WRITE | PROT_EXEC,
193 MAP_SHARED | MAP_FIXED, fd, V_BIOS))
194 == MAP_FAILED) {
195 xf86DrvMsg(screen, X_ERROR, "Cannot map V_BIOS\n");
196 close(fd);
197 goto error1;
198 }
199 close(fd);
200 }
201 else
202 goto error1;
203 }
204 ((linuxInt10Priv *) pInt->private)->highMem = high_mem;
205
206 DebugF("Mapping 640kB area\n");
207 if ((low_mem = shmget(counter++, V_RAM, IPC_CREAT | SHM_R | SHM_W)) == -1) {
208 xf86DrvMsg(screen, X_ERROR,
209 "shmget(lowmem) error: %s\n", strerror(errno));
210 goto error2;
211 }
212
213 ((linuxInt10Priv *) pInt->private)->lowMem = low_mem;
214 base = shmat(low_mem, 0, 0);
215 if (base == SHMERRORPTR) {
216 xf86DrvMsg(screen, X_ERROR,
217 "shmat(low_mem) error: %s\n", strerror(errno));
218 goto error3;
219 }
220 ((linuxInt10Priv *) pInt->private)->base = base;
221 if (high_mem > -1) {
222 base_high = shmat(high_mem, 0, 0);
223 if (base_high == SHMERRORPTR) {
224 xf86DrvMsg(screen, X_ERROR,
225 "shmat(high_mem) error: %s\n", strerror(errno));
226 goto error3;
227 }
228 ((linuxInt10Priv *) pInt->private)->base_high = base_high;
229 }
230 else
231 ((linuxInt10Priv *) pInt->private)->base_high = NULL;
232
233 if (!MapCurrentInt10(pInt))
234 goto error3;
235
236 Int10Current = pInt;
237
238 DebugF("Mapping int area\n");
239 /* note: yes, we really are writing the 0 page here */
240 if (!readLegacy(pInt->dev, (unsigned char *) 0, 0, LOW_PAGE_SIZE)) {
241 xf86DrvMsg(screen, X_ERROR, "Cannot read int vect\n");
242 goto error3;
243 }
244 DebugF("done\n");
245 /*
246 * Read in everything between V_BIOS and SYS_BIOS as some system BIOSes
247 * have executable code there. Note that xf86ReadBIOS() can only bring in
248 * 64K bytes at a time.
249 */
250 if (!videoBiosMapped) {
251 memset((void *) V_BIOS, 0, SYS_BIOS - V_BIOS);
252 DebugF("Reading BIOS\n");
253 for (cs = V_BIOS; cs < SYS_BIOS; cs += V_BIOS_SIZE)
254 if (!readLegacy(pInt->dev, (void *)cs, cs, V_BIOS_SIZE))
255 xf86DrvMsg(screen, X_WARNING,
256 "Unable to retrieve all of segment 0x%06lX.\n",
257 (long) cs);
258 DebugF("done\n");
259 }
260
261 if (xf86IsEntityPrimary(entityIndex) && !(initPrimary(options))) {
262 if (!xf86int10GetBiosSegment(pInt, NULL))
263 goto error3;
264
265 set_return_trap(pInt);
266 #ifdef _PC
267 pInt->Flags = Flags & (SET_BIOS_SCRATCH | RESTORE_BIOS_SCRATCH);
268 if (!(pInt->Flags & SET_BIOS_SCRATCH))
269 pInt->Flags &= ~RESTORE_BIOS_SCRATCH;
270 xf86Int10SaveRestoreBIOSVars(pInt, TRUE);
271 #endif
272 }
273 else {
274 const BusType location_type = xf86int10GetBiosLocationType(pInt);
275
276 switch (location_type) {
277 case BUS_PCI:{
278 int err;
279 struct pci_device *rom_device =
280 xf86GetPciInfoForEntity(pInt->entityIndex);
281
282 pci_device_enable(rom_device);
283 err = pci_device_read_rom(rom_device, (unsigned char *) (V_BIOS));
284 if (err) {
285 xf86DrvMsg(screen, X_ERROR, "Cannot read V_BIOS (%s)\n",
286 strerror(err));
287 goto error3;
288 }
289
290 pInt->BIOSseg = V_BIOS >> 4;
291 break;
292 }
293 default:
294 goto error3;
295 }
296
297 pInt->num = 0xe6;
298 reset_int_vect(pInt);
299 set_return_trap(pInt);
300 LockLegacyVGA(pInt, &vga);
301 xf86ExecX86int10(pInt);
302 UnlockLegacyVGA(pInt, &vga);
303 }
304 #ifdef DEBUG
305 dprint(0xc0000, 0x20);
306 #endif
307
308 free(options);
309 return pInt;
310
311 error3:
312 if (base_high)
313 shmdt(base_high);
314 shmdt(base);
315 shmdt(0);
316 if (base_high)
317 shmdt((char *) HIGH_MEM);
318 shmctl(low_mem, IPC_RMID, NULL);
319 Int10Current = NULL;
320 error2:
321 if (high_mem > -1)
322 shmctl(high_mem, IPC_RMID, NULL);
323 error1:
324 if (vMem)
325 munmap(vMem, SYS_BIOS - V_BIOS);
326 free(((linuxInt10Priv *) pInt->private)->alloc);
327 free(pInt->private);
328 error0:
329 free(options);
330 free(pInt);
331 return NULL;
332 }
333
334 Bool
MapCurrentInt10(xf86Int10InfoPtr pInt)335 MapCurrentInt10(xf86Int10InfoPtr pInt)
336 {
337 void *addr;
338 int fd = -1;
339
340 if (Int10Current) {
341 shmdt(0);
342 if (((linuxInt10Priv *) Int10Current->private)->highMem >= 0)
343 shmdt((char *) HIGH_MEM);
344 else
345 munmap((void *) V_BIOS, (SYS_BIOS - V_BIOS));
346 }
347 addr =
348 shmat(((linuxInt10Priv *) pInt->private)->lowMem, (char *) 1, SHM_RND);
349 if (addr == SHMERRORPTR) {
350 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR, "Cannot shmat() low memory\n");
351 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR,
352 "shmat(low_mem) error: %s\n", strerror(errno));
353 return FALSE;
354 }
355 if (mprotect((void *) 0, V_RAM, PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
356 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR,
357 "Cannot set EXEC bit on low memory: %s\n", strerror(errno));
358
359 if (((linuxInt10Priv *) pInt->private)->highMem >= 0) {
360 addr = shmat(((linuxInt10Priv *) pInt->private)->highMem,
361 (char *) HIGH_MEM, 0);
362 if (addr == SHMERRORPTR) {
363 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR,
364 "Cannot shmat() high memory\n");
365 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR,
366 "shmget error: %s\n", strerror(errno));
367 return FALSE;
368 }
369 if (mprotect((void *) HIGH_MEM, HIGH_MEM_SIZE,
370 PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
371 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR,
372 "Cannot set EXEC bit on high memory: %s\n",
373 strerror(errno));
374 }
375 else {
376 if ((fd = open(DEV_MEM, O_RDWR, 0)) >= 0) {
377 if (mmap((void *) (V_BIOS), SYS_BIOS - V_BIOS,
378 PROT_READ | PROT_WRITE | PROT_EXEC,
379 MAP_SHARED | MAP_FIXED, fd, V_BIOS)
380 == MAP_FAILED) {
381 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR, "Cannot map V_BIOS\n");
382 close(fd);
383 return FALSE;
384 }
385 }
386 else {
387 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR, "Cannot open %s\n", DEV_MEM);
388 return FALSE;
389 }
390 close(fd);
391 }
392
393 return TRUE;
394 }
395
396 void
xf86FreeInt10(xf86Int10InfoPtr pInt)397 xf86FreeInt10(xf86Int10InfoPtr pInt)
398 {
399 if (!pInt)
400 return;
401
402 #ifdef _PC
403 xf86Int10SaveRestoreBIOSVars(pInt, FALSE);
404 #endif
405 if (Int10Current == pInt) {
406 shmdt(0);
407 if (((linuxInt10Priv *) pInt->private)->highMem >= 0)
408 shmdt((char *) HIGH_MEM);
409 else
410 munmap((void *) V_BIOS, (SYS_BIOS - V_BIOS));
411 Int10Current = NULL;
412 }
413
414 if (((linuxInt10Priv *) pInt->private)->base_high)
415 shmdt(((linuxInt10Priv *) pInt->private)->base_high);
416 shmdt(((linuxInt10Priv *) pInt->private)->base);
417 shmctl(((linuxInt10Priv *) pInt->private)->lowMem, IPC_RMID, NULL);
418 if (((linuxInt10Priv *) pInt->private)->highMem >= 0)
419 shmctl(((linuxInt10Priv *) pInt->private)->highMem, IPC_RMID, NULL);
420 free(((linuxInt10Priv *) pInt->private)->alloc);
421 free(pInt->private);
422 free(pInt);
423 }
424
425 void *
xf86Int10AllocPages(xf86Int10InfoPtr pInt,int num,int * off)426 xf86Int10AllocPages(xf86Int10InfoPtr pInt, int num, int *off)
427 {
428 int pagesize = getpagesize();
429 int num_pages = ALLOC_ENTRIES(pagesize);
430 int i, j;
431
432 for (i = 0; i < (num_pages - num); i++) {
433 if (((linuxInt10Priv *) pInt->private)->alloc[i] == 0) {
434 for (j = i; j < (num + i); j++)
435 if ((((linuxInt10Priv *) pInt->private)->alloc[j] != 0))
436 break;
437 if (j == (num + i))
438 break;
439 else
440 i = i + num;
441 }
442 }
443 if (i == (num_pages - num))
444 return NULL;
445
446 for (j = i; j < (i + num); j++)
447 ((linuxInt10Priv *) pInt->private)->alloc[j] = 1;
448
449 *off = (i + 1) * pagesize;
450
451 return ((linuxInt10Priv *) pInt->private)->base + ((i + 1) * pagesize);
452 }
453
454 void
xf86Int10FreePages(xf86Int10InfoPtr pInt,void * pbase,int num)455 xf86Int10FreePages(xf86Int10InfoPtr pInt, void *pbase, int num)
456 {
457 int pagesize = getpagesize();
458 int first = (((unsigned long) pbase
459 - (unsigned long) ((linuxInt10Priv *) pInt->private)->base)
460 / pagesize) - 1;
461 int i;
462
463 for (i = first; i < (first + num); i++)
464 ((linuxInt10Priv *) pInt->private)->alloc[i] = 0;
465 }
466
467 static CARD8
read_b(xf86Int10InfoPtr pInt,int addr)468 read_b(xf86Int10InfoPtr pInt, int addr)
469 {
470 return *((CARD8 *) (memType) addr);
471 }
472
473 static CARD16
read_w(xf86Int10InfoPtr pInt,int addr)474 read_w(xf86Int10InfoPtr pInt, int addr)
475 {
476 return *((CARD16 *) (memType) addr);
477 }
478
479 static CARD32
read_l(xf86Int10InfoPtr pInt,int addr)480 read_l(xf86Int10InfoPtr pInt, int addr)
481 {
482 return *((CARD32 *) (memType) addr);
483 }
484
485 static void
write_b(xf86Int10InfoPtr pInt,int addr,CARD8 val)486 write_b(xf86Int10InfoPtr pInt, int addr, CARD8 val)
487 {
488 *((CARD8 *) (memType) addr) = val;
489 }
490
491 static void
write_w(xf86Int10InfoPtr pInt,int addr,CARD16 val)492 write_w(xf86Int10InfoPtr pInt, int addr, CARD16 val)
493 {
494 *((CARD16 *) (memType) addr) = val;
495 }
496
497 static
498 void
write_l(xf86Int10InfoPtr pInt,int addr,CARD32 val)499 write_l(xf86Int10InfoPtr pInt, int addr, CARD32 val)
500 {
501 *((CARD32 *) (memType) addr) = val;
502 }
503
504 void *
xf86int10Addr(xf86Int10InfoPtr pInt,CARD32 addr)505 xf86int10Addr(xf86Int10InfoPtr pInt, CARD32 addr)
506 {
507 if (addr < V_RAM)
508 return ((linuxInt10Priv *) pInt->private)->base + addr;
509 else if (addr < V_BIOS)
510 return (void *) (memType) addr;
511 else if (addr < SYS_BIOS) {
512 if (((linuxInt10Priv *) pInt->private)->base_high)
513 return (void *) (((linuxInt10Priv *) pInt->private)->base_high
514 - V_BIOS + addr);
515 else
516 return (void *) (memType) addr;
517 }
518 else
519 return (void *) (memType) addr;
520 }
521
522 #if defined DoSubModules
523
524 static Bool
vm86_tst(void)525 vm86_tst(void)
526 {
527 int __res;
528
529 #ifdef __PIC__
530 /* When compiling with -fPIC, we can't use asm constraint "b" because
531 %ebx is already taken by gcc. */
532 __asm__ __volatile__("pushl %%ebx\n\t"
533 "movl %2,%%ebx\n\t"
534 "movl %1,%%eax\n\t"
535 "int $0x80\n\t" "popl %%ebx":"=a"(__res)
536 :"n"((int) 113), "r"(NULL));
537 #else
538 __asm__ __volatile__("int $0x80\n\t":"=a"(__res):"a"((int) 113),
539 "b"((struct vm86_struct *) NULL));
540 #endif
541
542 if (__res < 0 && __res == -ENOSYS)
543 return FALSE;
544
545 return TRUE;
546 }
547
548 static Int10LinuxSubModuleState
int10LinuxLoadSubModule(ScrnInfoPtr pScrn)549 int10LinuxLoadSubModule(ScrnInfoPtr pScrn)
550 {
551 if (vm86_tst()) {
552 if (xf86LoadSubModule(pScrn, "vm86"))
553 return INT10_LOADED_VM86;
554 }
555 if (xf86LoadSubModule(pScrn, "x86emu"))
556 return INT10_LOADED_X86EMU;
557
558 return INT10_LOAD_FAILED;
559 }
560
561 #endif /* DoSubModules */
562