diff options
-rw-r--r-- | cpu/i386/Makefile | 2 | ||||
-rw-r--r-- | cpu/i386/cpu.c | 4 | ||||
-rw-r--r-- | cpu/i386/exceptions.c | 229 | ||||
-rw-r--r-- | cpu/i386/interrupts.c | 422 | ||||
-rw-r--r-- | include/asm-i386/interrupt.h | 48 | ||||
-rw-r--r-- | include/asm-i386/u-boot-i386.h | 6 | ||||
-rw-r--r-- | include/configs/eNET.h | 4 | ||||
-rw-r--r-- | include/configs/sc520_cdp.h | 2 | ||||
-rw-r--r-- | include/configs/sc520_spunk.h | 2 | ||||
-rw-r--r-- | lib_i386/Makefile | 2 | ||||
-rw-r--r-- | lib_i386/interrupts.c | 159 | ||||
-rw-r--r-- | lib_i386/pcat_interrupts.c | 165 |
12 files changed, 623 insertions, 422 deletions
diff --git a/cpu/i386/Makefile b/cpu/i386/Makefile index 761c4f6fcc..f72cd6ea16 100644 --- a/cpu/i386/Makefile +++ b/cpu/i386/Makefile @@ -29,7 +29,7 @@ include $(TOPDIR)/config.mk LIB = $(obj)lib$(CPU).a START = start.o start16.o resetvec.o -COBJS = serial.o interrupts.o cpu.o timer.o +COBJS = serial.o interrupts.o exceptions.o cpu.o timer.o SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) diff --git a/cpu/i386/cpu.c b/cpu/i386/cpu.c index b9af5f89d5..d91e33b947 100644 --- a/cpu/i386/cpu.c +++ b/cpu/i386/cpu.c @@ -46,6 +46,10 @@ int cpu_init(void) "orl $0x22, %eax\n" \ "movl %eax, %cr0\n" ); + /* Initialize core interrupt and exception functionality of CPU */ + cpu_init_interrupts (); + cpu_init_exceptions (); + return 0; } diff --git a/cpu/i386/exceptions.c b/cpu/i386/exceptions.c new file mode 100644 index 0000000000..bc3d434601 --- /dev/null +++ b/cpu/i386/exceptions.c @@ -0,0 +1,229 @@ +/* + * (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/interrupt.h> + +asm (".globl exp_return\n" + "exp_return:\n" + " addl $12, %esp\n" + " pop %esp\n" + " popa\n" + " iret\n"); + +char exception_stack[4096]; + +/* + * For detailed description of each exception, refer to: + * Intel® 64 and IA-32 Architectures Software Developer's Manual + * Volume 1: Basic Architecture + * Order Number: 253665-029US, November 2008 + * Table 6-1. Exceptions and Interrupts + */ +DECLARE_EXCEPTION(0, divide_error_entry); +DECLARE_EXCEPTION(1, debug_entry); +DECLARE_EXCEPTION(2, nmi_interrupt_entry); +DECLARE_EXCEPTION(3, breakpoint_entry); +DECLARE_EXCEPTION(4, overflow_entry); +DECLARE_EXCEPTION(5, bound_range_exceeded_entry); +DECLARE_EXCEPTION(6, invalid_opcode_entry); +DECLARE_EXCEPTION(7, device_not_available_entry); +DECLARE_EXCEPTION(8, double_fault_entry); +DECLARE_EXCEPTION(9, coprocessor_segment_overrun_entry); +DECLARE_EXCEPTION(10, invalid_tss_entry); +DECLARE_EXCEPTION(11, segment_not_present_entry); +DECLARE_EXCEPTION(12, stack_segment_fault_entry); +DECLARE_EXCEPTION(13, general_protection_entry); +DECLARE_EXCEPTION(14, page_fault_entry); +DECLARE_EXCEPTION(15, reserved_exception_entry); +DECLARE_EXCEPTION(16, floating_point_error_entry); +DECLARE_EXCEPTION(17, alignment_check_entry); +DECLARE_EXCEPTION(18, machine_check_entry); +DECLARE_EXCEPTION(19, simd_floating_point_exception_entry); +DECLARE_EXCEPTION(20, reserved_exception_entry); +DECLARE_EXCEPTION(21, reserved_exception_entry); +DECLARE_EXCEPTION(22, reserved_exception_entry); +DECLARE_EXCEPTION(23, reserved_exception_entry); +DECLARE_EXCEPTION(24, reserved_exception_entry); +DECLARE_EXCEPTION(25, reserved_exception_entry); +DECLARE_EXCEPTION(26, reserved_exception_entry); +DECLARE_EXCEPTION(27, reserved_exception_entry); +DECLARE_EXCEPTION(28, reserved_exception_entry); +DECLARE_EXCEPTION(29, reserved_exception_entry); +DECLARE_EXCEPTION(30, reserved_exception_entry); +DECLARE_EXCEPTION(31, reserved_exception_entry); + +__isr__ reserved_exception_entry(int cause, int ip, int seg) +{ + printf("Reserved Exception %d at %04x:%08x\n", cause, seg, ip); +} + +__isr__ divide_error_entry(int cause, int ip, int seg) +{ + printf("Divide Error (Division by zero) at %04x:%08x\n", seg, ip); + while(1); +} + +__isr__ debug_entry(int cause, int ip, int seg) +{ + printf("Debug Interrupt (Single step) at %04x:%08x\n", seg, ip); +} + +__isr__ nmi_interrupt_entry(int cause, int ip, int seg) +{ + printf("NMI Interrupt at %04x:%08x\n", seg, ip); +} + +__isr__ breakpoint_entry(int cause, int ip, int seg) +{ + printf("Breakpoint at %04x:%08x\n", seg, ip); +} + +__isr__ overflow_entry(int cause, int ip, int seg) +{ + printf("Overflow at %04x:%08x\n", seg, ip); + while(1); +} + +__isr__ bound_range_exceeded_entry(int cause, int ip, int seg) +{ + printf("BOUND Range Exceeded at %04x:%08x\n", seg, ip); + while(1); +} + +__isr__ invalid_opcode_entry(int cause, int ip, int seg) +{ + printf("Invalid Opcode (UnDefined Opcode) at %04x:%08x\n", seg, ip); + while(1); +} + +__isr__ device_not_available_entry(int cause, int ip, int seg) +{ + printf("Device Not Available (No Math Coprocessor) at %04x:%08x\n", seg, ip); + while(1); +} + +__isr__ double_fault_entry(int cause, int ip, int seg) +{ + printf("Double fault at %04x:%08x\n", seg, ip); + while(1); +} + +__isr__ coprocessor_segment_overrun_entry(int cause, int ip, int seg) +{ + printf("Co-processor segment overrun at %04x:%08x\n", seg, ip); + while(1); +} + +__isr__ invalid_tss_entry(int cause, int ip, int seg) +{ + printf("Invalid TSS at %04x:%08x\n", seg, ip); +} + +__isr__ segment_not_present_entry(int cause, int ip, int seg) +{ + printf("Segment Not Present at %04x:%08x\n", seg, ip); + while(1); +} + +__isr__ stack_segment_fault_entry(int cause, int ip, int seg) +{ + printf("Stack Segment Fault at %04x:%08x\n", seg, ip); + while(1); +} + +__isr__ general_protection_entry(int cause, int ip, int seg) +{ + printf("General Protection at %04x:%08x\n", seg, ip); +} + +__isr__ page_fault_entry(int cause, int ip, int seg) +{ + printf("Page fault at %04x:%08x\n", seg, ip); + while(1); +} + +__isr__ floating_point_error_entry(int cause, int ip, int seg) +{ + printf("Floating-Point Error (Math Fault) at %04x:%08x\n", seg, ip); +} + +__isr__ alignment_check_entry(int cause, int ip, int seg) +{ + printf("Alignment check at %04x:%08x\n", seg, ip); +} + +__isr__ machine_check_entry(int cause, int ip, int seg) +{ + printf("Machine Check at %04x:%08x\n", seg, ip); +} + +__isr__ simd_floating_point_exception_entry(int cause, int ip, int seg) +{ + printf("SIMD Floating-Point Exception at %04x:%08x\n", seg, ip); +} + +int cpu_init_exceptions(void) +{ + /* Just in case... */ + disable_interrupts(); + + /* 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); + + /* It is now safe to enable interrupts */ + enable_interrupts(); + + return 0; +} diff --git a/cpu/i386/interrupts.c b/cpu/i386/interrupts.c index badb30bb8a..026a21bd21 100644 --- a/cpu/i386/interrupts.c +++ b/cpu/i386/interrupts.c @@ -22,10 +22,6 @@ */ #include <common.h> -#include <malloc.h> -#include <asm/io.h> -#include <asm/i8259.h> -#include <asm/ibmpc.h> #include <asm/interrupt.h> @@ -41,361 +37,34 @@ struct idt_entry { 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]; - -asm ("irq_return:\n" +asm (".globl irq_return\n" + "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 */ -void set_vector(int intnum, void *routine) +void set_vector(u8 intnum, void *routine) { idt[intnum].base_high = (u16)((u32)(routine)>>16); idt[intnum].base_low = (u16)((u32)(routine)&0xffff); } -int interrupt_init(void) +int cpu_init_interrupts(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; @@ -406,89 +75,6 @@ int interrupt_init(void) 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 */ - - - /* 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(); diff --git a/include/asm-i386/interrupt.h b/include/asm-i386/interrupt.h index 315b4001ca..7f408cb944 100644 --- a/include/asm-i386/interrupt.h +++ b/include/asm-i386/interrupt.h @@ -1,7 +1,10 @@ /* - * (C) Copyright 2008 + * (C) Copyright 2009 * Graeme Russ, graeme.russ@gmail.com * + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, daniel@omicron.se + * * See file CREDITS for list of people who contributed to this * project. * @@ -24,6 +27,47 @@ #ifndef __ASM_INTERRUPT_H_ #define __ASM_INTERRUPT_H_ 1 -void set_vector(int intnum, void *routine); +/* cpu/i386/interrupts.c */ +void set_vector(u8 intnum, void *routine); + +/* lib_i386/interupts.c */ +void disable_irq(int irq); +void enable_irq(int irq); + +/* Architecture specific functions */ +void mask_irq(int irq); +void unmask_irq(int irq); +void specific_eoi(int irq); + +extern char exception_stack[]; + +#define __isr__ void __attribute__ ((regparm(0))) + +#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"); \ + __isr__ 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"); \ + __isr__ exp_##x(void) #endif diff --git a/include/asm-i386/u-boot-i386.h b/include/asm-i386/u-boot-i386.h index 12d10a78a0..9a60cacd19 100644 --- a/include/asm-i386/u-boot-i386.h +++ b/include/asm-i386/u-boot-i386.h @@ -45,6 +45,12 @@ extern ulong i386boot_bios_size; /* size of BIOS emulation code */ int cpu_init(void); int timer_init(void); +/* cpu/.../interrupts.c */ +int cpu_init_interrupts(void); + +/* cpu/.../exceptions.c */ +int cpu_init_exceptions(void); + /* board/.../... */ int board_init(void); int dram_init(void); diff --git a/include/configs/eNET.h b/include/configs/eNET.h index 2ae79d89f4..84e1aefe1f 100644 --- a/include/configs/eNET.h +++ b/include/configs/eNET.h @@ -90,7 +90,7 @@ #define CONFIG_CMD_RUN /* run command in env variable */ #define CONFIG_CMD_SETGETDCR /* DCR support on 4xx */ #define CONFIG_CMD_XIMG /* Load part of Multi Image */ -#undef CONFIG_CMD_IRQ /* IRQ Information */ +#define CONFIG_CMD_IRQ /* IRQ Information */ #define CONFIG_BOOTDELAY 15 #define CONFIG_BOOTARGS "root=/dev/mtdblock0 console=ttyS0,9600" @@ -148,6 +148,8 @@ #undef CONFIG_SYS_TSC_TIMER /* use the Pentium TSC timers */ #define CONFIG_SYS_USE_SIO_UART 0 /* prefer the uarts on the SIO to those * in the SC520 on the CDP */ +#define CONFIG_SYS_PCAT_INTERRUPTS +#define CONFIG_SYS_NUM_IRQS 16 /*----------------------------------------------------------------------- * Memory organization diff --git a/include/configs/sc520_cdp.h b/include/configs/sc520_cdp.h index cb0de421a2..19e5889ff6 100644 --- a/include/configs/sc520_cdp.h +++ b/include/configs/sc520_cdp.h @@ -53,6 +53,8 @@ #undef CONFIG_SYS_TSC_TIMER /* use the Pentium TSC timers */ #define CONFIG_SYS_USE_SIO_UART 0 /* prefer the uarts on the SIO to those * in the SC520 on the CDP */ +#define CONFIG_SYS_PCAT_INTERRUPTS +#define CONFIG_SYS_NUM_IRQS 16 #define CONFIG_SYS_STACK_SIZE 0x8000 /* Size of bootloader stack */ diff --git a/include/configs/sc520_spunk.h b/include/configs/sc520_spunk.h index 3e8618498f..20481bd499 100644 --- a/include/configs/sc520_spunk.h +++ b/include/configs/sc520_spunk.h @@ -49,6 +49,8 @@ #undef CONFIG_SYS_SC520_TIMER /* use SC520 swtimers */ #define CONFIG_SYS_GENERIC_TIMER 1 /* use the i8254 PIT timers */ #undef CONFIG_SYS_TSC_TIMER /* use the Pentium TSC timers */ +#define CONFIG_SYS_PCAT_INTERRUPTS +#define CONFIG_SYS_NUM_IRQS 16 #define CONFIG_SYS_STACK_SIZE 0x8000 /* Size of bootloader stack */ diff --git a/lib_i386/Makefile b/lib_i386/Makefile index 4fbcd08b88..fb4184b367 100644 --- a/lib_i386/Makefile +++ b/lib_i386/Makefile @@ -38,6 +38,8 @@ COBJS-y += realmode.o COBJS-y += video_bios.o COBJS-y += video.o COBJS-y += zimage.o +COBJS-y += interrupts.o +COBJS-$(CONFIG_SYS_PCAT_INTERRUPTS) += pcat_interrupts.o SRCS := $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c) OBJS := $(addprefix $(obj),$(SOBJS-y) $(COBJS-y)) diff --git a/lib_i386/interrupts.c b/lib_i386/interrupts.c new file mode 100644 index 0000000000..b0f84de4eb --- /dev/null +++ b/lib_i386/interrupts.c @@ -0,0 +1,159 @@ +/* + * (C) Copyright 2009 + * Graeme Russ, graeme.russ@gmail.com + * + * (C) Copyright 2007 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com + * + * (C) Copyright 2006 + * Detlev Zundel, DENX Software Engineering, dzu@denx.de + * + * (C) Copyright -2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, daniel@omicron.se + * + * (C) Copyright 2001 + * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc. + * + * 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 file contains the high-level API for the interrupt sub-system + * of the i386 port of U-Boot. Most of the functionality has been + * shamelessly stolen from the leon2 / leon3 ports of U-Boot. + * Daniel Hellstrom, Detlev Zundel, Wolfgang Denk and Josh Huber are + * credited for the corresponding work on those ports. The original + * interrupt handling routines for the i386 port were written by + * Daniel Engström + */ + +#include <common.h> +#include <asm/interrupt.h> + +struct irq_action { + interrupt_handler_t *handler; + void *arg; + unsigned int count; +}; + +static struct irq_action irq_handlers[CONFIG_SYS_NUM_IRQS] = { {0} }; +static int spurious_irq_cnt = 0; +static int spurious_irq = 0; + +void irq_install_handler(int irq, interrupt_handler_t *handler, void *arg) +{ + int status; + + if (irq < 0 || irq >= CONFIG_SYS_NUM_IRQS) { + printf("irq_install_handler: bad irq number %d\n", irq); + return; + } + + if (irq_handlers[irq].handler != NULL) + printf("irq_install_handler: 0x%08lx replacing 0x%08lx\n", + (ulong) handler, + (ulong) irq_handlers[irq].handler); + + status = disable_interrupts (); + + irq_handlers[irq].handler = handler; + irq_handlers[irq].arg = arg; + irq_handlers[irq].count = 0; + + unmask_irq(irq); + + if (status) + enable_interrupts(); + + return; +} + +void irq_free_handler(int irq) +{ + int status; + + if (irq < 0 || irq >= CONFIG_SYS_NUM_IRQS) { + printf("irq_free_handler: bad irq number %d\n", irq); + return; + } + + status = disable_interrupts (); + + mask_irq(irq); + + irq_handlers[irq].handler = NULL; + irq_handlers[irq].arg = NULL; + + if (status) + enable_interrupts(); + + return; +} + +__isr__ do_irq(int irq) +{ + if (irq < 0 || irq >= CONFIG_SYS_NUM_IRQS) { + printf("do_irq: bad irq number %d\n", irq); + return; + } + + if (irq_handlers[irq].handler) { + mask_irq(irq); + + irq_handlers[irq].handler(irq_handlers[irq].arg); + irq_handlers[irq].count++; + + unmask_irq(irq); + specific_eoi(irq); + + } else { + if ((irq & 7) != 7) { + spurious_irq_cnt++; + spurious_irq = irq; + } + } +} + +#if defined(CONFIG_CMD_IRQ) +int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int irq; + + printf("Spurious IRQ: %u, last unknown IRQ: %d\n", + spurious_irq_cnt, spurious_irq); + + printf ("Interrupt-Information:\n"); + printf ("Nr Routine Arg Count\n"); + + for (irq = 0; irq <= CONFIG_SYS_NUM_IRQS; irq++) { + if (irq_handlers[irq].handler != NULL) { + printf ("%02d %08lx %08lx %d\n", + irq, + (ulong)irq_handlers[irq].handler, + (ulong)irq_handlers[irq].arg, + irq_handlers[irq].count); + } + } + + return 0; +} +#endif diff --git a/lib_i386/pcat_interrupts.c b/lib_i386/pcat_interrupts.c new file mode 100644 index 0000000000..f01298e9cf --- /dev/null +++ b/lib_i386/pcat_interrupts.c @@ -0,0 +1,165 @@ +/* + * (C) Copyright 2009 + * Graeme Russ, graeme.russ@gmail.com + * + * (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 + */ + +/* + * This file provides the interrupt handling functionality for systems + * based on the standard PC/AT architecture using two cascaded i8259 + * Programmable Interrupt Controllers. + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/i8259.h> +#include <asm/ibmpc.h> +#include <asm/interrupt.h> + +#if CONFIG_SYS_NUM_IRQS != 16 +#error "CONFIG_SYS_NUM_IRQS must equal 16 if CONFIG_SYS_NUM_IRQS is defined" +#endif + +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); + +int interrupt_init(void) +{ + u8 i; + + disable_interrupts(); + + /* 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); + + /* Mask all interrupts */ + outb(0xff, MASTER_PIC + IMR); + outb(0xff, SLAVE_PIC + IMR); + + /* Master PIC */ + /* Place master PIC interrupts at INT20 */ + /* ICW3, One slave PIC is present */ + outb(ICW1_SEL|ICW1_EICW4, MASTER_PIC + ICW1); + outb(0x20, MASTER_PIC + ICW2); + outb(IR2, MASTER_PIC + ICW3); + outb(ICW4_PM, MASTER_PIC + ICW4); + + for (i = 0; i < 8; i++) + outb(OCW2_SEOI | i, MASTER_PIC + OCW2); + + /* Slave PIC */ + /* Place slave PIC interrupts at INT28 */ + /* Slave ID */ + outb(ICW1_SEL|ICW1_EICW4, SLAVE_PIC + ICW1); + outb(0x28, SLAVE_PIC + ICW2); + outb(0x02, SLAVE_PIC + ICW3); + outb(ICW4_PM, SLAVE_PIC + ICW4); + + for (i = 0; i < 8; i++) + outb(OCW2_SEOI | i, SLAVE_PIC + OCW2); + + /* + * Enable cascaded interrupts by unmasking the cascade IRQ pin of + * the master PIC + */ + unmask_irq (2); + + enable_interrupts(); + + return 0; +} + +void mask_irq(int irq) +{ + int imr_port; + + if (irq >= CONFIG_SYS_NUM_IRQS) + return; + + if (irq > 7) + imr_port = SLAVE_PIC + IMR; + else + imr_port = MASTER_PIC + IMR; + + outb(inb(imr_port) | (1 << (irq & 7)), imr_port); +} + +void unmask_irq(int irq) +{ + int imr_port; + + if (irq >= CONFIG_SYS_NUM_IRQS) + return; + + if (irq > 7) + imr_port = SLAVE_PIC + IMR; + else + imr_port = MASTER_PIC + IMR; + + outb(inb(imr_port) & ~(1 << (irq & 7)), imr_port); +} + +void specific_eoi(int irq) +{ + if (irq >= CONFIG_SYS_NUM_IRQS) + return; + + if (irq > 7) { + /* + * IRQ is on the slave - Issue a corresponding EOI to the + * slave PIC and an EOI for IRQ2 (the cascade interrupt) + * on the master PIC + */ + outb(OCW2_SEOI | (irq & 7), SLAVE_PIC + OCW2); + irq = SEOI_IR2; + } + + outb(OCW2_SEOI | irq, MASTER_PIC + OCW2); +} |