* Patch by Daniel Engström, 13 Nov 2002:
  Add support for i386 architecture and AMD SC520 board

* Patch by Pierre Aubert, 12 Nov 2002:
  Add support for DOS filesystem and booting from DOS floppy disk
diff --git a/cpu/i386/Makefile b/cpu/i386/Makefile
new file mode 100644
index 0000000..1482398
--- /dev/null
+++ b/cpu/i386/Makefile
@@ -0,0 +1,43 @@
+#
+# (C) Copyright 2002
+# Daniel Engström, Omicron Ceti AB, daniel@omicron.se.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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 $(TOPDIR)/config.mk
+
+LIB	= lib$(CPU).a
+
+START	= start.o start16.o reset.o 
+OBJS	= serial.o interrupts.o cpu.o timer.o
+	  
+all:	.depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(AR) crv $@ $(OBJS)
+
+#########################################################################
+
+.depend:	Makefile $(START:.o=.S) $(OBJS:.o=.c)
+		$(CC) -M $(CFLAGS) $(START:.o=.S) $(OBJS:.o=.c) > $@
+
+sinclude .depend
+
+#########################################################################
diff --git a/cpu/i386/config.mk b/cpu/i386/config.mk
new file mode 100644
index 0000000..70caeb2
--- /dev/null
+++ b/cpu/i386/config.mk
@@ -0,0 +1,26 @@
+#
+# (C) Copyright 2002
+# Daniel Engström, Omicron Ceti AB, daniel@omicron.se.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+PLATFORM_RELFLAGS += # -pipe -mpreferred-stack-boundary=2 -fno-builtin -nostdinc -nostdlib
+
+PLATFORM_CPPFLAGS += -march=i386
diff --git a/cpu/i386/cpu.c b/cpu/i386/cpu.c
new file mode 100644
index 0000000..669823f
--- /dev/null
+++ b/cpu/i386/cpu.c
@@ -0,0 +1,62 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se.
+ * 
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Alex Zuepke <azu@sysgo.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ */
+
+/*
+ * CPU specific code
+ */
+
+#include <common.h>
+#include <command.h>
+
+int cpu_init(void)
+{
+	return 0;
+}
+
+int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	extern void reset_cpu(ulong addr);
+
+	printf ("resetting ...\n");
+	udelay(50000);				/* wait 50 ms */
+	disable_interrupts();
+	reset_cpu(0);
+
+	/*NOTREACHED*/
+	return 0;
+}
+
+void  flush_cache (unsigned long dummy1, unsigned long dummy2)
+{
+	asm("wbinvd\n");
+	return;
+}
+
diff --git a/cpu/i386/interrupts.c b/cpu/i386/interrupts.c
new file mode 100644
index 0000000..81d6881
--- /dev/null
+++ b/cpu/i386/interrupts.c
@@ -0,0 +1,583 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 <common.h>
+#include <syscall.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/i8259.h>
+#include <asm/ibmpc.h>
+
+
+#if 0
+/* done */
+int	interrupt_init     (void);
+void	irq_install_handler(int, interrupt_handler_t *, void *);
+void	irq_free_handler   (int);
+void	enable_interrupts  (void);
+int	disable_interrupts (void);
+
+/* todo */
+void	timer_interrupt    (struct pt_regs *);
+void	external_interrupt (struct pt_regs *);
+void	reset_timer	   (void);
+ulong	get_timer	   (ulong base);
+void	set_timer	   (ulong t);
+
+#endif
+
+struct idt_entry {
+	u16	base_low;
+	u16	selector;
+	u8	res;
+	u8	access;
+	u16	base_high;
+} __attribute__ ((packed));
+
+
+struct idt_entry idt[256];
+
+
+#define MAX_IRQ 16
+
+typedef struct irq_handler { 
+	struct irq_handler *next;
+	interrupt_handler_t* isr_func;
+	void *isr_data;
+} irq_handler_t;
+
+#define IRQ_DISABLED   1
+
+typedef struct {
+	irq_handler_t *handler;
+	unsigned long status;
+} irq_desc_t;
+
+static irq_desc_t irq_table[MAX_IRQ];
+
+
+/* syscall stuff, very untested 
+ * the current approach which includes copying
+ * part of the stack will work badly for 
+ * varargs functions.
+ * if we were to store the top three words on the
+ * stack (eip, ss, eflags) somwhere and add 14 to
+ * %esp ....
+ */
+asm(".globl syscall_entry\n" \
+        "syscall_entry:\n" \
+        "movl   12(%esp), %eax\n" \
+	"movl   %esp, %ebx\n" \
+        "addl   $16, %ebx\n" \
+        "pushl  %ebx\n" \
+        "pushl  %eax\n" \
+        "call   do_syscall\n" \
+        "addl   $8, %esp\n" \
+        "iret\n");
+
+void __attribute__ ((regparm(0))) syscall_entry(void);
+
+int __attribute__ ((regparm(0))) do_syscall(u32 nr, u32 *stack)
+{
+	if (nr<NR_SYSCALLS) {
+		/* We copy 8 args of the syscall,
+		 * this will be a problem with the 
+		 * printf syscall .... */
+		int (*fp)(u32, u32, u32, u32,
+			  u32, u32, u32, u32);
+		fp = syscall_tbl[nr];
+		return fp(stack[0], stack[1], stack[2], stack[3],
+					     stack[4], stack[5], stack[6], stack[7]);
+	}
+	
+	return -1;
+}
+	
+
+asm ("irq_return:\n"
+     "     addl  $4, %esp\n"
+     "     popa\n"
+     "     iret\n");
+
+asm ("exp_return:\n"
+     "     addl  $12, %esp\n"
+     "     pop   %esp\n"
+     "     popa\n"
+     "     iret\n");
+
+char exception_stack[4096];
+
+#define DECLARE_INTERRUPT(x) \
+	asm(".globl irq_"#x"\n" \
+		    "irq_"#x":\n" \
+		    "pusha \n" \
+		    "pushl $"#x"\n" \
+		    "pushl $irq_return\n" \
+                    "jmp   do_irq\n"); \
+	void __attribute__ ((regparm(0))) irq_##x(void)
+
+#define DECLARE_EXCEPTION(x, f) \
+	asm(".globl exp_"#x"\n" \
+		    "exp_"#x":\n" \
+		    "pusha \n" \
+		    "movl     %esp, %ebx\n" \
+		    "movl     $exception_stack, %eax\n" \
+		    "movl     %eax, %esp \n" \
+		    "pushl    %ebx\n" \
+		    "movl     32(%esp), %ebx\n" \
+		    "xorl     %edx, %edx\n" \
+		    "movw     36(%esp), %dx\n" \
+		    "pushl    %edx\n" \
+		    "pushl    %ebx\n" \
+		    "pushl    $"#x"\n" \
+		    "pushl    $exp_return\n" \
+		    "jmp      "#f"\n"); \
+	void __attribute__ ((regparm(0))) exp_##x(void)
+
+DECLARE_EXCEPTION(0, divide_exception_entry);      /* Divide exception */
+DECLARE_EXCEPTION(1, debug_exception_entry);       /* Debug exception */
+DECLARE_EXCEPTION(2, nmi_entry);                   /* NMI */
+DECLARE_EXCEPTION(3, unknown_exception_entry);     /* Breakpoint/Coprocessor Error */
+DECLARE_EXCEPTION(4, unknown_exception_entry);     /* Overflow */
+DECLARE_EXCEPTION(5, unknown_exception_entry);     /* Bounds */
+DECLARE_EXCEPTION(6, invalid_instruction_entry);   /* Invalid instruction */
+DECLARE_EXCEPTION(7, unknown_exception_entry);     /* Device not present */
+DECLARE_EXCEPTION(8, double_fault_entry);          /* Double fault */
+DECLARE_EXCEPTION(9, unknown_exception_entry);     /* Co-processor segment overrun */
+DECLARE_EXCEPTION(10, invalid_tss_exception_entry);/* Invalid TSS */
+DECLARE_EXCEPTION(11, seg_fault_entry);            /* Segment not present */
+DECLARE_EXCEPTION(12, stack_fault_entry);          /* Stack overflow */
+DECLARE_EXCEPTION(13, gpf_entry);                  /* GPF */
+DECLARE_EXCEPTION(14, page_fault_entry);           /* PF */
+DECLARE_EXCEPTION(15, unknown_exception_entry);    /* Reserved */
+DECLARE_EXCEPTION(16, fp_exception_entry);         /* Floating point */
+DECLARE_EXCEPTION(17, alignment_check_entry);      /* alignment check */
+DECLARE_EXCEPTION(18, machine_check_entry);        /* machine check */
+DECLARE_EXCEPTION(19, unknown_exception_entry);    /* Reserved */
+DECLARE_EXCEPTION(20, unknown_exception_entry);    /* Reserved */
+DECLARE_EXCEPTION(21, unknown_exception_entry);    /* Reserved */
+DECLARE_EXCEPTION(22, unknown_exception_entry);    /* Reserved */
+DECLARE_EXCEPTION(23, unknown_exception_entry);    /* Reserved */
+DECLARE_EXCEPTION(24, unknown_exception_entry);    /* Reserved */
+DECLARE_EXCEPTION(25, unknown_exception_entry);    /* Reserved */
+DECLARE_EXCEPTION(26, unknown_exception_entry);    /* Reserved */
+DECLARE_EXCEPTION(27, unknown_exception_entry);    /* Reserved */
+DECLARE_EXCEPTION(28, unknown_exception_entry);    /* Reserved */
+DECLARE_EXCEPTION(29, unknown_exception_entry);    /* Reserved */
+DECLARE_EXCEPTION(30, unknown_exception_entry);    /* Reserved */
+DECLARE_EXCEPTION(31, unknown_exception_entry);    /* Reserved */
+
+DECLARE_INTERRUPT(0);
+DECLARE_INTERRUPT(1);
+DECLARE_INTERRUPT(3);
+DECLARE_INTERRUPT(4);
+DECLARE_INTERRUPT(5);
+DECLARE_INTERRUPT(6);
+DECLARE_INTERRUPT(7);
+DECLARE_INTERRUPT(8);
+DECLARE_INTERRUPT(9);
+DECLARE_INTERRUPT(10);
+DECLARE_INTERRUPT(11);
+DECLARE_INTERRUPT(12);
+DECLARE_INTERRUPT(13);
+DECLARE_INTERRUPT(14);
+DECLARE_INTERRUPT(15);
+  
+void __attribute__ ((regparm(0))) default_isr(void); 
+asm ("default_isr: iret\n");
+
+void disable_irq(int irq) 
+{
+	if (irq >= MAX_IRQ) {
+		return;
+	}
+	irq_table[irq].status |= IRQ_DISABLED;
+	
+}
+
+void enable_irq(int irq) 
+{
+	if (irq >= MAX_IRQ) {
+		return;
+	}
+	irq_table[irq].status &= ~IRQ_DISABLED;
+}
+
+/* masks one specific IRQ in the PIC */
+static void unmask_irq(int irq)
+{
+	int imr_port;
+	
+	if (irq >= MAX_IRQ) {
+		return;
+	}
+	if (irq > 7) {
+		imr_port = SLAVE_PIC + IMR;
+	} else {
+		imr_port = MASTER_PIC + IMR;
+	}
+	
+	outb(inb(imr_port)&~(1<<(irq&7)), imr_port);
+}
+
+
+/* unmasks one specific IRQ in the PIC */
+static void mask_irq(int irq)
+{
+	int imr_port;
+	
+	if (irq >= MAX_IRQ) {
+		return;
+	}
+	if (irq > 7) {
+		imr_port = SLAVE_PIC + IMR;
+	} else {
+		imr_port = MASTER_PIC + IMR;
+	}
+	
+	outb(inb(imr_port)|(1<<(irq&7)), imr_port); 
+}
+
+
+/* issue a Specific End Of Interrupt instruciton */
+static void specific_eoi(int irq)
+{
+	/* If it is on the slave PIC this have to be performed on
+	 * both the master and the slave PICs */
+	if (irq > 7) {
+		outb(OCW2_SEOI|(irq&7), SLAVE_PIC + OCW2);
+		irq = SEOI_IR2;               /* also do IR2 on master */
+	} 
+	outb(OCW2_SEOI|irq, MASTER_PIC + OCW2);
+}
+
+void __attribute__ ((regparm(0))) do_irq(int irq) 
+{
+	
+	mask_irq(irq);
+	
+	if (irq_table[irq].status & IRQ_DISABLED) {
+		unmask_irq(irq);
+		specific_eoi(irq);
+		return;
+	}
+	
+	
+	if (NULL != irq_table[irq].handler) {
+		irq_handler_t *handler;
+		for (handler = irq_table[irq].handler; 
+		     NULL!= handler; handler = handler->next) {
+			handler->isr_func(handler->isr_data);
+		}
+	} else {
+		if ((irq & 7) != 7) {				
+			printf("Spurious irq %d\n", irq);
+		}
+	}		
+	unmask_irq(irq);
+	specific_eoi(irq);	
+}
+
+
+void __attribute__ ((regparm(0))) unknown_exception_entry(int cause, int ip, int seg) 
+{
+	printf("Unknown Exception %d at %04x:%08x\n", cause, seg, ip);
+}
+
+void __attribute__ ((regparm(0))) divide_exception_entry(int cause, int ip, int seg) 
+{
+	printf("Divide Error (Division by zero) at %04x:%08x\n", seg, ip);
+	while(1);
+}
+
+void __attribute__ ((regparm(0))) debug_exception_entry(int cause, int ip, int seg) 
+{
+	printf("Debug Interrupt (Single step) at %04x:%08x\n", seg, ip);
+}
+
+void __attribute__ ((regparm(0))) nmi_entry(int cause, int ip, int seg) 
+{
+	printf("NMI Interrupt at %04x:%08x\n", seg, ip);
+}
+		
+void __attribute__ ((regparm(0))) invalid_instruction_entry(int cause, int ip, int seg) 
+{
+	printf("Invalid Instruction at %04x:%08x\n", seg, ip);
+	while(1);
+}
+				
+void __attribute__ ((regparm(0))) double_fault_entry(int cause, int ip, int seg) 
+{
+	printf("Double fault at %04x:%08x\n", seg, ip);
+	while(1);
+}
+
+void __attribute__ ((regparm(0))) invalid_tss_exception_entry(int cause, int ip, int seg) 
+{
+	printf("Invalid TSS at %04x:%08x\n", seg, ip);
+}
+		
+void __attribute__ ((regparm(0))) seg_fault_entry(int cause, int ip, int seg) 
+{
+	printf("Segmentation fault at %04x:%08x\n", seg, ip);
+	while(1);
+}
+
+void __attribute__ ((regparm(0))) stack_fault_entry(int cause, int ip, int seg) 
+{
+	printf("Stack fault at %04x:%08x\n", seg, ip);
+	while(1);
+}
+
+void __attribute__ ((regparm(0))) gpf_entry(int cause, int ip, int seg) 
+{
+	printf("General protection fault at %04x:%08x\n", seg, ip);
+}
+
+void __attribute__ ((regparm(0))) page_fault_entry(int cause, int ip, int seg) 
+{
+	printf("Page fault at %04x:%08x\n", seg, ip);
+	while(1);
+}
+
+void __attribute__ ((regparm(0))) fp_exception_entry(int cause, int ip, int seg) 
+{
+	printf("Floating point exception at %04x:%08x\n", seg, ip);
+}
+
+void __attribute__ ((regparm(0))) alignment_check_entry(int cause, int ip, int seg) 
+{
+	printf("Alignment check at %04x:%08x\n", seg, ip);
+}
+       
+void __attribute__ ((regparm(0))) machine_check_entry(int cause, int ip, int seg) 
+{
+	printf("Machine check exception at %04x:%08x\n", seg, ip);
+}
+
+
+void irq_install_handler(int ino, interrupt_handler_t *func, void *pdata)
+{
+	int status;
+	
+	if (ino>MAX_IRQ) {
+		return;
+	}
+		
+	if (NULL != irq_table[ino].handler) {
+		return;
+	}
+	
+	status = disable_interrupts();
+	irq_table[ino].handler = malloc(sizeof(irq_handler_t));
+	if (NULL == irq_table[ino].handler) {
+		return;
+	}
+	
+	memset(irq_table[ino].handler, 0, sizeof(irq_handler_t));
+	
+	irq_table[ino].handler->isr_func = func;
+	irq_table[ino].handler->isr_data = pdata;
+	if (status) {
+		enable_interrupts();
+	}
+	
+	unmask_irq(ino);
+	
+	return;
+}
+
+void irq_free_handler(int ino)
+{
+	int status;
+	if (ino>MAX_IRQ) {
+		return;
+	}
+	
+	status = disable_interrupts();
+	mask_irq(ino);
+	if (NULL == irq_table[ino].handler) {
+		return;
+	}
+	free(irq_table[ino].handler);
+	irq_table[ino].handler=NULL;
+	if (status) {
+		enable_interrupts();
+	}
+	return;
+}
+
+
+asm ("idt_ptr:\n"
+	".word	0x800\n" /* size of the table 8*256 bytes */
+	".long	idt\n"	 /* offset */
+	".word	0x18\n");/* data segment */
+
+static void set_vector(int intnum, void *routine)
+{
+	idt[intnum].base_high = (u16)((u32)(routine)>>16);	
+	idt[intnum].base_low = (u16)((u32)(routine)&0xffff);	
+}
+
+
+int interrupt_init(void)
+{
+	int i;
+	
+	/* Just in case... */
+	disable_interrupts();
+		
+	/* Initialize the IDT and stuff */
+	
+	
+	memset(irq_table, 0, sizeof(irq_table));
+
+	/* Setup the IDT */
+	for (i=0;i<256;i++) {		
+		idt[i].access = 0x8e;
+		idt[i].res = 0;	
+		idt[i].selector = 0x10;	
+		set_vector(i, default_isr);
+	}	
+	
+	asm ("cs lidt idt_ptr\n");
+	
+	/* Setup exceptions */
+	set_vector(0x00, exp_0);
+	set_vector(0x01, exp_1);
+	set_vector(0x02, exp_2);
+	set_vector(0x03, exp_3);
+	set_vector(0x04, exp_4);
+	set_vector(0x05, exp_5);
+	set_vector(0x06, exp_6);
+	set_vector(0x07, exp_7);
+	set_vector(0x08, exp_8);
+	set_vector(0x09, exp_9);
+	set_vector(0x0a, exp_10);
+	set_vector(0x0b, exp_11);
+	set_vector(0x0c, exp_12);
+	set_vector(0x0d, exp_13);
+	set_vector(0x0e, exp_14);
+	set_vector(0x0f, exp_15);
+	set_vector(0x10, exp_16);
+	set_vector(0x11, exp_17);
+	set_vector(0x12, exp_18);
+	set_vector(0x13, exp_19);
+	set_vector(0x14, exp_20);
+	set_vector(0x15, exp_21);
+	set_vector(0x16, exp_22);
+	set_vector(0x17, exp_23);
+	set_vector(0x18, exp_24);
+	set_vector(0x19, exp_25);
+	set_vector(0x1a, exp_26);
+	set_vector(0x1b, exp_27);
+	set_vector(0x1c, exp_28);
+	set_vector(0x1d, exp_29);
+	set_vector(0x1e, exp_30);
+	set_vector(0x1f, exp_31);
+
+
+	/* Setup interrupts */
+	set_vector(0x20, irq_0);
+	set_vector(0x21, irq_1);
+	set_vector(0x23, irq_3);
+	set_vector(0x24, irq_4);
+	set_vector(0x25, irq_5);
+	set_vector(0x26, irq_6);
+	set_vector(0x27, irq_7);
+	set_vector(0x28, irq_8);
+	set_vector(0x29, irq_9);
+	set_vector(0x2a, irq_10);
+	set_vector(0x2b, irq_11);
+	set_vector(0x2c, irq_12);
+	set_vector(0x2d, irq_13);
+	set_vector(0x2e, irq_14);
+	set_vector(0x2f, irq_15);
+	/* vectors 0x30-0x3f are reserved for irq 16-31 */
+	set_vector(0x40, syscall_entry);
+
+	
+	/* Mask all interrupts */
+	outb(0xff, MASTER_PIC + IMR);
+	outb(0xff, SLAVE_PIC + IMR);
+	
+	/* Master PIC */
+	outb(ICW1_SEL|ICW1_EICW4, MASTER_PIC + ICW1);	
+	outb(0x20, MASTER_PIC + ICW2);          /* Place master PIC interrupts at INT20 */
+	outb(IR2, MASTER_PIC + ICW3);		/* ICW3, One slevc PIC is present */	
+	outb(ICW4_PM, MASTER_PIC + ICW4);
+	
+	for (i=0;i<8;i++) {
+		outb(OCW2_SEOI|i, MASTER_PIC + OCW2);
+	}
+	
+	/* Slave PIC */
+	outb(ICW1_SEL|ICW1_EICW4, SLAVE_PIC + ICW1);	
+	outb(0x28, SLAVE_PIC + ICW2);	        /* Place slave PIC interrupts at INT28 */
+	outb(0x02, SLAVE_PIC + ICW3);		/* Slave ID */
+	outb(ICW4_PM, SLAVE_PIC + ICW4);        
+	
+	for (i=0;i<8;i++) {
+		outb(OCW2_SEOI|i, SLAVE_PIC + OCW2);
+	}
+	
+	
+	/* enable cascade interrerupt */
+	outb(0xfb, MASTER_PIC + IMR);
+	outb(0xff, SLAVE_PIC + IMR);
+	
+	/* It is now safe to enable interrupts */
+	enable_interrupts(); 
+	
+	return 0;
+}
+
+void enable_interrupts(void)
+{
+	asm("sti\n");
+}
+
+int disable_interrupts(void)
+{
+	long flags;
+	
+	asm volatile ("pushfl ; popl %0 ; cli\n" : "=g" (flags) : );
+	
+	return (flags&0x200); /* IE flags is bit 9 */
+}
+
+
+#ifdef CFG_RESET_GENERIC
+
+void __attribute__ ((regparm(0))) generate_gpf(void);
+asm(".globl generate_gpf\n" 
+    "generate_gpf:\n" 
+    "ljmp   $0x70, $0x47114711\n"); /* segment 0x70 is an arbitrary segment which does not 
+				    * exist */
+void reset_cpu(ulong addr)
+{
+	set_vector(13, generate_gpf);  /* general protection fault handler */
+	set_vector(8, generate_gpf);   /* double fault handler */
+	generate_gpf();                /* start the show */
+}
+#endif
diff --git a/cpu/i386/reset.S b/cpu/i386/reset.S
new file mode 100644
index 0000000..57e32a8
--- /dev/null
+++ b/cpu/i386/reset.S
@@ -0,0 +1,38 @@
+/*
+ *  U-boot - i386 Startup Code 
+ *
+ *  Copyright (c) 2002	Omicron Ceti AB, Daniel Engström <denaiel@omicron.se>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ */
+
+/* Reset vector, jumps to start16.S */
+
+.extern start16
+
+.section .reset, "ax"
+.code16
+reset_vector: 
+        cli
+        cld
+        jmp start16 
+
+	.org 0xf
+	nop
+	
diff --git a/cpu/i386/serial.c b/cpu/i386/serial.c
new file mode 100644
index 0000000..c0d2e8a
--- /dev/null
+++ b/cpu/i386/serial.c
@@ -0,0 +1,460 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se
+ * 
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ */
+/*------------------------------------------------------------------------------+ */
+/*
+ * This source code has been made available to you by IBM on an AS-IS
+ * basis.  Anyone receiving this source is licensed under IBM
+ * copyrights to use it in any way he or she deems fit, including
+ * copying it, modifying it, compiling it, and redistributing it either
+ * with or without modifications.  No license under IBM patents or
+ * patent applications is to be implied by the copyright license.
+ *
+ * Any user of this software should understand that IBM cannot provide
+ * technical support for this software and will not be responsible for
+ * any consequences resulting from the use of this software.
+ *
+ * Any person who transfers this source code or any derivative work
+ * must include the IBM copyright notice, this paragraph, and the
+ * preceding two paragraphs in the transferred software.
+ *
+ * COPYRIGHT   I B M   CORPORATION 1995
+ * LICENSED MATERIAL  -  PROGRAM PROPERTY OF I B M
+ */
+/*------------------------------------------------------------------------------- */
+
+#include <common.h>
+#include <watchdog.h>
+#include <asm/io.h>
+#include <asm/ibmpc.h>
+
+#if CONFIG_SERIAL_SOFTWARE_FIFO
+#include <malloc.h>
+#endif
+
+#define UART_RBR    0x00
+#define UART_THR    0x00
+#define UART_IER    0x01
+#define UART_IIR    0x02
+#define UART_FCR    0x02
+#define UART_LCR    0x03
+#define UART_MCR    0x04
+#define UART_LSR    0x05
+#define UART_MSR    0x06
+#define UART_SCR    0x07
+#define UART_DLL    0x00
+#define UART_DLM    0x01
+
+/*-----------------------------------------------------------------------------+
+  | Line Status Register.
+  +-----------------------------------------------------------------------------*/
+#define asyncLSRDataReady1            0x01
+#define asyncLSROverrunError1         0x02
+#define asyncLSRParityError1          0x04
+#define asyncLSRFramingError1         0x08
+#define asyncLSRBreakInterrupt1       0x10
+#define asyncLSRTxHoldEmpty1          0x20
+#define asyncLSRTxShiftEmpty1         0x40
+#define asyncLSRRxFifoError1          0x80
+
+
+
+#if CONFIG_SERIAL_SOFTWARE_FIFO
+/*-----------------------------------------------------------------------------+
+  | Fifo
+  +-----------------------------------------------------------------------------*/
+typedef struct {
+	char *rx_buffer;
+	ulong rx_put;
+	ulong rx_get;
+} serial_buffer_t;
+
+volatile static serial_buffer_t buf_info;
+#endif
+
+
+static int serial_div (int baudrate )
+{
+	
+	switch (baudrate) {
+	case 1200:
+		return 96;
+	case 9600:
+		return 12;
+	case 19200:
+		return 6;
+	case 38400:
+		return 3;
+	case 57600:
+		return 2;
+	case 115200:
+		return 1;		
+	}
+	hang ();
+}
+
+
+/*
+ * Minimal serial functions needed to use one of the SMC ports
+ * as serial console interface.
+ */
+
+int serial_init (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	volatile char val;
+
+	int bdiv = serial_div(gd->baudrate);
+    
+
+	outb(0x80, UART0_BASE + UART_LCR);	/* set DLAB bit */
+	outb(bdiv, UART0_BASE + UART_DLL);	/* set baudrate divisor */
+	outb(bdiv >> 8, UART0_BASE + UART_DLM);/* set baudrate divisor */
+	outb(0x03, UART0_BASE + UART_LCR);	/* clear DLAB; set 8 bits, no parity */
+	outb(0x00, UART0_BASE + UART_FCR);	/* disable FIFO */
+	outb(0x00, UART0_BASE + UART_MCR);	/* no modem control DTR RTS */
+	val = inb(UART0_BASE + UART_LSR);	/* clear line status */
+	val = inb(UART0_BASE + UART_RBR);	/* read receive buffer */
+	outb(0x00, UART0_BASE + UART_SCR);	/* set scratchpad */
+	outb(0x00, UART0_BASE + UART_IER);	/* set interrupt enable reg */
+
+	return (0);
+}
+
+
+void serial_setbrg (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	unsigned short bdiv;
+	
+	bdiv = serial_div (gd->baudrate);
+
+	outb(0x80, UART0_BASE + UART_LCR);	/* set DLAB bit */
+	outb(bdiv&0xff, UART0_BASE + UART_DLL);	/* set baudrate divisor */
+	outb(bdiv >> 8, UART0_BASE + UART_DLM);/* set baudrate divisor */
+	outb(0x03, UART0_BASE + UART_LCR);	/* clear DLAB; set 8 bits, no parity */
+}
+
+
+void serial_putc (const char c)
+{
+	int i;
+
+	if (c == '\n')
+		serial_putc ('\r');
+
+	/* check THRE bit, wait for transmiter available */
+	for (i = 1; i < 3500; i++) {
+		if ((inb (UART0_BASE + UART_LSR) & 0x20) == 0x20)
+			break;
+		udelay (100);
+	}
+	outb(c, UART0_BASE + UART_THR);	/* put character out */
+}
+
+
+void serial_puts (const char *s)
+{
+	while (*s) {
+		serial_putc (*s++);
+	}
+}
+
+
+int serial_getc ()
+{
+	unsigned char status = 0;
+
+	while (1) {
+#if defined(CONFIG_HW_WATCHDOG)
+		WATCHDOG_RESET ();	/* Reset HW Watchdog, if needed */
+#endif	/* CONFIG_HW_WATCHDOG */
+		status = inb (UART0_BASE + UART_LSR);
+		if ((status & asyncLSRDataReady1) != 0x0) {
+			break;
+		}
+		if ((status & ( asyncLSRFramingError1 |
+				asyncLSROverrunError1 |
+				asyncLSRParityError1  |
+				asyncLSRBreakInterrupt1 )) != 0) {
+			outb(asyncLSRFramingError1 |
+			      asyncLSROverrunError1 |
+			      asyncLSRParityError1  |
+			      asyncLSRBreakInterrupt1, UART0_BASE + UART_LSR);
+		}
+	}
+	return (0x000000ff & (int) inb (UART0_BASE));
+}
+
+
+int serial_tstc ()
+{
+	unsigned char status;
+
+	status = inb (UART0_BASE + UART_LSR);
+	if ((status & asyncLSRDataReady1) != 0x0) {
+		return (1);
+	}
+	if ((status & ( asyncLSRFramingError1 |
+			asyncLSROverrunError1 |
+			asyncLSRParityError1  |
+			asyncLSRBreakInterrupt1 )) != 0) {
+		outb(asyncLSRFramingError1 |
+		      asyncLSROverrunError1 |
+		      asyncLSRParityError1  |
+		      asyncLSRBreakInterrupt1, UART0_BASE + UART_LSR);
+	}
+	return 0;
+}
+
+
+#if CONFIG_SERIAL_SOFTWARE_FIFO
+
+void serial_isr (void *arg)
+{
+	int space;
+	int c;
+	const int rx_get = buf_info.rx_get;
+	int rx_put = buf_info.rx_put;
+
+	if (rx_get <= rx_put) {
+		space = CONFIG_SERIAL_SOFTWARE_FIFO - (rx_put - rx_get);
+	} else {
+		space = rx_get - rx_put;
+	}
+	while (serial_tstc ()) {
+		c = serial_getc ();
+		if (space) {
+			buf_info.rx_buffer[rx_put++] = c;
+			space--;
+		}
+		if (rx_put == CONFIG_SERIAL_SOFTWARE_FIFO)
+			rx_put = 0;
+		if (space < CONFIG_SERIAL_SOFTWARE_FIFO / 4) {
+			/* Stop flow by setting RTS inactive */
+			outb(inb (UART0_BASE + UART_MCR) & (0xFF ^ 0x02),
+			      UART0_BASE + UART_MCR);
+		}
+	}
+	buf_info.rx_put = rx_put;
+}
+
+void serial_buffered_init (void)
+{
+	serial_puts ("Switching to interrupt driven serial input mode.\n");
+	buf_info.rx_buffer = malloc (CONFIG_SERIAL_SOFTWARE_FIFO);
+	buf_info.rx_put = 0;
+	buf_info.rx_get = 0;
+
+	if (inb (UART0_BASE + UART_MSR) & 0x10) {
+		serial_puts ("Check CTS signal present on serial port: OK.\n");
+	} else {
+		serial_puts ("WARNING: CTS signal not present on serial port.\n");
+	}
+
+	irq_install_handler ( VECNUM_U0 /*UART0 *//*int vec */ ,
+			      serial_isr /*interrupt_handler_t *handler */ ,
+			      (void *) &buf_info /*void *arg */ );
+
+	/* Enable "RX Data Available" Interrupt on UART */
+	/* outb(inb(UART0_BASE + UART_IER) |0x01, UART0_BASE + UART_IER); */
+	outb(0x01, UART0_BASE + UART_IER);
+	/* Set DTR active */
+	outb(inb (UART0_BASE + UART_MCR) | 0x01, UART0_BASE + UART_MCR);
+	/* Start flow by setting RTS active */
+	outb(inb (UART0_BASE + UART_MCR) | 0x02, UART0_BASE + UART_MCR);
+	/* Setup UART FIFO: RX trigger level: 4 byte, Enable FIFO */
+	outb((1 << 6) | 1, UART0_BASE + UART_FCR);
+}
+
+void serial_buffered_putc (const char c)
+{
+	/* Wait for CTS */
+#if defined(CONFIG_HW_WATCHDOG)
+	while (!(inb (UART0_BASE + UART_MSR) & 0x10))
+		WATCHDOG_RESET ();
+#else
+	while (!(inb (UART0_BASE + UART_MSR) & 0x10));
+#endif
+	serial_putc (c);
+}
+
+void serial_buffered_puts (const char *s)
+{
+	serial_puts (s);
+}
+
+int serial_buffered_getc (void)
+{
+	int space;
+	int c;
+	int rx_get = buf_info.rx_get;
+	int rx_put;
+
+#if defined(CONFIG_HW_WATCHDOG)
+	while (rx_get == buf_info.rx_put)
+		WATCHDOG_RESET ();
+#else
+	while (rx_get == buf_info.rx_put);
+#endif
+	c = buf_info.rx_buffer[rx_get++];
+	if (rx_get == CONFIG_SERIAL_SOFTWARE_FIFO)
+		rx_get = 0;
+	buf_info.rx_get = rx_get;
+
+	rx_put = buf_info.rx_put;
+	if (rx_get <= rx_put) {
+		space = CONFIG_SERIAL_SOFTWARE_FIFO - (rx_put - rx_get);
+	} else {
+		space = rx_get - rx_put;
+	}
+	if (space > CONFIG_SERIAL_SOFTWARE_FIFO / 2) {
+		/* Start flow by setting RTS active */
+		outb(inb (UART0_BASE + UART_MCR) | 0x02, UART0_BASE + UART_MCR);
+	}
+
+	return c;
+}
+
+int serial_buffered_tstc (void)
+{
+	return (buf_info.rx_get != buf_info.rx_put) ? 1 : 0;
+}
+
+#endif	/* CONFIG_SERIAL_SOFTWARE_FIFO */
+
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+/*
+  AS HARNOIS : according to CONFIG_KGDB_SER_INDEX kgdb uses serial port
+  number 0 or number 1
+  - if CONFIG_KGDB_SER_INDEX = 1 => serial port number 0 :
+  configuration has been already done
+  - if CONFIG_KGDB_SER_INDEX = 2 => serial port number 1 :
+  configure port 1 for serial I/O with rate = CONFIG_KGDB_BAUDRATE
+*/
+#if (CONFIG_KGDB_SER_INDEX & 2)
+void kgdb_serial_init (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	volatile char val;
+	bdiv = serial_div (CONFIG_KGDB_BAUDRATE);
+
+	/*
+	 * Init onboard 16550 UART
+	 */
+	outb(0x80, UART1_BASE + UART_LCR);	/* set DLAB bit */
+	outb(bdiv & 0xff), UART1_BASE + UART_DLL);	/* set divisor for 9600 baud */
+	outb(bdiv >> 8), UART1_BASE + UART_DLM);	/* set divisor for 9600 baud */
+	outb(0x03, UART1_BASE + UART_LCR);	/* line control 8 bits no parity */
+	outb(0x00, UART1_BASE + UART_FCR);	/* disable FIFO */
+	outb(0x00, UART1_BASE + UART_MCR);	/* no modem control DTR RTS */
+	val = inb(UART1_BASE + UART_LSR);	/* clear line status */
+	val = inb(UART1_BASE + UART_RBR);	/* read receive buffer */
+	outb(0x00, UART1_BASE + UART_SCR);	/* set scratchpad */
+	outb(0x00, UART1_BASE + UART_IER);	/* set interrupt enable reg */
+}
+
+
+void putDebugChar (const char c)
+{
+	if (c == '\n')
+		serial_putc ('\r');
+
+	outb(c, UART1_BASE + UART_THR);	/* put character out */
+
+	/* check THRE bit, wait for transfer done */
+	while ((inb(UART1_BASE + UART_LSR) & 0x20) != 0x20);
+}
+
+
+void putDebugStr (const char *s)
+{
+	while (*s) {
+		serial_putc(*s++);
+	}
+}
+
+
+int getDebugChar (void)
+{
+	unsigned char status = 0;
+
+	while (1) {
+		status = inb(UART1_BASE + UART_LSR);
+		if ((status & asyncLSRDataReady1) != 0x0) {
+			break;
+		}
+		if ((status & ( asyncLSRFramingError1 |
+				asyncLSROverrunError1 |
+				asyncLSRParityError1  |
+				asyncLSRBreakInterrupt1 )) != 0) {
+			outb(asyncLSRFramingError1 |
+			     asyncLSROverrunError1 |
+			     asyncLSRParityError1  |
+			     asyncLSRBreakInterrupt1, UART1_BASE + UART_LSR);
+		}
+	}
+	return (0x000000ff & (int) inb(UART1_BASE));
+}
+
+
+void kgdb_interruptible (int yes)
+{
+	return;
+}
+
+#else	/* ! (CONFIG_KGDB_SER_INDEX & 2) */
+
+void kgdb_serial_init (void)
+{
+	serial_printf ("[on serial] ");
+}
+
+void putDebugChar (int c)
+{
+	serial_putc (c);
+}
+
+void putDebugStr (const char *str)
+{
+	serial_puts (str);
+}
+
+int getDebugChar (void)
+{
+	return serial_getc ();
+}
+
+void kgdb_interruptible (int yes)
+{
+	return;
+}
+#endif	/* (CONFIG_KGDB_SER_INDEX & 2) */
+#endif	/* CFG_CMD_KGDB */
+
diff --git a/cpu/i386/start.S b/cpu/i386/start.S
new file mode 100644
index 0000000..025555c
--- /dev/null
+++ b/cpu/i386/start.S
@@ -0,0 +1,198 @@
+/*
+ *  U-boot - i386 Startup Code 
+ *
+ *  Copyright (c) 2002	Omicron Ceti AB, Daniel Engström <denaiel@omicron.se>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 <config.h>
+#include <version.h>
+
+	
+.section .text
+.code32
+.globl _start
+.type _start, @function	
+.globl _i386boot_start
+_i386boot_start:
+_start:		
+        movl    $0x18,%eax         	/* Load our segement registes, the
+                                         * gdt have already been loaded by start16.S */
+        movw    %ax,%fs
+	movw	%ax,%ds
+        movw    %ax,%gs
+        movw    %ax,%es
+        movw    %ax,%ss
+	
+	/* We call a few functions in the board support package
+	 * since we have no stack yet we'll have to use %ebp
+	 * to store the return address */
+	
+	/* Early platform init (setup gpio, etc ) */
+	mov     $early_board_init_ret, %ebp
+	jmp	early_board_init
+early_board_init_ret:
+	
+	/* The __port80 entry-point should be usabe by now */
+	/* so we try to indicate progress */
+	movw	$0x01, %ax    
+	movl	$.progress0, %ebp
+	jmp	__show_boot_progress
+.progress0:  	
+
+	/* size memory */
+	mov	$mem_init_ret, %ebp
+	jmp     mem_init		
+mem_init_ret:
+	
+	/* check ammount of configured memory 
+	 * (we need atleast bss start+bss size+stack size) */		
+	movl	$_i386boot_bss_start, %ecx        /* BSS start */
+	addl	$_i386boot_bss_size, %ecx         /* BSS size */	
+	addl	$CFG_STACK_SIZE, %ecx
+	cmpl	%ecx, %eax 
+	jae	mem_ok
+	
+	/* indicate (lack of) progress */
+	movw	$0x81, %ax    
+	movl	$.progress0a, %ebp
+	jmp	__show_boot_progress
+.progress0a:  	
+	jmp 	die
+mem_ok:	
+
+	/* indicate progress */
+	movw	$0x02, %ax    
+	movl	$.progress1, %ebp
+	jmp	__show_boot_progress
+.progress1:  	
+
+	/* create a stack after the bss */
+        movl    $_i386boot_bss_start, %eax
+	addl	$_i386boot_bss_size, %eax
+	addl	$CFG_STACK_SIZE, %eax
+        movl    %eax, %esp
+	
+	pushl	$0
+	popl	%eax
+	cmpl	$0, %eax
+	jne	no_stack
+	push	$0x55aa55aa
+	popl	%ebx
+	cmpl	$0x55aa55aa, %ebx
+	je	stack_ok
+
+no_stack:
+	/* indicate (lack of) progress */
+	movw	$0x82, %ax    
+	movl	$.progress1a, %ebp
+	jmp	__show_boot_progress
+.progress1a:  	
+	jmp die
+	
+	
+stack_ok:	
+	/* indicate progress */
+	movw	$0x03, %ax    
+	movl	$.progress2, %ebp
+	jmp	__show_boot_progress
+.progress2:  	
+
+	/* copy data section to ram, size must be 4-byte aligned */
+	movl	$_i386boot_romdata_dest, %edi	  /* destination address */
+ 	movl	$_i386boot_romdata_start, %esi	  /* source address */
+	movl	$_i386boot_romdata_size, %ecx     /* number of bytes to copy */
+	movl	%ecx, %eax
+	andl	$3, %eax
+	jnz	data_fail
+	
+	shrl	$2, %ecx	                  /* copy 4 byte each time */
+	cld	 
+	cmpl	$0, %ecx
+	je	data_ok	
+data_segment:	
+	movsl		
+	loop	data_segment
+	jmp	data_ok
+data_fail:
+	/* indicate (lack of) progress */
+	movw	$0x83, %ax    
+	movl	$.progress2a, %ebp
+	jmp	__show_boot_progress
+.progress2a:  	
+	jmp 	die
+
+data_ok:	
+
+	/* indicate progress */
+	movw	$0x04, %ax    
+	movl	$.progress3, %ebp
+	jmp	__show_boot_progress
+.progress3:  	
+
+	/* clear bss section in ram, size must be 4-byte aligned  */
+	movl	$_i386boot_bss_start, %eax        /* BSS start */
+	movl	$_i386boot_bss_size, %ecx         /* BSS size */	
+	movl	%ecx, %eax
+	andl	$3, %eax
+	jnz	bss_fail
+	shrl	$2, %ecx	                  /* clear 4 byte each time */
+	cld		      
+	cmpl	$0, %ecx
+	je	bss_ok	
+bss:	
+	movl	$0, (%edi)
+	add	$4, %edi			
+	loop	bss
+	jmp 	bss_ok
+
+bss_fail:
+	/* indicate (lack of) progress */
+	movw	$0x84, %ax    
+	movl	$.progress3a, %ebp
+	jmp	__show_boot_progress
+.progress3a:  	
+	jmp 	die
+
+bss_ok:	
+
+	wbinvd	 
+
+
+	/* indicate progress */
+	movw	$0x05, %ax    
+	movl	$.progress4, %ebp
+	jmp	__show_boot_progress
+.progress4:
+
+	call	start_i386boot  /* Enter, U-boot! */
+
+	/* indicate (lack of) progress */
+	movw	$0x85, %ax    
+	movl	$.progress4a, %ebp
+	jmp	__show_boot_progress
+.progress4a:
+
+die:	hlt
+	jmp	die
+	hlt                     
+
+
diff --git a/cpu/i386/start16.S b/cpu/i386/start16.S
new file mode 100644
index 0000000..590a5a6
--- /dev/null
+++ b/cpu/i386/start16.S
@@ -0,0 +1,112 @@
+/*
+ *  U-boot - i386 Startup Code 
+ *
+ *  Copyright (c) 2002	Omicron Ceti AB, Daniel Engström <denaiel@omicron.se>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ */
+
+
+#define BOOT_SEG	0xffff0000	/* linear segment of boot code */
+#define a32		.byte 0x67;
+#define o32		.byte 0x66;
+
+.section .start16, "ax"
+.code16
+.globl start16
+start16: 
+	/* First we let the BSP do some early initialization
+	 * this code have to map the flash to its final position
+	 */
+	mov	$board_init16_ret, %bp
+	jmp	board_init16
+board_init16_ret:	
+	
+	/* Turn of cache (this might require a 486-class CPU) */
+        movl    %cr0, %eax
+        orl     $060000000,%eax
+        movl    %eax, %cr0
+        wbinvd  		     
+	
+	/* load the descriptor tables */
+o32 cs	lidt	idt_ptr
+o32 cs	lgdt    gdt_ptr		 
+
+
+	/* Now, we enter protected mode */
+        movl    %cr0, %eax               
+        orl     $1,%eax                  
+        movl    %eax, %cr0            
+	
+	/* Flush the prefetch queue */
+        jmp     ff        
+ff:
+
+	/* Finally jump to the 32bit initialization code */
+	movw	$code32start, %ax 
+        movw    %ax,%bp
+o32 cs	ljmp	*(%bp)
+
+	/* 48-bit far pointer */
+code32start:
+	.long	_start                          /* offset */
+	.word	0x10                            /* segment */
+
+idt_ptr:
+	.word	0				/* limit */
+	.long	0		       		/* base */
+	
+gdt_ptr:
+	.word	0x30			        /* limit (48 bytes = 6 GDT entries) */
+	.long	BOOT_SEG + gdt	        	/* base */
+
+	/* The GDT table ... 
+	 *
+	 *       Selector	Type 
+	 * 	 0x00		NULL
+	 * 	 0x08		Unused
+	 *	 0x10		32bit code 
+	 *	 0x18		32bit data/stack
+	 *	 0x20		16bit code
+	 *	 0x28	 	16bit data/stack
+	 */
+
+gdt:
+	.word	0, 0, 0, 0			/* NULL  */
+	.word	0, 0, 0, 0			/* unused */
+
+	.word	0xFFFF				/* 4Gb - (0x100000*0x1000 = 4Gb) */
+	.word	0				/* base address = 0 */
+	.word	0x9B00				/* code read/exec */
+	.word	0x00CF				/* granularity = 4096, 386 (+5th nibble of limit) */
+
+	.word	0xFFFF				/* 4Gb - (0x100000*0x1000 = 4Gb) */
+	.word	0x0				/* base address = 0 */
+	.word	0x9300				/* data read/write */
+	.word	0x00CF				/* granularity = 4096, 386 (+5th nibble of limit) */
+						
+	.word	0xFFFF				/* 64kb */
+	.word	0				/* base address = 0 */
+	.word	0x9b00				/* data read/write */
+	.word	0x0010				/* granularity = 1  (+5th nibble of limit) */
+	
+	.word	0xFFFF				/* 64kb */
+	.word	0				/* base address = 0 */
+	.word	0x9300				/* data read/write */
+	.word	0x0010				/* granularity = 1 (+5th nibble of limit) */
diff --git a/cpu/i386/timer.c b/cpu/i386/timer.c
new file mode 100644
index 0000000..a23cd6e
--- /dev/null
+++ b/cpu/i386/timer.c
@@ -0,0 +1,211 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 <common.h>
+#include <asm/io.h>
+#include <asm/i8254.h>
+#include <asm/ibmpc.h>
+
+
+static volatile unsigned long system_ticks;
+static int timer_init_done =0;
+
+static void timer_isr(void *unused)
+{
+	system_ticks++;
+}
+
+unsigned long get_system_ticks(void)
+{
+	return system_ticks;
+}
+
+#define TIMER0_VALUE 0x04aa /* 1kHz 1.9318MHz / 1000 */
+#define TIMER2_VALUE 0x0a8e /* 440Hz */
+
+int timer_init(void)
+{
+	system_ticks = 0;
+	
+	irq_install_handler(0, timer_isr, NULL);
+	
+	/* initialize timer 0 and 2 
+	 * 
+	 * Timer 0 is used to increment system_tick 1000 times/sec
+	 * Timer 1 was used for DRAM refresh in early PC's
+	 * Timer 2 is used to drive the speaker
+	 * (to stasrt a beep: write 3 to port 0x61,
+	 * to stop it again: write 0)
+	 */
+		
+        outb(PIT_CMD_CTR0|PIT_CMD_BOTH|PIT_CMD_MODE2, PIT_BASE + PIT_COMMAND);
+	outb(TIMER0_VALUE&0xff, PIT_BASE + PIT_T0);
+	outb(TIMER0_VALUE>>8, PIT_BASE + PIT_T0);
+
+        outb(PIT_CMD_CTR2|PIT_CMD_BOTH|PIT_CMD_MODE3, PIT_BASE + PIT_COMMAND);
+	outb(TIMER2_VALUE&0xff, PIT_BASE + PIT_T2);
+	outb(TIMER2_VALUE>>8, PIT_BASE + PIT_T2);
+
+	timer_init_done = 1;
+	
+	return 0;
+}
+
+
+#ifdef CFG_TIMER_GENERIC
+
+/* the unit for these is CFG_HZ */
+
+/* FixMe: implement these */
+void reset_timer (void)
+{
+	system_ticks = 0;
+}
+
+ulong get_timer (ulong base)
+{
+	return (system_ticks - base);
+}
+
+void set_timer (ulong t)	
+{
+	system_ticks = t;
+}
+
+static u16 read_pit(void)
+{
+	u8 low;
+	outb(PIT_CMD_LATCH, PIT_BASE + PIT_COMMAND);
+	low = inb(PIT_BASE + PIT_T0);
+	return ((inb(PIT_BASE + PIT_T0) << 8) | low);
+}
+
+/* this is not very exact */
+void udelay (unsigned long usec)
+{	
+	int counter;
+	int wraps;
+	
+	if (!timer_init_done) {
+		return;
+	}
+	counter = read_pit();
+	wraps = usec/1000;
+	usec = usec%1000;
+	
+	usec*=1194;
+	usec/=1000;
+	usec+=counter; 
+	if (usec > 1194) {
+		usec-=1194;
+		wraps++;
+	}
+
+	while (1) {
+		int new_count = read_pit();
+		
+		if (((new_count < usec) && !wraps) || wraps < 0) {
+			break;
+		}
+		
+		if (new_count > counter) {
+			wraps--;
+		}
+		counter = new_count;
+	}
+	
+}
+
+#if 0
+/* this is a version with debug output */
+void _udelay (unsigned long usec)
+{	
+	int counter;
+	int wraps;
+	
+	int usec1, usec2, usec3;
+	int wraps1, wraps2, wraps3, wraps4;
+	int ctr1, ctr2, ctr3, nct1, nct2;
+	int i;
+	usec1=usec;
+	if (!timer_init_done) {
+		return;
+	}
+	counter = read_pit();
+	ctr1 = counter;
+	wraps = usec/1000;
+	usec = usec%1000;
+	
+	usec2 = usec;
+	wraps1 = wraps;
+	
+	usec*=1194;
+	usec/=1000;
+	usec+=counter; 
+	if (usec > 1194) {
+		usec-=1194;
+		wraps++;
+	}
+
+	usec3 = usec;
+	wraps2 = wraps;
+	
+	ctr2 = wraps3 = nct1 = 4711;
+	ctr3 = wraps4 = nct2 = 4711;
+	i=0;
+	while (1) {
+		int new_count = read_pit();
+		i++;
+		if ((new_count < usec && !wraps) || wraps < 0) {
+			break;
+		}
+		
+		if (new_count > counter) {
+			wraps--;
+		}
+		if (ctr2==4711) {
+			ctr2 = counter;
+			wraps3 = wraps;
+			nct1 = new_count;
+		} else {
+			ctr3 = counter;
+			wraps4 = wraps;
+			nct2 = new_count;
+		}
+		
+		counter = new_count;
+	}
+	
+	printf("udelay(%d)\n", usec1);
+	printf("counter %d\n", ctr1);
+	printf("1: wraps %d, usec %d\n", wraps1, usec2);
+	printf("2: wraps %d, usec %d\n", wraps2, usec3);
+	printf("new_count[0] %d counter %d wraps %d\n", nct1, ctr2, wraps3);
+	printf("new_count[%d] %d counter %d wraps %d\n", i, nct2, ctr3, wraps4);
+
+	printf("%d %d %d %d %d\n",
+	       read_pit(), read_pit(), read_pit(),
+	       read_pit(), read_pit());
+}
+#endif
+#endif