#include #include "init.h" #include "printk.h" #include #include "pci-iface.h" #include "bios.h" #define die(x) { rom_printk(x); } #define warn(x) { rom_printk(x); } #define DEBUG_VIDEO 0 #define DebugV(fmt, args...) \ ({ if (DEBUG_VIDEO) \ rom_printk(fmt, ##args); }) void x86emu_dump_xregs(void); int int15_handler(void); int int16_handler(void); int int1A_handler(void); #ifndef _PC int int42_handler(void); #endif int intE6_handler(void); void setup_int_vect(void); int run_bios_int(int num); u32 getIntVect(int num); void pushw(u16 val); _ptr p; ptr currentp = 0; unsigned char biosmem[1024 * 1024]; int verbose = 1; /* Interrupt multiplexer */ void do_int(int num) { int ret = 0; // rom_printk("int%x vector at %x\n", num, getIntVect(num)); /* This is a pInt leftover */ currentp->num = num; switch (num) { #ifndef _PC case 0x10: case 0x42: case 0x6D: if (getIntVect(num) == 0xFF065) { ret = int42_handler(); } break; #endif case 0x15: ret = int15_handler(); break; case 0x16: ret = int16_handler(); break; case 0x1A: ret = int1A_handler(); break; case 0xe6: ret = intE6_handler(); break; default: break; } if (!ret) ret = run_bios_int(num); if (!ret) { rom_printk("\nint%x: not implemented\n", num); //x86emu_dump_xregs(); } } static void x_outb(u16 port, u8 val) { bios_outb(val, port); } static void x_outw(u16 port, u16 val) { bios_outw(val, port); } static void x_outl(u16 port, u32 val) { bios_outl(val, port); } X86EMU_pioFuncs myfuncs = { bios_inb, bios_inw, bios_inl, x_outb, x_outw, x_outl }; void X86EMU_setMemBase(void *base, unsigned int size); void X86EMU_setabseg(void *abseg); void x86emu_dump_xregs(void); int X86EMU_set_debug(int debug); X86EMU_intrFuncs intFuncs[256]; int pci_video_bios_init(struct bios_pci_dev *dev) { void *abseg = 0; int i; unsigned char *cp; unsigned int size = 0; int base = 0; unsigned short initialip = 0, initialcs = 0, devfn = 0; char *date = "01/01/99"; #ifdef DEBUG int debugflag = 0; int trace = 0; #endif // size = 64 * 1024; size = dev->rom_size; base = 0xc0000; initialcs = 0xc000; initialip = 0x0003; // rom_printk("Point 1 int%x vector at %x\n", 0x42, getIntVect(0x42)); abseg = (void *) 0xa0000; currentp = &p; X86EMU_setMemBase(biosmem, sizeof(biosmem)); X86EMU_setabseg(abseg); X86EMU_setupPioFuncs(&myfuncs); /* Setting up interrupt environment. * basically this means initializing PCI and * intXX handlers. */ pciInit(); setup_int_vect(); for (i = 0; i < 256; i++) intFuncs[i] = do_int; X86EMU_setupIntrFuncs(intFuncs); cp = (unsigned char *) dev->rom_address ; devfn = (PCI_SLOT(dev->devfn) << 3) | PCI_FUNC(dev->devfn); currentp->ax = devfn ? devfn : 0xff; currentp->dx = 0x80; for (i = 0; i < size; i++) { wrb(base + i, cp[i]); } /* Put a date into ROM */ for (i = 0; date[i]; i++) wrb(0xffff5 + i, date[i]); wrb(0xffff7, '/'); wrb(0xffffa, '/'); /* cpu setup */ X86_AX = devfn ? devfn : 0xff; X86_DX = 0x80; X86_EIP = initialip; X86_CS = initialcs; /* Initialize stack and data segment */ X86_SS = 0x0030; X86_DS = 0x0040; X86_SP = 0xfffe; /* We need a sane way to return from bios * execution. A hlt instruction and a pointer * to it, both kept on the stack, will do. */ pushw(0xf4f4); /* hlt; hlt */ pushw(X86_SS); pushw(X86_SP + 2); X86_ES = 0x0000; #ifdef DEBUG if (trace) { rom_printk("Switching to single step mode.\n"); X86EMU_trace_on(); } #endif #if 0 debugflag = DEBUG_MEM_TRACE_F | DEBUG_DECODE_F | DEBUG_DISASSEMBLE_F | DEBUG_TRACE_F | DEBUG_SYSINT_F; #endif #ifdef DEBUG // debugflag = 0x00ffffff; if (debugflag) { X86EMU_set_debug(debugflag); } #endif X86EMU_exec(); /* Cleaning up */ pciExit(); return 0; } /* VGA index register ports */ #define GRA_I 0x3CE /* Graphics Controller Index */ #define SEQ_I 0x3C4 /* Sequencer Index */ /* VGA data register ports */ #define GRA_D 0x3CF /* Graphics Controller Data Register */ #define SEQ_D 0x3C5 /* Sequencer Data Register */ #define CRT_IC 0x3D4 /* CRT Controller Index - color emulation */ #define CRT_DC 0x3D5 /* CRT Controller Data Register - color emulation */ #define IS1_RC 0x3DA /* Input Status Register 1 - color emulation */ #define ATT_IW 0x3C0 /* Attribute Controller Index & Data Write Register */ #define ATT_R 0x3C1 /* Attribute Controller Data Read Register */ #define ATC_MODE 0x10 #define ATC_COLOR_PAGE 0x14 #define CRTC_H_TOTAL 0 #define CRTC_H_DISP 1 #define CRTC_H_BLANK_START 2 #define CRTC_H_BLANK_END 3 #define CRTC_H_SYNC_START 4 #define CRTC_H_SYNC_END 5 #define CRTC_V_TOTAL 6 #define CRTC_OVERFLOW 7 #define CRTC_PRESET_ROW 8 #define CRTC_MAX_SCAN 9 #define CRTC_CURSOR_START 0x0A #define CRTC_CURSOR_END 0x0B #define CRTC_START_HI 0x0C #define CRTC_START_LO 0x0D #define CRTC_CURSOR_HI 0x0E #define CRTC_CURSOR_LO 0x0F #define CRTC_V_SYNC_START 0x10 #define CRTC_V_SYNC_END 0x11 #define CRTC_V_DISP_END 0x12 #define CRTC_OFFSET 0x13 #define CRTC_UNDERLINE 0x14 #define CRTC_V_BLANK_START 0x15 #define CRTC_V_BLANK_END 0x16 #define CRTC_MODE 0x17 #define CRTC_LINE_COMPARE 0x18 // macros for writing to vga regs #define write_seq(data, addr) \ ({ \ bios_outb(addr, SEQ_I); \ bios_outb(data, SEQ_D); \ }) #define write_gra(data, addr) \ ({ \ bios_outb(addr, GRA_I); \ bios_outb(data, GRA_D); \ }) #define write_crtc(data, addr) \ ({ \ bios_outb(addr, CRT_IC); \ bios_outb(data, CRT_DC); \ }) #define write_att(data, addr) \ ({ \ bios_inb(IS1_RC); \ bios_inb(0x80); \ bios_outb(addr, ATT_IW); \ bios_inb(0x80); \ bios_outb(data, ATT_IW); \ bios_inb(0x80); \ }) #define SEQ_CLOCK_MODE 0x01 #define SEQ_PLANE_WRITE 0x02 #define SEQ_CHARACTER_MAP 0x03 #define SEQ_MEMORY_MODE 0x04 #define GDC_PLANE_READ 0x04 #define GDC_MODE 0x05 #define GDC_MISC 0x06 #define GDC_BIT_MASK 0x08 #define VGA_FONT_BASE 0xa8000 #define CHAR_HEIGHT 16 unsigned char read_seq_b(unsigned short addr) { bios_outb(addr, SEQ_I); return bios_inb(SEQ_D); } unsigned char read_gra_b(unsigned short addr) { bios_outb(addr, GRA_I); return bios_inb(GRA_D); } unsigned char read_crtc_b(unsigned short addr) { bios_outb(addr, CRT_IC); return bios_inb(CRT_DC); } unsigned char read_att_b(unsigned short addr) { bios_inb(IS1_RC); bios_inb(0x80); bios_outb(addr, ATT_IW); return bios_inb(ATT_R); } #if 0 void vga_set_amode (void) { unsigned char byte; rom_printk("Switching into alpha mode..."); write_att(0x0c, ATC_MODE); //reset palette to normal in the case it was changed write_att(0x0, ATC_COLOR_PAGE); // // display is off at this point write_seq(0x3, SEQ_PLANE_WRITE); /* planes 0 & 1 */ byte = read_seq_b(SEQ_MEMORY_MODE) & ~0x04; write_seq(byte, SEQ_MEMORY_MODE); byte = read_gra_b(GDC_MODE) & ~0x60; write_gra(byte|0x10, GDC_MODE); write_gra(0x0e, GDC_MISC); write_crtc(0x00, CRTC_CURSOR_START); write_crtc(CHAR_HEIGHT-1, CRTC_CURSOR_END); byte = read_crtc_b(CRTC_MODE) & ~0xe0; write_crtc(byte|0xa0, CRTC_MODE); byte = read_crtc_b(CRTC_MAX_SCAN) & ~0x01f; write_crtc(byte | (CHAR_HEIGHT-1), CRTC_MAX_SCAN); // turn on display, disable access to attr palette bios_inb(IS1_RC); bios_outb(0x20, ATT_IW); rom_printk("done.\n"); } #endif /* * by Steve M. Gehlbach, Ph.D. * * vga_font_load loads a font into font memory. It * assumes alpha mode has been set. * * The font load code follows technique used * in the tiara project, which came from * the Universal Talkware Boot Loader, * http://www.talkware.net. */ void atyr128_font_enable(unsigned char *vidmem, int height, int num_chars) { /* Note: the font table is 'height' long but the font storage area * is 32 bytes long. */ int i; unsigned char byte; // rom_printk("Loading VGA font..."); // set sequencer map 2, odd/even off byte = read_seq_b(SEQ_PLANE_WRITE) & ~0xf; // rom_printk("SEQ_PLANE_WRITE %x\n", byte); write_seq(byte|4,SEQ_PLANE_WRITE); byte = read_seq_b(SEQ_MEMORY_MODE); // rom_printk("SEQ_MEMORY_MODE %x\n", byte); write_seq(byte|4,SEQ_MEMORY_MODE); // select graphics map 2, odd/even off, map starts at 0xa0000 write_gra(2,GDC_PLANE_READ); byte = read_gra_b(GDC_MODE) & ~0x10; // rom_printk("GDC_MODE %x\n", byte); write_gra(byte,GDC_MODE); write_gra(0,GDC_MISC); /* Clear 256K */ for (i = 0; i<(256 * 1024); i++) { vidmem[i] = 0; } // set sequencer back to maps 0,1, odd/even on byte = read_seq_b(SEQ_PLANE_WRITE) & ~0xf; write_seq(byte|3,SEQ_PLANE_WRITE); byte = read_seq_b(SEQ_MEMORY_MODE) & ~0x4; write_seq(byte,SEQ_MEMORY_MODE); byte = read_seq_b(SEQ_CHARACTER_MAP); // rom_printk("SEQ_CHARACTER_MAP %x\n", byte); write_seq(0x0a, SEQ_CHARACTER_MAP); // select graphics back to map 0,1, odd/even on write_gra(0,GDC_PLANE_READ); byte = read_gra_b(GDC_MODE); write_gra(byte|0x10,GDC_MODE); write_gra(0xe,GDC_MISC); // rom_printk("done\n"); } void video_bios(void) { struct bios_pci_dev *dev; int adpt_cnt; unsigned char *code = 0; int pcirom = 0; int atyr128 = 0; int cl5446 = 0; int mga2 = 0; adpt_cnt = 0; DebugV("video_bios() started\n"); dev = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, NULL); adpt_cnt++; if (dev) { #if DEBUG_VIDEO rom_printk("--------- VIDEO BIOS ------\n"); rom_printk("Class: %X\n", dev->class); rom_printk("command: %x\n", dev->command); rom_printk("base_address[0]: %04x\n", dev->base_address[0]); rom_printk("size[0]: %04x\n", dev->size[0]); rom_printk("base_address[1]: %04x\n", dev->base_address[1]); rom_printk("size[1]: %04x\n", dev->size[1]); rom_printk("base_address[2]: %04x\n", dev->base_address[2]); rom_printk("size[2]: %04x\n", dev->size[2]); rom_printk("base_address[3]: %04x\n", dev->base_address[3]); rom_printk("size[0]: %04x\n", dev->size[3]); rom_printk("base_address[4]: %04x\n", dev->base_address[4]); rom_printk("size[4]: %04x\n", dev->size[4]); rom_printk("base_address[5]: %04x\n", dev->base_address[5]); rom_printk("size[5]: %04x\n", dev->size[5]); rom_printk("rom_address: %04x\n", dev->rom_address); rom_printk("rom_size %04x\n", dev->rom_size); #endif code = (unsigned char *) dev->rom_address; if (code[0] == 0x55U && code[1] == 0xAAU ) { rom_printk("VIDEO BIOS found at %X\n", code); } else { rom_printk("No ROM signature found." " Skipping BIOS init...\n"); rom_printk("BYTES: %x %x\n", code[0], code[1]); } switch (dev->vendor) { case PCI_VENDOR_ID_CIRRUS: if (dev->device == PCI_DEVICE_ID_CIRRUS_5446) { rom_printk("Cirrus Logic GD 5446 detected!\n"); cl5446 = 1; }; break; case PCI_VENDOR_ID_ATI: switch(dev->device) { case PCI_DEVICE_ID_ATI_RAGE128_PP: rom_printk("ATI Rage 128 PP detected!\n"); atyr128 = 1; break; case PCI_DEVICE_ID_ATI_RAGE128_TR: rom_printk("ATI Rage 128 TR detected!\n"); atyr128 = 1; break; default: rom_printk("Unknown ATI display adapter detected!\n"); break; }; break; case PCI_VENDOR_ID_MCST_TMP: if (dev->device == PCI_DEVICE_ID_MCST_MGA2) { rom_printk("Embeded Graphic MGA2/GC2500 " "detected!\n"); mga2 = 1; }; break; default: rom_printk("Unknown display adapter found!\n"); break; } } else { rom_printk("No PCI display adaplers found!\n"); } if (pcirom) { pci_video_bios_init(dev); } else if (mga2) { #ifdef CONFIG_VGA_CONSOLE vga_init(); #endif /* CONFIG_VGA_CONSOLE */ } else { return; } if (atyr128) { atyr128_font_enable( (unsigned char *) VGA_FONT_BASE, CHAR_HEIGHT, 256); #if 0 unsigned char *vidmem = (unsigned char *) dev->base_address[0]; int i; for (i=0; i < (1 * 1024 * 1024); i++) { vidmem[i] = 0; }; #endif } // vga_set_amode(); hardware.video = 1; if (atyr128) { long int i; /* delay to relax ATI hardware */ for (i=0; i<77000000L; i++) { do { (void) (i); } while (0) ; } } #if 0 if (cl5446) { long int i; // rom_printk("qwertyuiopasdfghjklzxcvbnm\n"); // rom_printk("qwertyuiopasdfghjklzxcvbnm\n"); // rom_printk("qwertyuiopasdfghjklzxcvbnm\n"); for (i=0; i<2000000L; i++) { do {i; } while (0) ; } } #endif }