]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/xserver.git/blob - hw/xfree86/os-support/linux/int10/linux.c
Imported Upstream version 1.11.4
[glsdk/xserver.git] / hw / xfree86 / os-support / linux / int10 / linux.c
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
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 (pointer)(-1)
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>
31 static int counter = 0;
32 static unsigned long int10Generation = 0;
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);
41 int10MemRec linuxMem = {
42     read_b,
43     read_w,
44     read_l,
45     write_b,
46     write_w,
47     write_l
48 };
50 typedef struct {
51     int lowMem;
52     int highMem;
53     char* base;
54     char* base_high;
55     int screen;
56     char* alloc;
57 } linuxInt10Priv;
59 #if defined DoSubModules
61 typedef enum {
62     INT10_NOT_LOADED,
63     INT10_LOADED_VM86,
64     INT10_LOADED_X86EMU,
65     INT10_LOAD_FAILED
66 } Int10LinuxSubModuleState;
68 static Int10LinuxSubModuleState loadedSubModule = INT10_NOT_LOADED;
70 static Int10LinuxSubModuleState int10LinuxLoadSubModule(ScrnInfoPtr pScrn);
72 #endif /* DoSubModules */
74 xf86Int10InfoPtr
75 xf86ExtendedInitInt10(int entityIndex, int Flags)
76 {
77     xf86Int10InfoPtr pInt = NULL;
78     int screen;
79     int fd;
80     static void* vidMem = NULL;
81     static void* sysMem = NULL;
82     void* vMem = NULL;
83     void *options = NULL;
84     int low_mem;
85     int high_mem = -1;
86     char *base = SHMERRORPTR;
87     char *base_high = SHMERRORPTR;
88     int pagesize; 
89     memType cs;
90     legacyVGARec vga;
91     Bool videoBiosMapped = FALSE;
92     
93     if (int10Generation != serverGeneration) {
94         counter = 0;
95         int10Generation = serverGeneration;
96     }
98     screen = (xf86FindScreenForEntity(entityIndex))->scrnIndex;
100     options = xf86HandleInt10Options(xf86Screens[screen],entityIndex);
102     if (int10skip(options)) {
103         free(options);
104         return NULL;
105     }
107 #if defined DoSubModules
108     if (loadedSubModule == INT10_NOT_LOADED) 
109         loadedSubModule = int10LinuxLoadSubModule(xf86Screens[screen]);
111     if (loadedSubModule == INT10_LOAD_FAILED)
112         return NULL;
113 #endif
115     if ((!vidMem) || (!sysMem)) {
116         if ((fd = open(DEV_MEM, O_RDWR, 0)) >= 0) {
117             if (!sysMem) {
118                 DebugF("Mapping sys bios area\n");
119                 if ((sysMem = mmap((void *)(SYS_BIOS), BIOS_SIZE,
120                                    PROT_READ | PROT_EXEC,
121                                    MAP_SHARED | MAP_FIXED, fd, SYS_BIOS))
122                     == MAP_FAILED) {
123                     xf86DrvMsg(screen, X_ERROR, "Cannot map SYS BIOS\n");
124                     close(fd);
125                     goto error0;
126                 }
127             }
128             if (!vidMem) {
129                 DebugF("Mapping VRAM area\n");
130                 if ((vidMem = mmap((void *)(V_RAM), VRAM_SIZE,
131                                    PROT_READ | PROT_WRITE | PROT_EXEC,
132                                    MAP_SHARED | MAP_FIXED, fd, V_RAM))
133                     == MAP_FAILED) {
134                     xf86DrvMsg(screen, X_ERROR, "Cannot map V_RAM\n");
135                     close(fd);
136                     goto error0;
137                 }
138             }
139             close(fd);
140         } else {
141             xf86DrvMsg(screen, X_ERROR, "Cannot open %s\n", DEV_MEM);
142             goto error0;
143         }
144     }
146     pInt = (xf86Int10InfoPtr)xnfcalloc(1, sizeof(xf86Int10InfoRec));
147     pInt->scrnIndex = screen;
148     pInt->entityIndex = entityIndex;
149     pInt->dev = xf86GetPciInfoForEntity(entityIndex);
151     if (!xf86Int10ExecSetup(pInt))
152         goto error0;
153     pInt->mem = &linuxMem;
154     pagesize = getpagesize();
155     pInt->private = (pointer)xnfcalloc(1, sizeof(linuxInt10Priv));
156     ((linuxInt10Priv*)pInt->private)->screen = screen;
157     ((linuxInt10Priv*)pInt->private)->alloc =
158         (pointer)xnfcalloc(1, ALLOC_ENTRIES(pagesize));
160     if (!xf86IsEntityPrimary(entityIndex)) {
161         DebugF("Mapping high memory area\n");
162         if ((high_mem = shmget(counter++, HIGH_MEM_SIZE,
163                                IPC_CREAT | SHM_R | SHM_W)) == -1) {
164             if (errno == ENOSYS)
165                 xf86DrvMsg(screen, X_ERROR, "shmget error\n Please reconfigure"
166                            " your kernel to include System V IPC support\n");
167             else
168                 xf86DrvMsg(screen, X_ERROR,
169                            "shmget(highmem) error: %s\n",strerror(errno));
170             goto error1;
171         }
172     } else {
173         DebugF("Mapping Video BIOS\n");
174         videoBiosMapped = TRUE;
175         if ((fd = open(DEV_MEM, O_RDWR, 0)) >= 0) {
176             if ((vMem = mmap((void *)(V_BIOS), SYS_BIOS - V_BIOS,
177                              PROT_READ | PROT_WRITE | PROT_EXEC,
178                              MAP_SHARED | MAP_FIXED, fd, V_BIOS))
179                 == MAP_FAILED) {
180                 xf86DrvMsg(screen, X_ERROR, "Cannot map V_BIOS\n");
181                 close(fd);
182                 goto error1;
183             }
184             close (fd);
185         } else
186             goto error1;
187     }
188     ((linuxInt10Priv*)pInt->private)->highMem = high_mem;
189     
190     DebugF("Mapping 640kB area\n");
191     if ((low_mem = shmget(counter++, V_RAM,
192                           IPC_CREAT | SHM_R | SHM_W)) == -1) {
193         xf86DrvMsg(screen, X_ERROR,
194                    "shmget(lowmem) error: %s\n",strerror(errno));
195         goto error2;
196     }
198     ((linuxInt10Priv*)pInt->private)->lowMem = low_mem;
199     base = shmat(low_mem, 0, 0);
200     if (base == SHMERRORPTR) {
201         xf86DrvMsg(screen, X_ERROR,
202                    "shmat(low_mem) error: %s\n",strerror(errno));
203         goto error3;
204     }
205     ((linuxInt10Priv *)pInt->private)->base = base;
206     if (high_mem > -1) {
207         base_high = shmat(high_mem, 0, 0);
208         if (base_high == SHMERRORPTR) {
209             xf86DrvMsg(screen, X_ERROR,
210                        "shmat(high_mem) error: %s\n",strerror(errno));
211             goto error3;
212         }
213         ((linuxInt10Priv*)pInt->private)->base_high = base_high;
214     } else
215         ((linuxInt10Priv*)pInt->private)->base_high = NULL;
217     if (!MapCurrentInt10(pInt))
218         goto error3;
219     
220     Int10Current = pInt;
222     DebugF("Mapping int area\n");
223     if (xf86ReadBIOS(0, 0, (unsigned char *)0, LOW_PAGE_SIZE) < 0) {
224         xf86DrvMsg(screen, X_ERROR, "Cannot read int vect\n");
225         goto error3;
226     }
227     DebugF("done\n");
228     /*
229      * Read in everything between V_BIOS and SYS_BIOS as some system BIOSes
230      * have executable code there.  Note that xf86ReadBIOS() can only bring in
231      * 64K bytes at a time.
232      */
233     if (!videoBiosMapped) {
234         memset((pointer)V_BIOS, 0, SYS_BIOS - V_BIOS);
235         DebugF("Reading BIOS\n");
236         for (cs = V_BIOS;  cs < SYS_BIOS;  cs += V_BIOS_SIZE)
237             if (xf86ReadBIOS(cs, 0, (pointer)cs, V_BIOS_SIZE) < V_BIOS_SIZE)
238                 xf86DrvMsg(screen, X_WARNING,
239                            "Unable to retrieve all of segment 0x%06lX.\n",
240                            (long)cs);
241         DebugF("done\n");
242     }
244     if (xf86IsEntityPrimary(entityIndex) && !(initPrimary(options))) {
245         if (!xf86int10GetBiosSegment(pInt, NULL))
246             goto error3;
248         set_return_trap(pInt);
249 #ifdef _PC      
250         pInt->Flags = Flags & (SET_BIOS_SCRATCH | RESTORE_BIOS_SCRATCH);
251         if (! (pInt->Flags & SET_BIOS_SCRATCH))
252             pInt->Flags &= ~RESTORE_BIOS_SCRATCH;
253         xf86Int10SaveRestoreBIOSVars(pInt, TRUE);
254 #endif
255     } else {
256         const BusType location_type = xf86int10GetBiosLocationType(pInt);
258         switch (location_type) {
259         case BUS_PCI: {
260             int err;
261             struct pci_device *rom_device =
262                 xf86GetPciInfoForEntity(pInt->entityIndex);
264 #if HAVE_PCI_DEVICE_ENABLE
265             pci_device_enable(rom_device);
266 #endif
268             err = pci_device_read_rom(rom_device, (unsigned char *)(V_BIOS));
269             if (err) {
270                 xf86DrvMsg(screen,X_ERROR,"Cannot read V_BIOS (%s)\n",
271                            strerror(err));
272                 goto error3;
273             }
275             pInt->BIOSseg = V_BIOS >> 4;
276             break;
277         }
278         default:
279             goto error3;
280         }
282         pInt->num = 0xe6;
283         reset_int_vect(pInt);
284         set_return_trap(pInt);
285         LockLegacyVGA(pInt, &vga);
286         xf86ExecX86int10(pInt);
287         UnlockLegacyVGA(pInt, &vga);
288     }
289 #ifdef DEBUG
290     dprint(0xc0000, 0x20);
291 #endif
293     free(options);
294     return pInt;
296 error3:
297     if (base_high)
298         shmdt(base_high);
299     shmdt(base);
300     shmdt(0);
301     if (base_high)
302         shmdt((char*)HIGH_MEM);
303     shmctl(low_mem, IPC_RMID, NULL);
304     Int10Current = NULL;
305 error2:
306     if (high_mem > -1)
307         shmctl(high_mem, IPC_RMID,NULL);
308 error1:
309     if (vMem)
310         munmap(vMem, SYS_BIOS - V_BIOS);
311     free(((linuxInt10Priv*)pInt->private)->alloc);
312     free(pInt->private);
313 error0:
314     free(options);
315     free(pInt);
316     return NULL;
319 Bool
320 MapCurrentInt10(xf86Int10InfoPtr pInt)
322     pointer addr;
323     int fd = -1;
324     
325     if (Int10Current) {
326         shmdt(0);
327         if (((linuxInt10Priv*)Int10Current->private)->highMem >= 0)
328             shmdt((char*)HIGH_MEM);
329         else
330             munmap((pointer)V_BIOS, (SYS_BIOS - V_BIOS));
331     }
332     addr = shmat(((linuxInt10Priv*)pInt->private)->lowMem, (char*)1, SHM_RND);
333     if (addr == SHMERRORPTR) {
334         xf86DrvMsg(pInt->scrnIndex, X_ERROR, "Cannot shmat() low memory\n");
335         xf86DrvMsg(pInt->scrnIndex, X_ERROR,
336                    "shmat(low_mem) error: %s\n",strerror(errno));
337         return FALSE;
338     }
339     if (mprotect((void*)0, V_RAM, PROT_READ|PROT_WRITE|PROT_EXEC) != 0)
340         xf86DrvMsg(pInt->scrnIndex, X_ERROR,
341                    "Cannot set EXEC bit on low memory: %s\n", strerror(errno));
343     if (((linuxInt10Priv*)pInt->private)->highMem >= 0) {
344         addr = shmat(((linuxInt10Priv*)pInt->private)->highMem,
345                      (char*)HIGH_MEM, 0);
346         if (addr == SHMERRORPTR) {
347             xf86DrvMsg(pInt->scrnIndex, X_ERROR,
348                        "Cannot shmat() high memory\n");
349             xf86DrvMsg(pInt->scrnIndex, X_ERROR,
350                        "shmget error: %s\n",strerror(errno));
351             return FALSE;
352         }
353         if (mprotect((void*)HIGH_MEM, HIGH_MEM_SIZE,
354                      PROT_READ|PROT_WRITE|PROT_EXEC) != 0)
355             xf86DrvMsg(pInt->scrnIndex, X_ERROR,
356                        "Cannot set EXEC bit on high memory: %s\n",
357                        strerror(errno));
358     } else {
359         if ((fd = open(DEV_MEM, O_RDWR, 0)) >= 0) {
360             if (mmap((void *)(V_BIOS), SYS_BIOS - V_BIOS,
361                              PROT_READ | PROT_WRITE | PROT_EXEC,
362                              MAP_SHARED | MAP_FIXED, fd, V_BIOS)
363                 == MAP_FAILED) {
364                 xf86DrvMsg(pInt->scrnIndex, X_ERROR, "Cannot map V_BIOS\n");
365                 close (fd);
366                 return FALSE;
367             }
368         } else {
369             xf86DrvMsg(pInt->scrnIndex, X_ERROR, "Cannot open %s\n",DEV_MEM);
370             return FALSE;
371         }
372         close (fd);
373     }
374     
375     return TRUE;
378 void
379 xf86FreeInt10(xf86Int10InfoPtr pInt)
381     if (!pInt)
382         return;
384 #ifdef _PC
385     xf86Int10SaveRestoreBIOSVars(pInt, FALSE); 
386 #endif
387     if (Int10Current == pInt) {
388         shmdt(0);
389         if (((linuxInt10Priv*)pInt->private)->highMem >= 0)
390             shmdt((char*)HIGH_MEM);
391         else
392             munmap((pointer)V_BIOS, (SYS_BIOS - V_BIOS));
393         Int10Current = NULL;
394     }
395     
396     if (((linuxInt10Priv*)pInt->private)->base_high)
397         shmdt(((linuxInt10Priv*)pInt->private)->base_high);
398     shmdt(((linuxInt10Priv*)pInt->private)->base);
399     shmctl(((linuxInt10Priv*)pInt->private)->lowMem, IPC_RMID, NULL);
400     if (((linuxInt10Priv*)pInt->private)->highMem >= 0)
401         shmctl(((linuxInt10Priv*)pInt->private)->highMem, IPC_RMID, NULL);
402     free(((linuxInt10Priv*)pInt->private)->alloc);
403     free(pInt->private);
404     free(pInt);
407 void *
408 xf86Int10AllocPages(xf86Int10InfoPtr pInt, int num, int *off)
410     int pagesize = getpagesize();
411     int num_pages = ALLOC_ENTRIES(pagesize);
412     int i, j;
414     for (i = 0; i < (num_pages - num); i++) {
415         if (((linuxInt10Priv*)pInt->private)->alloc[i] == 0) {
416             for (j = i; j < (num + i); j++)
417                 if ((((linuxInt10Priv*)pInt->private)->alloc[j] != 0))
418                     break;
419             if (j == (num + i))
420                 break;
421             else
422                 i = i + num;
423         }
424     }
425     if (i == (num_pages - num))
426         return NULL;
428     for (j = i; j < (i + num); j++)
429         ((linuxInt10Priv*)pInt->private)->alloc[j] = 1;
431     *off = (i + 1) * pagesize;
433     return ((linuxInt10Priv*)pInt->private)->base + ((i + 1) * pagesize);
436 void
437 xf86Int10FreePages(xf86Int10InfoPtr pInt, void *pbase, int num)
439     int pagesize = getpagesize();
440     int first = (((unsigned long)pbase
441                  - (unsigned long)((linuxInt10Priv*)pInt->private)->base)
442         / pagesize) - 1;
443     int i;
445     for (i = first; i < (first + num); i++)
446         ((linuxInt10Priv*)pInt->private)->alloc[i] = 0;
449 static CARD8
450 read_b(xf86Int10InfoPtr pInt, int addr)
452     return *((CARD8 *)(memType)addr);
455 static CARD16
456 read_w(xf86Int10InfoPtr pInt, int addr)
458     return *((CARD16 *)(memType)addr);
461 static CARD32
462 read_l(xf86Int10InfoPtr pInt, int addr)
464     return *((CARD32 *)(memType)addr);
467 static void
468 write_b(xf86Int10InfoPtr pInt, int addr, CARD8 val)
470     *((CARD8 *)(memType)addr) = val;
473 static void
474 write_w(xf86Int10InfoPtr pInt, int addr, CARD16 val)
476     *((CARD16 *)(memType)addr) = val;
479 static
480 void write_l(xf86Int10InfoPtr pInt, int addr, CARD32 val)
482     *((CARD32 *)(memType) addr) = val;
485 pointer
486 xf86int10Addr(xf86Int10InfoPtr pInt, CARD32 addr)
488     if (addr < V_RAM)
489         return ((linuxInt10Priv*)pInt->private)->base + addr;
490     else if (addr < V_BIOS)
491         return (pointer)(memType)addr;
492     else if (addr < SYS_BIOS) {
493         if (((linuxInt10Priv*)pInt->private)->base_high)
494             return (pointer)(((linuxInt10Priv*)pInt->private)->base_high
495                              - V_BIOS + addr);
496         else
497             return (pointer) (memType)addr;
498     } else
499         return (pointer) (memType)addr;
502 #if defined DoSubModules
504 static Bool
505 vm86_tst(void)
507     int __res;
509 #ifdef __PIC__
510     /* When compiling with -fPIC, we can't use asm constraint "b" because
511        %ebx is already taken by gcc. */
512     __asm__ __volatile__("pushl %%ebx\n\t"
513                          "movl %2,%%ebx\n\t"
514                          "movl %1,%%eax\n\t"
515                          "int $0x80\n\t"
516                          "popl %%ebx"
517                          :"=a" (__res)
518                          :"n" ((int)113), "r" (NULL));
519 #else
520     __asm__ __volatile__("int $0x80\n\t"
521                          :"=a" (__res):"a" ((int)113),
522                          "b" ((struct vm86_struct *)NULL));
523 #endif
525     if (__res < 0 && __res == -ENOSYS) 
526         return FALSE;
528     return TRUE;
531 static Int10LinuxSubModuleState
532 int10LinuxLoadSubModule(ScrnInfoPtr pScrn)
534     if (vm86_tst()) {
535         if (xf86LoadSubModule(pScrn,"vm86"))
536             return INT10_LOADED_VM86;
537     } 
538     if (xf86LoadSubModule(pScrn,"x86emu"))
539         return INT10_LOADED_X86EMU;
541     return INT10_LOAD_FAILED;
544 #endif /* DoSubModules */