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