[coreboot] [v3] r1167 - coreboot-v3/util/x86emu

svn at coreboot.org svn at coreboot.org
Fri May 29 15:09:57 CEST 2009


Author: stepan
Date: 2009-05-29 15:09:57 +0200 (Fri, 29 May 2009)
New Revision: 1167

Added:
   coreboot-v3/util/x86emu/x86.c
   coreboot-v3/util/x86emu/x86_asm.S
   coreboot-v3/util/x86emu/x86_interrupts.c
Modified:
   coreboot-v3/util/x86emu/Config.lb
   coreboot-v3/util/x86emu/Makefile
   coreboot-v3/util/x86emu/biosemu.c
   coreboot-v3/util/x86emu/vm86.c
   coreboot-v3/util/x86emu/vm86_gdt.c
Log:
Part II - svn externals need to be committed separately

drop most of the crappy vm86 code and replace it with a rewritten
version that has all assembler in a .S file and all C code in a .c
file. Also, remove requirement to move around between GDTs.

This version includes the suggestions from Peter to clean up CR0 manipulation
and to guard critical code paths by cli/sti. Tested and working on my hardware.

Signed-off-by: Stefan Reinauer <stepan at coresystems.de>
Acked-by: Peter Stuge <peter at stuge.se>



Modified: coreboot-v3/util/x86emu/Config.lb
===================================================================
--- coreboot-v3/util/x86emu/Config.lb	2009-05-09 23:36:20 UTC (rev 1166)
+++ coreboot-v3/util/x86emu/Config.lb	2009-05-29 13:09:57 UTC (rev 1167)
@@ -6,8 +6,9 @@
   dir x86emu
 else
   if CONFIG_PCI_OPTION_ROM_RUN_VM86
-    object vm86.o
-    object vm86_gdt.o
+    object x86.o
+    object x86_interrupts.o
+    object x86_asm.S
   else
     object biosemu.o
     dir pcbios

Modified: coreboot-v3/util/x86emu/Makefile
===================================================================
--- coreboot-v3/util/x86emu/Makefile	2009-05-09 23:36:20 UTC (rev 1166)
+++ coreboot-v3/util/x86emu/Makefile	2009-05-29 13:09:57 UTC (rev 1167)
@@ -37,7 +37,7 @@
 #TODO: remove these, these are .h files from slof, to make the merge easier...
 X86EMU_INCLUDE += -I $(src)/util/x86emu/yabel/compat
 endif
-VM86_SRC    = vm86.c vm86_gdt.c 
+VM86_SRC    = x86.c x86_asm.S
 
 ifeq ($(CONFIG_PCI_OPTION_ROM_RUN_X86EMU),y)
 LIBX86EMU_SRC=$(patsubst %,x86emu/%,$(X86EMU_SRC)) $(BIOSEMU_SRC)

Modified: coreboot-v3/util/x86emu/biosemu.c
===================================================================
--- coreboot-v3/util/x86emu/biosemu.c	2009-05-09 23:36:20 UTC (rev 1166)
+++ coreboot-v3/util/x86emu/biosemu.c	2009-05-29 13:09:57 UTC (rev 1167)
@@ -213,6 +213,7 @@
 		ret = run_bios_int(num);
 
 }
+
 #if 0
 #define SYS_BIOS 0xf0000
 /*
@@ -386,7 +387,7 @@
 	pushw(X86_SS);
 	pushw(X86_SP + 2);
 
-#ifndef NO_TRACE
+#ifdef DEBUG
 	//X86EMU_trace_on();
 #endif
 

Modified: coreboot-v3/util/x86emu/vm86.c
===================================================================
--- coreboot-v3/util/x86emu/vm86.c	2009-05-09 23:36:20 UTC (rev 1166)
+++ coreboot-v3/util/x86emu/vm86.c	2009-05-29 13:09:57 UTC (rev 1167)
@@ -1,719 +0,0 @@
-/*
- *  Erik Arjan Hendriks <hendriks at lanl.gov>
- *  Copyright (C) 2000 Scyld.
- *  Copyright (C) 2000 Scyld Computing Corporation
- *  Copyright (C) 2001 University of California.  LA-CC Number 01-67.
- *  Copyright (C) 2005 Nick.Barker9 at btinternet.com
- *  Copyright (C) 2007-2009 coresystems GmbH
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- */
-
-#include <device/pci.h>
-#include <device/pci_ids.h>
-#include <device/pci_ops.h>
-#include <string.h>
-#ifdef COREBOOT_V2
-#include <console/console.h>
-#include <arch/io.h>
-#define printk(lvl, x...) printk_debug(x)
-#else
-#include <console.h>
-#include <io.h>
-#endif
-
-/* 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"
-		// FIXME: why is this 8?
-		"	movl    8(%ebp), %ecx	\n"
-		/* load 'our' gdt */
-		"	lgdt	%cs:__mygdtaddr	\n"
-
-		/*  This configures CS properly for real mode. */
-		"	ljmp	$0x28, $__rms_16bit\n"
-		"__rms_16bit:		  	\n"
-		"	.code16			\n"
-		/* 16 bit code from here on... */
-
-		/* 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"
-
-		/* Turn off protection (bit 0 in CR0) */
-		"	movl	%cr0, %eax	\n"
-		"	andl	$0xFFFFFFFE, %eax \n"
-		"	movl	%eax, %cr0	\n"
-
-		/* Now really going into real mode */
-		"	ljmp	$0,  $__rms_real\n"
-		"__rms_real:			\n"
-
-		/* Setup a stack: 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. */
-		"	mov	$0x0, %ax	\n"
-		"	mov	%ax, %ss	\n"
-		"	movl	$0x1000, %eax	\n"
-		"	movl	%eax, %esp	\n"
-
-		/* Load our 16 it idt */
-		"	xor	%ax, %ax	\n"
-		"	mov	%ax, %ds	\n"
-		"	lidt	__myidt		\n"
-
-		/* Dump zeros in the other segment registers */
-		"	mov	%ax, %es       	\n"
-		"	mov	%ax, %fs       	\n"
-		"	mov	%ax, %gs       	\n"
-		"	mov	$0x40, %ax	\n"
-		"	mov	%ax, %ds	\n"
-		"	mov	%cx, %ax	\n"
-
-		/* run VGA BIOS at 0xc000:0003 */
-		"	lcall	$0xc000, $0x0003\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.
-		 */
-		"	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"
-
-		/* restore proper gdt and idt */
-		"	lgdt	%cs:gdtarg	\n"
-		"	lidt	idtarg		\n"
-
-		".globl vga_exit		\n"
-		"vga_exit:			\n"
-		"	mov	__stack, %esp	\n"
-		"	popal			\n"
-		);
-}
-
-// FIXME: drop this
-// __asm__ (".text\n""real_mode_switch_end:\n");
-// extern char real_mode_switch_end[];
-
-/* call vga bios int 10 function 0x4f14 to enable main console
-   epia-m does not always autosence the main console so forcing it on is good !! */
-void vga_enable_console(void)
-{
-	__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"
-
-		/* load 'our' gdt */
-		"	lgdt 	%cs:__mygdtaddr	\n"
-
-		/*  This configures CS properly for real mode. */
-		"	ljmp 	$0x28, $__vga_ec_16bit\n"
-		"__vga_ec_16bit:		\n"
-		"	.code16			\n"
-		/* 16 bit code from here on... */
-
-		/* 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"
-
-		/* Turn off protection (bit 0 in CR0) */
-		"	movl	%cr0, %eax     	\n"
-		"	andl	$0xFFFFFFFE, %eax\n"
-		"	movl	%eax, %cr0     	\n"
-
-		/* Now really going into real mode */
-		"	ljmp	$0, $__vga_ec_real \n"
-		"__vga_ec_real:                  \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"
-
-		/* Load our 16 it idt */
-		"	xor	%ax, %ax       	\n"
-		"	mov	%ax, %ds	\n"
-		"	lidt	__myidt		\n"
-
-		/* Dump zeros in the other segregs */
-		"	mov	%ax, %ds	\n"
-		"	mov	%ax, %es	\n"
-		"	mov	%ax, %fs	\n"
-		"	mov	%ax, %gs	\n"
-
-		/* ask bios to enable main console */
-		/* set up for int 10 call - values found from X server
-		 * bios call routines */
-		"	movw	$0x4f14,%ax	\n"
-		"	movw	$0x8003,%bx	\n"
-		"	movw	$1, %cx		\n"
-		"	movw	$0, %dx		\n"
-		"	movw	$0, %di		\n"
-		"	int	$0x10		\n"
-
-		"	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. */
-		"	data32	ljmp	$0x10, $vga_ec_restart\n"
-		"vga_ec_restart:\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"
-
-		/* restore proper gdt and idt */
-		"	lgdt	%cs:gdtarg 	\n"
-		"	lidt	idtarg		\n"
-		"	.globl	vga__ec_exit	\n"
-		"vga_ec_exit:\n"
-		"	mov	__stack, %esp	\n"
-		"	popal\n"
-		);
-}
-
-// we had hoped to avoid this.
-// this is a stub IDT only. It's main purpose is to ignore calls
-// to the BIOS.
-// no longer. Dammit. We have to respond to these.
-struct realidt {
-	unsigned short offset, cs;
-};
-
-// from a handy writeup that andrey found.
-
-// handler.
-// There are some assumptions we can make here.
-// First, the Top Of Stack (TOS) is located on the top of page zero.
-// we can share this stack between real and protected mode.
-// that simplifies a lot of things ...
-// we'll just push all the registers on the stack as longwords,
-// and pop to protected mode.
-// second, since this only ever runs as part of coreboot,
-// we know all the segment register values -- so we don't save any.
-// keep the handler that calls things small. It can do a call to
-// more complex code in coreboot itself. This helps a lot as we don't
-// have to do address fixup in this little stub, and calls are absolute
-// so the handler is relocatable.
-void handler(void)
-{
-	__asm__ __volatile__ (
-		"	.code16		\n"
-		"idthandle:		\n"
-		"	pushal		\n"
-		"	movb 	$0, %al	\n"
-		"	ljmp 	$0, $callbiosint16\n"
-		"end_idthandle:		\n"
-		"	.code32		\n"
-		);
-}
-
-void debughandler(void)
-{
-	__asm__ __volatile__ (
-		"	.code16		\n"
-		"debughandle:		\n"
-		"	pushw	%cx	\n"
-		"	movw	$250, %cx \n"
-		"dbh1:			\n"
-		"	loop	dbh1	\n"
-		"	popw	%cx	\n"
-		"	iret		\n"
-		"end_debughandle:	\n"
-		".code32		\n"
-		);
-}
-
-// Calling conventions. The first C function is called with this stuff
-// on the stack. They look like value parameters, but note that if you
-// modify them they will go back to the INTx function modified.
-// the C function will call the biosint function with these as
-// REFERENCE parameters. In this way, we can easily get
-// returns back to the INTx caller (i.e. vgabios)
-void callbiosint(void)
-{
-	__asm__ __volatile__ (
-		"	.code16		\n"
-		"callbiosint16:		\n"
-		"	push	%ds	\n"
-		"	push	%es	\n"
-		"	push	%fs	\n"
-		"	push	%gs	\n"
-		// clean up the int #. To save space we put it in the lower
-		// byte. But the top 24 bits are junk.
-		"	andl	$0xff, %eax\n"
-		// this push does two things:
-		// - put the INT # on the stack as a parameter
-		// - provides us with a temp for the %cr0 mods.
-		"	pushl	%eax	\n"
-		"	movl    %cr0, %eax\n"
-		"	orl	$0x00000001, %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, $biosprotect\n"
-		"biosprotect:		\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"
-		"	lidt	idtarg         \n"
-		"	call	biosint	\n"
-		// back to real mode ...
-		"	ljmp	$0x28, $__rms_16bit2\n"
-		"__rms_16bit2:			\n"
-		"	.code16			\n"
-		/* 16 bit code from here on... */
-		/* 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"
-
-		/* Turn off protection (bit 0 in CR0) */
-		"	movl	%cr0, %eax		\n"
-		"	andl	$0xFFFFFFFE, %eax	\n"
-		"	movl	%eax, %cr0		\n"
-
-		/* Now really going into real mode */
-		"	ljmp $0,  $__rms_real2	\n"
-		"__rms_real2:			\n"
-
-		/* Setup a stack
-		 * FixME: where is esp? */
-		"	mov	$0x0, %ax       \n"
-		"	mov	%ax, %ss	\n"
-
-		/* ebugging for RGM */
-		"	mov	$0x11, %al	\n"
-		"	outb	%al, $0x80	\n"
-
-		/* Load our 16 it idt */
-		"	xor	%ax, %ax	\n"
-		"	mov	%ax, %ds	\n"
-		"	lidt	__myidt		\n"
-
-		/* Dump zeros in the other segregs */
-		"	mov	%ax, %es	\n"
-		"	mov	%ax, %fs	\n"
-		"	mov	%ax, %gs	\n"
-		"	mov	$0x40, %ax	\n"
-		"	mov	%ax, %ds	\n"
-
-		/* pop the INT # that you pushed earlier */
-		"	popl	%eax		\n"
-		"	pop	%gs		\n"
-		"	pop	%fs		\n"
-		"	pop	%es		\n"
-		"	pop	%ds		\n"
-		"	popal			\n"
-		"	iret			\n"
-		"	.code32			\n"
-		);
-}
-
-enum {
-	PCIBIOS = 0x1a,
-	MEMSIZE = 0x12
-};
-
-int pcibios(unsigned long *pedi, unsigned long *pesi, unsigned long *pebp,
-	    unsigned long *pesp, unsigned long *pebx, unsigned long *pedx,
-	    unsigned long *pecx, unsigned long *peax, unsigned long *pflags);
-
-int handleint21(unsigned long *pedi, unsigned long *pesi, unsigned long *pebp,
-		unsigned long *pesp, unsigned long *pebx, unsigned long *pedx,
-		unsigned long *pecx, unsigned long *peax, unsigned long *pflags
-	);
-
-extern void vga_exit(void);
-
-int __attribute__((regparm(0)))  biosint(unsigned long intnumber,
-	    unsigned long gsfs, unsigned long dses,
-	    unsigned long edi, unsigned long esi,
-	    unsigned long ebp, unsigned long esp,
-	    unsigned long ebx, unsigned long edx,
-	    unsigned long ecx, unsigned long eax,
-	    unsigned long cs_ip, unsigned short stackflags)
-{
-	unsigned long ip;
-	unsigned long cs;
-	unsigned long flags;
-	int ret = -1;
-
-	ip = cs_ip & 0xffff;
-	cs = cs_ip >> 16;
-	flags = stackflags;
-
-	printk(BIOS_DEBUG, "biosint: INT# 0x%lx\n", intnumber);
-	printk(BIOS_DEBUG, "biosint: eax 0x%lx ebx 0x%lx ecx 0x%lx edx 0x%lx\n",
-		      eax, ebx, ecx, edx);
-	printk(BIOS_DEBUG, "biosint: ebp 0x%lx esp 0x%lx edi 0x%lx esi 0x%lx\n",
-		     ebp, esp, edi, esi);
-	printk(BIOS_DEBUG, "biosint:  ip 0x%lx   cs 0x%lx  flags 0x%lx\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(BIOS_INFO, "biosint: Oops, exception %lu\n", intnumber);
-		if (esp < 0x1000) {
-			printk(BIOS_DEBUG, "Stack contents: ");
-			while (esp < 0x1000) {
-				printk(BIOS_DEBUG, "0x%04x ", *(unsigned short *) esp);
-				esp += 2;
-			}
-			printk(BIOS_DEBUG, "\n");
-		}
-		printk(BIOS_DEBUG, "biosint: Bailing out\n");
-		// "longjmp"
-		vga_exit();
-		break;
-
-	case PCIBIOS:
-		ret = pcibios( &edi, &esi, &ebp, &esp,
-			       &ebx, &edx, &ecx, &eax, &flags);
-		break;
-	case MEMSIZE:
-		// who cares.
-		eax = 64 * 1024;
-		ret = 0;
-		break;
-	case 0x15:
-		ret=handleint21( &edi, &esi, &ebp, &esp,
-				&ebx, &edx, &ecx, &eax, &flags);
-		break;
-	default:
-		printk(BIOS_INFO, "BIOSINT: Unsupport int #0x%lx\n",
-			    intnumber);
-		break;
-	}
-	if (ret)
-		flags |= 1; // carry flags
-	else
-		flags &= ~1;
-	stackflags = flags;
-	return ret;
-}
-
-void setup_realmode_idt(void)
-{
-	extern unsigned char idthandle, end_idthandle;
-#if 0
-	extern unsigned char debughandle, end_debughandle;
-#endif
-
-	int i;
-	struct realidt *idts = (struct realidt *) 0;
-	int codesize = &end_idthandle - &idthandle;
-	unsigned char *intbyte, *codeptr;
-
-	// for each int, we create a customized little handler
-	// that just pushes %ax, puts the int # in %al,
-	// then calls the common interrupt handler.
-	// this necessitated because intel didn't know much about
-	// architecture when they did the 8086 (it shows)
-	// (hmm do they know anymore even now :-)
-	// obviously you can see I don't really care about memory
-	// efficiency. If I did I would probe back through the stack
-	// and get it that way. But that's really disgusting.
-	for (i = 0; i < 256; i++) {
-		idts[i].cs = 0;
-		codeptr = (unsigned 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 = (unsigned char *) 0xff065;
-	memcpy(codeptr, &idthandle, codesize);
-	intbyte = codeptr + 3;
-	*intbyte = 0x42; /* int42 is the relocated int10 */
-
-	/* The source of the following code is not yet known.
- 	 * We feel it may be useful someday, but right now it
- 	 * scribbles over code space. We are leaving it here as a
- 	 * "Living comment" since it may at some point be needed
- 	 * again. It is a very intriguing idea -- one could run
- 	 * vm86 code with TF set and set programmable times
- 	 * between instructions to slow them down. For those who
- 	 * recall the "turbo" switch on old PCs, this is the
- 	 * software equivalent.
- 	 */
-#if 0
-	/* debug handler - useful to set a programmable delay between instructions if the
-	   TF bit is set upon call to real mode */
-	idts[1].cs = 0;
-	idts[1].offset = 16384;
-	memcpy((void *)16384, &debughandle, &end_debughandle - &debughandle);
-#endif
-}
-
-void run_bios(struct device *dev, unsigned long addr)
-{
-	int i;
-
-	/* clear vga bios data area */
-	for (i = 0x400; i < 0x500; i++) {
-		*(unsigned char *) i = 0;
-	}
-	setup_realmode_idt();
-	real_mode_switch_call_vga((dev->bus->secondary << 8) | dev->path.pci.devfn);
-}
-
-enum {
-	CHECK = 0xb001,
-	FINDDEV = 0xb102,
-	READCONFBYTE = 0xb108,
-	READCONFWORD = 0xb109,
-	READCONFDWORD = 0xb10a,
-	WRITECONFBYTE = 0xb10b,
-	WRITECONFWORD = 0xb10c,
-	WRITECONFDWORD = 0xb10d
-};
-
-// errors go in AH. Just set these up so that word assigns
-// will work. KISS.
-enum {
-	PCIBIOS_NODEV = 0x8600,
-	PCIBIOS_BADREG = 0x8700
-};
-
-int
-pcibios(unsigned long *pedi, unsigned long *pesi, unsigned long *pebp,
-	unsigned long *pesp, unsigned long *pebx, unsigned long *pedx,
-	unsigned long *pecx, unsigned long *peax, unsigned long *pflags)
-{
-	unsigned short func = (unsigned short) *peax;
-	int retval = 0;
-	unsigned short devid, vendorid, devfn;
-	/* Use short to get rid of gabage in upper half of 32-bit register */
-	short devindex;
-	unsigned char bus;
-	struct device *dev;
-
-	switch(func) {
-	case  CHECK:
-		*pedx = 0x4350;
-		*pecx = 0x2049;
-		retval = 0;
-		break;
-	case FINDDEV:
-	{
-		devid = *pecx;
-		vendorid = *pedx;
-		devindex = *pesi;
-		dev = 0;
-#ifdef COREBOOT_V2
-		while ((dev = dev_find_device(vendorid, devid, dev))) {
-#else
-		while ((dev = dev_find_pci_device(vendorid, devid, dev))) {
-#endif
-			if (devindex <= 0)
-				break;
-			devindex--;
-		}
-		if (dev) {
-			unsigned short busdevfn;
-			*peax = 0;
-			// busnum is an unsigned char;
-			// devfn is an int, so we mask it off.
-			busdevfn = (dev->bus->secondary << 8)
-				| (dev->path.pci.devfn & 0xff);
-			printk(BIOS_DEBUG, "0x%x: return 0x%x\n", func, busdevfn);
-			*pebx = busdevfn;
-			retval = 0;
-		} else {
-			*peax = PCIBIOS_NODEV;
-			retval = -1;
-		}
-	}
-	break;
-	case READCONFDWORD:
-	case READCONFWORD:
-	case READCONFBYTE:
-	case WRITECONFDWORD:
-	case WRITECONFWORD:
-	case WRITECONFBYTE:
-	{
-		unsigned long dword;
-		unsigned short word;
-		unsigned char byte;
-		unsigned char reg;
-
-		devfn = *pebx & 0xff;
-		bus = *pebx >> 8;
-		reg = *pedi;
-		dev = dev_find_slot(bus, devfn);
-		if (! dev) {
-			printk(BIOS_DEBUG, "0x%x: BAD DEVICE bus %d devfn 0x%x\n", func, bus, devfn);
-			// idiots. the pcibios guys assumed you'd never pass a bad bus/devfn!
-			*peax = PCIBIOS_BADREG;
-			retval = -1;
-		}
-		switch(func) {
-		case READCONFBYTE:
-			byte = pci_read_config8(dev, reg);
-			*pecx = byte;
-			break;
-		case READCONFWORD:
-			word = pci_read_config16(dev, reg);
-			*pecx = word;
-			break;
-		case READCONFDWORD:
-			dword = pci_read_config32(dev, reg);
-			*pecx = dword;
-			break;
-		case WRITECONFBYTE:
-			byte = *pecx;
-			pci_write_config8(dev, reg, byte);
-			break;
-		case WRITECONFWORD:
-			word = *pecx;
-			pci_write_config16(dev, reg, word);
-			break;
-		case WRITECONFDWORD:
-			dword = *pecx;
-			pci_write_config32(dev, reg, dword);
-			break;
-		}
-
-		if (retval)
-			retval = PCIBIOS_BADREG;
-		printk(BIOS_DEBUG, "0x%x: bus %d devfn 0x%x reg 0x%x val 0x%lx\n",
-			     func, bus, devfn, reg, *pecx);
-		*peax = 0;
-		retval = 0;
-	}
-	break;
-	default:
-		printk(BIOS_ERR, "UNSUPPORTED PCIBIOS FUNCTION 0x%x\n",  func);
-		break;
-	}
-
-	return retval;
-}
-
-int handleint21(unsigned long *edi, unsigned long *esi, unsigned long *ebp,
-		unsigned long *esp, unsigned long *ebx, unsigned long *edx,
-		unsigned long *ecx, unsigned long *eax, unsigned long *flags)
-{
-	int res=-1;
-	switch(*eax&0xffff)
-	{
-	case 0x5f19:
-		break;
-	case 0x5f18:
-		*eax=0x5f;
-		*ebx=0x545; // MCLK = 133, 32M frame buffer, 256 M main memory
-		*ecx=0x060;
-		res=0;
-		break;
-	case 0x5f00:
-		*eax = 0x8600;
-		break;
-	case 0x5f01:
-		*eax = 0x5f;
-		*ecx = (*ecx & 0xffffff00 ) | 2; // panel type =  2 = 1024 * 768
-		res = 0;
-		break;
-	case 0x5f02:
-		*eax=0x5f;
-		*ebx= (*ebx & 0xffff0000) | 2;
-		*ecx= (*ecx & 0xffff0000) | 0x401;  // PAL + crt only
-		*edx= (*edx & 0xffff0000) | 0;  // TV Layout - default
-		res=0;
-		break;
-	case 0x5f0f:
-		*eax=0x860f;
-		break;
-	}
-	return res;
-}

Modified: coreboot-v3/util/x86emu/vm86_gdt.c
===================================================================
--- coreboot-v3/util/x86emu/vm86_gdt.c	2009-05-09 23:36:20 UTC (rev 1166)
+++ coreboot-v3/util/x86emu/vm86_gdt.c	2009-05-29 13:09:57 UTC (rev 1167)
@@ -1,101 +0,0 @@
-/*
- *  Erik Arjan Hendriks <hendriks at lanl.gov>
- *  Copyright (C) 2000 Scyld.
- *  Copyright (C) 2000 Scyld Computing Corporation
- *  Copyright (C) 2001 University of California.  LA-CC Number 01-67.
- *  Copyright (C) 2005 Nick.Barker9 at btinternet.com
- *  Copyright (C) 2007 coresystems GmbH
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- */
-
-
-/* Declare a temporary global descriptor table - 
- * necessary because the core part of the bios 
- * no longer sets up any 16 bit segments 
- */
-
-__asm__ (
-	/* pointer to original gdt */
-	"	.globl gdtarg\n"
-	"gdtarg:			\n"
-	"	.word	gdt_limit	\n"
-#ifdef COREBOOT_V2
-	"	.long	gdt	       	\n"		
-#else
-	"	.long	gdtptr	       	\n"		
-#endif
-
-	/* compute the table limit */
-	"__mygdt_limit = __mygdt_end - __mygdt - 1	\n"
-	"	.globl __mygdtaddr\n"
-	"__mygdtaddr:			\n"
-	"	.word	__mygdt_limit  	\n"
-	"	.long	__mygdt	       	\n"
-
-	"	.globl __mygdt\n"
-	"__mygdt: 		       	\n"
-	/* selgdt 0, unused */
-	"	.word	0x0000, 0x0000	\n"
-	"	.byte	0x00, 0x00, 0x00, 0x00	\n"
-
-	/* selgdt 8, unused */
-	"	.word	0x0000, 0x0000	       	\n"
-	"	.byte	0x00, 0x00, 0x00, 0x00	\n"
-
-	/* selgdt 0x10, flat code segment */
-	"	.word	0xffff, 0x0000	       	\n"
-	"	.byte	0x00, 0x9b, 0xcf, 0x00	\n"	
-
-	/* selgdt 0x18, flat data segment */
-	"	.word	0xffff, 0x0000	       	\n"
-	"	.byte	0x00, 0x93, 0xcf, 0x00	\n"
-
-	/* selgdt 0x20, unused */
-	"	.word	0x0000, 0x0000	       	\n"
-	"	.byte	0x00, 0x00, 0x00, 0x00	\n"
-
-        /* selgdt 0x28 16-bit 64k code at 0x00000000 */
-	"	.word	0xffff, 0x0000	       	\n"
-	"	.byte	0, 0x9a, 0, 0	       	\n"
-
-	/* selgdt 0x30 16-bit 64k data at 0x00000000 */
-	"	.word	0xffff, 0x0000	       	\n"
-	"	.byte	0, 0x92, 0, 0	       	\n"
-
-	"__mygdt_end:				\n"
-
-#ifndef COREBOOT_V2
-	/* FIXME: This does probably not belong here */
-	"	.globl idtarg\n"
-	"idtarg:\n"
-	"	.word   _idt_end - _idt - 1\n"     /* limit */
-	"	.long   _idt\n"
-	"	.word   0\n"
-	"_idt:\n"
-	"	.fill   20, 8, 0\n" //       # idt is unitiailzed
-	"_idt_end:\n"
-#endif
-
-	/* Declare a pointer to where our idt is going to be i.e. at mem zero */
-	"	.globl __myidt\n"
-	 "__myidt:		\n"
-	 /* 16-bit limit */
-	 "	.word 1023	\n"
-	 /* 24-bit base */
-	 "	.long 0		\n"
-	 "	.word 0		\n"
-);

Added: coreboot-v3/util/x86emu/x86.c
===================================================================
--- coreboot-v3/util/x86emu/x86.c	                        (rev 0)
+++ coreboot-v3/util/x86emu/x86.c	2009-05-29 13:09:57 UTC (rev 1167)
@@ -0,0 +1,228 @@
+/*
+ *  Copyright (C) 2009 coresystems GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <device/pci.h>
+#include <string.h>
+
+#ifdef COREBOOT_V2
+#include <arch/io.h>
+#include <console/console.h>
+#define printk(x...) do_printk(x)
+#else
+#include <console.h>
+#endif
+
+#define REALMODE_BASE ((void *)0x500)
+
+struct realmode_idt {
+	u16 offset, cs;
+};
+
+struct eregs {
+	uint32_t eax, ecx, edx, ebx, esp, ebp, esi, edi;
+	uint32_t vector;
+	uint32_t error_code;
+	uint32_t eip;
+	uint32_t cs;
+	uint32_t eflags;
+};
+
+void x86_exception(struct eregs *info);
+
+extern unsigned char __idt_handler, __idt_handler_size;
+extern unsigned char __realmode_code, __realmode_code_size;
+extern unsigned char __run_optionrom, __run_interrupt;
+
+void (*run_optionrom)(u32 devfn) = (void *)&__run_optionrom;
+void (*vga_enable_console)(void) = (void *)&__run_interrupt;
+
+int (*intXX_handler[256])(struct eregs *regs) = { NULL };
+
+static int intXX_exception_handler(struct eregs *regs)
+{
+	printk(BIOS_INFO, "Oops, exception %d while executing option rom\n", 
+			regs->vector);
+	x86_exception(regs);	// Call coreboot exception handler 
+
+	return 0;		// Never returns?
+}
+
+static int intXX_unknown_handler(struct eregs *regs)
+{
+	printk(BIOS_INFO, "Unsupported software interrupt #0x%x\n", 
+			regs->vector);
+
+	return -1;
+}
+
+int int12_handler(struct eregs *regs);
+int int15_handler(struct eregs *regs);
+int int1a_handler(struct eregs *regs);
+
+static void setup_interrupt_handlers(void)
+{
+	int i;
+
+	/* The first 16 intXX functions are not BIOS services, 
+	 * but the CPU-generated exceptions ("hardware interrupts")
+	 */
+	for (i = 0; i < 0x10; i++)
+		intXX_handler[i] = &intXX_exception_handler;
+	
+	/* Mark all other intXX calls as unknown first */
+	for (i = 0x10; i < 0x100; i++)
+		intXX_handler[i] = &intXX_unknown_handler;
+
+	/* Now set the default functions that are actually
+	 * needed to initialize the option roms. This is very
+	 * slick, as it allows us to implement mainboard specific
+	 * interrupt handlers, such as the int15
+	 */
+	intXX_handler[0x12] = &int12_handler;
+	intXX_handler[0x15] = &int15_handler;
+	intXX_handler[0x1a] = &int1a_handler;
+}
+
+static void write_idt_stub(void *target, u8 intnum)
+{
+	unsigned char *codeptr;
+	codeptr = (unsigned char *) target;
+	memcpy(codeptr, &__idt_handler, (size_t)&__idt_handler_size);
+	codeptr[3] = intnum; /* modify int# in the code stub. */
+}
+
+static void setup_realmode_idt(void)
+{
+	struct realmode_idt *idts = (struct realmode_idt *) 0;
+	int i;
+
+	/* Copy IDT stub code for each interrupt. This might seem wasteful
+	 * but it is really simple
+	 */
+	 for (i = 0; i < 256; i++) {
+		idts[i].cs = 0;
+		idts[i].offset = 0x1000 + (i * (u32)&__idt_handler_size);
+		write_idt_stub((void *)((u32 )idts[i].offset), i);
+	}
+
+	/* Many option ROMs use the hard coded interrupt entry points in the
+	 * system bios. So install them at the known locations. 
+	 * Only need int10 so far.
+	 */
+	
+	/* int42 is the relocated int10 */
+	write_idt_stub((void *)0xff065, 0x42); 
+}
+
+void run_bios(struct device *dev, unsigned long addr)
+{
+	int i;
+
+	/* clear vga bios data area */
+	for (i = 0x400; i < 0x500; i++) {
+		*(unsigned char *) i = 0;
+	}
+	
+	/* Set up C interrupt handlers */
+	setup_interrupt_handlers();
+
+	/* Setting up realmode IDT */
+	setup_realmode_idt();
+
+	memcpy(REALMODE_BASE, &__realmode_code, (size_t)&__realmode_code_size);
+	printk(BIOS_SPEW, "Real mode stub @%p: %d bytes\n", REALMODE_BASE,
+			(u32)&__realmode_code_size);
+
+	printk(BIOS_DEBUG, "Calling Option Rom...\n");
+	run_optionrom((dev->bus->secondary << 8) | dev->path.pci.devfn);
+}
+
+int __attribute__((regparm(0))) interrupt_handler(u32 intnumber,
+	    u32 gsfs, u32 dses,
+	    u32 edi, u32 esi,
+	    u32 ebp, u32 esp,
+	    u32 ebx, u32 edx,
+	    u32 ecx, u32 eax,
+	    u32 cs_ip, u16 stackflags)
+{
+	u32 ip;
+	u32 cs;
+	u32 flags;
+	int ret = -1;
+	struct eregs reg_info;
+
+	ip = cs_ip & 0xffff;
+	cs = cs_ip >> 16;
+	flags = stackflags;
+
+	printk(BIOS_DEBUG, "oprom: INT# 0x%x\n", intnumber);
+	printk(BIOS_DEBUG, "oprom: eax: %08x ebx: %08x ecx: %08x edx: %08x\n",
+		      eax, ebx, ecx, edx);
+	printk(BIOS_DEBUG, "oprom: ebp: %08x esp: %08x edi: %08x esi: %08x\n",
+		     ebp, esp, edi, esi);
+	printk(BIOS_DEBUG, "oprom:  ip: %04x      cs: %04x   flags: %08x\n",
+		     ip, cs, flags);
+
+	// Fetch arguments from the stack and put them into
+	// a structure that we want to pass on to our sub interrupt
+	// handlers.
+	reg_info = (struct eregs) {
+		.eax=eax,
+		.ecx=ecx,
+		.edx=edx,
+		.ebx=ebx,
+		.esp=esp,
+		.ebp=ebp,
+		.esi=esi,
+		.edi=edi,
+		.vector=intnumber,
+		.error_code=0, // ??
+		.eip=ip,
+		.cs=cs,
+		.eflags=flags // ??
+	};
+
+	// Call the interrupt handler for this int#
+	ret = intXX_handler[intnumber](&reg_info);
+
+	// Put registers back on the stack. The assembler code
+	// will later pop them.
+	// What happens here is that we force (volatile!) changing
+	// the values of the parameters of this function. We do this
+	// because we know that they stay alive on the stack after 
+	// we leave this function. Don't say this is bollocks.
+	*(volatile u32 *)&eax = reg_info.eax;
+	*(volatile u32 *)&ecx = reg_info.ecx;
+	*(volatile u32 *)&edx = reg_info.edx;
+	*(volatile u32 *)&ebx = reg_info.ebx;
+	*(volatile u32 *)&esi = reg_info.esi;
+	*(volatile u32 *)&edi = reg_info.edi;
+	flags = reg_info.eflags;
+
+	/* Pass errors back to our caller via the CARRY flag */
+	if (ret) {
+		printk(BIOS_DEBUG,"error!\n");
+		flags |= 1;  // error: set carry
+	}else{
+		flags &= ~1; // no error: clear carry
+	}
+	*(volatile u16 *)&stackflags = flags;
+
+	return ret;
+}
+

Added: coreboot-v3/util/x86emu/x86_asm.S
===================================================================
--- coreboot-v3/util/x86emu/x86_asm.S	                        (rev 0)
+++ coreboot-v3/util/x86emu/x86_asm.S	2009-05-29 13:09:57 UTC (rev 1167)
@@ -0,0 +1,392 @@
+/*
+ *  Copyright (C) 2009 coresystems GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#define REALMODE_BASE		0x500
+#define RELOCATED(x)	(x - __realmode_code + REALMODE_BASE)
+
+/* CR0 bits */
+#define PE		(1 << 0)
+
+/* This is the intXX interrupt handler stub code. It gets copied
+ * to the IDT and to some fixed addresses in the F segment. Before
+ * the code can used, it gets patched up by the C function copying 
+ * it: byte 3 (the $0 in movb $0, %al) is overwritten with the int#.
+ */
+
+	.code16
+	.globl __idt_handler
+__idt_handler:
+	pushal
+	movb 	$0, %al /* This instruction gets modified */
+	ljmp 	$0, $__interrupt_handler_16bit
+	.globl __idt_handler_size
+__idt_handler_size = ( . - __idt_handler)
+
+
+/* In order to be independent of coreboot's position in RAM
+ * we relocate a part of the code to the low megabyte, so the
+ * CPU can use it in real-mode. This code lives at __realmode_code.
+ */
+	.globl __realmode_code
+__realmode_code:
+
+/* Realmode IDT pointer structure. */
+	.globl __realmode_idt
+__realmode_idt = RELOCATED(.)
+	.word 1023	/* 16-bit limit */
+	.long 0		/* 24-bit base */
+	.word 0
+
+/* Preserve old stack */
+__stack = RELOCATED(.)
+	.long 0
+
+	.code32
+	.globl __run_optionrom
+__run_optionrom = RELOCATED(.)
+	/* save all registers to the stack */
+	pushal
+
+	/* Move the protected mode stack to a safe place */
+	mov 	%esp, __stack
+
+	/* Get devfn into %ecx */
+	movl    %esp, %ebp
+	// FIXME: Should this function be called with regparm=0?
+	movl    8(%ebp), %ecx
+
+	/* Clear interrupts before making a
+	 * transition to Real Mode
+	 */
+	cli
+
+	/* Activate the right segment descriptor real mode. */
+	ljmp	$0x28, $RELOCATED(1f)
+1:
+.code16
+	/* 16 bit code from here on... */
+
+	/* 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
+	mov	%ax, %ds       
+	mov	%ax, %es       
+	mov	%ax, %fs       
+	mov	%ax, %gs       
+	mov	%ax, %ss       
+
+	/* Turn off protection */
+	movl	%cr0, %eax
+	andl	$~PE, %eax
+	movl	%eax, %cr0
+
+	/* Now really going into real mode */
+	ljmp	$0, $RELOCATED(1f)
+1:
+	/* Setup a stack: 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. */
+	mov	$0x0, %ax
+	mov	%ax, %ss
+	movl	$0x1000, %eax
+	movl	%eax, %esp
+
+	/* Load our 16 it idt */
+	xor	%ax, %ax
+	mov	%ax, %ds
+	lidt	__realmode_idt
+
+	/* All critical work is done, allow interrupts again */
+	sti
+
+	/* Set all segments to 0x0000, ds to 0x0040 */
+	mov	%ax, %es       
+	mov	%ax, %fs       
+	mov	%ax, %gs       
+	mov	$0x40, %ax
+	mov	%ax, %ds
+	mov	%cx, %ax	// restore ax
+
+	/* ************************************ */
+	// TODO this will not work for non-VGA option ROMs
+	/* run VGA BIOS at 0xc000:0003 */
+	lcall	$0xc000, $0x0003
+	/* ************************************ */
+
+	/* Clear interrupts before making a 
+	 * transition to Protected Mode
+	 */
+	cli
+
+	/* If we got here, just about done.
+	 * Need to get back to protected mode
+	 */
+	movl	%cr0, %eax
+	orl	$PE, %eax
+	movl	%eax, %cr0
+
+	/* Now that we are in protected mode
+	 * jump to a 32 bit code segment.
+	 */
+	data32	ljmp	$0x10, $RELOCATED(1f)
+1:
+	.code32
+	movw	$0x18, %ax     
+	mov	%ax, %ds       
+	mov	%ax, %es
+	mov	%ax, %fs
+	mov	%ax, %gs
+	mov	%ax, %ss
+
+	/* restore proper idt */
+	lidt	idtarg
+
+	/* All critical work is done, allow interrupts again */
+	sti
+
+	/* and exit */
+	mov	__stack, %esp
+	popal
+	ret
+
+	.globl __run_interrupt
+__run_interrupt = RELOCATED(.)
+
+	/* paranoia -- does ecx get saved? not sure. This is
+	 * the easiest safe thing to do. */
+	pushal
+	/* save the stack */
+	mov	%esp, __stack
+
+
+	/* Clear interrupts before making a 
+	 * transition to Real Mode
+	 */
+	cli
+
+	/*  This configures CS properly for real mode. */
+	ljmp 	$0x28, $RELOCATED(1f)
+1:
+	.code16 /* 16 bit code from here on... */
+
+	// DEBUG
+	movb    $0xec, %al
+	outb    %al, $0x80
+
+	/* 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     
+	mov	%ax, %ds       
+	mov	%ax, %es       
+	mov	%ax, %fs       
+	mov	%ax, %gs       
+	mov	%ax, %ss       
+
+	/* Turn off protected mode */
+	movl	%cr0, %eax     
+	andl	$~PE, %eax
+	movl	%eax, %cr0     
+
+	/* Now really going into real mode */
+	data32 ljmp	$0, $RELOCATED(1f)
+1:
+
+	/* 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
+	mov	%ax, %ss
+	movl	$0x1000, %eax
+	movl	%eax, %esp
+
+	/* Load 16-bit intXX IDT */
+	xor	%ax, %ax       
+	mov	%ax, %ds
+	lidt	__realmode_idt
+
+	/* All critical work is done, allow interrupts again */
+	sti
+
+	/* Set all segments to 0x0000 */
+	mov	%ax, %ds
+	mov	%ax, %es
+	mov	%ax, %fs
+	mov	%ax, %gs
+
+	/* Call VGA BIOS int10 function 0x4f14 to enable main console
+	 * Epia-M does not always autosence the main console so forcing
+	 * it on is good.
+	 */
+
+	/* Ask VGA option rom to enable main console */
+	movw	$0x4f14,%ax
+	movw	$0x8003,%bx
+	movw	$1, %cx
+	movw	$0, %dx
+	movw	$0, %di
+	int	$0x10
+
+	/* Clear interrupts before making a 
+	 * transition to Protected Mode
+	 */
+	cli
+
+	/* Ok, the job is done, now go back to protected mode coreboot */
+	movl	%cr0, %eax
+	orl	$PE, %eax
+	movl	%eax, %cr0
+
+	/* Now that we are in protected mode jump to a 32-bit code segment. */
+	data32	ljmp	$0x10, $RELOCATED(1f)
+1:
+	.code32
+	movw	$0x18, %ax
+	mov	%ax, %ds
+	mov	%ax, %es
+	mov	%ax, %fs
+	mov	%ax, %gs
+	mov	%ax, %ss
+
+	/* restore coreboot's 32-bit IDT */
+	lidt	idtarg
+
+	/* All critical work is done, allow interrupts again */
+	sti
+
+	/* Exit */
+	mov	__stack, %esp
+	popal
+	ret
+
+/* This is the 16-bit interrupt entry point called by the IDT stub code.
+ * Before this code code is called, %eax is pushed to the stack, and the
+ * interrupt number is loaded into %al
+ */
+	.code16
+__interrupt_handler_16bit = RELOCATED(.)
+	push	%ds
+	push	%es
+	push	%fs
+	push	%gs
+
+	/* Clean up the interrupt number. We could have done this in the stub,
+	 * but it would have cost 2 more bytes per stub entry.
+	 */
+	andl	$0xff, %eax
+	pushl	%eax		/* ... and make it the first parameter */
+
+	/* Clear interrupts before making a 
+	 * transition to Protected Mode
+	 */
+	cli
+
+	/* Switch to protected mode */
+	movl    %cr0, %eax
+	orl	$PE, %eax
+	movl	%eax, %cr0
+
+	/* ... and jump to a 32 bit code segment. */
+	data32 ljmp    $0x10, $RELOCATED(1f)
+1:
+	.code32
+	movw	$0x18, %ax
+	mov	%ax, %ds
+	mov	%ax, %es
+	mov	%ax, %fs
+	mov	%ax, %gs
+	mov	%ax, %ss
+
+	lidt	idtarg
+
+	/* All critical work is done, allow interrupts again */
+	sti
+
+	/* Call the C interrupt handler */
+	movl	$interrupt_handler, %eax
+	call	*%eax
+
+	/* Now return to real mode ... */
+	ljmp	$0x28, $RELOCATED(1f)
+1:
+	.code16
+	/* Load the segment registers with properly configured segment
+	 * descriptors.  They will retain these configurations (limits,
+	 * writability, etc.) once protected mode is turned off.
+	 */
+	mov	$0x30, %ax
+	mov	%ax, %ds
+	mov	%ax, %es
+	mov	%ax, %fs
+	mov	%ax, %gs
+	mov	%ax, %ss
+
+	/* Clear interrupts before making a 
+	 * transition to Real Mode
+	 */
+	cli
+
+	/* Disable Protected Mode */
+	movl	%cr0, %eax
+	andl	$~PE, %eax
+	movl	%eax, %cr0
+
+	/* Now really going into real mode */
+	ljmp $0,  $RELOCATED(1f)
+1:
+	/* Restore real-mode stack segment */
+	mov	$0x0, %ax
+	mov	%ax, %ss
+
+	/* Restore 16-bit IDT */
+	xor	%ax, %ax
+	mov	%ax, %ds
+	lidt	__realmode_idt
+
+	/* All critical work is done, allow interrupts again */
+	sti
+
+	/* Set up our segment registers to segment 0x0000 */
+	mov	%ax, %es
+	mov	%ax, %fs
+	mov	%ax, %gs
+	mov	$0x40, %ax
+	mov	%ax, %ds
+
+	/* Restore all registers, including those
+	 * manipulated by the C handler
+	 */
+	popl	%eax
+	pop	%gs
+	pop	%fs
+	pop	%es
+	pop	%ds
+	popal
+	iret
+
+	.globl __realmode_code_size
+__realmode_code_size = (. - __realmode_code)
+
+	.code32

Added: coreboot-v3/util/x86emu/x86_interrupts.c
===================================================================
--- coreboot-v3/util/x86emu/x86_interrupts.c	                        (rev 0)
+++ coreboot-v3/util/x86emu/x86_interrupts.c	2009-05-29 13:09:57 UTC (rev 1167)
@@ -0,0 +1,243 @@
+/*
+ *  Copyright (C) 2001 Ronald G. Minnich
+ *  Copyright (C) 2005 Nick.Barker9 at btinternet.com
+ *  Copyright (C) 2007-2009 coresystems GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <string.h>
+#ifdef COREBOOT_V2
+#include <console/console.h>
+#include <arch/io.h>
+#define printk(x...) do_printk(x)
+#else
+#include <console.h>
+#include <io.h>
+#endif
+
+struct eregs {
+	uint32_t eax, ecx, edx, ebx, esp, ebp, esi, edi;
+	uint32_t vector;
+	uint32_t error_code;
+	uint32_t eip;
+	uint32_t cs;
+	uint32_t eflags;
+};
+
+enum {
+	CHECK = 0xb001,
+	FINDDEV = 0xb102,
+	READCONFBYTE = 0xb108,
+	READCONFWORD = 0xb109,
+	READCONFDWORD = 0xb10a,
+	WRITECONFBYTE = 0xb10b,
+	WRITECONFWORD = 0xb10c,
+	WRITECONFDWORD = 0xb10d
+};
+
+// errors go in AH. Just set these up so that word assigns
+// will work. KISS.
+enum {
+	PCIBIOS_NODEV = 0x8600,
+	PCIBIOS_BADREG = 0x8700
+};
+
+int int12_handler(struct eregs *regs)
+{
+	regs->eax = 64 * 1024;
+	return 0;
+}
+
+int int1a_handler(struct eregs *regs)
+{
+	unsigned short func = (unsigned short) regs->eax;
+	int retval = 0;
+	unsigned short devid, vendorid, devfn;
+	/* Use short to get rid of gabage in upper half of 32-bit register */
+	short devindex;
+	unsigned char bus;
+	struct device *dev;
+
+	switch(func) {
+	case  CHECK:
+		regs->edx = 0x4350;
+		regs->ecx = 0x2049;
+		retval = 0;
+		break;
+	case FINDDEV:
+	{
+		devid = regs->ecx;
+		vendorid = regs->edx;
+		devindex = regs->esi;
+		dev = 0;
+#ifdef COREBOOT_V2
+		while ((dev = dev_find_device(vendorid, devid, dev))) {
+#else
+		while ((dev = dev_find_pci_device(vendorid, devid, dev))) {
+#endif
+			if (devindex <= 0)
+				break;
+			devindex--;
+		}
+		if (dev) {
+			unsigned short busdevfn;
+			regs->eax = 0;
+			// busnum is an unsigned char;
+			// devfn is an int, so we mask it off.
+			busdevfn = (dev->bus->secondary << 8)
+				| (dev->path.pci.devfn & 0xff);
+			printk(BIOS_DEBUG, "0x%x: return 0x%x\n", func, busdevfn);
+			regs->ebx = busdevfn;
+			retval = 0;
+		} else {
+			regs->eax = PCIBIOS_NODEV;
+			retval = -1;
+		}
+	}
+	break;
+	case READCONFDWORD:
+	case READCONFWORD:
+	case READCONFBYTE:
+	case WRITECONFDWORD:
+	case WRITECONFWORD:
+	case WRITECONFBYTE:
+	{
+		unsigned long dword;
+		unsigned short word;
+		unsigned char byte;
+		unsigned char reg;
+
+		devfn = regs->ebx & 0xff;
+		bus = regs->ebx >> 8;
+		reg = regs->edi;
+		dev = dev_find_slot(bus, devfn);
+		if (! dev) {
+			printk(BIOS_DEBUG, "0x%x: BAD DEVICE bus %d devfn 0x%x\n", func, bus, devfn);
+			// idiots. the pcibios guys assumed you'd never pass a bad bus/devfn!
+			regs->eax = PCIBIOS_BADREG;
+			retval = -1;
+		}
+		switch(func) {
+		case READCONFBYTE:
+			byte = pci_read_config8(dev, reg);
+			regs->ecx = byte;
+			break;
+		case READCONFWORD:
+			word = pci_read_config16(dev, reg);
+			regs->ecx = word;
+			break;
+		case READCONFDWORD:
+			dword = pci_read_config32(dev, reg);
+			regs->ecx = dword;
+			break;
+		case WRITECONFBYTE:
+			byte = regs->ecx;
+			pci_write_config8(dev, reg, byte);
+			break;
+		case WRITECONFWORD:
+			word = regs->ecx;
+			pci_write_config16(dev, reg, word);
+			break;
+		case WRITECONFDWORD:
+			dword = regs->ecx;
+			pci_write_config32(dev, reg, dword);
+			break;
+		}
+
+		if (retval)
+			retval = PCIBIOS_BADREG;
+		printk(BIOS_DEBUG, "0x%x: bus %d devfn 0x%x reg 0x%x val 0x%x\n",
+			     func, bus, devfn, reg, regs->ecx);
+		regs->eax = 0;
+		retval = 0;
+	}
+	break;
+	default:
+		printk(BIOS_ERR, "UNSUPPORTED PCIBIOS FUNCTION 0x%x\n",  func);
+		break;
+	}
+
+	return retval;
+}
+
+int int15_handler(struct eregs *regs)
+{
+	int res = -1;
+
+	/* This int15 handler is VIA Tech. specific. Other chipsets need other
+	 * handlers. The right way to do this is to move this handler code into
+	 * the mainboard or northbridge code.
+	 */
+	switch (regs->eax & 0xffff) {
+	case 0x5f19:
+		break;
+	case 0x5f18:
+		regs->eax = 0x5f;
+		// MCLK = 133, 32M frame buffer, 256 M main memory
+		regs->ebx = 0x545;
+		regs->ecx = 0x060;
+		res = 0;
+		break;
+	case 0x5f00:
+		regs->eax = 0x8600;
+		break;
+	case 0x5f01:
+		regs->eax = 0x5f;
+		regs->ecx = (regs->ecx & 0xffffff00 ) | 2; // panel type =  2 = 1024 * 768
+		res = 0;
+		break;
+	case 0x5f02:
+		regs->eax = 0x5f;
+		regs->ebx = (regs->ebx & 0xffff0000) | 2;
+		regs->ecx = (regs->ecx & 0xffff0000) | 0x401;  // PAL + crt only
+		regs->edx = (regs->edx & 0xffff0000) | 0;  // TV Layout - default
+		res = 0;
+		break;
+	case 0x5f0f:
+		regs->eax = 0x860f;
+		break;
+	/* And now Intel IGD code */
+#define BOOT_DISPLAY_CRT        (1 << 0)
+#define BOOT_DISPLAY_TV         (1 << 1)
+#define BOOT_DISPLAY_EFP        (1 << 2)
+#define BOOT_DISPLAY_LCD        (1 << 3)
+#define BOOT_DISPLAY_CRT2       (1 << 4)
+#define BOOT_DISPLAY_TV2        (1 << 5)
+#define BOOT_DISPLAY_EFP2       (1 << 6)
+#define BOOT_DISPLAY_LCD2       (1 << 7)
+
+	case 0x5f35:
+		regs->eax = 0x5f;
+		regs->ecx = BOOT_DISPLAY_LCD|BOOT_DISPLAY_CRT;
+		res = 0;
+		break;
+	case 0x5f40:
+		regs->eax = 0x5f;
+		regs->ecx = 3; // This is mainboard specific
+		printk(BIOS_DEBUG, "DISPLAY=%x\n", regs->ecx);
+		res = 0;
+		break;
+	default:
+		printk(BIOS_DEBUG, "Unknown INT15 function %04x!\n", 
+				regs->eax & 0xffff);
+	}
+
+	return res;
+}
+





More information about the coreboot mailing list