3.1.7 branch.
This commit is contained in:
parent
332842295a
commit
e9eb2c4f8b
@ -11,6 +11,10 @@
|
||||
#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"
|
||||
@ -23,6 +27,9 @@
|
||||
#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. */
|
||||
@ -194,6 +201,59 @@ PRIVATE void fpu_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
@ -438,3 +498,36 @@ PUBLIC struct proc * arch_finish_switch_to_user(void)
|
||||
*((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 */
|
||||
}
|
||||
}
|
||||
|
@ -50,6 +50,11 @@
|
||||
.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
|
||||
@ -655,6 +660,10 @@ _fninit:
|
||||
fninit
|
||||
ret
|
||||
|
||||
_clts:
|
||||
clts
|
||||
ret
|
||||
|
||||
_fnstsw:
|
||||
xor %eax, %eax
|
||||
|
||||
@ -671,6 +680,40 @@ _fnstcw:
|
||||
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 */
|
||||
/*===========================================================================*/
|
||||
@ -847,3 +890,4 @@ _switch_address_space:
|
||||
mov %edx, _ptproc
|
||||
0:
|
||||
ret
|
||||
|
||||
|
@ -90,7 +90,7 @@ begbss:
|
||||
.globl _params_offset
|
||||
.globl _mon_ds
|
||||
.globl _switch_to_user
|
||||
.globl _lazy_fpu
|
||||
.globl _save_fpu
|
||||
|
||||
.globl _hwint00 /* handlers for hardware interrupts */
|
||||
.globl _hwint01
|
||||
@ -589,33 +589,16 @@ _inval_opcode:
|
||||
|
||||
_copr_not_available:
|
||||
TEST_INT_IN_KERNEL(4, copr_not_available_in_kernel)
|
||||
clts
|
||||
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:
|
||||
@ -656,51 +639,6 @@ _machine_check:
|
||||
_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 */
|
||||
/*===========================================================================*/
|
||||
|
@ -86,6 +86,11 @@ _PROTOTYPE( void reload_ds, (void) );
|
||||
_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));
|
||||
|
||||
|
@ -141,9 +141,17 @@
|
||||
|
||||
#define SAVE_PROCESS_CTX(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
|
||||
|
@ -45,7 +45,6 @@ EXTERN time_t boottime;
|
||||
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 */
|
||||
|
@ -241,6 +241,7 @@ check_misc_flags:
|
||||
* 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;
|
||||
}
|
||||
|
@ -146,6 +146,7 @@ struct proc {
|
||||
#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 || \
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include <minix/safecopies.h>
|
||||
#include <machine/archtypes.h>
|
||||
#include <sys/sigcontext.h>
|
||||
#include <a.out.h>
|
||||
|
||||
/* Struct declarations. */
|
||||
@ -28,6 +29,9 @@ _PROTOTYPE( void cycles_accounting_init, (void) );
|
||||
_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) );
|
||||
|
@ -27,9 +27,6 @@ PUBLIC int do_sigsend(struct proc * caller, message * m_ptr)
|
||||
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);
|
||||
@ -69,38 +66,7 @@ PUBLIC int do_sigsend(struct proc * caller, message * m_ptr)
|
||||
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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user