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