generic.c (12175B)
1 /* 2 * XFree86 int10 module 3 * execute BIOS int 10h calls in x86 real mode environment 4 * Copyright 1999 Egbert Eich 5 */ 6 #ifdef HAVE_XORG_CONFIG_H 7 #include <xorg-config.h> 8 #endif 9 10 #include <string.h> 11 #include <unistd.h> 12 13 #include "xf86.h" 14 #include "xf86_OSproc.h" 15 #include "compiler.h" 16 #define _INT10_PRIVATE 17 #include "xf86int10.h" 18 #include "int10Defines.h" 19 #include "Pci.h" 20 21 #define ALLOC_ENTRIES(x) ((V_RAM / x) - 1) 22 23 #include <string.h> /* needed for memmove */ 24 25 static __inline__ uint32_t 26 ldl_u(uint32_t * p) 27 { 28 uint32_t ret; 29 30 memmove(&ret, p, sizeof(*p)); 31 return ret; 32 } 33 34 static __inline__ uint16_t 35 ldw_u(uint16_t * p) 36 { 37 uint16_t ret; 38 39 memmove(&ret, p, sizeof(*p)); 40 return ret; 41 } 42 43 static __inline__ void 44 stl_u(uint32_t val, uint32_t * p) 45 { 46 uint32_t tmp = val; 47 48 memmove(p, &tmp, sizeof(*p)); 49 } 50 51 static __inline__ void 52 stw_u(uint16_t val, uint16_t * p) 53 { 54 uint16_t tmp = val; 55 56 memmove(p, &tmp, sizeof(*p)); 57 } 58 59 static uint8_t read_b(xf86Int10InfoPtr pInt, int addr); 60 static uint16_t read_w(xf86Int10InfoPtr pInt, int addr); 61 static uint32_t read_l(xf86Int10InfoPtr pInt, int addr); 62 static void write_b(xf86Int10InfoPtr pInt, int addr, uint8_t val); 63 static void write_w(xf86Int10InfoPtr pInt, int addr, uint16_t val); 64 static void write_l(xf86Int10InfoPtr pInt, int addr, uint32_t val); 65 66 /* 67 * the emulator cannot pass a pointer to the current xf86Int10InfoRec 68 * to the memory access functions therefore store it here. 69 */ 70 71 typedef struct { 72 int shift; 73 int entries; 74 void *base; 75 void *vRam; 76 int highMemory; 77 void *sysMem; 78 char *alloc; 79 } genericInt10Priv; 80 81 #define INTPriv(x) ((genericInt10Priv*)x->private) 82 83 int10MemRec genericMem = { 84 read_b, 85 read_w, 86 read_l, 87 write_b, 88 write_w, 89 write_l 90 }; 91 92 static void MapVRam(xf86Int10InfoPtr pInt); 93 static void UnmapVRam(xf86Int10InfoPtr pInt); 94 95 #ifdef _PC 96 #define GET_HIGH_BASE(x) (((V_BIOS + (x) + getpagesize() - 1)/getpagesize()) \ 97 * getpagesize()) 98 #endif 99 100 static void *sysMem = NULL; 101 102 static Bool 103 readIntVec(struct pci_device *dev, unsigned char *buf, int len) 104 { 105 void *map; 106 107 if (pci_device_map_legacy(dev, 0, len, 0, &map)) 108 return FALSE; 109 110 memcpy(buf, map, len); 111 pci_device_unmap_legacy(dev, map, len); 112 113 return TRUE; 114 } 115 116 xf86Int10InfoPtr 117 xf86ExtendedInitInt10(int entityIndex, int Flags) 118 { 119 xf86Int10InfoPtr pInt; 120 void *base = 0; 121 void *vbiosMem = 0; 122 void *options = NULL; 123 legacyVGARec vga; 124 ScrnInfoPtr pScrn; 125 126 pScrn = xf86FindScreenForEntity(entityIndex); 127 128 options = xf86HandleInt10Options(pScrn, entityIndex); 129 130 if (int10skip(options)) { 131 free(options); 132 return NULL; 133 } 134 135 pInt = (xf86Int10InfoPtr) xnfcalloc(1, sizeof(xf86Int10InfoRec)); 136 pInt->entityIndex = entityIndex; 137 if (!xf86Int10ExecSetup(pInt)) 138 goto error0; 139 pInt->mem = &genericMem; 140 pInt->private = (void *) xnfcalloc(1, sizeof(genericInt10Priv)); 141 INTPriv(pInt)->alloc = (void *) xnfcalloc(1, ALLOC_ENTRIES(getpagesize())); 142 pInt->pScrn = pScrn; 143 base = INTPriv(pInt)->base = xnfalloc(SYS_BIOS); 144 145 /* FIXME: Shouldn't this be a failure case? Leaving dev as NULL seems like 146 * FIXME: an error 147 */ 148 pInt->dev = xf86GetPciInfoForEntity(entityIndex); 149 150 /* 151 * we need to map video RAM MMIO as some chipsets map mmio 152 * registers into this range. 153 */ 154 MapVRam(pInt); 155 #ifdef _PC 156 if (!sysMem) 157 pci_device_map_legacy(pInt->dev, V_BIOS, BIOS_SIZE + SYS_BIOS - V_BIOS, 158 PCI_DEV_MAP_FLAG_WRITABLE, &sysMem); 159 INTPriv(pInt)->sysMem = sysMem; 160 161 if (!readIntVec(pInt->dev, base, LOW_PAGE_SIZE)) { 162 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Cannot read int vect\n"); 163 goto error1; 164 } 165 166 /* 167 * Retrieve everything between V_BIOS and SYS_BIOS as some system BIOSes 168 * have executable code there. 169 */ 170 memset((char *) base + V_BIOS, 0, SYS_BIOS - V_BIOS); 171 INTPriv(pInt)->highMemory = V_BIOS; 172 173 if (xf86IsEntityPrimary(entityIndex) && !(initPrimary(options))) { 174 if (!xf86int10GetBiosSegment(pInt, (unsigned char *) sysMem - V_BIOS)) 175 goto error1; 176 177 set_return_trap(pInt); 178 179 pInt->Flags = Flags & (SET_BIOS_SCRATCH | RESTORE_BIOS_SCRATCH); 180 if (!(pInt->Flags & SET_BIOS_SCRATCH)) 181 pInt->Flags &= ~RESTORE_BIOS_SCRATCH; 182 xf86Int10SaveRestoreBIOSVars(pInt, TRUE); 183 184 } 185 else { 186 const BusType location_type = xf86int10GetBiosLocationType(pInt); 187 int bios_location = V_BIOS; 188 189 reset_int_vect(pInt); 190 set_return_trap(pInt); 191 192 switch (location_type) { 193 case BUS_PCI:{ 194 int err; 195 struct pci_device *rom_device = 196 xf86GetPciInfoForEntity(pInt->entityIndex); 197 198 vbiosMem = (unsigned char *) base + bios_location; 199 err = pci_device_read_rom(rom_device, vbiosMem); 200 if (err) { 201 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Cannot read V_BIOS (3) %s\n", 202 strerror(err)); 203 goto error1; 204 } 205 INTPriv(pInt)->highMemory = GET_HIGH_BASE(rom_device->rom_size); 206 break; 207 } 208 default: 209 goto error1; 210 } 211 pInt->BIOSseg = V_BIOS >> 4; 212 pInt->num = 0xe6; 213 LockLegacyVGA(pInt, &vga); 214 xf86ExecX86int10(pInt); 215 UnlockLegacyVGA(pInt, &vga); 216 } 217 #else 218 if (!sysMem) { 219 sysMem = xnfalloc(BIOS_SIZE); 220 setup_system_bios(sysMem); 221 } 222 INTPriv(pInt)->sysMem = sysMem; 223 setup_int_vect(pInt); 224 set_return_trap(pInt); 225 226 /* Retrieve the entire legacy video BIOS segment. This can be up to 227 * 128KiB. 228 */ 229 vbiosMem = (char *) base + V_BIOS; 230 memset(vbiosMem, 0, 2 * V_BIOS_SIZE); 231 if (pci_device_read_rom(pInt->dev, vbiosMem) != 0 232 || pInt->dev->rom_size < V_BIOS_SIZE) { 233 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 234 "Unable to retrieve all of segment 0x0C0000.\n"); 235 } 236 237 /* 238 * If this adapter is the primary, use its post-init BIOS (if we can find 239 * it). 240 */ 241 { 242 int bios_location = V_BIOS; 243 Bool done = FALSE; 244 245 vbiosMem = (unsigned char *) base + bios_location; 246 247 if (xf86IsEntityPrimary(entityIndex)) { 248 if (int10_check_bios(pScrn->scrnIndex, bios_location >> 4, vbiosMem)) 249 done = TRUE; 250 else 251 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 252 "No legacy BIOS found -- trying PCI\n"); 253 } 254 if (!done) { 255 int err; 256 struct pci_device *rom_device = 257 xf86GetPciInfoForEntity(pInt->entityIndex); 258 259 err = pci_device_read_rom(rom_device, vbiosMem); 260 if (err) { 261 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Cannot read V_BIOS (5) %s\n", 262 strerror(err)); 263 goto error1; 264 } 265 } 266 } 267 268 pInt->BIOSseg = V_BIOS >> 4; 269 pInt->num = 0xe6; 270 LockLegacyVGA(pInt, &vga); 271 xf86ExecX86int10(pInt); 272 UnlockLegacyVGA(pInt, &vga); 273 #endif 274 free(options); 275 return pInt; 276 277 error1: 278 free(base); 279 UnmapVRam(pInt); 280 free(INTPriv(pInt)->alloc); 281 free(pInt->private); 282 error0: 283 free(pInt); 284 free(options); 285 286 return NULL; 287 } 288 289 static void 290 MapVRam(xf86Int10InfoPtr pInt) 291 { 292 int pagesize = getpagesize(); 293 int size = ((VRAM_SIZE + pagesize - 1) / pagesize) * pagesize; 294 295 pci_device_map_legacy(pInt->dev, V_RAM, size, PCI_DEV_MAP_FLAG_WRITABLE, 296 &(INTPriv(pInt)->vRam)); 297 pInt->io = pci_legacy_open_io(pInt->dev, 0, 64 * 1024); 298 } 299 300 static void 301 UnmapVRam(xf86Int10InfoPtr pInt) 302 { 303 int pagesize = getpagesize(); 304 int size = ((VRAM_SIZE + pagesize - 1) / pagesize) * pagesize; 305 306 pci_device_unmap_legacy(pInt->dev, INTPriv(pInt)->vRam, size); 307 pci_device_close_io(pInt->dev, pInt->io); 308 pInt->io = NULL; 309 } 310 311 Bool 312 MapCurrentInt10(xf86Int10InfoPtr pInt) 313 { 314 /* nothing to do here */ 315 return TRUE; 316 } 317 318 void 319 xf86FreeInt10(xf86Int10InfoPtr pInt) 320 { 321 if (!pInt) 322 return; 323 #if defined (_PC) 324 xf86Int10SaveRestoreBIOSVars(pInt, FALSE); 325 #endif 326 if (Int10Current == pInt) 327 Int10Current = NULL; 328 free(INTPriv(pInt)->base); 329 UnmapVRam(pInt); 330 free(INTPriv(pInt)->alloc); 331 free(pInt->private); 332 free(pInt); 333 } 334 335 void * 336 xf86Int10AllocPages(xf86Int10InfoPtr pInt, int num, int *off) 337 { 338 int pagesize = getpagesize(); 339 int num_pages = ALLOC_ENTRIES(pagesize); 340 int i, j; 341 342 for (i = 0; i < (num_pages - num); i++) { 343 if (INTPriv(pInt)->alloc[i] == 0) { 344 for (j = i; j < (num + i); j++) 345 if (INTPriv(pInt)->alloc[j] != 0) 346 break; 347 if (j == (num + i)) 348 break; 349 i += num; 350 } 351 } 352 if (i == (num_pages - num)) 353 return NULL; 354 355 for (j = i; j < (i + num); j++) 356 INTPriv(pInt)->alloc[j] = 1; 357 358 *off = (i + 1) * pagesize; 359 360 return (char *) INTPriv(pInt)->base + *off; 361 } 362 363 void 364 xf86Int10FreePages(xf86Int10InfoPtr pInt, void *pbase, int num) 365 { 366 int pagesize = getpagesize(); 367 int first = 368 (((char *) pbase - (char *) INTPriv(pInt)->base) / pagesize) - 1; 369 int i; 370 371 for (i = first; i < (first + num); i++) 372 INTPriv(pInt)->alloc[i] = 0; 373 } 374 375 #define OFF(addr) ((addr) & 0xffff) 376 #if defined _PC 377 #define HIGH_OFFSET (INTPriv(pInt)->highMemory) 378 #define HIGH_BASE V_BIOS 379 #else 380 #define HIGH_OFFSET SYS_BIOS 381 #define HIGH_BASE SYS_BIOS 382 #endif 383 #define SYS(addr) ((addr) >= HIGH_OFFSET) 384 #define V_ADDR(addr) \ 385 (SYS(addr) ? ((char*)INTPriv(pInt)->sysMem) + (addr - HIGH_BASE) \ 386 : (((char*)(INTPriv(pInt)->base) + addr))) 387 #define VRAM_ADDR(addr) (addr - V_RAM) 388 #define VRAM_BASE (INTPriv(pInt)->vRam) 389 390 #define VRAM(addr) ((addr >= V_RAM) && (addr < (V_RAM + VRAM_SIZE))) 391 #define V_ADDR_RB(addr) \ 392 ((VRAM(addr)) ? MMIO_IN8((uint8_t*)VRAM_BASE,VRAM_ADDR(addr)) \ 393 : *(uint8_t*) V_ADDR(addr)) 394 #define V_ADDR_RW(addr) \ 395 ((VRAM(addr)) ? MMIO_IN16((uint16_t*)VRAM_BASE,VRAM_ADDR(addr)) \ 396 : ldw_u((void *)V_ADDR(addr))) 397 #define V_ADDR_RL(addr) \ 398 ((VRAM(addr)) ? MMIO_IN32((uint32_t*)VRAM_BASE,VRAM_ADDR(addr)) \ 399 : ldl_u((void *)V_ADDR(addr))) 400 401 #define V_ADDR_WB(addr,val) \ 402 if(VRAM(addr)) \ 403 MMIO_OUT8((uint8_t*)VRAM_BASE,VRAM_ADDR(addr),val); \ 404 else \ 405 *(uint8_t*) V_ADDR(addr) = val; 406 #define V_ADDR_WW(addr,val) \ 407 if(VRAM(addr)) \ 408 MMIO_OUT16((uint16_t*)VRAM_BASE,VRAM_ADDR(addr),val); \ 409 else \ 410 stw_u((val),(void *)(V_ADDR(addr))); 411 412 #define V_ADDR_WL(addr,val) \ 413 if (VRAM(addr)) \ 414 MMIO_OUT32((uint32_t*)VRAM_BASE,VRAM_ADDR(addr),val); \ 415 else \ 416 stl_u(val,(void *)(V_ADDR(addr))); 417 418 static uint8_t 419 read_b(xf86Int10InfoPtr pInt, int addr) 420 { 421 return V_ADDR_RB(addr); 422 } 423 424 static uint16_t 425 read_w(xf86Int10InfoPtr pInt, int addr) 426 { 427 #if X_BYTE_ORDER == X_LITTLE_ENDIAN 428 if (OFF(addr + 1) > 0) 429 return V_ADDR_RW(addr); 430 #endif 431 return V_ADDR_RB(addr) | (V_ADDR_RB(addr + 1) << 8); 432 } 433 434 static uint32_t 435 read_l(xf86Int10InfoPtr pInt, int addr) 436 { 437 #if X_BYTE_ORDER == X_LITTLE_ENDIAN 438 if (OFF(addr + 3) > 2) 439 return V_ADDR_RL(addr); 440 #endif 441 return V_ADDR_RB(addr) | 442 (V_ADDR_RB(addr + 1) << 8) | 443 (V_ADDR_RB(addr + 2) << 16) | (V_ADDR_RB(addr + 3) << 24); 444 } 445 446 static void 447 write_b(xf86Int10InfoPtr pInt, int addr, uint8_t val) 448 { 449 V_ADDR_WB(addr, val); 450 } 451 452 static void 453 write_w(xf86Int10InfoPtr pInt, int addr, CARD16 val) 454 { 455 #if X_BYTE_ORDER == X_LITTLE_ENDIAN 456 if (OFF(addr + 1) > 0) { 457 V_ADDR_WW(addr, val); 458 } 459 #endif 460 V_ADDR_WB(addr, val); 461 V_ADDR_WB(addr + 1, val >> 8); 462 } 463 464 static void 465 write_l(xf86Int10InfoPtr pInt, int addr, uint32_t val) 466 { 467 #if X_BYTE_ORDER == X_LITTLE_ENDIAN 468 if (OFF(addr + 3) > 2) { 469 V_ADDR_WL(addr, val); 470 } 471 #endif 472 V_ADDR_WB(addr, val); 473 V_ADDR_WB(addr + 1, val >> 8); 474 V_ADDR_WB(addr + 2, val >> 16); 475 V_ADDR_WB(addr + 3, val >> 24); 476 } 477 478 void * 479 xf86int10Addr(xf86Int10InfoPtr pInt, uint32_t addr) 480 { 481 return V_ADDR(addr); 482 }