1 /* Check __ppc_get_hwcap() and __ppc_get_at_plaftorm() functionality.
2 Copyright (C) 2015-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19 /* Tests if the hwcap, hwcap2 and platform data are stored in the TCB. */
20
21 #include <inttypes.h>
22 #include <stdio.h>
23 #include <stdint.h>
24 #include <pthread.h>
25
26 #include <support/check.h>
27 #include <support/xthread.h>
28
29 #include <sys/auxv.h>
30
31 #include <dl-procinfo.h>
32
33 #ifndef STATIC_TST_HWCAP
34 #undef PROCINFO_DECL
35 #include <dl-procinfo.c>
36 #endif
37
38 /* Offsets copied from tcb-offsets.h. */
39
40 #ifdef __powerpc64__
41 # define __TPREG "r13"
42 # define __HWCAPOFF -28776
43 # define __ATPLATOFF -28764
44 #else
45 # define __TPREG "r2"
46 # define __HWCAPOFF -28736
47 # define __HWCAP2OFF -28732
48 # define __ATPLATOFF -28724
49 #endif
50
check_tcbhwcap(long tid)51 uint64_t check_tcbhwcap (long tid)
52 {
53
54 uint32_t tcb_at_platform, at_platform;
55 uint64_t hwcap, hwcap2, tcb_hwcap;
56 const char *at_platform_string;
57
58 /* Testing if the hwcap/hwcap2 data is correctly initialized by
59 TLS_TP_INIT. */
60
61 register unsigned long __tp __asm__ (__TPREG);
62
63 #ifdef __powerpc64__
64 __asm__ ("ld %0,%1(%2)\n"
65 : "=r" (tcb_hwcap)
66 : "n" (__HWCAPOFF), "b" (__tp));
67 #else
68 uint64_t h1, h2;
69
70 __asm__ ("lwz %0,%1(%2)\n"
71 : "=r" (h1)
72 : "n" (__HWCAPOFF), "b" (__tp));
73 __asm__ ("lwz %0,%1(%2)\n"
74 : "=r" (h2)
75 : "n" (__HWCAP2OFF), "b" (__tp));
76 tcb_hwcap = (h1 >> 32) << 32 | (h2 >> 32);
77 #endif
78
79 hwcap = getauxval (AT_HWCAP);
80 hwcap2 = getauxval (AT_HWCAP2);
81
82 /* hwcap contains only the latest supported ISA, the code checks which is
83 and fills the previous supported ones. This is necessary because the
84 same is done in hwcapinfo.c when setting the values that are copied to
85 the TCB. */
86
87 if (hwcap2 & PPC_FEATURE2_ARCH_2_07)
88 hwcap |= PPC_FEATURE_ARCH_2_06
89 | PPC_FEATURE_ARCH_2_05
90 | PPC_FEATURE_POWER5_PLUS
91 | PPC_FEATURE_POWER5
92 | PPC_FEATURE_POWER4;
93 else if (hwcap & PPC_FEATURE_ARCH_2_06)
94 hwcap |= PPC_FEATURE_ARCH_2_05
95 | PPC_FEATURE_POWER5_PLUS
96 | PPC_FEATURE_POWER5
97 | PPC_FEATURE_POWER4;
98 else if (hwcap & PPC_FEATURE_ARCH_2_05)
99 hwcap |= PPC_FEATURE_POWER5_PLUS
100 | PPC_FEATURE_POWER5
101 | PPC_FEATURE_POWER4;
102 else if (hwcap & PPC_FEATURE_POWER5_PLUS)
103 hwcap |= PPC_FEATURE_POWER5
104 | PPC_FEATURE_POWER4;
105 else if (hwcap & PPC_FEATURE_POWER5)
106 hwcap |= PPC_FEATURE_POWER4;
107
108 hwcap = (hwcap << 32) + hwcap2;
109
110 if ( tcb_hwcap != hwcap )
111 {
112 printf ("FAIL: __ppc_get_hwcap() - HWCAP is %" PRIx64 ". Should be %"
113 PRIx64 " for thread %ld.\n", tcb_hwcap, hwcap, tid);
114 return 1;
115 }
116
117 /* Same test for the platform number. */
118 __asm__ ("lwz %0,%1(%2)\n"
119 : "=r" (tcb_at_platform)
120 : "n" (__ATPLATOFF), "b" (__tp));
121
122 at_platform_string = (const char *) getauxval (AT_PLATFORM);
123 at_platform = _dl_string_platform (at_platform_string);
124
125 if ( tcb_at_platform != at_platform )
126 {
127 printf ("FAIL: __ppc_get_at_platform() - AT_PLATFORM is %x. Should be %x"
128 " for thread %ld\n", tcb_at_platform, at_platform, tid);
129 return 1;
130 }
131
132 return 0;
133 }
134
t1(void * tid)135 void *t1 (void *tid)
136 {
137 if (check_tcbhwcap ((long) tid))
138 {
139 pthread_exit (tid);
140 }
141
142 pthread_exit (NULL);
143
144 }
145
146 static int
do_test(void)147 do_test (void)
148 {
149
150 pthread_t threads[2];
151 pthread_attr_t attr;
152 pthread_attr_init (&attr);
153 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE);
154
155 long i = 0;
156
157 /* Check for main. */
158 if (check_tcbhwcap (i))
159 {
160 return 1;
161 }
162
163 /* Check for other thread. */
164 i++;
165 threads[i] = xpthread_create (&attr, t1, (void *)i);
166
167 pthread_attr_destroy (&attr);
168 TEST_VERIFY_EXIT (xpthread_join (threads[i]) == NULL);
169
170 printf("PASS: HWCAP, HWCAP2 and AT_PLATFORM are correctly set in the TCB for"
171 " all threads.\n");
172
173 pthread_exit (NULL);
174
175 }
176
177 #include <support/test-driver.c>
178