bug-hurd
[Top][All Lists]
Advanced

[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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]