generic.c revision 5a112b11
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 25static __inline__ uint32_t 26ldl_u(uint32_t * p) 27{ 28 uint32_t ret; 29 30 memmove(&ret, p, sizeof(*p)); 31 return ret; 32} 33 34static __inline__ uint16_t 35ldw_u(uint16_t * p) 36{ 37 uint16_t ret; 38 39 memmove(&ret, p, sizeof(*p)); 40 return ret; 41} 42 43static __inline__ void 44stl_u(uint32_t val, uint32_t * p) 45{ 46 uint32_t tmp = val; 47 48 memmove(p, &tmp, sizeof(*p)); 49} 50 51static __inline__ void 52stw_u(uint16_t val, uint16_t * p) 53{ 54 uint16_t tmp = val; 55 56 memmove(p, &tmp, sizeof(*p)); 57} 58 59static uint8_t read_b(xf86Int10InfoPtr pInt, int addr); 60static uint16_t read_w(xf86Int10InfoPtr pInt, int addr); 61static uint32_t read_l(xf86Int10InfoPtr pInt, int addr); 62static void write_b(xf86Int10InfoPtr pInt, int addr, uint8_t val); 63static void write_w(xf86Int10InfoPtr pInt, int addr, uint16_t val); 64static 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 71typedef 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 83int10MemRec genericMem = { 84 read_b, 85 read_w, 86 read_l, 87 write_b, 88 write_w, 89 write_l 90}; 91 92static void MapVRam(xf86Int10InfoPtr pInt); 93static 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 100static void *sysMem = NULL; 101 102static Bool 103readIntVec(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 116xf86Int10InfoPtr 117xf86ExtendedInitInt10(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#if 0 // XXXMRG was there in xorg-server 1.10 266 if (!int10_check_bios(screen, bios_location >> 4, vbiosMem)) { 267 xf86Msg(X_INFO, "No BIOS found\n"); 268 goto error1; 269 } 270#endif 271 } 272 } 273 274 pInt->BIOSseg = V_BIOS >> 4; 275 pInt->num = 0xe6; 276 LockLegacyVGA(pInt, &vga); 277 xf86ExecX86int10(pInt); 278 UnlockLegacyVGA(pInt, &vga); 279#endif 280 free(options); 281 return pInt; 282 283 error1: 284 free(base); 285 UnmapVRam(pInt); 286 free(INTPriv(pInt)->alloc); 287 free(pInt->private); 288 error0: 289 free(pInt); 290 free(options); 291 292 return NULL; 293} 294 295static void 296MapVRam(xf86Int10InfoPtr pInt) 297{ 298 int pagesize = getpagesize(); 299 int size = ((VRAM_SIZE + pagesize - 1) / pagesize) * pagesize; 300 301 pci_device_map_legacy(pInt->dev, V_RAM, size, PCI_DEV_MAP_FLAG_WRITABLE, 302 &(INTPriv(pInt)->vRam)); 303 pInt->io = pci_legacy_open_io(pInt->dev, 0, 64 * 1024); 304} 305 306static void 307UnmapVRam(xf86Int10InfoPtr pInt) 308{ 309 int pagesize = getpagesize(); 310 int size = ((VRAM_SIZE + pagesize - 1) / pagesize) * pagesize; 311 312 pci_device_unmap_legacy(pInt->dev, INTPriv(pInt)->vRam, size); 313 pci_device_close_io(pInt->dev, pInt->io); 314 pInt->io = NULL; 315} 316 317Bool 318MapCurrentInt10(xf86Int10InfoPtr pInt) 319{ 320 /* nothing to do here */ 321 return TRUE; 322} 323 324void 325xf86FreeInt10(xf86Int10InfoPtr pInt) 326{ 327 if (!pInt) 328 return; 329#if defined (_PC) 330 xf86Int10SaveRestoreBIOSVars(pInt, FALSE); 331#endif 332 if (Int10Current == pInt) 333 Int10Current = NULL; 334 free(INTPriv(pInt)->base); 335 UnmapVRam(pInt); 336 free(INTPriv(pInt)->alloc); 337 free(pInt->private); 338 free(pInt); 339} 340 341void * 342xf86Int10AllocPages(xf86Int10InfoPtr pInt, int num, int *off) 343{ 344 int pagesize = getpagesize(); 345 int num_pages = ALLOC_ENTRIES(pagesize); 346 int i, j; 347 348 for (i = 0; i < (num_pages - num); i++) { 349 if (INTPriv(pInt)->alloc[i] == 0) { 350 for (j = i; j < (num + i); j++) 351 if (INTPriv(pInt)->alloc[j] != 0) 352 break; 353 if (j == (num + i)) 354 break; 355 i += num; 356 } 357 } 358 if (i == (num_pages - num)) 359 return NULL; 360 361 for (j = i; j < (i + num); j++) 362 INTPriv(pInt)->alloc[j] = 1; 363 364 *off = (i + 1) * pagesize; 365 366 return (char *) INTPriv(pInt)->base + *off; 367} 368 369void 370xf86Int10FreePages(xf86Int10InfoPtr pInt, void *pbase, int num) 371{ 372 int pagesize = getpagesize(); 373 int first = 374 (((char *) pbase - (char *) INTPriv(pInt)->base) / pagesize) - 1; 375 int i; 376 377 for (i = first; i < (first + num); i++) 378 INTPriv(pInt)->alloc[i] = 0; 379} 380 381#define OFF(addr) ((addr) & 0xffff) 382#if defined _PC 383#define HIGH_OFFSET (INTPriv(pInt)->highMemory) 384#define HIGH_BASE V_BIOS 385#else 386#define HIGH_OFFSET SYS_BIOS 387#define HIGH_BASE SYS_BIOS 388#endif 389#define SYS(addr) ((addr) >= HIGH_OFFSET) 390#define V_ADDR(addr) \ 391 (SYS(addr) ? ((char*)INTPriv(pInt)->sysMem) + (addr - HIGH_BASE) \ 392 : (((char*)(INTPriv(pInt)->base) + addr))) 393#define VRAM_ADDR(addr) (addr - V_RAM) 394#define VRAM_BASE (INTPriv(pInt)->vRam) 395 396#define VRAM(addr) ((addr >= V_RAM) && (addr < (V_RAM + VRAM_SIZE))) 397#define V_ADDR_RB(addr) \ 398 ((VRAM(addr)) ? MMIO_IN8((uint8_t*)VRAM_BASE,VRAM_ADDR(addr)) \ 399 : *(uint8_t*) V_ADDR(addr)) 400#define V_ADDR_RW(addr) \ 401 ((VRAM(addr)) ? MMIO_IN16((uint16_t*)VRAM_BASE,VRAM_ADDR(addr)) \ 402 : ldw_u((void *)V_ADDR(addr))) 403#define V_ADDR_RL(addr) \ 404 ((VRAM(addr)) ? MMIO_IN32((uint32_t*)VRAM_BASE,VRAM_ADDR(addr)) \ 405 : ldl_u((void *)V_ADDR(addr))) 406 407#define V_ADDR_WB(addr,val) \ 408 if(VRAM(addr)) \ 409 MMIO_OUT8((uint8_t*)VRAM_BASE,VRAM_ADDR(addr),val); \ 410 else \ 411 *(uint8_t*) V_ADDR(addr) = val; 412#define V_ADDR_WW(addr,val) \ 413 if(VRAM(addr)) \ 414 MMIO_OUT16((uint16_t*)VRAM_BASE,VRAM_ADDR(addr),val); \ 415 else \ 416 stw_u((val),(void *)(V_ADDR(addr))); 417 418#define V_ADDR_WL(addr,val) \ 419 if (VRAM(addr)) \ 420 MMIO_OUT32((uint32_t*)VRAM_BASE,VRAM_ADDR(addr),val); \ 421 else \ 422 stl_u(val,(void *)(V_ADDR(addr))); 423 424static uint8_t 425read_b(xf86Int10InfoPtr pInt, int addr) 426{ 427 return V_ADDR_RB(addr); 428} 429 430static uint16_t 431read_w(xf86Int10InfoPtr pInt, int addr) 432{ 433#if X_BYTE_ORDER == X_LITTLE_ENDIAN 434 if (OFF(addr + 1) > 0) 435 return V_ADDR_RW(addr); 436#endif 437 return V_ADDR_RB(addr) | (V_ADDR_RB(addr + 1) << 8); 438} 439 440static uint32_t 441read_l(xf86Int10InfoPtr pInt, int addr) 442{ 443#if X_BYTE_ORDER == X_LITTLE_ENDIAN 444 if (OFF(addr + 3) > 2) 445 return V_ADDR_RL(addr); 446#endif 447 return V_ADDR_RB(addr) | 448 (V_ADDR_RB(addr + 1) << 8) | 449 (V_ADDR_RB(addr + 2) << 16) | (V_ADDR_RB(addr + 3) << 24); 450} 451 452static void 453write_b(xf86Int10InfoPtr pInt, int addr, uint8_t val) 454{ 455 V_ADDR_WB(addr, val); 456} 457 458static void 459write_w(xf86Int10InfoPtr pInt, int addr, CARD16 val) 460{ 461#if X_BYTE_ORDER == X_LITTLE_ENDIAN 462 if (OFF(addr + 1) > 0) { 463 V_ADDR_WW(addr, val); 464 } 465#endif 466 V_ADDR_WB(addr, val); 467 V_ADDR_WB(addr + 1, val >> 8); 468} 469 470static void 471write_l(xf86Int10InfoPtr pInt, int addr, uint32_t val) 472{ 473#if X_BYTE_ORDER == X_LITTLE_ENDIAN 474 if (OFF(addr + 3) > 2) { 475 V_ADDR_WL(addr, val); 476 } 477#endif 478 V_ADDR_WB(addr, val); 479 V_ADDR_WB(addr + 1, val >> 8); 480 V_ADDR_WB(addr + 2, val >> 16); 481 V_ADDR_WB(addr + 3, val >> 24); 482} 483 484void * 485xf86int10Addr(xf86Int10InfoPtr pInt, uint32_t addr) 486{ 487 return V_ADDR(addr); 488} 489