* 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
This commit is contained in:
43
cpu/i386/Makefile
Normal file
43
cpu/i386/Makefile
Normal file
@@ -0,0 +1,43 @@
|
||||
#
|
||||
# (C) Copyright 2002
|
||||
# Daniel Engstr<74>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
|
||||
|
||||
#########################################################################
|
||||
26
cpu/i386/config.mk
Normal file
26
cpu/i386/config.mk
Normal file
@@ -0,0 +1,26 @@
|
||||
#
|
||||
# (C) Copyright 2002
|
||||
# Daniel Engstr<74>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
|
||||
62
cpu/i386/cpu.c
Normal file
62
cpu/i386/cpu.c
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* (C) Copyright 2002
|
||||
* Daniel Engstr<74>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;
|
||||
}
|
||||
|
||||
583
cpu/i386/interrupts.c
Normal file
583
cpu/i386/interrupts.c
Normal file
@@ -0,0 +1,583 @@
|
||||
/*
|
||||
* (C) Copyright 2002
|
||||
* Daniel Engstr<74>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
|
||||
38
cpu/i386/reset.S
Normal file
38
cpu/i386/reset.S
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* U-boot - i386 Startup Code
|
||||
*
|
||||
* Copyright (c) 2002 Omicron Ceti AB, Daniel Engstr<EFBFBD>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
|
||||
|
||||
460
cpu/i386/serial.c
Normal file
460
cpu/i386/serial.c
Normal file
@@ -0,0 +1,460 @@
|
||||
/*
|
||||
* (C) Copyright 2002
|
||||
* Daniel Engstr<74>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 */
|
||||
|
||||
198
cpu/i386/start.S
Normal file
198
cpu/i386/start.S
Normal file
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* U-boot - i386 Startup Code
|
||||
*
|
||||
* Copyright (c) 2002 Omicron Ceti AB, Daniel Engstr<EFBFBD>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
|
||||
|
||||
|
||||
112
cpu/i386/start16.S
Normal file
112
cpu/i386/start16.S
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* U-boot - i386 Startup Code
|
||||
*
|
||||
* Copyright (c) 2002 Omicron Ceti AB, Daniel Engstr<EFBFBD>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) */
|
||||
211
cpu/i386/timer.c
Normal file
211
cpu/i386/timer.c
Normal file
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* (C) Copyright 2002
|
||||
* Daniel Engstr<74>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
|
||||
Reference in New Issue
Block a user