xref: /aosp_15_r20/external/ltp/testcases/kernel/kvm/lib_guest.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
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