diff options
Diffstat (limited to 'cfe/cfe/pccons/vgainit.c')
-rw-r--r-- | cfe/cfe/pccons/vgainit.c | 1164 |
1 files changed, 1164 insertions, 0 deletions
diff --git a/cfe/cfe/pccons/vgainit.c b/cfe/cfe/pccons/vgainit.c new file mode 100644 index 0000000..7c22af2 --- /dev/null +++ b/cfe/cfe/pccons/vgainit.c @@ -0,0 +1,1164 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * VGA BIOS initialization File: VGAINIT.C + * + * This module interfaces with the X86 emulator borrowed from + * XFree86 to do VGA initialization. + * + * WARNING: This code is SB1250-specific for now. It's not + * hard to change, but then again, aren't we interested in the 1250? + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "sbmips.h" +#include "lib_types.h" +#include "lib_string.h" +#include "lib_printf.h" +#include "lib_malloc.h" +#include "pcireg.h" +#include "pcivar.h" +#include "cfe_console.h" +#include "vga.h" +#include "pcibios.h" +#include "lib_physio.h" +#include "vga_subr.h" +#include "x86mem.h" +#include "x86emu.h" +#include "env_subr.h" + + +/* ********************************************************************* + * Configuration + ********************************************************************* */ + +#define BYTESONLY 0 /* Always write registers as bytes */ +#define VGAINIT_NOISY 0 /* lots of debug output */ + +/* ********************************************************************* + * ISA port macros - currently SB1250-specific + ********************************************************************* */ + +#define INB(x) inb(x) +#define INW(x) inw(x) +#define INL(x) inl(x) +#define OUTB(x,y) outb(x,y) +#define OUTW(x,y) outw(x,y) +#define OUTL(x,y) outl(x,y) + +/* ********************************************************************* + * ISA memory macros - currently SB1250-specific + ********************************************************************* */ + +typedef uintptr_t vm_offset_t; + +#if defined(_P5064_) || defined(_P6064_) + #define PCI_MEM_SPACE 0x10000000 /* 128MB: s/w configurable */ + #define __ISAaddr(addr) ((physaddr_t)(PCI_MEM_SPACE+(addr))) +#else + #define __ISAaddr(addr) ((physaddr_t)0x40000000+(addr)) +#endif + +#define __ISAreadbyte(addr) phys_read8(__ISAaddr(addr)) +#define __ISAreadword(addr) phys_read16(__ISAaddr(addr)) +#define __ISAreaddword(addr) phys_read32(__ISAaddr(addr)) +#define __ISAwritebyte(addr,data) phys_write8(__ISAaddr(addr),(data)) +#define __ISAwriteword(addr,data) phys_write16(__ISAaddr(addr),(data)) +#define __ISAwritedword(addr,data) phys_write32(__ISAaddr(addr),(data)) + +/* ********************************************************************* + * Other macros + ********************************************************************* */ + +#define OFFSET(addr) (((addr) >> 0) & 0xffff) +#define SEGMENT(addr) (((addr) >> 4) & 0xf000) + +#define BSWAP_SHORT(s) ((((s) >> 8) & 0xFF) | (((s)&0xFF) << 8)) +#define BSWAP_LONG(s) ((((s) & 0xFF000000) >> 24) | \ + (((s) & 0x00FF0000) >> 8) | \ + (((s) & 0x0000FF00) << 8) | \ + (((s) & 0x000000FF) << 24)) + + +#ifdef __MIPSEB +#define CPU_TO_LE16(s) BSWAP_SHORT(s) +#define CPU_TO_LE32(s) BSWAP_LONG(s) +#define LE16_TO_CPU(s) BSWAP_SHORT(s) +#define LE32_TO_CPU(s) BSWAP_LONG(s) +#else +#define CPU_TO_LE16(s) (s) +#define CPU_TO_LE32(s) (s) +#define LE16_TO_CPU(s) (s) +#define LE32_TO_CPU(s) (s) +#endif + + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +int vga_biosinit(void); +int vga_probe(void); +extern void ui_restart(int); +void vgaraw_dump(char *tail); +int x86emutest(void); + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +static vga_term_t vga; +static x86mem_t x86mem; + +#define BIOSRAMLOC (0xC0000) +#define STACKSIZE 4096 +#define IRETOFFSET 12 +static uint8_t x86initcode[] = { +#if (VGA_TEXTMODE_ROWS == 60) + 0xB8,0x02,0x4F, /* mov ax,042F */ + 0xBB,0x08,0x01, /* mov bx,0108 */ /* VESA 80x60 */ +#else + 0xB8,0x03,0x00, /* mov AX,0003 */ /* 80x25 mode */ +#endif + + 0xCD,0x10, /* int 10 */ + 0xB8,0x34,0x12, /* mov ax,1234 */ + 0xBB,0x78,0x56, /* mov bx,5678 */ + 0xCC, /* int 3 */ + 0xCF}; /* IRET */ + +static uint8_t x86testcode[] = { + 0x90,0x90,0x90,0x90,0x90, /* nop, nop, nop, nop, nop */ + 0xeb,0x09, /* jmp 10 */ + 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90, /* 9 nops */ + 0xb8,0x34,0x12, /* mov ax,1234 */ + 0xbb,0x78,0x56, /* mov bx,5678 */ + 0xcc, /* int 3 */ + 0xcf}; /* iret */ + +static uint32_t __ISAreadmem(x86mem_t *mem,uint32_t addr,int size) +{ + unsigned long val; + + switch (size) { + case M_BYTE: + val = __ISAreadbyte(addr); + break; + case M_WORD: + if (BYTESONLY || (addr & 0x1)) { + val = (__ISAreadbyte(addr) | (__ISAreadbyte(addr + 1) << 8)); + } + else { + val = __ISAreadword(addr); + val = LE16_TO_CPU(val); + } + break; + case M_DWORD: + if (BYTESONLY || (addr & 0x3)) { + val = (__ISAreadbyte(addr) | + (__ISAreadbyte(addr + 1) << 8) | + (__ISAreadbyte(addr + 2) << 16) | + (__ISAreadbyte(addr + 3) << 24)); + } + else { + val = __ISAreaddword(addr); + val = LE32_TO_CPU(val); + } + break; + default: + val = 0; + } + + return val; +} + + + +static void __ISAwritemem(x86mem_t *mem,uint32_t addr,uint32_t data,int size) +{ + switch (size) { + case M_BYTE: + __ISAwritebyte(addr, data); + break; + + case M_WORD: + if (BYTESONLY || (addr & 0x1)) { + __ISAwritebyte(addr, data >> 0); + __ISAwritebyte(addr + 1, data >> 8); + } + else { + data = CPU_TO_LE16(data); + __ISAwriteword(addr, data); + } + break; + + case M_DWORD: + if (BYTESONLY || (addr & 0x3)) { + __ISAwritebyte(addr, data >> 0); + __ISAwritebyte(addr + 1, data >> 8); + __ISAwritebyte(addr + 2, data >> 16); + __ISAwritebyte(addr + 3, data >> 24); + } + else { + data = CPU_TO_LE32(data); + __ISAwritedword(addr, data); + } + break; + } +} + + +static u8 __x86emu_rdb(u32 addr) +{ +#if VGAINIT_NOISY + if ((addr < 0x400) || (addr > 0x100000)) { + xprintf("Read %08X (int %02X) ",addr,addr/4); + printf("CS:IP = %04X:%04X\n",M.x86.R_CS,M.x86.R_IP); + } +#endif + return x86mem_readb(&x86mem,addr); +} + + +static u16 __x86emu_rdw(u32 addr) +{ +#if VGAINIT_NOISY + if ((addr < 0x400) || (addr > 0x100000)) { + xprintf("Read %08X (int %02X) ",addr,addr/4); + printf("CS:IP = %04X:%04X\n",M.x86.R_CS,M.x86.R_IP); + } +#endif + return x86mem_readw(&x86mem,addr); +} + + +static u32 __x86emu_rdl(u32 addr) +{ +#if VGAINIT_NOISY + if ((addr < 0x400) || (addr > 0x100000)) { + xprintf("Read %08X (int %02X) ",addr,addr/4); + printf("CS:IP = %04X:%04X\n",M.x86.R_CS,M.x86.R_IP); + } +#endif + return x86mem_readl(&x86mem,addr); +} + + +static void __x86emu_wrb(u32 addr, u8 val) +{ +#if VGAINIT_NOISY + if ((addr < 0x400) || (addr > 0x100000)) { + xprintf("Write %08X (int %02X) ",addr,addr/4); + printf("CS:IP = %04X:%04X\n",M.x86.R_CS,M.x86.R_IP); + } +#endif + x86mem_writeb(&x86mem,addr,val); +} + + +static void __x86emu_wrw(u32 addr, u16 val) +{ +#if VGAINIT_NOISY + if ((addr < 0x400) || (addr > 0x100000)) { + xprintf("Write %08X %04X (int %02X) ",addr,val,addr/4); + printf("CS:IP = %04X:%04X\n",M.x86.R_CS,M.x86.R_IP); + } +#endif + x86mem_writew(&x86mem,addr,val); +} + + +static void __x86emu_wrl(u32 addr, u32 val) +{ +#if VGAINIT_NOISY + if ((addr < 0x400) || (addr > 0x100000)) { + xprintf("Write %08X (int %02X) ",addr,addr/4); + printf("CS:IP = %04X:%04X\n",M.x86.R_CS,M.x86.R_IP); + } +#endif + x86mem_writel(&x86mem,addr,val); +} + + +#define TS_COMMAND 0 +#define TS_DATA1 1 +#define TS_DATA2 2 +static uint16_t timerCount = 0; +static int timerState = TS_COMMAND; +static u8 __x86emu_inb(X86EMU_pioAddr port) +{ + u8 val; + + /* + * Emulate just enough functionality of the + * timer chip to fool the Trident BIOS + */ + if (port == 0x40) { + timerCount++; + switch (timerState) { + case TS_COMMAND: + return 0; + case TS_DATA1: + timerState = TS_DATA1; + return timerCount & 0xFF; + case TS_DATA2: + timerState = TS_COMMAND; + return (timerCount >> 8) & 0xFF; + } + } + + val = INB(port); + +#if VGAINIT_NOISY + /*if (port < 0x100)*/ xprintf("INB %08X %02X\n",port,val); + if (console_status()) ui_restart(0); +#endif + + + return val; +} + + +static u16 __x86emu_inw(X86EMU_pioAddr port) +{ + u16 val; + + val = INW(port); + + val = LE16_TO_CPU(val); + +#if VGAINIT_NOISY + /*if (port < 0x100)*/ xprintf("INW %08X %04X\n",port,val); +#endif + + return val; +} + + +static u32 __x86emu_inl(X86EMU_pioAddr port) +{ + u32 val; + + val = INL(port); + + val = LE32_TO_CPU(val); + +#if VGAINIT_NOISY + /*if (port < 0x100)*/ xprintf("INL %08X %08X\n",port,val); +#endif + + + return val; +} + + +static void __x86emu_outb(X86EMU_pioAddr port, u8 val) +{ + /* + * Emulate just enough functionality of the timer + * chip to fool the Trident BIOS + */ + if (port == 0x43) { + timerCount++; + timerState = TS_DATA1; + return; + } + +#if VGAINIT_NOISY + /*if (port < 0x100)*/ xprintf("OUTB %08X %08X\n",port,val); +#endif + + OUTB(port,val); +} + + +static void __x86emu_outw(X86EMU_pioAddr port, u16 val) +{ + val = CPU_TO_LE16(val); + +#if VGAINIT_NOISY + /*if (port < 0x100)*/ xprintf("OUTW %08X %04X ",port,val); + printf("CS:IP = %04X:%04X\n",M.x86.R_CS,M.x86.R_IP); +#endif + + OUTW(port,val); +} + + +static void __x86emu_outl(X86EMU_pioAddr port, u32 val) +{ + if (port == 0x2D) return; + + val = CPU_TO_LE32(val); + +#if VGAINIT_NOISY + /*if (port < 0x100)*/ xprintf("OUTL %08X %08X ",port,val); + printf("CS:IP = %04X:%04X\n",M.x86.R_CS,M.x86.R_IP); +#endif + + + OUTL(port,val); +} + + +static void regs2tag(pcitag_t *tag) +{ + pcitag_t mytag; + int bus,device,function; + + bus = M.x86.R_BH; + device = M.x86.R_BL >> 3; + function = M.x86.R_BL & 0x07; + + mytag = pci_make_tag(bus,device,function); + + *tag = mytag; +} + +static void __SIMint10(int intno) +{ +#if VGAINIT_NOISY + xprintf("Int10: BIOS function AX=%04X\n",M.x86.R_AX); +#endif + + /* + * The only BIOS function that VGAs appear to + * depend on in the real BIOS is the one + * that enables/disables video memory. + */ + + if ((M.x86.R_AH == 0x12) && (M.x86.R_BL == 0x32)) { + if (M.x86.R_AL == 0) { + /* enable video memory */ + __x86emu_outb(VGA_MISCOUTPUT_W, __x86emu_inb(VGA_MISCOUTPUT_R) | 0x02); + return; + } + else if (M.x86.R_AL == 1) { + /* disable video memory */ + __x86emu_outb(VGA_MISCOUTPUT_W, __x86emu_inb(VGA_MISCOUTPUT_R) & ~0x02); + return; + } + else { + xprintf("Int10 unknown function AX=%04X\n", + M.x86.R_AX); + } + } + else { + + /* Otherwise, pass the int10 on to the ROM */ + + X86EMU_prepareForInt(0x10); + } +} + + +static void __SIMint3(int intno) +{ +#if VGAINIT_NOISY + xprintf("Int3: Breakpoint reached.\n"); +#endif + HALT_SYS(); +} + + +static void __SIMintunk(int intno) +{ +#if VGAINIT_NOISY + xprintf("Int%02X: Unhandled interrupt!\n",intno); +#endif + HALT_SYS(); +} + +static void __SIMint42(int intno) +{ +#if VGAINIT_NOISY + xprintf("Int42: Function AX=%04X\n",M.x86.R_AX); +#endif + switch (M.x86.R_AH) { + case 0: + vga_reset(&vga); + break; + default: +#if VGAINIT_NOISY + xprintf("Int42: Unknown INT42 command: %x\n",M.x86.R_AH); +#endif + break; + } +} + + +static void __SIMint6D(int intno) +{ + int reflect = 1; + +#if VGAINIT_NOISY + xprintf("Int6D: Function AX=%04X\n",M.x86.R_AX); +#endif + + switch (M.x86.R_AH) { + case 0: + break; + case 0x13: + if (M.x86.R_AL == 1) { + unsigned long addr; + unsigned long count; + uint8_t ch; + + addr = (M.x86.R_ES << 4) + M.x86.R_BP; + count = M.x86.R_CX; + + while (count) { + ch = __x86emu_rdb(addr); + vga_writechar(&vga,ch,M.x86.R_BL); + addr++; + count--; + } + reflect = 0; + } + break; + default: +#if VGAINIT_NOISY + xprintf("Unknown INT6D command: %x\n",M.x86.R_AH); +#endif + break; + } + + if (reflect) X86EMU_prepareForInt(0x6D); +} + + + +static void __SIMint1A(int intno) +{ + pcitag_t tag; + int bus,device,function; + int ret; + + if (M.x86.R_AH != PCIBIOS_FN_MAJOR) return; + + switch (M.x86.R_AL) { + case PCIBIOS_FN_INSTCHK: + M.x86.R_EAX = 0x00; + M.x86.R_AL = 0x01; + M.x86.R_EDX = PCIBIOS_SIGNATURE; + M.x86.R_EBX = PCIBIOS_VERSION; + M.x86.R_ECX &= 0xFF00; + M.x86.R_CL = 0; /* Highest bus number */ +#ifdef VGAINIT_NOISY + xprintf("Int1A: Installation check\n"); +#endif + CLEAR_FLAG(F_CF); + break; + + case PCIBIOS_FN_FINDDEV: + ret = pci_find_device(M.x86.R_DX,M.x86.R_CX,M.x86.R_SI,&tag); +#if VGAINIT_NOISY + xprintf("Int1A: Find device VID=%04X,DID=%04X,Idx=%d: ", + M.x86.R_DX,M.x86.R_CX,M.x86.R_SI); + if (ret == 0) { + pci_break_tag(tag,&bus,&device,&function); + xprintf("Found Bus%d, Dev%d, Func%d\n",bus,device,function); + } + else { + xprintf("not found.\n"); + } +#endif + if (ret == 0) { + pci_break_tag(tag,&bus,&device,&function); + M.x86.R_BH = bus; + M.x86.R_BL = (device << 3) | function; + M.x86.R_AH = PCIBIOS_SUCCESSFUL; + } + else { + M.x86.R_AH = PCIBIOS_DEVICE_NOT_FOUND; + } + + CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL),F_CF); + break; + + case PCIBIOS_FN_FINDCLASS: + ret = pci_find_class(M.x86.R_ECX,M.x86.R_SI,&tag); +#if VGAINIT_NOISY + xprintf("Int1A: Find Class %08X,Idx=%d: ", + M.x86.R_ECX,M.x86.R_SI); + if (ret == 0) { + pci_break_tag(tag,&bus,&device,&function); + xprintf("Found Bus%d, Dev%d, Func%d\n",bus,device,function); + } + else { + xprintf("not found.\n"); + } +#endif + + if (ret == 0) { + pci_break_tag(tag,&bus,&device,&function); + M.x86.R_BH = bus; + M.x86.R_BL = (device << 3) | function; + M.x86.R_AH = PCIBIOS_SUCCESSFUL; + } + else { + M.x86.R_AH =PCIBIOS_DEVICE_NOT_FOUND; + } + + CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL),F_CF); + break; + + case PCIBIOS_FN_RDCFGBYTE: + regs2tag(&tag); + M.x86.R_CL = pci_conf_read8(tag,M.x86.R_DI); + M.x86.R_AH = PCIBIOS_SUCCESSFUL; +#if VGAINIT_NOISY + xprintf("Int1A: Read Cfg Byte %04X from ",M.x86.R_DI); + pci_break_tag(tag,&bus,&device,&function); + xprintf("Bus%d, Dev%d, Func%d",bus,device,function); + xprintf(": %02X\n",M.x86.R_CX); +#endif + + CLEAR_FLAG(F_CF); + break; + + case PCIBIOS_FN_RDCFGWORD: + regs2tag(&tag); + M.x86.R_CX = pci_conf_read16(tag,M.x86.R_DI); + M.x86.R_AH = PCIBIOS_SUCCESSFUL; +#if VGAINIT_NOISY + xprintf("Int1A: Read Cfg Word %04X from ",M.x86.R_DI); + pci_break_tag(tag,&bus,&device,&function); + xprintf("Bus%d, Dev%d, Func%d",bus,device,function); + xprintf(": %04X\n",M.x86.R_CX); +#endif + CLEAR_FLAG(F_CF); + break; + + case PCIBIOS_FN_RDCFGDWORD: + regs2tag(&tag); + M.x86.R_ECX = pci_conf_read(tag,M.x86.R_DI); +#if VGAINIT_NOISY + xprintf("Int1A: Read Cfg Dword %04X from ",M.x86.R_DI); + pci_break_tag(tag,&bus,&device,&function); + xprintf("Bus%d, Dev%d, Func%d",bus,device,function); + xprintf(": %08X\n",M.x86.R_ECX); +#endif + M.x86.R_AH = PCIBIOS_SUCCESSFUL; + CLEAR_FLAG(F_CF); + break; + + case PCIBIOS_FN_WRCFGBYTE: + regs2tag(&tag); + pci_conf_write8(tag,M.x86.R_DI,M.x86.R_CL); +#if VGAINIT_NOISY + xprintf("Int1A: Write Cfg byte %04X to ",M.x86.R_DI); + pci_break_tag(tag,&bus,&device,&function); + xprintf("Bus%d, Dev%d, Func%d",bus,device,function); + xprintf(": %02X\n",M.x86.R_CL); +#endif + + M.x86.R_AH = PCIBIOS_SUCCESSFUL; + CLEAR_FLAG(F_CF); + break; + + case PCIBIOS_FN_WRCFGWORD: + regs2tag(&tag); + pci_conf_write16(tag,M.x86.R_DI,M.x86.R_CX); +#if VGAINIT_NOISY + xprintf("Int1A: Write Cfg Word %04X to ",M.x86.R_DI); + pci_break_tag(tag,&bus,&device,&function); + xprintf("Bus%d, Dev%d, Func%d",bus,device,function); + xprintf(": %04X\n",M.x86.R_CX); +#endif + M.x86.R_AH = PCIBIOS_SUCCESSFUL; + CLEAR_FLAG(F_CF); + break; + + case PCIBIOS_FN_WRCFGDWORD: + regs2tag(&tag); + pci_conf_write(tag,M.x86.R_DI,M.x86.R_ECX); +#if VGAINIT_NOISY + xprintf("Int1A: Write Cfg Dword %04X to ",M.x86.R_DI); + pci_break_tag(tag,&bus,&device,&function); + xprintf("Bus%d, Dev%d, Func%d",bus,device,function); + xprintf(": %08X\n",M.x86.R_ECX); +#endif + M.x86.R_AH = PCIBIOS_SUCCESSFUL; + CLEAR_FLAG(F_CF); + break; + + default: +#if VGAINIT_NOISY + xprintf("Int1A: Unimplemented PCI BIOS function AX=%04x\n", M.x86.R_AX); +#endif + break; + } +} + + + +static int x86init(void) +{ + /* + * Access functions for I/O ports + */ + static X86EMU_pioFuncs piofuncs = { + __x86emu_inb, + __x86emu_inw, + __x86emu_inl, + __x86emu_outb, + __x86emu_outw, + __x86emu_outl + }; + + /* + * Access functions for memory + */ + static X86EMU_memFuncs memfuncs = { + __x86emu_rdb, + __x86emu_rdw, + __x86emu_rdl, + __x86emu_wrb, + __x86emu_wrw, + __x86emu_wrl + }; + + /* + * Interrupt table + */ + void (*funcs[256])(int num); /* XXX: can be 2 kilobytes! */ + int idx; + + /* + * Establish hooks in the simulator + */ + X86EMU_setupMemFuncs(&memfuncs); + X86EMU_setupPioFuncs(&piofuncs); + + /* + * Decode what X86 software interrupts we need to hook + */ + + for (idx = 0; idx < 256; idx++) { + funcs[idx] = __SIMintunk; /* assume all are bad */ + } + funcs[0x42] = __SIMint42; /* int42: video BIOS */ + funcs[0x1F] = NULL; /* reflect INT1F */ + funcs[0x43] = NULL; /* reflect INT43 */ + funcs[0x6D] = __SIMint6D; /* int6D: video BIOS */ + + funcs[0x03] = __SIMint3; /* int3: firmware exit */ + funcs[0x10] = __SIMint10; /* int10: video BIOS */ + funcs[0x1A] = __SIMint1A; /* int1A: PCI BIOS */ + + X86EMU_setupIntrFuncs(funcs); + + x86mem_init(&x86mem); + x86mem_hook(&x86mem,0xA0000,__ISAreadmem,__ISAwritemem); + x86mem_hook(&x86mem,0xA8000,__ISAreadmem,__ISAwritemem); + x86mem_hook(&x86mem,0xB0000,__ISAreadmem,__ISAwritemem); + x86mem_hook(&x86mem,0xB8000,__ISAreadmem,__ISAwritemem); + + return 0; + +} + + +static void x86uninit(void) +{ + x86mem_uninit(&x86mem); +} + + +int vga_probe(void) +{ + pcitag_t tag; + + if (pci_find_class(PCI_CLASS_DISPLAY,0,&tag) == 0) { + return 0; + } + + return -1; +} + +int vga_biosinit(void) +{ + physaddr_t biosaddr; + pcitag_t tag; + uint32_t addr; + uint32_t romaddr; + uint32_t destaddr; + uint32_t stackaddr; + uint32_t iretaddr; + unsigned int biossize; + int bus,device,function; + int idx; + int res; + + if (pci_find_class(PCI_CLASS_DISPLAY,0,&tag) == 0) { + romaddr = pci_conf_read(tag,PCI_MAPREG_ROM); + pci_conf_write(tag,PCI_MAPREG_ROM,romaddr | PCI_MAPREG_ROM_ENABLE); + } + else { + xprintf("No suitable VGA device found in the system.\n"); + return -1; + } + + addr = romaddr; + addr &= PCI_MAPREG_ROM_ADDR_MASK; +#if defined(_P5064_) || defined(_P6064_) + biosaddr = cpu_isamap((vm_offset_t) romaddr,0); +#else + biosaddr = (physaddr_t) romaddr; +#endif + + /* + * Check for the presence of a VGA BIOS on this adapter. + */ + + if (!((phys_read8(biosaddr+PCIBIOS_ROMSIG_OFFSET+0) == PCIBIOS_ROMSIG1) && + (phys_read8(biosaddr+PCIBIOS_ROMSIG_OFFSET+1) == PCIBIOS_ROMSIG2))) { + xprintf("No VGA BIOS on this adapter.\n"); + pci_conf_write(tag,PCI_MAPREG_ROM,romaddr); + return -1; + } + biossize = PCIBIOS_ROMSIZE(phys_read8(biosaddr+PCIBIOS_ROMSIZE_OFFSET)); + +#if VGAINIT_NOISY + xprintf("VGA BIOS size is %d bytes\n",biossize); +#endif + + /* + * Initialize the X86 emulator + */ + + if (x86init() != 0) { + xprintf("X86 emulator did not initialize.\n"); + pci_conf_write(tag,PCI_MAPREG_ROM,romaddr); + return -1; + } + + /* + * Allocate space for the ROM BIOS and the stack. + * The basic layout is: + * + * C000:0000 VGA BIOS + * C000:XXXX end of VGA BIOS, start of stack + * C000:YYYY end of stack, start of init code + * C000:ZZZZ end of allocated memory + * + * We put a little code stub after the stack to allow us to have + * a clean exit from the simulator. + */ + + + destaddr = BIOSRAMLOC; + stackaddr = destaddr + biossize + STACKSIZE; + + /* + * Copy the BIOS from the PCI rom into RAM + */ + +#if VGAINIT_NOISY + xprintf("Copying VGA BIOS to RAM.\n"); +#endif + + for (idx = 0; idx < biossize; idx+=4) { + uint32_t b; + + b = phys_read32(biosaddr+idx); + x86mem_memcpy(&x86mem,destaddr+idx,(uint8_t *) &b,sizeof(uint32_t)); + } + + /* + * Gross! The NVidia TNT2 BIOS expects to + * find a PC ROM BIOS date (just the slashes) + * at the right place in the ROMs. + */ + + x86mem_memcpy(&x86mem,0xFFFF5,"08/13/99",8); + + /* + * Turn off the BIOS ROM, we have our copy now. + */ + + pci_conf_write(tag,PCI_MAPREG_ROM,romaddr); + + /* + * Point certain vectors at a dummy IRET in our code space. + * Some ROMs don't take too kindly to null vectors, like + * the 3dfx Voodoo3 BIOS, which makes sure int1a is + * filled in before it attempts to call it. The + * code here is never really executed, since the emulator + * hooks it. + */ + + iretaddr = stackaddr + IRETOFFSET; + __x86emu_wrw(0x1A*4+0,OFFSET(iretaddr)); + __x86emu_wrw(0x1A*4+2,SEGMENT(iretaddr)); + + + /* + * The actual code begins 3 bytes after the beginning of the ROM. Set + * the start address to the first byte of executable code. + */ + + M.x86.R_CS = SEGMENT(destaddr + PCIBIOS_ROMENTRY_OFFSET); + M.x86.R_IP = OFFSET(destaddr + PCIBIOS_ROMENTRY_OFFSET); + + /* + * Set the stack to point after our copy of the ROM + */ + + M.x86.R_SS = SEGMENT(stackaddr - 8); + M.x86.R_SP = OFFSET(stackaddr - 8); + + /* + * GROSS! The Voodoo3 card expects BP to have + * the following value: + */ + + M.x86.R_BP = 0x197; + + /* + * The PCI BIOS spec says you pass the bus, device, and function + * numbers in the AX register when starting the ROM code. + */ + + pci_break_tag(tag,&bus,&device,&function); + M.x86.R_AH = bus; + M.x86.R_AL = (device << 3) | (function & 7); + + /* + * Arrange for the return address to point to a little piece + * of code that will do an int10 to set text mode, followed + * by storing a couple of simple signatures in the registers, + * and an int3 to stop the simulator. + * + * The location of this piece of code is just after our + * stack, and since the stack grows down, this is in 'stackaddr' + */ + + __x86emu_wrw(stackaddr-8,OFFSET(stackaddr)); + __x86emu_wrw(stackaddr-6,SEGMENT(stackaddr)); + + /* copy in the code. */ + + for (idx = 0; idx < sizeof(x86initcode); idx++) { + __x86emu_wrb(stackaddr+idx,x86initcode[idx]); + } + + /* + * Set up the VGA console descriptor. We need this to process the + * int10's that write firmware copyright notices and such. + */ + + vga_init(&vga,(__ISAaddr(VGA_TEXTBUF_COLOR)),outb); + + /* + * Launch the simulator. + */ + + xprintf("Initializing VGA.\n"); +#ifdef DEBUG + X86EMU_trace_on(); +#endif + X86EMU_exec(); + + /* + * Check for the magic exit values in the registers. These get set + * by the code in the array 'x86initcode' that was loaded above + */ + + if ((M.x86.R_AX == 0x1234) && (M.x86.R_BX == 0x5678)) res = 0; + else res = -1; + + /* + * Done! + */ + + x86uninit(); + + if (res < 0) { + xprintf("VGA initialization failed.\n"); + } + else { + char temp[32]; + char *str = "If you can see this message, the VGA has been successfully initialized!\r\n\r\n"; + + xprintf("VGA initialization successful.\n"); + vga_writestr(&vga,str,0x07,strlen(str)); + + sprintf(temp,"%d",VGA_TEXTMODE_ROWS); + env_setenv("VGA_ROWS",temp,ENV_FLG_BUILTIN | ENV_FLG_READONLY | ENV_FLG_ADMIN); + sprintf(temp,"%d",VGA_TEXTMODE_COLS); + env_setenv("VGA_COLS",temp,ENV_FLG_BUILTIN | ENV_FLG_READONLY | ENV_FLG_ADMIN); + + } + + return res; +} + +int x86emutest(void) +{ + uint32_t destaddr; + uint32_t stackaddr; + int res; + + /* + * Initialize the X86 emulator + */ + + if (x86init() != 0) { + xprintf("X86 emulator did not initialize.\n"); + return -1; + } + + destaddr = BIOSRAMLOC; + stackaddr = destaddr + 1024; + + /* + * Copy the BIOS from the PCI rom into RAM + */ + + xprintf("Copying test program to RAM.\n"); + x86mem_memcpy(&x86mem,destaddr,x86testcode,sizeof(x86testcode)); + + /* + * The actual code begins 3 bytes after the beginning of the ROM. Set + * the start address to the first byte of executable code. + */ + + M.x86.R_CS = SEGMENT(destaddr + PCIBIOS_ROMENTRY_OFFSET); + M.x86.R_IP = OFFSET(destaddr + PCIBIOS_ROMENTRY_OFFSET); + + /* + * Set the stack to point after our copy of the ROM + */ + + M.x86.R_SS = SEGMENT(stackaddr - 8); + M.x86.R_SP = OFFSET(stackaddr - 8); + + /* + * Launch the simulator. + */ + + xprintf("Running X86emu test.\n"); +#ifdef DEBUG + X86EMU_trace_on(); +#endif + X86EMU_exec(); + + /* + * Check for the magic exit values in the registers. These get set + * by the code in the array 'x86initcode' that was loaded above + */ + + if ((M.x86.R_AX == 0x1234) && (M.x86.R_BX == 0x5678)) res = 0; + else res = -1; + + /* + * Done! + */ + + x86uninit(); + + if (res < 0) xprintf("X86emu test failed.\n"); + else xprintf("X86emu test successful.\n"); + + return res; +} + + + +void vgaraw_dump(char *tail) +{ + physaddr_t biosaddr; + pcitag_t tag; + uint32_t addr; + uint32_t romaddr; + unsigned int biossize; + int idx; + int res; + + if (pci_find_class(PCI_CLASS_DISPLAY,0,&tag) == 0) { + romaddr = pci_conf_read(tag,PCI_MAPREG_ROM); + pci_conf_write(tag,PCI_MAPREG_ROM,romaddr | PCI_MAPREG_ROM_ENABLE); + } + else { + xprintf("No suitable VGA device found in the system.\n"); + return ; + } + + addr = romaddr; + addr &= PCI_MAPREG_ROM_ADDR_MASK; + + /* XXX This won't work if the PCI space is remapped somewhere else. */ +#if defined(_P5064_) || defined(_P6064_) + biosaddr = cpu_isamap((vm_offset_t) romaddr,0); +#else + biosaddr = romaddr; +#endif + + /* + * Check for the presence of a VGA BIOS on this adapter. + */ + + xprintf("VGA BIOS is mapped to %08X\n",(uint32_t) biosaddr); + + if (!((phys_read8(biosaddr+PCIBIOS_ROMSIG_OFFSET+0) == PCIBIOS_ROMSIG1) && + (phys_read8(biosaddr+PCIBIOS_ROMSIG_OFFSET+1) == PCIBIOS_ROMSIG2))) { + xprintf("No VGA BIOS on this adapter, assuming 32K ROM\n"); + biossize = 32768; + return; + } + else { + biossize = PCIBIOS_ROMSIZE(phys_read8(biosaddr+PCIBIOS_ROMSIZE_OFFSET)); + xprintf("VGA BIOS size is %d bytes\n",biossize); + } + + for (idx = 0; idx < biossize; idx+=16) { + xprintf("%04X: ",idx); + for (res = 0; res < 16; res++) { + xprintf("%02X ",phys_read8(biosaddr+idx+res)); + } + xprintf("\n"); + if (console_status()) break; + } + +// pci_conf_write(tag,PCI_MAPREG_ROM,romaddr); + +} |