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