1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2021 SUSE LLC <[email protected]>
4 *
5 * Minimal testing library for KVM tests
6 */
7
8 #include "kvm_test.h"
9
10 extern char kvm_heap_begin[];
11
12 static struct tst_kvm_result *const test_result =
13 (struct tst_kvm_result *)KVM_RESULT_BASEADDR;
14
15 static char *heap_end = kvm_heap_begin;
16
17 static struct tst_intr_handler {
18 tst_interrupt_callback callback;
19 void *userdata;
20 } intr_handlers[INTERRUPT_COUNT];
21
memset(void * dest,int val,size_t size)22 void *memset(void *dest, int val, size_t size)
23 {
24 char *ptr = dest;
25
26 while (size--)
27 *ptr++ = val;
28
29 return dest;
30 }
31
memzero(void * dest,size_t size)32 void *memzero(void *dest, size_t size)
33 {
34 return memset(dest, 0, size);
35 }
36
memcpy(void * dest,const void * src,size_t size)37 void *memcpy(void *dest, const void *src, size_t size)
38 {
39 char *dptr = dest;
40 const char *sptr = src;
41
42 while (size--)
43 *dptr++ = *sptr++;
44
45 return dest;
46 }
47
strcpy(char * dest,const char * src)48 char *strcpy(char *dest, const char *src)
49 {
50 char *ret = dest;
51
52 while ((*dest++ = *src++))
53 ;
54
55 return ret;
56 }
57
strcat(char * dest,const char * src)58 char *strcat(char *dest, const char *src)
59 {
60 char *ret = dest;
61
62 for (; *dest; dest++)
63 ;
64
65 strcpy(dest, src);
66 return ret;
67 }
68
strlen(const char * str)69 size_t strlen(const char *str)
70 {
71 size_t ret;
72
73 for (ret = 0; str[ret]; ret++)
74 ;
75
76 return ret;
77 }
78
strchr(const char * s,int c)79 char *strchr(const char *s, int c)
80 {
81 for (; *s; s++) {
82 if (*s == c)
83 return (char *)s;
84 }
85
86 return NULL;
87 }
88
strrchr(const char * s,int c)89 char *strrchr(const char *s, int c)
90 {
91 const char *ret = NULL;
92
93 for (; *s; s++) {
94 if (*s == c)
95 ret = s;
96 }
97
98 return (char *)ret;
99 }
100
101 #if defined(__x86_64__) && !defined(__ILP32__)
u64divu16(uint64_t a,uint16_t b)102 uint64_t u64divu16(uint64_t a, uint16_t b)
103 {
104 return a / b;
105 }
106
u64modu16(uint64_t a,uint16_t b)107 unsigned int u64modu16(uint64_t a, uint16_t b)
108 {
109 return a % b;
110 }
111
112 #else /* defined(__x86_64__) && !defined(__ILP32__) */
113
114 /* u64 short division helpers to avoid need to link libgcc on 32bit archs */
u64divu16(uint64_t a,uint16_t b)115 uint64_t u64divu16(uint64_t a, uint16_t b)
116 {
117 uint64_t ret = 0;
118 uint32_t tmp = a >> 32;
119
120 ret = tmp / b;
121 ret <<= 32;
122 tmp %= b;
123 tmp <<= 16;
124 tmp |= (a >> 16) & 0xffff;
125 ret |= (tmp / b) << 16;
126 tmp %= b;
127 tmp <<= 16;
128 tmp |= a & 0xffff;
129 ret |= tmp / b;
130 return ret;
131 }
132
u64modu16(uint64_t a,uint16_t b)133 unsigned int u64modu16(uint64_t a, uint16_t b)
134 {
135 uint32_t tmp = a >> 32;
136
137 tmp %= b;
138 tmp <<= 16;
139 tmp |= (a >> 16) & 0xffff;
140 tmp %= b;
141 tmp <<= 16;
142 tmp |= a & 0xffff;
143 return tmp % b;
144 }
145 #endif /* defined(__x86_64__) && !defined(__ILP32__) */
146
ptr2hex(char * dest,uintptr_t val)147 char *ptr2hex(char *dest, uintptr_t val)
148 {
149 unsigned int i;
150 uintptr_t tmp;
151 char *ret = dest;
152
153 for (i = 4, tmp = val >> 4; tmp; i += 4, tmp >>= 4)
154 ;
155
156 do {
157 i -= 4;
158 tmp = (val >> i) & 0xf;
159 *dest++ = tmp + (tmp >= 10 ? 'A' - 10 : '0');
160 } while (i);
161
162 *dest = '\0';
163 return ret;
164 }
165
u64tostr(char * dest,uint64_t val,uint16_t base,int caps)166 char *u64tostr(char *dest, uint64_t val, uint16_t base, int caps)
167 {
168 unsigned int i;
169 uintptr_t tmp = u64divu16(val, base);
170 char hex = caps ? 'A' : 'a';
171 char *ret = dest;
172
173 for (i = 1; tmp; i++, tmp = u64divu16(tmp, base))
174 ;
175
176 dest[i] = '\0';
177
178 do {
179 tmp = u64modu16(val, base);
180 dest[--i] = tmp + (tmp >= 10 ? hex - 10 : '0');
181 val = u64divu16(val, base);
182 } while (i);
183
184 return ret;
185 }
186
i64tostr(char * dest,int64_t val)187 char *i64tostr(char *dest, int64_t val)
188 {
189 if (val < 0) {
190 dest[0] = '-';
191 u64tostr(dest + 1, -val, 10, 0);
192 return dest;
193 }
194
195 return u64tostr(dest, val, 10, 0);
196 }
197
vsprintf(char * dest,const char * fmt,va_list ap)198 int vsprintf(char *dest, const char *fmt, va_list ap)
199 {
200 va_list args;
201 int ret = 0;
202 char conv;
203 uint64_t u64val = 0;
204 int64_t i64val = 0;
205 const char * const uint_conv = "ouxX";
206
207 va_copy(args, ap);
208
209 for (; *fmt; fmt++) {
210 if (*fmt != '%') {
211 dest[ret++] = *fmt;
212 continue;
213 }
214
215 conv = 0;
216 fmt++;
217
218 switch (*fmt) {
219 case '%':
220 dest[ret++] = *fmt;
221 break;
222
223 case 'c':
224 dest[ret++] = va_arg(args, int);
225 break;
226
227 case 's':
228 strcpy(dest + ret, va_arg(args, const char *));
229 ret += strlen(dest + ret);
230 break;
231
232 case 'p':
233 strcpy(dest + ret, "0x");
234 ptr2hex(dest + ret + 2,
235 (uintptr_t)va_arg(args, void *));
236 ret += strlen(dest + ret);
237 break;
238
239 case 'l':
240 fmt++;
241
242 switch (*fmt) {
243 case 'l':
244 fmt++;
245
246 if (*fmt == 'd' || *fmt == 'i') {
247 i64val = va_arg(args, long long);
248 conv = *fmt;
249 break;
250 }
251
252 if (strchr(uint_conv, *fmt)) {
253 u64val = va_arg(args,
254 unsigned long long);
255 conv = *fmt;
256 break;
257 }
258
259 va_end(args);
260 return -1;
261
262 case 'd':
263 case 'i':
264 i64val = va_arg(args, long);
265 conv = *fmt;
266 break;
267
268 default:
269 if (strchr(uint_conv, *fmt)) {
270 u64val = va_arg(args,
271 unsigned long);
272 conv = *fmt;
273 break;
274 }
275
276 va_end(args);
277 return -1;
278 }
279 break;
280
281 case 'h':
282 fmt++;
283
284 switch (*fmt) {
285 case 'h':
286 fmt++;
287
288 if (*fmt == 'd' || *fmt == 'i') {
289 i64val = (signed char)va_arg(args, int);
290 conv = *fmt;
291 break;
292 }
293
294 if (strchr(uint_conv, *fmt)) {
295 u64val = (unsigned char)va_arg(args,
296 unsigned int);
297 conv = *fmt;
298 break;
299 }
300
301 va_end(args);
302 return -1;
303
304 case 'd':
305 case 'i':
306 i64val = (short int)va_arg(args, int);
307 conv = *fmt;
308 break;
309
310 default:
311 if (strchr(uint_conv, *fmt)) {
312 u64val = (unsigned short int)va_arg(
313 args, unsigned int);
314 conv = *fmt;
315 break;
316 }
317
318 va_end(args);
319 return -1;
320 }
321 break;
322
323 case 'z':
324 fmt++;
325
326 if (*fmt == 'd' || *fmt == 'i') {
327 i64val = va_arg(args, ssize_t);
328 conv = *fmt;
329 break;
330 }
331
332 if (strchr(uint_conv, *fmt)) {
333 u64val = va_arg(args, size_t);
334 conv = *fmt;
335 break;
336 }
337
338 va_end(args);
339 return -1;
340
341 case 'd':
342 case 'i':
343 i64val = va_arg(args, int);
344 conv = *fmt;
345 break;
346
347 default:
348 if (strchr(uint_conv, *fmt)) {
349 u64val = va_arg(args, unsigned int);
350 conv = *fmt;
351 break;
352 }
353
354 va_end(args);
355 return -1;
356 }
357
358 switch (conv) {
359 case 0:
360 continue;
361
362 case 'd':
363 case 'i':
364 i64tostr(dest + ret, i64val);
365 ret += strlen(dest + ret);
366 break;
367
368 case 'o':
369 u64tostr(dest + ret, u64val, 8, 0);
370 ret += strlen(dest + ret);
371 break;
372
373 case 'u':
374 u64tostr(dest + ret, u64val, 10, 0);
375 ret += strlen(dest + ret);
376 break;
377
378 case 'x':
379 u64tostr(dest + ret, u64val, 16, 0);
380 ret += strlen(dest + ret);
381 break;
382
383 case 'X':
384 u64tostr(dest + ret, u64val, 16, 1);
385 ret += strlen(dest + ret);
386 break;
387
388 default:
389 va_end(args);
390 return -1;
391 }
392 }
393
394 va_end(args);
395 dest[ret++] = '\0';
396 return ret;
397 }
398
sprintf(char * dest,const char * fmt,...)399 int sprintf(char *dest, const char *fmt, ...)
400 {
401 va_list args;
402 int ret;
403
404 va_start(args, fmt);
405 ret = vsprintf(dest, fmt, args);
406 va_end(args);
407 return ret;
408 }
409
tst_heap_alloc_aligned(size_t size,size_t align)410 void *tst_heap_alloc_aligned(size_t size, size_t align)
411 {
412 uintptr_t addr = (uintptr_t)heap_end;
413 void *ret;
414
415 addr += align - 1;
416 addr -= addr % align;
417 ret = (void *)addr;
418 heap_end = (char *)LTP_ALIGN(addr + size, 4);
419 return ret;
420 }
421
tst_heap_alloc(size_t size)422 void *tst_heap_alloc(size_t size)
423 {
424 void *ret = heap_end;
425
426 heap_end += LTP_ALIGN(size, 4);
427 return ret;
428 }
429
tst_set_interrupt_callback(unsigned int vector,tst_interrupt_callback func,void * userdata)430 void tst_set_interrupt_callback(unsigned int vector,
431 tst_interrupt_callback func, void *userdata)
432 {
433 if (vector >= INTERRUPT_COUNT)
434 tst_brk(TBROK, "Set interrupt callback: vector out of range");
435
436 intr_handlers[vector].callback = func;
437 intr_handlers[vector].userdata = userdata;
438 }
439
tst_fatal_error(const char * file,const int lineno,const char * message,uintptr_t ip)440 static void tst_fatal_error(const char *file, const int lineno,
441 const char *message, uintptr_t ip)
442 {
443 test_result->result = TBROK;
444 test_result->lineno = lineno;
445 test_result->file_addr = (uintptr_t)file;
446 /* Avoid sprintf() here in case of bugs */
447 strcpy(test_result->message, message);
448 strcat(test_result->message, " at address 0x");
449 ptr2hex(test_result->message + strlen(test_result->message), ip);
450 kvm_yield();
451 kvm_exit();
452 }
453
tst_res_(const char * file,const int lineno,int result,const char * fmt,...)454 void tst_res_(const char *file, const int lineno, int result,
455 const char *fmt, ...)
456 {
457 va_list args;
458 int ret;
459
460 va_start(args, fmt);
461 test_result->result = result;
462 test_result->lineno = lineno;
463 test_result->file_addr = (uintptr_t)file;
464 ret = vsprintf(test_result->message, fmt, args);
465 va_end(args);
466
467 if (ret < 0) {
468 tst_brk_(file, lineno, TBROK, "Invalid tst_res() format: %s",
469 fmt);
470 }
471
472 kvm_yield();
473 }
474
tst_brk_(const char * file,const int lineno,int result,const char * fmt,...)475 void tst_brk_(const char *file, const int lineno, int result,
476 const char *fmt, ...)
477 {
478 va_list args;
479 int ret;
480
481 va_start(args, fmt);
482 test_result->result = result;
483 test_result->lineno = lineno;
484 test_result->file_addr = (uintptr_t)file;
485 ret = vsprintf(test_result->message, fmt, args);
486 va_end(args);
487
488 if (ret < 0) {
489 test_result->result = TBROK;
490 strcpy(test_result->message, "Invalid tst_brk() format: ");
491 strcat(test_result->message, fmt);
492 }
493
494 kvm_yield();
495 kvm_exit();
496 }
497
tst_signal_host(void * data)498 void tst_signal_host(void *data)
499 {
500 test_result->file_addr = (uintptr_t)data;
501 test_result->result = KVM_TSYNC;
502 }
503
tst_wait_host(void * data)504 void tst_wait_host(void *data)
505 {
506 volatile int32_t *vres = &test_result->result;
507
508 tst_signal_host(data);
509
510 while (*vres != KVM_TNONE)
511 ;
512 }
513
tst_handle_interrupt(struct kvm_interrupt_frame * ifrm,long vector,unsigned long errcode)514 void tst_handle_interrupt(struct kvm_interrupt_frame *ifrm, long vector,
515 unsigned long errcode)
516 {
517 uintptr_t ip = kvm_get_interrupt_ip(ifrm);
518 const char *iname;
519 tst_interrupt_callback callback;
520 int ret = 0;
521
522 if (vector < 0 || vector >= INTERRUPT_COUNT)
523 tst_fatal_error(__FILE__, __LINE__, "Unexpected interrupt", ip);
524
525 callback = intr_handlers[vector].callback;
526
527 if (callback)
528 ret = callback(intr_handlers[vector].userdata, ifrm, errcode);
529
530 iname = tst_interrupt_names[vector];
531 iname = iname ? iname : "Unexpected interrupt";
532
533 if (!ret)
534 tst_fatal_error(__FILE__, __LINE__, iname, ip);
535 }
536