diff options
Diffstat (limited to 'cpukit/score/cpu/i386')
-rw-r--r-- | cpukit/score/cpu/i386/.cvsignore | 2 | ||||
-rw-r--r-- | cpukit/score/cpu/i386/ChangeLog | 515 | ||||
-rw-r--r-- | cpukit/score/cpu/i386/Makefile.am | 20 | ||||
-rw-r--r-- | cpukit/score/cpu/i386/cpu.c | 244 | ||||
-rw-r--r-- | cpukit/score/cpu/i386/cpu_asm.S | 320 | ||||
-rw-r--r-- | cpukit/score/cpu/i386/preinstall.am | 53 | ||||
-rw-r--r-- | cpukit/score/cpu/i386/rtems/asm.h | 139 | ||||
-rw-r--r-- | cpukit/score/cpu/i386/rtems/score/cpu.h | 660 | ||||
-rw-r--r-- | cpukit/score/cpu/i386/rtems/score/i386.h | 246 | ||||
-rw-r--r-- | cpukit/score/cpu/i386/rtems/score/idtr.h | 66 | ||||
-rw-r--r-- | cpukit/score/cpu/i386/rtems/score/interrupts.h | 79 | ||||
-rw-r--r-- | cpukit/score/cpu/i386/rtems/score/registers.h | 72 | ||||
-rw-r--r-- | cpukit/score/cpu/i386/rtems/score/types.h | 44 | ||||
-rw-r--r-- | cpukit/score/cpu/i386/sse_test.c | 954 |
14 files changed, 3414 insertions, 0 deletions
diff --git a/cpukit/score/cpu/i386/.cvsignore b/cpukit/score/cpu/i386/.cvsignore new file mode 100644 index 0000000000..282522db03 --- /dev/null +++ b/cpukit/score/cpu/i386/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/cpukit/score/cpu/i386/ChangeLog b/cpukit/score/cpu/i386/ChangeLog new file mode 100644 index 0000000000..4f78220d02 --- /dev/null +++ b/cpukit/score/cpu/i386/ChangeLog @@ -0,0 +1,515 @@ +2011-02-11 Ralf Corsépius <ralf.corsepius@rtems.org> + + * cpu.c, sse_test.c, rtems/score/cpu.h, rtems/score/i386.h, + rtems/score/interrupts.h: + Use "__asm__" instead of "asm" for improved c99-compliance. + +2010-07-29 Gedare Bloom <giddyup44@yahoo.com> + + PR 1635/cpukit + * rtems/score/types.h: Refactoring of priority handling, to isolate the + bitmap implementation of priorities in the supercore so that priority + management is a little more modular. This change is in anticipation + of scheduler implementations that can select how they manage tracking + priority levels / finding the highest priority ready task. Note that + most of the changes here are simple renaming, to clarify the use of + the bitmap-based priority management. + +2010-07-16 Sebastian Huber <sebastian.huber@embedded-brains.de> + + * rtems/score/cpu.h: Include <rtems/score/types.h> first. + * rtems/score/types.h: Use <rtems/score/basedefs.h> header file. + +2010-06-15 Joel Sherrill <joel.sherrill@oarcorp.com> + + * cpu_asm.S: Formatting. + +2010-05-21 Vinu Rajashekhar <vinutheraj@gmail.com> + + * rtems/score/registers.h: Remove structs with bit-fields. Add a mask + for cr3 page directory. + +2010-03-27 Joel Sherrill <joel.sherrill@oarcorp.com> + + * cpu.c, cpu_asm.S, sse_test.c: Add include of config.h + +2009-11-09 Till Straumann <strauman@slac.stanford.edu> + + PR 1469/cpukit + * cpu.c: Add dummy entry for (non-existing) exception #15. + Otherwise all slots for vectors >= 16 are one element off. + +2009-10-29 Till Straumann <strauman@slac.stanford.edu> + + * rtems/score/cpu.h: Define _CPU_Interrupt_stack_setup() macro + which reserves space for the 'vector' arg to _C_dispatch_isr() + routine and aligns the irq stack to CPU_STACK_ALIGNMENT. + +2009-10-28 Till Straumann <strauman@slac.stanford.edu> + + * rtems/score/cpu.h: Replaced misleading typedef of + CPU_Interrupt_frame by 'void'. The i386 port does not + pass any frame info to the interrupt handlers. + +2009-10-28 Till Straumann <strauman@slac.stanford.edu> + + * rtems/score/cpu.h: + Added #ifdef ASM constructs so that this header can be + included from assembly code. + + Increased CPU_STACK_ALIGNMENT to 16 bytes. Gcc maintains + 16-byte alignment and it may be a advantageous to provide + initial 16-byte alignment. When using SSE some gcc versions + may produce code that crashes if the stack is not 16-byte aligned. + + Make sure _CPU_Context_Initialize() sets the thread stack + up so that it is aligned to CPU_CACHE_ALIGNMENT. + + * cpu_asm.S: + Align stack to CPU_CACHE_ALIGNMENT before calling C-code. + +2009-10-27 Till Straumann <strauman@slac.stanford.edu> + + * rtems/asm.h: Added definition for cr4 register. + +2009-09-25 Joel Sherrill <joel.sherrill@OARcorp.com> + + * rtems/score/cpu.h: Add no return atrribute to _CPU_Context_restore() + since it is used for restarting self. + +2009-02-12 Joel Sherrill <joel.sherrill@oarcorp.com> + + * cpu.c, rtems/score/cpu.h: Change prototype of IDLE thread to + consistently return void * and take a uintptr_t argument. + +2009-02-11 Joel Sherrill <joel.sherrill@oarcorp.com> + + * cpu.c, rtems/score/cpu.h: Eliminate _CPU_Thread_dispatch_pointer and + passing address of _Thread_Dispatch to _CPU_Initialize. Clean up + comments. + +2008-09-11 Ralf Corsépius <ralf.corsepius@rtems.org> + + * rtems/score/types.h: Do not define boolean, single_precision, + double_precision unless RTEMS_DEPRECATED_TYPES is given. + +2008-09-08 Joel Sherrill <joel.sherrill@oarcorp.com> + + * rtems/score/cpu.h: Remove extraneous spaces. + +2008-09-05 Ralf Corsépius <ralf.corsepius@rtems.org> + + * cpu.c: Stop using old-style defs. + +2008-08-21 Ralf Corsépius <ralf.corsepius@rtems.org> + + * rtems/score/types.h: Include stdbool.h. + Use bool as base-type for boolean. + +2008-08-19 Joel Sherrill <joel.sherrill@OARcorp.com> + + * cpu.c: Fix prototypes. + * rtems/score/cpu.h: Use memcpy() initialize FP structure and avoid + many casts and potential warnings. + +2008-08-16 Ralf Corsépius <ralf.corsepius@rtems.org> + + * rtems/score/cpu.h, rtems/score/i386.h: Add missing prototypes. + +2008-07-31 Joel Sherrill <joel.sherrill@OARcorp.com> + + * cpu.c, rtems/score/cpu.h: Correct prototype of Idle threads. + +2007-12-17 Joel Sherrill <joel.sherrill@oarcorp.com> + + * rtems/score/cpu.h: Add _CPU_Context_Get_SP() for stack check utility. + +2007-12-17 Joel Sherrill <joel.sherrill@OARcorp.com> + + * rtems/score/idtr.h: Sweep to make sure grep for COPYRIGHT passes. + +2007-12-04 Joel Sherrill <joel.sherrill@OARcorp.com> + + * cpu.c, rtems/score/cpu.h: Move interrupt_stack_size field from CPU + Table to Configuration Table. Eliminate CPU Table from all ports. + Delete references to CPU Table in all forms. + +2007-12-03 Joel Sherrill <joel.sherrill@OARcorp.com> + + * rtems/score/cpu.h: Moved most of the remaining CPU Table fields to + the Configuration Table. This included pretasking_hook, + predriver_hook, postdriver_hook, idle_task, do_zero_of_workspace, + extra_mpci_receive_server_stack, stack_allocate_hook, and + stack_free_hook. As a side-effect of this effort some multiprocessing + code was made conditional and some style clean up occurred. + +2007-11-26 Joel Sherrill <joel.sherrill@oarcorp.com> + + * rtems/score/cpu.h: Eliminate the interrupt_table_segment and + interrupt_table_offset fields in the i386 CPU Table since they are + never read. + +2007-05-09 Ralf Corsépius <ralf.corsepius@rtems.org> + + * rtems/score/cpu.h: Remove CPU_HAS_OWN_HOST_TO_NETWORK_ROUTINES. + +2007-04-17 Ralf Corsépius <ralf.corsepius@rtems.org> + + * cpu.c: + Use Context_Control_fp* instead of void* for fp_contexts. + * rtems/score/cpu.h: + Use Context_Control_fp* instead of void* for fp_contexts. + +2006-11-17 Ralf Corsépius <ralf.corsepius@rtems.org> + + * rtems/score/types.h: Remove unsigned64, signed64. + +2006-02-01 Joel Sherrill <joel@OARcorp.com> + + * rtems/score/cpu.h: Increase default stack size on i386 from 1K to 4K. + Most i386 targets are not memory strapped so making this a bit large + is not a burden. It lets more tests run. ticker and psxtimer will not + even run with 1K of stack. + +2005-11-08 Ralf Corsepius <ralf.corsepius@rtems.org> + + * rtems/score/types.h: Eliminate unsigned16, unsigned32. + +2005-10-27 Ralf Corsepius <ralf.corsepius@rtems.org> + + * rtems/asm.h: Remove private version of CONCAT macros. + Include <rtems/concat.h> instead. + +2005-02-08 Ralf Corsepius <ralf.corsepius@rtems.org> + + * Makefile.am: Split out preinstallation rules. + * preinstall.am: New (Split out from Makefile.am). + +2005-02-04 Ralf Corsepius <ralf.corsepius@rtems.org> + + PR 754/rtems + * rtems/asm.h: New (relocated from .). + * asm.h: Remove (moved to rtems/asm.h). + * Makefile.am: Reflect changes above. + +2004-01-28 Ralf Corsepius <ralf.corsepiu@rtems.org> + + * asm.h, rtems/score/cpu.h, rtems/score/i386.h, rtems/score/idtr.h, + rtems/score/interrupts.h, rtems/score/registers.h, + rtems/score/types.h: New header guards. + +2005-01-24 Ralf Corsepius <ralf.corsepius@rtems.org> + + * rtems/score/types.h: Remove signed8, signed16, signed32, + unsigned8, unsigned16, unsigned32. + +2005-01-24 Ralf Corsepius <ralf.corsepius@rtems.org> + + * rtems/score/i386.h: *_swap_u32( uint32_t ). + +2005-01-24 Ralf Corsepius <ralf.corsepius@rtems.org> + + * rtems/score/i386.h: *_swap_u16( uint16_t ). + +2005-01-24 Ralf Corsepius <ralf.corsepius@rtems.org> + + * rtems/score/types.h: #include <rtems/stdint.h>. + +2005-01-07 Ralf Corsepius <ralf.corsepius@rtems.org> + + * Makefile.am: Eliminate CFLAGS_OPTIMIZE_V. + +2005-01-01 Ralf Corsepius <ralf.corsepius@rtems.org> + + * Makefile.am: Remove build-variant support. + +2004-11-21 Ralf Corsepius <ralf.corsepius@rtems.org> + + * rtems/score/types.h: Use __rtems_score_types_h as preprocessor + guard. + +2004-11-21 Ralf Corsepius <ralf.corsepius@rtems.org> + + * asm.h: Add doxygen preamble. + +2004-10-02 Ralf Corsepius <ralf_corsepius@rtems.org> + + * rtems/score/cpu.h: Add doxygen preamble. + * rtems/score/i386.h: Add doxygen preamble. + * rtems/score/idtr.h: Add doxygen preamble. + * rtems/score/interrupts.h: Add doxygen preamble. + * rtems/score/registers.h: Add doxygen preamble. + * rtems/score/types.h: Add doxygen preamble. + +2004-04-16 Ralf Corsepius <ralf_corsepius@rtems.org> + + * rtems/score/i386.h: Rename i386_swap_U* to i386_swap_u* (API + consistency with other ports). + +2004-04-09 Ralf Corsepius <ralf_corsepius@rtems.org> + + * cpu_asm.S: Convert asm comments to C-comments to prevent gcc-3.4.0pre + from choking on them. + +2004-04-06 Ralf Corsepius <ralf_corsepius@rtems.org> + + * configure.ac: Remove (Merged into $(top_srcdir)/configure.ac). + * Makefile.am: Don't include multilib.am. + Reflect merging configure.ac into $(top_srcdir)/configure.ac. + +2004-04-01 Ralf Corsepius <ralf_corsepius@rtems.org> + + * Makefile.am: Install asm.h to $(includedir)/rtems. + +2004-04-01 Ralf Corsepius <ralf_corsepius@rtems.org> + + * cpu_asm.S: Include <rtems/asm.h> instead of <asm.h>. + +2004-03-30 Ralf Corsepius <ralf_corsepius@rtems.org> + + * cpu.c, cpu_asm.S, rtems/score/cpu.h, rtems/score/interrupts.h: + Convert to using c99 fixed size types. + +2004-03-29 Ralf Corsepius <ralf_corsepius@rtems.org> + + * configure.ac: RTEMS_TOP([../../../..]). + +2004-02-09 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + PR 565/rtems + * asm.h: Various hacks. + +2004-01-21 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * configure.ac: Move RTEMS_TOP one subdir down. + +2004-01-19 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * Makefile.am: Add PREINSTALL_DIRS. + +2004-01-14 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * Makefile.am: Re-add dirstamps to PREINSTALL_FILES. + Add PREINSTALL_FILES to CLEANFILES. + +2004-01-12 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * configure.ac: Requires automake >= 1.8.1. + +2004-01-11 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * Makefile.am: Include compile.am, again. + +2004-01-11 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * Makefile.am: Convert to using automake compilation rules. + +2003-12-12 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * Makefile.am: Use mkdir_p. Remove dirs from PREINSTALL_FILES. + +2003-12-12 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * configure.ac: Require automake >= 1.8, autoconf >= 2.59. + +2003-12-01 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * Makefile.am: Remove TMPINSTALL_FILES. + +2003-11-30 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * Makefile.am: Add $(dirstamp) to preinstallation rules. + +2003-11-23 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * Makefile.am: Don't use gmake rules for preinstallation. + +2003-10-21 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * configure.ac: Remove RTEMS_CANONICAL_HOST. + +2003-10-21 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * configure.ac: Remove RTEMS_CHECK_CPU. + +2003-09-04 Joel Sherrill <joel@OARcorp.com> + + * cpu.c, cpu_asm.S, rtems/score/cpu.h, rtems/score/i386.h, + rtems/score/idtr.h, rtems/score/interrupts.h, + rtems/score/registers.h, rtems/score/types.h: URL for license + changed. + +2003-08-11 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * configure.ac: Use rtems-bugs@rtems.com as bug report email address. + +2003-03-06 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * configure.ac: Remove AC_CONFIG_AUX_DIR. + +2002-12-11 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * configure.ac: Require autoconf-2.57 + automake-1.7.2. + * Makefile.am: Eliminate C_O_FILES, S_O_FILES, libscorecpu_a_OBJECTS. + +2002-11-19 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * configure.ac: Fix package name. + +2002-10-25 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * configure.ac: Add nostdinc to AM_INIT_AUTOMAKE. + +2002-10-21 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * .cvsignore: Reformat. + Add autom4te*cache. + Remove autom4te.cache. + +2002-07-26 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * Makefile.am: Build libscorecpu.a instead of rtems-cpu.rel. + +2002-07-22 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * Makefile.am: Use .$(OBJEXT) instead of .o. + +2002-07-22 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * Makefile.am: Use . instead of .o. + +2002-07-05 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * configure.ac: RTEMS_TOP(../../../..). + +2002-07-03 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * rtems.S: Remove. + * Makefile.am: Reflect changes above. + +2002-07-01 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * configure.ac: Remove RTEMS_PROJECT_ROOT. + +2002-06-27 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * configure.ac: Add RTEMS_PROG_CCAS + +2002-06-27 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * configure.ac: Use AC_CONFIG_AUX_DIR(../../../..). + Add AC_PROG_RANLIB. + +2002-06-17 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * Makefile.am: Include $(top_srcdir)/../../../automake/*.am. + Use ../../../aclocal. + +2002-03-29 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * rtems/score/idtr.h: New file, extracted from libcpu/cpu.h. + * rtems/score/interrupts.h: New file, extracted from libcpu/cpu.h. + * rtems/score/registers.h: New file, moved from libcpu. + * Makefile.am: Reflect changes above. + * cpu.c: Don't include cpuModel.h, + #include <rtems.h>, + #include <rtems/score/i386types.h>, + #include <rtems/score/idtr.h>. + * rtems/score/cpu.h: Don't include libcpu/cpu.h. + #include <rtems/score/interrupts.h>, + #include <rtems/score/registers.h>. + +2001-04-03 Joel Sherrill <joel@OARcorp.com> + + * Per PR94, all rtems/score/CPUtypes.h are named rtems/score/types.h. + * rtems/score/i386types.h: Removed. + * rtems/score/types.h: New file via CVS magic. + * Makefile.am, rtems/score/cpu.h: Account for name change. + +2002-03-27 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * configure.ac: + AC_INIT(package,_RTEMS_VERSION,_RTEMS_BUGS). + AM_INIT_AUTOMAKE([no-define foreign 1.6]). + * Makefile.am: Remove AUTOMAKE_OPTIONS. + +2001-02-05 Joel Sherrill <joel@OARcorp.com> + + * rtems/Makefile.am, rtems/score/Makefile.am: Removed again. + +2002-01-31 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * rtems/Makefile.am: Removed. + * rtems/score/Makefile.am: Removed. + * configure.ac: Reflect changes above. + * Makefile.am: Reflect changes above. + +2001-01-30 Joel Sherrill <joel@OARcorp.com> + + * Makefile.am: Corrected so .h files from rtems/score/ are installed. + +2002-01-03 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * cpu.c: Include rtems/bspIo.h instead of bspIo.h. + +2001-12-19 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * Makefile.am: Add multilib support. + +2001-11-28 Joel Sherrill <joel@OARcorp.com>, + + This was tracked as PR91. + * rtems/score/cpu.h: Added CPU_PROVIDES_ISR_IS_IN_PROGRESS macro which + is used to specify if the port uses the standard macro for this (FALSE). + A TRUE setting indicates the port provides its own implementation. + +2001-10-11 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * .cvsignore: Add autom4te.cache for autoconf > 2.52. + * configure.in: Remove. + * configure.ac: New file, generated from configure.in by autoupdate. + +2001-09-23 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * rtems/score/Makefile.am: Use 'PREINSTALL_FILES ='. + * Makefile.am: Use 'PREINSTALL_FILES ='. + +2001-02-04 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * Makefile.am, rtems/score/Makefile.am: + Apply include_*HEADERS instead of H_FILES. + +2001-01-03 Joel Sherrill <joel@OARcorp.com> + + * rtems/score/cpu.h: Added _CPU_Initialize_vectors(). + +2000-11-09 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * Makefile.am: Use ... instead of RTEMS_TOPdir in ACLOCAL_AMFLAGS. + +2000-11-02 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * Makefile.am: Switch to ACLOCAL_AMFLAGS = -I $(RTEMS_TOPdir)/aclocal. + +2000-10-25 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * Makefile.am: ACLOCAL_AMFLAGS= -I $(RTEMS_TOPdir)/macros. + Switch to GNU canonicalization. + +2000-09-12 Joel Sherrill <joel@OARcorp.com> + + * rtems/score/i386.h: Corrected "#elsif" to be "#elif". + +2000-09-04 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * Makefile.am: Include compile.am. + +2000-08-17 Ralf Corsepius <corsepiu@faw.uni-ulm.de> + + * rtems/score/i386.h: cpu-variant define handling + Rewrite due to introduction of multilib defines. + * asm.h: include cpuopts.h instead of targopts.h + +2000-08-10 Joel Sherrill <joel@OARcorp.com> + + * ChangeLog: New file. diff --git a/cpukit/score/cpu/i386/Makefile.am b/cpukit/score/cpu/i386/Makefile.am new file mode 100644 index 0000000000..f6c8e7f6d7 --- /dev/null +++ b/cpukit/score/cpu/i386/Makefile.am @@ -0,0 +1,20 @@ +## +## $Id$ +## + +include $(top_srcdir)/automake/compile.am + +include_rtemsdir = $(includedir)/rtems +include_rtems_HEADERS= rtems/asm.h + +include_rtems_scoredir = $(includedir)/rtems/score +include_rtems_score_HEADERS = rtems/score/cpu.h rtems/score/i386.h \ + rtems/score/types.h rtems/score/interrupts.h rtems/score/registers.h \ + rtems/score/idtr.h + +noinst_LIBRARIES = libscorecpu.a +libscorecpu_a_SOURCES = cpu.c cpu_asm.S +libscorecpu_a_CPPFLAGS = $(AM_CPPFLAGS) + +include $(srcdir)/preinstall.am +include $(top_srcdir)/automake/local.am diff --git a/cpukit/score/cpu/i386/cpu.c b/cpukit/score/cpu/i386/cpu.c new file mode 100644 index 0000000000..56971b63d5 --- /dev/null +++ b/cpukit/score/cpu/i386/cpu.c @@ -0,0 +1,244 @@ +/* + * Intel i386 Dependent Source + * + * + * COPYRIGHT (c) 1989-1999. + * 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.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/system.h> +#include <rtems/score/types.h> +#include <rtems/score/isr.h> +#include <rtems/score/idtr.h> + +#include <rtems/bspIo.h> +#include <rtems/score/thread.h> + +/* _CPU_Initialize + * + * This routine performs processor dependent initialization. + * + * INPUT PARAMETERS: NONE + */ + +void _CPU_Initialize(void) +{ +#if CPU_HARDWARE_FP + register uint16_t fp_status __asm__ ("ax"); + register Context_Control_fp *fp_context; +#endif + + /* + * The following code saves a NULL i387 context which is given + * to each task at start and restart time. The following code + * is based upon that provided in the i386 Programmer's + * Manual and should work on any coprocessor greater than + * the i80287. + * + * NOTE: The NO WAIT form of the coprocessor instructions + * MUST be used in case there is not a coprocessor + * to wait for. + */ + +#if CPU_HARDWARE_FP + fp_status = 0xa5a5; + __asm__ volatile( "fninit" ); + __asm__ volatile( "fnstsw %0" : "=a" (fp_status) : "0" (fp_status) ); + + if ( fp_status == 0 ) { + + fp_context = &_CPU_Null_fp_context; + +#ifdef __SSE__ + asm volatile( "fstcw %0":"=m"(fp_context->fpucw) ); +#else + __asm__ volatile( "fsave (%0)" : "=r" (fp_context) + : "0" (fp_context) + ); +#endif + } +#endif + +#ifdef __SSE__ + + __asm__ volatile("stmxcsr %0":"=m"(fp_context->mxcsr)); + + /* The BSP must enable the SSE extensions (early). + * If any SSE instruction was already attempted + * then that crashed the system. + * As a courtesy, we double-check here but it + * may be too late (which is also why we don't + * enable SSE here). + */ + { + uint32_t cr4; + __asm__ __volatile__("mov %%cr4, %0":"=r"(cr4)); + if ( 0x600 != (cr4 & 0x600) ) { + printk("PANIC: RTEMS was compiled for SSE but BSP did not enable it (CR4: 0x%08x)\n", cr4); + while ( 1 ) { + __asm__ __volatile__("hlt"); + } + } + } +#endif +} + +/*PAGE + * + * _CPU_ISR_Get_level + */ + +uint32_t _CPU_ISR_Get_level( void ) +{ + uint32_t level; + + i386_get_interrupt_level( level ); + + return level; +} + +void *_CPU_Thread_Idle_body( uintptr_t ignored ) +{ + while(1){ + __asm__ volatile ("hlt"); + } + return NULL; +} + +struct Frame_ { + struct Frame_ *up; + uintptr_t pc; +}; + +void _defaultExcHandler (CPU_Exception_frame *ctx) +{ + unsigned int faultAddr = 0; + printk("----------------------------------------------------------\n"); + printk("Exception %d caught at PC %x by thread %d\n", + ctx->idtIndex, + ctx->eip, + _Thread_Executing->Object.id); + printk("----------------------------------------------------------\n"); + printk("Processor execution context at time of the fault was :\n"); + printk("----------------------------------------------------------\n"); + printk(" EAX = %x EBX = %x ECX = %x EDX = %x\n", + ctx->eax, ctx->ebx, ctx->ecx, ctx->edx); + printk(" ESI = %x EDI = %x EBP = %x ESP = %x\n", + ctx->esi, ctx->edi, ctx->ebp, ctx->esp0); + printk("----------------------------------------------------------\n"); + printk("Error code pushed by processor itself (if not 0) = %x\n", + ctx->faultCode); + printk("----------------------------------------------------------\n"); + if (ctx->idtIndex == I386_EXCEPTION_PAGE_FAULT){ + faultAddr = i386_get_cr2(); + printk("Page fault linear address (CR2) = %x\n", faultAddr); + printk("----------------------------------------------------------\n\n"); + } + if (_ISR_Nest_level > 0) { + /* + * In this case we shall not delete the task interrupted as + * it has nothing to do with the fault. We cannot return either + * because the eip points to the faulty instruction so... + */ + printk("Exception while executing ISR!!!. System locked\n"); + _CPU_Fatal_halt(faultAddr); + } + else { + struct Frame_ *fp = (struct Frame_*)ctx->ebp; + int i; + + printk("Call Stack Trace of EIP:\n"); + if ( fp ) { + for ( i=1; fp->up; fp=fp->up, i++ ) { + printk("0x%08x ",fp->pc); + if ( ! (i&3) ) + printk("\n"); + } + } + printk("\n"); + /* + * OK I could probably use a simplified version but at least this + * should work. + */ + printk(" ************ FAULTY THREAD WILL BE SUSPENDED **************\n"); + rtems_task_suspend(_Thread_Executing->Object.id); + } +} + +cpuExcHandlerType _currentExcHandler = _defaultExcHandler; + +extern void rtems_exception_prologue_0(void); +extern void rtems_exception_prologue_1(void); +extern void rtems_exception_prologue_2(void); +extern void rtems_exception_prologue_3(void); +extern void rtems_exception_prologue_4(void); +extern void rtems_exception_prologue_5(void); +extern void rtems_exception_prologue_6(void); +extern void rtems_exception_prologue_7(void); +extern void rtems_exception_prologue_8(void); +extern void rtems_exception_prologue_9(void); +extern void rtems_exception_prologue_10(void); +extern void rtems_exception_prologue_11(void); +extern void rtems_exception_prologue_12(void); +extern void rtems_exception_prologue_13(void); +extern void rtems_exception_prologue_14(void); +extern void rtems_exception_prologue_16(void); +extern void rtems_exception_prologue_17(void); +extern void rtems_exception_prologue_18(void); +#ifdef __SSE__ +extern void rtems_exception_prologue_19(void); +#endif + +static rtems_raw_irq_hdl tbl[] = { + rtems_exception_prologue_0, + rtems_exception_prologue_1, + rtems_exception_prologue_2, + rtems_exception_prologue_3, + rtems_exception_prologue_4, + rtems_exception_prologue_5, + rtems_exception_prologue_6, + rtems_exception_prologue_7, + rtems_exception_prologue_8, + rtems_exception_prologue_9, + rtems_exception_prologue_10, + rtems_exception_prologue_11, + rtems_exception_prologue_12, + rtems_exception_prologue_13, + rtems_exception_prologue_14, + 0, + rtems_exception_prologue_16, + rtems_exception_prologue_17, + rtems_exception_prologue_18, +#ifdef __SSE__ + rtems_exception_prologue_19, +#endif +}; + +void rtems_exception_init_mngt(void) +{ + size_t i,j; + interrupt_gate_descriptor *currentIdtEntry; + unsigned limit; + unsigned level; + + i = sizeof(tbl) / sizeof (rtems_raw_irq_hdl); + + i386_get_info_from_IDTR (¤tIdtEntry, &limit); + + _CPU_ISR_Disable(level); + for (j = 0; j < i; j++) { + create_interrupt_gate_descriptor (¤tIdtEntry[j], tbl[j]); + } + _CPU_ISR_Enable(level); +} diff --git a/cpukit/score/cpu/i386/cpu_asm.S b/cpukit/score/cpu/i386/cpu_asm.S new file mode 100644 index 0000000000..418d2bf787 --- /dev/null +++ b/cpukit/score/cpu/i386/cpu_asm.S @@ -0,0 +1,320 @@ +/* cpu_asm.s + * + * This file contains all assembly code for the Intel i386 implementation + * of RTEMS. + * + * COPYRIGHT (c) 1989-1999. + * 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.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/asm.h> +#include <rtems/score/cpu.h> + +#ifndef CPU_STACK_ALIGNMENT +#error "Missing header? CPU_STACK_ALIGNMENT not defined" +#endif + +/* + * Format of i386 Register structure + */ + +.set REG_EFLAGS, 0 +.set REG_ESP, REG_EFLAGS + 4 +.set REG_EBP, REG_ESP + 4 +.set REG_EBX, REG_EBP + 4 +.set REG_ESI, REG_EBX + 4 +.set REG_EDI, REG_ESI + 4 +.set SIZE_REGS, REG_EDI + 4 + + BEGIN_CODE + +/* + * void _CPU_Context_switch( run_context, heir_context ) + * + * This routine performs a normal non-FP context. + */ + + .p2align 1 + PUBLIC (_CPU_Context_switch) + +.set RUNCONTEXT_ARG, 4 /* save context argument */ +.set HEIRCONTEXT_ARG, 8 /* restore context argument */ + +SYM (_CPU_Context_switch): + movl RUNCONTEXT_ARG(esp),eax /* eax = running threads context */ + pushf /* push eflags */ + popl REG_EFLAGS(eax) /* save eflags */ + movl esp,REG_ESP(eax) /* save stack pointer */ + movl ebp,REG_EBP(eax) /* save base pointer */ + movl ebx,REG_EBX(eax) /* save ebx */ + movl esi,REG_ESI(eax) /* save source register */ + movl edi,REG_EDI(eax) /* save destination register */ + + movl HEIRCONTEXT_ARG(esp),eax /* eax = heir threads context */ + +restore: + pushl REG_EFLAGS(eax) /* push eflags */ + popf /* restore eflags */ + movl REG_ESP(eax),esp /* restore stack pointer */ + movl REG_EBP(eax),ebp /* restore base pointer */ + movl REG_EBX(eax),ebx /* restore ebx */ + movl REG_ESI(eax),esi /* restore source register */ + movl REG_EDI(eax),edi /* restore destination register */ + ret + +/* + * NOTE: May be unnecessary to reload some registers. + */ + +/* + * void _CPU_Context_restore( new_context ) + * + * This routine performs a normal non-FP context. + */ + + PUBLIC (_CPU_Context_restore) + +.set NEWCONTEXT_ARG, 4 /* context to restore argument */ + +SYM (_CPU_Context_restore): + movl NEWCONTEXT_ARG(esp),eax /* eax = running threads context */ + jmp restore + +/*PAGE + * void _CPU_Context_save_fp_context( &fp_context_ptr ) + * void _CPU_Context_restore_fp_context( &fp_context_ptr ) + * + * This section is used to context switch an i80287, i80387, + * the built-in coprocessor or the i80486 or compatible. + */ + +.set FPCONTEXT_ARG, 4 /* FP context argument */ + +#ifndef __SSE__ + .p2align 1 + PUBLIC (_CPU_Context_save_fp) +SYM (_CPU_Context_save_fp): + movl FPCONTEXT_ARG(esp),eax /* eax = &ptr to FP context area */ + movl (eax),eax /* eax = FP context area */ + fsave (eax) /* save FP context */ + ret + + .p2align 1 + PUBLIC (_CPU_Context_restore_fp) +SYM (_CPU_Context_restore_fp): + movl FPCONTEXT_ARG(esp),eax /* eax = &ptr to FP context area */ + movl (eax),eax /* eax = FP context area */ + frstor (eax) /* restore FP context */ + ret +#endif + +#ifdef __SSE__ +#define SSE_OFF 16 +#endif + + PUBLIC (_Exception_Handler) +SYM (_Exception_Handler): + pusha /* Push general purpose registers */ + pushl $0 /* Null pointer to SSE area */ + movl esp, ebp /* Save original SP */ +#ifndef __SSE__ + subl $4, esp /* Reserve space for argument */ + /* Align stack (courtesy for C/gcc) */ + andl $ - CPU_STACK_ALIGNMENT, esp +#else + subl $512, esp /* Space for SSE area */ + /* Align stack (courtesy for C/gcc) */ + andl $ - CPU_STACK_ALIGNMENT, esp +/* Doing fwait here will re-throw an already pending FP exception! + fwait + */ + fxsave 0(esp) + fninit /* Clean-slate FPU */ + movl $0x1f80, 0(ebp) + ldmxcsr 0(ebp) /* Clean-slate MXCSR */ + movl esp, 0(ebp) /* Store pointer to SSE area */ + subl $SSE_OFF, esp /* Aligned space for argument */ +#endif + movl ebp, (esp) /* Store argument */ + movl _currentExcHandler, eax /* Call function stored in _currentExcHandler */ + call * eax +#ifdef __SSE__ + fwait + fxrstor 16(esp) +#endif + movl ebp, esp /* Restore original SP */ + addl $4, esp /* Skill pointer to SSE area */ + popa /* Restore general purpose registers */ + addl $8, esp /* Skill vector number and faultCode */ + iret + +#define DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY(_vector) \ + .p2align 4 ; \ + PUBLIC (rtems_exception_prologue_ ## _vector ) ; \ +SYM (rtems_exception_prologue_ ## _vector ): \ + pushl $ _vector ; \ + jmp SYM (_Exception_Handler) ; + +#define DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY(_vector) \ + .p2align 4 ; \ + PUBLIC (rtems_exception_prologue_ ## _vector ) ; \ +SYM (rtems_exception_prologue_ ## _vector ): \ + pushl $ 0 ; \ + pushl $ _vector ; \ + jmp SYM (_Exception_Handler) ; + +/* + * Divide Error + */ +DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (0) +/* + * Debug Exception + */ +DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (1) +/* + * NMI + */ +DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (2) +/* + * Breakpoint + */ +DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (3) +/* + * Overflow + */ +DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (4) +/* + * Bound Range Exceeded + */ +DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (5) +/* + * Invalid Opcode + */ +DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (6) +/* + * No Math Coproc + */ +DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (7) +/* + * Double Fault + */ +DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (8) +/* + * Coprocessor segment overrun + */ +DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (9) +/* + * Invalid TSS + */ +DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (10) +/* + * Segment Not Present + */ +DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (11) +/* + * Stack segment Fault + */ +DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (12) +/* + * General Protection Fault + */ +DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (13) +/* + * Page Fault + */ +DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (14) +/* + * Floating point error (NB 15 is reserved it is therefor skipped) + */ +DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (16) +/* + * Aligment Check + */ +DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (17) +/* + * Machine Check + */ +DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (18) + +#ifdef __SSE__ +/* + * SIMD FP Exception + */ +DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (19) +#endif + + +/* + * void *i386_Logical_to_physical( + * uint16_t segment, + * void *address + * ); + * + * Returns thirty-two bit physical address for segment:address. + */ + +.set SEGMENT_ARG, 4 +.set ADDRESS_ARG, 8 + + PUBLIC (i386_Logical_to_physical) + +SYM (i386_Logical_to_physical): + + xorl eax,eax /* clear eax */ + movzwl SEGMENT_ARG(esp),ecx /* ecx = segment value */ + movl $ SYM (_Global_descriptor_table),edx + /* edx = address of our GDT */ + addl ecx,edx /* edx = address of desired entry */ + movb 7(edx),ah /* ah = base 31:24 */ + movb 4(edx),al /* al = base 23:16 */ + shll $16,eax /* move ax into correct bits */ + movw 2(edx),ax /* ax = base 0:15 */ + movl ADDRESS_ARG(esp),ecx /* ecx = address to convert */ + addl eax,ecx /* ecx = physical address equivalent */ + movl ecx,eax /* eax = ecx */ + ret + +/* + * void *i386_Physical_to_logical( + * uint16_t segment, + * void *address + * ); + * + * Returns thirty-two bit physical address for segment:address. + */ + +/* + *.set SEGMENT_ARG, 4 + *.set ADDRESS_ARG, 8 -- use sets from above + */ + + PUBLIC (i386_Physical_to_logical) + +SYM (i386_Physical_to_logical): + xorl eax,eax /* clear eax */ + movzwl SEGMENT_ARG(esp),ecx /* ecx = segment value */ + movl $ SYM (_Global_descriptor_table),edx + /* edx = address of our GDT */ + addl ecx,edx /* edx = address of desired entry */ + movb 7(edx),ah /* ah = base 31:24 */ + movb 4(edx),al /* al = base 23:16 */ + shll $16,eax /* move ax into correct bits */ + movw 2(edx),ax /* ax = base 0:15 */ + movl ADDRESS_ARG(esp),ecx /* ecx = address to convert */ + subl eax,ecx /* ecx = logical address equivalent */ + movl ecx,eax /* eax = ecx */ + ret + +END_CODE + +END diff --git a/cpukit/score/cpu/i386/preinstall.am b/cpukit/score/cpu/i386/preinstall.am new file mode 100644 index 0000000000..7bf7af259a --- /dev/null +++ b/cpukit/score/cpu/i386/preinstall.am @@ -0,0 +1,53 @@ +## Automatically generated by ampolish3 - Do not edit + +if AMPOLISH3 +$(srcdir)/preinstall.am: Makefile.am + $(AMPOLISH3) $(srcdir)/Makefile.am > $(srcdir)/preinstall.am +endif + +PREINSTALL_DIRS = +DISTCLEANFILES = $(PREINSTALL_DIRS) + +all-am: $(PREINSTALL_FILES) + +PREINSTALL_FILES = +CLEANFILES = $(PREINSTALL_FILES) + +$(PROJECT_INCLUDE)/rtems/$(dirstamp): + @$(MKDIR_P) $(PROJECT_INCLUDE)/rtems + @: > $(PROJECT_INCLUDE)/rtems/$(dirstamp) +PREINSTALL_DIRS += $(PROJECT_INCLUDE)/rtems/$(dirstamp) + +$(PROJECT_INCLUDE)/rtems/asm.h: rtems/asm.h $(PROJECT_INCLUDE)/rtems/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/asm.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/asm.h + +$(PROJECT_INCLUDE)/rtems/score/$(dirstamp): + @$(MKDIR_P) $(PROJECT_INCLUDE)/rtems/score + @: > $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) +PREINSTALL_DIRS += $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) + +$(PROJECT_INCLUDE)/rtems/score/cpu.h: rtems/score/cpu.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/cpu.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/cpu.h + +$(PROJECT_INCLUDE)/rtems/score/i386.h: rtems/score/i386.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/i386.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/i386.h + +$(PROJECT_INCLUDE)/rtems/score/types.h: rtems/score/types.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/types.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/types.h + +$(PROJECT_INCLUDE)/rtems/score/interrupts.h: rtems/score/interrupts.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/interrupts.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/interrupts.h + +$(PROJECT_INCLUDE)/rtems/score/registers.h: rtems/score/registers.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/registers.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/registers.h + +$(PROJECT_INCLUDE)/rtems/score/idtr.h: rtems/score/idtr.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/idtr.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/idtr.h + diff --git a/cpukit/score/cpu/i386/rtems/asm.h b/cpukit/score/cpu/i386/rtems/asm.h new file mode 100644 index 0000000000..f18d54c5b1 --- /dev/null +++ b/cpukit/score/cpu/i386/rtems/asm.h @@ -0,0 +1,139 @@ +/** + * @file rtems/asm.h + * + * This include file attempts to address the problems + * caused by incompatible flavors of assemblers and + * toolsets. It primarily addresses variations in the + * use of leading underscores on symbols and the requirement + * that register names be preceded by a %. + */ + +/* + * NOTE: The spacing in the use of these macros + * is critical to them working as advertised. + * + * COPYRIGHT: + * + * This file is based on similar code found in newlib available + * from ftp.cygnus.com. The file which was used had no copyright + * notice. This file is freely distributable as long as the source + * of the file is noted. This file is: + * + * COPYRIGHT (c) 1994-1997. + * On-Line Applications Research Corporation (OAR). + * + * $Id$ + */ + +#ifndef _RTEMS_ASM_H +#define _RTEMS_ASM_H + +/* + * Indicate we are in an assembly file and get the basic CPU definitions. + */ + +#ifndef ASM +#define ASM +#endif +#include <rtems/score/cpuopts.h> +#include <rtems/score/i386.h> + +/* + * Recent versions of GNU cpp define variables which indicate the + * need for underscores and percents. If not using GNU cpp or + * the version does not support this, then you will obviously + * have to define these as appropriate. + */ + +#ifndef __USER_LABEL_PREFIX__ +#define __USER_LABEL_PREFIX__ +#endif + +/* + * Looks like there is a bug in gcc 2.6.2 where this is not + * defined correctly when configured as i386-coff and + * i386-aout. + */ + +#undef __REGISTER_PREFIX__ +#define __REGISTER_PREFIX__ % + +/* +#ifndef __REGISTER_PREFIX__ +#define __REGISTER_PREFIX__ +#endif +*/ + +#include <rtems/concat.h> + +/* Use the right prefix for global labels. */ + +#define SYM(x) CONCAT0 (__USER_LABEL_PREFIX__, x) + +/* Use the right prefix for registers. */ + +#define REG(x) CONCAT0 (__REGISTER_PREFIX__, x) + +#define eax REG (eax) +#define ebx REG (ebx) +#define ecx REG (ecx) +#define edx REG (edx) +#define esi REG (esi) +#define edi REG (edi) +#define esp REG (esp) +#define ebp REG (ebp) +#define cr0 REG (cr0) +#define cr4 REG (cr4) + +#define ax REG (ax) +#define bx REG (bx) +#define cx REG (cx) +#define dx REG (dx) +#define si REG (si) +#define di REG (di) +#define sp REG (sp) +#define bp REG (bp) + +#define ah REG (ah) +#define bh REG (bh) +#define ch REG (ch) +#define dh REG (dh) + +#define al REG (al) +#define bl REG (bl) +#define cl REG (cl) +#define dl REG (dl) + +#define cs REG (cs) +#define ds REG (ds) +#define es REG (es) +#define fs REG (fs) +#define gs REG (gs) +#define ss REG (ss) + +/* + * Define macros to handle section beginning and ends. + */ + + +#define BEGIN_CODE_DCL .text +#define END_CODE_DCL +#define BEGIN_DATA_DCL .data +#define END_DATA_DCL +#define BEGIN_CODE .text +#define END_CODE +#define BEGIN_DATA .data +#define END_DATA +#define BEGIN_BSS .bss +#define END_BSS +#define END + +/* + * Following must be tailor for a particular flavor of the C compiler. + * They may need to put underscores in front of the symbols. + */ + +#define PUBLIC(sym) .globl SYM (sym) +#define EXTERN(sym) .globl SYM (sym) + +#endif diff --git a/cpukit/score/cpu/i386/rtems/score/cpu.h b/cpukit/score/cpu/i386/rtems/score/cpu.h new file mode 100644 index 0000000000..0e47c285bb --- /dev/null +++ b/cpukit/score/cpu/i386/rtems/score/cpu.h @@ -0,0 +1,660 @@ +/** + * @file rtems/score/cpu.h + */ + +/* + * This include file contains information pertaining to the Intel + * i386 processor. + * + * COPYRIGHT (c) 1989-2011. + * 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.com/license/LICENSE. + * + * $Id$ + */ + +#ifndef _RTEMS_SCORE_CPU_H +#define _RTEMS_SCORE_CPU_H + +#ifndef ASM +#include <string.h> /* for memcpy */ +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#include <rtems/score/types.h> +#include <rtems/score/i386.h> + +#ifndef ASM +#include <rtems/score/interrupts.h> /* formerly in libcpu/cpu.h> */ +#include <rtems/score/registers.h> /* formerly part of libcpu */ +#endif + +/* conditional compilation parameters */ + +#define CPU_INLINE_ENABLE_DISPATCH TRUE +#define CPU_UNROLL_ENQUEUE_PRIORITY FALSE + +/* + * i386 has an RTEMS allocated and managed interrupt stack. + */ + +#define CPU_HAS_SOFTWARE_INTERRUPT_STACK TRUE +#define CPU_HAS_HARDWARE_INTERRUPT_STACK FALSE +#define CPU_ALLOCATE_INTERRUPT_STACK TRUE + +/* + * Does the RTEMS invoke the user's ISR with the vector number and + * a pointer to the saved interrupt frame (1) or just the vector + * number (0)? + */ + +#define CPU_ISR_PASSES_FRAME_POINTER 0 + +/* + * Some family members have no FP, some have an FPU such as the i387 + * for the i386, others have it built in (i486DX, Pentium). + */ + +#ifdef __SSE__ +#define CPU_HARDWARE_FP TRUE +#define CPU_SOFTWARE_FP FALSE + +#define CPU_ALL_TASKS_ARE_FP TRUE +#define CPU_IDLE_TASK_IS_FP TRUE +#define CPU_USE_DEFERRED_FP_SWITCH FALSE +#else /* __SSE__ */ + +#if ( I386_HAS_FPU == 1 ) +#define CPU_HARDWARE_FP TRUE /* i387 for i386 */ +#else +#define CPU_HARDWARE_FP FALSE +#endif +#define CPU_SOFTWARE_FP FALSE + +#define CPU_ALL_TASKS_ARE_FP FALSE +#define CPU_IDLE_TASK_IS_FP FALSE +#define CPU_USE_DEFERRED_FP_SWITCH TRUE +#endif /* __SSE__ */ + +#define CPU_STACK_GROWS_UP FALSE +#define CPU_STRUCTURE_ALIGNMENT + +/* + * Does this port provide a CPU dependent IDLE task implementation? + * + * If TRUE, then the routine _CPU_Thread_Idle_body + * must be provided and is the default IDLE thread body instead of + * _CPU_Thread_Idle_body. + * + * If FALSE, then use the generic IDLE thread body if the BSP does + * not provide one. + */ + +#define CPU_PROVIDES_IDLE_THREAD_BODY TRUE + +/* + * Define what is required to specify how the network to host conversion + * routines are handled. + */ + +#define CPU_BIG_ENDIAN FALSE +#define CPU_LITTLE_ENDIAN TRUE + +/* structures */ + +#ifndef ASM + +/* + * Basic integer context for the i386 family. + */ + +typedef struct { + uint32_t eflags; /* extended flags register */ + void *esp; /* extended stack pointer register */ + void *ebp; /* extended base pointer register */ + uint32_t ebx; /* extended bx register */ + uint32_t esi; /* extended source index register */ + uint32_t edi; /* extended destination index flags register */ +} Context_Control; + +#define _CPU_Context_Get_SP( _context ) \ + (_context)->esp + +/* + * FP context save area for the i387 numeric coprocessors. + */ +#ifdef __SSE__ +/* All FPU and SSE registers are volatile; hence, as long + * as we are within normally executing C code (including + * a task switch) there is no need for saving/restoring + * any of those registers. + * We must save/restore the full FPU/SSE context across + * interrupts and exceptions, however: + * - after ISR execution a _Thread_Dispatch() may happen + * and it is therefore necessary to save the FPU/SSE + * registers to be restored when control is returned + * to the interrupted task. + * - gcc may implicitly use FPU/SSE instructions in + * an ISR. + * + * Even though there is no explicit mentioning of the FPU + * control word in the SYSV ABI (i386) being non-volatile + * we maintain MXCSR and the FPU control-word for each task. + */ +typedef struct { + uint32_t mxcsr; + uint16_t fpucw; +} Context_Control_fp; + +#else + +typedef struct { + uint8_t fp_save_area[108]; /* context size area for I80387 */ + /* 28 bytes for environment */ +} Context_Control_fp; + +#endif + + +/* + * The following structure defines the set of information saved + * on the current stack by RTEMS upon receipt of execptions. + * + * idtIndex is either the interrupt number or the trap/exception number. + * faultCode is the code pushed by the processor on some exceptions. + * + * Since the first registers are directly pushed by the CPU they + * may not respect 16-byte stack alignment, which is, however, + * mandatory for the SSE register area. + * Therefore, these registers are stored at an aligned address + * and a pointer is stored in the CPU_Exception_frame. + * If the executive was compiled without SSE support then + * this pointer is NULL. + */ + +struct Context_Control_sse; + +typedef struct { + struct Context_Control_sse *fp_ctxt; + uint32_t edi; + uint32_t esi; + uint32_t ebp; + uint32_t esp0; + uint32_t ebx; + uint32_t edx; + uint32_t ecx; + uint32_t eax; + uint32_t idtIndex; + uint32_t faultCode; + uint32_t eip; + uint32_t cs; + uint32_t eflags; +} CPU_Exception_frame; + +#ifdef __SSE__ +typedef struct Context_Control_sse { + uint16_t fcw; + uint16_t fsw; + uint8_t ftw; + uint8_t res_1; + uint16_t fop; + uint32_t fpu_ip; + uint16_t cs; + uint16_t res_2; + uint32_t fpu_dp; + uint16_t ds; + uint16_t res_3; + uint32_t mxcsr; + uint32_t mxcsr_mask; + struct { + uint8_t fpreg[10]; + uint8_t res_4[ 6]; + } fp_mmregs[8]; + uint8_t xmmregs[8][16]; + uint8_t res_5[224]; +} Context_Control_sse +__attribute__((aligned(16))) +; +#endif + +typedef void (*cpuExcHandlerType) (CPU_Exception_frame*); +extern cpuExcHandlerType _currentExcHandler; +extern void rtems_exception_init_mngt(void); + +/* + * This port does not pass any frame info to the + * interrupt handler. + */ + +typedef void CPU_Interrupt_frame; + +typedef enum { + I386_EXCEPTION_DIVIDE_BY_ZERO = 0, + I386_EXCEPTION_DEBUG = 1, + I386_EXCEPTION_NMI = 2, + I386_EXCEPTION_BREAKPOINT = 3, + I386_EXCEPTION_OVERFLOW = 4, + I386_EXCEPTION_BOUND = 5, + I386_EXCEPTION_ILLEGAL_INSTR = 6, + I386_EXCEPTION_MATH_COPROC_UNAVAIL = 7, + I386_EXCEPTION_DOUBLE_FAULT = 8, + I386_EXCEPTION_I386_COPROC_SEG_ERR = 9, + I386_EXCEPTION_INVALID_TSS = 10, + I386_EXCEPTION_SEGMENT_NOT_PRESENT = 11, + I386_EXCEPTION_STACK_SEGMENT_FAULT = 12, + I386_EXCEPTION_GENERAL_PROT_ERR = 13, + I386_EXCEPTION_PAGE_FAULT = 14, + I386_EXCEPTION_INTEL_RES15 = 15, + I386_EXCEPTION_FLOAT_ERROR = 16, + I386_EXCEPTION_ALIGN_CHECK = 17, + I386_EXCEPTION_MACHINE_CHECK = 18, + I386_EXCEPTION_ENTER_RDBG = 50 /* to enter manually RDBG */ + +} Intel_symbolic_exception_name; + + +/* + * context size area for floating point + * + * NOTE: This is out of place on the i386 to avoid a forward reference. + */ + +#define CPU_CONTEXT_FP_SIZE sizeof( Context_Control_fp ) + +/* variables */ + +SCORE_EXTERN Context_Control_fp _CPU_Null_fp_context; + +#endif /* ASM */ + +/* constants */ + +/* + * This defines the number of levels and the mask used to pick those + * bits out of a thread mode. + */ + +#define CPU_MODES_INTERRUPT_LEVEL 0x00000001 /* interrupt level in mode */ +#define CPU_MODES_INTERRUPT_MASK 0x00000001 /* interrupt level in mode */ + +/* + * extra stack required by the MPCI receive server thread + */ + +#define CPU_MPCI_RECEIVE_SERVER_EXTRA_STACK 1024 + +/* + * i386 family supports 256 distinct vectors. + */ + +#define CPU_INTERRUPT_NUMBER_OF_VECTORS 256 +#define CPU_INTERRUPT_MAXIMUM_VECTOR_NUMBER (CPU_INTERRUPT_NUMBER_OF_VECTORS - 1) + +/* + * This is defined if the port has a special way to report the ISR nesting + * level. Most ports maintain the variable _ISR_Nest_level. + */ + +#define CPU_PROVIDES_ISR_IS_IN_PROGRESS FALSE + +/* + * Minimum size of a thread's stack. + */ + +#define CPU_STACK_MINIMUM_SIZE 4096 + +/* + * i386 is pretty tolerant of alignment. Just put things on 4 byte boundaries. + */ + +#define CPU_ALIGNMENT 4 +#define CPU_HEAP_ALIGNMENT CPU_ALIGNMENT +#define CPU_PARTITION_ALIGNMENT CPU_ALIGNMENT + +/* + * On i386 thread stacks require no further alignment after allocation + * from the Workspace. However, since gcc maintains 16-byte alignment + * we try to respect that. If you find an option to let gcc squeeze + * the stack more tightly then setting CPU_STACK_ALIGNMENT to 16 still + * doesn't waste much space since this only determines the *initial* + * alignment. + */ + +#define CPU_STACK_ALIGNMENT 16 + +/* macros */ + +#ifndef ASM +/* + * ISR handler macros + * + * These macros perform the following functions: + * + initialize the RTEMS vector table + * + disable all maskable CPU interrupts + * + restore previous interrupt level (enable) + * + temporarily restore interrupts (flash) + * + set a particular level + */ + +#define _CPU_Initialize_vectors() + +#define _CPU_ISR_Disable( _level ) i386_disable_interrupts( _level ) + +#define _CPU_ISR_Enable( _level ) i386_enable_interrupts( _level ) + +#define _CPU_ISR_Flash( _level ) i386_flash_interrupts( _level ) + +#define _CPU_ISR_Set_level( _new_level ) \ + { \ + if ( _new_level ) __asm__ volatile ( "cli" ); \ + else __asm__ volatile ( "sti" ); \ + } + +uint32_t _CPU_ISR_Get_level( void ); + +/* Make sure interrupt stack has space for ISR + * 'vector' arg at the top and that it is aligned + * properly. + */ + +#define _CPU_Interrupt_stack_setup( _lo, _hi ) \ + do { \ + _hi = (void*)(((uintptr_t)(_hi) - 4) & ~ (CPU_STACK_ALIGNMENT - 1)); \ + } while (0) + +#endif /* ASM */ + +/* end of ISR handler macros */ + +/* + * Context handler macros + * + * These macros perform the following functions: + * + initialize a context area + * + restart the current thread + * + calculate the initial pointer into a FP context area + * + initialize an FP context area + */ + +#define CPU_EFLAGS_INTERRUPTS_ON 0x00003202 +#define CPU_EFLAGS_INTERRUPTS_OFF 0x00003002 + +#ifndef ASM + +/* + * Stack alignment note: + * + * We want the stack to look to the '_entry_point' routine + * like an ordinary stack frame as if '_entry_point' was + * called from C-code. + * Note that '_entry_point' is jumped-to by the 'ret' + * instruction returning from _CPU_Context_switch() or + * _CPU_Context_restore() thus popping the _entry_point + * from the stack. + * However, _entry_point expects a frame to look like this: + * + * args [_Thread_Handler expects no args, however] + * ------ (alignment boundary) + * SP-> return_addr return here when _entry_point returns which (never happens) + * + * + * Hence we must initialize the stack as follows + * + * [arg1 ]: n/a + * [arg0 (aligned)]: n/a + * [ret. addr ]: NULL + * SP-> [jump-target ]: _entry_point + * + * When Context_switch returns it pops the _entry_point from + * the stack which then finds a standard layout. + */ + + +#define _CPU_Context_Initialize( _the_context, _stack_base, _size, \ + _isr, _entry_point, _is_fp ) \ + do { \ + uint32_t _stack; \ + \ + if ( (_isr) ) (_the_context)->eflags = CPU_EFLAGS_INTERRUPTS_OFF; \ + else (_the_context)->eflags = CPU_EFLAGS_INTERRUPTS_ON; \ + \ + _stack = ((uint32_t)(_stack_base)) + (_size); \ + _stack &= ~ (CPU_STACK_ALIGNMENT - 1); \ + _stack -= 2*sizeof(proc_ptr*); /* see above for why we need to do this */ \ + *((proc_ptr *)(_stack)) = (_entry_point); \ + (_the_context)->ebp = (void *) 0; \ + (_the_context)->esp = (void *) _stack; \ + } while (0) + +#define _CPU_Context_Restart_self( _the_context ) \ + _CPU_Context_restore( (_the_context) ); + +#if defined(RTEMS_SMP) + #define _CPU_Context_switch_to_first_task_smp( _the_context ) \ + _CPU_Context_restore( (_the_context) ); + + /* address space 1 is uncacheable */ + #define SMP_CPU_SWAP( _address, _value, _previous ) \ + do { \ + asm volatile("lock; xchgl %0, %1" : \ + "+m" (*_address), "=a" (_previous) : \ + "1" (_value) : \ + "cc"); \ + } while (0) +#endif + +#define _CPU_Context_Fp_start( _base, _offset ) \ + ( (void *) _Addresses_Add_offset( (_base), (_offset) ) ) + +#define _CPU_Context_Initialize_fp( _fp_area ) \ + { \ + memcpy( *_fp_area, &_CPU_Null_fp_context, CPU_CONTEXT_FP_SIZE ); \ + } + +/* end of Context handler macros */ + +/* + * Fatal Error manager macros + * + * These macros perform the following functions: + * + disable interrupts and halt the CPU + */ + +#define _CPU_Fatal_halt( _error ) \ + { \ + __asm__ volatile ( "cli ; \ + movl %0,%%eax ; \ + hlt" \ + : "=r" ((_error)) : "0" ((_error)) \ + ); \ + } + +#endif /* ASM */ + +/* end of Fatal Error manager macros */ + +/* + * Bitfield handler macros + * + * These macros perform the following functions: + * + scan for the highest numbered (MSB) set in a 16 bit bitfield + */ + +#define CPU_USE_GENERIC_BITFIELD_CODE FALSE +#define CPU_USE_GENERIC_BITFIELD_DATA FALSE + +#define _CPU_Bitfield_Find_first_bit( _value, _output ) \ + { \ + register uint16_t __value_in_register = (_value); \ + \ + _output = 0; \ + \ + __asm__ volatile ( "bsfw %0,%1 " \ + : "=r" (__value_in_register), "=r" (_output) \ + : "0" (__value_in_register), "1" (_output) \ + ); \ + } + +/* end of Bitfield handler macros */ + +/* + * Priority handler macros + * + * These macros perform the following functions: + * + return a mask with the bit for this major/minor portion of + * of thread priority set. + * + translate the bit number returned by "Bitfield_find_first_bit" + * into an index into the thread ready chain bit maps + */ + +#define _CPU_Priority_Mask( _bit_number ) \ + ( 1 << (_bit_number) ) + +#define _CPU_Priority_bits_index( _priority ) \ + (_priority) + +/* functions */ + +#ifndef ASM +/* + * _CPU_Initialize + * + * This routine performs CPU dependent initialization. + */ + +void _CPU_Initialize(void); + +/* + * _CPU_ISR_install_raw_handler + * + * This routine installs a "raw" interrupt handler directly into the + * processor's vector table. + */ + +void _CPU_ISR_install_raw_handler( + uint32_t vector, + proc_ptr new_handler, + proc_ptr *old_handler +); + +/* + * _CPU_ISR_install_vector + * + * This routine installs an interrupt vector. + */ + +void _CPU_ISR_install_vector( + uint32_t vector, + proc_ptr new_handler, + proc_ptr *old_handler +); + +/* + * _CPU_Thread_Idle_body + * + * Use the halt instruction of low power mode of a particular i386 model. + */ + +#if (CPU_PROVIDES_IDLE_THREAD_BODY == TRUE) + +void *_CPU_Thread_Idle_body( uintptr_t ignored ); + +#endif /* CPU_PROVIDES_IDLE_THREAD_BODY */ + +/* + * _CPU_Context_switch + * + * This routine switches from the run context to the heir context. + */ + +void _CPU_Context_switch( + Context_Control *run, + Context_Control *heir +); + +/* + * _CPU_Context_restore + * + * This routine is generally used only to restart self in an + * efficient manner and avoid stack conflicts. + */ + +void _CPU_Context_restore( + Context_Control *new_context +) RTEMS_COMPILER_NO_RETURN_ATTRIBUTE; + +/* + * _CPU_Context_save_fp + * + * This routine saves the floating point context passed to it. + */ + +#ifdef __SSE__ +#define _CPU_Context_save_fp(fp_context_pp) \ + do { \ + __asm__ __volatile__( \ + "fstcw %0" \ + :"=m"((*(fp_context_pp))->fpucw) \ + ); \ + __asm__ __volatile__( \ + "stmxcsr %0" \ + :"=m"((*(fp_context_pp))->mxcsr) \ + ); \ + } while (0) +#else +void _CPU_Context_save_fp( + Context_Control_fp **fp_context_ptr +); +#endif + +/* + * _CPU_Context_restore_fp + * + * This routine restores the floating point context passed to it. + */ +#ifdef __SSE__ +#define _CPU_Context_restore_fp(fp_context_pp) \ + do { \ + __asm__ __volatile__( \ + "fldcw %0" \ + ::"m"((*(fp_context_pp))->fpucw) \ + :"fpcr" \ + ); \ + __builtin_ia32_ldmxcsr(_Thread_Executing->fp_context->mxcsr); \ + } while (0) +#else +void _CPU_Context_restore_fp( + Context_Control_fp **fp_context_ptr +); +#endif + +#ifdef __SSE__ +#define _CPU_Context_Initialization_at_thread_begin() \ + do { \ + __asm__ __volatile__( \ + "finit" \ + : \ + : \ + :"st","st(1)","st(2)","st(3)", \ + "st(4)","st(5)","st(6)","st(7)", \ + "fpsr","fpcr" \ + ); \ + if ( _Thread_Executing->fp_context ) { \ + _CPU_Context_restore_fp(&_Thread_Executing->fp_context); \ + } \ + } while (0) +#endif + +#endif /* ASM */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/cpukit/score/cpu/i386/rtems/score/i386.h b/cpukit/score/cpu/i386/rtems/score/i386.h new file mode 100644 index 0000000000..2d8a8969cb --- /dev/null +++ b/cpukit/score/cpu/i386/rtems/score/i386.h @@ -0,0 +1,246 @@ +/** + * @file rtems/score/i386.h + */ + +/* + * This include file contains information pertaining to the Intel + * i386 processor. + * + * COPYRIGHT (c) 1989-1999. + * 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.com/license/LICENSE. + * + * $Id$ + */ + +#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) + * i386_nofp (i386 DX or SX w/o i387) + * i486dx + * i486sx + * 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. + * + */ + +#if defined(_SOFT_FLOAT) +#define I386_HAS_FPU 0 +#else +#define I386_HAS_FPU 1 +#endif + +#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__) + +# if !defined(_SOFT_FLOAT) +# define CPU_MODEL_NAME "i486dx" +# else +# define CPU_MODEL_NAME "i486sx" +# endif + +#elif defined(__i386__) + +#define I386_HAS_BSWAP 0 + +# if !defined(_SOFT_FLOAT) +# define CPU_MODEL_NAME "i386 with i387" +# else +# define CPU_MODEL_NAME "i386 w/o i387" +# endif + +#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_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 + +/* + * 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 +); + + +/* + * "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 diff --git a/cpukit/score/cpu/i386/rtems/score/idtr.h b/cpukit/score/cpu/i386/rtems/score/idtr.h new file mode 100644 index 0000000000..361c8472b9 --- /dev/null +++ b/cpukit/score/cpu/i386/rtems/score/idtr.h @@ -0,0 +1,66 @@ +/** + * @file rtems/score/idtr.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 + * + * Formerly contained in and extracted from libcpu/i386/cpu.h. + * + * 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 the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + * + * Applications must not include this file directly. + */ + +#ifndef _RTEMS_SCORE_IDTR_H +#define _RTEMS_SCORE_IDTR_H + +/* + * 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 + */ +extern void create_interrupt_gate_descriptor (interrupt_gate_descriptor*, rtems_raw_irq_hdl); + +/* + * C callable function enabling to get easily 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); + +#endif diff --git a/cpukit/score/cpu/i386/rtems/score/interrupts.h b/cpukit/score/cpu/i386/rtems/score/interrupts.h new file mode 100644 index 0000000000..b6b541fb0e --- /dev/null +++ b/cpukit/score/cpu/i386/rtems/score/interrupts.h @@ -0,0 +1,79 @@ +/** + * @file rtems/score/interrupts.h + */ + +/* + * i386 interrupt macros. + * + * Formerly contained in and extracted from libcpu/i386/cpu.h + * + * 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.rtems.com/license/LICENSE. + * + * $Id$ + * + * Applications must not include this file directly. + */ + +#ifndef _RTEMS_SCORE_INTERRUPTS_H +#define _RTEMS_SCORE_INTERRUPTS_H + +#ifndef ASM + +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__*); + +/* + * Interrupt Level Macros + */ + +#define i386_disable_interrupts( _level ) \ + { \ + __asm__ volatile ( "pushf ; \ + cli ; \ + pop %0" \ + : "=rm" ((_level)) \ + ); \ + } + +#define i386_enable_interrupts( _level ) \ + { \ + __asm__ volatile ( "push %0 ; \ + popf" \ + : : "rm" ((_level)) : "cc" \ + ); \ + } + +#define i386_flash_interrupts( _level ) \ + { \ + __asm__ volatile ( "push %0 ; \ + popf ; \ + cli" \ + : : "rm" ((_level)) : "cc" \ + ); \ + } + +#define i386_get_interrupt_level( _level ) \ + do { \ + register uint32_t _eflags; \ + \ + __asm__ volatile ( "pushf ; \ + pop %0" \ + : "=rm" ((_eflags)) \ + ); \ + \ + _level = (_eflags & EFLAGS_INTR_ENABLE) ? 0 : 1; \ + } while (0) + +#define _CPU_ISR_Disable( _level ) i386_disable_interrupts( _level ) +#define _CPU_ISR_Enable( _level ) i386_enable_interrupts( _level ) + +#endif +#endif diff --git a/cpukit/score/cpu/i386/rtems/score/registers.h b/cpukit/score/cpu/i386/rtems/score/registers.h new file mode 100644 index 0000000000..81c2a65e15 --- /dev/null +++ b/cpukit/score/cpu/i386/rtems/score/registers.h @@ -0,0 +1,72 @@ +/** + * @file rtems/score/registers.h + */ + +/* + * This file contains definition and constants related to Intel Cpu + * + * 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.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifndef _RTEMS_SCORE_REGISTERS_H +#define _RTEMS_SCORE_REGISTERS_H + +/* + * definition related to EFLAGS + */ +#define EFLAGS_CARRY 0x1 +#define EFLAGS_PARITY 0x4 + +#define EFLAGS_AUX_CARRY 0x10 +#define EFLAGS_ZERO 0x40 +#define EFLAGS_SIGN 0x80 + +#define EFLAGS_TRAP 0x100 +#define EFLAGS_INTR_ENABLE 0x200 +#define EFLAGS_DIRECTION 0x400 +#define EFLAGS_OVERFLOW 0x800 + +#define EFLAGS_IOPL_MASK 0x3000 +#define EFLAGS_NESTED_TASK 0x8000 + +#define EFLAGS_RESUME 0x10000 +#define EFLAGS_VIRTUAL_MODE 0x20000 +#define EFLAGS_ALIGN_CHECK 0x40000 +#define EFLAGS_VIRTUAL_INTR 0x80000 + +#define EFLAGS_VIRTUAL_INTR_PEND 0x100000 +#define EFLAGS_ID 0x200000 + +/* + * definitions related to CR0 + */ +#define CR0_PROTECTION_ENABLE 0x1 +#define CR0_MONITOR_COPROC 0x2 +#define CR0_COPROC_SOFT_EMUL 0x4 +#define CR0_FLOATING_INSTR_EXCEPTION 0x8 + +#define CR0_EXTENSION_TYPE 0x10 +#define CR0_NUMERIC_ERROR 0x20 + +#define CR0_WRITE_PROTECT 0x10000 +#define CR0_ALIGMENT_MASK 0x40000 + +#define CR0_NO_WRITE_THROUGH 0x20000000 +#define CR0_PAGE_LEVEL_CACHE_DISABLE 0x40000000 +#define CR0_PAGING 0x80000000 + +/* + * definitions related to CR3 + */ + +#define CR3_PAGE_CACHE_DISABLE 0x10 +#define CR3_PAGE_WRITE_THROUGH 0x8 +#define CR3_PAGE_DIRECTORY_MASK 0xFFFFF000 + +#endif diff --git a/cpukit/score/cpu/i386/rtems/score/types.h b/cpukit/score/cpu/i386/rtems/score/types.h new file mode 100644 index 0000000000..3a21714a0a --- /dev/null +++ b/cpukit/score/cpu/i386/rtems/score/types.h @@ -0,0 +1,44 @@ +/** + * @file rtems/score/types.h + */ + +/* + * This include file contains type definitions pertaining to the Intel + * i386 processor family. + * + * COPYRIGHT (c) 1989-1999. + * 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.com/license/LICENSE. + * + * $Id$ + */ + +#ifndef _RTEMS_SCORE_TYPES_H +#define _RTEMS_SCORE_TYPES_H + +#include <rtems/score/basedefs.h> + +#ifndef ASM + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This section defines the basic types for this processor. + */ + +typedef uint16_t Priority_bit_map_Control; +typedef void i386_isr; +typedef i386_isr ( *i386_isr_entry )( void ); + +#ifdef __cplusplus +} +#endif + +#endif /* !ASM */ + +#endif diff --git a/cpukit/score/cpu/i386/sse_test.c b/cpukit/score/cpu/i386/sse_test.c new file mode 100644 index 0000000000..8b1cbd2658 --- /dev/null +++ b/cpukit/score/cpu/i386/sse_test.c @@ -0,0 +1,954 @@ +/* $Id$ */ + +/* + * Authorship + * ---------- + * This software was created by + * Till Straumann <strauman@slac.stanford.edu>, 2009, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * This software was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ + + +/* Code for testing FPU/SSE context save/restore across exceptions + * (including interrupts). + * + * There are two tasks and an IRQ/EXC handler involved. One task (LP) + * is of lower priority than the other (HP) task. + * + * 1) LP task sets up a context area in memory (known contents; every + * register is loaded with different values) + * + * 2) LP task + * 2a saves original FP/SSE context + * 2b loads context from 1) into FPU/SSE + * 2c raises an exception or interrupt + * + * * (2d save FPU/SSE context after irq/exception returns to + * separate area for verification + * 2e reload original FP/SSE context.) + * + * * All these five steps are coded in assembly to prevent + * gcc from manipulating the FP/SSE state. The last two steps, + * however, are effectively executed during 6 when control is + * returned to the LP task. + * + * 3) IRQ/EXC handler OS wrapper saves context, initializes FPU and + * MXCSR. + * + * 4) user (our) irq/exc handler clears exception condition, clobbers + * FPU and XMM regs and finally releases a semaphore on which HP + * task is waiting. + * + * 5) context switch to HP task. HP task clobbers FPU and XMM regs. + * Then it tries to re-acquire the synchronization semaphore and + * blocks. + * + * 6) task switch back to (interrupted) LP task. Original context is + * restored and verified against the context that was setup in 1). + * + * + * Three methods for interrupting the LP task are tested + * + * a) FP exception (by setting an exception status in the context from 1) + * b) SSE exception (by computing the square root of a vector of negative + * numbers. + * c) IRQ (software IRQ via 'INT xx' instruction) + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef __rtems__ +#include <rtems.h> +#include <rtems/score/cpu.h> +#include <rtems/irq.h> +#include <rtems/error.h> +#endif + +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +/* This is currently hardcoded (int xx opcode requires immediate operand) */ +#define SSE_TEST_IRQ 10 + +typedef uint8_t __v8 __attribute__((vector_size(16))); +typedef uint32_t __v32 __attribute__((vector_size(16))); +typedef float __vf __attribute__((vector_size(16))); + +#ifndef __rtems__ +/* Clone of what is defined in rtems/score/cpu.h (for testing under linux) */ +typedef struct Context_Control_sse { + uint16_t fcw; + uint16_t fsw; + uint8_t ftw; + uint8_t res_1; + uint16_t fop; + uint32_t fpu_ip; + uint16_t cs; + uint16_t res_2; + uint32_t fpu_dp; + uint16_t ds; + uint16_t res_3; + uint32_t mxcsr; + uint32_t mxcsr_mask; + struct { + uint8_t fpreg[10]; + uint8_t res_4[ 6]; + } fp_mmregs[8]; + uint8_t xmmregs[8][16]; + uint8_t res_5[224]; +} Context_Control_sse +__attribute__((aligned(16))) +; +#endif + +#define MXCSR_FZ (1<<15) /* Flush to zero */ +#define MXCSR_RC(x) (((x)&3)<<13) /* Rounding ctrl */ +#define MXCSR_PM (1<<12) /* Precision msk */ +#define MXCSR_UM (1<<11) /* Underflow msk */ +#define MXCSR_OM (1<<10) /* Overflow msk */ +#define MXCSR_ZM (1<< 9) /* Divbyzero msk */ +#define MXCSR_DM (1<< 8) /* Denormal msk */ +#define MXCSR_IM (1<< 7) /* Invalidop msk */ +#define MXCSR_DAZ (1<< 6) /* Denorml are 0 */ +#define MXCSR_PE (1<< 5) /* Precision flg */ +#define MXCSR_UE (1<< 4) /* Underflow flg */ +#define MXCSR_OE (1<< 3) /* Overflow flg */ +#define MXCSR_ZE (1<< 2) /* Divbyzero flg */ +#define MXCSR_DE (1<< 1) /* Denormal flg */ +#define MXCSR_IE (1<< 0) /* Invalidop flg */ + +#define MXCSR_ALLM (MXCSR_PM | MXCSR_UM | MXCSR_OM | MXCSR_ZM | MXCSR_DM | MXCSR_IM) +#define MXCSR_ALLE (MXCSR_PE | MXCSR_UE | MXCSR_OE | MXCSR_ZE | MXCSR_DE | MXCSR_IE) + +#define FPSR_B (1<<15) /* FPU busy */ +#define FPSR_C3 (1<<14) /* Cond code C3 */ +#define FPSR_TOP(x) (((x)&7)<<11) /* TOP */ +#define FPSR_C2 (1<<10) /* Cond code C2 */ +#define FPSR_C1 (1<< 9) /* Cond code C1 */ +#define FPSR_C0 (1<< 8) /* Cond code C0 */ +#define FPSR_ES (1<< 7) /* Error summary */ +#define FPSR_SF (1<< 6) /* Stack fault */ +#define FPSR_PE (1<< 5) /* Precision flg */ +#define FPSR_UE (1<< 4) /* Underflow flg */ +#define FPSR_OE (1<< 3) /* Overflow flg */ +#define FPSR_ZE (1<< 2) /* Divbyzero flg */ +#define FPSR_DE (1<< 1) /* Denormal flg */ +#define FPSR_IE (1<< 0) /* Invalidop flg */ + +#define FPCW_X (1<<12) /* Infinity ctrl */ +#define FPCW_RC(x) (((x)&3)<<10) /* Rounding ctrl */ +#define FPCW_PC(x) (((x)&3)<< 8) /* Precision ctl */ +#define FPCW_PM (1<< 5) /* Precision msk */ +#define FPCW_UM (1<< 4) /* Underflow msk */ +#define FPCW_OM (1<< 3) /* Overflow msk */ +#define FPCW_ZM (1<< 2) /* Divbyzero msk */ +#define FPCW_DM (1<< 1) /* Denormal msk */ +#define FPCW_IM (1<< 0) /* Invalidop msk */ + +#define FPCW_ALLM (FPCW_PM | FPCW_UM | FPCW_OM | FPCW_ZM | FPCW_DM | FPCW_IM) +#define FPSR_ALLE (FPSR_ES | FPSR_SF | FPSR_PE | FPSR_UE | FPSR_OE | FPSR_ZE | FPSR_DE | FPSR_IE) + +/* Store 'double' into 80-bit register image */ +void +fp_st1(uint8_t (*p_dst)[10], double v) +{ + asm volatile("fstpt %0":"=m"(*p_dst):"t"(v):"st"); +} + +/* Store 'double' into 80-bit register image #i in context */ +void +fp_st(Context_Control_sse *p_ctxt, int i, double v) +{ + fp_st1(&p_ctxt->fp_mmregs[i].fpreg,v); +} + +/* Load 'double' from 80-bit register image */ +double +fp_ld1(uint8_t (*p_src)[10]) +{ +double v; + + asm volatile("fldt %1":"=t"(v):"m"((*p_src)[0]),"m"(*p_src)); + return v; +} + +/* Load 'double' from 80-bit register image #i in context */ +double +fp_ld(Context_Control_sse *p_ctxt, int i) +{ + return fp_ld1(&p_ctxt->fp_mmregs[i].fpreg); +} + +#define FPUCLOBBER \ + "st","st(1)","st(2)","st(3)", \ + "st(4)","st(5)","st(6)","st(7)",\ + "fpsr","fpcr" + +/* There seems to be no way to say that mxcsr was clobbered */ + +#define SSECLOBBER \ + "xmm0","xmm1","xmm2","xmm3", \ + "xmm4","xmm5","xmm6","xmm7" + +static void +sse_clobber(uint32_t x) +{ +__v32 v = { x, x, x, x }; + asm volatile ( + " movdqa %0, %%xmm0 \n" + " movdqa %%xmm0, %%xmm1 \n" + " movdqa %%xmm0, %%xmm2 \n" + " movdqa %%xmm0, %%xmm3 \n" + " movdqa %%xmm0, %%xmm4 \n" + " movdqa %%xmm0, %%xmm5 \n" + " movdqa %%xmm0, %%xmm6 \n" + " movdqa %%xmm0, %%xmm7 \n" + : + :"m"(v) + :SSECLOBBER + ); +} + +void +all_clobber(uint32_t v1, uint32_t v2); + +__asm__ ( +"all_clobber: \n" +" finit \n" +" movq 0(%esp), %xmm0 \n" +" punpcklqdq %xmm0, %xmm0 \n" +" movdqa %xmm0, %xmm1 \n" +" movdqa %xmm0, %xmm2 \n" +" movdqa %xmm0, %xmm3 \n" +" movdqa %xmm0, %xmm4 \n" +" movdqa %xmm0, %xmm5 \n" +" movdqa %xmm0, %xmm6 \n" +" movdqa %xmm0, %xmm7 \n" +" ret \n" +); + +/* Clear FPU and save FPU/SSE registers to context area */ + +void +init_ctxt(Context_Control_sse *p_ctxt); + +__asm__ ( +"init_ctxt: \n" +" finit \n" +" mov 4(%esp), %eax\n" +" fxsave (%eax) \n" +" fwait \n" +" ret \n" +); + +/* Save FPU/SSE registers to context area */ + +static void +stor_ctxt(Context_Control_sse *p_ctxt) +{ + memset(p_ctxt, 0, sizeof(*p_ctxt)); + asm volatile( +/* " finit \n" */ + " fxsave %0 \n" + " fwait \n" + : "=m"(*p_ctxt) + : + : FPUCLOBBER + ); +} + +#define H08 "0x%02"PRIx8 +#define H16 "0x%04"PRIx16 +#define H32 "0x%08"PRIx32 + +#define F16 "mismatch ("H16" != "H16")\n" + +#define FLDCMP(fld, fmt) \ + if ( a->fld != b->fld ) { \ + rval = 1; \ + if ( !quiet ) \ + fprintf(stderr,#fld" mismatch ("fmt" != "fmt")\n",a->fld, b->fld); \ + } + +#define FLTCMP(i) \ + do { \ + if ( ( (a->ftw ^ b->ftw) & (1<<i)) \ + || ( (a->ftw & b->ftw & (1<<i)) && \ + memcmp(a->fp_mmregs[i].fpreg, \ + b->fp_mmregs[i].fpreg, \ + sizeof(a->fp_mmregs[i].fpreg)) \ + ) \ + ) { \ + rval = 1; \ + if ( !quiet ) { \ + double fa = fp_ld(a, i); \ + double fb = fp_ld(b, i); \ + if ( ((a->ftw ^ b->ftw) & (1<<i)) ) \ + fprintf(stderr,"fpreg[%u] TAG mismatch (%u != %u)\n",i,(a->ftw & (1<<i)) ? 1 : 0,(b->ftw & (1<<i)) ? 1 : 0); \ + else \ + fprintf(stderr,"fpreg[%u] mismatch (%g != %g)\n",i,fa,fb); \ + } \ + } \ + } while (0) + +#define XMMCMP(i) \ + do { \ + if ( memcmp(&a->xmmregs[i], \ + &b->xmmregs[i], \ + sizeof(a->xmmregs[i])) \ + ) { \ + rval = 1; \ + if ( !quiet ) { \ + int _jj; \ + fprintf(stderr,"xmmreg[%u] mismatch:\n", i); \ + fprintf(stderr," "); \ + for (_jj=0; _jj<16; _jj++) \ + fprintf(stderr,"%02x ",a->xmmregs[i][_jj]); \ + fprintf(stderr,"\n !=\n"); \ + fprintf(stderr," "); \ + for (_jj=0; _jj<16; _jj++) \ + fprintf(stderr,"%02x ",b->xmmregs[i][_jj]); \ + fprintf(stderr,"\n"); \ + } \ + } \ + } while (0) + + +/* Compare two FPU/SSE context areas and flag differences; + * RETURNS: zero if the contexts match and nonzero otherwise + */ +static int +cmp_ctxt(Context_Control_sse *a, Context_Control_sse *b, int quiet) +{ +int rval = 0; +int i; + FLDCMP(fcw,H16); + FLDCMP(fsw,H16); + FLDCMP(ftw,H08); + FLDCMP(fop,H16); + FLDCMP(fpu_ip,H32); + FLDCMP(cs,H16); + FLDCMP(fpu_dp,H32); + FLDCMP(ds,H16); + FLDCMP(mxcsr,H32); + FLDCMP(mxcsr_mask,H32); + for ( i=0; i<8; i++ ) { + FLTCMP(i); + } + for ( i=0; i<8; i++ ) { + XMMCMP(i); + } + return rval; +} + +/* Possible arguments to exc_raise() */ + +#define FP_EXC 0 +#define IRQ_EXC 1 +#define SSE_EXC -1 + +/* Check stack alignment by raising the interrupt from a + * non-16-byte aligned section of code. The exception/IRQ + * handler must align the stack and SSE context area + * properly or it will crash. + */ +#define __INTRAISE(x) " int $32+"#x" \n" +#define INTRAISE(x) __INTRAISE(x) + +__asm__ ( +"do_raise: \n" +" fwait \n" +" test %eax, %eax \n" +" je 2f \n" +" jl 1f \n" +INTRAISE(SSE_TEST_IRQ) +" jmp 2f \n" +"1: sqrtps %xmm0, %xmm0 \n" +"2: \n" +" ret \n" +); + +#define SSE_TEST_HP_FAILED 1 +#define SSE_TEST_FSPR_FAILED 2 +#define SSE_TEST_CTXTCMP_FAILED 4 + +static const char *fail_msgs[] = { + "Seems that HP task was not executing", + "FPSR 'Invalid-operation' flag should be clear", + "Restored context does NOT match the saved one", +}; + +static void prstat(int st, const char *where) +{ +int i,msk; + for ( i=0, msk=1; i<sizeof(fail_msgs)/sizeof(fail_msgs[0]); i++, msk<<=1 ) { + if ( (st & msk) ) { + fprintf(stderr,"sse_test ERROR: %s (testing: %s)\n", fail_msgs[i], where); + } + } +} + +int sse_test_debug = 0; + +static int +exc_raise(int kind) +{ +Context_Control_sse nctxt; +Context_Control_sse octxt; +Context_Control_sse orig_ctxt; +int i,j,rval; +double s2; +uint16_t fsw; +__vf f4 = { -1., -2., -3., -4. }; +__vf tmp; +__v32 sgn = { (1<<31), (1<<31), (1<<31), (1<<31) }; + + stor_ctxt(&octxt); + + octxt.fsw &= ~FPSR_ALLE; + octxt.mxcsr &= ~MXCSR_ALLE; + + for ( i=0; i<8; i++ ) { + fp_st(&octxt, i, (double)i+0.1); + for (j=0; j<16; j++) { + octxt.xmmregs[i][j]=(i<<4)+j; + } + } + + + if ( SSE_EXC == kind ) { + memcpy(octxt.xmmregs[0], &f4, sizeof(f4)); + octxt.mxcsr &= ~MXCSR_IM; + } + + /* set tags to 'valid' */ + octxt.ftw = 0xff; + + /* enable 'invalid arg' exception */ + octxt.fcw &= ~ ( FPCW_IM ); + + if ( FP_EXC == kind ) { + octxt.fsw |= ( FPSR_IE | FPSR_ES ); + } + + if ( sse_test_debug ) + printk("RAISE (fsw was 0x%04x)\n", orig_ctxt.fsw); + asm volatile( + " fxsave %2 \n" +#ifdef __rtems__ + " movl %4, sse_test_check\n" +#endif + " fxrstor %3 \n" + " call do_raise \n" +#ifdef __rtems__ + " movl sse_test_check, %1\n" +#else + " movl $0, %1 \n" +#endif +#ifdef TEST_MISMATCH + " pxor %%xmm0, %%xmm0 \n" +#endif + " fxsave %0 \n" + " fxrstor %2 \n" + : "=m"(nctxt),"=&r"(rval),"=m"(orig_ctxt) + : "m"(octxt), "i"(SSE_TEST_HP_FAILED),"a"(kind) + : "xmm0" + ); + + if ( ( FPSR_IE & nctxt.fsw ) ) { + rval |= SSE_TEST_FSPR_FAILED; + } + if ( FP_EXC == kind ) + nctxt.fsw |= (FPSR_IE | FPSR_ES); + else if ( SSE_EXC == kind ) { + tmp = __builtin_ia32_sqrtps( (__vf)(~sgn & (__v32)f4) ); + /* sqrt raises PE; just clear it */ + nctxt.mxcsr &= ~MXCSR_PE; + memcpy( octxt.xmmregs[0], &tmp, sizeof(tmp) ); + } + + if ( cmp_ctxt(&nctxt, &octxt, 0) ) { + rval |= SSE_TEST_CTXTCMP_FAILED; + } + + s2 = sqrt(2.0); + + asm volatile("fstsw %0":"=m"(fsw)); + + if ( sse_test_debug ) + printf("sqrt(2): %f (FSTW: 0x%02"PRIx16")\n", sqrt(2.0), fsw); + + return rval; +} + +#ifdef __rtems__ +static void +sse_test_ehdl(CPU_Exception_frame *p_f); + +rtems_id sse_test_sync = 0; +cpuExcHandlerType sse_test_ohdl = 0; + +CPU_Exception_frame *sse_test_frame = 0; +volatile int sse_test_check = SSE_TEST_HP_FAILED; +unsigned sse_tests = 0; + +rtems_task +sse_test_hp_task(rtems_task_argument arg) +{ +rtems_id sync = (rtems_id)arg; + +uint16_t fp_cw; +uint32_t mxcsr; +rtems_status_code sc; +const char * msgs[] = {"FPU_EXC", "SSE_EXC", "IRQ_EXC"}; +int i; + + /* verify that FPU control word is default value */ + asm volatile("fstcw %0":"=m"(fp_cw)); + if ( fp_cw != _CPU_Null_fp_context.fpucw ) { + fprintf( + stderr, + "ERROR: FPU CW initialization mismatch: got 0x%04"PRIx16"; expected 0x%04"PRIx16"\n", + fp_cw, + _CPU_Null_fp_context.fpucw + ); + } + + /* check MXCSR default value */ + asm volatile("stmxcsr %0":"=m"(mxcsr)); + if ( mxcsr != _CPU_Null_fp_context.mxcsr ) { + fprintf( + stderr, + "ERROR: MXCSR initialization mismatch: got 0x%08"PRIx32"; expected 0x%08"PRIx32"\n", + mxcsr, + _CPU_Null_fp_context.mxcsr + ); + } + + + for (i=0; i<sizeof(msgs)/sizeof(msgs[0]); i++ ) { + if ( ( sse_tests & (1<<i) ) ) { + if ( sse_test_debug ) + printk("HP task will now block for %s\n",msgs[i]); + + /* Blocking here lets the low-priority task continue */ + sc = rtems_semaphore_obtain(sync, RTEMS_WAIT, 500); + + all_clobber(0xaffeaffe, 0xcafecafe); + + if ( RTEMS_SUCCESSFUL != sc ) { + rtems_error(sc,"ERROR: sse_test hp task wasn't notified of exception\n"); + goto bail; + } + + /* set flag indicating that we executed until here */ + sse_test_check = 0; + } + } + +bail: + rtems_task_suspend(RTEMS_SELF); +} + +/* Flags to skip individual tests */ +#define SSE_TEST_FPU_EXC (1<<0) +#define SSE_TEST_SSE_EXC (1<<1) +#define SSE_TEST_IRQ_EXC (1<<2) + +#define SSE_TEST_ALL 7 + +/* If this flag is given the executing task is not deleted + * when the test finishes. This is useful if you want to + * execute from a shell or similar. + */ +#define SSE_TEST_NO_DEL (1<<0) + +/* Task arg is bitmask of these flags */ +rtems_task +sse_test_lp_task(rtems_task_argument arg) +{ +rtems_id hp_task = 0; +rtems_status_code sc; +rtems_task_priority pri; +uint16_t fp_cw,fp_cw_set; +uint32_t mxcsr, mxcsr_set; +rtems_irq_connect_data irqd; +int flags = (int)arg; +int st; +int errs = 0; + + sse_tests = SSE_TEST_ALL & ~(flags>>1); + + sse_test_ohdl = 0; + + fp_cw_set = _CPU_Null_fp_context.fpucw | FPCW_RC(3) ; + mxcsr_set = _CPU_Null_fp_context.mxcsr | MXCSR_RC(3) ; + asm volatile("ldmxcsr %0"::"m"(mxcsr_set)); + asm volatile("fldcw %0"::"m"(fp_cw_set)); + + sc = rtems_semaphore_create( + rtems_build_name('s','s','e','S'), + 0, + RTEMS_SIMPLE_BINARY_SEMAPHORE, + 0, + &sse_test_sync + ); + if ( RTEMS_SUCCESSFUL != sc ) { + rtems_error(sc, "sse_test ERROR: creation of 'sync' semaphore failed"); + errs++; + goto bail; + } + + rtems_task_set_priority( RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &pri ); + + sc = rtems_task_create( + rtems_build_name('s','s','e','H'), + pri - 2, + 20000, + RTEMS_DEFAULT_MODES, + RTEMS_FLOATING_POINT, + &hp_task + ); + if ( RTEMS_SUCCESSFUL != sc ) { + hp_task = 0; + rtems_error( sc, "sse_test ERROR: creation of high-priority task failed"); + errs++; + goto bail; + } + + sc = rtems_task_start( hp_task, sse_test_hp_task, (rtems_task_argument)sse_test_sync ); + if ( RTEMS_SUCCESSFUL != sc ) { + rtems_error( sc, "sse_test ERROR: start of high-priority task failed"); + goto bail; + } + + /* Test if FP/SSE context is saved/restored across an exception */ + sse_test_ohdl = _currentExcHandler; + _currentExcHandler = sse_test_ehdl; + + if ( (sse_tests & SSE_TEST_FPU_EXC) ) { + if ( (st = exc_raise(FP_EXC)) ) { + prstat(st,"FP_EXC"); + errs++; + } + + /* Test modified FPCW/MXCSR */ + asm volatile("fstcw %0":"=m"(fp_cw)); + asm volatile("stmxcsr %0":"=m"(mxcsr)); + mxcsr &= ~(MXCSR_ALLE); + if ( fp_cw != fp_cw_set ) { + fprintf(stderr,"sse_test ERROR: FPCW mismatch (after FP_EXC): expected 0x%04"PRIx16", got 0x%04"PRIx16"\n", fp_cw_set, fp_cw); + errs++; + } + if ( mxcsr != mxcsr_set ) { + fprintf(stderr,"sse_test ERROR: MXCSR mismatch (after FP_EXC): expected 0x%08"PRIx32", got 0x%08"PRIx32"\n", mxcsr_set, mxcsr); + errs++; + } + } + + if ( (sse_tests & SSE_TEST_SSE_EXC) ) { + if ( (st = exc_raise(SSE_EXC)) ) { + prstat(st, "SSE_EXC"); + errs++; + } + + /* Test modified FPCW/MXCSR */ + asm volatile("fstcw %0":"=m"(fp_cw)); + asm volatile("stmxcsr %0":"=m"(mxcsr)); + mxcsr &= ~(MXCSR_ALLE); + if ( fp_cw != fp_cw_set ) { + fprintf(stderr,"sse_test ERROR: FPCW mismatch (after SSE_EXC): expected 0x%04"PRIx16", got 0x%04"PRIx16"\n", fp_cw_set, fp_cw); + errs++; + } + if ( mxcsr != mxcsr_set ) { + fprintf(stderr,"sse_test ERROR: MXCSR mismatch (after SSE_EXC): expected 0x%08"PRIx32", got 0x%08"PRIx32"\n", mxcsr_set, mxcsr); + errs++; + } + } + + + if ( (sse_tests & SSE_TEST_IRQ_EXC) ) { + memset( &irqd, 0, sizeof(irqd) ); + irqd.name = SSE_TEST_IRQ; + irqd.hdl = (void*)sse_test_ehdl; + irqd.handle = 0; + + if ( ! BSP_install_rtems_irq_handler( &irqd ) ) { + fprintf(stderr, "sse_test ERROR: Unable to install ISR\n"); + errs++; + goto bail; + } + + /* Test if FP/SSE context is saved/restored across an interrupt */ + if ( (st = exc_raise(IRQ_EXC)) ) { + prstat(st, "IRQ"); + errs++; + } + + if ( ! BSP_remove_rtems_irq_handler( &irqd ) ) { + fprintf(stderr, "sse_test ERROR: Unable to uninstall ISR\n"); + } + + /* Test modified FPCW/MXCSR */ + asm volatile("fstcw %0":"=m"(fp_cw)); + asm volatile("stmxcsr %0":"=m"(mxcsr)); + mxcsr &= ~(MXCSR_ALLE); + if ( fp_cw != fp_cw_set ) { + fprintf(stderr,"sse_test ERROR: FPCW mismatch (after IRQ): expected 0x%04"PRIx16", got 0x%04"PRIx16"\n", fp_cw_set, fp_cw); + errs++; + } + if ( mxcsr != mxcsr_set ) { + fprintf(stderr,"sse_test ERROR: MXCSR mismatch (after IRQ): expected 0x%08"PRIx32", got 0x%08"PRIx32"\n", mxcsr_set, mxcsr); + errs++; + } + } + + +bail: + /* Wait for console to calm down... */ + rtems_task_wake_after(5); + fprintf(stderr,"SSE/FPU Test %s (%u errors)\n", errs ? "FAILED":"PASSED", errs); + if ( sse_test_ohdl ) { + _currentExcHandler = sse_test_ohdl; + sse_test_ohdl = 0; + } + if ( sse_test_sync ) + rtems_semaphore_delete( sse_test_sync ); + sse_test_sync = 0; + if ( hp_task ) + rtems_task_delete( hp_task ); + + if ( ! (flags & SSE_TEST_NO_DEL) ) + rtems_task_delete( RTEMS_SELF ); +} + +static void +sse_test_ehdl(CPU_Exception_frame *p_f) +{ +int i,j,start = 0; +int mismatch; +__vf f4; + + if ( p_f ) { + printk("Got exception #%u\n", p_f->idtIndex); + printk("EIP: 0x%08x, ESP: 0x%08x\n", p_f->eip, p_f->esp0); + printk("TID: 0x%08x\n", _Thread_Executing->Object.id); + + if ( ! p_f->fp_ctxt ) { + printk("ERROR: NO FP/SSE CONTEXT ATTACHED ??\n"); + sse_test_ohdl(p_f); + } + if ( 16 == p_f->idtIndex ) { + printk("Resetting FP status (0x%04"PRIx16")\n", p_f->fp_ctxt->fsw); + p_f->fp_ctxt->fsw = 0; + } else if ( 19 == p_f->idtIndex ) { + start = 1; + memcpy(&f4, p_f->fp_ctxt->xmmregs[0], sizeof(f4)); + f4 = -f4; + memcpy(p_f->fp_ctxt->xmmregs[0], &f4, sizeof(f4)); + p_f->fp_ctxt->mxcsr &= ~MXCSR_ALLE; + } else { + printk("(skipping non-FP exception)\n"); + sse_test_ohdl(p_f); + } + + printk("Checking XMM regs -- "); + for ( mismatch=0, i=start; i<8; i++ ) { + for ( j=0; j<16; j++ ) { + if ( p_f->fp_ctxt->xmmregs[i][j] != ((i<<4) | j) ) + mismatch++; + } + } + if ( mismatch ) { + printk("%u mismatches; dump:\n", mismatch); + for ( i=0; i<8; i++ ) { + for ( j=0; j<16; j++ ) { + printk("0x%02x ", p_f->fp_ctxt->xmmregs[i][j]); + } + printk("\n"); + } + } else { + printk("OK\n"); + } + } else { + printk("IRQ %u\n", SSE_TEST_IRQ); + } + printk("Clobbering FPU/SSE state\n"); + asm volatile("finit"); + sse_clobber(0xdeadbeef); + printk("Notifying task\n"); + rtems_semaphore_release( sse_test_sync ); +} + +#else + +/* Code using signals for testing under linux; unfortunately, 32-bit + * linux seems to pass no SSE context info to the sigaction... + */ + +#include <signal.h> +#include <ucontext.h> + +#define MKCASE(X) case FPE_##X: msg="FPE_"#X; break; + +#define CLRXMM(i) __asm__ volatile("pxor %%xmm"#i", %%xmm"#i:::"xmm"#i) + +static void +fpe_act(int signum, siginfo_t *p_info, void *arg3) +{ +ucontext_t *p_ctxt = arg3; +const char *msg = "FPE_UNKNOWN"; +uint16_t *p_fst; + + if ( SIGFPE != signum ) { + fprintf(stderr,"WARNING: fpe_act handles SIGFPE\n"); + return; + } + switch ( p_info->si_code ) { + default: + fprintf(stderr,"WARNING: fpe_act got unkown code %u\n", p_info->si_code); + return; + MKCASE(INTDIV); + MKCASE(INTOVF); + MKCASE(FLTDIV); + MKCASE(FLTOVF); + MKCASE(FLTUND); + MKCASE(FLTRES); + MKCASE(FLTINV); + MKCASE(FLTSUB); + } + fprintf(stderr,"Got SIGFPE (%s) @%p\n", msg, p_info->si_addr); +#ifdef __linux__ + fprintf(stderr,"Resetting FP status 0x%02lx\n", p_ctxt->uc_mcontext.fpregs->sw); + p_ctxt->uc_mcontext.fpregs->sw = 0; +#ifdef TEST_MISMATCH + fp_st1((void*)&p_ctxt->uc_mcontext.fpregs->_st[3],2.345); +#endif +#endif + + /* Clear FPU; if context is properly saved/restored around exception + * then this shouldn't disturb the register contents of the interrupted + * task/process. + */ + asm volatile("finit"); + sse_clobber(0xdeadbeef); +} + +static void +test(void) +{ +Context_Control_sse ctxt; + + stor_ctxt(&ctxt); + printf("FPCW: 0x%"PRIx16"\nFPSW: 0x%"PRIx16"\n", ctxt.fcw, ctxt.fsw); + printf("FTAG: 0x%"PRIx8"\n",ctxt.ftw); +} + +int +main(int argc, char **argv) +{ +struct sigaction a1, a2; +uint32_t mxcsr; + + memset(&a1, 0, sizeof(a1)); + + a1.sa_sigaction = fpe_act; + a1.sa_flags = SA_SIGINFO; + + if ( sigaction(SIGFPE, &a1, &a2) ) { + perror("sigaction"); + return 1; + } + + asm volatile("stmxcsr %0":"=m"(mxcsr)); + printf("MXCSR: 0x%08"PRIx32"\n", mxcsr); + + test(); + exc_raise(0); + return 0; +} +#endif + +/* Helpers to access CR4 and MXCSR */ + +uint32_t +mfcr4() +{ +uint32_t rval; + asm volatile("mov %%cr4, %0":"=r"(rval)); + return rval; +} + +void +mtcr4(uint32_t rval) +{ + asm volatile("mov %0, %%cr4"::"r"(rval)); +} + +uint32_t +mfmxcsr() +{ +uint32_t rval; + asm volatile("stmxcsr %0":"=m"(rval)); + return rval; +} + +void +mtmxcsr(uint32_t rval) +{ + asm volatile("ldmxcsr %0"::"m"(rval)); +} + + +float +sseraise() +{ +__vf f4={-2., -2., -2. -2.}; +float f; + f4 = __builtin_ia32_sqrtps( f4 ); + memcpy(&f,&f4,sizeof(f)); + return f; +} |