]>
Commit | Line | Data |
---|---|---|
1 | /*****************************************************************************\ | |
2 | * Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC. | |
3 | * Copyright (C) 2007 The Regents of the University of California. | |
4 | * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). | |
5 | * Written by Brian Behlendorf <behlendorf1@llnl.gov>. | |
6 | * UCRL-CODE-235197 | |
7 | * | |
8 | * This file is part of the SPL, Solaris Porting Layer. | |
9 | * For details, see <http://zfsonlinux.org/>. | |
10 | * | |
11 | * The SPL is free software; you can redistribute it and/or modify it | |
12 | * under the terms of the GNU General Public License as published by the | |
13 | * Free Software Foundation; either version 2 of the License, or (at your | |
14 | * option) any later version. | |
15 | * | |
16 | * The SPL is distributed in the hope that it will be useful, but WITHOUT | |
17 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
18 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
19 | * for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU General Public License along | |
22 | * with the SPL. If not, see <http://www.gnu.org/licenses/>. | |
23 | ***************************************************************************** | |
24 | * Solaris Porting LAyer Tests (SPLAT) Generic Tests. | |
25 | \*****************************************************************************/ | |
26 | ||
27 | #include <sys/sunddi.h> | |
28 | #include <linux/math64_compat.h> | |
29 | #include "splat-internal.h" | |
30 | ||
31 | #define SPLAT_GENERIC_NAME "generic" | |
32 | #define SPLAT_GENERIC_DESC "Kernel Generic Tests" | |
33 | ||
34 | #define SPLAT_GENERIC_TEST1_ID 0x0d01 | |
35 | #define SPLAT_GENERIC_TEST1_NAME "ddi_strtoul" | |
36 | #define SPLAT_GENERIC_TEST1_DESC "ddi_strtoul Test" | |
37 | ||
38 | #define SPLAT_GENERIC_TEST2_ID 0x0d02 | |
39 | #define SPLAT_GENERIC_TEST2_NAME "ddi_strtol" | |
40 | #define SPLAT_GENERIC_TEST2_DESC "ddi_strtol Test" | |
41 | ||
42 | #define SPLAT_GENERIC_TEST3_ID 0x0d03 | |
43 | #define SPLAT_GENERIC_TEST3_NAME "ddi_strtoull" | |
44 | #define SPLAT_GENERIC_TEST3_DESC "ddi_strtoull Test" | |
45 | ||
46 | #define SPLAT_GENERIC_TEST4_ID 0x0d04 | |
47 | #define SPLAT_GENERIC_TEST4_NAME "ddi_strtoll" | |
48 | #define SPLAT_GENERIC_TEST4_DESC "ddi_strtoll Test" | |
49 | ||
50 | # define SPLAT_GENERIC_TEST5_ID 0x0d05 | |
51 | # define SPLAT_GENERIC_TEST5_NAME "udivdi3" | |
52 | # define SPLAT_GENERIC_TEST5_DESC "Unsigned Div-64 Test" | |
53 | ||
54 | # define SPLAT_GENERIC_TEST6_ID 0x0d06 | |
55 | # define SPLAT_GENERIC_TEST6_NAME "divdi3" | |
56 | # define SPLAT_GENERIC_TEST6_DESC "Signed Div-64 Test" | |
57 | ||
58 | #define STR_POS "123456789" | |
59 | #define STR_NEG "-123456789" | |
60 | #define STR_BASE "0xabcdef" | |
61 | #define STR_RANGE_MAX "10000000000000000" | |
62 | #define STR_RANGE_MIN "-10000000000000000" | |
63 | #define STR_INVAL1 "12345U" | |
64 | #define STR_INVAL2 "invald" | |
65 | ||
66 | #define VAL_POS 123456789 | |
67 | #define VAL_NEG -123456789 | |
68 | #define VAL_BASE 0xabcdef | |
69 | #define VAL_INVAL1 12345U | |
70 | ||
71 | #define define_generic_msg_strtox(type, valtype) \ | |
72 | static void \ | |
73 | generic_msg_strto##type(struct file *file, char *msg, int rc, int *err, \ | |
74 | const char *s, valtype d, char *endptr) \ | |
75 | { \ | |
76 | splat_vprint(file, SPLAT_GENERIC_TEST1_NAME, \ | |
77 | "%s (%d) %s: %s == %lld, 0x%p\n", \ | |
78 | rc ? "Fail" : "Pass", *err, msg, s, \ | |
79 | (unsigned long long)d, endptr); \ | |
80 | *err = rc; \ | |
81 | } | |
82 | ||
83 | define_generic_msg_strtox(ul, unsigned long); | |
84 | define_generic_msg_strtox(l, long); | |
85 | define_generic_msg_strtox(ull, unsigned long long); | |
86 | define_generic_msg_strtox(ll, long long); | |
87 | ||
88 | #define define_splat_generic_test_strtox(type, valtype) \ | |
89 | static int \ | |
90 | splat_generic_test_strto##type(struct file *file, void *arg) \ | |
91 | { \ | |
92 | int rc, rc1, rc2, rc3, rc4, rc5, rc6, rc7; \ | |
93 | char str[20], *endptr; \ | |
94 | valtype r; \ | |
95 | \ | |
96 | /* Positive value: expect success */ \ | |
97 | r = 0; \ | |
98 | rc = 1; \ | |
99 | endptr = NULL; \ | |
100 | rc1 = ddi_strto##type(STR_POS, &endptr, 10, &r); \ | |
101 | if (rc1 == 0 && r == VAL_POS && endptr && *endptr == '\0') \ | |
102 | rc = 0; \ | |
103 | \ | |
104 | generic_msg_strto##type(file, "positive", rc , &rc1, \ | |
105 | STR_POS, r, endptr); \ | |
106 | \ | |
107 | /* Negative value: expect success */ \ | |
108 | r = 0; \ | |
109 | rc = 1; \ | |
110 | endptr = NULL; \ | |
111 | strcpy(str, STR_NEG); \ | |
112 | rc2 = ddi_strto##type(str, &endptr, 10, &r); \ | |
113 | if (#type[0] == 'u') { \ | |
114 | if (rc2 == 0 && r == 0 && endptr == str) \ | |
115 | rc = 0; \ | |
116 | } else { \ | |
117 | if (rc2 == 0 && r == VAL_NEG && \ | |
118 | endptr && *endptr == '\0') \ | |
119 | rc = 0; \ | |
120 | } \ | |
121 | \ | |
122 | generic_msg_strto##type(file, "negative", rc, &rc2, \ | |
123 | STR_NEG, r, endptr); \ | |
124 | \ | |
125 | /* Non decimal base: expect sucess */ \ | |
126 | r = 0; \ | |
127 | rc = 1; \ | |
128 | endptr = NULL; \ | |
129 | rc3 = ddi_strto##type(STR_BASE, &endptr, 0, &r); \ | |
130 | if (rc3 == 0 && r == VAL_BASE && endptr && *endptr == '\0') \ | |
131 | rc = 0; \ | |
132 | \ | |
133 | generic_msg_strto##type(file, "base", rc, &rc3, \ | |
134 | STR_BASE, r, endptr); \ | |
135 | \ | |
136 | /* Max out of range: failure expected, r unchanged */ \ | |
137 | r = 0; \ | |
138 | rc = 1; \ | |
139 | endptr = NULL; \ | |
140 | rc4 = ddi_strto##type(STR_RANGE_MAX, &endptr, 16, &r); \ | |
141 | if (rc4 == ERANGE && r == 0 && endptr == NULL) \ | |
142 | rc = 0; \ | |
143 | \ | |
144 | generic_msg_strto##type(file, "max", rc, &rc4, \ | |
145 | STR_RANGE_MAX, r, endptr); \ | |
146 | \ | |
147 | /* Min out of range: failure expected, r unchanged */ \ | |
148 | r = 0; \ | |
149 | rc = 1; \ | |
150 | endptr = NULL; \ | |
151 | strcpy(str, STR_RANGE_MIN); \ | |
152 | rc5 = ddi_strto##type(str, &endptr, 16, &r); \ | |
153 | if (#type[0] == 'u') { \ | |
154 | if (rc5 == 0 && r == 0 && endptr == str) \ | |
155 | rc = 0; \ | |
156 | } else { \ | |
157 | if (rc5 == ERANGE && r == 0 && endptr == NULL) \ | |
158 | rc = 0; \ | |
159 | } \ | |
160 | \ | |
161 | generic_msg_strto##type(file, "min", rc, &rc5, \ | |
162 | STR_RANGE_MIN, r, endptr); \ | |
163 | \ | |
164 | /* Invalid string: success expected, endptr == 'U' */ \ | |
165 | r = 0; \ | |
166 | rc = 1; \ | |
167 | endptr = NULL; \ | |
168 | rc6 = ddi_strto##type(STR_INVAL1, &endptr, 10, &r); \ | |
169 | if (rc6 == 0 && r == VAL_INVAL1 && endptr && *endptr == 'U') \ | |
170 | rc = 0; \ | |
171 | \ | |
172 | generic_msg_strto##type(file, "invalid", rc, &rc6, \ | |
173 | STR_INVAL1, r, endptr); \ | |
174 | \ | |
175 | /* Invalid string: failure expected, endptr == str */ \ | |
176 | r = 0; \ | |
177 | rc = 1; \ | |
178 | endptr = NULL; \ | |
179 | strcpy(str, STR_INVAL2); \ | |
180 | rc7 = ddi_strto##type(str, &endptr, 10, &r); \ | |
181 | if (rc7 == 0 && r == 0 && endptr == str) \ | |
182 | rc = 0; \ | |
183 | \ | |
184 | generic_msg_strto##type(file, "invalid", rc, &rc7, \ | |
185 | STR_INVAL2, r, endptr); \ | |
186 | \ | |
187 | return (rc1 || rc2 || rc3 || rc4 || rc5 || rc6 || rc7) ? \ | |
188 | -EINVAL : 0; \ | |
189 | } | |
190 | ||
191 | define_splat_generic_test_strtox(ul, unsigned long); | |
192 | define_splat_generic_test_strtox(l, long); | |
193 | define_splat_generic_test_strtox(ull, unsigned long long); | |
194 | define_splat_generic_test_strtox(ll, long long); | |
195 | ||
196 | /* | |
197 | * The entries in the table are used in all combinations and the | |
198 | * return value is checked to ensure it is range. On 32-bit | |
199 | * systems __udivdi3 will be invoked for the 64-bit division. | |
200 | * On 64-bit system the native 64-bit divide will be used so | |
201 | * __udivdi3 isn't used but we might as well stil run the test. | |
202 | */ | |
203 | static int | |
204 | splat_generic_test_udivdi3(struct file *file, void *arg) | |
205 | { | |
206 | const uint64_t tabu[] = { | |
207 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, | |
208 | 10, 11, 12, 13, 14, 15, 16, 1000, 2003, | |
209 | 32765, 32766, 32767, 32768, 32769, 32760, | |
210 | 65533, 65534, 65535, 65536, 65537, 65538, | |
211 | 0x7ffffffeULL, 0x7fffffffULL, 0x80000000ULL, 0x80000001ULL, | |
212 | 0x7000000000000000ULL, 0x7000000080000000ULL, 0x7000000080000001ULL, | |
213 | 0x7fffffffffffffffULL, 0x7fffffff8fffffffULL, 0x7fffffff8ffffff1ULL, | |
214 | 0x7fffffff00000000ULL, 0x7fffffff80000000ULL, 0x7fffffff00000001ULL, | |
215 | 0x8000000000000000ULL, 0x8000000080000000ULL, 0x8000000080000001ULL, | |
216 | 0xc000000000000000ULL, 0xc000000080000000ULL, 0xc000000080000001ULL, | |
217 | 0xfffffffffffffffdULL, 0xfffffffffffffffeULL, 0xffffffffffffffffULL, | |
218 | }; | |
219 | uint64_t uu, vu, qu, ru; | |
220 | int n, i, j, errors = 0; | |
221 | ||
222 | splat_vprint(file, SPLAT_GENERIC_TEST5_NAME, "%s", | |
223 | "Testing unsigned 64-bit division.\n"); | |
224 | n = sizeof(tabu) / sizeof(tabu[0]); | |
225 | for (i = 0; i < n; i++) { | |
226 | for (j = 1; j < n; j++) { | |
227 | uu = tabu[i]; | |
228 | vu = tabu[j]; | |
229 | qu = uu / vu; /* __udivdi3 */ | |
230 | ru = uu - qu * vu; | |
231 | if (qu > uu || ru >= vu) { | |
232 | splat_vprint(file, SPLAT_GENERIC_TEST5_NAME, | |
233 | "%016llx/%016llx != %016llx rem %016llx\n", | |
234 | uu, vu, qu, ru); | |
235 | errors++; | |
236 | } | |
237 | } | |
238 | } | |
239 | ||
240 | if (errors) { | |
241 | splat_vprint(file, SPLAT_GENERIC_TEST5_NAME, | |
242 | "Failed %d/%d tests\n", errors, n * (n - 1)); | |
243 | return -ERANGE; | |
244 | } | |
245 | ||
246 | splat_vprint(file, SPLAT_GENERIC_TEST5_NAME, | |
247 | "Passed all %d tests\n", n * (n - 1)); | |
248 | ||
249 | return 0; | |
250 | } | |
251 | ||
252 | /* | |
253 | * The entries the table are used in all combinations, with + and - signs | |
254 | * preceding them. The return value is checked to ensure it is range. | |
255 | * On 32-bit systems __divdi3 will be invoked for the 64-bit division. | |
256 | * On 64-bit system the native 64-bit divide will be used so __divdi3 | |
257 | * isn't used but we might as well stil run the test. | |
258 | */ | |
259 | static int | |
260 | splat_generic_test_divdi3(struct file *file, void *arg) | |
261 | { | |
262 | const int64_t tabs[] = { | |
263 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, | |
264 | 10, 11, 12, 13, 14, 15, 16, 1000, 2003, | |
265 | 32765, 32766, 32767, 32768, 32769, 32760, | |
266 | 65533, 65534, 65535, 65536, 65537, 65538, | |
267 | 0x7ffffffeLL, 0x7fffffffLL, 0x80000000LL, 0x80000001LL, | |
268 | 0x7000000000000000LL, 0x7000000080000000LL, 0x7000000080000001LL, | |
269 | 0x7fffffffffffffffLL, 0x7fffffff8fffffffLL, 0x7fffffff8ffffff1LL, | |
270 | 0x7fffffff00000000LL, 0x7fffffff80000000LL, 0x7fffffff00000001LL, | |
271 | 0x0123456789abcdefLL, 0x00000000abcdef01LL, 0x0000000012345678LL, | |
272 | #if BITS_PER_LONG == 32 | |
273 | 0x8000000000000000LL, 0x8000000080000000LL, 0x8000000080000001LL, | |
274 | #endif | |
275 | }; | |
276 | int64_t u, v, q, r; | |
277 | int n, i, j, k, errors = 0; | |
278 | ||
279 | splat_vprint(file, SPLAT_GENERIC_TEST6_NAME, "%s", | |
280 | "Testing signed 64-bit division.\n"); | |
281 | n = sizeof(tabs) / sizeof(tabs[0]); | |
282 | for (i = 0; i < n; i++) { | |
283 | for (j = 1; j < n; j++) { | |
284 | for (k = 0; k <= 3; k++) { | |
285 | u = (k & 1) ? -tabs[i] : tabs[i]; | |
286 | v = (k >= 2) ? -tabs[j] : tabs[j]; | |
287 | ||
288 | q = u / v; /* __divdi3 */ | |
289 | r = u - q * v; | |
290 | if (abs64(q) > abs64(u) || | |
291 | abs64(r) >= abs64(v) || | |
292 | (r != 0 && (r ^ u) < 0)) { | |
293 | splat_vprint(file, | |
294 | SPLAT_GENERIC_TEST6_NAME, | |
295 | "%016llx/%016llx != %016llx " | |
296 | "rem %016llx\n", u, v, q, r); | |
297 | errors++; | |
298 | } | |
299 | } | |
300 | } | |
301 | } | |
302 | ||
303 | if (errors) { | |
304 | splat_vprint(file, SPLAT_GENERIC_TEST6_NAME, | |
305 | "Failed %d/%d tests\n", errors, n * (n - 1)); | |
306 | return -ERANGE; | |
307 | } | |
308 | ||
309 | splat_vprint(file, SPLAT_GENERIC_TEST6_NAME, | |
310 | "Passed all %d tests\n", n * (n - 1)); | |
311 | ||
312 | return 0; | |
313 | } | |
314 | ||
315 | splat_subsystem_t * | |
316 | splat_generic_init(void) | |
317 | { | |
318 | splat_subsystem_t *sub; | |
319 | ||
320 | sub = kmalloc(sizeof(*sub), GFP_KERNEL); | |
321 | if (sub == NULL) | |
322 | return NULL; | |
323 | ||
324 | memset(sub, 0, sizeof(*sub)); | |
325 | strncpy(sub->desc.name, SPLAT_GENERIC_NAME, SPLAT_NAME_SIZE); | |
326 | strncpy(sub->desc.desc, SPLAT_GENERIC_DESC, SPLAT_DESC_SIZE); | |
327 | INIT_LIST_HEAD(&sub->subsystem_list); | |
328 | INIT_LIST_HEAD(&sub->test_list); | |
329 | spin_lock_init(&sub->test_lock); | |
330 | sub->desc.id = SPLAT_SUBSYSTEM_GENERIC; | |
331 | ||
332 | SPLAT_TEST_INIT(sub, SPLAT_GENERIC_TEST1_NAME, SPLAT_GENERIC_TEST1_DESC, | |
333 | SPLAT_GENERIC_TEST1_ID, splat_generic_test_strtoul); | |
334 | SPLAT_TEST_INIT(sub, SPLAT_GENERIC_TEST2_NAME, SPLAT_GENERIC_TEST2_DESC, | |
335 | SPLAT_GENERIC_TEST2_ID, splat_generic_test_strtol); | |
336 | SPLAT_TEST_INIT(sub, SPLAT_GENERIC_TEST3_NAME, SPLAT_GENERIC_TEST3_DESC, | |
337 | SPLAT_GENERIC_TEST3_ID, splat_generic_test_strtoull); | |
338 | SPLAT_TEST_INIT(sub, SPLAT_GENERIC_TEST4_NAME, SPLAT_GENERIC_TEST4_DESC, | |
339 | SPLAT_GENERIC_TEST4_ID, splat_generic_test_strtoll); | |
340 | SPLAT_TEST_INIT(sub, SPLAT_GENERIC_TEST5_NAME, SPLAT_GENERIC_TEST5_DESC, | |
341 | SPLAT_GENERIC_TEST5_ID, splat_generic_test_udivdi3); | |
342 | SPLAT_TEST_INIT(sub, SPLAT_GENERIC_TEST6_NAME, SPLAT_GENERIC_TEST6_DESC, | |
343 | SPLAT_GENERIC_TEST6_ID, splat_generic_test_divdi3); | |
344 | ||
345 | return sub; | |
346 | } | |
347 | ||
348 | void | |
349 | splat_generic_fini(splat_subsystem_t *sub) | |
350 | { | |
351 | ASSERT(sub); | |
352 | ||
353 | SPLAT_TEST_FINI(sub, SPLAT_GENERIC_TEST6_ID); | |
354 | SPLAT_TEST_FINI(sub, SPLAT_GENERIC_TEST5_ID); | |
355 | SPLAT_TEST_FINI(sub, SPLAT_GENERIC_TEST4_ID); | |
356 | SPLAT_TEST_FINI(sub, SPLAT_GENERIC_TEST3_ID); | |
357 | SPLAT_TEST_FINI(sub, SPLAT_GENERIC_TEST2_ID); | |
358 | SPLAT_TEST_FINI(sub, SPLAT_GENERIC_TEST1_ID); | |
359 | ||
360 | kfree(sub); | |
361 | } | |
362 | ||
363 | int | |
364 | splat_generic_id(void) | |
365 | { | |
366 | return SPLAT_SUBSYSTEM_GENERIC; | |
367 | } |