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 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 73static Bool 74readLegacy(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 87xf86Int10InfoPtr 88xf86ExtendedInitInt10(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 334Bool 335MapCurrentInt10(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 396void 397xf86FreeInt10(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 425void * 426xf86Int10AllocPages(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 454void 455xf86Int10FreePages(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 467static CARD8 468read_b(xf86Int10InfoPtr pInt, int addr) 469{ 470 return *((CARD8 *) (memType) addr); 471} 472 473static CARD16 474read_w(xf86Int10InfoPtr pInt, int addr) 475{ 476 return *((CARD16 *) (memType) addr); 477} 478 479static CARD32 480read_l(xf86Int10InfoPtr pInt, int addr) 481{ 482 return *((CARD32 *) (memType) addr); 483} 484 485static void 486write_b(xf86Int10InfoPtr pInt, int addr, CARD8 val) 487{ 488 *((CARD8 *) (memType) addr) = val; 489} 490 491static void 492write_w(xf86Int10InfoPtr pInt, int addr, CARD16 val) 493{ 494 *((CARD16 *) (memType) addr) = val; 495} 496 497static 498 void 499write_l(xf86Int10InfoPtr pInt, int addr, CARD32 val) 500{ 501 *((CARD32 *) (memType) addr) = val; 502} 503 504void * 505xf86int10Addr(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 524static Bool 525vm86_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 548static Int10LinuxSubModuleState 549int10LinuxLoadSubModule(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