summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libcpu
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>1998-07-23 22:02:34 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>1998-07-23 22:02:34 +0000
commit67a2288991ce3662a588ee83c0bea9c9efae5f1e (patch)
treea8d68b22bfd313619f2a0d0b2e3b4755b8278b9d /c/src/lib/libcpu
parentPatch from Ralf Corsepius <corsepiu@faw.uni-ulm.de>: (diff)
downloadrtems-67a2288991ce3662a588ee83c0bea9c9efae5f1e.tar.bz2
Patch from Eric VALETTE <valette@crf.canon.fr>:
Here is a enhanced version of my previous patch. This patch enables to potentially share the new interrupt management code for all Intel targets (pc386, go32 and force386) bsp. Note : this patch is complete only for pc386. It still needs to be completed for go32 and force386. I carrefully checked that anything needed is in for force386 (only some function name changes for IDT manipulation and GDT segment manipulation). But anyway I will not be able to test any of theses targets...
Diffstat (limited to 'c/src/lib/libcpu')
-rw-r--r--c/src/lib/libcpu/i386/Makefile.in64
-rw-r--r--c/src/lib/libcpu/i386/cpu.c265
-rw-r--r--c/src/lib/libcpu/i386/cpu.h365
-rw-r--r--c/src/lib/libcpu/i386/cpu_asm.S117
-rw-r--r--c/src/lib/libcpu/i386/idt.c265
-rw-r--r--c/src/lib/libcpu/i386/wrapup/Makefile.in50
6 files changed, 1126 insertions, 0 deletions
diff --git a/c/src/lib/libcpu/i386/Makefile.in b/c/src/lib/libcpu/i386/Makefile.in
new file mode 100644
index 0000000000..8a1c6f0951
--- /dev/null
+++ b/c/src/lib/libcpu/i386/Makefile.in
@@ -0,0 +1,64 @@
+#
+# $Id$
+#
+
+@SET_MAKE@
+srcdir = @srcdir@
+VPATH = @srcdir@
+RTEMS_ROOT = @top_srcdir@
+PROJECT_ROOT = @PROJECT_ROOT@
+
+PGM=${ARCH}/libcpu.rel
+
+# C source names, if any, go here -- minus the .c
+C_PIECES=cpu
+C_FILES=$(C_PIECES:%=%.c)
+C_O_FILES=$(C_PIECES:%=${ARCH}/%.o)
+
+H_FILES=$(srcdir)/cpu.h
+
+# Assembly source names, if any, go here -- minus the .s
+S_PIECES=cpu_asm
+S_FILES=$(S_PIECES:%=%.S)
+S_O_FILES=$(S_FILES:%.S=${ARCH}/%.o)
+
+SRCS=$(C_FILES) $(H_FILES)
+OBJS=$(C_O_FILES) $(S_O_FILES)
+
+include $(RTEMS_ROOT)/make/custom/$(RTEMS_BSP).cfg
+include $(RTEMS_ROOT)/make/leaf.cfg
+
+#
+# (OPTIONAL) Add local stuff here using +=
+#
+
+DEFINES +=
+CPPFLAGS +=
+CFLAGS +=
+
+LD_PATHS +=
+LD_LIBS +=
+LDFLAGS +=
+
+#
+# Add your list of files to delete here. The config files
+# already know how to delete some stuff, so you may want
+# to just run 'make clean' first to see what gets missed.
+# 'make clobber' already includes 'make clean'
+#
+
+CLEAN_ADDITIONS +=
+CLOBBER_ADDITIONS +=
+
+${PGM}: ${SRCS} ${OBJS}
+ $(make-rel)
+
+preinstall :
+ $(MKDIR) $(PROJECT_INCLUDE)/libcpu
+ $(INSTALL) -m 444 ${H_FILES} $(PROJECT_INCLUDE)/libcpu
+
+all: ${ARCH} $(SRCS) preinstall $(OBJ) $(PGM)
+ cd wrapup; $(MAKE)
+
+# the .rel file built here will be put into libcpu.a by ../wrapup/Makefile
+install: all
diff --git a/c/src/lib/libcpu/i386/cpu.c b/c/src/lib/libcpu/i386/cpu.c
new file mode 100644
index 0000000000..8873de3811
--- /dev/null
+++ b/c/src/lib/libcpu/i386/cpu.c
@@ -0,0 +1,265 @@
+/*
+ * cpu.c - This file contains implementation of C function to
+ * Instanciate IDT entries. More detailled information can be found
+ * on Intel site and more precisely in the following book :
+ *
+ * Pentium Processor familly
+ * 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 found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <libcpu/cpu.h>
+#include <irq.h>
+
+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)
+{
+ rtems_raw_irq_hdl hdl;
+ interrupt_gate_descriptor* idt_entry_tbl;
+ unsigned limit;
+
+ i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
+
+ * ((unsigned int*) &hdl) = (idt_entry_tbl[index].low_offsets_bits |
+ (idt_entry_tbl[index].high_offsets_bits << 16));
+ return hdl;
+}
+
+int i386_set_idt_entry (const rtems_raw_irq_connect_data* irq)
+{
+ interrupt_gate_descriptor* idt_entry_tbl;
+ unsigned limit;
+ unsigned int level;
+
+
+ i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
+
+ 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;
+ }
+ _CPU_ISR_Disable(level);
+
+ raw_irq_table [irq->idtIndex] = *irq;
+ create_interrupt_gate_descriptor (&idt_entry_tbl[irq->idtIndex], irq->hdl);
+ irq->on(irq);
+
+ _CPU_ISR_Enable(level);
+ return 1;
+}
+
+void _CPU_ISR_install_vector (unsigned vector,
+ void* hdl,
+ void** oldHdl)
+{
+ interrupt_gate_descriptor* idt_entry_tbl;
+ unsigned limit;
+ interrupt_gate_descriptor new;
+ unsigned int level;
+
+ i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
+
+ if (vector > limit) {
+ return;
+ }
+ _CPU_ISR_Disable(level)
+ * ((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;
+
+ _CPU_ISR_Enable(level);
+}
+
+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);
+
+ if (irq->idtIndex > limit) {
+ return 1;
+ }
+ raw_irq_table [irq->idtIndex].hdl = get_hdl_from_vector(irq->idtIndex);
+
+ *irq = raw_irq_table [irq->idtIndex];
+
+ return 0;
+}
+
+int i386_delete_idt_entry (const rtems_raw_irq_connect_data* irq)
+{
+ interrupt_gate_descriptor* idt_entry_tbl;
+ unsigned limit;
+ unsigned int level;
+
+ i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
+
+ if (irq->idtIndex > limit) {
+ return 1;
+ }
+ /*
+ * 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 1;
+ }
+ _CPU_ISR_Disable(level);
+
+ idt_entry_tbl[irq->idtIndex] = default_idt_entry;
+
+ irq->off(irq);
+
+ raw_irq_table[irq->idtIndex] = default_raw_irq_entry;
+
+ _CPU_ISR_Enable(level);
+
+ return 0;
+}
+
+/*
+ * Caution this function assumes the IDTR has been already set.
+ */
+int i386_init_idt (rtems_raw_irq_global_settings* config)
+{
+ unsigned limit;
+ unsigned i;
+ unsigned level;
+ interrupt_gate_descriptor* idt_entry_tbl;
+
+ i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
+
+
+ if (config->idtSize != limit) {
+ return 1;
+ }
+ /*
+ * store various accelarators
+ */
+ raw_irq_table = config->rawIrqHdlTbl;
+ local_settings = config;
+ default_raw_irq_entry = config->defaultRawEntry;
+
+ _CPU_ISR_Disable(level);
+
+ 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]);
+ }
+ }
+ _CPU_ISR_Enable(level);
+
+ return 0;
+}
+
+int i386_get_idt_config (rtems_raw_irq_global_settings** config)
+{
+ *config = local_settings;
+ return 0;
+}
+
+/*
+ * Caution this function assumes the GDTR has been already set.
+ */
+int i386_set_gdt_entry (unsigned short segment_selector, unsigned base,
+ unsigned limit)
+{
+ unsigned gdt_limit;
+ unsigned short tmp_segment = 0;
+ unsigned int limit_adjusted;
+ segment_descriptors* gdt_entry_tbl;
+
+
+ i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit);
+
+ if (segment_selector > limit) {
+ return 1;
+ }
+ /*
+ * set up limit first
+ */
+ limit_adjusted = limit;
+ if ( limit > 4095 ) {
+ gdt_entry_tbl[segment_selector].granularity = 1;
+ limit_adjusted /= 4096;
+ }
+ gdt_entry_tbl[segment_selector].limit_15_0 = limit_adjusted & 0xffff;
+ gdt_entry_tbl[segment_selector].limit_19_16 = (limit_adjusted >> 16) & 0xf;
+ /*
+ * set up base
+ */
+ gdt_entry_tbl[segment_selector].base_address_15_0 = base & 0xffff;
+ gdt_entry_tbl[segment_selector].base_address_23_16 = (base >> 16) & 0xff;
+ gdt_entry_tbl[segment_selector].base_address_31_24 = (base >> 24) & 0xff;
+ /*
+ * set up descriptor type (this may well becomes a parameter if needed)
+ */
+ gdt_entry_tbl[segment_selector].type = 2; /* Data R/W */
+ gdt_entry_tbl[segment_selector].descriptor_type = 1; /* Code or Data */
+ gdt_entry_tbl[segment_selector].privilege = 0; /* ring 0 */
+ gdt_entry_tbl[segment_selector].present = 1; /* not present */
+
+ /*
+ * Now, reload all segment registers so the limit takes effect.
+ */
+
+ asm volatile( "movw %%ds,%0 ; movw %0,%%ds
+ movw %%es,%0 ; movw %0,%%es
+ movw %%fs,%0 ; movw %0,%%fs
+ movw %%gs,%0 ; movw %0,%%gs
+ movw %%ss,%0 ; movw %0,%%ss"
+ : "=r" (tmp_segment)
+ : "0" (tmp_segment)
+ );
+
+ return 0;
+}
diff --git a/c/src/lib/libcpu/i386/cpu.h b/c/src/lib/libcpu/i386/cpu.h
new file mode 100644
index 0000000000..cded552740
--- /dev/null
+++ b/c/src/lib/libcpu/i386/cpu.h
@@ -0,0 +1,365 @@
+/*
+ * cpu.h - This file contains definitions for data structure related
+ * to Intel system programming. More information can be found
+ * on Intel site and more precisely in the following book :
+ *
+ * Pentium Processor familly
+ * 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 found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#ifndef _i386_CPU_H
+#define _i386_CPU_H
+
+#ifndef ASM
+
+/*
+ * Interrupt Level Macros
+ */
+
+#define i386_disable_interrupts( _level ) \
+ { \
+ _level = 0; /* avoids warnings */ \
+ asm volatile ( "pushf ; \
+ cli ; \
+ pop %0" \
+ : "=r" ((_level)) : "0" ((_level)) \
+ ); \
+ }
+
+#define i386_enable_interrupts( _level ) \
+ { \
+ asm volatile ( "push %0 ; \
+ popf" \
+ : "=r" ((_level)) : "0" ((_level)) \
+ ); \
+ }
+
+#define i386_flash_interrupts( _level ) \
+ { \
+ asm volatile ( "push %0 ; \
+ popf ; \
+ cli" \
+ : "=r" ((_level)) : "0" ((_level)) \
+ ); \
+ }
+
+#define i386_get_interrupt_level( _level ) \
+ do { \
+ register unsigned32 _eflags = 0; \
+ \
+ asm volatile ( "pushf ; \
+ pop %0" \
+ : "=r" ((_eflags)) : "0" ((_eflags)) \
+ ); \
+ \
+ _level = (_eflags & 0x0200) ? 0 : 1; \
+ } while (0)
+
+#define _CPU_ISR_Disable( _level ) i386_disable_interrupts( _level )
+#define _CPU_ISR_Enable( _level ) i386_enable_interrupts( _level )
+
+/*
+ * Segment Access Routines
+ *
+ * NOTE: Unfortunately, these are still static inlines even when the
+ * "macro" implementation of the generic code is used.
+ */
+
+static inline unsigned short i386_get_cs()
+{
+ register unsigned short segment = 0;
+
+ asm volatile ( "movw %%cs,%0" : "=r" (segment) : "0" (segment) );
+
+ return segment;
+}
+
+static inline unsigned short i386_get_ds()
+{
+ register unsigned short segment = 0;
+
+ asm volatile ( "movw %%ds,%0" : "=r" (segment) : "0" (segment) );
+
+ return segment;
+}
+
+static inline unsigned short i386_get_es()
+{
+ register unsigned short segment = 0;
+
+ asm volatile ( "movw %%es,%0" : "=r" (segment) : "0" (segment) );
+
+ return segment;
+}
+
+static inline unsigned short i386_get_ss()
+{
+ register unsigned short segment = 0;
+
+ asm volatile ( "movw %%ss,%0" : "=r" (segment) : "0" (segment) );
+
+ return segment;
+}
+
+static inline unsigned short i386_get_fs()
+{
+ register unsigned short segment = 0;
+
+ asm volatile ( "movw %%fs,%0" : "=r" (segment) : "0" (segment) );
+
+ return segment;
+}
+
+static inline unsigned short i386_get_gs()
+{
+ register unsigned short segment = 0;
+
+ asm volatile ( "movw %%gs,%0" : "=r" (segment) : "0" (segment) );
+
+ return segment;
+}
+
+/*
+ * IO Port Access Routines
+ */
+
+#define i386_outport_byte( _port, _value ) \
+ { register unsigned short __port = _port; \
+ register unsigned char __value = _value; \
+ \
+ asm volatile ( "outb %0,%1" : "=a" (__value), "=d" (__port) \
+ : "0" (__value), "1" (__port) \
+ ); \
+ }
+
+#define i386_outport_word( _port, _value ) \
+ { register unsigned short __port = _port; \
+ register unsigned short __value = _value; \
+ \
+ asm volatile ( "outw %0,%1" : "=a" (__value), "=d" (__port) \
+ : "0" (__value), "1" (__port) \
+ ); \
+ }
+
+#define i386_outport_long( _port, _value ) \
+ { register unsigned short __port = _port; \
+ register unsigned int __value = _value; \
+ \
+ asm volatile ( "outl %0,%1" : "=a" (__value), "=d" (__port) \
+ : "0" (__value), "1" (__port) \
+ ); \
+ }
+
+#define i386_inport_byte( _port, _value ) \
+ { register unsigned short __port = _port; \
+ register unsigned char __value = 0; \
+ \
+ asm volatile ( "inb %1,%0" : "=a" (__value), "=d" (__port) \
+ : "0" (__value), "1" (__port) \
+ ); \
+ _value = __value; \
+ }
+
+#define i386_inport_word( _port, _value ) \
+ { register unsigned short __port = _port; \
+ register unsigned short __value = 0; \
+ \
+ asm volatile ( "inw %1,%0" : "=a" (__value), "=d" (__port) \
+ : "0" (__value), "1" (__port) \
+ ); \
+ _value = __value; \
+ }
+
+#define i386_inport_long( _port, _value ) \
+ { register unsigned short __port = _port; \
+ register unsigned int __value = 0; \
+ \
+ asm volatile ( "inl %1,%0" : "=a" (__value), "=d" (__port) \
+ : "0" (__value), "1" (__port) \
+ ); \
+ _value = __value; \
+ }
+
+/*
+ * Type definition for raw interrupts.
+ */
+
+typedef unsigned char rtems_vector_offset;
+
+struct __rtems_raw_irq_connect_data__;
+
+typedef void (*rtems_raw_irq_hdl) (void);
+typedef void (*rtems_raw_irq_enable) (const struct __rtems_raw_irq_connect_data__*);
+typedef void (*rtems_raw_irq_disable) (const struct __rtems_raw_irq_connect_data__*);
+typedef int (*rtems_raw_irq_is_enabled) (const struct __rtems_raw_irq_connect_data__*);
+
+typedef struct __rtems_raw_irq_connect_data__{
+ /*
+ * IDT vector offset (IRQ line + PC386_IRQ_VECTOR_BASE)
+ */
+ rtems_vector_offset idtIndex;
+ /*
+ * IDT raw handler. See comment on handler properties below in function prototype.
+ */
+ rtems_raw_irq_hdl hdl;
+ /*
+ * function for enabling raw interrupts. In order to be consistent
+ * with the fact that the raw connexion can defined in the
+ * libcpu library, this library should have no knowledge of
+ * board specific hardware to manage interrupts and thus the
+ * "on" routine must enable the irq both at device and PIC level.
+ *
+ */
+ rtems_raw_irq_enable on;
+ /*
+ * function for disabling raw interrupts. In order to be consistent
+ * with the fact that the raw connexion can defined in the
+ * libcpu library, this library should have no knowledge of
+ * board specific hardware to manage interrupts and thus the
+ * "on" routine must disable the irq both at device and PIC level.
+ *
+ */
+ rtems_raw_irq_disable off;
+ /*
+ * function enabling to know what interrupt may currently occur
+ */
+ rtems_raw_irq_is_enabled isOn;
+}rtems_raw_irq_connect_data;
+
+typedef struct {
+ /*
+ * size of all the table fields (*Tbl) described below.
+ */
+ unsigned int idtSize;
+ /*
+ * Default handler used when disconnecting interrupts.
+ */
+ rtems_raw_irq_connect_data defaultRawEntry;
+ /*
+ * Table containing initials/current value.
+ */
+ rtems_raw_irq_connect_data* rawIrqHdlTbl;
+}rtems_raw_irq_global_settings;
+
+/*
+ * See page 14.9 Figure 14-2.
+ *
+ */
+typedef struct {
+ unsigned int low_offsets_bits : 16;
+ unsigned int segment_selector : 16;
+ unsigned int fixed_value_bits : 8;
+ unsigned int gate_type : 5;
+ unsigned int privilege : 2;
+ unsigned int present : 1;
+ unsigned int high_offsets_bits: 16;
+}interrupt_gate_descriptor;
+
+
+/*
+ * C callable function enabling to create a interrupt_gate_descriptor
+ */
+void create_interrupt_gate_descriptor (interrupt_gate_descriptor*, rtems_raw_irq_hdl);
+
+/*
+ * C callable function enabling to get handler currently connected to a vector
+ *
+ */
+rtems_raw_irq_hdl get_hdl_from_vector(rtems_vector_offset);
+
+/*
+ * C callable function enabling to get easilly usable info from
+ * the actual value of IDT register.
+ */
+extern void i386_get_info_from_IDTR (interrupt_gate_descriptor** table,
+ unsigned* limit);
+/*
+ * C callable function enabling to change the value of IDT register. Must be called
+ * with interrupts masked at processor level!!!.
+ */
+extern void i386_set_IDTR (interrupt_gate_descriptor* table,
+ unsigned limit);
+
+/*
+ * C callable function enabling to set up one raw idt entry
+ */
+extern int i386_set_idt_entry (const rtems_raw_irq_connect_data*);
+
+/*
+ * C callable function enabling to get one current raw idt entry
+ */
+extern int i386_get_current_idt_entry (rtems_raw_irq_connect_data*);
+
+/*
+ * C callable function enabling to remove one current raw idt entry
+ */
+extern int i386_delete_idt_entry (const rtems_raw_irq_connect_data*);
+
+/*
+ * C callable function enabling to init idt.
+ *
+ * CAUTION : this function assumes that the IDTR register
+ * has been already set.
+ */
+extern int i386_init_idt (rtems_raw_irq_global_settings* config);
+
+/*
+ * C callable function enabling to get actual idt configuration
+ */
+extern int i386_get_idt_config (rtems_raw_irq_global_settings** config);
+
+
+/*
+ * See page 11.12 Figure 11-8.
+ *
+ */
+
+typedef struct {
+ unsigned int limit_15_0 : 16;
+ unsigned int base_address_15_0 : 16;
+ unsigned int base_address_23_16 : 8;
+ unsigned int type : 4;
+ unsigned int descriptor_type : 1;
+ unsigned int privilege : 2;
+ unsigned int present : 1;
+ unsigned int limit_19_16 : 4;
+ unsigned int available : 1;
+ unsigned int fixed_value_bits : 1;
+ unsigned int operation_size : 1;
+ unsigned int granularity : 1;
+ unsigned int base_address_31_24 : 8;
+}segment_descriptors;
+
+/*
+ * C callable function enabling to get easilly usable info from
+ * the actual value of GDT register.
+ */
+extern void i386_get_info_from_GDTR (segment_descriptors** table,
+ unsigned* limit);
+/*
+ * C callable function enabling to change the value of GDT register. Must be called
+ * with interrupts masked at processor level!!!.
+ */
+extern void i386_set_GDTR (segment_descriptors*,
+ unsigned limit);
+
+/*
+ * C callable function enabling to set up one raw interrupt handler
+ */
+extern int i386_set_gdt_entry (unsigned short segment_selector, unsigned base,
+ unsigned limit);
+
+# endif /* ASM */
+
+#endif
diff --git a/c/src/lib/libcpu/i386/cpu_asm.S b/c/src/lib/libcpu/i386/cpu_asm.S
new file mode 100644
index 0000000000..38dc7318ae
--- /dev/null
+++ b/c/src/lib/libcpu/i386/cpu_asm.S
@@ -0,0 +1,117 @@
+/* cpu_asm.S
+ *
+ * This file contains all assembly code for the Intel i386 IDT
+ * manipulation.
+ *
+ * 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.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <asm.h>
+
+BEGIN_CODE
+/*
+ * C callable function enabling to get easilly usable info from
+ * the actual value of IDT register.
+ *
+extern void i386_get_info_from_IDTR (interrupt_gate_descriptor** table,
+ unsigned* limit);
+ */
+PUBLIC (i386_get_info_from_IDTR)
+PUBLIC (i386_set_IDTR)
+PUBLIC (i386_get_info_from_GDTR)
+PUBLIC (i386_set_GDTR)
+
+SYM (i386_get_info_from_IDTR):
+ movl 4(esp), ecx /* get location where table address */
+ /* must be stored */
+ movl 8(esp), edx /* get location table size must be stored */
+
+ subl $6, esp /* let room to prepare 48 bit IDTR */
+
+ sidt (esp) /* get 48 bit IDTR value */
+
+ movl 2(esp), eax /* get base */
+ movl eax, (ecx)
+
+ movzwl (esp), eax /* get limit */
+ movl eax, (edx)
+
+ addl $6, esp /* restore %esp */
+ ret
+
+/*
+ * C callable function enabling to change the value of IDT register. Must be called
+ * with inmterrupt masked at processor level!!!.
+ *
+extern void i386_set_IDTR (interrupt_gate_descriptor* table,
+ unsigned limit);
+ */
+SYM (i386_set_IDTR):
+
+ leal 4(esp), edx /* load in edx address of input */
+ /* parameter "table" */
+
+ movl (edx), eax /* load base into eax */
+ movl 4(edx), ecx /* load limit into ecx */
+
+ movw cx, (edx) /* prepare 48 bit pointer */
+ movl eax, 2(edx)
+
+ lidt (edx)
+
+ ret
+/*
+ *
+ * C callable function enabling to get easilly usable info from
+ * the actual value of GDT register.
+extern void i386_get_info_from_GDTR (segment_descriptors** table,
+ unsigned* limit);
+ */
+
+SYM (i386_get_info_from_GDTR):
+ movl 4(esp), ecx /* get location where table address */
+ /* must be stored */
+ movl 8(esp), edx /* get location table size must be stored */
+
+ subl $6, esp /* let room to prepare 48 bit GDTR */
+
+ sgdt (esp) /* get 48 bit GDTR value */
+
+ movl 2(esp), eax /* get base */
+ movl eax, (ecx)
+
+ movzwl (esp), eax /* get limit */
+ movl eax, (edx)
+
+ addl $6, esp /* restore %esp */
+ ret
+
+/*
+ * C callable function enabling to change the value of GDT register.
+ * Must be called with interrupts masked at processor level!!!.
+ * extern void i386_set_GDTR (segment_descriptors*, unsigned limit);
+ */
+SYM (i386_set_GDTR):
+
+ leal 4(esp), edx /* load in edx address of input */
+ /* parameter "table" */
+
+ movl (edx), eax /* load base into eax */
+ movl 4(edx), ecx /* load limit into ecx */
+
+ movw cx, (edx) /* prepare 48 bit pointer */
+ movl eax, 2(edx)
+
+ lgdt (edx)
+
+ ret
+
+END_CODE
+
+END
diff --git a/c/src/lib/libcpu/i386/idt.c b/c/src/lib/libcpu/i386/idt.c
new file mode 100644
index 0000000000..8873de3811
--- /dev/null
+++ b/c/src/lib/libcpu/i386/idt.c
@@ -0,0 +1,265 @@
+/*
+ * cpu.c - This file contains implementation of C function to
+ * Instanciate IDT entries. More detailled information can be found
+ * on Intel site and more precisely in the following book :
+ *
+ * Pentium Processor familly
+ * 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 found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <libcpu/cpu.h>
+#include <irq.h>
+
+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)
+{
+ rtems_raw_irq_hdl hdl;
+ interrupt_gate_descriptor* idt_entry_tbl;
+ unsigned limit;
+
+ i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
+
+ * ((unsigned int*) &hdl) = (idt_entry_tbl[index].low_offsets_bits |
+ (idt_entry_tbl[index].high_offsets_bits << 16));
+ return hdl;
+}
+
+int i386_set_idt_entry (const rtems_raw_irq_connect_data* irq)
+{
+ interrupt_gate_descriptor* idt_entry_tbl;
+ unsigned limit;
+ unsigned int level;
+
+
+ i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
+
+ 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;
+ }
+ _CPU_ISR_Disable(level);
+
+ raw_irq_table [irq->idtIndex] = *irq;
+ create_interrupt_gate_descriptor (&idt_entry_tbl[irq->idtIndex], irq->hdl);
+ irq->on(irq);
+
+ _CPU_ISR_Enable(level);
+ return 1;
+}
+
+void _CPU_ISR_install_vector (unsigned vector,
+ void* hdl,
+ void** oldHdl)
+{
+ interrupt_gate_descriptor* idt_entry_tbl;
+ unsigned limit;
+ interrupt_gate_descriptor new;
+ unsigned int level;
+
+ i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
+
+ if (vector > limit) {
+ return;
+ }
+ _CPU_ISR_Disable(level)
+ * ((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;
+
+ _CPU_ISR_Enable(level);
+}
+
+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);
+
+ if (irq->idtIndex > limit) {
+ return 1;
+ }
+ raw_irq_table [irq->idtIndex].hdl = get_hdl_from_vector(irq->idtIndex);
+
+ *irq = raw_irq_table [irq->idtIndex];
+
+ return 0;
+}
+
+int i386_delete_idt_entry (const rtems_raw_irq_connect_data* irq)
+{
+ interrupt_gate_descriptor* idt_entry_tbl;
+ unsigned limit;
+ unsigned int level;
+
+ i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
+
+ if (irq->idtIndex > limit) {
+ return 1;
+ }
+ /*
+ * 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 1;
+ }
+ _CPU_ISR_Disable(level);
+
+ idt_entry_tbl[irq->idtIndex] = default_idt_entry;
+
+ irq->off(irq);
+
+ raw_irq_table[irq->idtIndex] = default_raw_irq_entry;
+
+ _CPU_ISR_Enable(level);
+
+ return 0;
+}
+
+/*
+ * Caution this function assumes the IDTR has been already set.
+ */
+int i386_init_idt (rtems_raw_irq_global_settings* config)
+{
+ unsigned limit;
+ unsigned i;
+ unsigned level;
+ interrupt_gate_descriptor* idt_entry_tbl;
+
+ i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
+
+
+ if (config->idtSize != limit) {
+ return 1;
+ }
+ /*
+ * store various accelarators
+ */
+ raw_irq_table = config->rawIrqHdlTbl;
+ local_settings = config;
+ default_raw_irq_entry = config->defaultRawEntry;
+
+ _CPU_ISR_Disable(level);
+
+ 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]);
+ }
+ }
+ _CPU_ISR_Enable(level);
+
+ return 0;
+}
+
+int i386_get_idt_config (rtems_raw_irq_global_settings** config)
+{
+ *config = local_settings;
+ return 0;
+}
+
+/*
+ * Caution this function assumes the GDTR has been already set.
+ */
+int i386_set_gdt_entry (unsigned short segment_selector, unsigned base,
+ unsigned limit)
+{
+ unsigned gdt_limit;
+ unsigned short tmp_segment = 0;
+ unsigned int limit_adjusted;
+ segment_descriptors* gdt_entry_tbl;
+
+
+ i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit);
+
+ if (segment_selector > limit) {
+ return 1;
+ }
+ /*
+ * set up limit first
+ */
+ limit_adjusted = limit;
+ if ( limit > 4095 ) {
+ gdt_entry_tbl[segment_selector].granularity = 1;
+ limit_adjusted /= 4096;
+ }
+ gdt_entry_tbl[segment_selector].limit_15_0 = limit_adjusted & 0xffff;
+ gdt_entry_tbl[segment_selector].limit_19_16 = (limit_adjusted >> 16) & 0xf;
+ /*
+ * set up base
+ */
+ gdt_entry_tbl[segment_selector].base_address_15_0 = base & 0xffff;
+ gdt_entry_tbl[segment_selector].base_address_23_16 = (base >> 16) & 0xff;
+ gdt_entry_tbl[segment_selector].base_address_31_24 = (base >> 24) & 0xff;
+ /*
+ * set up descriptor type (this may well becomes a parameter if needed)
+ */
+ gdt_entry_tbl[segment_selector].type = 2; /* Data R/W */
+ gdt_entry_tbl[segment_selector].descriptor_type = 1; /* Code or Data */
+ gdt_entry_tbl[segment_selector].privilege = 0; /* ring 0 */
+ gdt_entry_tbl[segment_selector].present = 1; /* not present */
+
+ /*
+ * Now, reload all segment registers so the limit takes effect.
+ */
+
+ asm volatile( "movw %%ds,%0 ; movw %0,%%ds
+ movw %%es,%0 ; movw %0,%%es
+ movw %%fs,%0 ; movw %0,%%fs
+ movw %%gs,%0 ; movw %0,%%gs
+ movw %%ss,%0 ; movw %0,%%ss"
+ : "=r" (tmp_segment)
+ : "0" (tmp_segment)
+ );
+
+ return 0;
+}
diff --git a/c/src/lib/libcpu/i386/wrapup/Makefile.in b/c/src/lib/libcpu/i386/wrapup/Makefile.in
new file mode 100644
index 0000000000..aa05a7fae7
--- /dev/null
+++ b/c/src/lib/libcpu/i386/wrapup/Makefile.in
@@ -0,0 +1,50 @@
+#
+# $Id$
+#
+
+@SET_MAKE@
+srcdir = @srcdir@
+VPATH = @srcdir@
+RTEMS_ROOT = @top_srcdir@
+PROJECT_ROOT = @PROJECT_ROOT@
+
+BSP_PIECES=startup clock console timer
+GENERIC_PIECES=
+
+# bummer; have to use $foreach since % pattern subst rules only replace 1x
+OBJS=../$(ARCH)/libcpu.rel
+LIB=$(ARCH)/libcpu.a
+
+include $(RTEMS_ROOT)/make/custom/$(RTEMS_BSP).cfg
+include $(RTEMS_ROOT)/make/lib.cfg
+
+#
+# (OPTIONAL) Add local stuff here using +=
+#
+
+DEFINES +=
+CPPFLAGS +=
+CFLAGS +=
+
+LD_PATHS +=
+LD_LIBS +=
+LDFLAGS +=
+
+#
+# Add your list of files to delete here. The config files
+# already know how to delete some stuff, so you may want
+# to just run 'make clean' first to see what gets missed.
+# 'make clobber' already includes 'make clean'
+#
+
+CLEAN_ADDITIONS +=
+CLOBBER_ADDITIONS +=
+
+$(LIB): ${OBJS}
+ $(make-library)
+
+all: ${ARCH} $(SRCS) $(LIB)
+ $(INSTALL_VARIANT) -m 644 $(LIB) ${PROJECT_RELEASE}/lib
+# we create here a directory specific to the PC386 BSP to store the BootImage
+# files so they can be easily found
+ mkdir -p ${PROJECT_RELEASE}/BootImgs