/* i386.h * * This include file contains information pertaining to the Intel * i386 processor. * * COPYRIGHT (c) 1989-1998. * On-Line Applications Research Corporation (OAR). * Copyright assigned to U.S. Government, 1994. * * 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$ */ #ifndef __i386_h #define __i386_h #ifdef __cplusplus extern "C" { #endif /* * 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_nofp (i386 DX or SX w/o i387) * i486dx * i486sx * pentium * * CPU Model Feature Flags: * * I386_HAS_BSWAP: Defined to "1" if the instruction for endian swapping * (bswap) should be used. This instruction appears to * be present in all i486's and above. * * I386_HAS_FPU: Defined to "1" if the CPU has an FPU. * */ #if defined(i386_fp) #define CPU_MODEL_NAME "i386 with i387" #define I386_HAS_BSWAP 0 #elif defined(i386_nofp) #define CPU_MODEL_NAME "i386 w/o i387" #define I386_HAS_FPU 0 #define I386_HAS_BSWAP 0 #elif defined(i486dx) #define CPU_MODEL_NAME "i486dx" #elif defined(i486sx) #define CPU_MODEL_NAME "i486sx" #define I386_HAS_FPU 0 #elif defined(pentium) #define CPU_MODEL_NAME "Pentium" #else #error "Unsupported CPU Model" #endif /* * Set default values for CPU model feature flags * * NOTE: These settings are chosen to reflect most of the family members. */ #ifndef I386_HAS_FPU #define I386_HAS_FPU 1 #endif #ifndef I386_HAS_BSWAP #define I386_HAS_BSWAP 1 #endif /* * Define the name of the CPU family. */ #define CPU_NAME "Intel i386" #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. */ static inline unsigned int i386_swap_U32( unsigned int value ) { unsigned long lout; #if (I386_HAS_BSWAP == 0) asm volatile( "rorw $8,%%ax;" "rorl $16,%0;" "rorw $8,%%ax" : "=a" (lout) : "0" (value) ); #else __asm__ volatile( "bswap %0" : "=r" (lout) : "0" (value)); #endif return( lout ); } static inline unsigned int i386_swap_U16( unsigned int value ) { unsigned short sout; __asm__ volatile( "rorw $8,%0" : "=r" (sout) : "0" (value)); 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 */ #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 ) #define CPU_swap_u16( _value ) i386_swap_U16( _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 */