#include <minix/cpufeature.h>
#include <a.out.h>
#include <assert.h>
+#include <signal.h>
+#include <machine/vm.h>
+
+#include <sys/sigcontext.h>
#include "archconst.h"
#include "proto.h"
#include "apic.h"
#endif
+PRIVATE int osfxsr_feature; /* FXSAVE/FXRSTOR instructions support (SSEx) */
+
+
/* set MP and NE flags to handle FPU exceptions in native mode. */
#define CR0_MP_NE 0x0022
/* set CR4.OSFXSR[bit 9] if FXSR is supported. */
}
}
+PUBLIC void save_fpu(struct proc *pr)
+{
+ if(!fpu_presence)
+ return;
+
+ /* If the process hasn't touched the FPU, there is nothing to do. */
+
+ if(!(pr->p_misc_flags & MF_USED_FPU))
+ return;
+
+ /* Save changed FPU context. */
+
+ if(osfxsr_feature) {
+ fxsave(pr->p_fpu_state.fpu_save_area_p);
+ fninit();
+ } else {
+ fnsave(pr->p_fpu_state.fpu_save_area_p);
+ }
+
+ /* Clear MF_USED_FPU to signal there is no unsaved FPU state. */
+
+ pr->p_misc_flags &= ~MF_USED_FPU;
+}
+
+PUBLIC void restore_fpu(struct proc *pr)
+{
+ /* If the process hasn't touched the FPU, enable the FPU exception
+ * and don't restore anything.
+ */
+ if(!(pr->p_misc_flags & MF_USED_FPU)) {
+ write_cr0(read_cr0() | I386_CR0_TS);
+ return;
+ }
+
+ /* If the process has touched the FPU, disable the FPU
+ * exception (both for the kernel and for the process once
+ * it's scheduled), and initialize or restore the FPU state.
+ */
+
+ clts();
+
+ if(!(pr->p_misc_flags & MF_FPU_INITIALIZED)) {
+ fninit();
+ pr->p_misc_flags |= MF_FPU_INITIALIZED;
+ } else {
+ if(osfxsr_feature) {
+ fxrstor(pr->p_fpu_state.fpu_save_area_p);
+ } else {
+ frstor(pr->p_fpu_state.fpu_save_area_p);
+ }
+ }
+}
+
PUBLIC void arch_init(void)
{
#ifdef CONFIG_APIC
*((reg_t *)stk) = (reg_t) proc_ptr;
return proc_ptr;
}
+
+PUBLIC void fpu_sigcontext(struct proc *pr, struct sigframe *fr, struct sigcontext *sc)
+{
+ int fp_error;
+
+ if (osfxsr_feature) {
+ fp_error = sc->sc_fpu_state.xfp_regs.fp_status &
+ ~sc->sc_fpu_state.xfp_regs.fp_control;
+ } else {
+ fp_error = sc->sc_fpu_state.fpu_regs.fp_status &
+ ~sc->sc_fpu_state.fpu_regs.fp_control;
+ }
+
+ if (fp_error & 0x001) { /* Invalid op */
+ /*
+ * swd & 0x240 == 0x040: Stack Underflow
+ * swd & 0x240 == 0x240: Stack Overflow
+ * User must clear the SF bit (0x40) if set
+ */
+ fr->sf_code = FPE_FLTINV;
+ } else if (fp_error & 0x004) {
+ fr->sf_code = FPE_FLTDIV; /* Divide by Zero */
+ } else if (fp_error & 0x008) {
+ fr->sf_code = FPE_FLTOVF; /* Overflow */
+ } else if (fp_error & 0x012) {
+ fr->sf_code = FPE_FLTUND; /* Denormal, Underflow */
+ } else if (fp_error & 0x020) {
+ fr->sf_code = FPE_FLTRES; /* Precision */
+ } else {
+ fr->sf_code = 0; /* XXX - probably should be used for FPE_INTOVF or
+ * FPE_INTDIV */
+ }
+}
.globl _fninit /* non-waiting FPU initialization */
.globl _fnstsw /* store status word (non-waiting) */
.globl _fnstcw /* store control word (non-waiting) */
+.globl _fxsave
+.globl _fnsave
+.globl _fxrstor
+.globl _frstor
+.globl _clts
/*
* The routines only guarantee to preserve the registers the C compiler
fninit
ret
+_clts:
+ clts
+ ret
+
_fnstsw:
xor %eax, %eax
pop %eax
ret
+/*===========================================================================*/
+/* fxsave */
+/*===========================================================================*/
+_fxsave:
+ mov 4(%esp), %eax
+ fxsave (%eax) /* Do not change the operand! (gas2ack) */
+ ret
+
+/*===========================================================================*/
+/* fnsave */
+/*===========================================================================*/
+_fnsave:
+ mov 4(%esp), %eax
+ fnsave (%eax) /* Do not change the operand! (gas2ack) */
+ fwait /* required for compatibility with processors prior pentium */
+ ret
+
+/*===========================================================================*/
+/* fxrstor */
+/*===========================================================================*/
+_fxrstor:
+ mov 4(%esp), %eax
+ fxrstor (%eax) /* Do not change the operand! (gas2ack) */
+ ret
+
+/*===========================================================================*/
+/* frstor */
+/*===========================================================================*/
+_frstor:
+ mov 4(%esp), %eax
+ frstor (%eax) /* Do not change the operand! (gas2ack) */
+ ret
+
+
/*===========================================================================*/
/* read_cr0 */
/*===========================================================================*/
mov %edx, _ptproc
0:
ret
+
.globl _params_offset
.globl _mon_ds
.globl _switch_to_user
-.globl _lazy_fpu
+.globl _save_fpu
.globl _hwint00 /* handlers for hardware interrupts */
.globl _hwint01
_copr_not_available:
TEST_INT_IN_KERNEL(4, copr_not_available_in_kernel)
- clts
- cld /* set direction flag to a known value */
+ cld /* set direction flag to a known value */
SAVE_PROCESS_CTX_NON_LAZY(0)
/* stop user process cycles */
push %ebp
+ mov $0, %ebp
call _context_stop
pop %ebp
lea P_MISC_FLAGS(%ebp), %ebx
- movw (%ebx), %cx
- and $MF_FPU_INITIALIZED, %cx
- jnz 0f /* jump if FPU is already initialized */
- orw $MF_FPU_INITIALIZED, (%ebx)
- fninit
- jmp copr_return
-0: /* load FPU context for current process */
- mov %ss:FP_SAVE_AREA_P(%ebp), %eax
- cmp $0, _osfxsr_feature
- jz fp_l_no_fxsr /* FXSR is not avaible. */
-
- /* DO NOT CHANGE THE OPERAND!!! gas2ack does not handle it yet */
- fxrstor (%eax)
- jmp copr_return
-fp_l_no_fxsr:
- /* DO NOT CHANGE THE OPERAND!!! gas2ack does not handle it yet */
- frstor (%eax)
-copr_return:
- orw $MF_USED_FPU, (%ebx) /* fpu was used during last execution */
+ orw $MF_USED_FPU, (%ebx)
+ mov $0, %ebp
jmp _switch_to_user
copr_not_available_in_kernel:
_simd_exception:
EXCEPTION_NO_ERR_CODE(SIMD_EXCEPTION_VECTOR)
-/*===========================================================================*/
-/* lazy_fpu */
-/*===========================================================================*/
-/* void lazy_fpu(struct proc *pptr)
- * It's called, when we are on kernel stack.
- * Actualy lazy code is just few lines, which check MF_USED_FPU,
- * another part is save_init_fpu().
- */
-_lazy_fpu:
- push %ebp
- mov %esp, %ebp
- push %eax
- push %ebx
- push %ecx
- cmp $0, _fpu_presence /* Do we have FPU? */
- jz no_fpu_available
- mov 8(%ebp), %eax /* Get pptr */
- lea P_MISC_FLAGS(%eax), %ebx
- movw (%ebx), %cx
- and $MF_USED_FPU, %cx
- jz 0f /* Don't save FPU */
- mov %ss:FP_SAVE_AREA_P(%eax), %eax
- cmp $0, _osfxsr_feature
- jz fp_s_no_fxsr /* FXSR is not avaible. */
-
- /* DO NOT CHANGE THE OPERAND!!! gas2ack does not handle it yet */
- fxsave (%eax)
- fninit
- jmp fp_saved
-fp_s_no_fxsr:
- /* DO NOT CHANGE THE OPERAND!!! gas2ack does not handle it yet */
- fnsave (%eax)
- fwait /* required for compatibility with processors prior pentium */
-fp_saved:
- andw $~MF_USED_FPU, (%ebx)
-0: mov %cr0, %eax
- or $0x00000008, %eax /* Set TS flag */
- mov %eax, %cr0
-no_fpu_available:
- pop %ecx
- pop %ebx
- pop %eax
- pop %ebp
- ret
-
/*===========================================================================*/
/* reload_cr3 */
/*===========================================================================*/
_PROTOTYPE( void ia32_msr_read, (u32_t reg, u32_t * hi, u32_t * lo) );
_PROTOTYPE( void ia32_msr_write, (u32_t reg, u32_t hi, u32_t lo) );
_PROTOTYPE( void fninit, (void));
+_PROTOTYPE( void clts, (void));
+_PROTOTYPE( void fxsave, (void *));
+_PROTOTYPE( void fnsave, (void *));
+_PROTOTYPE( void fxrstor, (void *));
+_PROTOTYPE( void frstor, (void *));
_PROTOTYPE( unsigned short fnstsw, (void));
_PROTOTYPE( void fnstcw, (unsigned short* cw));
SAVE_TRAP_CTX(displ, %ebp, %esi) ;
#define SAVE_PROCESS_CTX(displ) \
- SAVE_PROCESS_CTX_NON_LAZY(displ) ;\
+ SAVE_PROCESS_CTX_NON_LAZY(displ) ;\
+ push %eax ;\
+ push %ebx ;\
+ push %ecx ;\
+ push %edx ;\
push %ebp ;\
- call _lazy_fpu ;\
- add $4, %esp ;
+ call _save_fpu ;\
+ pop %ebp ;\
+ pop %edx ;\
+ pop %ecx ;\
+ pop %ebx ;\
+ pop %eax ;
/*
* clear the IF flag in eflags which are stored somewhere in memory, e.g. on
EXTERN char params_buffer[512]; /* boot monitor parameters */
EXTERN int minix_panicing;
EXTERN char fpu_presence;
-EXTERN char osfxsr_feature; /* FXSAVE/FXRSTOR instructions support (SSEx) */
EXTERN int verboseboot; /* verbose boot, init'ed in cstart */
#define MAGICTEST 0xC0FFEE23
EXTERN u32_t magictest; /* global magic number */
* restore_user_context() carries out the actual mode switch from kernel
* to userspace. This function does not return
*/
+ restore_fpu(proc_ptr);
restore_user_context(proc_ptr);
NOT_REACHABLE;
}
#define proc_is_preempted(p) ((p)->p_rts_flags & RTS_PREEMPTED)
#define proc_no_quantum(p) ((p)->p_rts_flags & RTS_NO_QUANTUM)
#define proc_ptr_ok(p) ((p)->p_magic == PMAGIC)
+#define proc_used_fpu(p) ((p)->p_misc_flags & (MF_FPU_INITIALIZED|MF_USED_FPU))
/* test whether the process is scheduled by the kernel's default policy */
#define proc_kernel_scheduler(p) ((p)->p_scheduler == NULL || \
#include <minix/safecopies.h>
#include <machine/archtypes.h>
+#include <sys/sigcontext.h>
#include <a.out.h>
/* Struct declarations. */
_PROTOTYPE( void context_stop, (struct proc * p) );
/* this is a wrapper to make calling it from assembly easier */
_PROTOTYPE( void context_stop_idle, (void) );
+_PROTOTYPE( void restore_fpu, (struct proc *) );
+_PROTOTYPE( void save_fpu, (struct proc *) );
+_PROTOTYPE( void fpu_sigcontext, (struct proc *, struct sigframe *fr, struct sigcontext *sc) );
/* main.c */
_PROTOTYPE( void main, (void) );
struct sigcontext sc, *scp;
struct sigframe fr, *frp;
int proc_nr, r;
- #if (_MINIX_CHIP == _CHIP_INTEL)
- unsigned short int fp_error;
- #endif
if (!isokendpt(m_ptr->SIG_ENDPT, &proc_nr)) return(EINVAL);
if (iskerneln(proc_nr)) return(EPERM);
rp->p_reg.fp = (reg_t) &frp->sf_fp;
fr.sf_scp = scp;
- #if (_MINIX_CHIP == _CHIP_INTEL)
- if (osfxsr_feature == 1) {
- fp_error = sc.sc_fpu_state.xfp_regs.fp_status &
- ~sc.sc_fpu_state.xfp_regs.fp_control;
- } else {
- fp_error = sc.sc_fpu_state.fpu_regs.fp_status &
- ~sc.sc_fpu_state.fpu_regs.fp_control;
- }
-
- if (fp_error & 0x001) { /* Invalid op */
- /*
- * swd & 0x240 == 0x040: Stack Underflow
- * swd & 0x240 == 0x240: Stack Overflow
- * User must clear the SF bit (0x40) if set
- */
- fr.sf_code = FPE_FLTINV;
- } else if (fp_error & 0x004) {
- fr.sf_code = FPE_FLTDIV; /* Divide by Zero */
- } else if (fp_error & 0x008) {
- fr.sf_code = FPE_FLTOVF; /* Overflow */
- } else if (fp_error & 0x012) {
- fr.sf_code = FPE_FLTUND; /* Denormal, Underflow */
- } else if (fp_error & 0x020) {
- fr.sf_code = FPE_FLTRES; /* Precision */
- } else {
- fr.sf_code = 0; /* XXX - probably should be used for FPE_INTOVF or
- * FPE_INTDIV */
- }
-
-#else
- fr.sf_code = 0;
-#endif
+ fpu_sigcontext(rp, &fr, &sc);
fr.sf_signo = smsg.sm_signo;
fr.sf_retadr = (void (*)()) smsg.sm_sigreturn;