summaryrefslogtreecommitdiffstats
path: root/bsps/i386
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-23 09:50:39 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-23 15:18:44 +0200
commit8f8ccee0d9e1c3adfb1de484f26f6d9f6ff08708 (patch)
tree5dc76f7a4527b0a500fbf5ee91486b2780e47a1a /bsps/i386
parentbsps: Move SPI drivers to bsps (diff)
downloadrtems-8f8ccee0d9e1c3adfb1de484f26f6d9f6ff08708.tar.bz2
bsps: Move interrupt controller support to bsps
This patch is a part of the BSP source reorganization. Update #3285.
Diffstat (limited to 'bsps/i386')
-rw-r--r--bsps/i386/shared/irq/elcr.c170
-rw-r--r--bsps/i386/shared/irq/elcr.h37
-rw-r--r--bsps/i386/shared/irq/idt.c381
-rw-r--r--bsps/i386/shared/irq/irq.c405
-rw-r--r--bsps/i386/shared/irq/irq_asm.S268
-rw-r--r--bsps/i386/shared/irq/irq_init.c191
6 files changed, 1452 insertions, 0 deletions
diff --git a/bsps/i386/shared/irq/elcr.c b/bsps/i386/shared/irq/elcr.c
new file mode 100644
index 0000000000..f72e36c33f
--- /dev/null
+++ b/bsps/i386/shared/irq/elcr.c
@@ -0,0 +1,170 @@
+/*-
+ * Copyright (c) 2004 John Baldwin <jhb@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef __rtems__
+__FBSDID("$FreeBSD$");
+#endif /* __rtems__ */
+
+/*
+ * The ELCR is a register that controls the trigger mode and polarity of
+ * EISA and ISA interrupts. In FreeBSD 3.x and 4.x, the ELCR was only
+ * consulted for determining the appropriate trigger mode of EISA
+ * interrupts when using an APIC. However, it seems that almost all
+ * systems that include PCI also include an ELCR that manages the ISA
+ * IRQs 0 through 15. Thus, we check for the presence of an ELCR on
+ * every machine by checking to see if the values found at bootup are
+ * sane. Note that the polarity of ISA and EISA IRQs are linked to the
+ * trigger mode. All edge triggered IRQs use active-hi polarity, and
+ * all level triggered interrupts use active-lo polarity.
+ *
+ * The format of the ELCR is simple: it is a 16-bit bitmap where bit 0
+ * controls IRQ 0, bit 1 controls IRQ 1, etc. If the bit is zero, the
+ * associated IRQ is edge triggered. If the bit is one, the IRQ is
+ * level triggered.
+ */
+
+#ifndef __rtems__
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/systm.h>
+#include <machine/intr_machdep.h>
+#endif /* __rtems__ */
+
+#ifdef __rtems__
+#include <bsp.h>
+#include "i386_io.h"
+#include <errno.h>
+#include "elcr.h"
+#endif /* __rtems__ */
+
+#define ELCR_PORT 0x4d0
+#define ELCR_MASK(irq) (1 << (irq))
+
+static int elcr_status;
+#ifdef __rtems__
+static
+#endif /* __rtems__ */
+int elcr_found;
+
+#ifdef __rtems__
+#undef printf
+#define printf printk
+#define bootverbose 1
+#define KASSERT(...)
+#endif /* __rtems__ */
+
+/*
+ * Check to see if we have what looks like a valid ELCR. We do this by
+ * verifying that IRQs 0, 1, 2, and 13 are all edge triggered.
+ */
+int
+elcr_probe(void)
+{
+ int i;
+
+ elcr_status = inb(ELCR_PORT) | inb(ELCR_PORT + 1) << 8;
+ if ((elcr_status & (ELCR_MASK(0) | ELCR_MASK(1) | ELCR_MASK(2) |
+ ELCR_MASK(8) | ELCR_MASK(13))) != 0)
+ return (ENXIO);
+ if (bootverbose) {
+ printf("ELCR Found. ISA IRQs programmed as:\n");
+ for (i = 0; i < 16; i++)
+ printf(" %2d", i);
+ printf("\n");
+ for (i = 0; i < 16; i++)
+ if (elcr_status & ELCR_MASK(i))
+ printf(" L");
+ else
+ printf(" E");
+ printf("\n");
+ }
+#ifndef __rtems__
+ if (resource_disabled("elcr", 0))
+ return (ENXIO);
+#endif /* __rtems__ */
+ elcr_found = 1;
+ return (0);
+}
+
+/*
+ * Returns 1 for level trigger, 0 for edge.
+ */
+enum intr_trigger
+elcr_read_trigger(u_int irq)
+{
+#ifdef __rtems__
+ if (!elcr_found)
+ return INTR_TRIGGER_EDGE;
+#endif /* __rtems__ */
+ KASSERT(elcr_found, ("%s: no ELCR was found!", __func__));
+ KASSERT(irq <= 15, ("%s: invalid IRQ %u", __func__, irq));
+ if (elcr_status & ELCR_MASK(irq))
+ return (INTR_TRIGGER_LEVEL);
+ else
+ return (INTR_TRIGGER_EDGE);
+}
+
+/*
+ * Set the trigger mode for a specified IRQ. Mode of 0 means edge triggered,
+ * and a mode of 1 means level triggered.
+ */
+void
+elcr_write_trigger(u_int irq, enum intr_trigger trigger)
+{
+ int new_status;
+
+#ifdef __rtems__
+ if (!elcr_found)
+ return;
+#endif /* __rtems__ */
+ KASSERT(elcr_found, ("%s: no ELCR was found!", __func__));
+ KASSERT(irq <= 15, ("%s: invalid IRQ %u", __func__, irq));
+ if (trigger == INTR_TRIGGER_LEVEL)
+ new_status = elcr_status | ELCR_MASK(irq);
+ else
+ new_status = elcr_status & ~ELCR_MASK(irq);
+ if (new_status == elcr_status)
+ return;
+ elcr_status = new_status;
+ if (irq >= 8)
+ outb(ELCR_PORT + 1, elcr_status >> 8);
+ else
+ outb(ELCR_PORT, elcr_status & 0xff);
+}
+
+void
+elcr_resume(void)
+{
+#ifdef __rtems__
+ if (!elcr_found)
+ return;
+#endif /* __rtems__ */
+
+ KASSERT(elcr_found, ("%s: no ELCR was found!", __func__));
+ outb(ELCR_PORT, elcr_status & 0xff);
+ outb(ELCR_PORT + 1, elcr_status >> 8);
+}
diff --git a/bsps/i386/shared/irq/elcr.h b/bsps/i386/shared/irq/elcr.h
new file mode 100644
index 0000000000..a006d4f149
--- /dev/null
+++ b/bsps/i386/shared/irq/elcr.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2016 Chris Johns <chrisj@rtems.org>
+ *
+ * Header for the FreeBSD ported elcr.c
+ */
+
+#ifndef _IRQ_ELCR_H_
+#define _IRQ_ELCR_H_
+
+#include <sys/cdefs.h>
+
+enum intr_trigger {
+ INTR_TRIGGER_EDGE,
+ INTR_TRIGGER_LEVEL
+};
+
+/*
+ * Check to see if we have what looks like a valid ELCR. We do this by
+ * verifying that IRQs 0, 1, 2, and 13 are all edge triggered.
+ */
+int elcr_probe(void);
+
+/*
+ * Returns 1 for level trigger, 0 for edge.
+ */
+enum intr_trigger elcr_read_trigger(u_int irq);
+
+/*
+ * Set the trigger mode for a specified IRQ. Mode of 0 means edge triggered,
+ * and a mode of 1 means level triggered.
+ */
+void elcr_write_trigger(u_int irq, enum intr_trigger trigger);
+
+void elcr_resume(void);
+
+
+#endif
diff --git a/bsps/i386/shared/irq/idt.c b/bsps/i386/shared/irq/idt.c
new file mode 100644
index 0000000000..d3adbc4f05
--- /dev/null
+++ b/bsps/i386/shared/irq/idt.c
@@ -0,0 +1,381 @@
+/*
+ * cpu.c - This file contains implementation of C function to
+ * instantiate IDT entries. More detailled information can be found
+ * on Intel site and more precisely in the following book :
+ *
+ * Pentium Processor family
+ * Developper's Manual
+ *
+ * Volume 3 : Architecture and Programming Manual
+ *
+ * Copyright (C) 1998 Eric Valette (valette@crf.canon.fr)
+ * Canon Centre Recherche France.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems/score/cpu.h>
+#include <bsp/irq.h>
+#include <bsp/tblsizes.h>
+
+/*
+ * This locking is not enough if IDT is changed at runtime
+ * and entry can be changed for vector which is enabled
+ * at change time. But such use is broken anyway.
+ * Protect code only against concurrent changes.
+ * Even that is probably unnecessary if different
+ * entries are changed concurrently.
+ */
+RTEMS_INTERRUPT_LOCK_DEFINE( static, rtems_idt_access_lock, "rtems_idt_access_lock" );
+
+static rtems_raw_irq_connect_data* raw_irq_table;
+static rtems_raw_irq_connect_data default_raw_irq_entry;
+static interrupt_gate_descriptor default_idt_entry;
+static rtems_raw_irq_global_settings* local_settings;
+
+void create_interrupt_gate_descriptor (interrupt_gate_descriptor* idtEntry,
+ rtems_raw_irq_hdl hdl)
+{
+ idtEntry->low_offsets_bits = (((unsigned) hdl) & 0xffff);
+ idtEntry->segment_selector = i386_get_cs();
+ idtEntry->fixed_value_bits = 0;
+ idtEntry->gate_type = 0xe;
+ idtEntry->privilege = 0;
+ idtEntry->present = 1;
+ idtEntry->high_offsets_bits = ((((unsigned) hdl) >> 16) & 0xffff);
+}
+
+rtems_raw_irq_hdl get_hdl_from_vector(rtems_vector_offset index)
+{
+ uint32_t hdl;
+ interrupt_gate_descriptor* idt_entry_tbl;
+ unsigned limit;
+
+ i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
+
+ /* Convert limit into number of entries */
+ limit = (limit + 1) / sizeof(interrupt_gate_descriptor);
+
+ if(index >= limit) {
+ return 0;
+ }
+
+ hdl = (idt_entry_tbl[index].low_offsets_bits |
+ (idt_entry_tbl[index].high_offsets_bits << 16));
+ return (rtems_raw_irq_hdl) hdl;
+}
+
+int i386_set_idt_entry (const rtems_raw_irq_connect_data* irq)
+{
+ interrupt_gate_descriptor* idt_entry_tbl;
+ unsigned limit;
+ rtems_interrupt_lock_context lock_context;
+
+ i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
+
+ /* Convert limit into number of entries */
+ limit = (limit + 1) / sizeof(interrupt_gate_descriptor);
+
+ if (irq->idtIndex >= limit) {
+ return 0;
+ }
+ /*
+ * Check if default handler is actually connected. If not issue an error.
+ * You must first get the current handler via i386_get_current_idt_entry
+ * and then disconnect it using i386_delete_idt_entry.
+ * RATIONALE : to always have the same transition by forcing the user
+ * to get the previous handler before accepting to disconnect.
+ */
+ if (get_hdl_from_vector(irq->idtIndex) != default_raw_irq_entry.hdl) {
+ return 0;
+ }
+
+ rtems_interrupt_lock_acquire(&rtems_idt_access_lock, &lock_context);
+
+ raw_irq_table [irq->idtIndex] = *irq;
+ create_interrupt_gate_descriptor (&idt_entry_tbl[irq->idtIndex], irq->hdl);
+ if (irq->on)
+ irq->on(irq);
+
+ rtems_interrupt_lock_release(&rtems_idt_access_lock, &lock_context);
+ return 1;
+}
+
+void _CPU_ISR_install_vector (uint32_t vector,
+ proc_ptr hdl,
+ proc_ptr * oldHdl)
+{
+ interrupt_gate_descriptor* idt_entry_tbl;
+ unsigned limit;
+ interrupt_gate_descriptor new;
+ rtems_interrupt_lock_context lock_context;
+
+ i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
+
+ /* Convert limit into number of entries */
+ limit = (limit + 1) / sizeof(interrupt_gate_descriptor);
+
+ if (vector >= limit) {
+ return;
+ }
+ rtems_interrupt_lock_acquire(&rtems_idt_access_lock, &lock_context);
+ * ((unsigned int *) oldHdl) = idt_entry_tbl[vector].low_offsets_bits |
+ (idt_entry_tbl[vector].high_offsets_bits << 16);
+
+ create_interrupt_gate_descriptor(&new, hdl);
+ idt_entry_tbl[vector] = new;
+
+ rtems_interrupt_lock_release(&rtems_idt_access_lock, &lock_context);
+}
+
+int i386_get_current_idt_entry (rtems_raw_irq_connect_data* irq)
+{
+ interrupt_gate_descriptor* idt_entry_tbl;
+ unsigned limit;
+
+ i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
+
+ /* Convert limit into number of entries */
+ limit = (limit + 1) / sizeof(interrupt_gate_descriptor);
+
+ if (irq->idtIndex >= limit) {
+ return 0;
+ }
+ raw_irq_table [irq->idtIndex].hdl = get_hdl_from_vector(irq->idtIndex);
+
+ *irq = raw_irq_table [irq->idtIndex];
+
+ return 1;
+}
+
+int i386_delete_idt_entry (const rtems_raw_irq_connect_data* irq)
+{
+ interrupt_gate_descriptor* idt_entry_tbl;
+ unsigned limit;
+ rtems_interrupt_lock_context lock_context;
+
+ i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
+
+ /* Convert limit into number of entries */
+ limit = (limit + 1) / sizeof(interrupt_gate_descriptor);
+
+ if (irq->idtIndex >= limit) {
+ return 0;
+ }
+ /*
+ * Check if handler passed is actually connected. If not issue an error.
+ * You must first get the current handler via i386_get_current_idt_entry
+ * and then disconnect it using i386_delete_idt_entry.
+ * RATIONALE : to always have the same transition by forcing the user
+ * to get the previous handler before accepting to disconnect.
+ */
+ if (get_hdl_from_vector(irq->idtIndex) != irq->hdl){
+ return 0;
+ }
+ rtems_interrupt_lock_acquire(&rtems_idt_access_lock, &lock_context);
+
+ idt_entry_tbl[irq->idtIndex] = default_idt_entry;
+
+ if (irq->off)
+ irq->off(irq);
+
+ raw_irq_table[irq->idtIndex] = default_raw_irq_entry;
+ raw_irq_table[irq->idtIndex].idtIndex = irq->idtIndex;
+
+ rtems_interrupt_lock_release(&rtems_idt_access_lock, &lock_context);
+
+ return 1;
+}
+
+/*
+ * Caution this function assumes the IDTR has been already set.
+ */
+int i386_init_idt (rtems_raw_irq_global_settings* config)
+{
+ unsigned limit;
+ unsigned i;
+ rtems_interrupt_lock_context lock_context;
+ interrupt_gate_descriptor* idt_entry_tbl;
+
+ i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
+
+ /* Convert limit into number of entries */
+ limit = (limit + 1) / sizeof(interrupt_gate_descriptor);
+
+ if (config->idtSize != limit) {
+ return 0;
+ }
+ /*
+ * store various accelarators
+ */
+ raw_irq_table = config->rawIrqHdlTbl;
+ local_settings = config;
+ default_raw_irq_entry = config->defaultRawEntry;
+
+ rtems_interrupt_lock_acquire(&rtems_idt_access_lock, &lock_context);
+
+ create_interrupt_gate_descriptor (&default_idt_entry, default_raw_irq_entry.hdl);
+
+ for (i=0; i < limit; i++) {
+ interrupt_gate_descriptor new;
+ create_interrupt_gate_descriptor (&new, raw_irq_table[i].hdl);
+ idt_entry_tbl[i] = new;
+ if (raw_irq_table[i].hdl != default_raw_irq_entry.hdl) {
+ raw_irq_table[i].on(&raw_irq_table[i]);
+ }
+ else {
+ raw_irq_table[i].off(&raw_irq_table[i]);
+ }
+ }
+ rtems_interrupt_lock_release(&rtems_idt_access_lock, &lock_context);
+
+ return 1;
+}
+
+int i386_get_idt_config (rtems_raw_irq_global_settings** config)
+{
+ *config = local_settings;
+ return 1;
+}
+
+uint32_t i386_raw_gdt_entry (uint16_t segment_selector_index,
+ segment_descriptors* sd)
+{
+ uint16_t gdt_limit;
+ uint16_t tmp_segment = 0;
+ segment_descriptors* gdt_entry_tbl;
+ uint8_t present;
+
+ i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit);
+
+ if (segment_selector_index >= (gdt_limit+1)/8) {
+ /* index to GDT table out of bounds */
+ return 0;
+ }
+ if (segment_selector_index == 0) {
+ /* index 0 is not usable */
+ return 0;
+ }
+
+ /* put prepared descriptor into the GDT */
+ present = sd->present;
+ sd->present = 0;
+ gdt_entry_tbl[segment_selector_index].present = 0;
+ RTEMS_COMPILER_MEMORY_BARRIER();
+ gdt_entry_tbl[segment_selector_index] = *sd;
+ RTEMS_COMPILER_MEMORY_BARRIER();
+ gdt_entry_tbl[segment_selector_index].present = present;
+ sd->present = present;
+ /*
+ * Now, reload all segment registers so that the possible changes takes effect.
+ */
+ __asm__ volatile( "movw %%ds,%0 ; movw %0,%%ds\n\t"
+ "movw %%es,%0 ; movw %0,%%es\n\t"
+ "movw %%fs,%0 ; movw %0,%%fs\n\t"
+ "movw %%gs,%0 ; movw %0,%%gs\n\t"
+ "movw %%ss,%0 ; movw %0,%%ss"
+ : "=r" (tmp_segment)
+ : "0" (tmp_segment)
+ );
+ return 1;
+}
+
+void i386_fill_segment_desc_base(uint32_t base,
+ segment_descriptors* sd)
+{
+ sd->base_address_15_0 = base & 0xffff;
+ sd->base_address_23_16 = (base >> 16) & 0xff;
+ sd->base_address_31_24 = (base >> 24) & 0xff;
+}
+
+void i386_fill_segment_desc_limit(uint32_t limit,
+ segment_descriptors* sd)
+{
+ sd->granularity = 0;
+ if (limit > 65535) {
+ sd->granularity = 1;
+ limit /= 4096;
+ }
+ sd->limit_15_0 = limit & 0xffff;
+ sd->limit_19_16 = (limit >> 16) & 0xf;
+}
+
+/*
+ * Caution this function assumes the GDTR has been already set.
+ */
+uint32_t i386_set_gdt_entry (uint16_t segment_selector_index, uint32_t base,
+ uint32_t limit)
+{
+ segment_descriptors gdt_entry;
+ memset(&gdt_entry, 0, sizeof(gdt_entry));
+
+ i386_fill_segment_desc_limit(limit, &gdt_entry);
+ i386_fill_segment_desc_base(base, &gdt_entry);
+ /*
+ * set up descriptor type (this may well becomes a parameter if needed)
+ */
+ gdt_entry.type = 2; /* Data R/W */
+ gdt_entry.descriptor_type = 1; /* Code or Data */
+ gdt_entry.privilege = 0; /* ring 0 */
+ gdt_entry.present = 1; /* not present */
+
+ /*
+ * Now, reload all segment registers so the limit takes effect.
+ */
+ return i386_raw_gdt_entry(segment_selector_index, &gdt_entry);
+}
+
+uint16_t i386_next_empty_gdt_entry ()
+{
+ uint16_t gdt_limit;
+ segment_descriptors* gdt_entry_tbl;
+ /* initial amount of filled descriptors */
+ static uint16_t segment_selector_index = NUM_SYSTEM_GDT_DESCRIPTORS - 1;
+
+ segment_selector_index += 1;
+ i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit);
+ if (segment_selector_index >= (gdt_limit+1)/8) {
+ return 0;
+ }
+ return segment_selector_index;
+}
+
+uint16_t i386_cpy_gdt_entry(uint16_t segment_selector_index,
+ segment_descriptors* struct_to_fill)
+{
+ uint16_t gdt_limit;
+ segment_descriptors* gdt_entry_tbl;
+
+ i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit);
+
+ if (segment_selector_index >= (gdt_limit+1)/8) {
+ return 0;
+ }
+
+ *struct_to_fill = gdt_entry_tbl[segment_selector_index];
+ return segment_selector_index;
+}
+
+segment_descriptors* i386_get_gdt_entry(uint16_t segment_selector_index)
+{
+ uint16_t gdt_limit;
+ segment_descriptors* gdt_entry_tbl;
+
+ i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit);
+
+ if (segment_selector_index >= (gdt_limit+1)/8) {
+ return 0;
+ }
+ return &gdt_entry_tbl[segment_selector_index];
+}
+
+uint32_t i386_limit_gdt_entry(segment_descriptors* gdt_entry)
+{
+ uint32_t lim = (gdt_entry->limit_15_0 + (gdt_entry->limit_19_16<<16));
+ if (gdt_entry->granularity) {
+ return lim*4096+4095;
+ }
+ return lim;
+}
diff --git a/bsps/i386/shared/irq/irq.c b/bsps/i386/shared/irq/irq.c
new file mode 100644
index 0000000000..ac08f1f7be
--- /dev/null
+++ b/bsps/i386/shared/irq/irq.c
@@ -0,0 +1,405 @@
+/*
+ * This file contains the implementation of the function described in irq.h
+ */
+
+/*
+ * Copyright (c) 2009 embedded brains GmbH
+ * Copyright (C) 1998 valette@crf.canon.fr
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <bsp/irq.h>
+#include <bsp/irq-generic.h>
+#include <rtems/score/cpu.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+
+#include "elcr.h"
+
+RTEMS_INTERRUPT_LOCK_DEFINE( static, rtems_i8259_access_lock, "rtems_i8259_access_lock" );
+
+/*
+ * pointer to the mask representing the additionnal irq vectors
+ * that must be disabled when a particular entry is activated.
+ * They will be dynamically computed from teh prioruty table given
+ * in BSP_rtems_irq_mngt_set();
+ * CAUTION : this table is accessed directly by interrupt routine
+ * prologue.
+ */
+static rtems_i8259_masks irq_mask_or_tbl[BSP_IRQ_LINES_NUMBER];
+
+/*
+ * Stats of interrupts dispatched.
+ */
+static uint32_t irq_count[BSP_IRQ_VECTOR_NUMBER] = {0};
+static uint32_t spurious_count;
+
+/*
+ * Edge or level trigger interrupts.
+ */
+static enum intr_trigger irq_trigger[BSP_IRQ_LINES_NUMBER];
+
+/*-------------------------------------------------------------------------+
+| Cache for 1st and 2nd PIC IRQ line's mssk (enabled or disabled) register.
++--------------------------------------------------------------------------*/
+/*
+ * lower byte is interrupt mask on the master PIC.
+ * while upper bits are interrupt on the slave PIC.
+ * This cache is initialized in ldseg.s
+ */
+static rtems_i8259_masks i8259a_imr_cache = 0xFFFB;
+static rtems_i8259_masks i8259a_in_progress = 0;
+
+static inline
+void BSP_i8259a_irq_update_master_imr( void )
+{
+ rtems_i8259_masks mask = i8259a_in_progress | i8259a_imr_cache;
+ outport_byte( PIC_MASTER_IMR_IO_PORT, mask & 0xff );
+}
+
+static inline
+void BSP_i8259a_irq_update_slave_imr( void )
+{
+ rtems_i8259_masks mask = i8259a_in_progress | i8259a_imr_cache;
+ outport_byte( PIC_SLAVE_IMR_IO_PORT, ( mask >> 8 ) & 0xff );
+}
+
+/*
+ * Print the stats.
+ */
+uint32_t BSP_irq_count_dump(FILE *f)
+{
+ uint32_t tot = 0;
+ int i;
+ if ( !f )
+ f = stdout;
+ fprintf(f,"SPURIOUS: %9"PRIu32"\n", spurious_count);
+ for ( i = 0; i < BSP_IRQ_VECTOR_NUMBER; i++ ) {
+ char type = '-';
+ if (i < BSP_IRQ_LINES_NUMBER)
+ type = irq_trigger[i] == INTR_TRIGGER_EDGE ? 'E' : 'L';
+ tot += irq_count[i];
+ fprintf(f,"IRQ %2u: %c %9"PRIu32"\n", i, type, irq_count[i]);
+ }
+ return tot;
+}
+
+/*
+ * Is the IRQ valid?
+ */
+static inline bool BSP_i8259a_irq_valid(const rtems_irq_number irqLine)
+{
+ return ((int)irqLine >= BSP_IRQ_VECTOR_LOWEST_OFFSET) &&
+ ((int)irqLine <= BSP_IRQ_MAX_ON_i8259A);
+}
+
+/*
+ * Read the IRR register. The default.
+ */
+static inline uint8_t BSP_i8259a_irq_int_request_reg(uint32_t ioport)
+{
+ uint8_t isr;
+ inport_byte(ioport, isr);
+ return isr;
+}
+
+/*
+ * Read the ISR register. Keep the default of the IRR.
+ */
+static inline uint8_t BSP_i8259a_irq_in_service_reg(uint32_t ioport)
+{
+ uint8_t isr;
+ outport_byte(ioport, PIC_OCW3_SEL | PIC_OCW3_RR | PIC_OCW3_RIS);
+ inport_byte(ioport, isr);
+ outport_byte(ioport, PIC_OCW3_SEL | PIC_OCW3_RR);
+ return isr;
+}
+
+/*-------------------------------------------------------------------------+
+| Function: BSP_irq_disable_at_i8259a
+| Description: Mask IRQ line in appropriate PIC chip.
+| Global Variables: i8259a_imr_cache, i8259a_in_progress
+| Arguments: vector_offset - number of IRQ line to mask.
+| Returns: 0 is OK.
++--------------------------------------------------------------------------*/
+static int BSP_irq_disable_at_i8259a(const rtems_irq_number irqLine)
+{
+ unsigned short mask;
+ rtems_interrupt_lock_context lock_context;
+
+ rtems_interrupt_lock_acquire(&rtems_i8259_access_lock, &lock_context);
+
+ mask = 1 << irqLine;
+ i8259a_imr_cache |= mask;
+
+ if (irqLine < 8)
+ {
+ BSP_i8259a_irq_update_master_imr();
+ }
+ else
+ {
+ BSP_i8259a_irq_update_slave_imr();
+ }
+
+ rtems_interrupt_lock_release(&rtems_i8259_access_lock, &lock_context);
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------+
+| Function: BSP_irq_enable_at_i8259a
+| Description: Unmask IRQ line in appropriate PIC chip.
+| Global Variables: i8259a_imr_cache, i8259a_in_progress
+| Arguments: irqLine - number of IRQ line to mask.
+| Returns: Nothing.
++--------------------------------------------------------------------------*/
+static int BSP_irq_enable_at_i8259a(const rtems_irq_number irqLine)
+{
+ unsigned short mask;
+ rtems_interrupt_lock_context lock_context;
+ uint8_t isr;
+ uint8_t irr;
+
+ rtems_interrupt_lock_acquire(&rtems_i8259_access_lock, &lock_context);
+
+ mask = 1 << irqLine;
+ i8259a_imr_cache &= ~mask;
+
+ if (irqLine < 8)
+ {
+ isr = BSP_i8259a_irq_in_service_reg(PIC_MASTER_COMMAND_IO_PORT);
+ irr = BSP_i8259a_irq_int_request_reg(PIC_MASTER_COMMAND_IO_PORT);
+ BSP_i8259a_irq_update_master_imr();
+ }
+ else
+ {
+ isr = BSP_i8259a_irq_in_service_reg(PIC_SLAVE_COMMAND_IO_PORT);
+ irr = BSP_i8259a_irq_int_request_reg(PIC_SLAVE_COMMAND_IO_PORT);
+ BSP_i8259a_irq_update_slave_imr();
+ }
+
+ if (((isr ^ irr) & mask) != 0)
+ printk("i386: isr=%x irr=%x\n", isr, irr);
+
+ rtems_interrupt_lock_release(&rtems_i8259_access_lock, &lock_context);
+
+ return 0;
+} /* mask_irq */
+
+/*-------------------------------------------------------------------------+
+| Function: BSP_irq_ack_at_i8259a
+| Description: Signal generic End Of Interrupt (EOI) to appropriate PIC.
+| Global Variables: None.
+| Arguments: irqLine - number of IRQ line to acknowledge.
+| Returns: Nothing.
++--------------------------------------------------------------------------*/
+static int BSP_irq_ack_at_i8259a(const rtems_irq_number irqLine)
+{
+ uint8_t slave_isr = 0;
+
+ if (irqLine >= 8) {
+ outport_byte(PIC_SLAVE_COMMAND_IO_PORT, PIC_EOI);
+ slave_isr = BSP_i8259a_irq_in_service_reg(PIC_SLAVE_COMMAND_IO_PORT);
+ }
+
+ /*
+ * Only issue the EOI to the master if there are no more interrupts in
+ * service for the slave. i8259a data sheet page 18, The Special Fully Nested
+ * Mode, b.
+ */
+ if (slave_isr == 0)
+ outport_byte(PIC_MASTER_COMMAND_IO_PORT, PIC_EOI);
+
+ return 0;
+
+} /* ackIRQ */
+
+/*
+ * ------------------------ RTEMS Irq helper functions ----------------
+ */
+
+static rtems_irq_prio irqPrioTable[BSP_IRQ_LINES_NUMBER]={
+ /*
+ * actual priorities for each interrupt source:
+ * 0 means that only current interrupt is masked
+ * 255 means all other interrupts are masked
+ * The second entry has a priority of 255 because
+ * it is the slave pic entry and is should always remain
+ * unmasked.
+ */
+ 0,0,
+ 255,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static void compute_i8259_masks_from_prio (void)
+{
+ rtems_interrupt_lock_context lock_context;
+ unsigned int i;
+ unsigned int j;
+
+ rtems_interrupt_lock_acquire(&rtems_i8259_access_lock, &lock_context);
+
+ /*
+ * Always mask at least current interrupt to prevent re-entrance
+ */
+ for (i=0; i < BSP_IRQ_LINES_NUMBER; i++) {
+ * ((unsigned short*) &irq_mask_or_tbl[i]) = (1 << i);
+ for (j = 0; j < BSP_IRQ_LINES_NUMBER; j++) {
+ /*
+ * Mask interrupts at i8259 level that have a lower priority
+ */
+ if (irqPrioTable [i] > irqPrioTable [j]) {
+ * ((unsigned short*) &irq_mask_or_tbl[i]) |= (1 << j);
+ }
+ }
+ }
+
+ rtems_interrupt_lock_release(&rtems_i8259_access_lock, &lock_context);
+}
+
+static inline bool bsp_interrupt_vector_is_valid(rtems_vector_number vector)
+{
+ return BSP_i8259a_irq_valid((const rtems_irq_number) vector);
+}
+
+void bsp_interrupt_vector_enable(rtems_vector_number vector)
+{
+ bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
+ BSP_irq_enable_at_i8259a(vector);
+}
+
+void bsp_interrupt_vector_disable(rtems_vector_number vector)
+{
+ bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
+ BSP_irq_disable_at_i8259a(vector);
+}
+
+rtems_status_code bsp_interrupt_facility_initialize(void)
+{
+ int i;
+
+ /*
+ * set up internal tables used by rtems interrupt prologue
+ */
+ compute_i8259_masks_from_prio();
+
+ /*
+ * must enable slave pic anyway
+ */
+ BSP_irq_enable_at_i8259a(2);
+
+ /*
+ * Probe the ELCR.
+ */
+ elcr_probe();
+
+ for (i = 0; i < BSP_IRQ_LINES_NUMBER; i++)
+ irq_trigger[i] = elcr_read_trigger(i);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * Global so the asm handler can call it.
+ */
+void BSP_dispatch_isr(int vector);
+
+void BSP_dispatch_isr(int vector)
+{
+ rtems_interrupt_lock_context lock_context;
+ rtems_i8259_masks in_progress_save = 0;
+
+ if (vector < BSP_IRQ_VECTOR_NUMBER) {
+ /*
+ * Hardware?
+ */
+ if (vector <= BSP_IRQ_MAX_ON_i8259A) {
+
+ rtems_interrupt_lock_acquire_isr(&rtems_i8259_access_lock, &lock_context);
+
+ /*
+ * See if this is a spurious interrupt.
+ */
+ if ((vector == 7 || vector == 15)) {
+ /*
+ * Only check it there no handler for 7 or 15.
+ */
+ if (bsp_interrupt_handler_is_empty(vector)) {
+ /*
+ * Read the ISR register to see if IRQ 7/15 is really pending.
+ */
+ uint8_t isr = BSP_i8259a_irq_in_service_reg(PIC_MASTER_COMMAND_IO_PORT);
+ if ((isr & (1 << 7)) == 0) {
+ ++spurious_count;
+ rtems_interrupt_lock_release_isr(&rtems_i8259_access_lock, &lock_context);
+ return;
+ }
+ }
+ }
+
+ /*
+ * Save the current cached value for the IMR. It will have the bit for this
+ * vector clear.
+ */
+ if (vector <= BSP_IRQ_MAX_ON_i8259A) {
+ in_progress_save = i8259a_in_progress;
+ i8259a_in_progress |= irq_mask_or_tbl[vector];
+ BSP_i8259a_irq_update_master_imr();
+ BSP_i8259a_irq_update_slave_imr();
+ }
+
+ /*
+ * Do not use auto-EOI as some slave PIC do not work correctly.
+ */
+ BSP_irq_ack_at_i8259a(vector);
+
+ rtems_interrupt_lock_release_isr(&rtems_i8259_access_lock, &lock_context);
+ }
+
+ /*
+ * Count the interrupt.
+ */
+ irq_count[vector]++;
+
+ RTEMS_COMPILER_MEMORY_BARRIER();
+ /*
+ * Allow nesting.
+ */
+ __asm__ __volatile__("sti");
+
+ bsp_interrupt_handler_dispatch(vector);
+
+ /*
+ * Disallow nesting.
+ */
+ __asm__ __volatile__("cli");
+
+ RTEMS_COMPILER_MEMORY_BARRIER();
+
+ if (vector <= BSP_IRQ_MAX_ON_i8259A) {
+
+ rtems_interrupt_lock_acquire_isr(&rtems_i8259_access_lock, &lock_context);
+
+ /*
+ * Put the mask back but keep this vector masked if the trigger type is
+ * level. The driver or a thread level interrupt server needs to enable it
+ * again.
+ */
+ if (vector <= BSP_IRQ_MAX_ON_i8259A) {
+ i8259a_in_progress = in_progress_save;
+ BSP_i8259a_irq_update_master_imr();
+ BSP_i8259a_irq_update_slave_imr();
+ }
+
+ rtems_interrupt_lock_release_isr(&rtems_i8259_access_lock, &lock_context);
+ }
+ }
+}
diff --git a/bsps/i386/shared/irq/irq_asm.S b/bsps/i386/shared/irq/irq_asm.S
new file mode 100644
index 0000000000..181293351e
--- /dev/null
+++ b/bsps/i386/shared/irq/irq_asm.S
@@ -0,0 +1,268 @@
+/*
+ * This file contains the implementation of the function described in irq.h
+ */
+
+/*
+ * Copyright (C) 1998 valette@crf.canon.fr
+ *
+ * COPYRIGHT (c) 1989-2011.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems/asm.h>
+#include <rtems/system.h>
+#include <bspopts.h>
+#include <rtems/score/cpu.h>
+#include <rtems/score/percpu.h>
+
+#include <bsp.h> /* to establish dependency on prototype */
+
+#ifndef CPU_STACK_ALIGNMENT
+#error "Missing header? CPU_STACK_ALIGNMENT is not defined here"
+#endif
+
+/* Stack frame we use for intermediate storage */
+#define ARG_OFF 0
+#define MSK_OFF 4 /* not used any more */
+#define EBX_OFF 8 /* ebx */
+#define EBP_OFF 12 /* code restoring ebp/esp relies on */
+#define ESP_OFF 16 /* esp being on top of ebp! */
+#ifdef __SSE__
+/* need to be on 16 byte boundary for SSE, add 12 to do that */
+#define FRM_SIZ (20+12+512)
+#define SSE_OFF 32
+#else
+#define FRM_SIZ 20
+#endif
+
+ BEGIN_CODE
+
+SYM (_ISR_Handler):
+ /*
+ * Before this was point is reached the vectors unique
+ * entry point did the following:
+ *
+ * 1. saved scratch registers registers eax edx ecx"
+ * 2. put the vector number in ecx.
+ *
+ * BEGINNING OF ESTABLISH SEGMENTS
+ *
+ * WARNING: If an interrupt can occur when the segments are
+ * not correct, then this is where we should establish
+ * the segments. In addition to establishing the
+ * segments, it may be necessary to establish a stack
+ * in the current data area on the outermost interrupt.
+ *
+ * NOTE: If the previous values of the segment registers are
+ * pushed, do not forget to adjust SAVED_REGS.
+ *
+ * NOTE: Make sure the exit code which restores these
+ * when this type of code is needed.
+ */
+
+ /***** ESTABLISH SEGMENTS CODE GOES HERE ******/
+
+ /*
+ * END OF ESTABLISH SEGMENTS
+ */
+
+ /*
+ * Establish an aligned stack frame
+ * original sp
+ * saved ebx
+ * saved ebp
+ * saved irq mask
+ * vector arg to BSP_dispatch_isr <- aligned SP
+ */
+ movl esp, eax
+ subl $FRM_SIZ, esp
+ andl $ - CPU_STACK_ALIGNMENT, esp
+ movl ebx, EBX_OFF(esp)
+ movl eax, ESP_OFF(esp)
+ movl ebp, EBP_OFF(esp)
+
+ /*
+ * GCC versions starting with 4.3 no longer place the cld
+ * instruction before string operations. We need to ensure
+ * it is set correctly for ISR handlers.
+ */
+ cld
+
+#ifdef __SSE__
+ /* NOTE: SSE only is supported if the BSP enables fxsave/fxrstor
+ * to save/restore SSE context! This is so far only implemented
+ * for pc386!.
+ */
+
+ /* We save SSE here (on the task stack) because we possibly
+ * call other C-code (besides the ISR, namely _Thread_Dispatch())
+ */
+ /* don't wait here; a possible exception condition will eventually be
+ * detected when the task resumes control and executes a FP instruction
+ fwait
+ */
+ fxsave SSE_OFF(esp)
+ fninit /* clean-slate FPU */
+ movl $0x1f80, ARG_OFF(esp) /* use ARG_OFF as scratch space */
+ ldmxcsr ARG_OFF(esp) /* clean-slate MXCSR */
+#endif
+
+ /*
+ * Now switch stacks if necessary
+ */
+
+PUBLIC (ISR_STOP)
+ISR_STOP:
+.check_stack_switch:
+ movl esp, ebp /* ebp = previous stack pointer */
+
+#ifdef RTEMS_SMP
+ call SYM(_CPU_SMP_Get_current_processor)
+ sall $PER_CPU_CONTROL_SIZE_LOG2, eax
+ addl $SYM(_Per_CPU_Information), eax
+ movl eax, ebx
+#else
+ movl $SYM(_Per_CPU_Information), ebx
+#endif
+
+ /* is this the outermost interrupt? */
+ cmpl $0, PER_CPU_ISR_NEST_LEVEL(ebx)
+ jne nested /* No, then continue */
+ movl PER_CPU_INTERRUPT_STACK_HIGH(ebx), esp
+
+ /*
+ * We want to insure that the old stack pointer is in ebp
+ * By saving it on every interrupt, all we have to do is
+ * movl ebp->esp near the end of every interrupt.
+ */
+
+nested:
+ incl PER_CPU_ISR_NEST_LEVEL(ebx) /* one nest level deeper */
+ incl PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(ebx) /* disable
+ multitasking */
+ /*
+ * ECX is preloaded with the vector number; store as arg
+ * on top of stack. Note that _CPU_Interrupt_stack_high
+ * was adjusted in _CPU_Interrupt_stack_setup() (score/rtems/cpu.h)
+ * to make sure there is space.
+ */
+
+ movl ecx, ARG_OFF(esp) /* store vector arg in stack */
+ call BSP_dispatch_isr
+
+ movl ARG_OFF(esp), ecx /* grab vector arg from stack */
+
+ /*
+ * Restore stack. This moves back to the task stack
+ * when all interrupts are unnested.
+ */
+ movl ebp, esp
+
+ decl PER_CPU_ISR_NEST_LEVEL(ebx) /* one less ISR nest level */
+ /* If interrupts are nested, */
+ /* then dispatching is disabled */
+
+ decl PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(ebx)
+ /* unnest multitasking */
+ /* Is dispatch disabled */
+ jne .exit /* Yes, then exit */
+
+ cmpb $0, PER_CPU_DISPATCH_NEEDED(ebx)
+ /* Is task switch necessary? */
+ jne .schedule /* Yes, then call the scheduler */
+ jmp .exit /* No, exit */
+
+.schedule:
+ /*
+ * the scratch registers have already been saved and we are already
+ * back on the thread system stack. So we can call _Thread_Dispatch
+ * directly
+ */
+ call _Thread_Dispatch
+ /*
+ * fall through exit to restore complete contex (scratch registers
+ * eip, CS, Flags).
+ */
+.exit:
+
+#ifdef __SSE__
+ fwait
+ fxrstor SSE_OFF(esp)
+#endif
+
+ /* restore ebx, ebp and original esp */
+ addl $EBX_OFF, esp
+ popl ebx
+ popl ebp
+ popl esp
+
+ /*
+ * BEGINNING OF DE-ESTABLISH SEGMENTS
+ *
+ * NOTE: Make sure there is code here if code is added to
+ * load the segment registers.
+ *
+ */
+
+ /******* DE-ESTABLISH SEGMENTS CODE GOES HERE ********/
+
+ /*
+ * END OF DE-ESTABLISH SEGMENTS
+ */
+ popl edx
+ popl ecx
+ popl eax
+ iret
+
+#define DISTINCT_INTERRUPT_ENTRY(_vector) \
+ .p2align 4 ; \
+ PUBLIC (rtems_irq_prologue_ ## _vector ) ; \
+SYM (rtems_irq_prologue_ ## _vector ): \
+ pushl eax ; \
+ pushl ecx ; \
+ pushl edx ; \
+ movl $ _vector, ecx ; \
+ jmp SYM (_ISR_Handler) ;
+
+DISTINCT_INTERRUPT_ENTRY(0)
+DISTINCT_INTERRUPT_ENTRY(1)
+DISTINCT_INTERRUPT_ENTRY(2)
+DISTINCT_INTERRUPT_ENTRY(3)
+DISTINCT_INTERRUPT_ENTRY(4)
+DISTINCT_INTERRUPT_ENTRY(5)
+DISTINCT_INTERRUPT_ENTRY(6)
+DISTINCT_INTERRUPT_ENTRY(7)
+DISTINCT_INTERRUPT_ENTRY(8)
+DISTINCT_INTERRUPT_ENTRY(9)
+DISTINCT_INTERRUPT_ENTRY(10)
+DISTINCT_INTERRUPT_ENTRY(11)
+DISTINCT_INTERRUPT_ENTRY(12)
+DISTINCT_INTERRUPT_ENTRY(13)
+DISTINCT_INTERRUPT_ENTRY(14)
+DISTINCT_INTERRUPT_ENTRY(15)
+DISTINCT_INTERRUPT_ENTRY(16)
+
+ /*
+ * routine used to initialize the IDT by default
+ */
+
+PUBLIC (default_raw_idt_handler)
+PUBLIC (raw_idt_notify)
+
+SYM (default_raw_idt_handler):
+ pusha
+ cld
+ mov esp, ebp
+ andl $ - CPU_STACK_ALIGNMENT, esp
+ call raw_idt_notify
+ mov ebp, esp
+ popa
+ iret
+
+END_CODE
+
+END
diff --git a/bsps/i386/shared/irq/irq_init.c b/bsps/i386/shared/irq/irq_init.c
new file mode 100644
index 0000000000..fdf4801a5a
--- /dev/null
+++ b/bsps/i386/shared/irq/irq_init.c
@@ -0,0 +1,191 @@
+/* irq_init.c
+ *
+ * This file contains the implementation of rtems initialization
+ * related to interrupt handling.
+ *
+ * Copyright (c) 2009 embedded brains GmbH
+ * CopyRight (C) 1998 valette@crf.canon.fr
+ *
+ * COPYRIGHT (c) 2011.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems/bspIo.h>
+
+#include <rtems/score/cpu.h>
+
+#include <bsp.h>
+#include <bsp/irq.h>
+#include <bsp/irq-generic.h>
+
+/*
+ * rtems prologue generated in irq_asm.S
+ */
+extern void rtems_irq_prologue_0(void);
+extern void rtems_irq_prologue_1(void);
+extern void rtems_irq_prologue_2(void);
+extern void rtems_irq_prologue_3(void);
+extern void rtems_irq_prologue_4(void);
+extern void rtems_irq_prologue_5(void);
+extern void rtems_irq_prologue_6(void);
+extern void rtems_irq_prologue_7(void);
+extern void rtems_irq_prologue_8(void);
+extern void rtems_irq_prologue_9(void);
+extern void rtems_irq_prologue_10(void);
+extern void rtems_irq_prologue_11(void);
+extern void rtems_irq_prologue_12(void);
+extern void rtems_irq_prologue_13(void);
+extern void rtems_irq_prologue_14(void);
+extern void rtems_irq_prologue_15(void);
+extern void rtems_irq_prologue_16(void);
+/*
+ * default vectors
+ */
+extern void default_raw_idt_handler(void);
+
+/*
+ * default raw on/off function
+ */
+static void raw_nop_func(const struct __rtems_raw_irq_connect_data__ *unused)
+{
+}
+
+/*
+ * default raw isOn function
+ */
+static int raw_not_connected(
+ const struct __rtems_raw_irq_connect_data__ *unused
+)
+{
+ return 0;
+}
+
+static rtems_raw_irq_connect_data idtHdl[IDT_SIZE];
+
+static rtems_raw_irq_hdl rtemsIrq[BSP_IRQ_VECTOR_NUMBER] = {
+ rtems_irq_prologue_0,
+ rtems_irq_prologue_1,
+ rtems_irq_prologue_2,
+ rtems_irq_prologue_3,
+ rtems_irq_prologue_4,
+ rtems_irq_prologue_5,
+ rtems_irq_prologue_6,
+ rtems_irq_prologue_7,
+ rtems_irq_prologue_8,
+ rtems_irq_prologue_9,
+ rtems_irq_prologue_10,
+ rtems_irq_prologue_11,
+ rtems_irq_prologue_12,
+ rtems_irq_prologue_13,
+ rtems_irq_prologue_14,
+ rtems_irq_prologue_15,
+ rtems_irq_prologue_16,
+};
+
+static rtems_raw_irq_connect_data defaultRawIrq = {
+ 0, /* vectorIdex */
+ default_raw_idt_handler, /* hdl */
+ raw_nop_func, /* on */
+ raw_nop_func, /* off */
+ raw_not_connected /* isOn */
+};
+
+static interrupt_gate_descriptor idtEntry;
+
+static rtems_raw_irq_global_settings raw_initial_config;
+
+
+/*
+ * This method is called from irq_asm.S and cannot be static.
+ */
+void raw_idt_notify(void)
+{
+ printk("raw_idt_notify has been called \n");
+}
+
+void rtems_irq_mngt_init(void)
+{
+ int i;
+ interrupt_gate_descriptor* idt_entry_tbl;
+ unsigned int limit;
+ rtems_interrupt_level level;
+
+ i386_get_info_from_IDTR(&idt_entry_tbl, &limit);
+
+ /* Convert into number of entries */
+ limit = (limit + 1)/sizeof(interrupt_gate_descriptor);
+
+ if(limit != IDT_SIZE) {
+ printk("IDT table size mismatch !!! System locked\n");
+ while(1);
+ }
+
+ /*
+ * The interrupt management can be initialized only once
+ * during system bootup and that should happen on boot
+ * CPU so there is no need to synchronize with others CPUs.
+ */
+ rtems_interrupt_local_disable(level);
+
+ /*
+ * Init the complete IDT vector table with defaultRawIrq value
+ */
+ for (i = 0; i < IDT_SIZE ; i++) {
+ idtHdl[i] = defaultRawIrq;
+ idtHdl[i].idtIndex = i;
+ }
+
+ raw_initial_config.idtSize = IDT_SIZE;
+ raw_initial_config.defaultRawEntry = defaultRawIrq;
+ raw_initial_config.rawIrqHdlTbl = idtHdl;
+
+ if (!i386_init_idt (&raw_initial_config)) {
+ /*
+ * put something here that will show the failure...
+ */
+ printk("Unable to initialize IDT!!! System locked\n");
+ while (1);
+ }
+ /*
+ * Patch the entry that will be used by RTEMS for interrupt management
+ * with RTEMS prologue.
+ */
+ for (i = 0; i < BSP_IRQ_VECTOR_NUMBER; i++) {
+ create_interrupt_gate_descriptor(&idtEntry, rtemsIrq[i]);
+ idt_entry_tbl[i + BSP_ASM_IRQ_VECTOR_BASE] = idtEntry;
+ }
+ /*
+ * At this point we have completed the initialization of IDT
+ * with raw handlers. We must now initialize the higher level
+ * interrupt management.
+ */
+
+ /*
+ * Init initial Interrupt management config
+ */
+ bsp_interrupt_initialize();
+
+ /*
+ * #define DEBUG
+ */
+#ifdef DEBUG
+ {
+ /*
+ * following adresses should be the same
+ */
+ unsigned tmp;
+
+ printk("idt_entry_tbl = %x Interrupt_descriptor_table addr = %x\n",
+ idt_entry_tbl, &Interrupt_descriptor_table);
+ tmp = (unsigned) get_hdl_from_vector (BSP_ASM_IRQ_VECTOR_BASE + BSP_PERIODIC_TIMER);
+ printk("clock isr address from idt = %x should be %x\n",
+ tmp, (unsigned) rtems_irq_prologue_0);
+ }
+ printk("i8259s_cache = %x\n", * (unsigned short*) &i8259s_cache);
+ BSP_wait_polled_input();
+#endif
+}