1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * tools/testing/selftests/kvm/lib/test_util.c
4 *
5 * Copyright (C) 2020, Google LLC.
6 */
7 #include <stdio.h>
8 #include <stdarg.h>
9 #include <assert.h>
10 #include <ctype.h>
11 #include <limits.h>
12 #include <stdlib.h>
13 #include <time.h>
14 #include <sys/stat.h>
15 #include <sys/syscall.h>
16 #include <linux/mman.h>
17 #include "linux/kernel.h"
18
19 #include "test_util.h"
20
21 sigjmp_buf expect_sigbus_jmpbuf;
22
expect_sigbus_handler(int signum)23 void __attribute__((used)) expect_sigbus_handler(int signum)
24 {
25 siglongjmp(expect_sigbus_jmpbuf, 1);
26 }
27
28 /*
29 * Random number generator that is usable from guest code. This is the
30 * Park-Miller LCG using standard constants.
31 */
32
new_guest_random_state(uint32_t seed)33 struct guest_random_state new_guest_random_state(uint32_t seed)
34 {
35 struct guest_random_state s = {.seed = seed};
36 return s;
37 }
38
guest_random_u32(struct guest_random_state * state)39 uint32_t guest_random_u32(struct guest_random_state *state)
40 {
41 state->seed = (uint64_t)state->seed * 48271 % ((uint32_t)(1 << 31) - 1);
42 return state->seed;
43 }
44
45 /*
46 * Parses "[0-9]+[kmgt]?".
47 */
parse_size(const char * size)48 size_t parse_size(const char *size)
49 {
50 size_t base;
51 char *scale;
52 int shift = 0;
53
54 TEST_ASSERT(size && isdigit(size[0]), "Need at least one digit in '%s'", size);
55
56 base = strtoull(size, &scale, 0);
57
58 TEST_ASSERT(base != ULLONG_MAX, "Overflow parsing size!");
59
60 switch (tolower(*scale)) {
61 case 't':
62 shift = 40;
63 break;
64 case 'g':
65 shift = 30;
66 break;
67 case 'm':
68 shift = 20;
69 break;
70 case 'k':
71 shift = 10;
72 break;
73 case 'b':
74 case '\0':
75 shift = 0;
76 break;
77 default:
78 TEST_ASSERT(false, "Unknown size letter %c", *scale);
79 }
80
81 TEST_ASSERT((base << shift) >> shift == base, "Overflow scaling size!");
82
83 return base << shift;
84 }
85
timespec_to_ns(struct timespec ts)86 int64_t timespec_to_ns(struct timespec ts)
87 {
88 return (int64_t)ts.tv_nsec + 1000000000LL * (int64_t)ts.tv_sec;
89 }
90
timespec_add_ns(struct timespec ts,int64_t ns)91 struct timespec timespec_add_ns(struct timespec ts, int64_t ns)
92 {
93 struct timespec res;
94
95 res.tv_nsec = ts.tv_nsec + ns;
96 res.tv_sec = ts.tv_sec + res.tv_nsec / 1000000000LL;
97 res.tv_nsec %= 1000000000LL;
98
99 return res;
100 }
101
timespec_add(struct timespec ts1,struct timespec ts2)102 struct timespec timespec_add(struct timespec ts1, struct timespec ts2)
103 {
104 int64_t ns1 = timespec_to_ns(ts1);
105 int64_t ns2 = timespec_to_ns(ts2);
106 return timespec_add_ns((struct timespec){0}, ns1 + ns2);
107 }
108
timespec_sub(struct timespec ts1,struct timespec ts2)109 struct timespec timespec_sub(struct timespec ts1, struct timespec ts2)
110 {
111 int64_t ns1 = timespec_to_ns(ts1);
112 int64_t ns2 = timespec_to_ns(ts2);
113 return timespec_add_ns((struct timespec){0}, ns1 - ns2);
114 }
115
timespec_elapsed(struct timespec start)116 struct timespec timespec_elapsed(struct timespec start)
117 {
118 struct timespec end;
119
120 clock_gettime(CLOCK_MONOTONIC, &end);
121 return timespec_sub(end, start);
122 }
123
timespec_div(struct timespec ts,int divisor)124 struct timespec timespec_div(struct timespec ts, int divisor)
125 {
126 int64_t ns = timespec_to_ns(ts) / divisor;
127
128 return timespec_add_ns((struct timespec){0}, ns);
129 }
130
print_skip(const char * fmt,...)131 void print_skip(const char *fmt, ...)
132 {
133 va_list ap;
134
135 assert(fmt);
136 va_start(ap, fmt);
137 vprintf(fmt, ap);
138 va_end(ap);
139 puts(", skipping test");
140 }
141
test_sysfs_path(const char * path)142 static bool test_sysfs_path(const char *path)
143 {
144 struct stat statbuf;
145 int ret;
146
147 ret = stat(path, &statbuf);
148 TEST_ASSERT(ret == 0 || (ret == -1 && errno == ENOENT),
149 "Error in stat()ing '%s'", path);
150
151 return ret == 0;
152 }
153
thp_configured(void)154 bool thp_configured(void)
155 {
156 return test_sysfs_path("/sys/kernel/mm/transparent_hugepage");
157 }
158
get_sysfs_val(const char * path)159 static size_t get_sysfs_val(const char *path)
160 {
161 size_t size;
162 FILE *f;
163 int ret;
164
165 f = fopen(path, "r");
166 TEST_ASSERT(f, "Error opening '%s'", path);
167
168 ret = fscanf(f, "%ld", &size);
169 TEST_ASSERT(ret > 0, "Error reading '%s'", path);
170
171 /* Re-scan the input stream to verify the entire file was read. */
172 ret = fscanf(f, "%ld", &size);
173 TEST_ASSERT(ret < 1, "Error reading '%s'", path);
174
175 fclose(f);
176 return size;
177 }
178
get_trans_hugepagesz(void)179 size_t get_trans_hugepagesz(void)
180 {
181 TEST_ASSERT(thp_configured(), "THP is not configured in host kernel");
182
183 return get_sysfs_val("/sys/kernel/mm/transparent_hugepage/hpage_pmd_size");
184 }
185
is_numa_balancing_enabled(void)186 bool is_numa_balancing_enabled(void)
187 {
188 if (!test_sysfs_path("/proc/sys/kernel/numa_balancing"))
189 return false;
190 return get_sysfs_val("/proc/sys/kernel/numa_balancing") == 1;
191 }
192
get_def_hugetlb_pagesz(void)193 size_t get_def_hugetlb_pagesz(void)
194 {
195 char buf[64];
196 const char *hugepagesize = "Hugepagesize:";
197 const char *hugepages_total = "HugePages_Total:";
198 FILE *f;
199
200 f = fopen("/proc/meminfo", "r");
201 TEST_ASSERT(f != NULL, "Error in opening /proc/meminfo");
202
203 while (fgets(buf, sizeof(buf), f) != NULL) {
204 if (strstr(buf, hugepages_total) == buf) {
205 unsigned long long total = strtoull(buf + strlen(hugepages_total), NULL, 10);
206 if (!total) {
207 fprintf(stderr, "HUGETLB is not enabled in /proc/sys/vm/nr_hugepages\n");
208 exit(KSFT_SKIP);
209 }
210 }
211 if (strstr(buf, hugepagesize) == buf) {
212 fclose(f);
213 return strtoull(buf + strlen(hugepagesize), NULL, 10) << 10;
214 }
215 }
216
217 if (feof(f)) {
218 fprintf(stderr, "HUGETLB is not configured in host kernel");
219 exit(KSFT_SKIP);
220 }
221
222 TEST_FAIL("Error in reading /proc/meminfo");
223 }
224
225 #define ANON_FLAGS (MAP_PRIVATE | MAP_ANONYMOUS)
226 #define ANON_HUGE_FLAGS (ANON_FLAGS | MAP_HUGETLB)
227
vm_mem_backing_src_alias(uint32_t i)228 const struct vm_mem_backing_src_alias *vm_mem_backing_src_alias(uint32_t i)
229 {
230 static const struct vm_mem_backing_src_alias aliases[] = {
231 [VM_MEM_SRC_ANONYMOUS] = {
232 .name = "anonymous",
233 .flag = ANON_FLAGS,
234 },
235 [VM_MEM_SRC_ANONYMOUS_THP] = {
236 .name = "anonymous_thp",
237 .flag = ANON_FLAGS,
238 },
239 [VM_MEM_SRC_ANONYMOUS_HUGETLB] = {
240 .name = "anonymous_hugetlb",
241 .flag = ANON_HUGE_FLAGS,
242 },
243 [VM_MEM_SRC_ANONYMOUS_HUGETLB_16KB] = {
244 .name = "anonymous_hugetlb_16kb",
245 .flag = ANON_HUGE_FLAGS | MAP_HUGE_16KB,
246 },
247 [VM_MEM_SRC_ANONYMOUS_HUGETLB_64KB] = {
248 .name = "anonymous_hugetlb_64kb",
249 .flag = ANON_HUGE_FLAGS | MAP_HUGE_64KB,
250 },
251 [VM_MEM_SRC_ANONYMOUS_HUGETLB_512KB] = {
252 .name = "anonymous_hugetlb_512kb",
253 .flag = ANON_HUGE_FLAGS | MAP_HUGE_512KB,
254 },
255 [VM_MEM_SRC_ANONYMOUS_HUGETLB_1MB] = {
256 .name = "anonymous_hugetlb_1mb",
257 .flag = ANON_HUGE_FLAGS | MAP_HUGE_1MB,
258 },
259 [VM_MEM_SRC_ANONYMOUS_HUGETLB_2MB] = {
260 .name = "anonymous_hugetlb_2mb",
261 .flag = ANON_HUGE_FLAGS | MAP_HUGE_2MB,
262 },
263 [VM_MEM_SRC_ANONYMOUS_HUGETLB_8MB] = {
264 .name = "anonymous_hugetlb_8mb",
265 .flag = ANON_HUGE_FLAGS | MAP_HUGE_8MB,
266 },
267 [VM_MEM_SRC_ANONYMOUS_HUGETLB_16MB] = {
268 .name = "anonymous_hugetlb_16mb",
269 .flag = ANON_HUGE_FLAGS | MAP_HUGE_16MB,
270 },
271 [VM_MEM_SRC_ANONYMOUS_HUGETLB_32MB] = {
272 .name = "anonymous_hugetlb_32mb",
273 .flag = ANON_HUGE_FLAGS | MAP_HUGE_32MB,
274 },
275 [VM_MEM_SRC_ANONYMOUS_HUGETLB_256MB] = {
276 .name = "anonymous_hugetlb_256mb",
277 .flag = ANON_HUGE_FLAGS | MAP_HUGE_256MB,
278 },
279 [VM_MEM_SRC_ANONYMOUS_HUGETLB_512MB] = {
280 .name = "anonymous_hugetlb_512mb",
281 .flag = ANON_HUGE_FLAGS | MAP_HUGE_512MB,
282 },
283 [VM_MEM_SRC_ANONYMOUS_HUGETLB_1GB] = {
284 .name = "anonymous_hugetlb_1gb",
285 .flag = ANON_HUGE_FLAGS | MAP_HUGE_1GB,
286 },
287 [VM_MEM_SRC_ANONYMOUS_HUGETLB_2GB] = {
288 .name = "anonymous_hugetlb_2gb",
289 .flag = ANON_HUGE_FLAGS | MAP_HUGE_2GB,
290 },
291 [VM_MEM_SRC_ANONYMOUS_HUGETLB_16GB] = {
292 .name = "anonymous_hugetlb_16gb",
293 .flag = ANON_HUGE_FLAGS | MAP_HUGE_16GB,
294 },
295 [VM_MEM_SRC_SHMEM] = {
296 .name = "shmem",
297 .flag = MAP_SHARED,
298 },
299 [VM_MEM_SRC_SHARED_HUGETLB] = {
300 .name = "shared_hugetlb",
301 /*
302 * No MAP_HUGETLB, we use MFD_HUGETLB instead. Since
303 * we're using "file backed" memory, we need to specify
304 * this when the FD is created, not when the area is
305 * mapped.
306 */
307 .flag = MAP_SHARED,
308 },
309 };
310 _Static_assert(ARRAY_SIZE(aliases) == NUM_SRC_TYPES,
311 "Missing new backing src types?");
312
313 TEST_ASSERT(i < NUM_SRC_TYPES, "Backing src type ID %d too big", i);
314
315 return &aliases[i];
316 }
317
318 #define MAP_HUGE_PAGE_SIZE(x) (1ULL << ((x >> MAP_HUGE_SHIFT) & MAP_HUGE_MASK))
319
get_backing_src_pagesz(uint32_t i)320 size_t get_backing_src_pagesz(uint32_t i)
321 {
322 uint32_t flag = vm_mem_backing_src_alias(i)->flag;
323
324 switch (i) {
325 case VM_MEM_SRC_ANONYMOUS:
326 case VM_MEM_SRC_SHMEM:
327 return getpagesize();
328 case VM_MEM_SRC_ANONYMOUS_THP:
329 return get_trans_hugepagesz();
330 case VM_MEM_SRC_ANONYMOUS_HUGETLB:
331 case VM_MEM_SRC_SHARED_HUGETLB:
332 return get_def_hugetlb_pagesz();
333 default:
334 return MAP_HUGE_PAGE_SIZE(flag);
335 }
336 }
337
is_backing_src_hugetlb(uint32_t i)338 bool is_backing_src_hugetlb(uint32_t i)
339 {
340 return !!(vm_mem_backing_src_alias(i)->flag & MAP_HUGETLB);
341 }
342
print_available_backing_src_types(const char * prefix)343 static void print_available_backing_src_types(const char *prefix)
344 {
345 int i;
346
347 printf("%sAvailable backing src types:\n", prefix);
348
349 for (i = 0; i < NUM_SRC_TYPES; i++)
350 printf("%s %s\n", prefix, vm_mem_backing_src_alias(i)->name);
351 }
352
backing_src_help(const char * flag)353 void backing_src_help(const char *flag)
354 {
355 printf(" %s: specify the type of memory that should be used to\n"
356 " back the guest data region. (default: %s)\n",
357 flag, vm_mem_backing_src_alias(DEFAULT_VM_MEM_SRC)->name);
358 print_available_backing_src_types(" ");
359 }
360
parse_backing_src_type(const char * type_name)361 enum vm_mem_backing_src_type parse_backing_src_type(const char *type_name)
362 {
363 int i;
364
365 for (i = 0; i < NUM_SRC_TYPES; i++)
366 if (!strcmp(type_name, vm_mem_backing_src_alias(i)->name))
367 return i;
368
369 print_available_backing_src_types("");
370 TEST_FAIL("Unknown backing src type: %s", type_name);
371 return -1;
372 }
373
get_run_delay(void)374 long get_run_delay(void)
375 {
376 char path[64];
377 long val[2];
378 FILE *fp;
379
380 sprintf(path, "/proc/%ld/schedstat", syscall(SYS_gettid));
381 fp = fopen(path, "r");
382 /* Return MIN_RUN_DELAY_NS upon failure just to be safe */
383 if (fscanf(fp, "%ld %ld ", &val[0], &val[1]) < 2)
384 val[1] = MIN_RUN_DELAY_NS;
385 fclose(fp);
386
387 return val[1];
388 }
389
atoi_paranoid(const char * num_str)390 int atoi_paranoid(const char *num_str)
391 {
392 char *end_ptr;
393 long num;
394
395 errno = 0;
396 num = strtol(num_str, &end_ptr, 0);
397 TEST_ASSERT(!errno, "strtol(\"%s\") failed", num_str);
398 TEST_ASSERT(num_str != end_ptr,
399 "strtol(\"%s\") didn't find a valid integer.", num_str);
400 TEST_ASSERT(*end_ptr == '\0',
401 "strtol(\"%s\") failed to parse trailing characters \"%s\".",
402 num_str, end_ptr);
403 TEST_ASSERT(num >= INT_MIN && num <= INT_MAX,
404 "%ld not in range of [%d, %d]", num, INT_MIN, INT_MAX);
405
406 return num;
407 }
408
strdup_printf(const char * fmt,...)409 char *strdup_printf(const char *fmt, ...)
410 {
411 va_list ap;
412 char *str;
413
414 va_start(ap, fmt);
415 TEST_ASSERT(vasprintf(&str, fmt, ap) >= 0, "vasprintf() failed");
416 va_end(ap);
417
418 return str;
419 }
420
421 #define CLOCKSOURCE_PATH "/sys/devices/system/clocksource/clocksource0/current_clocksource"
422
sys_get_cur_clocksource(void)423 char *sys_get_cur_clocksource(void)
424 {
425 char *clk_name;
426 struct stat st;
427 FILE *fp;
428
429 fp = fopen(CLOCKSOURCE_PATH, "r");
430 TEST_ASSERT(fp, "failed to open clocksource file, errno: %d", errno);
431
432 TEST_ASSERT(!fstat(fileno(fp), &st), "failed to stat clocksource file, errno: %d",
433 errno);
434
435 clk_name = malloc(st.st_size);
436 TEST_ASSERT(clk_name, "failed to allocate buffer to read file");
437
438 TEST_ASSERT(fgets(clk_name, st.st_size, fp), "failed to read clocksource file: %d",
439 ferror(fp));
440
441 fclose(fp);
442
443 return clk_name;
444 }
445