diff --git a/src/arch/i386/lib/idt.c b/src/arch/i386/lib/idt.c index c89c5253e1..ef6d9b3c44 100644 --- a/src/arch/i386/lib/idt.c +++ b/src/arch/i386/lib/idt.c @@ -132,6 +132,9 @@ pcibios( unsigned long *pflags ); #endif + +extern void vga_exit(void); + int biosint( unsigned long intnumber, @@ -143,19 +146,16 @@ biosint( unsigned long edx, unsigned long ecx, unsigned long eax, - // these came in from 16-bit land - // but gcc does something weird we have to undo. - unsigned short stackip, - unsigned short stackflags, - unsigned short stackcs + unsigned long cs_ip, + unsigned short stackflags ) { unsigned long ip; unsigned long cs; unsigned long flags; int ret = -1; - ip = stackip; - cs = stackcs; + ip = cs_ip & 0xffff; + cs = cs_ip >> 16; flags = stackflags; printk_debug("biosint: # 0x%lx, eax 0x%lx ebx 0x%lx ecx 0x%lx edx 0x%lx\n", @@ -164,6 +164,21 @@ biosint( printk_debug("biosint: ip 0x%x cs 0x%x flags 0x%x\n", ip, cs, flags); // cases in a good compiler are just as good as your own tables. switch (intnumber) { + case 0 ... 15: + // These are not BIOS service, but the CPU-generated exceptions + printk_info("biosint: Oops, exception %u\n", intnumber); + if (esp < 0x1000) { + printk_debug("Stack contents: "); + while (esp < 0x1000) { + printk_debug("0x%04x ", *(unsigned short *) esp); + esp += 2; + } + printk_debug("\n"); + } + printk_debug("biosint: Bailing out\n"); + // "longjmp" + vga_exit(); + break; #ifdef CONFIG_PCIBIOS case PCIBIOS: ret = pcibios( &edi, &esi, &ebp, &esp, @@ -208,11 +223,21 @@ setup_realmode_idt(void) { // and get it that way. But that's really disgusting. for (i = 0; i < 256; i++) { idts[i].cs = 0; - codeptr = 1024 + i * codesize; - idts[i].offset = codeptr; - memcpy((void *) codeptr, &idthandle, codesize); + codeptr = (char*) 4096 + i * codesize; + idts[i].offset = (unsigned) codeptr; + memcpy(codeptr, &idthandle, codesize); intbyte = codeptr + 3; *intbyte = i; } + // fixed entry points + + // VGA BIOSes tend to hardcode f000:f065 as the previous handler of + // 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 */ } diff --git a/src/arch/i386/lib/vgabios.c b/src/arch/i386/lib/vgabios.c index 900cbcc446..2cce8bc796 100644 --- a/src/arch/i386/lib/vgabios.c +++ b/src/arch/i386/lib/vgabios.c @@ -69,15 +69,21 @@ static char rcsid[] = "$Id$"; /* The address arguments to this function are PHYSICAL ADDRESSES */ -static void real_mode_switch_call_vga(void) +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" @@ -110,7 +116,7 @@ static void real_mode_switch_call_vga(void) " mov %ax, %ss \n" " movl $0x1000, %eax \n" " movl %eax, %esp \n" - /* ebugging for RGM */ + /* debugging for RGM */ " mov $0x11, %al \n" " outb %al, $0x80\n" @@ -120,6 +126,7 @@ static void real_mode_switch_call_vga(void) " 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. @@ -139,7 +146,10 @@ static void real_mode_switch_call_vga(void) " 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"); @@ -149,11 +159,21 @@ void do_vgabios(void) { struct pci_dev *dev; + unsigned long busdevfn; unsigned int rom = 0; unsigned char *buf; 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) { @@ -179,7 +199,8 @@ do_vgabios(void) for(i = 0; i < 16; i++) printk_debug("0x%x ", buf[i]); // check signature here later! - real_mode_switch_call_vga(); + busdevfn = (dev->bus->secondary << 8) | dev->devfn; + real_mode_switch_call_vga(busdevfn); } else printk_debug("BAD SIGNATURE 0x%x 0x%x\n", buf[0], buf[1]); #ifndef VGABIOS_START