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...
This commit is contained in:
Joel Sherrill
1998-07-23 22:02:34 +00:00
parent 73452854c0
commit 67a2288991
36 changed files with 2772 additions and 632 deletions

View File

@@ -31,7 +31,7 @@ endif
include $(RTEMS_ROOT)/make/main.cfg
MTARGETS = all install $(TARGET_VARIANTS) $(TARGET_VARIANTS:%=%_all) \
MTARGETS = pre_install_src all install $(TARGET_VARIANTS) $(TARGET_VARIANTS:%=%_all) \
$(TARGET_VARIANTS:%=%_install) $(TARGET_VARIANTS:%=%_tests) \
clean_wrapup distclean clean_dirs clean_tools tests clean depend

View File

@@ -49,7 +49,19 @@ CREATE_DIRS = \
# Make all/install must include 'env'
# if something is added to TARGET_VARIANTS, then account for it here
all: env
make_src_makefiles: Makefile.in Makefile
find . -name Makefile -exec grep -q ^preinstall {} \; -print > make_src_makefiles
pre_install_src: env make_src_makefiles
cd build-tools/scripts; $(MAKE)
CURRDIR=`pwd`; \
for i in `cat make_src_makefiles` ; do \
DIR=`dirname $$i`; \
cd $$DIR; \
$(MAKE) preinstall; \
cd $$CURRDIR; \
done
all: pre_install_src env
debug: env
profile: env

View File

@@ -76,102 +76,3 @@ unsigned32 _CPU_ISR_Get_level( void )
return level;
}
/*PAGE
*
* _CPU_ISR_install_raw_handler
*/
#if __GO32__
#include <go32.h>
#include <dpmi.h>
#endif /* __GO32__ */
void _CPU_ISR_install_raw_handler(
unsigned32 vector,
proc_ptr new_handler,
proc_ptr *old_handler
)
{
#if __GO32__
_go32_dpmi_seginfo handler_info;
/* get the address of the old handler */
_go32_dpmi_get_protected_mode_interrupt_vector( vector, &handler_info);
/* Notice how we're failing to save the pm_segment portion of the */
/* structure here? That means we might crash the system if we */
/* try to restore the ISR. Can't fix this until i386_isr is */
/* redefined. XXX [BHC]. */
*old_handler = (proc_ptr *) handler_info.pm_offset;
handler_info.pm_offset = (u_long) new_handler;
handler_info.pm_selector = _go32_my_cs();
/* install the IDT entry */
_go32_dpmi_set_protected_mode_interrupt_vector( vector, &handler_info );
#else
i386_IDT_slot idt;
unsigned32 handler;
*old_handler = 0; /* XXX not supported */
handler = (unsigned32) new_handler;
/* build the IDT entry */
idt.offset_0_15 = handler & 0xffff;
idt.segment_selector = i386_get_cs();
idt.reserved = 0x00;
idt.p_dpl = 0x8e; /* present, ISR */
idt.offset_16_31 = handler >> 16;
/* install the IDT entry */
i386_Install_idt(
(unsigned32) &idt,
_CPU_Table.interrupt_table_segment,
(unsigned32) _CPU_Table.interrupt_table_offset + (8 * vector)
);
#endif
}
/*PAGE
*
* _CPU_ISR_install_vector
*
* This kernel routine installs the RTEMS handler for the
* specified vector.
*
* Input parameters:
* vector - interrupt vector number
* old_handler - former ISR for this vector number
* new_handler - replacement ISR for this vector number
*
* Output parameters: NONE
*
*/
void _ISR_Handler_0(), _ISR_Handler_1();
#define PER_ISR_ENTRY \
(((unsigned32) _ISR_Handler_1 - (unsigned32) _ISR_Handler_0))
#define _Interrupt_Handler_entry( _vector ) \
(((unsigned32)_ISR_Handler_0) + ((_vector) * PER_ISR_ENTRY))
void _CPU_ISR_install_vector(
unsigned32 vector,
proc_ptr new_handler,
proc_ptr *old_handler
)
{
proc_ptr ignored;
unsigned32 unique_handler;
*old_handler = _ISR_Vector_table[ vector ];
/* calculate the unique entry point for this vector */
unique_handler = _Interrupt_Handler_entry( vector );
_CPU_ISR_install_raw_handler( vector, (void *)unique_handler, &ignored );
_ISR_Vector_table[ vector ] = new_handler;
}

View File

@@ -22,6 +22,8 @@ extern "C" {
#endif
#include <rtems/score/i386.h> /* pick up machine definitions */
#include <libcpu/cpu.h>
#ifndef ASM
#include <rtems/score/i386types.h>
#endif

View File

@@ -552,46 +552,6 @@ SYM (_ISR_Dispatch):
*/
#ifndef __GO32__
/*PAGE
*
* void i386_Install_idt(
* unsigned32 source_offset,
* unsigned16 destination_segment,
* unsigned32 destination_offset
* );
*/
.p2align 2
PUBLIC (i386_Install_idt)
.set INSTALL_IDT_SAVED_REGS, 8
.set SOURCE_OFFSET_ARG, INSTALL_IDT_SAVED_REGS + 4
.set DESTINATION_SEGMENT_ARG, INSTALL_IDT_SAVED_REGS + 8
.set DESTINATION_OFFSET_ARG, INSTALL_IDT_SAVED_REGS + 12
SYM (i386_Install_idt):
push esi
push edi
movl SOURCE_OFFSET_ARG(esp),esi
movl DESTINATION_OFFSET_ARG(esp),edi
pushf # save flags
cli # DISABLE INTERRUPTS!!!
movw DESTINATION_SEGMENT_ARG+4(esp),ax
push es # save es
movw ax,es
movsl # copy 1st half of IDT entry
movsl # copy 2nd half of IDT entry
pop es # restore es
popf # ENABLE INTERRUPTS!!!
pop edi
pop esi
ret
/*
* void *i386_Logical_to_physical(

View File

@@ -98,82 +98,6 @@ extern "C" {
#ifndef ASM
/*
* Structure which makes it easier to deal with LxDT and SxDT instructions.
*/
typedef struct {
unsigned short limit;
unsigned short physical_address[ 2 ];
} i386_DTR_load_save_format;
/* See Chapter 5 - Memory Management in i386 manual */
typedef struct {
unsigned short limit_0_15;
unsigned short base_0_15;
unsigned char base_16_23;
unsigned char type_dt_dpl_p;
unsigned char limit_16_19_granularity;
unsigned char base_24_31;
} i386_GDT_slot;
/* See Chapter 9 - Exceptions and Interrupts in i386 manual
*
* NOTE: This is the IDT entry for interrupt gates ONLY.
*/
typedef struct {
unsigned short offset_0_15;
unsigned short segment_selector;
unsigned char reserved;
unsigned char p_dpl;
unsigned short offset_16_31;
} i386_IDT_slot;
/*
* 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)
/*
* The following routine swaps the endian format of an unsigned int.
* It must be static so it can be referenced indirectly.
@@ -205,67 +129,6 @@ static inline unsigned int i386_swap_U16(
return (sout);
}
/*
* 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
*/
@@ -327,101 +190,6 @@ static inline unsigned short i386_get_gs()
_value = __value; \
}
/*
* Descriptor Table helper routines
*/
#define i386_get_GDTR( _gdtr_address ) \
{ \
void *_gdtr = (_gdtr_address); \
\
asm volatile( "sgdt (%0)" : "=r" (_gdtr) : "0" (_gdtr) ); \
}
#define i386_get_GDT_slot( _gdtr_base, _segment, _slot_address ) \
{ \
register unsigned int _gdt_slot = (_gdtr_base) + (_segment); \
register volatile void *_slot = (_slot_address); \
register unsigned int _temporary = 0; \
\
asm volatile( "movl %%gs:(%0),%1 ; \
movl %1,(%2) ; \
movl %%gs:4(%0),%1 ; \
movl %1,4(%2)" \
: "=r" (_gdt_slot), "=r" (_temporary), "=r" (_slot) \
: "0" (_gdt_slot), "1" (_temporary), "2" (_slot) \
); \
}
#define i386_set_GDT_slot( _gdtr_base, _segment, _slot_address ) \
{ \
register unsigned int _gdt_slot = (_gdtr_base) + (_segment); \
register volatile void *_slot = (_slot_address); \
register unsigned int _temporary = 0; \
\
asm volatile( "movl (%2),%1 ; \
movl %1,%%gs:(%0) ; \
movl 4(%2),%1 ; \
movl %1,%%gs:4(%0) \
" \
: "=r" (_gdt_slot), "=r" (_temporary), "=r" (_slot) \
: "0" (_gdt_slot), "1" (_temporary), "2" (_slot) \
); \
}
static inline void i386_set_segment(
unsigned short segment,
unsigned int base,
unsigned int limit
)
{
i386_DTR_load_save_format gdtr;
volatile i386_GDT_slot Gdt_slot;
volatile i386_GDT_slot *gdt_slot = &Gdt_slot;
unsigned short tmp_segment = 0;
unsigned int limit_adjusted;
/* load physical address of the GDT */
i386_get_GDTR( &gdtr );
gdt_slot->type_dt_dpl_p = 0x92; /* present, dpl=0, */
/* application=1, */
/* type=data read/write */
gdt_slot->limit_16_19_granularity = 0x40; /* 32 bit segment */
limit_adjusted = limit;
if ( limit > 4095 ) {
gdt_slot->limit_16_19_granularity |= 0x80; /* set granularity bit */
limit_adjusted /= 4096;
}
gdt_slot->limit_16_19_granularity |= (limit_adjusted >> 16) & 0xff;
gdt_slot->limit_0_15 = limit_adjusted & 0xffff;
gdt_slot->base_0_15 = base & 0xffff;
gdt_slot->base_16_23 = (base >> 16) & 0xff;
gdt_slot->base_24_31 = (base >> 24);
i386_set_GDT_slot(
gdtr.physical_address[0] + (gdtr.physical_address[1] << 16),
segment,
gdt_slot
);
/* 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)
);
}
/* routines */
@@ -447,17 +215,6 @@ void *i386_Physical_to_logical(
void *address
);
/*
* i386_Install_idt
*
* This routine installs an IDT entry.
*/
void i386_Install_idt(
unsigned int source_offset,
unsigned short destination_segment,
unsigned int destination_offset
);
/*
* "Simpler" names for a lot of the things defined in this file
@@ -484,20 +241,6 @@ void i386_Install_idt(
#define inport_word( _port, _value ) i386_inport_word( _port, _value )
#define inport_long( _port, _value ) i386_inport_long( _port, _value )
/* complicated static inline functions */
#define get_GDTR( _gdtr_address ) \
i386_get_GDTR( _gdtr_address )
#define get_GDT_slot( _gdtr_base, _segment, _slot_address ) \
i386_get_GDT_slot( _gdtr_base, _segment, _slot_address )
#define set_GDT_slot( _gdtr_base, _segment, _slot_address ) \
i386_set_GDT_slot( _gdtr_base, _segment, _slot_address )
#define set_segment( _segment, _base, _limit ) \
i386_set_segment( _segment, _base, _limit )
#ifdef __cplusplus
}

View File

@@ -12,4 +12,4 @@ include $(RTEMS_ROOT)/make/custom/$(RTEMS_BSP).cfg
include $(RTEMS_ROOT)/make/directory.cfg
# Descend into the $(RTEMS_BSP_FAMILY) directory
SUB_DIRS=$(RTEMS_BSP_FAMILY)
SUB_DIRS=shared $(RTEMS_BSP_FAMILY)

View File

@@ -38,11 +38,6 @@
#include <irq.h>
#include <rtems/libio.h>
/*-------------------------------------------------------------------------+
| Constants
+--------------------------------------------------------------------------*/
#define CLOCK_IRQ 0x00 /* Clock IRQ. */
/*-------------------------------------------------------------------------+
| Macros
+--------------------------------------------------------------------------*/
@@ -67,13 +62,12 @@ rtems_device_minor_number rtems_clock_minor;
/*-------------------------------------------------------------------------+
| Function: clockIsr
| Description: Interrupt Service Routine for clock (08h) interruption.
| Description: Interrupt Service Routine for clock (0h) interruption.
| Global Variables: Clock_driver_ticks, Clock_isrs.
| Arguments: vector - standard RTEMS argument - see documentation.
| Returns: standard return value - see documentation.
+--------------------------------------------------------------------------*/
static rtems_isr
clockIsr(rtems_vector_number vector)
static void clockIsr()
{
/*-------------------------------------------------------------------------+
| PLEASE NOTE: The following is directly transcribed from the go32 BSP for
@@ -98,10 +92,8 @@ clockIsr(rtems_vector_number vector)
else
Clock_isrs--;
PC386_ackIrq(vector - PC386_IRQ_VECTOR_BASE);
} /* clockIsr */
/*-------------------------------------------------------------------------+
| Function: Clock_exit
| Description: Clock cleanup routine at RTEMS exit. NOTE: This routine is
@@ -110,7 +102,7 @@ clockIsr(rtems_vector_number vector)
| Arguments: None.
| Returns: Nothing.
+--------------------------------------------------------------------------*/
void Clock_exit(void)
void clockOff(const rtems_irq_connect_data* unused)
{
if (BSP_Configuration.ticks_per_timeslice)
{
@@ -129,13 +121,10 @@ void Clock_exit(void)
| Arguments: None.
| Returns: Nothing.
+--------------------------------------------------------------------------*/
void
Install_clock(rtems_isr_entry isr)
static void clockOn(const rtems_irq_connect_data* unused)
{
rtems_unsigned32 microseconds_per_isr;
rtems_status_code status;
#if 0
/* Initialize clock from on-board real time clock. This breaks the */
/* test code which assumes which assumes the application will do it. */
@@ -175,21 +164,24 @@ Install_clock(rtems_isr_entry isr)
/* 105/88 approximates TIMER_TICK * 1e-6 */
rtems_unsigned32 count = US_TO_TICK(microseconds_per_isr);
status = PC386_installRtemsIrqHandler(CLOCK_IRQ, isr);
if (status != RTEMS_SUCCESSFUL)
{
printk("Error installing clock interrupt handler!\n");
rtems_fatal_error_occurred(status);
}
outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN);
outport_byte(TIMER_CNTR0, count >> 0 & 0xff);
outport_byte(TIMER_CNTR0, count >> 8 & 0xff);
}
atexit(Clock_exit);
} /* Install_clock */
}
int clockIsOn(const rtems_irq_connect_data* unused)
{
return ((i8259s_cache & 0x1) == 0);
}
static rtems_irq_connect_data clockIrqData = {PC_386_PERIODIC_TIMER,
clockIsr,
clockOn,
clockOff,
clockIsOn};
/*-------------------------------------------------------------------------+
@@ -202,8 +194,11 @@ Clock_initialize(rtems_device_major_number major,
rtems_device_minor_number minor,
void *pargp)
{
Install_clock(clockIsr); /* Install the interrupt handler */
if (!pc386_install_rtems_irq_handler (&clockIrqData)) {
printk("Unable to initialize system clock\n");
rtems_fatal_error_occurred(1);
}
/* make major/minor avail to others such as shared memory driver */
rtems_clock_major = major;
@@ -231,17 +226,12 @@ Clock_control(rtems_device_major_number major,
+-------------------------------------------------------------------------*/
if (args->command == rtems_build_name('I', 'S', 'R', ' '))
clockIsr(PC386_IRQ_VECTOR_BASE + CLOCK_IRQ);
clockIsr();
else if (args->command == rtems_build_name('N', 'E', 'W', ' '))
{
rtems_status_code status;
status = PC386_installRtemsIrqHandler(CLOCK_IRQ, clockIsr);
if (status != RTEMS_SUCCESSFUL)
{
if (!pc386_install_rtems_irq_handler (&clockIrqData)) {
printk("Error installing clock interrupt handler!\n");
rtems_fatal_error_occurred(status);
rtems_fatal_error_occurred(1);
}
}
}
@@ -249,6 +239,10 @@ Clock_control(rtems_device_major_number major,
return RTEMS_SUCCESSFUL;
} /* Clock_control */
void Clock_exit()
{
pc386_remove_rtems_irq_handler (&clockIrqData);
}
/*-------------------------------------------------------------------------+
| PLEASE NOTE: The following is directly transcribed from the go32 BSP for

View File

@@ -45,17 +45,20 @@ int PC386ConsolePort = PC386_CONSOLE_PORT_CONSOLE;
static int conSetAttr(int minor, const struct termios *);
/*-------------------------------------------------------------------------+
| Constants
+--------------------------------------------------------------------------*/
#define KEYBOARD_IRQ 0x01 /* Keyboard IRQ. */
/*-------------------------------------------------------------------------+
| External Prototypes
+--------------------------------------------------------------------------*/
extern rtems_isr _IBMPC_keyboard_isr(rtems_vector_number);
/* keyboard (IRQ 0x01) Interrupt Service Routine (defined in 'inch.c') */
extern void _IBMPC_keyboard_isr(void);
extern void _IBMPC_keyboard_isr_on(const rtems_irq_connect_data*);
extern void _IBMPC_keyboard_isr_off(const rtems_irq_connect_data*);
extern int _IBMPC_keyboard_isr_is_on(const rtems_irq_connect_data*);
static rtems_irq_connect_data console_isr_data = {PC_386_KEYBOARD,
_IBMPC_keyboard_isr,
_IBMPC_keyboard_isr_on,
_IBMPC_keyboard_isr_off,
_IBMPC_keyboard_isr_is_on};
extern rtems_boolean _IBMPC_scankey(char *); /* defined in 'inch.c' */
@@ -164,9 +167,9 @@ console_initialize(rtems_device_major_number major,
{
/* Install keyboard interrupt handler */
status = PC386_installRtemsIrqHandler(KEYBOARD_IRQ, _IBMPC_keyboard_isr);
status = pc386_install_rtems_irq_handler(&console_isr_data);
if (status != RTEMS_SUCCESSFUL)
if (!status)
{
printk("Error installing keyboard interrupt handler!\n");
rtems_fatal_error_occurred(status);
@@ -198,16 +201,18 @@ console_initialize(rtems_device_major_number major,
/* Set interrupt handler */
if(PC386ConsolePort == PC386_UART_COM1)
{
status = PC386_installRtemsIrqHandler(PC386_UART_COM1_IRQ,
PC386_uart_termios_isr_com1);
console_isr_data.name = PC386_UART_COM1_IRQ;
console_isr_data.hdl = PC386_uart_termios_isr_com1;
}
else
{
assert(PC386ConsolePort == PC386_UART_COM2);
status = PC386_installRtemsIrqHandler(PC386_UART_COM2_IRQ,
PC386_uart_termios_isr_com2);
console_isr_data.name = PC386_UART_COM2_IRQ;
console_isr_data.hdl = PC386_uart_termios_isr_com2;
}
status =pc386_install_rtems_irq_handler(&console_isr_data);
/*
* Register the device
*/
@@ -291,12 +296,15 @@ console_close(rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg)
{
rtems_device_driver res = RTEMS_SUCCESSFUL;
if(PC386ConsolePort != PC386_CONSOLE_PORT_CONSOLE)
{
return rtems_termios_close (arg);
res = rtems_termios_close (arg);
}
pc386_remove_rtems_irq_handler (&console_isr_data);
return RTEMS_SUCCESSFUL;
return res;
} /* console_close */

View File

@@ -210,6 +210,17 @@ _IBMPC_scankey(char *outChar)
return TRUE;
} /* _IBMPC_scankey */
void _IBMPC_keyboard_isr_on(const rtems_irq_connect_data* unused)
{}
void _IBMPC_keyboard_isr_off(const rtems_irq_connect_data* unused)
{}
int _IBMPC_keyboard_isr_is_on(const rtems_irq_connect_data* irq)
{
return pc386_irq_enabled_at_i8259s (irq->name);
}
/*-------------------------------------------------------------------------+
| Function: _IBMPC_keyboard_isr
@@ -218,8 +229,7 @@ _IBMPC_scankey(char *outChar)
| Arguments: vector - standard RTEMS argument - see documentation.
| Returns: standard return value - see documentation.
+--------------------------------------------------------------------------*/
rtems_isr
_IBMPC_keyboard_isr(rtems_vector_number vector)
void _IBMPC_keyboard_isr()
{
if (_IBMPC_scankey(&kbd_buffer[kbd_last]))
{
@@ -231,8 +241,6 @@ _IBMPC_keyboard_isr(rtems_vector_number vector)
kbd_last = next;
}
}
PC386_ackIrq(vector - PC386_IRQ_VECTOR_BASE); /* Mark interrupt as handled. */
} /* _IBMPC_keyboard_isr */
@@ -281,6 +289,21 @@ _IBMPC_inch(void)
return c;
} /* _IBMPC_inch */
/*
* Routine that can be used before interrupt management is initialized.
*/
char
debugPollingGetChar(void)
{
char c;
while (!_IBMPC_scankey(&c))
continue;
return c;
}
/*-------------------------------------------------------------------------+
| Function: _IBMPC_inch_sleep
| Description: If charcter is ready return it, otherwise sleep until

View File

@@ -8,8 +8,8 @@ VPATH = @srcdir@
RTEMS_ROOT = @top_srcdir@
PROJECT_ROOT = @PROJECT_ROOT@
H_FILES = $(srcdir)/bsp.h $(srcdir)/coverhd.h $(srcdir)/irq.h \
$(srcdir)/crt.h $(srcdir)/pc386uart.h $(srcdir)/pcibios.h
H_FILES = $(srcdir)/bsp.h $(srcdir)/coverhd.h $(srcdir)/crt.h \
$(srcdir)/pc386uart.h $(srcdir)/pcibios.h
#
# Equate files are for including from assembly preprocessed by

View File

@@ -51,6 +51,7 @@ extern "C" {
#include <iosupp.h>
#include <console.h>
#include <clockdrv.h>
#include <libcpu/cpu.h>
/*-------------------------------------------------------------------------+
| Constants
@@ -133,8 +134,11 @@ extern "C" {
/*-------------------------------------------------------------------------+
| External Variables.
+--------------------------------------------------------------------------*/
extern i386_IDT_slot Interrupt_descriptor_table[];
extern i386_GDT_slot Global_descriptor_table [];
#define IDT_SIZE 256
#define GDT_SIZE 3
extern interrupt_gate_descriptor Interrupt_descriptor_table[IDT_SIZE];
extern segment_descriptors Global_descriptor_table [GDT_SIZE];
extern rtems_configuration_table BSP_Configuration;
/* User provided BSP configuration table. */

View File

@@ -104,7 +104,8 @@ speakl: jmp speakl # and SPIN!!!
call printk
addl $4, esp
/*call debugPollingGetChar */
call debugPollingGetChar
#endif
/*----------------------------------------------------------------------------+

View File

@@ -11,14 +11,14 @@ PROJECT_ROOT = @PROJECT_ROOT@
PGM=${ARCH}/startup.rel
# C source names, if any, go here -- minus the .c
C_PIECES=bspclean bsplibc bsppost bspstart exit irq main sbrk
C_PIECES=bspclean bsplibc bsppost bspstart exit irq irq_init main sbrk
C_FILES=$(C_PIECES:%=%.c)
C_O_FILES=$(C_PIECES:%=${ARCH}/%.o)
H_FILES=
# Assembly source names, if any, go here -- minus the .s
S_PIECES=ldsegs
S_PIECES=ldsegs irq_asm
S_FILES=$(S_PIECES:%=%.s)
S_O_FILES=$(S_FILES:%.s=${ARCH}/%.o)
@@ -50,6 +50,12 @@ LDFLAGS +=
CLEAN_ADDITIONS +=
CLOBBER_ADDITIONS +=
IMPORT_SRC=$(srcdir)/../../shared/irq/irq.c \
$(srcdir)/../../shared/irq/irq_init.c $(srcdir)/../../shared/irq/irq_asm.s
preinstall:
${CP} ${IMPORT_SRC} .
${PGM}: ${SRCS} ${OBJS}
$(make-rel)
all: ${ARCH} $(SRCS) $(PGM)

View File

@@ -65,6 +65,7 @@ char *rtems_progname; /* Program name - from main(). */
extern void _exit(int); /* define in exit.c */
void bsp_libc_init( void *, unsigned32, int );
void bsp_postdriver_hook(void);
extern void rtems_irq_mngt_init();
/*-------------------------------------------------------------------------+
| Function: bsp_pretasking_hook
@@ -128,6 +129,11 @@ void bsp_start( void )
console_reserve_resources(&BSP_Configuration);
/*
* Init trems_interrupt_management
*/
rtems_irq_mngt_init();
/*
* The following information is very useful when debugging.
*/

View File

@@ -45,12 +45,13 @@
/*----------------------------------------------------------------------------+
| CODE section
+----------------------------------------------------------------------------*/
EXTERN (rtems_i8259_masks)
BEGIN_CODE
EXTERN (_establish_stack)
EXTERN (Timer_exit)
EXTERN (Clock_exit)
EXTERN (clockOff)
.p2align 4
/*----------------------------------------------------------------------------+
@@ -95,25 +96,6 @@ next_step:
movw ax, fs
movw ax, gs
/* Set default interrupt handler */
movl $0, ecx
movl $Interrupt_descriptor_table, eax
movl $_default_int_handler, ebx
movl ebx, edx
sarl $16, edx
loop:
movw bx, (eax)
movw $0x8, 2(eax)
movw $0x8e00, 4(eax)
movw dx, 8(eax)
addl $8, eax
addl $1, ecx
cmpl $255, ecx
jle loop
/*---------------------------------------------------------------------+
| Now we have to reprogram the interrupts :-(. We put them right after
| the intel-reserved hardware interrupts, at int 0x20-0x2F. There they
@@ -157,6 +139,8 @@ loop:
outb al, $0x21 /* is cascaded */
call SYM(delay)
movw $0xFFFB, SYM(i8259s_cache) /* set up same values in cache */
jmp SYM (_establish_stack) # return to the bsp entry code
/*-------------------------------------------------------------------------+
@@ -185,10 +169,6 @@ SYM (_return_to_monitor):
+--------------------------------------------------------------------------*/
.p2align 4
PUBLIC (_default_int_handler)
SYM (_default_int_handler):
iret
/*---------------------------------------------------------------------------+
| GDT itself
+--------------------------------------------------------------------------*/

View File

@@ -43,7 +43,6 @@
/*-------------------------------------------------------------------------+
| Constants
+--------------------------------------------------------------------------*/
#define TIMER_IRQ 0x00 /* Timer IRQ. */
#define AVG_OVERHEAD 0 /* 0.1 microseconds to start/stop timer. */
#define LEAST_VALID 1 /* Don't trust a value lower than this. */
@@ -53,6 +52,13 @@
volatile rtems_unsigned32 Ttimer_val;
rtems_boolean Timer_driver_Find_average_overhead = TRUE;
/*-------------------------------------------------------------------------+
| External Prototypes
+--------------------------------------------------------------------------*/
extern void timerisr();
/* timer (int 08h) Interrupt Service Routine (defined in 'timerisr.s') */
extern int clockIsOn(const rtems_irq_connect_data*);
/*-------------------------------------------------------------------------+
| Pentium optimized timer handling.
+--------------------------------------------------------------------------*/
@@ -86,7 +92,6 @@ rdtsc(void)
void
Timer_exit(void)
{
PC386_disableIrq(TIMER_IRQ);
} /* Timer_exit */
@@ -107,8 +112,6 @@ Timer_initialize(void)
First = FALSE;
atexit(Timer_exit); /* Try not to hose the system at exit. */
PC386_enableIrq(TIMER_IRQ);
/* Disable the programmable timer so ticks don't interfere. */
}
Ttimer_val = rdtsc(); /* read starting time */
} /* Timer_initialize */
@@ -143,11 +146,48 @@ Read_timer(void)
+--------------------------------------------------------------------------*/
#define US_PER_ISR 250 /* Number of micro-seconds per timer interruption */
/*-------------------------------------------------------------------------+
| External Prototypes
| Function: Timer_exit
| Description: Timer cleanup routine at RTEMS exit. NOTE: This routine is
| not really necessary, since there will be a reset at exit.
| Global Variables: None.
| Arguments: None.
| Returns: Nothing.
+--------------------------------------------------------------------------*/
extern rtems_isr timerisr(rtems_vector_number);
/* timer (int 08h) Interrupt Service Routine (defined in 'timerisr.s') */
void
timerOff(const rtems_raw_irq_connect_data* used)
{
/*
* disable interrrupt at i8259 level
*/
pc386_irq_disable_at_i8259s(used->idtIndex - PC386_IRQ_VECTOR_BASE);
/* reset timer mode to standard (DOS) value */
outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN);
outport_byte(TIMER_CNTR0, 0);
outport_byte(TIMER_CNTR0, 0);
} /* Timer_exit */
void timerOn(const rtems_raw_irq_connect_data* used)
{
/* load timer for US_PER_ISR microsecond period */
outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN);
outport_byte(TIMER_CNTR0, US_TO_TICK(US_PER_ISR) >> 0 & 0xff);
outport_byte(TIMER_CNTR0, US_TO_TICK(US_PER_ISR) >> 8 & 0xff);
/*
* disable interrrupt at i8259 level
*/
pc386_irq_enable_at_i8259s(used->idtIndex - PC386_IRQ_VECTOR_BASE);
}
static rtems_raw_irq_connect_data timer_raw_irq_data = {
PC_386_PERIODIC_TIMER + PC386_IRQ_VECTOR_BASE,
timerisr,
timerOn,
timerOff,
clockIsOn
};
/*-------------------------------------------------------------------------+
| Function: Timer_exit
@@ -160,13 +200,9 @@ extern rtems_isr timerisr(rtems_vector_number);
void
Timer_exit(void)
{
/* reset timer mode to standard (DOS) value */
outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN);
outport_byte(TIMER_CNTR0, 0);
outport_byte(TIMER_CNTR0, 0);
i386_delete_idt_entry (&timer_raw_irq_data);
} /* Timer_exit */
/*-------------------------------------------------------------------------+
| Function: Timer_initialize
| Description: Timer initialization routine.
@@ -184,14 +220,10 @@ Timer_initialize(void)
First = FALSE;
atexit(Timer_exit); /* Try not to hose the system at exit. */
/* install a raw interrupt handler for timer */
PC386_installRawIrqHandler(TIMER_IRQ, timerisr);
/* load timer for US_PER_ISR microsecond period */
outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN);
outport_byte(TIMER_CNTR0, US_TO_TICK(US_PER_ISR) >> 0 & 0xff);
outport_byte(TIMER_CNTR0, US_TO_TICK(US_PER_ISR) >> 8 & 0xff);
if (!i386_set_idt_entry (&timer_raw_irq_data)) {
printk("raw handler connexion failed\n");
rtems_fatal_error_occurred(1);
}
}
/* wait for ISR to be called at least once */
Ttimer_val = 0;

View File

@@ -0,0 +1,16 @@
#
# $Id$
#
@SET_MAKE@
srcdir = @srcdir@
VPATH = @srcdir@
RTEMS_ROOT = @top_srcdir@
PROJECT_ROOT = @PROJECT_ROOT@
include $(RTEMS_ROOT)/make/custom/$(RTEMS_BSP).cfg
include $(RTEMS_ROOT)/make/directory.cfg
# Descend into the $(RTEMS_BSP_FAMILY) directory
SUB_DIRS=irq

View File

@@ -0,0 +1,33 @@
#
# $Id$
#
@SET_MAKE@
srcdir = @srcdir@
VPATH = @srcdir@
RTEMS_ROOT = @top_srcdir@
PROJECT_ROOT = @PROJECT_ROOT@
H_FILES = $(srcdir)/irq.h $(srcdir)/irq_asm.h
#
# Equate files are for including from assembly preprocessed by
# gm4 or gasp. No examples are provided except for those for
# other CPUs. The best way to generate them would be to
# provide a program which generates the constants used based
# on the C equivalents.
#
EQ_FILES =
SRCS=$(H_FILES) $(EQ_FILES)
include $(RTEMS_ROOT)/make/custom/$(RTEMS_BSP).cfg
include $(RTEMS_ROOT)/make/leaf.cfg
CLEAN_ADDITIONS +=
CLOBBER_ADDITIONS +=
preinstall all: $(SRCS)
$(INSTALL) -m 444 $(H_FILES) $(PROJECT_INCLUDE)
$(INSTALL) -m 444 $(EQ_FILES) $(PROJECT_INCLUDE)

View File

@@ -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;
}

View File

@@ -0,0 +1,358 @@
/* irq.c
*
* This file contains the implementation of the function described in irq.h
*
* CopyRight (C) 1998 valette@crf.canon.fr
*
* 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 <bsp.h>
#include <irq.h>
/*
* 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 pc386_rtems_irq_mngt_set();
* CAUTION : this table is accessed directly by interrupt routine
* prologue.
*/
rtems_i8259_masks irq_mask_or_tbl[PC_386_IRQ_LINES_NUMBER];
/*
* Copy of data given via initial pc386_rtems_irq_mngt_set() for
* the sake of efficiency.
* CAUTION : this table is accessed directly by interrupt routine
* prologue.
*/
rtems_irq_hdl current_irq[PC_386_IRQ_LINES_NUMBER];
/*
* default handler connected on each irq after bsp initialization
*/
static rtems_irq_connect_data default_rtems_entry;
/*
* location used to store initial tables used for interrupt
* management.
*/
static rtems_irq_global_settings* internal_config;
static rtems_irq_connect_data* rtems_hdl_tbl;
/*-------------------------------------------------------------------------+
| Cache for 1st and 2nd PIC IRQ line's status (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
*/
rtems_i8259_masks i8259s_cache;
/*-------------------------------------------------------------------------+
| Function: PC386_irq_disable_at_i8259s
| Description: Mask IRQ line in appropriate PIC chip.
| Global Variables: i8259s_cache
| Arguments: vector_offset - number of IRQ line to mask.
| Returns: Nothing.
+--------------------------------------------------------------------------*/
int pc386_irq_disable_at_i8259s (const rtems_irq_symbolic_name irqLine)
{
unsigned short mask;
unsigned int level;
if ( ((int)irqLine < PC_386_LOWEST_OFFSET) ||
((int)irqLine > PC_386_MAX_OFFSET )
)
return 1;
_CPU_ISR_Disable(level);
mask = 1 << irqLine;
i8259s_cache |= mask;
if (irqLine < 8)
{
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
}
else
{
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) > 8));
}
_CPU_ISR_Enable (level);
return 0;
}
/*-------------------------------------------------------------------------+
| Function: pc386_irq_enable_at_i8259s
| Description: Unmask IRQ line in appropriate PIC chip.
| Global Variables: i8259s_cache
| Arguments: irqLine - number of IRQ line to mask.
| Returns: Nothing.
+--------------------------------------------------------------------------*/
int pc386_irq_enable_at_i8259s (const rtems_irq_symbolic_name irqLine)
{
unsigned short mask;
unsigned int level;
if ( ((int)irqLine < PC_386_LOWEST_OFFSET) ||
((int)irqLine > PC_386_MAX_OFFSET )
)
return 1;
_CPU_ISR_Disable(level);
mask = ~(1 << irqLine);
i8259s_cache &= mask;
if (irqLine < 8)
{
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
}
else
{
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) > 8));
}
_CPU_ISR_Enable (level);
return 0;
} /* mask_irq */
int pc386_irq_enabled_at_i8259s (const rtems_irq_symbolic_name irqLine)
{
unsigned short mask;
if ( ((int)irqLine < PC_386_LOWEST_OFFSET) ||
((int)irqLine > PC_386_MAX_OFFSET )
)
return 1;
mask = (1 << irqLine);
return (~(i8259s_cache & mask));
}
/*-------------------------------------------------------------------------+
| Function: pc386_irq_ack_at_i8259s
| Description: Signal generic End Of Interrupt (EOI) to appropriate PIC.
| Global Variables: None.
| Arguments: irqLine - number of IRQ line to acknowledge.
| Returns: Nothing.
+--------------------------------------------------------------------------*/
int pc386_irq_ack_at_i8259s (const rtems_irq_symbolic_name irqLine)
{
if ( ((int)irqLine < PC_386_LOWEST_OFFSET) ||
((int)irqLine > PC_386_MAX_OFFSET )
)
return 1;
if (irqLine >= 8) {
outport_byte(PIC_SLAVE_COMMAND_IO_PORT, PIC_EOI);
}
outport_byte(PIC_MASTER_COMMAND_IO_PORT, PIC_EOI);
return 0;
} /* ackIRQ */
/*
* ------------------------ RTEMS Irq helper functions ----------------
*/
/*
* Caution : this function assumes the variable "internal_config"
* is already set and that the tables it contains are still valid
* and accessible.
*/
static void compute_i8259_masks_from_prio ()
{
unsigned int i;
unsigned int j;
/*
* Always mask at least current interrupt to prevent re-entrance
*/
for (i=0; i < internal_config->irqNb; i++) {
* ((unsigned short*) &irq_mask_or_tbl[i]) = (1 << i);
for (j = 0; j < internal_config->irqNb; j++) {
/*
* Mask interrupts at i8259 level that have a lower priority
*/
if (internal_config->irqPrioTbl [i] > internal_config->irqPrioTbl [j]) {
* ((unsigned short*) &irq_mask_or_tbl[i]) |= (1 << j);
}
}
}
}
/*
* Caution : this function assumes the variable "internal_config"
* is already set and that the tables it contains are still valid
* and accessible.
*/
static void make_copy_of_handlers ()
{
int i;
for (i=0; i < internal_config->irqNb; i++) {
current_irq [i] = internal_config->irqHdlTbl[i].hdl;
}
}
/*
* This function check that the value given for the irq line
* is valid.
*/
static int isValidInterrupt(int irq)
{
if ( (irq < PC_386_LOWEST_OFFSET) || (irq > PC_386_MAX_OFFSET))
return 0;
return 1;
}
/*
* ------------------------ RTEMS Single Irq Handler Mngt Routines ----------------
*/
int pc386_install_rtems_irq_handler (const rtems_irq_connect_data* irq)
{
unsigned int level;
if (!isValidInterrupt(irq->name)) {
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 (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) {
return 0;
}
_CPU_ISR_Disable(level);
/*
* store the data provided by user
*/
rtems_hdl_tbl[irq->name] = *irq;
/*
* update table used directly by rtems interrupt prologue
*/
current_irq [irq->name] = irq->hdl;
/*
* Enable interrupt at PIC level
*/
pc386_irq_enable_at_i8259s (irq->name);
/*
* Enable interrupt on device
*/
irq->on(irq);
_CPU_ISR_Enable(level);
return 1;
}
int pc386_get_current_rtems_irq_handler (rtems_irq_connect_data* irq)
{
if (!isValidInterrupt(irq->name)) {
return 0;
}
*irq = rtems_hdl_tbl[irq->name];
return 1;
}
int pc386_remove_rtems_irq_handler (const rtems_irq_connect_data* irq)
{
unsigned int level;
if (!isValidInterrupt(irq->name)) {
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 (rtems_hdl_tbl[irq->name].hdl != irq->hdl) {
return 0;
}
_CPU_ISR_Disable(level);
/*
* disable interrupt at PIC level
*/
pc386_irq_disable_at_i8259s (irq->name);
/*
* Disable interrupt on device
*/
irq->off(irq);
/*
* restore the default irq value
*/
rtems_hdl_tbl[irq->name] = default_rtems_entry;
current_irq[irq->name] = default_rtems_entry.hdl;
_CPU_ISR_Enable(level);
return 1;
}
/*
* ------------------------ RTEMS Global Irq Handler Mngt Routines ----------------
*/
int pc386_rtems_irq_mngt_set(rtems_irq_global_settings* config)
{
int i;
unsigned int level;
/*
* Store various code accelerators
*/
internal_config = config;
default_rtems_entry = config->defaultEntry;
rtems_hdl_tbl = config->irqHdlTbl;
_CPU_ISR_Disable(level);
/*
* set up internal tables used by rtems interrupt prologue
*/
compute_i8259_masks_from_prio ();
make_copy_of_handlers ();
for (i=0; i < internal_config->irqNb; i++) {
if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
pc386_irq_enable_at_i8259s (i);
rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
}
else {
rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
pc386_irq_disable_at_i8259s (i);
}
}
/*
* must disable slave pic anyway
*/
pc386_irq_enable_at_i8259s (2);
_CPU_ISR_Enable(level);
return 1;
}
int pc386_rtems_irq_mngt_get(rtems_irq_global_settings** config)
{
*config = internal_config;
return 0;
}

View File

@@ -0,0 +1,260 @@
/* irq.h
*
* This include file describe the data structure and the functions implemented
* by rtems to write interrupt handlers.
*
* CopyRight (C) 1998 valette@crf.canon.fr
*
* This code is heavilly inspired by the public specification of STREAM V2
* that can be found at :
*
* <http://www.chorus.com/Documentation/index.html> by following
* the STREAM API Specification Document link.
*
* 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 _IRQ_H_
#define _IRQ_H_
#ifdef __cplusplus
extern "C" {
#endif
/*
* Include some preprocessor value also used by assember code
*/
#include <irq_asm.h>
#include <rtems.h>
/*-------------------------------------------------------------------------+
| Constants
+--------------------------------------------------------------------------*/
typedef enum {
/* Base vector for our IRQ handlers. */
PC386_IRQ_VECTOR_BASE = PC386_ASM_IRQ_VECTOR_BASE,
PC_386_IRQ_LINES_NUMBER = 16,
PC_386_LOWEST_OFFSET = 0,
PC_386_MAX_OFFSET = PC_386_IRQ_LINES_NUMBER - 1,
/*
* Interrupt offset in comparison to PC386_ASM_IRQ_VECTOR_BASE
* NB : 1) Interrupt vector number in IDT = offset + PC386_ASM_IRQ_VECTOR_BASE
* 2) The same name should be defined on all architecture
* so that handler connexion can be unchanged.
*/
PC_386_PERIODIC_TIMER = 0,
PC_386_KEYBOARD = 1,
PC386_UART_COM2_IRQ = 3,
PC386_UART_COM1_IRQ = 4,
PC_386_RT_TIMER1 = 8
}rtems_irq_symbolic_name;
/*
* Type definition for RTEMS managed interrupts
*/
typedef unsigned char rtems_irq_prio;
typedef unsigned short rtems_i8259_masks;
extern rtems_i8259_masks i8259s_cache;
struct __rtems_irq_connect_data__; /* forward declaratiuon */
typedef void (*rtems_irq_hdl) (void);
typedef void (*rtems_irq_enable) (const struct __rtems_irq_connect_data__*);
typedef void (*rtems_irq_disable) (const struct __rtems_irq_connect_data__*);
typedef int (*rtems_irq_is_enabled) (const struct __rtems_irq_connect_data__*);
typedef struct __rtems_irq_connect_data__ {
/*
* IRQ line
*/
rtems_irq_symbolic_name name;
/*
* handler. See comment on handler properties below in function prototype.
*/
rtems_irq_hdl hdl;
/*
* function for enabling interrupts at device level (ONLY!).
* The BSP code will automatically enable it at i8259s level.
* RATIONALE : anyway such code has to exist in current driver code.
* It is usually called immediately AFTER connecting the interrupt handler.
* RTEMS may well need such a function when restoring normal interrupt
* processing after a debug session.
*
*/
rtems_irq_enable on;
/*
* function for disabling interrupts at device level (ONLY!).
* The code will disable it at i8259s level. RATIONALE : anyway
* such code has to exist for clean shutdown. It is usually called
* BEFORE disconnecting the interrupt. RTEMS may well need such
* a function when disabling normal interrupt processing for
* a debug session. May well be a NOP function.
*/
rtems_irq_disable off;
/*
* function enabling to know what interrupt may currently occur
* if someone manipulates the i8259s interrupt mask without care...
*/
rtems_irq_is_enabled isOn;
}rtems_irq_connect_data;
typedef struct {
/*
* size of all the table fields (*Tbl) described below.
*/
unsigned int irqNb;
/*
* Default handler used when disconnecting interrupts.
*/
rtems_irq_connect_data defaultEntry;
/*
* Table containing initials/current value.
*/
rtems_irq_connect_data* irqHdlTbl;
/*
* actual value of PC386_IRQ_VECTOR_BASE...
*/
rtems_irq_symbolic_name irqBase;
/*
* software priorities associated with interrupts.
* if irqPrio [i] > intrPrio [j] it means that
* interrupt handler hdl connected for interrupt name i
* will not be interrupted by the handler connected for interrupt j
* The interrupt source will be physically masked at i8259 level.
*/
rtems_irq_prio* irqPrioTbl;
}rtems_irq_global_settings;
/*-------------------------------------------------------------------------+
| Function Prototypes.
+--------------------------------------------------------------------------*/
/*
* ------------------------ Intel 8259 (or emulation) Mngt Routines -------
*/
/*
* function to disable a particular irq at 8259 level. After calling
* this function, even if the device asserts the interrupt line it will
* not be propagated further to the processor
*/
int pc386_irq_disable_at_i8259s (const rtems_irq_symbolic_name irqLine);
/*
* function to enable a particular irq at 8259 level. After calling
* this function, if the device asserts the interrupt line it will
* be propagated further to the processor
*/
int pc386_irq_enable_at_i8259s (const rtems_irq_symbolic_name irqLine);
/*
* function to acknoledge a particular irq at 8259 level. After calling
* this function, if a device asserts an enabled interrupt line it will
* be propagated further to the processor. Mainly usefull for people
* writting raw handlers as this is automagically done for rtems managed
* handlers.
*/
int pc386_irq_ack_at_i8259s (const rtems_irq_symbolic_name irqLine);
/*
* function to check if a particular irq is enabled at 8259 level. After calling
*/
int pc386_irq_enabled_at_i8259s (const rtems_irq_symbolic_name irqLine);
/*
* ------------------------ RTEMS Single Irq Handler Mngt Routines ----------------
*/
/*
* function to connect a particular irq handler. This hanlder will NOT be called
* directly as the result of the corresponding interrupt. Instead, a RTEMS
* irq prologue will be called that will :
*
* 1) save the C scratch registers,
* 2) switch to a interrupt stack if the interrupt is not nested,
* 3) store the current i8259s' interrupt masks
* 4) modify them to disable the current interrupt at 8259 level (and may
* be others depending on software priorities)
* 5) aknowledge the i8259s',
* 6) demask the processor,
* 7) call the application handler
*
* As a result the hdl function provided
*
* a) can perfectly be written is C,
* b) may also well directly call the part of the RTEMS API that can be used
* from interrupt level,
* c) It only responsible for handling the jobs that need to be done at
* the device level including (aknowledging/re-enabling the interrupt at device,
* level, getting the data,...)
*
* When returning from the function, the following will be performed by
* the RTEMS irq epilogue :
*
* 1) masks the interrupts again,
* 2) restore the original i8259s' interrupt masks
* 3) switch back on the orinal stack if needed,
* 4) perform rescheduling when necessary,
* 5) restore the C scratch registers...
* 6) restore initial execution flow
*
*/
int pc386_install_rtems_irq_handler (const rtems_irq_connect_data*);
/*
* function to get the current RTEMS irq handler for ptr->name. It enables to
* define hanlder chain...
*/
int pc386_get_current_rtems_irq_handler (rtems_irq_connect_data* ptr);
/*
* function to get disconnect the RTEMS irq handler for ptr->name.
* This function checks that the value given is the current one for safety reason.
* The user can use the previous function to get it.
*/
int pc386_remove_rtems_irq_handler (const rtems_irq_connect_data*);
/*
* ------------------------ RTEMS Global Irq Handler Mngt Routines ----------------
*/
/*
* (Re) Initialize the RTEMS interrupt management.
*
* The result of calling this function will be the same as if each individual
* handler (config->irqHdlTbl[i].hdl) different from "config->defaultEntry.hdl"
* has been individualy connected via
* pc386_install_rtems_irq_handler(&config->irqHdlTbl[i])
* And each handler currently equal to config->defaultEntry.hdl
* has been previously disconnected via
* pc386_remove_rtems_irq_handler (&config->irqHdlTbl[i])
*
* This is to say that all information given will be used and not just
* only the space.
*
* CAUTION : the various table address contained in config will be used
* directly by the interrupt mangement code in order to save
* data size so they must stay valid after the call => they should
* not be modified or declared on a stack.
*/
int pc386_rtems_irq_mngt_set(rtems_irq_global_settings* config);
/*
* (Re) get info on current RTEMS interrupt management.
*/
int pc386_rtems_irq_mngt_get(rtems_irq_global_settings**);
#ifdef __cplusplus
}
#endif
#endif /* _IRQ_H_ */
/* end of include file */

View File

@@ -0,0 +1,30 @@
/* irq_asm.h
*
* This include file has defines to represent some contant used
* to program and manage the Intel 8259 interrupt controller
*
*
* COPYRIGHT (c) 1998 valette@crf.canon.fr
*
* 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 __IRQ_ASM_H__
#define __IRQ_ASM_H__
#define PC386_ASM_IRQ_VECTOR_BASE 0x20
/* PIC's command and mask registers */
#define PIC_MASTER_COMMAND_IO_PORT 0x20 /* Master PIC command register */
#define PIC_SLAVE_COMMAND_IO_PORT 0xa0 /* Slave PIC command register */
#define PIC_MASTER_IMR_IO_PORT 0x21 /* Master PIC Interrupt Mask Register */
#define PIC_SLAVE_IMR_IO_PORT 0xa1 /* Slave PIC Interrupt Mask Register */
/* Command for specific EOI (End Of Interrupt): Interrupt acknowledge */
#define PIC_EOSI 0x60 /* End of Specific Interrupt (EOSI) */
#define PIC_EOI 0x20 /* Generic End of Interrupt (EOI) */
#endif

View File

@@ -0,0 +1,261 @@
/* irq.c
*
* This file contains the implementation of the function described in irq.h
*
* CopyRight (C) 1998 valette@crf.canon.fr
*
* 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 "asm.h"
#include <irq_asm.h>
.set SAVED_REGS , 32 # space consumed by saved regs
.set EIP_OFFSET , SAVED_REGS # offset of tasks eip
.set CS_OFFSET , EIP_OFFSET+4 # offset of tasks code segment
.set EFLAGS_OFFSET , CS_OFFSET+4 # offset of tasks eflags
/*PAGE
* void _new_ISR_Displatch()
*
* Entry point from the outermost interrupt service routine exit.
* The current stack is the supervisor mode stack.
*/
PUBLIC (_new_ISR_Displatch)
SYM (_New_ISR_Displatch):
call SYM (_Thread_Dispatch) # invoke Dispatcher
/*
* 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
*/
popa # restore general registers
iret # return to interrupted thread
SYM (_New_ISR_Handler):
/*
* Before this was point is reached the vectors unique
* entry point did the following:
*
* 1. saved sctach 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
*/
/*
* Now switch stacks if necessary
*/
movw SYM (i8259s_cache), ax # move current i8259 interrupt mask in ax
pushl eax # push it on the stack
/*
* compute the new PIC mask:
*
* <new mask> = <old mask> | irq_mask_or_tbl[<intr number aka ecx>]
*/
movw SYM (irq_mask_or_tbl) (,ecx,2), dx
orw dx, ax
/*
* Install new computed value on the i8259 and update cache
* accordingly
*/
movw ax, SYM (i8259s_cache)
outb $PIC_MASTER_IMR_IO_PORT
movb ah, al
outb $PIC_SLAVE_IMR_IO_PORT
/*
* acknowledge the interrupt
*
*/
movb $PIC_EOI, al
cmpl $7, ecx
jbe .master
outb $PIC_SLAVE_COMMAND_IO_PORT
.master:
outb $PIC_MASTER_COMMAND_IO_PORT
.check_stack_switch:
pushl ebp
movl esp, ebp # ebp = previous stack pointer
cmpl $0, SYM (_ISR_Nest_level) # is this the outermost interrupt?
jne nested # No, then continue
movl SYM (_CPU_Interrupt_stack_high), esp
/*
* We want to insure that the old stack pointer is on the
* stack we will be on at the end of the ISR when we restore it.
* By saving it on every interrupt, all we have to do is pop it
* near the end of every interrupt.
*/
nested:
incl SYM (_ISR_Nest_level) # one nest level deeper
incl SYM (_Thread_Dispatch_disable_level) # disable multitasking
/*
* re-enable interrupts at processor level as the current
* interrupt source is now masked via i8259
*/
sti
/*
* ECX is preloaded with the vector number but it is a scratch register
* so we must save it again.
*/
pushl ecx # push vector number
mov SYM (current_irq) (,ecx,4),eax
# eax = Users handler
call *eax # invoke user ISR
/*
* disable interrupts_again
*/
cli
popl ecx # ecx = vector number
/*
* restore stack
*/
movl ebp, esp
popl ebp
/*
* restore the original i8259 masks
*/
popl eax
movw ax, SYM (i8259s_cache)
outb $PIC_MASTER_IMR_IO_PORT
movb ah, al
outb $PIC_SLAVE_IMR_IO_PORT
decl SYM (_ISR_Nest_level) # one less ISR nest level
# If interrupts are nested,
# then dispatching is disabled
decl SYM (_Thread_Dispatch_disable_level)
# unnest multitasking
# Is dispatch disabled
jne .exit # Yes, then exit
cmpl $0, SYM (_Context_Switch_necessary)
# Is task switch necessary?
jne bframe # Yes, then build stack
cmpl $0, SYM (_ISR_Signals_to_thread_executing)
# signals sent to Run_thread
# while in interrupt handler?
je .exit # No, exit
bframe:
movl $0, SYM (_ISR_Signals_to_thread_executing)
/*
* complete code as if a pusha had been executed on entry
*/
pushl ebx
pushl esp
pushl ebp
pushl esi
pushl edi
# push the isf for Isr_dispatch
pushl EFLAGS_OFFSET(esp) # push tasks eflags
push cs # cs of Isr_dispatch
pushl $ SYM (_New_ISR_Displatch)# entry point
iret
.exit:
/*
* 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 (_New_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)
/*
* routine used to initialize the IDT by default
*/
PUBLIC (default_raw_idt_handler)
PUBLIC (raw_idt_notify)
SYM (default_raw_idt_handler):
pusha
cld
call raw_idt_notify
popa
iret

View File

@@ -0,0 +1,200 @@
/* irq_init.c
*
* This file contains the implementation of rtems initialization
* related to interrupt handling.
*
* 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 <libcpu/cpu.h>
#include <irq.h>
#include <bsp.h>
/*
* rtems prologue generated in irq_asm.S
*/
extern void rtems_irq_prologue_0();
extern void rtems_irq_prologue_1();
extern void rtems_irq_prologue_2();
extern void rtems_irq_prologue_3();
extern void rtems_irq_prologue_4();
extern void rtems_irq_prologue_5();
extern void rtems_irq_prologue_6();
extern void rtems_irq_prologue_7();
extern void rtems_irq_prologue_8();
extern void rtems_irq_prologue_9();
extern void rtems_irq_prologue_10();
extern void rtems_irq_prologue_11();
extern void rtems_irq_prologue_12();
extern void rtems_irq_prologue_13();
extern void rtems_irq_prologue_14();
extern void rtems_irq_prologue_15();
/*
* default idt vector
*/
extern void default_raw_idt_handler();
/*
* default on/off function
*/
static void nop_func(){}
/*
* default isOn function
*/
static int not_connected() {return 0;}
static rtems_raw_irq_connect_data idtHdl[IDT_SIZE];
/*
* Table used to store rtems managed interrupt handlers.
* Borrow the table to store raw handler entries at the beginning.
* The table will be reinitialized before the call to pc386_rtems_irq_mngt_set().
*/
static rtems_irq_connect_data rtemsIrq[PC_386_IRQ_LINES_NUMBER] = {
{0,(rtems_irq_hdl)rtems_irq_prologue_0},
{0,(rtems_irq_hdl)rtems_irq_prologue_1},
{0,(rtems_irq_hdl)rtems_irq_prologue_2},
{0,(rtems_irq_hdl)rtems_irq_prologue_3},
{0,(rtems_irq_hdl)rtems_irq_prologue_4},
{0,(rtems_irq_hdl)rtems_irq_prologue_5},
{0,(rtems_irq_hdl)rtems_irq_prologue_6},
{0,(rtems_irq_hdl)rtems_irq_prologue_7},
{0,(rtems_irq_hdl)rtems_irq_prologue_8},
{0,(rtems_irq_hdl)rtems_irq_prologue_9},
{0,(rtems_irq_hdl)rtems_irq_prologue_10},
{0,(rtems_irq_hdl)rtems_irq_prologue_11},
{0,(rtems_irq_hdl)rtems_irq_prologue_12},
{0,(rtems_irq_hdl)rtems_irq_prologue_13},
{0,(rtems_irq_hdl)rtems_irq_prologue_14},
{0,(rtems_irq_hdl)rtems_irq_prologue_15}
};
static rtems_raw_irq_connect_data defaultRawIrq = {
/* vectorIdex, hdl , on , off , isOn */
0, default_raw_idt_handler ,nop_func , nop_func, not_connected
};
static rtems_irq_connect_data defaultIrq = {
/* vectorIdex, hdl , on , off , isOn */
0, nop_func , nop_func , nop_func , not_connected
};
static rtems_irq_prio irqPrioTable[PC_386_IRQ_LINES_NUMBER]={
/*
* actual rpiorities for interrupt :
* 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
* unamsked.
*/
0,0,
255,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static interrupt_gate_descriptor idtEntry;
static rtems_irq_global_settings initial_config;
static rtems_raw_irq_global_settings raw_initial_config;
void raw_idt_notify()
{
printk("raw_idt_notify has been called \n");
}
void rtems_irq_mngt_init()
{
int i;
interrupt_gate_descriptor* idt_entry_tbl;
unsigned limit;
unsigned int level;
i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
_CPU_ISR_Disable(level);
/*
* Init the complete IDT vector table with defaultRawIrq value
*/
for (i = 0; i < IDT_SIZE; i++) {
idtHdl[i] = defaultRawIrq;
}
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...
*/
_IBMPC_initVideo();
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 < PC_386_IRQ_LINES_NUMBER; i++) {
create_interrupt_gate_descriptor(&idtEntry,(rtems_raw_irq_hdl) rtemsIrq[i].hdl);
idt_entry_tbl[i + PC386_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.
*/
/*
* re-init the rtemsIrq table
*/
for (i = 0; i < PC_386_IRQ_LINES_NUMBER; i++) {
rtemsIrq[i] = defaultIrq;
}
/*
* Init initial Interrupt management config
*/
initial_config.irqNb = PC_386_IRQ_LINES_NUMBER;
initial_config.defaultEntry = defaultIrq;
initial_config.irqHdlTbl = rtemsIrq;
initial_config.irqBase = PC386_ASM_IRQ_VECTOR_BASE;
initial_config.irqPrioTbl = irqPrioTable;
if (!pc386_rtems_irq_mngt_set(&initial_config)) {
/*
* put something here that will show the failure...
*/
_IBMPC_initVideo();
printk("Unable to initialize RTEMS interrupt Management!!! System locked\n");
while (1);
}
#define DEBUG
#ifdef DEBUG
{
/*
* following adresses should be the same
*/
unsigned tmp;
_IBMPC_initVideo();
printk("idt_entry_tbl = %x Interrupt_descriptor_table addr = %x\n",
idt_entry_tbl, &Interrupt_descriptor_table);
tmp = (unsigned) get_hdl_from_vector (PC386_ASM_IRQ_VECTOR_BASE + PC_386_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);
debugPollingGetChar();
#endif
asm volatile ("sti");
}

View File

@@ -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

265
c/src/lib/libcpu/i386/cpu.c Normal file
View File

@@ -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;
}

365
c/src/lib/libcpu/i386/cpu.h Normal file
View File

@@ -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

View File

@@ -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

265
c/src/lib/libcpu/i386/idt.c Normal file
View File

@@ -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;
}

View File

@@ -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

View File

@@ -16,6 +16,7 @@ include $(RTEMS_ROOT)/make/lib.cfg
LIB=$(PROJECT_RELEASE)/lib/librtemsall${LIB_VARIANT}.a
SRCS=$(wildcard $(PROJECT_RELEASE)/lib/libbsp$(LIB_VARIANT).a) \
$(PROJECT_RELEASE)/lib/libcpu$(LIB_VARIANT).a \
$(PROJECT_RELEASE)/lib/librtems$(LIB_VARIANT).a \
$(wildcard $(PROJECT_RELEASE)/lib/libposix$(LIB_VARIANT).a) \
$(wildcard $(PROJECT_RELEASE)/lib/libka9q$(LIB_VARIANT).a) \

View File

@@ -16,6 +16,7 @@ include $(RTEMS_ROOT)/make/lib.cfg
LIB=$(PROJECT_RELEASE)/lib/librtemsall${LIB_VARIANT}.a
SRCS=$(wildcard $(PROJECT_RELEASE)/lib/libbsp$(LIB_VARIANT).a) \
$(PROJECT_RELEASE)/lib/libcpu$(LIB_VARIANT).a \
$(PROJECT_RELEASE)/lib/librtems$(LIB_VARIANT).a \
$(wildcard $(PROJECT_RELEASE)/lib/libposix$(LIB_VARIANT).a) \
$(wildcard $(PROJECT_RELEASE)/lib/libka9q$(LIB_VARIANT).a) \

57
configure vendored
View File

@@ -3012,6 +3012,21 @@ else
fi
echo $ac_n "checking for Makefile.in in c/src/lib/libbsp/${bspcpudir}shared""... $ac_c" 1>&6
echo "configure:3018: checking for Makefile.in in c/src/lib/libbsp/${bspcpudir}shared" >&5
if test -d $srcdir/c/src/lib/libbsp/${bspcpudir}shared; then
rtems_av_save_dir=`pwd`;
cd $srcdir;
rtems_av_tmp=`find c/src/lib/libbsp/${bspcpudir}shared -name "Makefile.in" -print | sed "s/Makefile\.in/%/" | sort | sed "s/%/Makefile/"`
makefiles="$makefiles $rtems_av_tmp";
cd $rtems_av_save_dir;
echo "$ac_t""done" 1>&6
else
echo "$ac_t""no" 1>&6
fi
fi
else
{ echo "configure: error: unable to find libbsp directory ($bspdir) for $i" 1>&2; exit 1; }
@@ -3022,7 +3037,7 @@ fi
# find all the CPU dependent library Makefiles
echo $ac_n "checking for Makefile.in in c/src/lib/libcpu/$target_cpu""... $ac_c" 1>&6
echo "configure:3026: checking for Makefile.in in c/src/lib/libcpu/$target_cpu" >&5
echo "configure:3041: checking for Makefile.in in c/src/lib/libcpu/$target_cpu" >&5
if test -d $srcdir/c/src/lib/libcpu/$target_cpu; then
rtems_av_save_dir=`pwd`;
cd $srcdir;
@@ -3039,7 +3054,7 @@ fi
if test "$skip_startfiles" != "yes"; then
echo $ac_n "checking for Makefile.in in c/src/lib/start/$target_cpu""... $ac_c" 1>&6
echo "configure:3043: checking for Makefile.in in c/src/lib/start/$target_cpu" >&5
echo "configure:3058: checking for Makefile.in in c/src/lib/start/$target_cpu" >&5
if test -d $srcdir/c/src/lib/start/$target_cpu; then
rtems_av_save_dir=`pwd`;
cd $srcdir;
@@ -3081,7 +3096,7 @@ fi
# If the tests are enabled, then find all the test suite Makefiles
echo $ac_n "checking if the test suites are enabled? ""... $ac_c" 1>&6
echo "configure:3085: checking if the test suites are enabled? " >&5
echo "configure:3100: checking if the test suites are enabled? " >&5
tests_enabled=yes
# Check whether --enable-tests or --disable-tests was given.
if test "${enable_tests+set}" = set; then
@@ -3100,7 +3115,7 @@ fi
echo $ac_n "checking for Makefile.in in c/src/tests/tools/$target_cpu""... $ac_c" 1>&6
echo "configure:3104: checking for Makefile.in in c/src/tests/tools/$target_cpu" >&5
echo "configure:3119: checking for Makefile.in in c/src/tests/tools/$target_cpu" >&5
if test -d $srcdir/c/src/tests/tools/$target_cpu; then
rtems_av_save_dir=`pwd`;
cd $srcdir;
@@ -3117,7 +3132,7 @@ fi
if test "$tests_enabled" = "yes"; then
echo $ac_n "checking for Makefile.in in c/src/tests/libtests""... $ac_c" 1>&6
echo "configure:3121: checking for Makefile.in in c/src/tests/libtests" >&5
echo "configure:3136: checking for Makefile.in in c/src/tests/libtests" >&5
if test -d $srcdir/c/src/tests/libtests; then
rtems_av_save_dir=`pwd`;
cd $srcdir;
@@ -3132,7 +3147,7 @@ fi
echo $ac_n "checking for Makefile.in in c/src/tests/sptests""... $ac_c" 1>&6
echo "configure:3136: checking for Makefile.in in c/src/tests/sptests" >&5
echo "configure:3151: checking for Makefile.in in c/src/tests/sptests" >&5
if test -d $srcdir/c/src/tests/sptests; then
rtems_av_save_dir=`pwd`;
cd $srcdir;
@@ -3147,7 +3162,7 @@ fi
echo $ac_n "checking for Makefile.in in c/src/tests/tmtests""... $ac_c" 1>&6
echo "configure:3151: checking for Makefile.in in c/src/tests/tmtests" >&5
echo "configure:3166: checking for Makefile.in in c/src/tests/tmtests" >&5
if test -d $srcdir/c/src/tests/tmtests; then
rtems_av_save_dir=`pwd`;
cd $srcdir;
@@ -3162,7 +3177,7 @@ fi
echo $ac_n "checking for Makefile.in in c/src/tests/mptests""... $ac_c" 1>&6
echo "configure:3166: checking for Makefile.in in c/src/tests/mptests" >&5
echo "configure:3181: checking for Makefile.in in c/src/tests/mptests" >&5
if test -d $srcdir/c/src/tests/mptests; then
rtems_av_save_dir=`pwd`;
cd $srcdir;
@@ -3178,7 +3193,7 @@ fi
if test "$RTEMS_HAS_POSIX_API" = "yes"; then
echo $ac_n "checking for Makefile.in in c/src/tests/psxtests""... $ac_c" 1>&6
echo "configure:3182: checking for Makefile.in in c/src/tests/psxtests" >&5
echo "configure:3197: checking for Makefile.in in c/src/tests/psxtests" >&5
if test -d $srcdir/c/src/tests/psxtests; then
rtems_av_save_dir=`pwd`;
cd $srcdir;
@@ -3196,7 +3211,7 @@ fi
# If the HWAPI is enabled, the find the HWAPI Makefiles
echo $ac_n "checking if the HWAPI is enabled? ""... $ac_c" 1>&6
echo "configure:3200: checking if the HWAPI is enabled? " >&5
echo "configure:3215: checking if the HWAPI is enabled? " >&5
# Check whether --enable-hwapi or --disable-hwapi was given.
if test "${enable_hwapi+set}" = set; then
enableval="$enable_hwapi"
@@ -3207,7 +3222,7 @@ if test "${enable_hwapi+set}" = set; then
makefiles="$makefiles c/src/lib/libhwapi/Makefile"
echo $ac_n "checking for Makefile.in in c/src/lib/libhwapi/analog""... $ac_c" 1>&6
echo "configure:3211: checking for Makefile.in in c/src/lib/libhwapi/analog" >&5
echo "configure:3226: checking for Makefile.in in c/src/lib/libhwapi/analog" >&5
if test -d $srcdir/c/src/lib/libhwapi/analog; then
rtems_av_save_dir=`pwd`;
cd $srcdir;
@@ -3222,7 +3237,7 @@ fi
echo $ac_n "checking for Makefile.in in c/src/lib/libhwapi/discrete""... $ac_c" 1>&6
echo "configure:3226: checking for Makefile.in in c/src/lib/libhwapi/discrete" >&5
echo "configure:3241: checking for Makefile.in in c/src/lib/libhwapi/discrete" >&5
if test -d $srcdir/c/src/lib/libhwapi/discrete; then
rtems_av_save_dir=`pwd`;
cd $srcdir;
@@ -3237,7 +3252,7 @@ fi
echo $ac_n "checking for Makefile.in in c/src/lib/libhwapi/drivers""... $ac_c" 1>&6
echo "configure:3241: checking for Makefile.in in c/src/lib/libhwapi/drivers" >&5
echo "configure:3256: checking for Makefile.in in c/src/lib/libhwapi/drivers" >&5
if test -d $srcdir/c/src/lib/libhwapi/drivers; then
rtems_av_save_dir=`pwd`;
cd $srcdir;
@@ -3252,7 +3267,7 @@ fi
echo $ac_n "checking for Makefile.in in c/src/lib/libhwapi/non_volatile_memory""... $ac_c" 1>&6
echo "configure:3256: checking for Makefile.in in c/src/lib/libhwapi/non_volatile_memory" >&5
echo "configure:3271: checking for Makefile.in in c/src/lib/libhwapi/non_volatile_memory" >&5
if test -d $srcdir/c/src/lib/libhwapi/non_volatile_memory; then
rtems_av_save_dir=`pwd`;
cd $srcdir;
@@ -3267,7 +3282,7 @@ fi
echo $ac_n "checking for Makefile.in in c/src/lib/libhwapi/serial""... $ac_c" 1>&6
echo "configure:3271: checking for Makefile.in in c/src/lib/libhwapi/serial" >&5
echo "configure:3286: checking for Makefile.in in c/src/lib/libhwapi/serial" >&5
if test -d $srcdir/c/src/lib/libhwapi/serial; then
rtems_av_save_dir=`pwd`;
cd $srcdir;
@@ -3282,7 +3297,7 @@ fi
echo $ac_n "checking for Makefile.in in c/src/lib/libhwapi/support""... $ac_c" 1>&6
echo "configure:3286: checking for Makefile.in in c/src/lib/libhwapi/support" >&5
echo "configure:3301: checking for Makefile.in in c/src/lib/libhwapi/support" >&5
if test -d $srcdir/c/src/lib/libhwapi/support; then
rtems_av_save_dir=`pwd`;
cd $srcdir;
@@ -3297,7 +3312,7 @@ fi
echo $ac_n "checking for Makefile.in in c/src/lib/libhwapi/wrapup""... $ac_c" 1>&6
echo "configure:3301: checking for Makefile.in in c/src/lib/libhwapi/wrapup" >&5
echo "configure:3316: checking for Makefile.in in c/src/lib/libhwapi/wrapup" >&5
if test -d $srcdir/c/src/lib/libhwapi/wrapup; then
rtems_av_save_dir=`pwd`;
cd $srcdir;
@@ -3342,7 +3357,7 @@ fi
# pick up all the Makefiles in required parts of the tree
echo $ac_n "checking for Makefile.in in c/build-tools""... $ac_c" 1>&6
echo "configure:3346: checking for Makefile.in in c/build-tools" >&5
echo "configure:3361: checking for Makefile.in in c/build-tools" >&5
if test -d $srcdir/c/build-tools; then
rtems_av_save_dir=`pwd`;
cd $srcdir;
@@ -3357,7 +3372,7 @@ fi
echo $ac_n "checking for Makefile.in in make""... $ac_c" 1>&6
echo "configure:3361: checking for Makefile.in in make" >&5
echo "configure:3376: checking for Makefile.in in make" >&5
if test -d $srcdir/make; then
rtems_av_save_dir=`pwd`;
cd $srcdir;
@@ -3372,7 +3387,7 @@ fi
echo $ac_n "checking for Makefile.in in c/src/lib/libmisc""... $ac_c" 1>&6
echo "configure:3376: checking for Makefile.in in c/src/lib/libmisc" >&5
echo "configure:3391: checking for Makefile.in in c/src/lib/libmisc" >&5
if test -d $srcdir/c/src/lib/libmisc; then
rtems_av_save_dir=`pwd`;
cd $srcdir;
@@ -3387,7 +3402,7 @@ fi
echo $ac_n "checking for Makefile.in in c/src/tests/samples""... $ac_c" 1>&6
echo "configure:3391: checking for Makefile.in in c/src/tests/samples" >&5
echo "configure:3406: checking for Makefile.in in c/src/tests/samples" >&5
if test -d $srcdir/c/src/tests/samples; then
rtems_av_save_dir=`pwd`;
cd $srcdir;

View File

@@ -329,6 +329,7 @@ if test -d "$srcdir/c/src/lib/libbsp/$target_cpu"; then
if test $? -ne 0 ; then
bspdirs="$bspdirs $bspdir"
RTEMS_CHECK_MAKEFILE(c/src/lib/libbsp/$bspcpudir$bspdir)
RTEMS_CHECK_MAKEFILE(c/src/lib/libbsp/${bspcpudir}shared)
fi
else
AC_MSG_ERROR([unable to find libbsp directory ($bspdir) for $i])

View File

@@ -76,102 +76,3 @@ unsigned32 _CPU_ISR_Get_level( void )
return level;
}
/*PAGE
*
* _CPU_ISR_install_raw_handler
*/
#if __GO32__
#include <go32.h>
#include <dpmi.h>
#endif /* __GO32__ */
void _CPU_ISR_install_raw_handler(
unsigned32 vector,
proc_ptr new_handler,
proc_ptr *old_handler
)
{
#if __GO32__
_go32_dpmi_seginfo handler_info;
/* get the address of the old handler */
_go32_dpmi_get_protected_mode_interrupt_vector( vector, &handler_info);
/* Notice how we're failing to save the pm_segment portion of the */
/* structure here? That means we might crash the system if we */
/* try to restore the ISR. Can't fix this until i386_isr is */
/* redefined. XXX [BHC]. */
*old_handler = (proc_ptr *) handler_info.pm_offset;
handler_info.pm_offset = (u_long) new_handler;
handler_info.pm_selector = _go32_my_cs();
/* install the IDT entry */
_go32_dpmi_set_protected_mode_interrupt_vector( vector, &handler_info );
#else
i386_IDT_slot idt;
unsigned32 handler;
*old_handler = 0; /* XXX not supported */
handler = (unsigned32) new_handler;
/* build the IDT entry */
idt.offset_0_15 = handler & 0xffff;
idt.segment_selector = i386_get_cs();
idt.reserved = 0x00;
idt.p_dpl = 0x8e; /* present, ISR */
idt.offset_16_31 = handler >> 16;
/* install the IDT entry */
i386_Install_idt(
(unsigned32) &idt,
_CPU_Table.interrupt_table_segment,
(unsigned32) _CPU_Table.interrupt_table_offset + (8 * vector)
);
#endif
}
/*PAGE
*
* _CPU_ISR_install_vector
*
* This kernel routine installs the RTEMS handler for the
* specified vector.
*
* Input parameters:
* vector - interrupt vector number
* old_handler - former ISR for this vector number
* new_handler - replacement ISR for this vector number
*
* Output parameters: NONE
*
*/
void _ISR_Handler_0(), _ISR_Handler_1();
#define PER_ISR_ENTRY \
(((unsigned32) _ISR_Handler_1 - (unsigned32) _ISR_Handler_0))
#define _Interrupt_Handler_entry( _vector ) \
(((unsigned32)_ISR_Handler_0) + ((_vector) * PER_ISR_ENTRY))
void _CPU_ISR_install_vector(
unsigned32 vector,
proc_ptr new_handler,
proc_ptr *old_handler
)
{
proc_ptr ignored;
unsigned32 unique_handler;
*old_handler = _ISR_Vector_table[ vector ];
/* calculate the unique entry point for this vector */
unique_handler = _Interrupt_Handler_entry( vector );
_CPU_ISR_install_raw_handler( vector, (void *)unique_handler, &ignored );
_ISR_Vector_table[ vector ] = new_handler;
}