Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / xfree86 / os-support / linux / int10 / linux.c
CommitLineData
a09e091a
JB
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 (pointer)(-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
31static int counter = 0;
32static unsigned long int10Generation = 0;
33
34static CARD8 read_b(xf86Int10InfoPtr pInt, int addr);
35static CARD16 read_w(xf86Int10InfoPtr pInt, int addr);
36static CARD32 read_l(xf86Int10InfoPtr pInt, int addr);
37static void write_b(xf86Int10InfoPtr pInt, int addr, CARD8 val);
38static void write_w(xf86Int10InfoPtr pInt, int addr, CARD16 val);
39static void write_l(xf86Int10InfoPtr pInt, int addr, CARD32 val);
40
41int10MemRec linuxMem = {
42 read_b,
43 read_w,
44 read_l,
45 write_b,
46 write_w,
47 write_l
48};
49
50typedef 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
60typedef enum {
61 INT10_NOT_LOADED,
62 INT10_LOADED_VM86,
63 INT10_LOADED_X86EMU,
64 INT10_LOAD_FAILED
65} Int10LinuxSubModuleState;
66
67static Int10LinuxSubModuleState loadedSubModule = INT10_NOT_LOADED;
68
69static Int10LinuxSubModuleState int10LinuxLoadSubModule(ScrnInfoPtr pScrn);
70
71#endif /* DoSubModules */
72
73xf86Int10InfoPtr
74xf86ExtendedInitInt10(int entityIndex, int Flags)
75{
76 xf86Int10InfoPtr pInt = NULL;
77 int screen;
78 int fd;
79 static void *vidMem = NULL;
80 static void *sysMem = NULL;
81 void *vMem = NULL;
82 void *options = NULL;
83 int low_mem;
84 int high_mem = -1;
85 char *base = SHMERRORPTR;
86 char *base_high = SHMERRORPTR;
87 int pagesize;
88 memType cs;
89 legacyVGARec vga;
90 Bool videoBiosMapped = FALSE;
91 ScrnInfoPtr pScrn;
92 if (int10Generation != serverGeneration) {
93 counter = 0;
94 int10Generation = serverGeneration;
95 }
96
97 pScrn = xf86FindScreenForEntity(entityIndex);
98 screen = pScrn->scrnIndex;
99
100 options = xf86HandleInt10Options(pScrn, entityIndex);
101
102 if (int10skip(options)) {
103 free(options);
104 return NULL;
105 }
106
107#if defined DoSubModules
108 if (loadedSubModule == INT10_NOT_LOADED)
109 loadedSubModule = int10LinuxLoadSubModule(pScrn);
110
111 if (loadedSubModule == INT10_LOAD_FAILED)
112 return NULL;
113#endif
114
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 }
141 else {
142 xf86DrvMsg(screen, X_ERROR, "Cannot open %s\n", DEV_MEM);
143 goto error0;
144 }
145 }
146
147 pInt = (xf86Int10InfoPtr) xnfcalloc(1, sizeof(xf86Int10InfoRec));
148 pInt->pScrn = pScrn;
149 pInt->entityIndex = entityIndex;
150 pInt->dev = xf86GetPciInfoForEntity(entityIndex);
151
152 if (!xf86Int10ExecSetup(pInt))
153 goto error0;
154 pInt->mem = &linuxMem;
155 pagesize = getpagesize();
156 pInt->private = (pointer) xnfcalloc(1, sizeof(linuxInt10Priv));
157 ((linuxInt10Priv *) pInt->private)->alloc =
158 (pointer) xnfcalloc(1, ALLOC_ENTRIES(pagesize));
159
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 }
173 else {
174 DebugF("Mapping Video BIOS\n");
175 videoBiosMapped = TRUE;
176 if ((fd = open(DEV_MEM, O_RDWR, 0)) >= 0) {
177 if ((vMem = mmap((void *) (V_BIOS), SYS_BIOS - V_BIOS,
178 PROT_READ | PROT_WRITE | PROT_EXEC,
179 MAP_SHARED | MAP_FIXED, fd, V_BIOS))
180 == MAP_FAILED) {
181 xf86DrvMsg(screen, X_ERROR, "Cannot map V_BIOS\n");
182 close(fd);
183 goto error1;
184 }
185 close(fd);
186 }
187 else
188 goto error1;
189 }
190 ((linuxInt10Priv *) pInt->private)->highMem = high_mem;
191
192 DebugF("Mapping 640kB area\n");
193 if ((low_mem = shmget(counter++, V_RAM, IPC_CREAT | SHM_R | SHM_W)) == -1) {
194 xf86DrvMsg(screen, X_ERROR,
195 "shmget(lowmem) error: %s\n", strerror(errno));
196 goto error2;
197 }
198
199 ((linuxInt10Priv *) pInt->private)->lowMem = low_mem;
200 base = shmat(low_mem, 0, 0);
201 if (base == SHMERRORPTR) {
202 xf86DrvMsg(screen, X_ERROR,
203 "shmat(low_mem) error: %s\n", strerror(errno));
204 goto error3;
205 }
206 ((linuxInt10Priv *) pInt->private)->base = base;
207 if (high_mem > -1) {
208 base_high = shmat(high_mem, 0, 0);
209 if (base_high == SHMERRORPTR) {
210 xf86DrvMsg(screen, X_ERROR,
211 "shmat(high_mem) error: %s\n", strerror(errno));
212 goto error3;
213 }
214 ((linuxInt10Priv *) pInt->private)->base_high = base_high;
215 }
216 else
217 ((linuxInt10Priv *) pInt->private)->base_high = NULL;
218
219 if (!MapCurrentInt10(pInt))
220 goto error3;
221
222 Int10Current = pInt;
223
224 DebugF("Mapping int area\n");
225 if (xf86ReadBIOS(0, 0, (unsigned char *) 0, LOW_PAGE_SIZE) < 0) {
226 xf86DrvMsg(screen, X_ERROR, "Cannot read int vect\n");
227 goto error3;
228 }
229 DebugF("done\n");
230 /*
231 * Read in everything between V_BIOS and SYS_BIOS as some system BIOSes
232 * have executable code there. Note that xf86ReadBIOS() can only bring in
233 * 64K bytes at a time.
234 */
235 if (!videoBiosMapped) {
236 memset((pointer) V_BIOS, 0, SYS_BIOS - V_BIOS);
237 DebugF("Reading BIOS\n");
238 for (cs = V_BIOS; cs < SYS_BIOS; cs += V_BIOS_SIZE)
239 if (xf86ReadBIOS(cs, 0, (pointer) cs, V_BIOS_SIZE) < V_BIOS_SIZE)
240 xf86DrvMsg(screen, X_WARNING,
241 "Unable to retrieve all of segment 0x%06lX.\n",
242 (long) cs);
243 DebugF("done\n");
244 }
245
246 if (xf86IsEntityPrimary(entityIndex) && !(initPrimary(options))) {
247 if (!xf86int10GetBiosSegment(pInt, NULL))
248 goto error3;
249
250 set_return_trap(pInt);
251#ifdef _PC
252 pInt->Flags = Flags & (SET_BIOS_SCRATCH | RESTORE_BIOS_SCRATCH);
253 if (!(pInt->Flags & SET_BIOS_SCRATCH))
254 pInt->Flags &= ~RESTORE_BIOS_SCRATCH;
255 xf86Int10SaveRestoreBIOSVars(pInt, TRUE);
256#endif
257 }
258 else {
259 const BusType location_type = xf86int10GetBiosLocationType(pInt);
260
261 switch (location_type) {
262 case BUS_PCI:{
263 int err;
264 struct pci_device *rom_device =
265 xf86GetPciInfoForEntity(pInt->entityIndex);
266
267 pci_device_enable(rom_device);
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 }
274
275 pInt->BIOSseg = V_BIOS >> 4;
276 break;
277 }
278 default:
279 goto error3;
280 }
281
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
292
293 free(options);
294 return pInt;
295
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;
317}
318
319Bool
320MapCurrentInt10(xf86Int10InfoPtr pInt)
321{
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 =
333 shmat(((linuxInt10Priv *) pInt->private)->lowMem, (char *) 1, SHM_RND);
334 if (addr == SHMERRORPTR) {
335 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR, "Cannot shmat() low memory\n");
336 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR,
337 "shmat(low_mem) error: %s\n", strerror(errno));
338 return FALSE;
339 }
340 if (mprotect((void *) 0, V_RAM, PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
341 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR,
342 "Cannot set EXEC bit on low memory: %s\n", strerror(errno));
343
344 if (((linuxInt10Priv *) pInt->private)->highMem >= 0) {
345 addr = shmat(((linuxInt10Priv *) pInt->private)->highMem,
346 (char *) HIGH_MEM, 0);
347 if (addr == SHMERRORPTR) {
348 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR,
349 "Cannot shmat() high memory\n");
350 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR,
351 "shmget error: %s\n", strerror(errno));
352 return FALSE;
353 }
354 if (mprotect((void *) HIGH_MEM, HIGH_MEM_SIZE,
355 PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
356 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR,
357 "Cannot set EXEC bit on high memory: %s\n",
358 strerror(errno));
359 }
360 else {
361 if ((fd = open(DEV_MEM, O_RDWR, 0)) >= 0) {
362 if (mmap((void *) (V_BIOS), SYS_BIOS - V_BIOS,
363 PROT_READ | PROT_WRITE | PROT_EXEC,
364 MAP_SHARED | MAP_FIXED, fd, V_BIOS)
365 == MAP_FAILED) {
366 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR, "Cannot map V_BIOS\n");
367 close(fd);
368 return FALSE;
369 }
370 }
371 else {
372 xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR, "Cannot open %s\n", DEV_MEM);
373 return FALSE;
374 }
375 close(fd);
376 }
377
378 return TRUE;
379}
380
381void
382xf86FreeInt10(xf86Int10InfoPtr pInt)
383{
384 if (!pInt)
385 return;
386
387#ifdef _PC
388 xf86Int10SaveRestoreBIOSVars(pInt, FALSE);
389#endif
390 if (Int10Current == pInt) {
391 shmdt(0);
392 if (((linuxInt10Priv *) pInt->private)->highMem >= 0)
393 shmdt((char *) HIGH_MEM);
394 else
395 munmap((pointer) V_BIOS, (SYS_BIOS - V_BIOS));
396 Int10Current = NULL;
397 }
398
399 if (((linuxInt10Priv *) pInt->private)->base_high)
400 shmdt(((linuxInt10Priv *) pInt->private)->base_high);
401 shmdt(((linuxInt10Priv *) pInt->private)->base);
402 shmctl(((linuxInt10Priv *) pInt->private)->lowMem, IPC_RMID, NULL);
403 if (((linuxInt10Priv *) pInt->private)->highMem >= 0)
404 shmctl(((linuxInt10Priv *) pInt->private)->highMem, IPC_RMID, NULL);
405 free(((linuxInt10Priv *) pInt->private)->alloc);
406 free(pInt->private);
407 free(pInt);
408}
409
410void *
411xf86Int10AllocPages(xf86Int10InfoPtr pInt, int num, int *off)
412{
413 int pagesize = getpagesize();
414 int num_pages = ALLOC_ENTRIES(pagesize);
415 int i, j;
416
417 for (i = 0; i < (num_pages - num); i++) {
418 if (((linuxInt10Priv *) pInt->private)->alloc[i] == 0) {
419 for (j = i; j < (num + i); j++)
420 if ((((linuxInt10Priv *) pInt->private)->alloc[j] != 0))
421 break;
422 if (j == (num + i))
423 break;
424 else
425 i = i + num;
426 }
427 }
428 if (i == (num_pages - num))
429 return NULL;
430
431 for (j = i; j < (i + num); j++)
432 ((linuxInt10Priv *) pInt->private)->alloc[j] = 1;
433
434 *off = (i + 1) * pagesize;
435
436 return ((linuxInt10Priv *) pInt->private)->base + ((i + 1) * pagesize);
437}
438
439void
440xf86Int10FreePages(xf86Int10InfoPtr pInt, void *pbase, int num)
441{
442 int pagesize = getpagesize();
443 int first = (((unsigned long) pbase
444 - (unsigned long) ((linuxInt10Priv *) pInt->private)->base)
445 / pagesize) - 1;
446 int i;
447
448 for (i = first; i < (first + num); i++)
449 ((linuxInt10Priv *) pInt->private)->alloc[i] = 0;
450}
451
452static CARD8
453read_b(xf86Int10InfoPtr pInt, int addr)
454{
455 return *((CARD8 *) (memType) addr);
456}
457
458static CARD16
459read_w(xf86Int10InfoPtr pInt, int addr)
460{
461 return *((CARD16 *) (memType) addr);
462}
463
464static CARD32
465read_l(xf86Int10InfoPtr pInt, int addr)
466{
467 return *((CARD32 *) (memType) addr);
468}
469
470static void
471write_b(xf86Int10InfoPtr pInt, int addr, CARD8 val)
472{
473 *((CARD8 *) (memType) addr) = val;
474}
475
476static void
477write_w(xf86Int10InfoPtr pInt, int addr, CARD16 val)
478{
479 *((CARD16 *) (memType) addr) = val;
480}
481
482static
483 void
484write_l(xf86Int10InfoPtr pInt, int addr, CARD32 val)
485{
486 *((CARD32 *) (memType) addr) = val;
487}
488
489pointer
490xf86int10Addr(xf86Int10InfoPtr pInt, CARD32 addr)
491{
492 if (addr < V_RAM)
493 return ((linuxInt10Priv *) pInt->private)->base + addr;
494 else if (addr < V_BIOS)
495 return (pointer) (memType) addr;
496 else if (addr < SYS_BIOS) {
497 if (((linuxInt10Priv *) pInt->private)->base_high)
498 return (pointer) (((linuxInt10Priv *) pInt->private)->base_high
499 - V_BIOS + addr);
500 else
501 return (pointer) (memType) addr;
502 }
503 else
504 return (pointer) (memType) addr;
505}
506
507#if defined DoSubModules
508
509static Bool
510vm86_tst(void)
511{
512 int __res;
513
514#ifdef __PIC__
515 /* When compiling with -fPIC, we can't use asm constraint "b" because
516 %ebx is already taken by gcc. */
517 __asm__ __volatile__("pushl %%ebx\n\t"
518 "movl %2,%%ebx\n\t"
519 "movl %1,%%eax\n\t"
520 "int $0x80\n\t" "popl %%ebx":"=a"(__res)
521 :"n"((int) 113), "r"(NULL));
522#else
523 __asm__ __volatile__("int $0x80\n\t":"=a"(__res):"a"((int) 113),
524 "b"((struct vm86_struct *) NULL));
525#endif
526
527 if (__res < 0 && __res == -ENOSYS)
528 return FALSE;
529
530 return TRUE;
531}
532
533static Int10LinuxSubModuleState
534int10LinuxLoadSubModule(ScrnInfoPtr pScrn)
535{
536 if (vm86_tst()) {
537 if (xf86LoadSubModule(pScrn, "vm86"))
538 return INT10_LOADED_VM86;
539 }
540 if (xf86LoadSubModule(pScrn, "x86emu"))
541 return INT10_LOADED_X86EMU;
542
543 return INT10_LOAD_FAILED;
544}
545
546#endif /* DoSubModules */