xref: /minix3/minix/lib/libvassert/vassert.c (revision 65f76edb8f568553a5b4386b0c4917803d47e97d)
1433d6423SLionel Sambuc #include <string.h>
2433d6423SLionel Sambuc #include <stdarg.h>
3433d6423SLionel Sambuc #include <signal.h>
4433d6423SLionel Sambuc #include <setjmp.h>
5433d6423SLionel Sambuc #include <minix/config.h>
6433d6423SLionel Sambuc #include <minix/const.h>
7433d6423SLionel Sambuc #include <minix/ipc.h>
8433d6423SLionel Sambuc #include <minix/com.h>
9433d6423SLionel Sambuc #include <minix/syslib.h>
10433d6423SLionel Sambuc #include <machine/stackframe.h>
11433d6423SLionel Sambuc #include "vassert.h"
12433d6423SLionel Sambuc 
13433d6423SLionel Sambuc VAssert_StateWrapper vassert_state ALIGNED(VASSERT_PAGE_SIZE);
14433d6423SLionel Sambuc 
15433d6423SLionel Sambuc #define TRUE 1
16433d6423SLionel Sambuc #define FALSE 0
17433d6423SLionel Sambuc 
18433d6423SLionel Sambuc #define MAGIC_CMD  0x564d5868
19433d6423SLionel Sambuc #define MAGIC_PORT 0x5658
20433d6423SLionel Sambuc #define HIGH_BAND_PORT 0x5659
21433d6423SLionel Sambuc 
22433d6423SLionel Sambuc #define BACKDOOR_PORT 		51
23433d6423SLionel Sambuc #define BACKDOOR_HB_PORT	1
24433d6423SLionel Sambuc #define CMD_SET_ADDRESS 	BACKDOOR_PORT|(1<<16)
25433d6423SLionel Sambuc #define CMD_RETURN_REPLAY 	BACKDOOR_PORT|(2<<16)
26433d6423SLionel Sambuc #define CMD_GO_LIVE		BACKDOOR_PORT|(3<<16)
27433d6423SLionel Sambuc #define CMD_LOG			BACKDOOR_HB_PORT|(4<<16)
28433d6423SLionel Sambuc #define CMD_SET_RECORD		47
29433d6423SLionel Sambuc 
30433d6423SLionel Sambuc #define LOG_MAX 512
31433d6423SLionel Sambuc 
32433d6423SLionel Sambuc typedef char Bool;
33433d6423SLionel Sambuc typedef unsigned int uint32;
34433d6423SLionel Sambuc typedef unsigned long long uint64;
35433d6423SLionel Sambuc 
36433d6423SLionel Sambuc #ifdef VM_X86_64
37433d6423SLionel Sambuc typedef uint64 VA;
38433d6423SLionel Sambuc #else
39433d6423SLionel Sambuc typedef uint32 VA;
40433d6423SLionel Sambuc #endif
41433d6423SLionel Sambuc 
42433d6423SLionel Sambuc static sigjmp_buf segv_jmp;
43433d6423SLionel Sambuc 
44433d6423SLionel Sambuc void libvassert_process_backdoor(uint32, uint32, uint32, reg_t *, reg_t *,
45433d6423SLionel Sambuc 				 reg_t *, reg_t *);
46433d6423SLionel Sambuc 
47433d6423SLionel Sambuc /*
48433d6423SLionel Sambuc  *---------------------------------------------------------------------
49433d6423SLionel Sambuc  *
50433d6423SLionel Sambuc  * sig_segv --
51433d6423SLionel Sambuc  *
52433d6423SLionel Sambuc  *    Customed SEGV signal handler for VAssert_IsInVM.
53433d6423SLionel Sambuc  *
54433d6423SLionel Sambuc  * Results:
55433d6423SLionel Sambuc  *
56433d6423SLionel Sambuc  *    None.
57433d6423SLionel Sambuc  *
58433d6423SLionel Sambuc  * Side effects:
59433d6423SLionel Sambuc  *    None.
60433d6423SLionel Sambuc  *
61433d6423SLionel Sambuc  *---------------------------------------------------------------------
62433d6423SLionel Sambuc  */
63433d6423SLionel Sambuc 
sig_segv(int sig_no)64*65f76edbSDavid van Moolenbroek static void __dead sig_segv(int sig_no)
65433d6423SLionel Sambuc {
66433d6423SLionel Sambuc    /* jumping to error handling in VAssert_IsInVM. */
67433d6423SLionel Sambuc    siglongjmp(segv_jmp, 1);
68433d6423SLionel Sambuc }
69433d6423SLionel Sambuc 
70433d6423SLionel Sambuc 
71433d6423SLionel Sambuc /*
72433d6423SLionel Sambuc  *---------------------------------------------------------------------
73433d6423SLionel Sambuc  *
74433d6423SLionel Sambuc  * VAssert_IsInVM --
75433d6423SLionel Sambuc  *
76433d6423SLionel Sambuc  *    Check if we are in virtual world.
77433d6423SLionel Sambuc  *
78433d6423SLionel Sambuc  * Results:
79433d6423SLionel Sambuc  *
80433d6423SLionel Sambuc  *    Return TRUE on success, or FALSE on failure.
81433d6423SLionel Sambuc  *
82433d6423SLionel Sambuc  * Side effects:
83433d6423SLionel Sambuc  *    None.
84433d6423SLionel Sambuc  *
85433d6423SLionel Sambuc  *---------------------------------------------------------------------
86433d6423SLionel Sambuc  */
87433d6423SLionel Sambuc 
VAssert_IsInVM(void)88433d6423SLionel Sambuc static Bool VAssert_IsInVM(void)
89433d6423SLionel Sambuc {
90433d6423SLionel Sambuc    uint32 eax, ebx, ecx, edx;
91433d6423SLionel Sambuc    static Bool inVM = FALSE;
92433d6423SLionel Sambuc    static Bool tested = FALSE;
93433d6423SLionel Sambuc    if (!tested) {
94433d6423SLionel Sambuc       /* Error handling. */
95433d6423SLionel Sambuc       if (sigsetjmp(segv_jmp, 0) != 0) {
96433d6423SLionel Sambuc          signal(SIGSEGV, SIG_DFL);
97433d6423SLionel Sambuc          inVM = FALSE;
98433d6423SLionel Sambuc          return inVM;
99433d6423SLionel Sambuc       }
100433d6423SLionel Sambuc       tested = TRUE;
101433d6423SLionel Sambuc       /* Install custom handler. */
102433d6423SLionel Sambuc       signal(SIGSEGV, sig_segv);
103433d6423SLionel Sambuc       /* Test if we are in a VM. */
104433d6423SLionel Sambuc       libvassert_process_backdoor(0x0a, 0, MAGIC_PORT, &eax, &ebx, &ecx, &edx);
105433d6423SLionel Sambuc       signal(SIGSEGV, SIG_DFL);
106433d6423SLionel Sambuc       inVM = TRUE;
107433d6423SLionel Sambuc    }
108433d6423SLionel Sambuc    return inVM;
109433d6423SLionel Sambuc }
110433d6423SLionel Sambuc 
111433d6423SLionel Sambuc 
112433d6423SLionel Sambuc /*
113433d6423SLionel Sambuc  *---------------------------------------------------------------------
114433d6423SLionel Sambuc  *
115433d6423SLionel Sambuc  * VAssert_Init --
116433d6423SLionel Sambuc  *
117433d6423SLionel Sambuc  *    Tell vmx that vassert is inited.
118433d6423SLionel Sambuc  *
119433d6423SLionel Sambuc  * Results:
120433d6423SLionel Sambuc  *
121433d6423SLionel Sambuc  *    Return 0 on success, or -1 on failure.
122433d6423SLionel Sambuc  *
123433d6423SLionel Sambuc  * Side effects:
124433d6423SLionel Sambuc  *    None
125433d6423SLionel Sambuc  *
126433d6423SLionel Sambuc  *---------------------------------------------------------------------
127433d6423SLionel Sambuc  */
128433d6423SLionel Sambuc 
VAssert_Init(void)129433d6423SLionel Sambuc char VAssert_Init(void)
130433d6423SLionel Sambuc {
131433d6423SLionel Sambuc    uint32 eax, ebx, ecx, edx;
132433d6423SLionel Sambuc    VA page_address = (VA) &vassert_state.inReplay;
133433d6423SLionel Sambuc    if (!VAssert_IsInVM()) {
134433d6423SLionel Sambuc       return -1;
135433d6423SLionel Sambuc    }
136433d6423SLionel Sambuc    bzero((char*) &vassert_state, sizeof vassert_state);
137433d6423SLionel Sambuc #ifndef __minix
138433d6423SLionel Sambuc    /* Lock the page. */
139433d6423SLionel Sambuc    if (mlock(&vassert_state, sizeof vassert_state)) {
140433d6423SLionel Sambuc       return -1;
141433d6423SLionel Sambuc    }
142433d6423SLionel Sambuc #endif
143433d6423SLionel Sambuc 
144433d6423SLionel Sambuc    libvassert_process_backdoor(CMD_SET_ADDRESS, page_address,
145433d6423SLionel Sambuc    	MAGIC_PORT|(1<<16), &eax, &ebx, &ecx, &edx);
146433d6423SLionel Sambuc 
147*65f76edbSDavid van Moolenbroek    return (eax != (uint32)-1) ? 0 : -1;
148433d6423SLionel Sambuc }
149433d6423SLionel Sambuc 
150433d6423SLionel Sambuc 
151433d6423SLionel Sambuc /*
152433d6423SLionel Sambuc  *---------------------------------------------------------------------
153433d6423SLionel Sambuc  *
154433d6423SLionel Sambuc  * VAssert_Uninit --
155433d6423SLionel Sambuc  *
156433d6423SLionel Sambuc  *    Tell vmx that vassert is finalized.
157433d6423SLionel Sambuc  *
158433d6423SLionel Sambuc  * Results:
159433d6423SLionel Sambuc  *
160433d6423SLionel Sambuc  *    Return 0 on success, or -1 on failure.
161433d6423SLionel Sambuc  *
162433d6423SLionel Sambuc  * Side effects:
163433d6423SLionel Sambuc  *    None
164433d6423SLionel Sambuc  *
165433d6423SLionel Sambuc  *---------------------------------------------------------------------
166433d6423SLionel Sambuc  */
167433d6423SLionel Sambuc 
VAssert_Uninit(void)168433d6423SLionel Sambuc char VAssert_Uninit(void)
169433d6423SLionel Sambuc {
170433d6423SLionel Sambuc    unsigned int eax, ebx, ecx, edx;
171433d6423SLionel Sambuc    if (!VAssert_IsInVM()) {
172433d6423SLionel Sambuc       return -1;
173433d6423SLionel Sambuc    }
174433d6423SLionel Sambuc    libvassert_process_backdoor(CMD_SET_ADDRESS, 0, MAGIC_PORT|(0<<16), &eax, &ebx, &ecx, &edx);
175*65f76edbSDavid van Moolenbroek    return (eax != (unsigned int)-1) ? 0 : 1;
176433d6423SLionel Sambuc }
177433d6423SLionel Sambuc 
178433d6423SLionel Sambuc 
179433d6423SLionel Sambuc /*
180433d6423SLionel Sambuc  *---------------------------------------------------------------------
181433d6423SLionel Sambuc  *
182433d6423SLionel Sambuc  * VAssert_LogMain --
183433d6423SLionel Sambuc  *
184433d6423SLionel Sambuc  *    Print message to a text file on host side.
185433d6423SLionel Sambuc  *
186433d6423SLionel Sambuc  * Results:
187433d6423SLionel Sambuc  *    None
188433d6423SLionel Sambuc  *
189433d6423SLionel Sambuc  * Side effects:
190433d6423SLionel Sambuc  *    Write to a text file with fixed name.
191433d6423SLionel Sambuc  *    If the file exists, host UI will ask for append/replace/ignore
192433d6423SLionel Sambuc  *
193433d6423SLionel Sambuc  *---------------------------------------------------------------------
194433d6423SLionel Sambuc  */
195433d6423SLionel Sambuc 
VAssert_LogMain(const char * format,...)196433d6423SLionel Sambuc void VAssert_LogMain(const char *format, ...)
197433d6423SLionel Sambuc {
198433d6423SLionel Sambuc    unsigned int eax, ebx, ecx, edx;
199433d6423SLionel Sambuc    char buf[LOG_MAX];
200433d6423SLionel Sambuc    unsigned int len = 0;
201433d6423SLionel Sambuc    va_list ap;
202433d6423SLionel Sambuc    va_start(ap, format);
203433d6423SLionel Sambuc    len = vsnprintf(buf, LOG_MAX, format, ap);
204433d6423SLionel Sambuc    va_end(ap);
205433d6423SLionel Sambuc    __asm__ __volatile__("cld; rep outsb;"
206433d6423SLionel Sambuc                         : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
207433d6423SLionel Sambuc                         : "0"(MAGIC_CMD), "1"(CMD_LOG), "2"(len), "d"(HIGH_BAND_PORT), "S"(buf)
208433d6423SLionel Sambuc                         : "memory"
209433d6423SLionel Sambuc                        );
210433d6423SLionel Sambuc }
211433d6423SLionel Sambuc 
212433d6423SLionel Sambuc 
213433d6423SLionel Sambuc /*
214433d6423SLionel Sambuc  *---------------------------------------------------------------------
215433d6423SLionel Sambuc  *
216433d6423SLionel Sambuc  * VAssert_GoLiveMain --
217433d6423SLionel Sambuc  *
218433d6423SLionel Sambuc  *    Make the vm which is in replay exit replay.
219433d6423SLionel Sambuc  *
220433d6423SLionel Sambuc  * Results:
221433d6423SLionel Sambuc  *    None
222433d6423SLionel Sambuc  *
223433d6423SLionel Sambuc  * Side effects:
224433d6423SLionel Sambuc  *    Replay is stopped.
225433d6423SLionel Sambuc  *
226433d6423SLionel Sambuc  *---------------------------------------------------------------------
227433d6423SLionel Sambuc  */
228433d6423SLionel Sambuc 
VAssert_GoLiveMain(void)229433d6423SLionel Sambuc void VAssert_GoLiveMain(void)
230433d6423SLionel Sambuc {
231433d6423SLionel Sambuc    unsigned int eax, ebx, ecx, edx;
232433d6423SLionel Sambuc    vassert_state.inReplay = 0;
233433d6423SLionel Sambuc    libvassert_process_backdoor(CMD_GO_LIVE, 0, MAGIC_PORT, &eax, &ebx, &ecx, &edx);
234433d6423SLionel Sambuc }
235433d6423SLionel Sambuc 
236433d6423SLionel Sambuc 
237433d6423SLionel Sambuc /*
238433d6423SLionel Sambuc  *---------------------------------------------------------------------
239433d6423SLionel Sambuc  *
240433d6423SLionel Sambuc  * VAssert_ReturnToReplayMain --
241433d6423SLionel Sambuc  *
242433d6423SLionel Sambuc  *    Called after the custom work is done, and replay is to continue.
243433d6423SLionel Sambuc  *
244433d6423SLionel Sambuc  * Results:
245433d6423SLionel Sambuc  *    None
246433d6423SLionel Sambuc  *
247433d6423SLionel Sambuc  * Side effects:
248433d6423SLionel Sambuc  *    Replay is continued from pause.
249433d6423SLionel Sambuc  *
250433d6423SLionel Sambuc  *---------------------------------------------------------------------
251433d6423SLionel Sambuc  */
252433d6423SLionel Sambuc 
VAssert_ReturnToReplayMain(void)253433d6423SLionel Sambuc void VAssert_ReturnToReplayMain(void)
254433d6423SLionel Sambuc {
255433d6423SLionel Sambuc    unsigned int eax, ebx, ecx, edx;
256433d6423SLionel Sambuc    libvassert_process_backdoor(CMD_RETURN_REPLAY, 0, MAGIC_PORT, &eax, &ebx, &ecx, &edx);
257433d6423SLionel Sambuc }
258433d6423SLionel Sambuc 
259433d6423SLionel Sambuc 
260433d6423SLionel Sambuc /*
261433d6423SLionel Sambuc  *---------------------------------------------------------------------
262433d6423SLionel Sambuc  *
263433d6423SLionel Sambuc  * VAssert_SetRecordingMain --
264433d6423SLionel Sambuc  *
265433d6423SLionel Sambuc  *    Ask vmx for starting or stopping recording.
266433d6423SLionel Sambuc  *
267433d6423SLionel Sambuc  * Results:
268433d6423SLionel Sambuc  *
269433d6423SLionel Sambuc  *    Return TRUE on success, or FALSE on failure.
270433d6423SLionel Sambuc  *
271433d6423SLionel Sambuc  * Side effects:
272433d6423SLionel Sambuc  *    Recording is started or stopped.
273433d6423SLionel Sambuc  *
274433d6423SLionel Sambuc  *---------------------------------------------------------------------
275433d6423SLionel Sambuc  */
276433d6423SLionel Sambuc 
VAssert_SetRecordingMain(char start)277433d6423SLionel Sambuc char VAssert_SetRecordingMain(char start)
278433d6423SLionel Sambuc {
279433d6423SLionel Sambuc    uint32 eax, ebx, ecx, edx;
280433d6423SLionel Sambuc    if (!VAssert_IsInVM()) {
281433d6423SLionel Sambuc       return FALSE;
282433d6423SLionel Sambuc    }
283433d6423SLionel Sambuc    libvassert_process_backdoor(CMD_SET_RECORD, start ? 1 : 2, MAGIC_PORT, &eax, &ebx, &ecx, &edx);
284433d6423SLionel Sambuc    return (eax == 1) ? TRUE : FALSE;
285433d6423SLionel Sambuc }
286433d6423SLionel Sambuc 
287