forked from Imagelibrary/rtems
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:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -104,7 +104,8 @@ speakl: jmp speakl # and SPIN!!!
|
||||
call printk
|
||||
addl $4, esp
|
||||
|
||||
/*call debugPollingGetChar */
|
||||
call debugPollingGetChar
|
||||
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------+
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
+--------------------------------------------------------------------------*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
16
c/src/lib/libbsp/i386/shared/Makefile.in
Normal file
16
c/src/lib/libbsp/i386/shared/Makefile.in
Normal 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
|
||||
|
||||
33
c/src/lib/libbsp/i386/shared/irq/Makefile.in
Normal file
33
c/src/lib/libbsp/i386/shared/irq/Makefile.in
Normal 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)
|
||||
265
c/src/lib/libbsp/i386/shared/irq/idt.c
Normal file
265
c/src/lib/libbsp/i386/shared/irq/idt.c
Normal 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;
|
||||
}
|
||||
358
c/src/lib/libbsp/i386/shared/irq/irq.c
Normal file
358
c/src/lib/libbsp/i386/shared/irq/irq.c
Normal 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;
|
||||
}
|
||||
260
c/src/lib/libbsp/i386/shared/irq/irq.h
Normal file
260
c/src/lib/libbsp/i386/shared/irq/irq.h
Normal 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 */
|
||||
30
c/src/lib/libbsp/i386/shared/irq/irq_asm.h
Normal file
30
c/src/lib/libbsp/i386/shared/irq/irq_asm.h
Normal 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
|
||||
261
c/src/lib/libbsp/i386/shared/irq/irq_asm.s
Normal file
261
c/src/lib/libbsp/i386/shared/irq/irq_asm.s
Normal 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
|
||||
|
||||
200
c/src/lib/libbsp/i386/shared/irq/irq_init.c
Normal file
200
c/src/lib/libbsp/i386/shared/irq/irq_init.c
Normal 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");
|
||||
}
|
||||
64
c/src/lib/libcpu/i386/Makefile.in
Normal file
64
c/src/lib/libcpu/i386/Makefile.in
Normal 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
265
c/src/lib/libcpu/i386/cpu.c
Normal 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
365
c/src/lib/libcpu/i386/cpu.h
Normal 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
|
||||
117
c/src/lib/libcpu/i386/cpu_asm.S
Normal file
117
c/src/lib/libcpu/i386/cpu_asm.S
Normal 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
265
c/src/lib/libcpu/i386/idt.c
Normal 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;
|
||||
}
|
||||
50
c/src/lib/libcpu/i386/wrapup/Makefile.in
Normal file
50
c/src/lib/libcpu/i386/wrapup/Makefile.in
Normal 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
|
||||
@@ -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) \
|
||||
|
||||
@@ -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
57
configure
vendored
@@ -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;
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user