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 (unsigned long)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 149 pInt->mem = &genericMem; 150 pInt->private = (pointer)xnfcalloc(1, sizeof(genericInt10Priv)); 151 INTPriv(pInt)->alloc = (pointer)xnfcalloc(1, ALLOC_ENTRIES(getpagesize())); 152 pInt->scrnIndex = screen; 153 base = INTPriv(pInt)->base = xnfalloc(SYS_BIOS); 154 155 /* FIXME: Shouldn't this be a failure case? Leaving dev as NULL seems like 156 * FIXME: an error 157 */ 158 159 pInt->dev = xf86GetPciInfoForEntity(entityIndex); 160 161 /* 162 * we need to map video RAM MMIO as some chipsets map mmio 163 * registers into this range. 164 */ 165 MapVRam(pInt); 166#ifdef _PC 167 if (!sysMem) 168 sysMem = xf86MapVidMem(screen, VIDMEM_MMIO, V_BIOS, 169 BIOS_SIZE + SYS_BIOS - V_BIOS); 170 INTPriv(pInt)->sysMem = sysMem; 171 172 if (xf86ReadBIOS(0, 0, base, LOW_PAGE_SIZE) < 0) { 173 xf86DrvMsg(screen, X_ERROR, "Cannot read int vect\n"); 174 goto error1; 175 } 176 177 /* 178 * Retrieve everything between V_BIOS and SYS_BIOS as some system BIOSes 179 * have executable code there. Note that xf86ReadBIOS() can only read in 180 * 64kB at a time. 181 */ 182 memset((char *)base + V_BIOS, 0, SYS_BIOS - V_BIOS); 183#if 0 184 for (cs = V_BIOS; cs < SYS_BIOS; cs += V_BIOS_SIZE) 185 if (xf86ReadBIOS(cs, 0, (unsigned char *)base + cs, V_BIOS_SIZE) < 186 V_BIOS_SIZE) 187 xf86DrvMsg(screen, X_WARNING, 188 "Unable to retrieve all of segment 0x%06X.\n", cs); 189#endif 190 INTPriv(pInt)->highMemory = V_BIOS; 191 192 if (xf86IsEntityPrimary(entityIndex) && !(initPrimary(options))) { 193 if (!xf86int10GetBiosSegment(pInt, (unsigned char *)sysMem - V_BIOS)) 194 goto error1; 195 196 set_return_trap(pInt); 197 198 pInt->Flags = Flags & (SET_BIOS_SCRATCH | RESTORE_BIOS_SCRATCH); 199 if (! (pInt->Flags & SET_BIOS_SCRATCH)) 200 pInt->Flags &= ~RESTORE_BIOS_SCRATCH; 201 xf86Int10SaveRestoreBIOSVars(pInt, TRUE); 202 203 } else { 204 const BusType location_type = xf86int10GetBiosLocationType(pInt); 205 int bios_location = V_BIOS; 206 207 reset_int_vect(pInt); 208 set_return_trap(pInt); 209 210 switch (location_type) { 211 case BUS_PCI: { 212 int err; 213 struct pci_device *rom_device = 214 xf86GetPciInfoForEntity(pInt->entityIndex); 215 216 vbiosMem = (unsigned char *)base + bios_location; 217 err = pci_device_read_rom(rom_device, vbiosMem); 218 if (err) { 219 xf86DrvMsg(screen,X_ERROR,"Cannot read V_BIOS (3) %s\n", 220 strerror(err)); 221 goto error1; 222 } 223 INTPriv(pInt)->highMemory = GET_HIGH_BASE(rom_device->rom_size); 224 break; 225 } 226 default: 227 goto error1; 228 } 229 pInt->BIOSseg = V_BIOS >> 4; 230 pInt->num = 0xe6; 231 LockLegacyVGA(pInt, &vga); 232 xf86ExecX86int10(pInt); 233 UnlockLegacyVGA(pInt, &vga); 234 } 235#else 236 if (!sysMem) { 237 sysMem = xnfalloc(BIOS_SIZE); 238 setup_system_bios(sysMem); 239 } 240 INTPriv(pInt)->sysMem = sysMem; 241 setup_int_vect(pInt); 242 set_return_trap(pInt); 243 244 /* Retrieve the entire legacy video BIOS segment. This can be upto 245 * 128KiB. 246 */ 247 vbiosMem = (char *)base + V_BIOS; 248 memset(vbiosMem, 0, 2 * V_BIOS_SIZE); 249 if (read_legacy_video_BIOS(pInt->dev, vbiosMem) < V_BIOS_SIZE) { 250 xf86DrvMsg(screen, X_WARNING, 251 "Unable to retrieve all of segment 0x0C0000.\n"); 252 } 253 254 /* 255 * If this adapter is the primary, use its post-init BIOS (if we can find 256 * it). 257 */ 258 { 259 int bios_location = V_BIOS; 260 Bool done = FALSE; 261 vbiosMem = (unsigned char *)base + bios_location; 262 263 if (xf86IsEntityPrimary(entityIndex)) { 264 if (int10_check_bios(screen, bios_location >> 4, vbiosMem)) 265 done = TRUE; 266 else 267 xf86DrvMsg(screen,X_INFO, 268 "No legacy BIOS found -- trying PCI\n"); 269 } 270 271 if (!done) { 272 int err; 273 struct pci_device *rom_device = 274 xf86GetPciInfoForEntity(pInt->entityIndex); 275 276 err = pci_device_read_rom(rom_device, vbiosMem); 277 278 if (err) { 279 xf86DrvMsg(screen,X_ERROR,"Cannot read V_BIOS (5) %s\n", 280 strerror(err)); 281 goto error1; 282 } 283 if (!int10_check_bios(screen, bios_location >> 4, vbiosMem)) { 284 xf86Msg(X_INFO, "No BIOS found\n"); 285 goto error1; 286 } 287 } 288 } 289 290 pInt->BIOSseg = V_BIOS >> 4; 291 pInt->num = 0xe6; 292 LockLegacyVGA(pInt, &vga); 293 xf86ExecX86int10(pInt); 294 UnlockLegacyVGA(pInt, &vga); 295#endif 296 free(options); 297 return pInt; 298 299 error1: 300 free(base); 301 UnmapVRam(pInt); 302 free(INTPriv(pInt)->alloc); 303 free(pInt->private); 304 error0: 305 free(pInt); 306 free(options); 307 308 return NULL; 309} 310 311static void 312MapVRam(xf86Int10InfoPtr pInt) 313{ 314 int pagesize = getpagesize(); 315 int size = ((VRAM_SIZE + pagesize - 1) / pagesize) * pagesize; 316 317 INTPriv(pInt)->vRam = xf86MapDomainMemory(pInt->scrnIndex, VIDMEM_MMIO, 318 pInt->dev, V_RAM, size); 319 320 pInt->ioBase = xf86Screens[pInt->scrnIndex]->domainIOBase; 321} 322 323static void 324UnmapVRam(xf86Int10InfoPtr pInt) 325{ 326 int screen = pInt->scrnIndex; 327 int pagesize = getpagesize(); 328 int size = ((VRAM_SIZE + pagesize - 1)/pagesize) * pagesize; 329 330 xf86UnMapVidMem(screen, INTPriv(pInt)->vRam, size); 331} 332 333Bool 334MapCurrentInt10(xf86Int10InfoPtr pInt) 335{ 336 /* nothing to do here */ 337 return TRUE; 338} 339 340void 341xf86FreeInt10(xf86Int10InfoPtr pInt) 342{ 343 if (!pInt) 344 return; 345#if defined (_PC) 346 xf86Int10SaveRestoreBIOSVars(pInt, FALSE); 347#endif 348 if (Int10Current == pInt) 349 Int10Current = NULL; 350 free(INTPriv(pInt)->base); 351 UnmapVRam(pInt); 352 free(INTPriv(pInt)->alloc); 353 free(pInt->private); 354 free(pInt); 355} 356 357void * 358xf86Int10AllocPages(xf86Int10InfoPtr pInt, int num, int *off) 359{ 360 int pagesize = getpagesize(); 361 int num_pages = ALLOC_ENTRIES(pagesize); 362 int i,j; 363 364 for (i = 0; i < (num_pages - num); i++) { 365 if (INTPriv(pInt)->alloc[i] == 0) { 366 for (j = i; j < (num + i); j++) 367 if (INTPriv(pInt)->alloc[j] != 0) 368 break; 369 if (j == (num + i)) 370 break; 371 i += num; 372 } 373 } 374 if (i == (num_pages - num)) 375 return NULL; 376 377 for (j = i; j < (i + num); j++) 378 INTPriv(pInt)->alloc[j] = 1; 379 380 *off = (i + 1) * pagesize; 381 382 return (char *)INTPriv(pInt)->base + *off; 383} 384 385void 386xf86Int10FreePages(xf86Int10InfoPtr pInt, void *pbase, int num) 387{ 388 int pagesize = getpagesize(); 389 int first = (((char *)pbase - (char *)INTPriv(pInt)->base) / pagesize) - 1; 390 int i; 391 392 for (i = first; i < (first + num); i++) 393 INTPriv(pInt)->alloc[i] = 0; 394} 395 396#define OFF(addr) ((addr) & 0xffff) 397#if defined _PC 398# define HIGH_OFFSET (INTPriv(pInt)->highMemory) 399# define HIGH_BASE V_BIOS 400#else 401# define HIGH_OFFSET SYS_BIOS 402# define HIGH_BASE SYS_BIOS 403#endif 404# define SYS(addr) ((addr) >= HIGH_OFFSET) 405#define V_ADDR(addr) \ 406 (SYS(addr) ? ((char*)INTPriv(pInt)->sysMem) + (addr - HIGH_BASE) \ 407 : (((char*)(INTPriv(pInt)->base) + addr))) 408#define VRAM_ADDR(addr) (addr - V_RAM) 409#define VRAM_BASE (INTPriv(pInt)->vRam) 410 411#define VRAM(addr) ((addr >= V_RAM) && (addr < (V_RAM + VRAM_SIZE))) 412#define V_ADDR_RB(addr) \ 413 (VRAM(addr)) ? MMIO_IN8((CARD8*)VRAM_BASE,VRAM_ADDR(addr)) \ 414 : *(CARD8*) V_ADDR(addr) 415#define V_ADDR_RW(addr) \ 416 (VRAM(addr)) ? MMIO_IN16((CARD16*)VRAM_BASE,VRAM_ADDR(addr)) \ 417 : ldw_u((pointer)V_ADDR(addr)) 418#define V_ADDR_RL(addr) \ 419 (VRAM(addr)) ? MMIO_IN32((CARD32*)VRAM_BASE,VRAM_ADDR(addr)) \ 420 : ldl_u((pointer)V_ADDR(addr)) 421 422#define V_ADDR_WB(addr,val) \ 423 if(VRAM(addr)) \ 424 MMIO_OUT8((CARD8*)VRAM_BASE,VRAM_ADDR(addr),val); \ 425 else \ 426 *(CARD8*) V_ADDR(addr) = val; 427#define V_ADDR_WW(addr,val) \ 428 if(VRAM(addr)) \ 429 MMIO_OUT16((CARD16*)VRAM_BASE,VRAM_ADDR(addr),val); \ 430 else \ 431 stw_u((val),(pointer)(V_ADDR(addr))); 432 433#define V_ADDR_WL(addr,val) \ 434 if (VRAM(addr)) \ 435 MMIO_OUT32((CARD32*)VRAM_BASE,VRAM_ADDR(addr),val); \ 436 else \ 437 stl_u(val,(pointer)(V_ADDR(addr))); 438 439static CARD8 440read_b(xf86Int10InfoPtr pInt, int addr) 441{ 442 return V_ADDR_RB(addr); 443} 444 445static CARD16 446read_w(xf86Int10InfoPtr pInt, int addr) 447{ 448#if X_BYTE_ORDER == X_LITTLE_ENDIAN 449 if (OFF(addr + 1) > 0) 450 return V_ADDR_RW(addr); 451#endif 452 return V_ADDR_RB(addr) | (V_ADDR_RB(addr + 1) << 8); 453} 454 455static CARD32 456read_l(xf86Int10InfoPtr pInt, int addr) 457{ 458#if X_BYTE_ORDER == X_LITTLE_ENDIAN 459 if (OFF(addr + 3) > 2) 460 return V_ADDR_RL(addr); 461#endif 462 return V_ADDR_RB(addr) | 463 (V_ADDR_RB(addr + 1) << 8) | 464 (V_ADDR_RB(addr + 2) << 16) | 465 (V_ADDR_RB(addr + 3) << 24); 466} 467 468static void 469write_b(xf86Int10InfoPtr pInt, int addr, CARD8 val) 470{ 471 V_ADDR_WB(addr,val); 472} 473 474static void 475write_w(xf86Int10InfoPtr pInt, int addr, CARD16 val) 476{ 477#if X_BYTE_ORDER == X_LITTLE_ENDIAN 478 if (OFF(addr + 1) > 0) 479 { V_ADDR_WW(addr, val); } 480#endif 481 V_ADDR_WB(addr, val); 482 V_ADDR_WB(addr + 1, val >> 8); 483} 484 485static void 486write_l(xf86Int10InfoPtr pInt, int addr, CARD32 val) 487{ 488#if X_BYTE_ORDER == X_LITTLE_ENDIAN 489 if (OFF(addr + 3) > 2) 490 { V_ADDR_WL(addr, val); } 491#endif 492 V_ADDR_WB(addr, val); 493 V_ADDR_WB(addr + 1, val >> 8); 494 V_ADDR_WB(addr + 2, val >> 16); 495 V_ADDR_WB(addr + 3, val >> 24); 496} 497 498pointer 499xf86int10Addr(xf86Int10InfoPtr pInt, CARD32 addr) 500{ 501 return V_ADDR(addr); 502} 503