summaryrefslogtreecommitdiff
path: root/cpu/i386
diff options
context:
space:
mode:
Diffstat (limited to 'cpu/i386')
-rw-r--r--cpu/i386/Makefile43
-rw-r--r--cpu/i386/config.mk26
-rw-r--r--cpu/i386/cpu.c62
-rw-r--r--cpu/i386/interrupts.c583
-rw-r--r--cpu/i386/reset.S38
-rw-r--r--cpu/i386/serial.c460
-rw-r--r--cpu/i386/start.S198
-rw-r--r--cpu/i386/start16.S112
-rw-r--r--cpu/i386/timer.c211
9 files changed, 1733 insertions, 0 deletions
diff --git a/cpu/i386/Makefile b/cpu/i386/Makefile
new file mode 100644
index 00000000000..1482398efe3
--- /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 00000000000..70caeb270aa
--- /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 00000000000..669823f946e
--- /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 00000000000..81d6881857c
--- /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 00000000000..57e32a8b7f0
--- /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 00000000000..c0d2e8aa14f
--- /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 00000000000..025555c0a14
--- /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 00000000000..590a5a6c9d7
--- /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 00000000000..a23cd6e48bf
--- /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