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 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 != -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 != -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