--- /dev/null
+#include <string.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <minix/config.h>
+#include <minix/const.h>
+#include <minix/ipc.h>
+#include <minix/com.h>
+#include "vassert.h"
+
+VAssert_StateWrapper vassert_state ALIGNED(VASSERT_PAGE_SIZE);
+
+#define TRUE 1
+#define FALSE 0
+
+#define MAGIC_CMD 0x564d5868
+#define MAGIC_PORT 0x5658
+#define HIGH_BAND_PORT 0x5659
+
+#define BACKDOOR_PORT 51
+#define BACKDOOR_HB_PORT 1
+#define CMD_SET_ADDRESS BACKDOOR_PORT|(1<<16)
+#define CMD_RETURN_REPLAY BACKDOOR_PORT|(2<<16)
+#define CMD_GO_LIVE BACKDOOR_PORT|(3<<16)
+#define CMD_LOG BACKDOOR_HB_PORT|(4<<16)
+#define CMD_SET_RECORD 47
+
+#define LOG_MAX 512
+
+typedef char Bool;
+typedef unsigned int uint32;
+typedef unsigned long long uint64;
+
+#ifdef VM_X86_64
+typedef uint64 VA;
+#else
+typedef uint32 VA;
+#endif
+
+static sigjmp_buf segv_jmp;
+
+/*
+ *---------------------------------------------------------------------
+ *
+ * sig_segv --
+ *
+ * Customed SEGV signal handler for VAssert_IsInVM.
+ *
+ * Results:
+ *
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------
+ */
+
+static void
+sig_segv(int sig_no)
+{
+ /* jumping to error handling in VAssert_IsInVM. */
+ siglongjmp(segv_jmp, 1);
+}
+
+
+/*
+ *---------------------------------------------------------------------
+ *
+ * VAssert_IsInVM --
+ *
+ * Check if we are in virtual world.
+ *
+ * Results:
+ *
+ * Return TRUE on success, or FALSE on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------
+ */
+
+static Bool
+VAssert_IsInVM(void)
+{
+ uint32 eax, ebx, ecx, edx;
+ static Bool inVM = FALSE;
+ static Bool tested = FALSE;
+ if (!tested) {
+ /* Error handling. */
+ if (sigsetjmp(segv_jmp, 0) != 0) {
+ signal(SIGSEGV, SIG_DFL);
+ inVM = FALSE;
+ return inVM;
+ }
+ tested = TRUE;
+ /* Install custom handler. */
+ signal(SIGSEGV, sig_segv);
+ /* Test if we are in a VM. */
+ libvassert_process_backdoor(0x0a, 0, MAGIC_PORT, &eax, &ebx, &ecx, &edx);
+ signal(SIGSEGV, SIG_DFL);
+ inVM = TRUE;
+ }
+ return inVM;
+}
+
+
+/*
+ *---------------------------------------------------------------------
+ *
+ * VAssert_Init --
+ *
+ * Tell vmx that vassert is inited.
+ *
+ * Results:
+ *
+ * Return 0 on success, or -1 on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *---------------------------------------------------------------------
+ */
+
+char
+VAssert_Init(void)
+{
+ uint32 eax, ebx, ecx, edx;
+ VA page_address = (VA) &vassert_state.inReplay, ph;
+ if (!VAssert_IsInVM()) {
+ return -1;
+ }
+ bzero((char*) &vassert_state, sizeof vassert_state);
+#ifndef __minix
+ /* Lock the page. */
+ if (mlock(&vassert_state, sizeof vassert_state)) {
+ return -1;
+ }
+#endif
+
+ /* vmware expects a linear address (or is simply forgetting
+ * to adjust the given address for segments)
+ */
+
+ if(sys_umap(SELF, D, page_address, 1, &ph)) {
+ printf("VAssert_Init: sys_umap failed\n");
+ return -1;
+ }
+
+ libvassert_process_backdoor(CMD_SET_ADDRESS, ph,
+ MAGIC_PORT|(1<<16), &eax, &ebx, &ecx, &edx);
+
+ return (eax != -1) ? 0 : -1;
+}
+
+
+/*
+ *---------------------------------------------------------------------
+ *
+ * VAssert_Uninit --
+ *
+ * Tell vmx that vassert is finalized.
+ *
+ * Results:
+ *
+ * Return 0 on success, or -1 on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *---------------------------------------------------------------------
+ */
+
+char
+VAssert_Uninit(void)
+{
+ unsigned int eax, ebx, ecx, edx;
+ if (!VAssert_IsInVM()) {
+ return -1;
+ }
+ libvassert_process_backdoor(CMD_SET_ADDRESS, 0, MAGIC_PORT|(0<<16), &eax, &ebx, &ecx, &edx);
+ return (eax != -1) ? 0 : 1;
+}
+
+
+/*
+ *---------------------------------------------------------------------
+ *
+ * VAssert_LogMain --
+ *
+ * Print message to a text file on host side.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * Write to a text file with fixed name.
+ * If the file exists, host UI will ask for append/replace/ignore
+ *
+ *---------------------------------------------------------------------
+ */
+
+void
+VAssert_LogMain(const char *format, ...)
+{
+ unsigned int eax, ebx, ecx, edx;
+ char buf[LOG_MAX];
+ unsigned int len = 0;
+ va_list ap;
+ va_start(ap, format);
+ len = vsnprintf(buf, LOG_MAX, format, ap);
+ va_end(ap);
+ __asm__ __volatile__("cld; rep outsb;"
+ : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
+ : "0"(MAGIC_CMD), "1"(CMD_LOG), "2"(len), "d"(HIGH_BAND_PORT), "S"(buf)
+ : "memory"
+ );
+}
+
+
+/*
+ *---------------------------------------------------------------------
+ *
+ * VAssert_GoLiveMain --
+ *
+ * Make the vm which is in replay exit replay.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * Replay is stopped.
+ *
+ *---------------------------------------------------------------------
+ */
+
+void
+VAssert_GoLiveMain()
+{
+ unsigned int eax, ebx, ecx, edx;
+ vassert_state.inReplay = 0;
+ libvassert_process_backdoor(CMD_GO_LIVE, 0, MAGIC_PORT, &eax, &ebx, &ecx, &edx);
+}
+
+
+/*
+ *---------------------------------------------------------------------
+ *
+ * VAssert_ReturnToReplayMain --
+ *
+ * Called after the custom work is done, and replay is to continue.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * Replay is continued from pause.
+ *
+ *---------------------------------------------------------------------
+ */
+
+void
+VAssert_ReturnToReplayMain()
+{
+ unsigned int eax, ebx, ecx, edx;
+ libvassert_process_backdoor(CMD_RETURN_REPLAY, 0, MAGIC_PORT, &eax, &ebx, &ecx, &edx);
+}
+
+
+/*
+ *---------------------------------------------------------------------
+ *
+ * VAssert_SetRecordingMain --
+ *
+ * Ask vmx for starting or stopping recording.
+ *
+ * Results:
+ *
+ * Return TRUE on success, or FALSE on failure.
+ *
+ * Side effects:
+ * Recording is started or stopped.
+ *
+ *---------------------------------------------------------------------
+ */
+
+char
+VAssert_SetRecordingMain(char start)
+{
+ uint32 eax, ebx, ecx, edx;
+ if (!VAssert_IsInVM()) {
+ return FALSE;
+ }
+ libvassert_process_backdoor(CMD_SET_RECORD, start ? 1 : 2, MAGIC_PORT, &eax, &ebx, &ecx, &edx);
+ return (eax == 1) ? TRUE : FALSE;
+}
+
--- /dev/null
+#ifndef _VASSERT_H_
+#define _VASSERT_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /*__cplusplus*/
+
+#define ALIGNED(n) __attribute__((__aligned__(n)))
+#define VASSERT_TRIGGER_OFFSET 1221
+#define VASSERT_PAGE_SIZE 4096
+
+/* Need to align at 4K. */
+/* Ensure the inReplay flag is on its own page. */
+#pragma pack(1)
+typedef struct VAssert_StateWrapper {
+ char space1[VASSERT_TRIGGER_OFFSET];
+ volatile char inReplay;
+ char space[VASSERT_PAGE_SIZE - VASSERT_TRIGGER_OFFSET - sizeof(char)];
+} VAssert_StateWrapper;
+#pragma pack()
+
+extern VAssert_StateWrapper vassert_state;
+
+/*
+ * User-selectable standard functions.
+ * XXX: Document these, in coordination with the SDK docs.
+ */
+
+#if defined(__KERNEL__)
+# define KERNEL_VASSERT
+#endif
+
+#ifdef KERNEL_VASSERT
+
+# ifndef VASSERT_CUSTOM_ASSERT
+# define VASSERT_CUSTOM_ASSERT(expr)
+# endif
+
+# ifndef VASSERT_CUSTOM_ABORT
+# include <linux/kernel.h>
+# define VASSERT_CUSTOM_ABORT() ((void)0) // printk(KERN_ALERT"VAssert abort at %s: %d", __FILE__, __LINE__)
+# endif
+
+# ifndef VASSERT_CUSTOM_LOG
+# include <linux/kernel.h>
+# define VASSERT_CUSTOM_LOG printk
+# endif
+
+#else
+# ifndef VASSERT_CUSTOM_ASSERT
+# include <assert.h>
+# define VASSERT_CUSTOM_ASSERT assert
+# endif
+
+# ifndef VASSERT_CUSTOM_ABORT
+# include <stdlib.h>
+# define VASSERT_CUSTOM_ABORT abort
+# endif
+
+# ifndef VASSERT_CUSTOM_LOG
+# include <stdio.h>
+# define VASSERT_CUSTOM_LOG printf
+# endif
+#endif
+
+/* Results: 0 if successful, -1 if not. */
+// XXX need to automatic de-register trigger page when the program quits
+extern char VAssert_Init(void);
+extern char VAssert_Uninit(void);
+
+/*
+ * These functions should not be called directly; they need to be wrapped.
+ */
+extern void VAssert_LogMain(const char *format, ...);
+extern void VAssert_GoLiveMain(void);
+extern void VAssert_ReturnToReplayMain(void);
+extern char VAssert_Trace(size_t max_size);
+
+#ifdef VASSERT_ALWAYS_EXECUTE
+
+#define VAssert_Assert(expr) \
+do { \
+ VASSERT_CUSTOM_ASSERT(expr); \
+} while (0)
+
+#define VAssert_Log(args) \
+do { \
+ VASSERT_CUSTOM_LOG args; \
+} while (0)
+
+#define VAssert_BeginBlock
+#define VAssert_EndBlock
+
+#else /* VASSERT_ALWAYS_EXECUTE */
+
+#define VAssert_Assert(expr) \
+do { \
+ if (vassert_state.inReplay) { \
+ if (!(expr)) { \
+ VAssert_GoLiveMain(); \
+ VASSERT_CUSTOM_ABORT(); \
+ } else { \
+ VAssert_ReturnToReplayMain(); \
+ } \
+ } \
+} while (0)
+
+#define VAssert_Log(args) \
+do { \
+ if (vassert_state.inReplay) { \
+ VAssert_LogMain args; \
+ VAssert_ReturnToReplayMain(); \
+ } \
+} while (0)
+
+#define VAssert_BeginBlock if (vassert_state.inReplay)
+#define VAssert_EndBlock VAssert_ReturnToReplayMain()
+
+#endif /* VASSERT_ALWAYS_EXECUTE */
+
+/*
+ * Record/Replay functionality
+ */
+/*
+ * Results: True if successful, false if not.
+ * Input: True to start recording, false to stop.
+ */
+extern char VAssert_SetRecordingMain(char start);
+
+#define VAssert_StartRecording() VAssert_SetRecordingMain(1)
+#define VAssert_StopRecording() VAssert_SetRecordingMain(0)
+
+#ifdef __cplusplus
+}
+#endif /*__cplusplus*/
+
+#endif /*_VASSERT_H_*/