1 /*
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright © 2020 Keith Packard
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * 3. Neither the name of the copyright holder nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33 * OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #include <stdio.h>
37 #include <picotls.h>
38 #include <stdlib.h>
39 #include <stdbool.h>
40 #include <stdint.h>
41 #include <string.h>
42
43 #define DATA_VAL 0x600df00d
44 #define DATA_VAL2 0x0a0a0a0a
45
46 #define OVERALIGN_DATA 128
47 #define OVERALIGN_BSS 256
48
49 #define TLS_ALIGN (OVERALIGN_DATA > OVERALIGN_BSS ? OVERALIGN_DATA : OVERALIGN_BSS)
50
51 NEWLIB_THREAD_LOCAL volatile int data_var = DATA_VAL;
52 NEWLIB_THREAD_LOCAL volatile int bss_var;
53 _Alignas(OVERALIGN_DATA) NEWLIB_THREAD_LOCAL volatile int overaligned_data_var = DATA_VAL2;
54 _Alignas(OVERALIGN_BSS) NEWLIB_THREAD_LOCAL volatile int overaligned_bss_var;
55
56 volatile int *volatile data_addr;
57 volatile int *volatile overaligned_data_addr;
58 volatile int *volatile bss_addr;
59 volatile int *volatile overaligned_bss_addr;
60
61 #ifdef PICOLIBC_TLS
62 extern char __tdata_start[], __tdata_end[];
63 extern char __tdata_source[], __tdata_source_end[];
64 extern char __data_start[], __data_source[];
65 extern char __non_tls_bss_start[];
66
67 static bool
inside_tls_region(void * ptr,const void * tls)68 inside_tls_region(void *ptr, const void *tls)
69 {
70 return (uintptr_t)ptr >= (uintptr_t)tls &&
71 (uintptr_t)ptr < (uintptr_t)tls + _tls_size();
72 }
73
74 #define check_inside_tls_region(ptr, tls_start) \
75 if (!inside_tls_region(__DEVOLATILE(void *, ptr), tls_start)) { \
76 printf("%s (%p) is not inside TLS region [%p-%p)\n", #ptr, \
77 ptr, tls_start, (char *)tls_start + _tls_size()); \
78 result++; \
79 }
80 #endif
81
82 int
check_tls(char * where,bool check_addr,void * tls_region)83 check_tls(char *where, bool check_addr, void *tls_region)
84 {
85 int result = 0;
86
87 printf("tls check %s %p %p %p %p\n", where, &data_var,
88 &overaligned_data_var, &bss_var, &overaligned_bss_var);
89 #ifdef PICOLIBC_TLS
90 if (_tls_align() & (OVERALIGN_DATA-1)) {
91 printf("TLS alignment too small for data (need %ld, got %ld)\n",
92 (unsigned long) OVERALIGN_DATA,
93 (unsigned long) _tls_align());
94 result++;
95 }
96 if (_tls_align() & (OVERALIGN_BSS-1)) {
97 printf("TLS alignment too small for bss (need %ld, got %ld)\n",
98 (unsigned long) OVERALIGN_BSS,
99 (unsigned long) _tls_align());
100 result++;
101 }
102 #endif
103 if (!__is_aligned(tls_region, TLS_ALIGN)) {
104 printf("TLS data region (%p) is not %ld aligned\n",
105 tls_region, (unsigned long) TLS_ALIGN);
106 result++;
107 }
108 if (!__is_aligned((uintptr_t)&overaligned_data_var, OVERALIGN_DATA)) {
109 printf("overaligned_data_var (%p) is not %ld aligned\n",
110 &overaligned_data_var, (unsigned long) OVERALIGN_DATA);
111 result++;
112 }
113 if (!__is_aligned((uintptr_t)&overaligned_bss_var, OVERALIGN_BSS)) {
114 printf("overaligned_bss_var (%p) is not %ld aligned\n",
115 &overaligned_bss_var, (unsigned long) OVERALIGN_BSS);
116 result++;
117 }
118 if (data_var != DATA_VAL) {
119 printf("%s: initialized thread var has wrong value (0x%x instead of 0x%x)\n",
120 where, data_var, DATA_VAL);
121 result++;
122 }
123 if (overaligned_data_var != DATA_VAL2) {
124 printf("%s: initialized overaligned thread var has wrong value (0x%x instead of 0x%x)\n",
125 where, overaligned_data_var, DATA_VAL2);
126 result++;
127 }
128
129 if (bss_var != 0) {
130 printf("%s: uninitialized thread var has wrong value (0x%x instead of 0x%x)\n",
131 where, bss_var, 0);
132 result++;
133 }
134 if (overaligned_bss_var != 0) {
135 printf("%s: overaligned uninitialized thread var has wrong value (0x%x instead of 0x%x)\n",
136 where, overaligned_bss_var, 0);
137 result++;
138 }
139
140 data_var = ~data_var;
141
142 if (data_var != ~DATA_VAL) {
143 printf("%s: initialized thread var set to wrong value (0x%x instead of 0x%x)\n",
144 where, data_var, ~DATA_VAL);
145 result++;
146 }
147
148 overaligned_data_var = ~overaligned_data_var;
149
150 if (overaligned_data_var != ~DATA_VAL2) {
151 printf("%s: overaligned initialized thread var set to wrong value (0x%x instead of 0x%x)\n",
152 where, overaligned_data_var, ~DATA_VAL2);
153 result++;
154 }
155
156 bss_var = ~bss_var;
157
158 if (bss_var != ~0) {
159 printf("%s: uninitialized thread var has wrong value (0x%x instead of 0x%x)\n",
160 where, bss_var, ~0);
161 result++;
162 }
163
164 overaligned_bss_var = ~overaligned_bss_var;
165
166 if (overaligned_bss_var != ~0) {
167 printf("%s: overaligned uninitialized thread var has wrong value (0x%x instead of 0x%x)\n",
168 where, overaligned_bss_var, ~0);
169 result++;
170 }
171
172 if (check_addr) {
173 if (data_addr == &data_var) {
174 printf("_set_tls didn't affect initialized addr %p\n", data_addr);
175 result++;
176 }
177
178 if (overaligned_data_addr == &overaligned_data_var) {
179 printf("_set_tls didn't affect initialized addr %p\n", overaligned_data_addr);
180 result++;
181 }
182
183 if (bss_addr == &bss_var) {
184 printf("_set_tls didn't affect uninitialized addr %p\n", bss_addr);
185 result++;
186 }
187
188 if (overaligned_bss_addr == &overaligned_bss_var) {
189 printf("_set_tls didn't affect uninitialized addr %p\n", overaligned_bss_addr);
190 result++;
191 }
192 }
193 #ifdef PICOLIBC_TLS
194 check_inside_tls_region(&data_var, tls_region);
195 check_inside_tls_region(&overaligned_data_var, tls_region);
196 check_inside_tls_region(&bss_var, tls_region);
197 check_inside_tls_region(&overaligned_bss_var, tls_region);
198
199 if (__non_tls_bss_start < __tdata_start + _tls_size() || __tdata_start + _tls_size() + 64 < __non_tls_bss_start) {
200 printf("non-TLS bss data doesn't start after TLS data (is %p should be %p)\n",
201 __non_tls_bss_start, __tdata_start + _tls_size());
202 result++;
203 }
204 #endif
205 return result;
206 }
207
208 void
hexdump(const void * ptr,int length,const char * hdr)209 hexdump(const void *ptr, int length, const char *hdr)
210 {
211 const unsigned char *cp = ptr;
212
213 for (int i = 0; i < length; i += 16) {
214 printf("%s%08zx ", hdr, i + (size_t)ptr);
215 for (int j = 0; j < 16; j++) {
216 int offset = i + j;
217 if (offset < length)
218 printf(" %02x", cp[offset]);
219 else
220 printf(" ");
221 }
222 printf("\n");
223 }
224 }
225
226 int
main(void)227 main(void)
228 {
229 int result = 0;
230
231 data_addr = &data_var;
232 overaligned_data_addr = &overaligned_data_var;
233 bss_addr = &bss_var;
234 overaligned_bss_addr = &overaligned_bss_var;
235
236 #ifdef PICOLIBC_TLS
237 printf("TLS region: %p-%p (%zd bytes)\n", __tdata_start,
238 __tdata_start + _tls_size(), _tls_size());
239 size_t tdata_source_size = __tdata_source_end - __tdata_source;
240 size_t tdata_size = __tdata_end - __tdata_start;
241
242 if (__tdata_start - __data_start != __tdata_source - __data_source) {
243 printf("ROM/RAM .tdata offset from .data mismatch. "
244 "VMA offset=%zd, LMA offset =%zd."
245 "Linker behaviour changed?\n",
246 __tdata_start - __data_start,
247 __tdata_source - __data_source);
248 }
249
250 if (tdata_source_size != tdata_size ||
251 memcmp(&__tdata_source, &__tdata_start, tdata_size) != 0) {
252 printf("TLS data in RAM does not match ROM\n");
253 hexdump(__tdata_source, tdata_source_size, "ROM:");
254 hexdump(__tdata_start, tdata_size, "RAM:");
255 result++;
256 }
257 result += check_tls("pre-defined", false, __tdata_start);
258 #else
259 result += check_tls("pre-defined", false, NULL);
260 #endif
261
262
263 #ifdef _HAVE_PICOLIBC_TLS_API
264
265 size_t tls_align = _tls_align();
266 size_t tls_size = _tls_size();
267 void *tls = aligned_alloc(tls_align, tls_size);
268
269 /*
270 * Fill the region with data to make sure even bss
271 * gets correctly initialized
272 */
273 memset(tls, 0x55, tls_size);
274
275 _init_tls(tls);
276 _set_tls(tls);
277
278 if (memcmp(tls, &__tdata_source, tdata_size) != 0) {
279 printf("New TLS data in RAM does not match ROM\n");
280 hexdump(&__tdata_source, tdata_source_size, "ROM:");
281 hexdump(tls, tdata_size, "RAM:");
282 result++;
283 }
284
285 result += check_tls("allocated", true, tls);
286 #endif
287
288 printf("tls test result %d\n", result);
289 return result;
290 }
291