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