summaryrefslogtreecommitdiffstats
path: root/cpukit/score/cpu/i386/cpu_asm.S
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/score/cpu/i386/cpu_asm.S')
-rw-r--r--cpukit/score/cpu/i386/cpu_asm.S320
1 files changed, 320 insertions, 0 deletions
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