diff options
Diffstat (limited to 'c/src/exec/score/cpu/i386/i386.h')
-rw-r--r-- | c/src/exec/score/cpu/i386/i386.h | 493 |
1 files changed, 493 insertions, 0 deletions
diff --git a/c/src/exec/score/cpu/i386/i386.h b/c/src/exec/score/cpu/i386/i386.h new file mode 100644 index 0000000000..a8db759984 --- /dev/null +++ b/c/src/exec/score/cpu/i386/i386.h @@ -0,0 +1,493 @@ +/* i386.h + * + * This include file contains information pertaining to the Intel + * i386 processor. + * + * COPYRIGHT (c) 1989, 1990, 1991, 1992, 1993, 1994. + * On-Line Applications Research Corporation (OAR). + * All rights assigned to U.S. Government, 1994. + * + * This material may be reproduced by or for the U.S. Government pursuant + * to the copyright license under the clause at DFARS 252.227-7013. This + * notice must appear in all copies of this file and its derivatives. + * + * $Id$ + */ + +#ifndef __i386_h +#define __i386_h + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The following define the CPU Family and Model within the family + * + * NOTE: The string "REPLACE_THIS_WITH_THE_CPU_MODEL" is replaced + * with the name of the appropriate macro for this target CPU. + */ + +#define i386 +#define REPLACE_THIS_WITH_THE_CPU_MODEL +#define REPLACE_THIS_WITH_THE_BSP + +/* + * This section contains the information required to build + * RTEMS for a particular member of the Intel i386 + * family when executing in protected mode. It does + * this by setting variables to indicate which implementation + * dependent features are present in a particular member + * of the family. + * + * Currently recognized: + * i386_fp (i386 DX or SX w/i387) + * i386_fp (i386 DX or SX w/o i387) + * i486dx + * i486sx + * pentium + * + * Floating point is the only feature which currently varies. Eventually + * the i486-plus level instruction for endian swapping should be added + * to this feature list. + */ + +#if defined(i386_fp) + +#define RTEMS_MODEL_NAME "i386 with i387" +#define I386_HAS_FPU 1 + +#elif defined(i386_nofp) + +#define RTEMS_MODEL_NAME "i386 w/o i387" +#define I386_HAS_FPU 1 + +#elif defined(i486dx) + +#define RTEMS_MODEL_NAME "i486dx" +#define I386_HAS_FPU 1 + +#elif defined(i486sx) + +#define RTEMS_MODEL_NAME "i486sx" +#define I386_HAS_FPU 0 + +#elif defined(pentium) + +#define RTEMS_MODEL_NAME "Pentium" +#define I386_HAS_FPU 1 + +#else + +#error "Unsupported CPU Model" + +#endif + +/* + * Define the name of the CPU family. + */ + +#define CPU_NAME "Intel i386" + +#ifndef ASM + +/* + * This section defines the basic types for this processor. + */ + +typedef unsigned char unsigned8; /* 8-bit unsigned integer */ +typedef unsigned short unsigned16; /* 16-bit unsigned integer */ +typedef unsigned int unsigned32; /* 32-bit unsigned integer */ +typedef unsigned long long unsigned64; /* 64-bit unsigned integer */ + +typedef unsigned16 Priority_Bit_map_control; + +typedef unsigned char signed8; /* 8-bit signed integer */ +typedef unsigned short signed16; /* 16-bit signed integer */ +typedef unsigned int signed32; /* 32-bit signed integer */ +typedef long long signed64; /* 64-bit signed integer */ + +typedef unsigned32 boolean; /* Boolean value */ + +typedef float single_precision; /* single precision float */ +typedef double double_precision; /* double precision float */ + +/* + * 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; + +typedef void ( *i386_isr )( void ); + +#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)) \ + ); \ + } + +/* + * The following routine swaps the endian format of an unsigned int. + * It must be static so it can be referenced indirectly. + */ + +static inline unsigned int i386_swap_U32( + unsigned int value +) +{ + asm volatile( "rorw $8,%%ax;" + "rorl $16,%0;" + "rorw $8,%%ax" : "=a" (value) : "0" (value) ); + + return( value ); +} + +/* + * 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; \ + } + +/* + * 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 */ + +/* + * i386_Logical_to_physical + * + * Converts logical address to physical address. + */ + +void *i386_Logical_to_physical( + unsigned short segment, + void *address +); + +/* + * i386_Physical_to_logical + * + * Converts physical address to logical address. + */ + +void *i386_Physical_to_logical( + unsigned short segment, + 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 + */ + +/* segment access routines */ + +#define get_cs() i386_get_cs() +#define get_ds() i386_get_ds() +#define get_es() i386_get_es() +#define get_ss() i386_get_ss() +#define get_fs() i386_get_fs() +#define get_gs() i386_get_gs() + +#define CPU_swap_u32( _value ) i386_swap_U32( _value ) + +/* i80x86 I/O instructions */ + +#define outport_byte( _port, _value ) i386_outport_byte( _port, _value ) +#define outport_word( _port, _value ) i386_outport_word( _port, _value ) +#define outport_long( _port, _value ) i386_outport_long( _port, _value ) +#define inport_byte( _port, _value ) i386_inport_byte( _port, _value ) +#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 +} +#endif + +#endif /* !ASM */ + +#endif +/* end of include file */ |