[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH gnumach v3 1/3] add xfloat thread state interface
From: |
Luca Dariz |
Subject: |
[PATCH gnumach v3 1/3] add xfloat thread state interface |
Date: |
Wed, 4 Sep 2024 22:18:04 +0200 |
* 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; make sure the new state
is set as valid, otherwise it won't be applied; add
i386_get_xstate_size() to dynamically retrieve the FPU state size.
* 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 and use the new i386_get_xstate_size()
helper.
* i386/include/mach/i386/mach_i386.defs: expose the new helper
i386_get_xstate_size().
* i386/include/mach/i386/thread_status.h: add interface definition for
I386_XFLOAT_STATE and the corresponding data structure.
---
i386/i386/fpu.c | 139 +++++++++++++++++++------
i386/i386/fpu.h | 9 +-
i386/i386/pcb.c | 37 ++++++-
i386/include/mach/i386/mach_i386.defs | 7 ++
i386/include/mach/i386/thread_status.h | 12 +++
5 files changed, 161 insertions(+), 43 deletions(-)
diff --git a/i386/i386/fpu.c b/i386/i386/fpu.c
index 316e3b41..43771e7f 100644
--- a/i386/i386/fpu.c
+++ b/i386/i386/fpu.c
@@ -250,6 +250,17 @@ init_fpu(void)
}
}
+kern_return_t
+i386_get_xstate_size(host_t host, vm_size_t *size)
+{
+ if (host == HOST_NULL)
+ return KERN_INVALID_ARGUMENT;
+
+ *size = sizeof(struct i386_xfloat_state) + fp_xsave_size;
+
+ return KERN_SUCCESS;
+}
+
/*
* Initialize FP handling.
*/
@@ -385,10 +396,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 +422,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 +441,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);
@@ -454,10 +460,43 @@ ASSERT_IPL(SPL0);
* Ensure that reserved parts of the environment are 0.
*/
memset(ifps, 0, fp_xsave_size);
+ ifps->fp_valid = TRUE;
- 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) && (xfstate->fp_save_kind
== fp_save_kind)) {
+ 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 +506,17 @@ 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]));
+
+ memcpy(&ifps->xfp_save_state.header, &user_fp_state->header,
+ sizeof(ifps->xfp_save_state.header));
+ if (fp_xsave_size > sizeof(struct i386_xfp_save)) {
+ memcpy(&ifps->xfp_save_state.extended,
&user_fp_state->extended,
+ fp_xsave_size - sizeof(struct i386_xfp_save));
+ }
+
}
simple_unlock(&pcb->lock);
@@ -495,10 +534,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 +552,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, fp_xsave_size);
return KERN_SUCCESS;
}
@@ -529,18 +572,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 +613,37 @@ 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;
+ xfstate->fp_save_kind = fp_save_kind;
+
+ 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]));
+
+ memcpy(&user_fp_state->header, &ifps->xfp_save_state.header,
+ sizeof(ifps->xfp_save_state.header));
+ if (fp_xsave_size > sizeof(struct i386_xfp_save)) {
+ memcpy(&user_fp_state->extended,
&ifps->xfp_save_state.extended,
+ fp_xsave_size - sizeof(struct i386_xfp_save));
+ }
}
simple_unlock(&pcb->lock);
diff --git a/i386/i386/fpu.h b/i386/i386/fpu.h
index 51e0f31d..83a8f2d6 100644
--- a/i386/i386/fpu.h
+++ b/i386/i386/fpu.h
@@ -35,6 +35,7 @@
#include <sys/types.h>
#include <i386/proc_reg.h>
#include <kern/thread.h>
+#include "i386/i386/mach_i386.server.h"
/*
* FPU instructions.
@@ -233,12 +234,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..5ca6f124 100644
--- a/i386/i386/pcb.c
+++ b/i386/i386/pcb.c
@@ -613,8 +613,22 @@ 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: {
+
+ vm_size_t xfp_size;
+ kern_return_t kr;
+ kr = i386_get_xstate_size(&realhost, &xfp_size);
+ if (kr != KERN_SUCCESS)
+ return kr;
+
+ xfp_size /= sizeof(integer_t);
+ if (count < xfp_size)
+ return(KERN_INVALID_ARGUMENT);
+
+ return fpu_set_state(thread, tstate, flavor);
}
/*
@@ -831,8 +845,23 @@ 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: {
+
+ vm_size_t xfp_size;
+ kern_return_t kr;
+ kr = i386_get_xstate_size(&realhost, &xfp_size);
+ if (kr != KERN_SUCCESS)
+ return kr;
+
+ xfp_size /= sizeof(integer_t);
+ if (*count < xfp_size)
+ return(KERN_INVALID_ARGUMENT);
+
+ *count = xfp_size;
+ return fpu_get_state(thread, tstate, flavor);
}
/*
diff --git a/i386/include/mach/i386/mach_i386.defs
b/i386/include/mach/i386/mach_i386.defs
index 965d5c3b..78bbc2ed 100644
--- a/i386/include/mach/i386/mach_i386.defs
+++ b/i386/include/mach/i386/mach_i386.defs
@@ -111,3 +111,10 @@ routine i386_get_gdt(
target_thread : thread_t;
selector : int;
out desc : descriptor_t);
+
+/* Returns the size in bytes of the FPU extended state, to be used
+ with i386_XFLOAT_STATE instead of i386_XFLOAT_STATE_COUNT.
+ */
+routine i386_get_xstate_size(
+ host : host_t;
+ out size : vm_size_t);
diff --git a/i386/include/mach/i386/thread_status.h
b/i386/include/mach/i386/thread_status.h
index 94596a74..2f472247 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))
+struct i386_xfloat_state {
+ int fpkind; /* FP_NO..FP_387X (readonly) */
+ int initialized;
+ int exc_status; /* exception status (readonly)
*/
+ int fp_save_kind; /* format of hardware state */
+ unsigned char hw_state[]; /* actual "hardware" state */
+ /* don't add anything here, as hw_state is dynamically sized */
+};
+/* NOTE: i386_XFLOAT_STATE_COUNT is not defined as i386_xfloat_state is
+ * dynamically sized. Use i386_get_xstate_size(host) to get the current
+ * size. */
#define PORT_MAP_BITS 0x400
struct i386_isa_port_map_state {
--
2.39.2
- [PATCH gnumach v3 1/3] add xfloat thread state interface,
Luca Dariz <=