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
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
ptr2hex(char * dest,uintptr_t val)79 char *ptr2hex(char *dest, uintptr_t val)
80 {
81 unsigned int i;
82 uintptr_t tmp;
83 char *ret = dest;
84
85 for (i = 4; val >> i; i += 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
tst_heap_alloc_aligned(size_t size,size_t align)98 void *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
tst_heap_alloc(size_t size)110 void *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
tst_set_interrupt_callback(unsigned int vector,tst_interrupt_callback func,void * userdata)118 void 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
tst_fatal_error(const char * file,const int lineno,const char * message,uintptr_t ip)128 static 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
tst_res_(const char * file,const int lineno,int result,const char * message)141 void 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
tst_brk_(const char * file,const int lineno,int result,const char * message)151 void 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
tst_handle_interrupt(struct kvm_interrupt_frame * ifrm,long vector,unsigned long errcode)158 void tst_handle_interrupt(struct kvm_interrupt_frame *ifrm, long vector,
159 unsigned long errcode)
160 {
161 uintptr_t ip = kvm_get_interrupt_ip(ifrm);
162 const char *iname;
163 tst_interrupt_callback callback;
164 int ret = 0;
165
166 if (vector < 0 || vector >= INTERRUPT_COUNT)
167 tst_fatal_error(__FILE__, __LINE__, "Unexpected interrupt", ip);
168
169 callback = intr_handlers[vector].callback;
170
171 if (callback)
172 ret = callback(intr_handlers[vector].userdata, ifrm, errcode);
173
174 iname = tst_interrupt_names[vector];
175 iname = iname ? iname : "Unexpected interrupt";
176
177 if (!ret)
178 tst_fatal_error(__FILE__, __LINE__, iname, ip);
179 }
180