1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * VGA BIOS initialization File: VGAINIT.C 5 * 6 * This module interfaces with the X86 emulator borrowed from 7 * XFree86 to do VGA initialization. 8 * 9 * WARNING: This code is SB1250-specific for now. It's not 10 * hard to change, but then again, aren't we interested in the 1250? 11 * 12 * Author: Mitch Lichtenberg 13 * 14 ********************************************************************* 15 * 16 * Copyright 2000,2001,2002,2003 17 * Broadcom Corporation. All rights reserved. 18 * 19 * This software is furnished under license and may be used and 20 * copied only in accordance with the following terms and 21 * conditions. Subject to these conditions, you may download, 22 * copy, install, use, modify and distribute modified or unmodified 23 * copies of this software in source and/or binary form. No title 24 * or ownership is transferred hereby. 25 * 26 * 1) Any source code used, modified or distributed must reproduce 27 * and retain this copyright notice and list of conditions 28 * as they appear in the source file. 29 * 30 * 2) No right is granted to use any trade name, trademark, or 31 * logo of Broadcom Corporation. The "Broadcom Corporation" 32 * name may not be used to endorse or promote products derived 33 * from this software without the prior written permission of 34 * Broadcom Corporation. 35 * 36 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR 37 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED 38 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 39 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 40 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 41 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, 42 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 43 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 44 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 45 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 46 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 47 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 48 * THE POSSIBILITY OF SUCH DAMAGE. 49 ********************************************************************* */ 50 51#include "cfe.h" 52#include "sbmips.h" 53#include "pcireg.h" 54#include "pcivar.h" 55#include "pci_internal.h" 56#include "vga.h" 57#include "pcibios.h" 58#include "lib_physio.h" 59#include "vga_subr.h" 60#include "x86mem.h" 61#include "x86emu.h" 62#include "env_subr.h" 63 64 65/* ********************************************************************* 66 * Configuration 67 ********************************************************************* */ 68 69#define BYTESONLY 0 /* Always write registers as bytes */ 70#define VGAINIT_NOISY 0 /* lots of debug output */ 71 72#define SB1250_PASS2_WORKAROUNDS /* Work around BCM1250 pass2 issues */ 73 74/* ********************************************************************* 75 * ISA port macros - currently SB1250-specific 76 ********************************************************************* */ 77 78#define INB(x) inb(x) 79#define INW(x) inw(x) 80#define INL(x) inl(x) 81#define OUTB(x,y) outb(x,y) 82#define OUTW(x,y) outw(x,y) 83#define OUTL(x,y) outl(x,y) 84 85/* ********************************************************************* 86 * ISA memory macros - currently SB1250-specific 87 ********************************************************************* */ 88 89typedef uintptr_t vm_offset_t; 90 91#if defined(_P5064_) || defined(_P6064_) 92 #define PCI_MEM_SPACE 0x10000000 /* 128MB: s/w configurable */ 93 #define __ISAaddr(addr) ((physaddr_t)(PCI_MEM_SPACE+(addr))) 94#else 95 #define __ISAaddr(addr) ((physaddr_t)0x40000000+(addr)) 96#endif 97 98#define __ISAreadbyte(addr) phys_read8(__ISAaddr(addr)) 99#define __ISAreadword(addr) phys_read16(__ISAaddr(addr)) 100#define __ISAreaddword(addr) phys_read32(__ISAaddr(addr)) 101#define __ISAwritebyte(addr,data) phys_write8(__ISAaddr(addr),(data)) 102#define __ISAwriteword(addr,data) phys_write16(__ISAaddr(addr),(data)) 103#define __ISAwritedword(addr,data) phys_write32(__ISAaddr(addr),(data)) 104 105/* ********************************************************************* 106 * Other macros 107 ********************************************************************* */ 108 109#define OFFSET(addr) (((addr) >> 0) & 0xffff) 110#define SEGMENT(addr) (((addr) >> 4) & 0xf000) 111 112#define BSWAP_SHORT(s) ((((s) >> 8) & 0xFF) | (((s)&0xFF) << 8)) 113#define BSWAP_LONG(s) ((((s) & 0xFF000000) >> 24) | \ 114 (((s) & 0x00FF0000) >> 8) | \ 115 (((s) & 0x0000FF00) << 8) | \ 116 (((s) & 0x000000FF) << 24)) 117 118 119#ifdef __MIPSEB 120#define CPU_TO_LE16(s) BSWAP_SHORT(s) 121#define CPU_TO_LE32(s) BSWAP_LONG(s) 122#define LE16_TO_CPU(s) BSWAP_SHORT(s) 123#define LE32_TO_CPU(s) BSWAP_LONG(s) 124#else 125#define CPU_TO_LE16(s) (s) 126#define CPU_TO_LE32(s) (s) 127#define LE16_TO_CPU(s) (s) 128#define LE32_TO_CPU(s) (s) 129#endif 130 131 132/* ********************************************************************* 133 * Prototypes 134 ********************************************************************* */ 135 136int vga_biosinit(void); 137int vga_probe(void); 138extern void ui_restart(int); 139void vgaraw_dump(char *tail); 140int x86emutest(void); 141 142/* ********************************************************************* 143 * Globals 144 ********************************************************************* */ 145 146static vga_term_t vga; 147static x86mem_t x86mem; 148 149#define BIOSRAMLOC (0xC0000) 150#define STACKSIZE 4096 151#define IRETOFFSET 12 152static uint8_t x86initcode[] = { 153#if (VGA_TEXTMODE_ROWS == 60) 154 0xB8,0x02,0x4F, /* mov ax,042F */ 155 0xBB,0x08,0x01, /* mov bx,0108 */ /* VESA 80x60 */ 156#else 157 0xB8,0x03,0x00, /* mov AX,0003 */ /* 80x25 mode */ 158#endif 159 160 0xCD,0x10, /* int 10 */ 161 0xB8,0x34,0x12, /* mov ax,1234 */ 162 0xBB,0x78,0x56, /* mov bx,5678 */ 163 0xCC, /* int 3 */ 164 0xCF}; /* IRET */ 165 166static uint8_t x86testcode[] = { 167 0x90,0x90,0x90,0x90,0x90, /* nop, nop, nop, nop, nop */ 168 0xeb,0x09, /* jmp 10 */ 169 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90, /* 9 nops */ 170 0xb8,0x34,0x12, /* mov ax,1234 */ 171 0xbb,0x78,0x56, /* mov bx,5678 */ 172 0xcc, /* int 3 */ 173 0xcf}; /* iret */ 174 175static uint32_t __ISAreadmem(x86mem_t *mem,uint32_t addr,int size) 176{ 177 unsigned long val; 178 179 switch (size) { 180 case M_BYTE: 181 val = __ISAreadbyte(addr); 182 break; 183 case M_WORD: 184 if (BYTESONLY || (addr & 0x1)) { 185 val = (__ISAreadbyte(addr) | (__ISAreadbyte(addr + 1) << 8)); 186 } 187 else { 188 val = __ISAreadword(addr); 189 val = LE16_TO_CPU(val); 190 } 191 break; 192 case M_DWORD: 193 if (BYTESONLY || (addr & 0x3)) { 194 val = (__ISAreadbyte(addr) | 195 (__ISAreadbyte(addr + 1) << 8) | 196 (__ISAreadbyte(addr + 2) << 16) | 197 (__ISAreadbyte(addr + 3) << 24)); 198 } 199 else { 200 val = __ISAreaddword(addr); 201 val = LE32_TO_CPU(val); 202 } 203 break; 204 default: 205 val = 0; 206 } 207 208 return val; 209} 210 211 212 213static void __ISAwritemem(x86mem_t *mem,uint32_t addr,uint32_t data,int size) 214{ 215 switch (size) { 216 case M_BYTE: 217 __ISAwritebyte(addr, data); 218 break; 219 220 case M_WORD: 221 if (BYTESONLY || (addr & 0x1)) { 222 __ISAwritebyte(addr, data >> 0); 223 __ISAwritebyte(addr + 1, data >> 8); 224 } 225 else { 226 data = CPU_TO_LE16(data); 227 __ISAwriteword(addr, data); 228 } 229 break; 230 231 case M_DWORD: 232 if (BYTESONLY || (addr & 0x3)) { 233 __ISAwritebyte(addr, data >> 0); 234 __ISAwritebyte(addr + 1, data >> 8); 235 __ISAwritebyte(addr + 2, data >> 16); 236 __ISAwritebyte(addr + 3, data >> 24); 237 } 238 else { 239 data = CPU_TO_LE32(data); 240 __ISAwritedword(addr, data); 241 } 242 break; 243 } 244} 245 246 247static u8 __x86emu_rdb(u32 addr) 248{ 249#if VGAINIT_NOISY 250 if ((addr < 0x400) || (addr > 0x100000)) { 251 xprintf("Read %08X (int %02X) ",addr,addr/4); 252 printf("CS:IP = %04X:%04X\n",M.x86.R_CS,M.x86.R_IP); 253 } 254#endif 255 return x86mem_readb(&x86mem,addr); 256} 257 258 259static u16 __x86emu_rdw(u32 addr) 260{ 261#if VGAINIT_NOISY 262 if ((addr < 0x400) || (addr > 0x100000)) { 263 xprintf("Read %08X (int %02X) ",addr,addr/4); 264 printf("CS:IP = %04X:%04X\n",M.x86.R_CS,M.x86.R_IP); 265 } 266#endif 267 return x86mem_readw(&x86mem,addr); 268} 269 270 271static u32 __x86emu_rdl(u32 addr) 272{ 273#if VGAINIT_NOISY 274 if ((addr < 0x400) || (addr > 0x100000)) { 275 xprintf("Read %08X (int %02X) ",addr,addr/4); 276 printf("CS:IP = %04X:%04X\n",M.x86.R_CS,M.x86.R_IP); 277 } 278#endif 279 return x86mem_readl(&x86mem,addr); 280} 281 282 283static void __x86emu_wrb(u32 addr, u8 val) 284{ 285#if VGAINIT_NOISY 286 if ((addr < 0x400) || (addr > 0x100000)) { 287 xprintf("Write %08X (int %02X) ",addr,addr/4); 288 printf("CS:IP = %04X:%04X\n",M.x86.R_CS,M.x86.R_IP); 289 } 290#endif 291 x86mem_writeb(&x86mem,addr,val); 292} 293 294 295static void __x86emu_wrw(u32 addr, u16 val) 296{ 297#if VGAINIT_NOISY 298 if ((addr < 0x400) || (addr > 0x100000)) { 299 xprintf("Write %08X %04X (int %02X) ",addr,val,addr/4); 300 printf("CS:IP = %04X:%04X\n",M.x86.R_CS,M.x86.R_IP); 301 } 302#endif 303 x86mem_writew(&x86mem,addr,val); 304} 305 306 307static void __x86emu_wrl(u32 addr, u32 val) 308{ 309#if VGAINIT_NOISY 310 if ((addr < 0x400) || (addr > 0x100000)) { 311 xprintf("Write %08X (int %02X) ",addr,addr/4); 312 printf("CS:IP = %04X:%04X\n",M.x86.R_CS,M.x86.R_IP); 313 } 314#endif 315 x86mem_writel(&x86mem,addr,val); 316} 317 318 319#define TS_COMMAND 0 320#define TS_DATA1 1 321#define TS_DATA2 2 322static uint16_t timerCount = 0; 323static int timerState = TS_COMMAND; 324static u8 __x86emu_inb(X86EMU_pioAddr port) 325{ 326 u8 val; 327 328 /* 329 * Emulate just enough functionality of the 330 * timer chip to fool the Trident BIOS 331 */ 332 if (port == 0x40) { 333 timerCount++; 334 switch (timerState) { 335 case TS_COMMAND: 336 return 0; 337 case TS_DATA1: 338 timerState = TS_DATA1; 339 return timerCount & 0xFF; 340 case TS_DATA2: 341 timerState = TS_COMMAND; 342 return (timerCount >> 8) & 0xFF; 343 } 344 } 345 346#ifdef SB1250_PASS2_WORKAROUNDS 347 if ((port < 0x3BC) || (port > 0x3DF)) { 348 return 0; 349 } 350#endif 351 352 val = INB(port); 353 354#if VGAINIT_NOISY 355 /*if (port < 0x100)*/ xprintf("INB %08X %02X\n",port,val); 356 if (console_status()) ui_restart(0); 357#endif 358 359 360 return val; 361} 362 363 364static u16 __x86emu_inw(X86EMU_pioAddr port) 365{ 366 u16 val; 367 368#ifdef SB1250_PASS2_WORKAROUNDS 369 if ((port < 0x3BC) || (port > 0x3DF)) { 370 return 0; 371 } 372#endif 373 374 val = INW(port); 375 376 val = LE16_TO_CPU(val); 377 378#if VGAINIT_NOISY 379 /*if (port < 0x100)*/ xprintf("INW %08X %04X\n",port,val); 380#endif 381 382 return val; 383} 384 385 386static u32 __x86emu_inl(X86EMU_pioAddr port) 387{ 388 u32 val; 389 390#ifdef SB1250_PASS2_WORKAROUNDS 391 if ((port < 0x3BC) || (port > 0x3DF)) { 392 return 0; 393 } 394#endif 395 396 val = INL(port); 397 398 val = LE32_TO_CPU(val); 399 400#if VGAINIT_NOISY 401 /*if (port < 0x100)*/ xprintf("INL %08X %08X\n",port,val); 402#endif 403 404 405 return val; 406} 407 408 409static void __x86emu_outb(X86EMU_pioAddr port, u8 val) 410{ 411 /* 412 * Emulate just enough functionality of the timer 413 * chip to fool the Trident BIOS 414 */ 415 if (port == 0x43) { 416 timerCount++; 417 timerState = TS_DATA1; 418 return; 419 } 420 421#if VGAINIT_NOISY 422 /*if (port < 0x100)*/ xprintf("OUTB %08X %08X\n",port,val); 423#endif 424 425#ifdef SB1250_PASS2_WORKAROUNDS 426 if ((port < 0x3BC) || (port > 0x3DF)) { 427 return; 428 } 429#endif 430 431 OUTB(port,val); 432} 433 434 435static void __x86emu_outw(X86EMU_pioAddr port, u16 val) 436{ 437 val = CPU_TO_LE16(val); 438 439#if VGAINIT_NOISY 440 /*if (port < 0x100)*/ xprintf("OUTW %08X %04X ",port,val); 441 printf("CS:IP = %04X:%04X\n",M.x86.R_CS,M.x86.R_IP); 442#endif 443 444#ifdef SB1250_PASS2_WORKAROUNDS 445 if ((port < 0x3BC) || (port > 0x3DF)) { 446 return; 447 } 448#endif 449 450 OUTW(port,val); 451} 452 453 454static void __x86emu_outl(X86EMU_pioAddr port, u32 val) 455{ 456 if (port == 0x2D) return; 457 458 val = CPU_TO_LE32(val); 459 460#if VGAINIT_NOISY 461 /*if (port < 0x100)*/ xprintf("OUTL %08X %08X ",port,val); 462 printf("CS:IP = %04X:%04X\n",M.x86.R_CS,M.x86.R_IP); 463#endif 464 465#ifdef SB1250_PASS2_WORKAROUNDS 466 if ((port < 0x3BC) || (port > 0x3DF)) { 467 return; 468 } 469#endif 470 471 472 OUTL(port,val); 473} 474 475 476static void regs2tag(pcitag_t *tag) 477{ 478 pcitag_t mytag; 479 int bus,device,function; 480 481 bus = M.x86.R_BH; 482 device = M.x86.R_BL >> 3; 483 function = M.x86.R_BL & 0x07; 484 485 mytag = pci_make_tag(0,bus,device,function); 486 487 *tag = mytag; 488} 489 490static void __SIMint10(int intno) 491{ 492#if VGAINIT_NOISY 493 xprintf("Int10: BIOS function AX=%04X\n",M.x86.R_AX); 494#endif 495 496 /* 497 * The only BIOS function that VGAs appear to 498 * depend on in the real BIOS is the one 499 * that enables/disables video memory. 500 */ 501 502 if ((M.x86.R_AH == 0x12) && (M.x86.R_BL == 0x32)) { 503 if (M.x86.R_AL == 0) { 504 /* enable video memory */ 505 __x86emu_outb(VGA_MISCOUTPUT_W, __x86emu_inb(VGA_MISCOUTPUT_R) | 0x02); 506 return; 507 } 508 else if (M.x86.R_AL == 1) { 509 /* disable video memory */ 510 __x86emu_outb(VGA_MISCOUTPUT_W, __x86emu_inb(VGA_MISCOUTPUT_R) & ~0x02); 511 return; 512 } 513 else { 514 xprintf("Int10 unknown function AX=%04X\n", 515 M.x86.R_AX); 516 } 517 } 518 else { 519 520 /* Otherwise, pass the int10 on to the ROM */ 521 522 X86EMU_prepareForInt(0x10); 523 } 524} 525 526 527static void __SIMint3(int intno) 528{ 529#if VGAINIT_NOISY 530 xprintf("Int3: Breakpoint reached.\n"); 531#endif 532 HALT_SYS(); 533} 534 535 536static void __SIMintunk(int intno) 537{ 538#if VGAINIT_NOISY 539 xprintf("Int%02X: Unhandled interrupt!\n",intno); 540#endif 541 HALT_SYS(); 542} 543 544static void __SIMint42(int intno) 545{ 546#if VGAINIT_NOISY 547 xprintf("Int42: Function AX=%04X\n",M.x86.R_AX); 548#endif 549 switch (M.x86.R_AH) { 550 case 0: 551 vga_reset(&vga); 552 break; 553 default: 554#if VGAINIT_NOISY 555 xprintf("Int42: Unknown INT42 command: %x\n",M.x86.R_AH); 556#endif 557 break; 558 } 559} 560 561 562static void __SIMint6D(int intno) 563{ 564 int reflect = 1; 565 566#if VGAINIT_NOISY 567 xprintf("Int6D: Function AX=%04X\n",M.x86.R_AX); 568#endif 569 570 switch (M.x86.R_AH) { 571 case 0: 572 break; 573 case 0x13: 574 if (M.x86.R_AL == 1) { 575 unsigned long addr; 576 unsigned long count; 577 uint8_t ch; 578 579 addr = (M.x86.R_ES << 4) + M.x86.R_BP; 580 count = M.x86.R_CX; 581 582 while (count) { 583 ch = __x86emu_rdb(addr); 584 vga_writechar(&vga,ch,M.x86.R_BL); 585 addr++; 586 count--; 587 } 588 reflect = 0; 589 } 590 break; 591 default: 592#if VGAINIT_NOISY 593 xprintf("Unknown INT6D command: %x\n",M.x86.R_AH); 594#endif 595 break; 596 } 597 598 if (reflect) X86EMU_prepareForInt(0x6D); 599} 600 601 602 603static void __SIMint1A(int intno) 604{ 605 pcitag_t tag; 606 int bus,device,function; 607 int ret; 608 609 if (M.x86.R_AH != PCIBIOS_FN_MAJOR) return; 610 611 switch (M.x86.R_AL) { 612 case PCIBIOS_FN_INSTCHK: 613 M.x86.R_EAX = 0x00; 614 M.x86.R_AL = 0x01; 615 M.x86.R_EDX = PCIBIOS_SIGNATURE; 616 M.x86.R_EBX = PCIBIOS_VERSION; 617 M.x86.R_ECX &= 0xFF00; 618 M.x86.R_CL = 0; /* Highest bus number */ 619#ifdef VGAINIT_NOISY 620 xprintf("Int1A: Installation check\n"); 621#endif 622 CLEAR_FLAG(F_CF); 623 break; 624 625 case PCIBIOS_FN_FINDDEV: 626 ret = pci_find_device(M.x86.R_DX,M.x86.R_CX,M.x86.R_SI,&tag); 627#if VGAINIT_NOISY 628 xprintf("Int1A: Find device VID=%04X,DID=%04X,Idx=%d: ", 629 M.x86.R_DX,M.x86.R_CX,M.x86.R_SI); 630 if (ret == 0) { 631 pci_break_tag(tag,NULL,&bus,&device,&function); 632 xprintf("Found Bus%d, Dev%d, Func%d\n",bus,device,function); 633 } 634 else { 635 xprintf("not found.\n"); 636 } 637#endif 638 if (ret == 0) { 639 pci_break_tag(tag,NULL,&bus,&device,&function); 640 M.x86.R_BH = bus; 641 M.x86.R_BL = (device << 3) | function; 642 M.x86.R_AH = PCIBIOS_SUCCESSFUL; 643 } 644 else { 645 M.x86.R_AH = PCIBIOS_DEVICE_NOT_FOUND; 646 } 647 648 CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL),F_CF); 649 break; 650 651 case PCIBIOS_FN_FINDCLASS: 652 ret = pci_find_class(M.x86.R_ECX,M.x86.R_SI,&tag); 653#if VGAINIT_NOISY 654 xprintf("Int1A: Find Class %08X,Idx=%d: ", 655 M.x86.R_ECX,M.x86.R_SI); 656 if (ret == 0) { 657 pci_break_tag(tag,NULL,&bus,&device,&function); 658 xprintf("Found Bus%d, Dev%d, Func%d\n",bus,device,function); 659 } 660 else { 661 xprintf("not found.\n"); 662 } 663#endif 664 665 if (ret == 0) { 666 pci_break_tag(tag,NULL,&bus,&device,&function); 667 M.x86.R_BH = bus; 668 M.x86.R_BL = (device << 3) | function; 669 M.x86.R_AH = PCIBIOS_SUCCESSFUL; 670 } 671 else { 672 M.x86.R_AH =PCIBIOS_DEVICE_NOT_FOUND; 673 } 674 675 CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL),F_CF); 676 break; 677 678 case PCIBIOS_FN_RDCFGBYTE: 679 regs2tag(&tag); 680 M.x86.R_CL = pci_conf_read8(tag,M.x86.R_DI); 681 M.x86.R_AH = PCIBIOS_SUCCESSFUL; 682#if VGAINIT_NOISY 683 xprintf("Int1A: Read Cfg Byte %04X from ",M.x86.R_DI); 684 pci_break_tag(tag,NULL,&bus,&device,&function); 685 xprintf("Bus%d, Dev%d, Func%d",bus,device,function); 686 xprintf(": %02X\n",M.x86.R_CX); 687#endif 688 689 CLEAR_FLAG(F_CF); 690 break; 691 692 case PCIBIOS_FN_RDCFGWORD: 693 regs2tag(&tag); 694 M.x86.R_CX = pci_conf_read16(tag,M.x86.R_DI); 695 M.x86.R_AH = PCIBIOS_SUCCESSFUL; 696#if VGAINIT_NOISY 697 xprintf("Int1A: Read Cfg Word %04X from ",M.x86.R_DI); 698 pci_break_tag(tag,NULL,&bus,&device,&function); 699 xprintf("Bus%d, Dev%d, Func%d",bus,device,function); 700 xprintf(": %04X\n",M.x86.R_CX); 701#endif 702 CLEAR_FLAG(F_CF); 703 break; 704 705 case PCIBIOS_FN_RDCFGDWORD: 706 regs2tag(&tag); 707 M.x86.R_ECX = pci_conf_read(tag,M.x86.R_DI); 708#if VGAINIT_NOISY 709 xprintf("Int1A: Read Cfg Dword %04X from ",M.x86.R_DI); 710 pci_break_tag(tag,NULL,&bus,&device,&function); 711 xprintf("Bus%d, Dev%d, Func%d",bus,device,function); 712 xprintf(": %08X\n",M.x86.R_ECX); 713#endif 714 M.x86.R_AH = PCIBIOS_SUCCESSFUL; 715 CLEAR_FLAG(F_CF); 716 break; 717 718 case PCIBIOS_FN_WRCFGBYTE: 719 regs2tag(&tag); 720 pci_conf_write8(tag,M.x86.R_DI,M.x86.R_CL); 721#if VGAINIT_NOISY 722 xprintf("Int1A: Write Cfg byte %04X to ",M.x86.R_DI); 723 pci_break_tag(tag,NULL,&bus,&device,&function); 724 xprintf("Bus%d, Dev%d, Func%d",bus,device,function); 725 xprintf(": %02X\n",M.x86.R_CL); 726#endif 727 728 M.x86.R_AH = PCIBIOS_SUCCESSFUL; 729 CLEAR_FLAG(F_CF); 730 break; 731 732 case PCIBIOS_FN_WRCFGWORD: 733 regs2tag(&tag); 734 pci_conf_write16(tag,M.x86.R_DI,M.x86.R_CX); 735#if VGAINIT_NOISY 736 xprintf("Int1A: Write Cfg Word %04X to ",M.x86.R_DI); 737 pci_break_tag(tag,NULL,&bus,&device,&function); 738 xprintf("Bus%d, Dev%d, Func%d",bus,device,function); 739 xprintf(": %04X\n",M.x86.R_CX); 740#endif 741 M.x86.R_AH = PCIBIOS_SUCCESSFUL; 742 CLEAR_FLAG(F_CF); 743 break; 744 745 case PCIBIOS_FN_WRCFGDWORD: 746 regs2tag(&tag); 747 pci_conf_write(tag,M.x86.R_DI,M.x86.R_ECX); 748#if VGAINIT_NOISY 749 xprintf("Int1A: Write Cfg Dword %04X to ",M.x86.R_DI); 750 pci_break_tag(tag,NULL,&bus,&device,&function); 751 xprintf("Bus%d, Dev%d, Func%d",bus,device,function); 752 xprintf(": %08X\n",M.x86.R_ECX); 753#endif 754 M.x86.R_AH = PCIBIOS_SUCCESSFUL; 755 CLEAR_FLAG(F_CF); 756 break; 757 758 default: 759#if VGAINIT_NOISY 760 xprintf("Int1A: Unimplemented PCI BIOS function AX=%04x\n", M.x86.R_AX); 761#endif 762 break; 763 } 764} 765 766 767 768static int x86init(void) 769{ 770 /* 771 * Access functions for I/O ports 772 */ 773 static X86EMU_pioFuncs piofuncs = { 774 __x86emu_inb, 775 __x86emu_inw, 776 __x86emu_inl, 777 __x86emu_outb, 778 __x86emu_outw, 779 __x86emu_outl 780 }; 781 782 /* 783 * Access functions for memory 784 */ 785 static X86EMU_memFuncs memfuncs = { 786 __x86emu_rdb, 787 __x86emu_rdw, 788 __x86emu_rdl, 789 __x86emu_wrb, 790 __x86emu_wrw, 791 __x86emu_wrl 792 }; 793 794 /* 795 * Interrupt table 796 */ 797 void (*funcs[256])(int num); /* XXX: can be 2 kilobytes! */ 798 int idx; 799 800 /* 801 * Establish hooks in the simulator 802 */ 803 X86EMU_setupMemFuncs(&memfuncs); 804 X86EMU_setupPioFuncs(&piofuncs); 805 806 /* 807 * Decode what X86 software interrupts we need to hook 808 */ 809 810 for (idx = 0; idx < 256; idx++) { 811 funcs[idx] = __SIMintunk; /* assume all are bad */ 812 } 813 funcs[0x42] = __SIMint42; /* int42: video BIOS */ 814 funcs[0x1F] = NULL; /* reflect INT1F */ 815 funcs[0x43] = NULL; /* reflect INT43 */ 816 funcs[0x6D] = __SIMint6D; /* int6D: video BIOS */ 817 818 funcs[0x03] = __SIMint3; /* int3: firmware exit */ 819 funcs[0x10] = __SIMint10; /* int10: video BIOS */ 820 funcs[0x1A] = __SIMint1A; /* int1A: PCI BIOS */ 821 822 X86EMU_setupIntrFuncs(funcs); 823 824 x86mem_init(&x86mem); 825 x86mem_hook(&x86mem,0xA0000,__ISAreadmem,__ISAwritemem); 826 x86mem_hook(&x86mem,0xA8000,__ISAreadmem,__ISAwritemem); 827 x86mem_hook(&x86mem,0xB0000,__ISAreadmem,__ISAwritemem); 828 x86mem_hook(&x86mem,0xB8000,__ISAreadmem,__ISAwritemem); 829 830 return 0; 831 832} 833 834 835static void x86uninit(void) 836{ 837 x86mem_uninit(&x86mem); 838} 839 840 841int vga_probe(void) 842{ 843 pcitag_t tag; 844 845 if (pci_find_class(PCI_CLASS_DISPLAY,0,&tag) == 0) { 846 return 0; 847 } 848 849 return -1; 850} 851 852int vga_biosinit(void) 853{ 854 physaddr_t biosaddr; 855 pcitag_t tag; 856 uint32_t addr; 857 uint32_t romaddr; 858 uint32_t destaddr; 859 uint32_t stackaddr; 860 uint32_t iretaddr; 861 unsigned int biossize; 862 int bus,device,function; 863 int idx; 864 int res; 865 866 if (pci_find_class(PCI_CLASS_DISPLAY,0,&tag) == 0) { 867 romaddr = pci_conf_read(tag,PCI_MAPREG_ROM); 868 pci_conf_write(tag,PCI_MAPREG_ROM,romaddr | PCI_MAPREG_ROM_ENABLE); 869 } 870 else { 871 xprintf("No suitable VGA device found in the system.\n"); 872 return -1; 873 } 874 875 addr = romaddr; 876 addr &= PCI_MAPREG_ROM_ADDR_MASK; 877#if defined(_P5064_) || defined(_P6064_) 878 biosaddr = cpu_isamap((vm_offset_t) romaddr,0); 879#else 880 biosaddr = (physaddr_t) romaddr; 881#endif 882 883 /* 884 * Check for the presence of a VGA BIOS on this adapter. 885 */ 886 887 if (!((phys_read8(biosaddr+PCIBIOS_ROMSIG_OFFSET+0) == PCIBIOS_ROMSIG1) && 888 (phys_read8(biosaddr+PCIBIOS_ROMSIG_OFFSET+1) == PCIBIOS_ROMSIG2))) { 889 xprintf("No VGA BIOS on this adapter.\n"); 890 pci_conf_write(tag,PCI_MAPREG_ROM,romaddr); 891 return -1; 892 } 893 biossize = PCIBIOS_ROMSIZE(phys_read8(biosaddr+PCIBIOS_ROMSIZE_OFFSET)); 894 895#if VGAINIT_NOISY 896 xprintf("VGA BIOS size is %d bytes\n",biossize); 897#endif 898 899 /* 900 * Initialize the X86 emulator 901 */ 902 903 if (x86init() != 0) { 904 xprintf("X86 emulator did not initialize.\n"); 905 pci_conf_write(tag,PCI_MAPREG_ROM,romaddr); 906 return -1; 907 } 908 909 /* 910 * Allocate space for the ROM BIOS and the stack. 911 * The basic layout is: 912 * 913 * C000:0000 VGA BIOS 914 * C000:XXXX end of VGA BIOS, start of stack 915 * C000:YYYY end of stack, start of init code 916 * C000:ZZZZ end of allocated memory 917 * 918 * We put a little code stub after the stack to allow us to have 919 * a clean exit from the simulator. 920 */ 921 922 923 destaddr = BIOSRAMLOC; 924 stackaddr = destaddr + biossize + STACKSIZE; 925 926 /* 927 * Copy the BIOS from the PCI rom into RAM 928 */ 929 930#if VGAINIT_NOISY 931 xprintf("Copying VGA BIOS to RAM.\n"); 932#endif 933 934 for (idx = 0; idx < biossize; idx+=4) { 935 uint32_t b; 936 937 b = phys_read32(biosaddr+idx); 938 x86mem_memcpy(&x86mem,destaddr+idx,(uint8_t *) &b,sizeof(uint32_t)); 939 } 940 941 /* 942 * Gross! The NVidia TNT2 BIOS expects to 943 * find a PC ROM BIOS date (just the slashes) 944 * at the right place in the ROMs. 945 */ 946 947 x86mem_memcpy(&x86mem,0xFFFF5,"08/13/99",8); 948 949 /* 950 * Turn off the BIOS ROM, we have our copy now. 951 */ 952 953 pci_conf_write(tag,PCI_MAPREG_ROM,romaddr); 954 955 /* 956 * Point certain vectors at a dummy IRET in our code space. 957 * Some ROMs don't take too kindly to null vectors, like 958 * the 3dfx Voodoo3 BIOS, which makes sure int1a is 959 * filled in before it attempts to call it. The 960 * code here is never really executed, since the emulator 961 * hooks it. 962 */ 963 964 iretaddr = stackaddr + IRETOFFSET; 965 __x86emu_wrw(0x1A*4+0,OFFSET(iretaddr)); 966 __x86emu_wrw(0x1A*4+2,SEGMENT(iretaddr)); 967 968 969 /* 970 * The actual code begins 3 bytes after the beginning of the ROM. Set 971 * the start address to the first byte of executable code. 972 */ 973 974 M.x86.R_CS = SEGMENT(destaddr + PCIBIOS_ROMENTRY_OFFSET); 975 M.x86.R_IP = OFFSET(destaddr + PCIBIOS_ROMENTRY_OFFSET); 976 977 /* 978 * Set the stack to point after our copy of the ROM 979 */ 980 981 M.x86.R_SS = SEGMENT(stackaddr - 8); 982 M.x86.R_SP = OFFSET(stackaddr - 8); 983 984 /* 985 * GROSS! The Voodoo3 card expects BP to have 986 * the following value: 987 */ 988 989 M.x86.R_BP = 0x197; 990 991 /* 992 * The PCI BIOS spec says you pass the bus, device, and function 993 * numbers in the AX register when starting the ROM code. 994 */ 995 996 pci_break_tag(tag,NULL,&bus,&device,&function); 997 M.x86.R_AH = bus; 998 M.x86.R_AL = (device << 3) | (function & 7); 999 1000 /* 1001 * Arrange for the return address to point to a little piece 1002 * of code that will do an int10 to set text mode, followed 1003 * by storing a couple of simple signatures in the registers, 1004 * and an int3 to stop the simulator. 1005 * 1006 * The location of this piece of code is just after our 1007 * stack, and since the stack grows down, this is in 'stackaddr' 1008 */ 1009 1010 __x86emu_wrw(stackaddr-8,OFFSET(stackaddr)); 1011 __x86emu_wrw(stackaddr-6,SEGMENT(stackaddr)); 1012 1013 /* copy in the code. */ 1014 1015 for (idx = 0; idx < sizeof(x86initcode); idx++) { 1016 __x86emu_wrb(stackaddr+idx,x86initcode[idx]); 1017 } 1018 1019 /* 1020 * Set up the VGA console descriptor. We need this to process the 1021 * int10's that write firmware copyright notices and such. 1022 */ 1023 1024 vga_init(&vga,(__ISAaddr(VGA_TEXTBUF_COLOR)),outb); 1025 1026 /* 1027 * Launch the simulator. 1028 */ 1029 1030 xprintf("Initializing VGA.\n"); 1031#ifdef DEBUG 1032 X86EMU_trace_on(); 1033#endif 1034 X86EMU_exec(); 1035 1036 /* 1037 * Check for the magic exit values in the registers. These get set 1038 * by the code in the array 'x86initcode' that was loaded above 1039 */ 1040 1041 if ((M.x86.R_AX == 0x1234) && (M.x86.R_BX == 0x5678)) res = 0; 1042 else res = -1; 1043 1044 /* 1045 * Done! 1046 */ 1047 1048 x86uninit(); 1049 1050 if (res < 0) { 1051 xprintf("VGA initialization failed.\n"); 1052 } 1053 else { 1054 char temp[32]; 1055 char *str = "If you can see this message, the VGA has been successfully initialized!\r\n\r\n"; 1056 1057 xprintf("VGA initialization successful.\n"); 1058 vga_writestr(&vga,(PTR2HSADDR(str)),0x07,strlen(str)); 1059 1060 sprintf(temp,"%d",VGA_TEXTMODE_ROWS); 1061 env_setenv("VGA_ROWS",temp,ENV_FLG_BUILTIN | ENV_FLG_READONLY | ENV_FLG_ADMIN); 1062 sprintf(temp,"%d",VGA_TEXTMODE_COLS); 1063 env_setenv("VGA_COLS",temp,ENV_FLG_BUILTIN | ENV_FLG_READONLY | ENV_FLG_ADMIN); 1064 1065 } 1066 1067 return res; 1068} 1069 1070int x86emutest(void) 1071{ 1072 uint32_t destaddr; 1073 uint32_t stackaddr; 1074 int res; 1075 1076 /* 1077 * Initialize the X86 emulator 1078 */ 1079 1080 if (x86init() != 0) { 1081 xprintf("X86 emulator did not initialize.\n"); 1082 return -1; 1083 } 1084 1085 destaddr = BIOSRAMLOC; 1086 stackaddr = destaddr + 1024; 1087 1088 /* 1089 * Copy the BIOS from the PCI rom into RAM 1090 */ 1091 1092 xprintf("Copying test program to RAM.\n"); 1093 x86mem_memcpy(&x86mem,destaddr,x86testcode,sizeof(x86testcode)); 1094 1095 /* 1096 * The actual code begins 3 bytes after the beginning of the ROM. Set 1097 * the start address to the first byte of executable code. 1098 */ 1099 1100 M.x86.R_CS = SEGMENT(destaddr + PCIBIOS_ROMENTRY_OFFSET); 1101 M.x86.R_IP = OFFSET(destaddr + PCIBIOS_ROMENTRY_OFFSET); 1102 1103 /* 1104 * Set the stack to point after our copy of the ROM 1105 */ 1106 1107 M.x86.R_SS = SEGMENT(stackaddr - 8); 1108 M.x86.R_SP = OFFSET(stackaddr - 8); 1109 1110 /* 1111 * Launch the simulator. 1112 */ 1113 1114 xprintf("Running X86emu test.\n"); 1115#ifdef DEBUG 1116 X86EMU_trace_on(); 1117#endif 1118 X86EMU_exec(); 1119 1120 /* 1121 * Check for the magic exit values in the registers. These get set 1122 * by the code in the array 'x86initcode' that was loaded above 1123 */ 1124 1125 if ((M.x86.R_AX == 0x1234) && (M.x86.R_BX == 0x5678)) res = 0; 1126 else res = -1; 1127 1128 /* 1129 * Done! 1130 */ 1131 1132 x86uninit(); 1133 1134 if (res < 0) xprintf("X86emu test failed.\n"); 1135 else xprintf("X86emu test successful.\n"); 1136 1137 return res; 1138} 1139 1140 1141 1142void vgaraw_dump(char *tail) 1143{ 1144 physaddr_t biosaddr; 1145 pcitag_t tag; 1146 uint32_t addr; 1147 uint32_t romaddr; 1148 unsigned int biossize; 1149 int idx; 1150 int res; 1151 1152 if (pci_find_class(PCI_CLASS_DISPLAY,0,&tag) == 0) { 1153 romaddr = pci_conf_read(tag,PCI_MAPREG_ROM); 1154 pci_conf_write(tag,PCI_MAPREG_ROM,romaddr | PCI_MAPREG_ROM_ENABLE); 1155 } 1156 else { 1157 xprintf("No suitable VGA device found in the system.\n"); 1158 return ; 1159 } 1160 1161 addr = romaddr; 1162 addr &= PCI_MAPREG_ROM_ADDR_MASK; 1163 1164 /* XXX This won't work if the PCI space is remapped somewhere else. */ 1165#if defined(_P5064_) || defined(_P6064_) 1166 biosaddr = cpu_isamap((vm_offset_t) romaddr,0); 1167#else 1168 biosaddr = romaddr; 1169#endif 1170 1171 /* 1172 * Check for the presence of a VGA BIOS on this adapter. 1173 */ 1174 1175 xprintf("VGA BIOS is mapped to %08X\n",(uint32_t) biosaddr); 1176 1177 if (!((phys_read8(biosaddr+PCIBIOS_ROMSIG_OFFSET+0) == PCIBIOS_ROMSIG1) && 1178 (phys_read8(biosaddr+PCIBIOS_ROMSIG_OFFSET+1) == PCIBIOS_ROMSIG2))) { 1179 xprintf("No VGA BIOS on this adapter, assuming 32K ROM\n"); 1180 biossize = 32768; 1181 return; 1182 } 1183 else { 1184 biossize = PCIBIOS_ROMSIZE(phys_read8(biosaddr+PCIBIOS_ROMSIZE_OFFSET)); 1185 xprintf("VGA BIOS size is %d bytes\n",biossize); 1186 } 1187 1188 for (idx = 0; idx < biossize; idx+=16) { 1189 xprintf("%04X: ",idx); 1190 for (res = 0; res < 16; res++) { 1191 xprintf("%02X ",phys_read8(biosaddr+idx+res)); 1192 } 1193 xprintf("\n"); 1194 if (console_status()) break; 1195 } 1196 1197// pci_conf_write(tag,PCI_MAPREG_ROM,romaddr); 1198 1199} 1200