xref: /minix/minix/lib/libvassert/vassert.c (revision 9f988b79)
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 
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 
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 
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 
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 
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 
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 
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 
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