* i386/i386/fpu.c: extend current getter and setter to support the extended state; move the struct casting here to reuse the locking and allocation logic for the thread state. * i386/i386/fpu.h: update prototypes to accept generic thread state * i386/i386/pcb.c: forward raw thread state to getter and setter, only checking for minimum size. * i386/include/mach/i386/thread_status.h: add interface definition for I386_XFLOAT_STATE and the corresponding data structure. --- i386/i386/fpu.c | 115 ++++++++++++++++++------- i386/i386/fpu.h | 8 +- i386/i386/pcb.c | 23 ++++- i386/include/mach/i386/thread_status.h | 12 +++ 4 files changed, 115 insertions(+), 43 deletions(-)
diff --git a/i386/i386/fpu.c b/i386/i386/fpu.c index 316e3b41..4f783293 100644 --- a/i386/i386/fpu.c +++ b/i386/i386/fpu.c @@ -385,10 +385,11 @@ twd_fxsr_to_i387 (struct i386_xfp_save *fxsave) * concurrent fpu_set_state or fpu_get_state. */ kern_return_t -fpu_set_state(const thread_t thread, - struct i386_float_state *state) +fpu_set_state(const thread_t thread, void *state, int flavor) { pcb_t pcb = thread->pcb; + struct i386_float_state *fstate = (struct i386_float_state*)state; + struct i386_xfloat_state *xfstate = (struct i386_xfloat_state*)state; struct i386_fpsave_state *ifps; struct i386_fpsave_state *new_ifps; @@ -410,7 +411,8 @@ ASSERT_IPL(SPL0); } #endif - if (state->initialized == 0) { + if ((flavor == i386_FLOAT_STATE && fstate->initialized == 0) || + (flavor == i386_XFLOAT_STATE && xfstate->initialized == 0)) { /* * new FPU state is 'invalid'. * Deallocate the fp state if it exists. @@ -428,13 +430,6 @@ ASSERT_IPL(SPL0); /* * Valid state. Allocate the fp state if there is none. */ - struct i386_fp_save *user_fp_state; - struct i386_fp_regs *user_fp_regs; - - user_fp_state = (struct i386_fp_save *) &state->hw_state[0]; - user_fp_regs = (struct i386_fp_regs *) - &state->hw_state[sizeof(struct i386_fp_save)]; - new_ifps = 0; Retry: simple_lock(&pcb->lock); @@ -455,9 +450,41 @@ ASSERT_IPL(SPL0); */ memset(ifps, 0, fp_xsave_size); - if (fp_save_kind != FP_FNSAVE) { - int i; + if (flavor == i386_FLOAT_STATE) { + struct i386_fp_save *user_fp_state; + struct i386_fp_regs *user_fp_regs; + + user_fp_state = (struct i386_fp_save *) &fstate->hw_state[0]; + user_fp_regs = (struct i386_fp_regs *) + &fstate->hw_state[sizeof(struct i386_fp_save)]; + if (fp_save_kind != FP_FNSAVE) { + int i; + + ifps->xfp_save_state.fp_control = user_fp_state->fp_control; + ifps->xfp_save_state.fp_status = user_fp_state->fp_status; + ifps->xfp_save_state.fp_tag = twd_i387_to_fxsr(user_fp_state->fp_tag); + ifps->xfp_save_state.fp_eip = user_fp_state->fp_eip; + ifps->xfp_save_state.fp_cs = user_fp_state->fp_cs; + ifps->xfp_save_state.fp_opcode = user_fp_state->fp_opcode; + ifps->xfp_save_state.fp_dp = user_fp_state->fp_dp; + ifps->xfp_save_state.fp_ds = user_fp_state->fp_ds; + for (i=0; i<8; i++) + memcpy(&ifps->xfp_save_state.fp_reg_word[i], &user_fp_regs->fp_reg_word[i], sizeof(user_fp_regs->fp_reg_word[i])); + } else { + ifps->fp_save_state.fp_control = user_fp_state->fp_control; + ifps->fp_save_state.fp_status = user_fp_state->fp_status; + ifps->fp_save_state.fp_tag = user_fp_state->fp_tag; + ifps->fp_save_state.fp_eip = user_fp_state->fp_eip; + ifps->fp_save_state.fp_cs = user_fp_state->fp_cs; + ifps->fp_save_state.fp_opcode = user_fp_state->fp_opcode; + ifps->fp_save_state.fp_dp = user_fp_state->fp_dp; + ifps->fp_save_state.fp_ds = user_fp_state->fp_ds; + ifps->fp_regs = *user_fp_regs; + } + } else if (flavor == i386_XFLOAT_STATE) { + int i; + struct i386_xfp_save *user_fp_state = (struct i386_xfp_save *) &xfstate->hw_state[0]; ifps->xfp_save_state.fp_control = user_fp_state->fp_control; ifps->xfp_save_state.fp_status = user_fp_state->fp_status; ifps->xfp_save_state.fp_tag = twd_i387_to_fxsr(user_fp_state->fp_tag); @@ -467,17 +494,11 @@ ASSERT_IPL(SPL0); ifps->xfp_save_state.fp_dp = user_fp_state->fp_dp; ifps->xfp_save_state.fp_ds = user_fp_state->fp_ds; for (i=0; i<8; i++) - memcpy(&ifps->xfp_save_state.fp_reg_word[i], &user_fp_regs->fp_reg_word[i], sizeof(user_fp_regs->fp_reg_word[i])); - } else { - ifps->fp_save_state.fp_control = user_fp_state->fp_control; - ifps->fp_save_state.fp_status = user_fp_state->fp_status; - ifps->fp_save_state.fp_tag = user_fp_state->fp_tag; - ifps->fp_save_state.fp_eip = user_fp_state->fp_eip; - ifps->fp_save_state.fp_cs = user_fp_state->fp_cs; - ifps->fp_save_state.fp_opcode = user_fp_state->fp_opcode; - ifps->fp_save_state.fp_dp = user_fp_state->fp_dp; - ifps->fp_save_state.fp_ds = user_fp_state->fp_ds; - ifps->fp_regs = *user_fp_regs; + memcpy(&ifps->xfp_save_state.fp_reg_word[i], &user_fp_state->fp_reg_word[i], sizeof(user_fp_state->fp_reg_word[i])); + for (i=0; i<16; i++) + memcpy(&ifps->xfp_save_state.fp_xreg_word[i], &user_fp_state->fp_xreg_word[i], sizeof(user_fp_state->fp_xreg_word[i])); + + /* TODO: handle header and extended state */ } simple_unlock(&pcb->lock); @@ -495,10 +516,11 @@ ASSERT_IPL(SPL0); * concurrent fpu_set_state or fpu_get_state. */ kern_return_t -fpu_get_state(const thread_t thread, - struct i386_float_state *state) +fpu_get_state(const thread_t thread, void *state, int flavor) { pcb_t pcb = thread->pcb; + struct i386_float_state *fstate = (struct i386_float_state*)state; + struct i386_xfloat_state *xfstate = (struct i386_xfloat_state*)state; struct i386_fpsave_state *ifps; ASSERT_IPL(SPL0); @@ -512,7 +534,10 @@ ASSERT_IPL(SPL0); * No valid floating-point state. */ simple_unlock(&pcb->lock); - memset(state, 0, sizeof(struct i386_float_state)); + if (flavor == i386_FLOAT_STATE) + memset(state, 0, sizeof(struct i386_float_state)); + else if (flavor == i386_XFLOAT_STATE) + memset(state, 0, sizeof(struct i386_xfloat_state)); return KERN_SUCCESS; } @@ -529,18 +554,17 @@ ASSERT_IPL(SPL0); clear_fpu(); } - state->fpkind = fp_kind; - state->exc_status = 0; - - { + if (flavor == i386_FLOAT_STATE) { struct i386_fp_save *user_fp_state; struct i386_fp_regs *user_fp_regs; - state->initialized = ifps->fp_valid; + fstate->fpkind = fp_kind; + fstate->exc_status = 0; + fstate->initialized = ifps->fp_valid; - user_fp_state = (struct i386_fp_save *) &state->hw_state[0]; + user_fp_state = (struct i386_fp_save *) &fstate->hw_state[0]; user_fp_regs = (struct i386_fp_regs *) - &state->hw_state[sizeof(struct i386_fp_save)]; + &fstate->hw_state[sizeof(struct i386_fp_save)]; /* * Ensure that reserved parts of the environment are 0. @@ -571,6 +595,31 @@ ASSERT_IPL(SPL0); user_fp_state->fp_ds = ifps->fp_save_state.fp_ds; *user_fp_regs = ifps->fp_regs; } + } else if (flavor == i386_XFLOAT_STATE) { + int i; + struct i386_xfp_save *user_fp_state; + + xfstate->fpkind = fp_kind; + xfstate->exc_status = 0; + xfstate->initialized = ifps->fp_valid; + + user_fp_state = (struct i386_xfp_save *) &xfstate->hw_state[0]; + memset(user_fp_state, 0, sizeof(struct i386_xfp_save)); + + user_fp_state->fp_control = ifps->xfp_save_state.fp_control; + user_fp_state->fp_status = ifps->xfp_save_state.fp_status; + user_fp_state->fp_tag = twd_fxsr_to_i387(&ifps->xfp_save_state); + user_fp_state->fp_eip = ifps->xfp_save_state.fp_eip; + user_fp_state->fp_cs = ifps->xfp_save_state.fp_cs; + user_fp_state->fp_opcode = ifps->xfp_save_state.fp_opcode; + user_fp_state->fp_dp = ifps->xfp_save_state.fp_dp; + user_fp_state->fp_ds = ifps->xfp_save_state.fp_ds; + for (i=0; i<8; i++) + memcpy(&user_fp_state->fp_reg_word[i], &ifps->xfp_save_state.fp_reg_word[i], sizeof(user_fp_state->fp_reg_word[i])); + for (i=0; i<16; i++) + memcpy(&user_fp_state->fp_xreg_word[i], &ifps->xfp_save_state.fp_xreg_word[i], sizeof(user_fp_state->fp_xreg_word[i])); + + /* TODO: handle header and extended state */ } simple_unlock(&pcb->lock); diff --git a/i386/i386/fpu.h b/i386/i386/fpu.h index 51e0f31d..527d6a99 100644 --- a/i386/i386/fpu.h +++ b/i386/i386/fpu.h @@ -233,12 +233,8 @@ extern void fp_save(thread_t thread); extern void fp_load(thread_t thread); extern void fp_free(struct i386_fpsave_state *fps); extern void fpu_module_init(void); -extern kern_return_t fpu_set_state( - thread_t thread, - struct i386_float_state *state); -extern kern_return_t fpu_get_state( - thread_t thread, - struct i386_float_state *state); +extern kern_return_t fpu_set_state(thread_t thread, void *state, int flavor); +extern kern_return_t fpu_get_state(thread_t thread, void *state, int flavor); extern void fpnoextflt(void); extern void fpextovrflt(void); extern void fpexterrflt(void); diff --git a/i386/i386/pcb.c b/i386/i386/pcb.c index e8901550..e0358fb7 100644 --- a/i386/i386/pcb.c +++ b/i386/i386/pcb.c @@ -613,8 +613,15 @@ kern_return_t thread_setstatus( if (count < i386_FLOAT_STATE_COUNT) return(KERN_INVALID_ARGUMENT); - return fpu_set_state(thread, - (struct i386_float_state *) tstate); + return fpu_set_state(thread, tstate, flavor); + } + + case i386_XFLOAT_STATE: { + + if (count < i386_XFLOAT_STATE_COUNT) + return(KERN_INVALID_ARGUMENT); + + return fpu_set_state(thread, tstate, flavor); } /* @@ -831,8 +838,16 @@ kern_return_t thread_getstatus( return(KERN_INVALID_ARGUMENT); *count = i386_FLOAT_STATE_COUNT; - return fpu_get_state(thread, - (struct i386_float_state *)tstate); + return fpu_get_state(thread, tstate, flavor); + } + + case i386_XFLOAT_STATE: { + + if (*count < i386_XFLOAT_STATE_COUNT) + return(KERN_INVALID_ARGUMENT); + + *count = i386_XFLOAT_STATE_COUNT; + return fpu_get_state(thread, tstate, flavor); } /* diff --git a/i386/include/mach/i386/thread_status.h b/i386/include/mach/i386/thread_status.h index 94596a74..39c0acfa 100644 --- a/i386/include/mach/i386/thread_status.h +++ b/i386/include/mach/i386/thread_status.h @@ -58,6 +58,7 @@ #define i386_REGS_SEGS_STATE 5 #define i386_DEBUG_STATE 6 #define i386_FSGS_BASE_STATE 7 +#define i386_XFLOAT_STATE 8 /* * This structure is used for both @@ -148,6 +149,17 @@ struct i386_float_state { }; #define i386_FLOAT_STATE_COUNT (sizeof(struct i386_float_state)/sizeof(unsigned int)) +#define XFP_STATE_BYTES (sizeof (struct i386_xfp_save)) + +struct i386_xfloat_state { + int fpkind; /* FP_NO..FP_387X (readonly) */ + int initialized; + int exc_status; /* exception status (readonly) */ + unsigned char hw_state[XFP_STATE_BYTES]; /* actual "hardware" state */ + /* don't add anything here, the last field of i386_xfp_save is + * dynamically sized */ +}; +#define i386_XFLOAT_STATE_COUNT (sizeof(struct i386_xfloat_state)/sizeof(unsigned int)) #define PORT_MAP_BITS 0x400 struct i386_isa_port_map_state { -- 2.39.2