1 #include <string.h>
2 #include <stdarg.h>
3 #include <signal.h>
4 #include <setjmp.h>
5 #include <minix/config.h>
6 #include <minix/const.h>
7 #include <minix/ipc.h>
8 #include <minix/com.h>
9 #include <minix/syslib.h>
10 #include <machine/stackframe.h>
11 #include "vassert.h"
12
13 VAssert_StateWrapper vassert_state ALIGNED(VASSERT_PAGE_SIZE);
14
15 #define TRUE 1
16 #define FALSE 0
17
18 #define MAGIC_CMD 0x564d5868
19 #define MAGIC_PORT 0x5658
20 #define HIGH_BAND_PORT 0x5659
21
22 #define BACKDOOR_PORT 51
23 #define BACKDOOR_HB_PORT 1
24 #define CMD_SET_ADDRESS BACKDOOR_PORT|(1<<16)
25 #define CMD_RETURN_REPLAY BACKDOOR_PORT|(2<<16)
26 #define CMD_GO_LIVE BACKDOOR_PORT|(3<<16)
27 #define CMD_LOG BACKDOOR_HB_PORT|(4<<16)
28 #define CMD_SET_RECORD 47
29
30 #define LOG_MAX 512
31
32 typedef char Bool;
33 typedef unsigned int uint32;
34 typedef unsigned long long uint64;
35
36 #ifdef VM_X86_64
37 typedef uint64 VA;
38 #else
39 typedef uint32 VA;
40 #endif
41
42 static sigjmp_buf segv_jmp;
43
44 void libvassert_process_backdoor(uint32, uint32, uint32, reg_t *, reg_t *,
45 reg_t *, reg_t *);
46
47 /*
48 *---------------------------------------------------------------------
49 *
50 * sig_segv --
51 *
52 * Customed SEGV signal handler for VAssert_IsInVM.
53 *
54 * Results:
55 *
56 * None.
57 *
58 * Side effects:
59 * None.
60 *
61 *---------------------------------------------------------------------
62 */
63
sig_segv(int sig_no)64 static void __dead sig_segv(int sig_no)
65 {
66 /* jumping to error handling in VAssert_IsInVM. */
67 siglongjmp(segv_jmp, 1);
68 }
69
70
71 /*
72 *---------------------------------------------------------------------
73 *
74 * VAssert_IsInVM --
75 *
76 * Check if we are in virtual world.
77 *
78 * Results:
79 *
80 * Return TRUE on success, or FALSE on failure.
81 *
82 * Side effects:
83 * None.
84 *
85 *---------------------------------------------------------------------
86 */
87
VAssert_IsInVM(void)88 static Bool VAssert_IsInVM(void)
89 {
90 uint32 eax, ebx, ecx, edx;
91 static Bool inVM = FALSE;
92 static Bool tested = FALSE;
93 if (!tested) {
94 /* Error handling. */
95 if (sigsetjmp(segv_jmp, 0) != 0) {
96 signal(SIGSEGV, SIG_DFL);
97 inVM = FALSE;
98 return inVM;
99 }
100 tested = TRUE;
101 /* Install custom handler. */
102 signal(SIGSEGV, sig_segv);
103 /* Test if we are in a VM. */
104 libvassert_process_backdoor(0x0a, 0, MAGIC_PORT, &eax, &ebx, &ecx, &edx);
105 signal(SIGSEGV, SIG_DFL);
106 inVM = TRUE;
107 }
108 return inVM;
109 }
110
111
112 /*
113 *---------------------------------------------------------------------
114 *
115 * VAssert_Init --
116 *
117 * Tell vmx that vassert is inited.
118 *
119 * Results:
120 *
121 * Return 0 on success, or -1 on failure.
122 *
123 * Side effects:
124 * None
125 *
126 *---------------------------------------------------------------------
127 */
128
VAssert_Init(void)129 char VAssert_Init(void)
130 {
131 uint32 eax, ebx, ecx, edx;
132 VA page_address = (VA) &vassert_state.inReplay;
133 if (!VAssert_IsInVM()) {
134 return -1;
135 }
136 bzero((char*) &vassert_state, sizeof vassert_state);
137 #ifndef __minix
138 /* Lock the page. */
139 if (mlock(&vassert_state, sizeof vassert_state)) {
140 return -1;
141 }
142 #endif
143
144 libvassert_process_backdoor(CMD_SET_ADDRESS, page_address,
145 MAGIC_PORT|(1<<16), &eax, &ebx, &ecx, &edx);
146
147 return (eax != (uint32)-1) ? 0 : -1;
148 }
149
150
151 /*
152 *---------------------------------------------------------------------
153 *
154 * VAssert_Uninit --
155 *
156 * Tell vmx that vassert is finalized.
157 *
158 * Results:
159 *
160 * Return 0 on success, or -1 on failure.
161 *
162 * Side effects:
163 * None
164 *
165 *---------------------------------------------------------------------
166 */
167
VAssert_Uninit(void)168 char VAssert_Uninit(void)
169 {
170 unsigned int eax, ebx, ecx, edx;
171 if (!VAssert_IsInVM()) {
172 return -1;
173 }
174 libvassert_process_backdoor(CMD_SET_ADDRESS, 0, MAGIC_PORT|(0<<16), &eax, &ebx, &ecx, &edx);
175 return (eax != (unsigned int)-1) ? 0 : 1;
176 }
177
178
179 /*
180 *---------------------------------------------------------------------
181 *
182 * VAssert_LogMain --
183 *
184 * Print message to a text file on host side.
185 *
186 * Results:
187 * None
188 *
189 * Side effects:
190 * Write to a text file with fixed name.
191 * If the file exists, host UI will ask for append/replace/ignore
192 *
193 *---------------------------------------------------------------------
194 */
195
VAssert_LogMain(const char * format,...)196 void VAssert_LogMain(const char *format, ...)
197 {
198 unsigned int eax, ebx, ecx, edx;
199 char buf[LOG_MAX];
200 unsigned int len = 0;
201 va_list ap;
202 va_start(ap, format);
203 len = vsnprintf(buf, LOG_MAX, format, ap);
204 va_end(ap);
205 __asm__ __volatile__("cld; rep outsb;"
206 : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
207 : "0"(MAGIC_CMD), "1"(CMD_LOG), "2"(len), "d"(HIGH_BAND_PORT), "S"(buf)
208 : "memory"
209 );
210 }
211
212
213 /*
214 *---------------------------------------------------------------------
215 *
216 * VAssert_GoLiveMain --
217 *
218 * Make the vm which is in replay exit replay.
219 *
220 * Results:
221 * None
222 *
223 * Side effects:
224 * Replay is stopped.
225 *
226 *---------------------------------------------------------------------
227 */
228
VAssert_GoLiveMain(void)229 void VAssert_GoLiveMain(void)
230 {
231 unsigned int eax, ebx, ecx, edx;
232 vassert_state.inReplay = 0;
233 libvassert_process_backdoor(CMD_GO_LIVE, 0, MAGIC_PORT, &eax, &ebx, &ecx, &edx);
234 }
235
236
237 /*
238 *---------------------------------------------------------------------
239 *
240 * VAssert_ReturnToReplayMain --
241 *
242 * Called after the custom work is done, and replay is to continue.
243 *
244 * Results:
245 * None
246 *
247 * Side effects:
248 * Replay is continued from pause.
249 *
250 *---------------------------------------------------------------------
251 */
252
VAssert_ReturnToReplayMain(void)253 void VAssert_ReturnToReplayMain(void)
254 {
255 unsigned int eax, ebx, ecx, edx;
256 libvassert_process_backdoor(CMD_RETURN_REPLAY, 0, MAGIC_PORT, &eax, &ebx, &ecx, &edx);
257 }
258
259
260 /*
261 *---------------------------------------------------------------------
262 *
263 * VAssert_SetRecordingMain --
264 *
265 * Ask vmx for starting or stopping recording.
266 *
267 * Results:
268 *
269 * Return TRUE on success, or FALSE on failure.
270 *
271 * Side effects:
272 * Recording is started or stopped.
273 *
274 *---------------------------------------------------------------------
275 */
276
VAssert_SetRecordingMain(char start)277 char VAssert_SetRecordingMain(char start)
278 {
279 uint32 eax, ebx, ecx, edx;
280 if (!VAssert_IsInVM()) {
281 return FALSE;
282 }
283 libvassert_process_backdoor(CMD_SET_RECORD, start ? 1 : 2, MAGIC_PORT, &eax, &ebx, &ecx, &edx);
284 return (eax == 1) ? TRUE : FALSE;
285 }
286
287