bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH gnumach v3 2/3] add tests for FLOAT/XFLOAT state


From: Samuel Thibault
Subject: Re: [PATCH gnumach v3 2/3] add tests for FLOAT/XFLOAT state
Date: Sun, 8 Sep 2024 01:08:06 +0200

Applied, thanks!

Luca Dariz, le mer. 04 sept. 2024 22:18:05 +0200, a ecrit:
> ---
>  tests/include/testlib.h      |   1 +
>  tests/test-thread-state-fp.c | 240 +++++++++++++++++++++++++++++++++++
>  tests/testlib.c              |  16 +++
>  tests/user-qemu.mk           |   3 +-
>  4 files changed, 259 insertions(+), 1 deletion(-)
>  create mode 100644 tests/test-thread-state-fp.c
> 
> diff --git a/tests/include/testlib.h b/tests/include/testlib.h
> index 7c7c2b11..17a96660 100644
> --- a/tests/include/testlib.h
> +++ b/tests/include/testlib.h
> @@ -70,6 +70,7 @@ thread_t test_thread_start(task_t task, 
> void(*routine)(void*), void* arg);
>  mach_port_t host_priv(void);
>  mach_port_t device_priv(void);
>  void wait_thread_terminated(thread_t th);
> +void wait_thread_suspended(thread_t th);
>  
>  extern vm_size_t vm_page_size;
>  
> diff --git a/tests/test-thread-state-fp.c b/tests/test-thread-state-fp.c
> new file mode 100644
> index 00000000..2aab8ca9
> --- /dev/null
> +++ b/tests/test-thread-state-fp.c
> @@ -0,0 +1,240 @@
> +/*
> + * Copyright (c) 2024 Free Software Foundation.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + */
> +
> +#include <syscalls.h>
> +#include <testlib.h>
> +#include <mach/exception.h>
> +#include <mach.user.h>
> +#include <mach_port.user.h>
> +
> +#if defined(__i386__) || defined(__x86_64__)
> +#include <mach_i386.user.h>
> +
> +static void printx(struct i386_xfloat_state *state, int size)
> +{
> +  printf("xfloat init %d fp %d exc %d\n",
> +         state->initialized, state->fpkind, state->exc_status);
> +  struct i386_xfp_save *xfp = (struct i386_xfp_save *) &state->hw_state[0];
> +  printf("xfp %x %x %x %x %x %x %x %x\n",
> +         xfp->fp_control, xfp->fp_status, xfp->fp_tag, xfp->fp_eip,
> +         xfp->fp_cs, xfp->fp_opcode, xfp->fp_dp, xfp->fp_ds);
> +  for (int i=0; i<8; i++)
> +    {
> +      printf("fp%d", i);
> +      for (int j=0; j<16; j++)
> +        printf(" %02x", xfp->fp_reg_word[i][j]);
> +      printf("\n");
> +    }
> +  for (int i=0; i<16; i++)
> +    {
> +      printf("xmm%02d", i);
> +      for (int j=0; j<16; j++)
> +        printf(" %02x", xfp->fp_xreg_word[i][j]);
> +      printf("\n");
> +    }
> +  printf("header xfp_features %llx bv %llx\n",
> +         xfp->header.xfp_features, xfp->header.xcomp_bv);
> +  int rem = size - sizeof(*state) - sizeof(struct i386_xfp_save);
> +  if (rem > 0)
> +    {
> +      int iter = 0;
> +      while (rem > 0)
> +        {
> +          const int len = 16;
> +          int n;
> +          if (rem > len)
> +            n = len;
> +          else
> +            n = rem;
> +          printf("ext");
> +          for (int j=0; j<n; j++)
> +            printf(" %02x", xfp->extended[j + iter*len]);
> +          printf("\n");
> +          rem -= n;
> +          iter++;
> +        }
> +    }
> +}
> +
> +static void thread_fp_getset(void *arg)
> +{
> +  int err;
> +  thread_t th = *(thread_t*)arg;
> +
> +  wait_thread_suspended(th);
> +
> +  mach_msg_type_number_t state_count = i386_FLOAT_STATE_COUNT;
> +  struct i386_float_state state;
> +
> +  memset(&state, 0, sizeof(state));
> +  err = thread_get_state(th, i386_FLOAT_STATE,
> +                        (thread_state_t) &state, &state_count);
> +  ASSERT_RET(err, "thread_get_state get failed");
> +  ASSERT(state_count == i386_FLOAT_STATE_COUNT, "bad state_count");
> +
> +  struct i386_fp_regs *fpr =
> +      (struct i386_fp_regs *) (&state.hw_state[0] + sizeof(struct 
> i386_fp_save));
> +
> +  printf("fp regs get:\n");
> +  for (int i=0; i<8; i++)
> +  {
> +      printf("fp%d", i);
> +      for (int j=0; j<5; j++)
> +          printf(" %04x", fpr->fp_reg_word[i][j]);
> +      printf("\n");
> +  }
> +
> +  char tmp[10];
> +  memcpy(tmp, &fpr->fp_reg_word[1][0], sizeof(tmp));
> +  memcpy(&fpr->fp_reg_word[1][0], &fpr->fp_reg_word[0][0], sizeof(tmp));
> +  memcpy(&fpr->fp_reg_word[0][0], tmp, sizeof(tmp));
> +
> +  printf("fp regs set:\n");
> +  for (int i=0; i<8; i++)
> +  {
> +      printf("fp%d", i);
> +      for (int j=0; j<5; j++)
> +          printf(" %04x", fpr->fp_reg_word[i][j]);
> +      printf("\n");
> +  }
> +
> +  err = thread_set_state(th, i386_FLOAT_STATE,
> +                        (thread_state_t) &state, state_count);
> +  ASSERT_RET(err, "thread_set_state set failed");
> +
> +  err = thread_resume(th);
> +  ASSERT_RET(err, "error in thread_resume");
> +  thread_terminate(mach_thread_self());
> +  FAILURE("thread_terminate");
> +}
> +
> +static void test_fp_state_getset()
> +{
> +  int err;
> +  thread_t th = mach_thread_self();
> +
> +  /* load some known value in FP registers */
> +  int n1[1] = {1111111111};
> +  float d2[1] = {123.456};
> +  asm volatile ("fildl  %0\n"
> +                "fldl   %1\n"
> +                :: "m" (n1), "m" (d2) :);
> +
> +  /* then switch to the get/set test thread, and wait to be resumed */
> +  test_thread_start(mach_task_self(), thread_fp_getset, &th);
> +  err = thread_suspend(th);
> +  ASSERT_RET(err, "error in thread_suspend");
> +
> +  /* and check that now we have the values swapped in FP registers */
> +  int m1[1] = {0};
> +  float f2[1] = {0.0};
> +  asm volatile ("fistpl %0\n"
> +                "fstpl %1\n"
> +                :: "m" (m1), "m" (f2):);
> +  int fint, fdec;
> +  fint = (int)f2[0];
> +  fdec = (int)((f2[0] - fint) * 1000);
> +  printf("fp %d %d.%03d\n", m1[0], fint, fdec);
> +  ASSERT(n1[0] == m1[0], "error in moving int value in fp regs");
> +  ASSERT(f2[0] == d2[0], "error in moving fp value in fp regs");
> +}
> +
> +
> +static void thread_xfp_getset(void *arg)
> +{
> +  int err;
> +  thread_t th = *(thread_t*)arg;
> +
> +  wait_thread_suspended(th);
> +
> +  vm_size_t xfp_size;
> +  err = i386_get_xstate_size(host_priv(), &xfp_size);
> +  ASSERT_RET(err, "i386_get_xstate_size");
> +
> +  mach_msg_type_number_t state_count = xfp_size / sizeof(integer_t);
> +  struct i386_xfloat_state *state = __builtin_alloca(xfp_size);
> +  printf("xfp size %u min %u\n", xfp_size, sizeof(struct i386_xfloat_state));
> +
> +  memset(state, 0, xfp_size);
> +  err = thread_get_state(th, i386_XFLOAT_STATE,
> +                        (thread_state_t) state, &state_count);
> +  ASSERT_RET(err, "thread_get_state get failed");
> +  ASSERT(state_count == (xfp_size / sizeof(integer_t)), "bad state_count");
> +  printx(state, xfp_size);
> +
> +  struct i386_xfp_save *xfp = (struct i386_xfp_save *) &state->hw_state[0];
> +  printf("xmm3 (after get)");
> +  for (int j=0; j<16; j++)
> +    printf(" %02x", xfp->fp_xreg_word[3][j]);
> +  printf("\n");
> +  for (int j=0; j<16; j++)
> +    ASSERT(xfp->fp_xreg_word[3][j] == 0x33,
> +           "register xmm3 wasn't correctly retrieved from the getset 
> thread");
> +
> +  memset(xfp->fp_xreg_word[7], 0x77, 16);
> +
> +  err = thread_set_state(th, i386_XFLOAT_STATE,
> +                        (thread_state_t) state, state_count);
> +  ASSERT_RET(err, "thread_set_state set failed");
> +
> +  err = thread_resume(th);
> +  ASSERT_RET(err, "error in thread_resume");
> +  thread_terminate(mach_thread_self());
> +  FAILURE("thread_terminate");
> +}
> +
> +static void test_xfp_state_getset()
> +{
> +  int err;
> +  thread_t th = mach_thread_self();
> +
> +  /* load some known value in XMM registers */
> +  char buf3[16];
> +  memset(buf3, 0x33, 16);
> +  asm volatile ("movups (%0),%%xmm3" :: "r" (buf3) :);
> +
> +  /* then switch to the get/set test thread, and wait to be resumed */
> +  test_thread_start(mach_task_self(), thread_xfp_getset, &th);
> +  err = thread_suspend(th);
> +  ASSERT_RET(err, "error in thread_suspend");
> +
> +  /* and check that now we have different values in XMM registers */
> +  char buf7[16];
> +  memset(buf7, 0, 16);
> +  asm volatile ("movups %%xmm7,(%0)" :: "r" (buf7) :);
> +
> +  printf("xmm7 (after set)");
> +  for (int j=0; j<16; j++)
> +    printf(" %02x", buf7[j]);
> +  printf("\n");
> +  for (int j=0; j<16; j++)
> +    ASSERT(buf7[j] == 0x77,
> +           "register xmm7 wasn't correctly set by the getset thread");
> +}
> +#endif
> +
> +int main(int argc, char *argv[], int envc, char *envp[])
> +{
> +#if defined(__i386__) || defined(__x86_64__)
> +  test_fp_state_getset();
> +  test_xfp_state_getset();
> +#else
> +  FAILURE("FP/XSTATE test missing on this arch!");
> +#endif
> +  return 0;
> +}
> diff --git a/tests/testlib.c b/tests/testlib.c
> index d1ce6d86..77b34372 100644
> --- a/tests/testlib.c
> +++ b/tests/testlib.c
> @@ -224,6 +224,22 @@ void wait_thread_terminated(thread_t th)
>    } while (1);
>  }
>  
> +void wait_thread_suspended(thread_t th)
> +{
> +  int err;
> +  struct thread_basic_info info;
> +  mach_msg_type_number_t count;
> +  do {
> +    count = THREAD_BASIC_INFO_COUNT;
> +    err = thread_info(th, THREAD_BASIC_INFO, (thread_info_t)&info, &count);
> +    ASSERT_RET(err, "error in thread_info");
> +    if (info.suspend_count <= 0)
> +      msleep(100); // don't poll continuously
> +    else
> +      break;
> +  } while (1);
> +}
> +
>  /*
>   * Minimal _start() for test modules, we just take the arguments from the
>   * kernel, call main() and reboot. As in glibc, we expect the argument 
> pointer
> diff --git a/tests/user-qemu.mk b/tests/user-qemu.mk
> index a3013b59..b48f49ec 100644
> --- a/tests/user-qemu.mk
> +++ b/tests/user-qemu.mk
> @@ -210,7 +210,8 @@ USER_TESTS := \
>       tests/test-machmsg \
>       tests/test-task \
>       tests/test-threads \
> -     tests/test-thread-state
> +     tests/test-thread-state \
> +     tests/test-thread-state-fp
>  
>  USER_TESTS_CLEAN = $(subst tests/,clean-,$(USER_TESTS))
>  
> -- 
> 2.39.2
> 
> 

-- 
Samuel
<D> m'enfin, le 5 juillet, le mec vient visiter le labo...
* D a marque d'une croix rouge le 5 juillet sur son agenda
<y> niarc niarc niarc
<D> cet homme va souffrir
<B> c'est donc le 5 juillet qu'il meurt d'un accident de la route écrasé par un 
truck muni d'un pare buffle
 -+- #ens-mim - repaire de terroristes -+-



reply via email to

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