Blame sysdeps/powerpc/test-get_hwcap.c

Packit 6c4009
/* Check __ppc_get_hwcap() and __ppc_get_at_plaftorm() functionality.
Packit 6c4009
   Copyright (C) 2015-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
/* Tests if the hwcap, hwcap2 and platform data are stored in the TCB.  */
Packit 6c4009
Packit 6c4009
#include <inttypes.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
#include <pthread.h>
Packit 6c4009
Packit 6c4009
#include <support/check.h>
Packit 6c4009
#include <support/xthread.h>
Packit 6c4009
Packit 6c4009
#include <sys/auxv.h>
Packit 6c4009
Packit 6c4009
#include <dl-procinfo.h>
Packit 6c4009
Packit 6c4009
#ifndef STATIC_TST_HWCAP
Packit 6c4009
#undef PROCINFO_DECL
Packit 6c4009
#include <dl-procinfo.c>
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Offsets copied from tcb-offsets.h.  */
Packit 6c4009
Packit 6c4009
#ifdef __powerpc64__
Packit 6c4009
# define __TPREG     "r13"
Packit 6c4009
# define __HWCAPOFF -28776
Packit 6c4009
# define __ATPLATOFF -28764
Packit 6c4009
#else
Packit 6c4009
# define __TPREG     "r2"
Packit 6c4009
# define __HWCAPOFF -28736
Packit 6c4009
# define __HWCAP2OFF -28732
Packit 6c4009
# define __ATPLATOFF -28724
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
uint64_t check_tcbhwcap (long tid)
Packit 6c4009
{
Packit 6c4009
Packit 6c4009
  uint32_t tcb_at_platform, at_platform;
Packit 6c4009
  uint64_t hwcap, hwcap2, tcb_hwcap;
Packit 6c4009
  const char *at_platform_string;
Packit 6c4009
Packit 6c4009
  /* Testing if the hwcap/hwcap2 data is correctly initialized by
Packit 6c4009
     TLS_TP_INIT.  */
Packit 6c4009
Packit 6c4009
  register unsigned long __tp __asm__ (__TPREG);
Packit 6c4009
Packit 6c4009
#ifdef __powerpc64__
Packit 6c4009
  __asm__  ("ld %0,%1(%2)\n"
Packit 6c4009
	    : "=r" (tcb_hwcap)
Packit 6c4009
	    : "i" (__HWCAPOFF), "b" (__tp));
Packit 6c4009
#else
Packit 6c4009
  uint64_t h1, h2;
Packit 6c4009
Packit 6c4009
  __asm__ ("lwz %0,%1(%2)\n"
Packit 6c4009
      : "=r" (h1)
Packit 6c4009
      : "i" (__HWCAPOFF), "b" (__tp));
Packit 6c4009
  __asm__ ("lwz %0,%1(%2)\n"
Packit 6c4009
      : "=r" (h2)
Packit 6c4009
      : "i" (__HWCAP2OFF), "b" (__tp));
Packit 6c4009
  tcb_hwcap = (h1 >> 32) << 32 | (h2 >> 32);
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  hwcap = getauxval (AT_HWCAP);
Packit 6c4009
  hwcap2 = getauxval (AT_HWCAP2);
Packit 6c4009
Packit 6c4009
  /* hwcap contains only the latest supported ISA, the code checks which is
Packit 6c4009
     and fills the previous supported ones.  This is necessary because the
Packit 6c4009
     same is done in hwcapinfo.c when setting the values that are copied to
Packit 6c4009
     the TCB.  */
Packit 6c4009
Packit 6c4009
  if (hwcap2 & PPC_FEATURE2_ARCH_2_07)
Packit 6c4009
    hwcap |= PPC_FEATURE_ARCH_2_06
Packit 6c4009
	  | PPC_FEATURE_ARCH_2_05
Packit 6c4009
	  | PPC_FEATURE_POWER5_PLUS
Packit 6c4009
	  | PPC_FEATURE_POWER5
Packit 6c4009
	  | PPC_FEATURE_POWER4;
Packit 6c4009
  else if (hwcap & PPC_FEATURE_ARCH_2_06)
Packit 6c4009
    hwcap |= PPC_FEATURE_ARCH_2_05
Packit 6c4009
	  | PPC_FEATURE_POWER5_PLUS
Packit 6c4009
	  | PPC_FEATURE_POWER5
Packit 6c4009
	  | PPC_FEATURE_POWER4;
Packit 6c4009
  else if (hwcap & PPC_FEATURE_ARCH_2_05)
Packit 6c4009
    hwcap |= PPC_FEATURE_POWER5_PLUS
Packit 6c4009
	  | PPC_FEATURE_POWER5
Packit 6c4009
	  | PPC_FEATURE_POWER4;
Packit 6c4009
  else if (hwcap & PPC_FEATURE_POWER5_PLUS)
Packit 6c4009
    hwcap |= PPC_FEATURE_POWER5
Packit 6c4009
	  | PPC_FEATURE_POWER4;
Packit 6c4009
  else if (hwcap & PPC_FEATURE_POWER5)
Packit 6c4009
    hwcap |= PPC_FEATURE_POWER4;
Packit 6c4009
Packit 6c4009
  hwcap = (hwcap << 32) + hwcap2;
Packit 6c4009
Packit 6c4009
  if ( tcb_hwcap != hwcap )
Packit 6c4009
    {
Packit 6c4009
      printf ("FAIL: __ppc_get_hwcap() - HWCAP is %" PRIx64 ". Should be %"
Packit 6c4009
	      PRIx64 " for thread %ld.\n", tcb_hwcap, hwcap, tid);
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Same test for the platform number.  */
Packit 6c4009
  __asm__  ("lwz %0,%1(%2)\n"
Packit 6c4009
	    : "=r" (tcb_at_platform)
Packit 6c4009
	    : "i" (__ATPLATOFF), "b" (__tp));
Packit 6c4009
Packit 6c4009
  at_platform_string = (const char *) getauxval (AT_PLATFORM);
Packit 6c4009
  at_platform = _dl_string_platform (at_platform_string);
Packit 6c4009
Packit 6c4009
  if ( tcb_at_platform != at_platform )
Packit 6c4009
    {
Packit 6c4009
      printf ("FAIL: __ppc_get_at_platform() - AT_PLATFORM is %x. Should be %x"
Packit 6c4009
	     " for thread %ld\n", tcb_at_platform, at_platform, tid);
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
void *t1 (void *tid)
Packit 6c4009
{
Packit 6c4009
  if (check_tcbhwcap ((long) tid))
Packit 6c4009
    {
Packit 6c4009
      pthread_exit (tid);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  pthread_exit (NULL);
Packit 6c4009
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
do_test (void)
Packit 6c4009
{
Packit 6c4009
Packit 6c4009
  pthread_t threads[2];
Packit 6c4009
  pthread_attr_t attr;
Packit 6c4009
  pthread_attr_init (&attr);
Packit 6c4009
  pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE);
Packit 6c4009
Packit 6c4009
  long i = 0;
Packit 6c4009
Packit 6c4009
  /* Check for main.  */
Packit 6c4009
  if (check_tcbhwcap (i))
Packit 6c4009
    {
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Check for other thread.  */
Packit 6c4009
  i++;
Packit 6c4009
  threads[i] = xpthread_create (&attr, t1, (void *)i);
Packit 6c4009
Packit 6c4009
  pthread_attr_destroy (&attr);
Packit 6c4009
  TEST_VERIFY_EXIT (xpthread_join (threads[i]) == NULL);
Packit 6c4009
Packit 6c4009
  printf("PASS: HWCAP, HWCAP2 and AT_PLATFORM are correctly set in the TCB for"
Packit 6c4009
	 " all threads.\n");
Packit 6c4009
Packit 6c4009
  pthread_exit (NULL);
Packit 6c4009
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#include <support/test-driver.c>