1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2021 SUSE LLC <mdoucha@suse.cz>
4 *
5 * Minimal testing library for KVM tests
6 */
7
8#include "kvm_test.h"
9
10extern char kvm_heap_begin[];
11
12static struct tst_kvm_result *const test_result =
13	(struct tst_kvm_result *)KVM_RESULT_BASEADDR;
14
15static char *heap_end = kvm_heap_begin;
16
17static struct tst_intr_handler {
18	tst_interrupt_callback callback;
19	void *userdata;
20} intr_handlers[INTERRUPT_COUNT];
21
22void *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
32void *memzero(void *dest, size_t size)
33{
34	return memset(dest, 0, size);
35}
36
37void *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
48char *strcpy(char *dest, const char *src)
49{
50	char *ret = dest;
51
52	while ((*dest++ = *src++))
53		;
54
55	return ret;
56}
57
58char *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
69size_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
79char *ptr2hex(char *dest, uintptr_t val)
80{
81	unsigned int i;
82	uintptr_t tmp;
83	char *ret = dest;
84
85	for (i = 4, tmp = val >> 4; tmp; i += 4, tmp >>= 4)
86		;
87
88	do {
89		i -= 4;
90		tmp = (val >> i) & 0xf;
91		*dest++ = tmp + (tmp >= 10 ? 'A' - 10 : '0');
92	} while (i);
93
94	*dest = '\0';
95	return ret;
96}
97
98void *tst_heap_alloc_aligned(size_t size, size_t align)
99{
100	uintptr_t addr = (uintptr_t)heap_end;
101	void *ret;
102
103	addr += align - 1;
104	addr -= addr % align;
105	ret = (void *)addr;
106	heap_end = (char *)LTP_ALIGN(addr + size, 4);
107	return ret;
108}
109
110void *tst_heap_alloc(size_t size)
111{
112	void *ret = heap_end;
113
114	heap_end += LTP_ALIGN(size, 4);
115	return ret;
116}
117
118void tst_set_interrupt_callback(unsigned int vector,
119	tst_interrupt_callback func, void *userdata)
120{
121	if (vector >= INTERRUPT_COUNT)
122		tst_brk(TBROK, "Set interrupt callback: vector out of range");
123
124	intr_handlers[vector].callback = func;
125	intr_handlers[vector].userdata = userdata;
126}
127
128static void tst_fatal_error(const char *file, const int lineno,
129	const char *message, uintptr_t ip)
130{
131	test_result->result = TBROK;
132	test_result->lineno = lineno;
133	test_result->file_addr = (uintptr_t)file;
134	strcpy(test_result->message, message);
135	strcat(test_result->message, " at address 0x");
136	ptr2hex(test_result->message + strlen(test_result->message), ip);
137	kvm_yield();
138	kvm_exit();
139}
140
141void tst_res_(const char *file, const int lineno, int result,
142	const char *message)
143{
144	test_result->result = result;
145	test_result->lineno = lineno;
146	test_result->file_addr = (uintptr_t)file;
147	strcpy(test_result->message, message);
148	kvm_yield();
149}
150
151void tst_brk_(const char *file, const int lineno, int result,
152	const char *message)
153{
154	tst_res_(file, lineno, result, message);
155	kvm_exit();
156}
157
158void tst_signal_host(void *data)
159{
160	test_result->file_addr = (uintptr_t)data;
161	test_result->result = KVM_TSYNC;
162}
163
164void tst_wait_host(void *data)
165{
166	volatile int32_t *vres = &test_result->result;
167
168	tst_signal_host(data);
169
170	while (*vres != KVM_TNONE)
171		;
172}
173
174void tst_handle_interrupt(struct kvm_interrupt_frame *ifrm, long vector,
175	unsigned long errcode)
176{
177	uintptr_t ip = kvm_get_interrupt_ip(ifrm);
178	const char *iname;
179	tst_interrupt_callback callback;
180	int ret = 0;
181
182	if (vector < 0 || vector >= INTERRUPT_COUNT)
183		tst_fatal_error(__FILE__, __LINE__, "Unexpected interrupt", ip);
184
185	callback = intr_handlers[vector].callback;
186
187	if (callback)
188		ret = callback(intr_handlers[vector].userdata, ifrm, errcode);
189
190	iname = tst_interrupt_names[vector];
191	iname = iname ? iname : "Unexpected interrupt";
192
193	if (!ret)
194		tst_fatal_error(__FILE__, __LINE__, iname, ip);
195}
196