/** * @file * * @brief Intel I386 CPU Dependent Source * * This include file contains information pertaining to the Intel * i386 processor. */ /* * COPYRIGHT (c) 1989-2013. * On-Line Applications Research Corporation (OAR). * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.org/license/LICENSE. */ #ifndef _RTEMS_SCORE_I386_H #define _RTEMS_SCORE_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) * i486dx * pentium * pentiumpro * * 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. * As of at least gcc 4.7, i386 soft-float was obsoleted. * Thus this is always set to "1". */ #define I386_HAS_FPU 1 #if defined(__pentiumpro__) #define CPU_MODEL_NAME "Pentium Pro" #elif defined(__i586__) #if defined(__pentium__) #define CPU_MODEL_NAME "Pentium" #elif defined(__k6__) #define CPU_MODEL_NAME "K6" #else #define CPU_MODEL_NAME "i586" #endif #elif defined(__i486__) #define CPU_MODEL_NAME "i486dx" #elif defined(__i386__) #define I386_HAS_BSWAP 0 #define CPU_MODEL_NAME "i386 with i387" #else #error "Unknown 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_BSWAP #define I386_HAS_BSWAP 1 #endif /* * Define the name of the CPU family. */ #define CPU_NAME "Intel i386" #ifndef ASM /* * The following routine swaps the endian format of an unsigned int. * It must be static so it can be referenced indirectly. */ static inline uint32_t i386_swap_u32( uint32_t value ) { uint32_t 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 uint16_t i386_swap_u16( uint16_t value ) { unsigned short sout; __asm__ volatile( "rorw $8,%0" : "=r" (sout) : "0" (value)); return (sout); } /* * Added for pagination management */ static inline unsigned int i386_get_cr0(void) { register unsigned int segment = 0; __asm__ volatile ( "movl %%cr0,%0" : "=r" (segment) : "0" (segment) ); return segment; } static inline void i386_set_cr0(unsigned int segment) { __asm__ volatile ( "movl %0,%%cr0" : "=r" (segment) : "0" (segment) ); } static inline unsigned int i386_get_cr2(void) { register unsigned int segment = 0; __asm__ volatile ( "movl %%cr2,%0" : "=r" (segment) : "0" (segment) ); return segment; } static inline unsigned int i386_get_cr3(void) { register unsigned int segment = 0; __asm__ volatile ( "movl %%cr3,%0" : "=r" (segment) : "0" (segment) ); return segment; } static inline void i386_set_cr3(unsigned int segment) { __asm__ volatile ( "movl %0,%%cr3" : "=r" (segment) : "0" (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 ); /** * @brief Converts real mode pointer {segment, offset} to physical address. * * i386_Real_to_physical * * @param[in] segment used with \p offset to compute physical address * @param[in] offset used with \p segment to compute physical address * @retval physical address */ RTEMS_INLINE_ROUTINE void *i386_Real_to_physical( uint16_t segment, uint16_t offset) { return (void *)(((uint32_t)segment<<4)+offset); } /** * @brief Retreives real mode pointer elements {segmnet, offset} from * physical address. * * i386_Physical_to_real * Function returns the highest segment (base) address possible. * Example: input address - 0x4B3A2 * output segment - 0x4B3A * offset - 0x2 * input address - 0x10F12E * output segment - 0xFFFF * offset - 0xF13E * * @param[in] address address to be converted, must be less than 0x10FFEF * @param[out] segment segment computed from \p address * @param[out] offset offset computed from \p address * @retval 0 address not convertible * @retval 1 segment and offset extracted */ int i386_Physical_to_real( void *address, uint16_t *segment, uint16_t *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 ) #ifdef __cplusplus } #endif #endif /* !ASM */ #endif