use linker to align fpu state save area

This commit is contained in:
Ben Gras 2012-04-19 15:06:47 +02:00
parent 093c949274
commit a149be43fc
11 changed files with 45 additions and 81 deletions

View file

@ -26,19 +26,10 @@ typedef struct segframe {
reg_t p_ldt_sel; /* selector in gdt with ldt base and limit */ reg_t p_ldt_sel; /* selector in gdt with ldt base and limit */
reg_t p_cr3; /* page table root */ reg_t p_cr3; /* page table root */
u32_t *p_cr3_v; u32_t *p_cr3_v;
char *fpu_state;
struct segdesc_s p_ldt[LDT_SIZE]; /* CS, DS and remote */ struct segdesc_s p_ldt[LDT_SIZE]; /* CS, DS and remote */
} segframe_t; } segframe_t;
/* fpu_state_s is used in kernel proc table.
* Any changes in this structure requires changes in sconst.h,
* since this structure is used in proc structure. */
struct fpu_state_s {
union fpu_state_u *fpu_save_area_p; /* 16-aligned fpu_save_area */
/* fpu_image includes 512 bytes of image itself and
* additional 15 bytes required for manual 16-byte alignment. */
char fpu_image[527];
};
#define INMEMORY(p) (!p->p_seg.p_cr3 || get_cpulocal_var(ptproc) == p) #define INMEMORY(p) (!p->p_seg.p_cr3 || get_cpulocal_var(ptproc) == p)
typedef u32_t atomic_t; /* access to an aligned 32bit value is atomic on i386 */ typedef u32_t atomic_t; /* access to an aligned 32bit value is atomic on i386 */

View file

@ -275,6 +275,8 @@ void fpu_init(void)
void save_local_fpu(struct proc *pr, int retain) void save_local_fpu(struct proc *pr, int retain)
{ {
char *state = pr->p_seg.fpu_state;
/* Save process FPU context. If the 'retain' flag is set, keep the FPU /* Save process FPU context. If the 'retain' flag is set, keep the FPU
* state as is. If the flag is not set, the state is undefined upon * state as is. If the flag is not set, the state is undefined upon
* return, and the caller is responsible for reloading a proper state. * return, and the caller is responsible for reloading a proper state.
@ -283,12 +285,14 @@ void save_local_fpu(struct proc *pr, int retain)
if(!is_fpu()) if(!is_fpu())
return; return;
assert(state);
if(osfxsr_feature) { if(osfxsr_feature) {
fxsave(pr->p_fpu_state.fpu_save_area_p); fxsave(state);
} else { } else {
fnsave(pr->p_fpu_state.fpu_save_area_p); fnsave(state);
if (retain) if (retain)
(void) frstor(pr->p_fpu_state.fpu_save_area_p); (void) frstor(state);
} }
} }
@ -322,18 +326,41 @@ void save_fpu(struct proc *pr)
} }
} }
/* reserve a chunk of memory for fpu state; every one has to
* be FPUALIGN-aligned.
*/
static char fpu_state[NR_PROCS][FPU_XFP_SIZE] __aligned(FPUALIGN);
void arch_proc_init(int nr, struct proc *pr)
{
if(nr < 0) return;
char *v;
assert(nr < NR_PROCS);
v = fpu_state[nr];
/* verify alignment */
assert(!((vir_bytes)v % FPUALIGN));
pr->p_seg.fpu_state = v;
}
int restore_fpu(struct proc *pr) int restore_fpu(struct proc *pr)
{ {
int failed; int failed;
char *state = pr->p_seg.fpu_state;
assert(state);
if(!proc_used_fpu(pr)) { if(!proc_used_fpu(pr)) {
fninit(); fninit();
pr->p_misc_flags |= MF_FPU_INITIALIZED; pr->p_misc_flags |= MF_FPU_INITIALIZED;
} else { } else {
if(osfxsr_feature) { if(osfxsr_feature) {
failed = fxrstor(pr->p_fpu_state.fpu_save_area_p); failed = fxrstor(state);
} else { } else {
failed = frstor(pr->p_fpu_state.fpu_save_area_p); failed = frstor(state);
} }
if (failed) return EINVAL; if (failed) return EINVAL;

View file

@ -21,7 +21,6 @@ member CSREG p_reg.cs
member PSWREG p_reg.psw member PSWREG p_reg.psw
member SPREG p_reg.sp member SPREG p_reg.sp
member SSREG p_reg.ss member SSREG p_reg.ss
member FP_SAVE_AREA_P p_fpu_state
member P_LDT_SEL p_seg.p_ldt_sel member P_LDT_SEL p_seg.p_ldt_sel
member P_CR3 p_seg.p_cr3 member P_CR3 p_seg.p_cr3
member P_CR3_V p_seg.p_cr3_v member P_CR3_V p_seg.p_cr3_v

View file

@ -136,6 +136,9 @@ void proc_init(void)
rp->p_scheduler = NULL; /* no user space scheduler */ rp->p_scheduler = NULL; /* no user space scheduler */
rp->p_priority = 0; /* no priority */ rp->p_priority = 0; /* no priority */
rp->p_quantum_size_ms = 0; /* no quantum size */ rp->p_quantum_size_ms = 0; /* no quantum size */
/* arch-specific initialization */
arch_proc_init(i, rp);
} }
for (sp = BEG_PRIV_ADDR, i = 0; sp < END_PRIV_ADDR; ++sp, ++i) { for (sp = BEG_PRIV_ADDR, i = 0; sp < END_PRIV_ADDR; ++sp, ++i) {
sp->s_proc_nr = NONE; /* initialize as free */ sp->s_proc_nr = NONE; /* initialize as free */
@ -155,25 +158,6 @@ void proc_init(void)
ip->p_rts_flags |= RTS_PROC_STOP; ip->p_rts_flags |= RTS_PROC_STOP;
set_idle_name(ip->p_name, i); set_idle_name(ip->p_name, i);
} }
#if (_MINIX_CHIP == _CHIP_INTEL)
for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; ++rp) {
/*
* FXSR requires 16-byte alignment of memory image, but
* unfortunately a.out does not preserve the alignment while
* linking. Thus we have to do manual alignment.
*/
phys_bytes aligned_fp_area;
aligned_fp_area =
(phys_bytes) &rp->p_fpu_state.fpu_image;
if(aligned_fp_area % FPUALIGN) {
aligned_fp_area += FPUALIGN -
(aligned_fp_area % FPUALIGN);
}
rp->p_fpu_state.fpu_save_area_p =
(void *) aligned_fp_area;
}
#endif
} }
static void switch_address_space_idle(void) static void switch_address_space_idle(void)

View file

@ -21,7 +21,6 @@
struct proc { struct proc {
struct stackframe_s p_reg; /* process' registers saved in stack frame */ struct stackframe_s p_reg; /* process' registers saved in stack frame */
struct fpu_state_s p_fpu_state; /* process' fpu_regs saved lazily */
struct segframe p_seg; /* segment descriptors */ struct segframe p_seg; /* segment descriptors */
proc_nr_t p_nr; /* number of this process (for fast access) */ proc_nr_t p_nr; /* number of this process (for fast access) */
struct priv *p_priv; /* system privileges structure */ struct priv *p_priv; /* system privileges structure */

View file

@ -55,6 +55,7 @@ int mini_notify(const struct proc *src, endpoint_t dst);
void enqueue(struct proc *rp); void enqueue(struct proc *rp);
void dequeue(struct proc *rp); void dequeue(struct proc *rp);
void switch_to_user(void); void switch_to_user(void);
void arch_proc_init(int nr, struct proc *rp);
struct proc * arch_finish_switch_to_user(void); struct proc * arch_finish_switch_to_user(void);
struct proc *endpoint_lookup(endpoint_t ep); struct proc *endpoint_lookup(endpoint_t ep);
#if DEBUG_ENABLE_IPC_WARNINGS #if DEBUG_ENABLE_IPC_WARNINGS

View file

@ -27,7 +27,7 @@ int do_fork(struct proc * caller, message * m_ptr)
/* Handle sys_fork(). PR_ENDPT has forked. The child is PR_SLOT. */ /* Handle sys_fork(). PR_ENDPT has forked. The child is PR_SLOT. */
#if (_MINIX_CHIP == _CHIP_INTEL) #if (_MINIX_CHIP == _CHIP_INTEL)
reg_t old_ldt_sel; reg_t old_ldt_sel;
void *old_fpu_save_area_p; char *old_fpu_save_area_p;
#endif #endif
register struct proc *rpc; /* child process pointer */ register struct proc *rpc; /* child process pointer */
struct proc *rpp; /* parent process pointer */ struct proc *rpp; /* parent process pointer */
@ -59,16 +59,14 @@ int do_fork(struct proc * caller, message * m_ptr)
gen = _ENDPOINT_G(rpc->p_endpoint); gen = _ENDPOINT_G(rpc->p_endpoint);
#if (_MINIX_CHIP == _CHIP_INTEL) #if (_MINIX_CHIP == _CHIP_INTEL)
old_ldt_sel = rpc->p_seg.p_ldt_sel; /* backup local descriptors */ old_ldt_sel = rpc->p_seg.p_ldt_sel; /* backup local descriptors */
old_fpu_save_area_p = rpc->p_fpu_state.fpu_save_area_p; old_fpu_save_area_p = rpc->p_seg.fpu_state;
#endif #endif
*rpc = *rpp; /* copy 'proc' struct */ *rpc = *rpp; /* copy 'proc' struct */
#if (_MINIX_CHIP == _CHIP_INTEL) #if (_MINIX_CHIP == _CHIP_INTEL)
rpc->p_seg.p_ldt_sel = old_ldt_sel; /* restore descriptors */ rpc->p_seg.p_ldt_sel = old_ldt_sel; /* restore descriptors */
rpc->p_fpu_state.fpu_save_area_p = old_fpu_save_area_p; rpc->p_seg.fpu_state = old_fpu_save_area_p;
if(proc_used_fpu(rpp)) if(proc_used_fpu(rpp))
memcpy(rpc->p_fpu_state.fpu_save_area_p, memcpy(rpc->p_seg.fpu_state, rpp->p_seg.fpu_state, FPU_XFP_SIZE);
rpp->p_fpu_state.fpu_save_area_p,
FPU_XFP_SIZE);
#endif #endif
if(++gen >= _ENDPOINT_MAX_GENERATION) /* increase generation */ if(++gen >= _ENDPOINT_MAX_GENERATION) /* increase generation */
gen = 1; /* generation number wraparound */ gen = 1; /* generation number wraparound */

View file

@ -45,8 +45,7 @@ int do_getmcontext(struct proc * caller, message * m_ptr)
/* make sure that the FPU context is saved into proc structure first */ /* make sure that the FPU context is saved into proc structure first */
save_fpu(rp); save_fpu(rp);
mc.mc_fpu_flags = rp->p_misc_flags & MF_FPU_INITIALIZED; mc.mc_fpu_flags = rp->p_misc_flags & MF_FPU_INITIALIZED;
memcpy(&(mc.mc_fpu_state), rp->p_fpu_state.fpu_save_area_p, memcpy(&(mc.mc_fpu_state), rp->p_seg.fpu_state, FPU_XFP_SIZE);
FPU_XFP_SIZE);
} }
#endif #endif
@ -84,8 +83,7 @@ int do_setmcontext(struct proc * caller, message * m_ptr)
/* Copy FPU state */ /* Copy FPU state */
if (mc.mc_fpu_flags & MF_FPU_INITIALIZED) { if (mc.mc_fpu_flags & MF_FPU_INITIALIZED) {
rp->p_misc_flags |= MF_FPU_INITIALIZED; rp->p_misc_flags |= MF_FPU_INITIALIZED;
memcpy(rp->p_fpu_state.fpu_save_area_p, &(mc.mc_fpu_state), memcpy(rp->p_seg.fpu_state, &(mc.mc_fpu_state), FPU_XFP_SIZE);
FPU_XFP_SIZE);
} else } else
rp->p_misc_flags &= ~MF_FPU_INITIALIZED; rp->p_misc_flags &= ~MF_FPU_INITIALIZED;
/* force reloading FPU in either case */ /* force reloading FPU in either case */

View file

@ -55,8 +55,7 @@ int do_sigreturn(struct proc * caller, message * m_ptr)
#if (_MINIX_CHIP == _CHIP_INTEL) #if (_MINIX_CHIP == _CHIP_INTEL)
if(sc.sc_flags & MF_FPU_INITIALIZED) if(sc.sc_flags & MF_FPU_INITIALIZED)
{ {
memcpy(rp->p_fpu_state.fpu_save_area_p, &sc.sc_fpu_state, memcpy(rp->p_seg.fpu_state, &sc.sc_fpu_state, FPU_XFP_SIZE);
FPU_XFP_SIZE);
rp->p_misc_flags |= MF_FPU_INITIALIZED; /* Restore math usage flag. */ rp->p_misc_flags |= MF_FPU_INITIALIZED; /* Restore math usage flag. */
/* force reloading FPU */ /* force reloading FPU */
release_fpu(rp); release_fpu(rp);

View file

@ -46,8 +46,7 @@ int do_sigsend(struct proc * caller, message * m_ptr)
if(proc_used_fpu(rp)) { if(proc_used_fpu(rp)) {
/* save the FPU context before saving it to the sig context */ /* save the FPU context before saving it to the sig context */
save_fpu(rp); save_fpu(rp);
memcpy(&sc.sc_fpu_state, rp->p_fpu_state.fpu_save_area_p, memcpy(&sc.sc_fpu_state, rp->p_seg.fpu_state, FPU_XFP_SIZE);
FPU_XFP_SIZE);
} }
#endif #endif

View file

@ -22,8 +22,6 @@
static void adjust_proc_slot(struct proc *rp, struct proc *from_rp); static void adjust_proc_slot(struct proc *rp, struct proc *from_rp);
static void adjust_priv_slot(struct priv *privp, struct priv static void adjust_priv_slot(struct priv *privp, struct priv
*from_privp); *from_privp);
static void swap_fpu_state(struct proc *a_rp, struct proc *b_orig_rp,
struct proc *b_copy_rp);
static void swap_proc_slot_pointer(struct proc **rpp, struct proc static void swap_proc_slot_pointer(struct proc **rpp, struct proc
*src_rp, struct proc *dst_rp); *src_rp, struct proc *dst_rp);
@ -110,10 +108,6 @@ int do_update(struct proc * caller, message * m_ptr)
adjust_priv_slot(priv(src_rp), &orig_src_priv); adjust_priv_slot(priv(src_rp), &orig_src_priv);
adjust_priv_slot(priv(dst_rp), &orig_dst_priv); adjust_priv_slot(priv(dst_rp), &orig_dst_priv);
/* Swap FPU state. Can only be done after adjusting the process slots. */
swap_fpu_state(src_rp, dst_rp, &orig_dst_proc);
swap_fpu_state(dst_rp, src_rp, &orig_src_proc);
/* Swap global process slot addresses. */ /* Swap global process slot addresses. */
swap_proc_slot_pointer(get_cpulocal_var_ptr(ptproc), src_rp, dst_rp); swap_proc_slot_pointer(get_cpulocal_var_ptr(ptproc), src_rp, dst_rp);
@ -152,11 +146,6 @@ static void adjust_proc_slot(struct proc *rp, struct proc *from_rp)
priv(rp)->s_proc_nr = from_rp->p_nr; priv(rp)->s_proc_nr = from_rp->p_nr;
rp->p_caller_q = from_rp->p_caller_q; rp->p_caller_q = from_rp->p_caller_q;
#if (_MINIX_CHIP == _CHIP_INTEL)
/* Preserve FPU pointer. */
rp->p_fpu_state.fpu_save_area_p = from_rp->p_fpu_state.fpu_save_area_p;
#endif
/* preserve scheduling */ /* preserve scheduling */
rp->p_scheduler = from_rp->p_scheduler; rp->p_scheduler = from_rp->p_scheduler;
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
@ -179,26 +168,6 @@ static void adjust_priv_slot(struct priv *privp, struct priv *from_privp)
privp->s_alarm_timer = from_privp->s_alarm_timer; privp->s_alarm_timer = from_privp->s_alarm_timer;
} }
/*===========================================================================*
* swap_fpu_state *
*===========================================================================*/
static void swap_fpu_state(struct proc *a_rp, struct proc *b_orig_rp,
struct proc *b_copy_rp)
{
/* Copy the FPU state from process B's copied slot, using B's original FPU
* save area alignment, into process A's slot.
*/
#if (_MINIX_CHIP == _CHIP_INTEL)
int align;
align = (int) ((char *) b_orig_rp->p_fpu_state.fpu_save_area_p -
(char *) &b_orig_rp->p_fpu_state.fpu_image);
memcpy(a_rp->p_fpu_state.fpu_save_area_p,
b_copy_rp->p_fpu_state.fpu_image + align, FPU_XFP_SIZE);
#endif
}
/*===========================================================================* /*===========================================================================*
* swap_proc_slot_pointer * * swap_proc_slot_pointer *
*===========================================================================*/ *===========================================================================*/