diff --git a/src/arch/i386/lib/idt.c b/src/arch/i386/lib/idt.c index ef6d9b3c44..81ddf1c4d7 100644 --- a/src/arch/i386/lib/idt.c +++ b/src/arch/i386/lib/idt.c @@ -176,7 +176,7 @@ biosint( printk_debug("\n"); } printk_debug("biosint: Bailing out\n"); - // "longjmp" + // Should be replaced by longjmp for generalization. vga_exit(); break; #ifdef CONFIG_PCIBIOS @@ -230,14 +230,23 @@ setup_realmode_idt(void) { *intbyte = i; } - // fixed entry points + // Support for fixed entry points - // VGA BIOSes tend to hardcode f000:f065 as the previous handler of - // int10. + // First off, fill 0xCC (breakpoint) from f000:e000 to f000:ffff + // so we can catch the calls to unimplemented entry points. + // This 8KB area is where the fixed entry points are at. + // Maybe the original IBM PC had only this much of ROM. + memset((void *) 0xfe000, 0xCC, 0x2000); + + // VGA BIOSes tend to hardcode f000:f065 as the default handler for + // int10. // calling convention here is the same as INTs, we can reuse // the int entry code. codeptr = (char*) 0xff065; memcpy(codeptr, &idthandle, codesize); intbyte = codeptr + 3; *intbyte = 0x42; /* int42 is the relocated int10 */ + + // Clear the BIOS Data Area, not to confuse the realmode code. + memset((void *) 0x400, 0, 0x100); } diff --git a/src/arch/i386/lib/vgabios.c b/src/arch/i386/lib/vgabios.c index 2cce8bc796..29c226aba8 100644 --- a/src/arch/i386/lib/vgabios.c +++ b/src/arch/i386/lib/vgabios.c @@ -68,92 +68,96 @@ static char rcsid[] = "$Id$"; #if (CONFIG_VGABIOS == 1) -/* The address arguments to this function are PHYSICAL ADDRESSES */ -static void real_mode_switch_call_vga(unsigned long devfn) -{ - __asm__ __volatile__ - ( - // paranoia -- does ecx get saved? not sure. This is - // the easiest safe thing to do. - "pushal\n" - /* save the stack */ - "mov %esp, __stack\n" - "jmp 1f\n" - "__stack: .long 0\n" - "1:\n" - /* get devfn into %ecx */ - "movl %esp, %ebp\n" - "movl 8(%ebp), %ecx\n" - /* This configures CS properly for real mode. */ - " ljmp $0x28, $__rms_16bit\n" - "__rms_16bit: \n" - ".code16 \n" /* 16 bit code from here on... */ +extern void real_mode_switch_call_vga(unsigned long busdevfn); - /* Load the segment registers w/ properly configured segment - * descriptors. They will retain these configurations (limits, - * writability, etc.) once protected mode is turned off. */ - " mov $0x30, %ax \n" - " mov %ax, %ds \n" - " mov %ax, %es \n" - " mov %ax, %fs \n" - " mov %ax, %gs \n" - " mov %ax, %ss \n" +__asm__ ( +".text\n" +"__stack:\n" +" .long 0\n" +"real_mode_switch_call_vga:\n" +" pushl %ebp\n" +" movl %esp, %ebp\n" +/* Save callee-saved registers, since we don't know what VGABIOS would break */ +" pushl %ebx\n" +" pushl %esi\n" +" pushl %edi\n" +/* Get busdevfn in %ecx */ +" movl 8(%ebp), %ecx\n" +/* Save the stack */ +" mov %esp, __stack\n" +/* This configures CS properly for real mode. */ +" ljmp $0x28, $1f\n" +"1:\n" +".code16\n" /* 16 bit code from here on... */ - /* Turn off protection (bit 0 in CR0) */ - " movl %cr0, %eax \n" - " andl $0xFFFFFFFE, %eax \n" - " movl %eax, %cr0 \n" +/* Load the segment registers w/ properly configured segment +* descriptors. They will retain these configurations (limits, +* writability, etc.) once protected mode is turned off. */ +" movw $0x30, %ax\n" +" movw %ax, %ds\n" +" movw %ax, %es\n" +" movw %ax, %fs\n" +" movw %ax, %gs\n" +" movw %ax, %ss\n" - /* Now really going into real mode */ - " ljmp $0, $__rms_real \n" - "__rms_real: \n" +/* Turn off protection (bit 0 in CR0) */ +" movl %cr0, %eax\n" +" andl $0xFFFFFFFE, %eax\n" +" movl %eax, %cr0\n" - // put the stack at the end of page zero. - // that way we can easily share it between real and protected, - // since the 16-bit ESP at segment 0 will work for any case. - /* Setup a stack */ - " mov $0x0, %ax \n" - " mov %ax, %ss \n" - " movl $0x1000, %eax \n" - " movl %eax, %esp \n" - /* debugging for RGM */ - " mov $0x11, %al \n" - " outb %al, $0x80\n" +/* Now really going into real mode */ +" ljmp $0, $1f\n" +"1:\n" - /* Dump zeros in the other segregs */ - " xor %ax, %ax \n" - " mov %ax, %ds \n" - " mov %ax, %es \n" - " mov %ax, %fs \n" - " mov %ax, %gs \n" - " mov %cx, %ax \n" - " .byte 0x9a, 0x03, 0, 0, 0xc0 \n" - " movb $0x55, %al\noutb %al, $0x80\n" - /* if we got here, just about done. - * Need to get back to protected mode */ - "movl %cr0, %eax\n" -// "andl $0x7FFAFFD1, %eax\n" /* PG,AM,WP,NE,TS,EM,MP = 0 */ -// "orl $0x60000001, %eax\n" /* CD, NW, PE = 1 */ - "orl $0x0000001, %eax\n" /* PE = 1 */ - "movl %eax, %cr0\n" - /* Now that we are in protected mode jump to a 32 bit code segment. */ - "data32 ljmp $0x10, $vgarestart\n" - "vgarestart:\n" - ".code32\n" - " movw $0x18, %ax \n" - " mov %ax, %ds \n" - " mov %ax, %es \n" - " mov %ax, %fs \n" - " mov %ax, %gs \n" - " mov %ax, %ss \n" - ".globl vga_exit\n" - "vga_exit:\n" - " mov __stack, %esp\n" - " popal\n" - ); -} -__asm__ (".text\n""real_mode_switch_end:\n"); -extern char real_mode_switch_end[]; +// put the stack at the end of page zero. +// that way we can easily share it between real and protected, +// since the 16-bit ESP at segment 0 will work for any case. +/* Setup a stack */ +" xorw %ax, %ax\n" +" movw %ax, %ss\n" +" movl $0x1000, %esp\n" +/* debugging for RGM */ +" movb $0x11, %al\n" +" outb %al, $0x80\n" + +/* Dump zeros in the other segregs */ +" xorw %ax, %ax\n" +" movw %ax, %ds\n" +" movw %ax, %es\n" +" movw %ax, %fs\n" +" movw %ax, %gs\n" +/* Set bus/devfn to %ax */ +" movw %cx, %ax\n" +/* Now do the deed */ +" lcallw $0xc000, $0x0003\n" +/* debugging for RGM */ +" movb $0x55, %al\n" +" outb %al, $0x80\n" +/* if we got here, just about done. +* Need to get back to protected mode */ +" movl %cr0, %eax\n" +" orl $0x0000001, %eax\n" /* PE = 1 */ +" movl %eax, %cr0\n" +/* Now that we are in protected mode jump to a 32 bit code segment. */ +" ljmpl $0x10, $1f\n" +"1:\n" +".code32\n" +" movw $0x18, %ax\n" +" movw %ax, %ds\n" +" movw %ax, %es\n" +" movw %ax, %fs\n" +" movw %ax, %gs\n" +" movw %ax, %ss\n" +/* Emergency exit */ +".globl vga_exit\n" +"vga_exit:\n" +" movl __stack, %esp\n" +" popl %edi\n" +" popl %esi\n" +" popl %ebx\n" +" popl %ebp\n" +" ret\n" +); void do_vgabios(void) @@ -165,15 +169,6 @@ do_vgabios(void) unsigned int size = 64*1024; int i; -for (i=0x400; i<0x500; i++) { - printk_debug("%02x%c", *(unsigned char *)i, i%16==15 ? '\n' : ' '); - *(unsigned char *) i = 0; -} - -for (i=0x400; i<0x500; i++) { - printk_debug("%02x%c", *(unsigned char *)i, i%16==15 ? '\n' : ' '); -} - dev = pci_find_class(PCI_CLASS_DISPLAY_VGA <<8, NULL); if (! dev) { @@ -192,15 +187,23 @@ for (i=0x400; i<0x500; i++) { pci_write_config_dword(dev, PCI_ROM_ADDRESS, rom|1); printk_debug("rom base, size: %x\n", rom); #endif + buf = (unsigned char *) rom; - if ((buf[0] == 0x55) && (buf[1] = 0xaa)) { + if ((buf[0] == 0x55) && (buf[1] == 0xaa)) { + memcpy((void *) 0xc0000, buf, size); for(i = 0; i < 16; i++) printk_debug("0x%x ", buf[i]); - // check signature here later! - busdevfn = (dev->bus->secondary << 8) | dev->devfn; - real_mode_switch_call_vga(busdevfn); + // check signature again + buf = (unsigned char *) 0xc0000; + if (buf[0]==0x55 && buf[1]==0xAA) { + busdevfn = (dev->bus->secondary << 8) | dev->devfn; + printk_debug("bus/devfn = %#x\n", busdevfn); + + real_mode_switch_call_vga(busdevfn); + } else + printk_debug("Failed to copy VGA BIOS to 0xc0000\n"); } else printk_debug("BAD SIGNATURE 0x%x 0x%x\n", buf[0], buf[1]); #ifndef VGABIOS_START