Add '-accel <mode>' and 'no-accel' options.

This patch adds two new options to better control CPU emulation
acceleration (i.e. KVM and HAX). More specifically:

  '-no-accel' can be used to disable acceleration if available.
  '-accel off' does the same.
  '-accel on' forces to run with acceleration, or refuses to start
  the emulator.
  '-accel auto' probes the system for a working accelerator and uses
  it when possible (i.e. when emulating x86 or x86_64 images only).

Also print some information with -verbose or -debug-init.

Note: This adds QEMU-independent probing code for KVM and HAX
      under android/emulation/ (C++), as well as some glue to
      use it from C under android/cpu_accelerator.[hc].

Note: HAX is no longer enabled by default when reaching the QEMU
      main function.

Change-Id: Ic91db7a3b213d69296c50fec35cd29a32a8e5779
diff --git a/Makefile.common b/Makefile.common
index 8215a52..ff3b5eb 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -125,6 +125,7 @@
 	android/base/String.cpp \
 	android/base/StringFormat.cpp \
 	android/base/StringView.cpp \
+	android/emulation/CpuAccelerator.cpp \
 	android/filesystems/ext4_utils.cpp \
 	android/utils/assert.c \
 	android/utils/bufprint.c \
diff --git a/Makefile.target b/Makefile.target
index 1f3fbd0..7c13cbb 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -331,6 +331,7 @@
     vl-android.c \
     android/cmdline-option.c \
     android/console.c \
+    android/cpu_accelerator.cpp \
     android/display.c \
     android/display-core.c \
     android/help.c \
diff --git a/Makefile.tests b/Makefile.tests
index 68933b6..d97812f 100644
--- a/Makefile.tests
+++ b/Makefile.tests
@@ -19,6 +19,7 @@
   android/base/String_unittest.cpp \
   android/base/StringFormat_unittest.cpp \
   android/base/StringView_unittest.cpp \
+  android/emulation/CpuAccelerator_unittest.cpp \
   android/filesystems/ext4_utils_unittest.cpp \
 
 ifeq (windows,$(HOST_OS))
diff --git a/android/cmdline-options.h b/android/cmdline-options.h
index 0c75783..f268f9f 100644
--- a/android/cmdline-options.h
+++ b/android/cmdline-options.h
@@ -93,6 +93,9 @@
 CFG_FLAG ( dynamic_skin, "dynamically construct a skin of given size, requires -skin WxH option" )
 CFG_PARAM( memory, "<size>", "physical RAM size in MBs" )
 
+OPT_PARAM( accel, "<mode>", "Configure emulation acceleration" )
+OPT_FLAG ( no_accel, "Same as '-accel off'" )
+
 OPT_PARAM( netspeed, "<speed>", "maximum network download/upload speeds" )
 OPT_PARAM( netdelay, "<delay>", "network latency emulation" )
 OPT_FLAG ( netfast, "disable network shaping" )
diff --git a/android/cpu_accelerator.cpp b/android/cpu_accelerator.cpp
new file mode 100644
index 0000000..872e60d
--- /dev/null
+++ b/android/cpu_accelerator.cpp
@@ -0,0 +1,32 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#include "android/cpu_accelerator.h"
+
+// This source acts as a small C++ -> C bridge between android/emulation/
+// and android/main.c
+
+#include "android/base/String.h"
+#include "android/emulation/CpuAccelerator.h"
+
+#include "android/utils/system.h"
+
+extern "C" bool android_hasCpuAcceleration(char** status_p) {
+    android::CpuAccelerator accel = android::GetCurrentCpuAccelerator();
+
+    if (status_p) {
+        android::base::String status =
+                android::GetCurrentCpuAcceleratorStatus();
+        *status_p = ASTRDUP(status.c_str());
+    }
+
+    return accel != android::CPU_ACCELERATOR_NONE;
+}
diff --git a/android/cpu_accelerator.h b/android/cpu_accelerator.h
new file mode 100644
index 0000000..845cab6
--- /dev/null
+++ b/android/cpu_accelerator.h
@@ -0,0 +1,30 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#ifndef ANDROID_CPU_ACCELERATOR_H
+#define ANDROID_CPU_ACCELERATOR_H
+
+#include <stdbool.h>
+
+#include "android/utils/compiler.h"
+
+ANDROID_BEGIN_HEADER
+
+// Returns true if CPU acceleration is possible on this machine.
+// If |status| is not NULL, on exit, |*status| will be set to a
+// heap-allocated string describing the status of acceleration,
+// to be freed by the caller.
+bool android_hasCpuAcceleration(char** status);
+
+ANDROID_END_HEADER
+
+#endif  // ANDROID_CPU_ACCELERATOR_H
+
diff --git a/android/emulation/CpuAccelerator.cpp b/android/emulation/CpuAccelerator.cpp
new file mode 100644
index 0000000..be0175e
--- /dev/null
+++ b/android/emulation/CpuAccelerator.cpp
@@ -0,0 +1,347 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#include "android/emulation/CpuAccelerator.h"
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN 1
+#include <windows.h>
+#include <winioctl.h>
+#else
+#include <fcntl.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+
+#include "android/utils/path.h"
+
+#include "android/base/Compiler.h"
+#include "android/base/files/ScopedFd.h"
+#ifdef _WIN32
+#include "android/base/files/ScopedHandle.h"
+#endif
+#include "android/base/Log.h"
+#include "android/base/StringFormat.h"
+
+// NOTE: This source file must be independent of the rest of QEMU, as such
+//       it should not include / reuse any QEMU source file or function
+//       related to KVM or HAX.
+
+#ifdef __linux__
+#  define  HAVE_KVM  1
+#  define  HAVE_HAX  0
+#elif defined(_WIN32) || defined(__APPLE__)
+#  define HAVE_KVM 0
+#  define HAVE_HAX 1
+#else
+#  error "Unsupported host platform!"
+#endif
+
+namespace android {
+
+using base::String;
+using base::StringAppendFormat;
+using base::ScopedFd;
+
+namespace {
+
+struct GlobalState {
+    bool probed;
+    bool testing;
+    CpuAccelerator accel;
+    char status[256];
+};
+
+GlobalState gGlobals = { false, false, CPU_ACCELERATOR_NONE, { '\0' } };
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+/////
+/////   Linux KVM support.
+/////
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+#if HAVE_KVM
+
+#include <linux/kvm.h>
+
+// Return true iff KVM is installed and usable on this machine.
+// |*status| will be set to a small status string explaining the
+// status of KVM on success or failure.
+bool ProbeKVM(String *status) {
+    // 1) Check that /dev/kvm exists.
+    if (::access("/dev/kvm", F_OK)) {
+        status->assign(
+            "KVM is not installed on this machine (/dev/kvm is missing).");
+        return false;
+    }
+    // 2) Check that /dev/kvm can be opened.
+    if (::access("/dev/kvm", R_OK)) {
+        status->assign(
+            "This user doesn't have permissions to use KVM (/dev/kvm).");
+        return false;
+    }
+    // 3) Open the file.
+    ScopedFd fd(TEMP_FAILURE_RETRY(open("/dev/kvm", O_RDWR)));
+    if (!fd.valid()) {
+        status->assign("Could not open /dev/kvm :");
+        status->append(strerror(errno));
+        return false;
+    }
+
+    // 4) Extract KVM version number.
+    int version = ::ioctl(fd.get(), KVM_GET_API_VERSION, 0);
+    if (version < 0) {
+        status->assign("Could not extract KVM version: ");
+        status->append(strerror(errno));
+        return false;
+    }
+
+    // 5) Compare to minimum supported version
+    status->clear();
+
+    if (version < KVM_API_VERSION) {
+        StringAppendFormat(status,
+                           "KVM version too old: %d (expected at least %d)\n",
+                           version,
+                           KVM_API_VERSION);
+        return false;
+    }
+
+    // 6) Profit!
+    StringAppendFormat(status,
+                       "KVM (version %d) is installed and usable.",
+                       version);
+    return true;
+}
+
+#endif  // HAVE_KVM
+
+
+#if HAVE_HAX
+
+// Version numbers for the HAX kernel module.
+// |compat_version| is the minimum API version supported by the module.
+// |current_version| is its current API version.
+struct HaxModuleVersion {
+    uint32_t compat_version;
+    uint32_t current_version;
+};
+
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+/////
+/////  Windows HAX support.
+/////
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+#if defined(_WIN32)
+
+using base::ScopedHandle;
+
+// Windows IOCTL code to extract HAX kernel module version.
+#define HAX_DEVICE_TYPE 0x4000
+#define HAX_IOCTL_VERSION       \
+    CTL_CODE(HAX_DEVICE_TYPE, 0x900, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+// The minimum API version supported by the Android emulator.
+#define HAX_MIN_VERSION  1
+
+bool ProbeHAX(String* status) {
+    status->clear();
+    // 1) Try to find the HAX kernel module.
+    ScopedHandle hax(CreateFile("\\\\.\\HAX",
+                                GENERIC_READ | GENERIC_WRITE,
+                                0,
+                                NULL,
+                                CREATE_ALWAYS,
+                                FILE_ATTRIBUTE_NORMAL,
+                                NULL));
+    if (!hax.valid()) {
+        DWORD err = GetLastError();
+        if (err == ERROR_FILE_NOT_FOUND) {
+            status->assign("HAX kernel module is not installed!");
+        } else {
+            StringAppendFormat(status,
+                               "Opening HAX kernel module failed: %u",
+                               err);
+        }
+        return false;
+    }
+
+    // 2) Extract the module's version.
+    HaxModuleVersion hax_version;
+
+    DWORD dSize = 0;
+    BOOL ret = DeviceIoControl(hax.get(),
+                               HAX_IOCTL_VERSION,
+                               NULL, 0,
+                               &hax_version, sizeof(hax_version),
+                               &dSize,
+                               (LPOVERLAPPED) NULL);
+    if (!ret) {
+        DWORD err = GetLastError();
+        StringAppendFormat(status,
+                            "Could not extract HAX module version: %u",
+                            err);
+        return false;
+    }
+
+    // 3) Check that it is the right version.
+    if (hax_version.current_version < HAX_MIN_VERSION) {
+        StringAppendFormat(status,
+                           "HAX version (%d) is too old (need at least %d).",
+                           hax_version.current_version,
+                           HAX_MIN_VERSION);
+        return false;
+    }
+
+    // 4) Profit!
+    StringAppendFormat(status,
+                       "HAX (version %d) is installed and usable.",
+                       hax_version.current_version);
+    return true;
+}
+
+#elif defined(__APPLE__)
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+/////
+/////  Darwin HAX support.
+/////
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+// An IOCTL command number used to retrieve the HAX kernel module version.
+#define HAX_IOCTL_VERSION _IOWR(0, 0x20, HaxModuleVersion)
+
+// The minimum API version supported by the Android emulator.
+#define HAX_MIN_VERSION  1
+
+bool ProbeHAX(String* status) {
+    // 1) Check that /dev/HAX exists.
+    if (::access("/dev/HAX", F_OK)) {
+        status->assign(
+            "HAX is not installed on this machine (/dev/HAX is missing).");
+        return false;
+    }
+    // 2) Check that /dev/HAX can be opened.
+    if (::access("/dev/HAX", R_OK)) {
+        status->assign(
+            "This user doesn't have permission to use HAX (/dev/HAX).");
+        return false;
+    }
+    // 3) Open the file.
+    ScopedFd fd(open("/dev/HAX", O_RDWR));
+    if (!fd.valid()) {
+        status->assign("Could not open /dev/HAX: ");
+        status->append(strerror(errno));
+        return false;
+    }
+
+    // 4) Extract HAX version number.
+    status->clear();
+
+    HaxModuleVersion hax_version;
+    if (::ioctl(fd.get(), HAX_IOCTL_VERSION, &hax_version) < 0) {
+        StringAppendFormat(status,
+                           "Could not extract HAX version: %s",
+                           strerror(errno));
+        return false;
+    }
+
+    if (hax_version.current_version < hax_version.compat_version) {
+        StringAppendFormat(
+                status,
+                "Malformed HAX version numbers (current=%d, compat=%d)\n",
+                hax_version.current_version,
+                hax_version.compat_version);
+        return false;
+    }
+
+    // 5) Compare to minimum supported version.
+
+    if (hax_version.current_version < HAX_MIN_VERSION) {
+        StringAppendFormat(status,
+                           "HAX version too old: %d (expected at least %d)\n",
+                           hax_version.current_version,
+                           HAX_MIN_VERSION);
+        return false;
+    }
+
+    // 6) Profit!
+    StringAppendFormat(status,
+                       "HAX (version %d) is installed and usable.",
+                       hax_version.current_version);
+    return true;
+}
+
+#else   // !_WIN32 && !__APPLE__
+#error "Unsupported HAX host platform"
+#endif  // !_WIN32 && !__APPLE__
+
+#endif  // HAVE_HAX
+
+}  // namespace
+
+CpuAccelerator GetCurrentCpuAccelerator() {
+    GlobalState* g = &gGlobals;
+
+    if (g->probed || g->testing) {
+        return g->accel;
+    }
+
+    String status;
+#if HAVE_KVM
+    if (ProbeKVM(&status)) {
+        g->accel = CPU_ACCELERATOR_KVM;
+    }
+#elif HAVE_HAX
+    if (ProbeHAX(&status)) {
+        g->accel = CPU_ACCELERATOR_HAX;
+    }
+#else
+    status = "This system does not support CPU acceleration.";
+#endif
+    ::snprintf(g->status, sizeof(g->status), "%s", status.c_str());
+
+    g->probed = true;
+    return g->accel;
+}
+
+String GetCurrentCpuAcceleratorStatus() {
+    GlobalState *g = &gGlobals;
+
+    if (!g->probed && !g->testing) {
+        // Force detection of the current CPU accelerator.
+        GetCurrentCpuAccelerator();
+    }
+
+    return String(g->status);
+}
+
+void SetCurrentCpuAcceleratorForTesting(CpuAccelerator accel,
+                                        const char* status) {
+    GlobalState *g = &gGlobals;
+
+    g->testing = true;
+    g->accel = accel;
+    ::snprintf(g->status, sizeof(g->status), "%s", status);
+}
+
+}  // namespace android
diff --git a/android/emulation/CpuAccelerator.h b/android/emulation/CpuAccelerator.h
new file mode 100644
index 0000000..5c5e08e
--- /dev/null
+++ b/android/emulation/CpuAccelerator.h
@@ -0,0 +1,58 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#ifndef ANDROID_EMULATION_CPU_EMULATOR_H
+#define ANDROID_EMULATION_CPU_EMULATOR_H
+
+#include "android/base/String.h"
+
+namespace android {
+
+using ::android::base::String;
+
+// The list of CPU emulation acceleration technologies supported by the
+// Android emulator.
+//  CPU_ACCELERATOR_NONE means no acceleration is supported on this machine.
+//
+//  CPU_ACCELERATOR_KVM means Linux KVM, which requires a specific driver
+//  to be installed and that /dev/kvm is properly accessible by the current
+//  user.
+//
+//  CPU_ACCELERATOR_HAX means Intel's Hardware Accelerated eXecution,
+//  which can be installed on Windows and OS X machines running on an
+//  Intel processor.
+//
+enum CpuAccelerator {
+    CPU_ACCELERATOR_NONE = 0,
+    CPU_ACCELERATOR_KVM,
+    CPU_ACCELERATOR_HAX,
+};
+
+// Return the CPU accelerator technology usable on the current machine.
+// This only returns CPU_ACCELERATOR_KVM or CPU_ACCELERATOR_HAX if the
+// corresponding accelerator can be used properly. Otherwise it will
+// return CPU_ACCELERATOR_NONE.
+CpuAccelerator  GetCurrentCpuAccelerator();
+
+// Return an ASCII string describing the state of the current CPU
+// acceleration on this machine. If GetCurrentCpuAccelerator() returns
+// CPU_ACCELERATOR_NONE this will contain a small explanation why
+// the accelerator cannot be used.
+String GetCurrentCpuAcceleratorStatus();
+
+// For unit testing/debugging purpose only, must be called before
+// GetCurrentCpuAccelerator().
+void SetCurrentCpuAcceleratorForTesting(CpuAccelerator accel,
+                                        const char* status);
+
+}  // namespace android
+
+#endif  // ANDROID_EMULATION_CPU_EMULATOR_H
diff --git a/android/emulation/CpuAccelerator_unittest.cpp b/android/emulation/CpuAccelerator_unittest.cpp
new file mode 100644
index 0000000..68780ea
--- /dev/null
+++ b/android/emulation/CpuAccelerator_unittest.cpp
@@ -0,0 +1,62 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#include "android/emulation/CpuAccelerator.h"
+
+#include <stdio.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+
+class CpuAcceleratorTest : public ::testing::Test {
+public:
+    CpuAcceleratorTest() {
+        saved_accel_ = GetCurrentCpuAccelerator();
+        saved_status_ = GetCurrentCpuAcceleratorStatus();
+    }
+
+    ~CpuAcceleratorTest() {
+        // Restore previous state.
+        SetCurrentCpuAcceleratorForTesting(saved_accel_,
+                                           saved_status_.c_str());
+    }
+private:
+    CpuAccelerator saved_accel_;
+    String saved_status_;
+};
+
+// Not really a test, but a simple way to print the current accelerator
+// value for simple verification.
+TEST_F(CpuAcceleratorTest, Default) {
+    CpuAccelerator accel = GetCurrentCpuAccelerator();
+    String status = GetCurrentCpuAcceleratorStatus();
+
+    switch (accel) {
+    case CPU_ACCELERATOR_NONE:
+        printf("No acceleration possible on this machine!\n");
+        break;
+
+    case CPU_ACCELERATOR_KVM:
+        printf("KVM acceleration usable on this machine!\n");
+        break;
+
+    case CPU_ACCELERATOR_HAX:
+        printf("HAX acceleration usable on this machine!\n");
+        break;
+
+    default:
+        ASSERT_FALSE(1) << "Invalid accelerator value: " << accel;
+    }
+    printf("Status: %s\n", status.c_str());
+}
+
+}  // namespace android
diff --git a/android/help.c b/android/help.c
index e5d3e49..b703ec5 100644
--- a/android/help.c
+++ b/android/help.c
@@ -734,6 +734,39 @@
 }
 
 static void
+help_accel(stralloc_t *out)
+{
+    PRINTF(
+        "  Use '-accel <mode>' to control how CPU emulation can be accelerated\n"
+        "  when launching the Android emulator. Accelerated emulation only works\n"
+        "  for x86 and x86_64 system images. On Linux, it relies on KVM being\n"
+        "  installed. On Windows and OS X, it relies on an Intel CPU and the\n"
+        "  Intel HAXM driver being installed on your development machine.\n"
+        "  Valid values for <mode> are:\n\n"
+
+        "     auto   The default, determines automatically if acceleration\n"
+        "            is supported, and uses it when possible.\n\n"
+
+        "     off    Disables acceleration entirely. Mostly useful for debugging.\n\n"
+
+        "     on     Force acceleration. If KVM/HAXM is not installed or usable,\n"
+        "            the emulator will refuse to start and print an error message.\n\n"
+
+        "  Note that this flag is ignored if you're not emulating an x86 or x86_64\n"
+    );
+}
+
+static void
+help_no_accel(stralloc_t* out)
+{
+    PRINTF(
+        "  Use '-no-accel' as a shortcut to '-accel off', i.e. to disable accelerated\n"
+        "  CPU emulation, when emulating an x86 or x86_64 system image. Only useful\n"
+        "  for debugging.\n"
+    );
+}
+
+static void
 help_skindir(stralloc_t*  out)
 {
     PRINTF(
diff --git a/android/main.c b/android/main.c
index 0662bfe..c0ac767 100644
--- a/android/main.c
+++ b/android/main.c
@@ -36,6 +36,7 @@
 #include "android/utils/debug.h"
 #include "android/config-file.h"
 #include "android/config/config.h"
+#include "android/cpu_accelerator.h"
 
 #include "android/user-config.h"
 #include "android/utils/bufprint.h"
@@ -1202,6 +1203,91 @@
         args[n++] = "socket,vlan=1,mcast=230.0.0.10:1234";
     }
 
+    /* Handle CPU acceleration options. */
+    if (opts->no_accel) {
+        if (opts->accel) {
+            if (strcmp(opts->accel, "off") != 0) {
+                derror("You cannot use -no-accel and '-accel %s' at the same time",
+                       opts->accel);
+                exit(1);
+            }
+        } else {
+            AFREE(opts->accel);
+            opts->accel = ASTRDUP("off");
+        }
+    }
+
+    enum {
+        ACCEL_OFF = 0,
+        ACCEL_ON = 1,
+        ACCEL_AUTO = 2,
+    } accel_mode = ACCEL_AUTO;
+
+    if (opts->accel) {
+        if (!strcmp(opts->accel, "off")) {
+            accel_mode = ACCEL_OFF;
+        } else if (!strcmp(opts->accel, "on")) {
+            accel_mode = ACCEL_ON;
+        } else if (!strcmp(opts->accel, "auto")) {
+            accel_mode = ACCEL_AUTO;
+        } else {
+            derror("Invalid '-accel %s' parameter, valid values are: on off auto\n",
+                   opts->accel);
+            exit(1);
+        }
+    }
+
+#if defined(TARGET_I386) || defined(TARGET_X86_64)
+    char* accel_status = NULL;
+    bool accel_ok = android_hasCpuAcceleration(&accel_status);
+
+#ifdef __linux__
+    static const char kEnableAccelerator[] = "-enable-kvm";
+    static const char kDisableAccelerator[] = "-disable-kvm";
+#else
+    static const char kEnableAccelerator[] = "-enable-hax";
+    static const char kDisableAccelerator[] = "-disable-hax";
+#endif
+
+    // Dump CPU acceleration status.
+    if (VERBOSE_CHECK(init)) {
+        const char* accel_str = "DISABLED";
+        if (accel_ok) {
+            if (accel_mode == ACCEL_OFF) {
+                accel_str = "working, but disabled by user";
+            } else {
+                accel_str = "working";
+            }
+        }
+        dprint("CPU Acceleration: %s", accel_str);
+        dprint("CPU Acceleration status: %s", accel_status);
+    }
+
+    // CPU acceleration only works for x86 and x86_64 system images.
+    if (accel_mode == ACCEL_OFF && accel_ok) {
+        args[n++] = ASTRDUP(kDisableAccelerator);
+    } else if (accel_mode == ACCEL_ON) {
+        if (!accel_ok) {
+            derror("CPU acceleration not supported on this machine!");
+            derror("Reason: %s", accel_status);
+            exit(1);
+        }
+        args[n++] = ASTRDUP(kEnableAccelerator);
+    } else {
+        args[n++] = accel_ok ? ASTRDUP(kEnableAccelerator)
+                             : ASTRDUP(kDisableAccelerator);
+    }
+
+    AFREE(accel_status);
+#else
+    (void)accel_mode;
+
+    if (VERBOSE_CHECK(init)) {
+        dwarning("CPU acceleration only works with x86/x86_64 "
+            "system images.");
+    }
+#endif
+
     /* Setup screen emulation */
     if (opts->screen) {
         if (strcmp(opts->screen, "touch") &&
diff --git a/qemu-options.hx b/qemu-options.hx
index 48e9782..6e8495f 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1340,12 +1340,22 @@
 if KVM support is enabled when compiling.
 ETEXI
 
+#ifdef CONFIG_HAX
+DEF("enable-hax", 0, QEMU_OPTION_enable_hax, \
+    "-enable-hax    Enable HAX full virtualization support\n")
 DEF("disable-hax", 0, QEMU_OPTION_disable_hax, \
     "-disable-hax   Disable HAX full virtualization support\n")
+#endif
+STEXI
+@item -enable-hax
+Enable HAX (Hardware-based Acceleration eXecution) support. This option is
+only supported on Max OS X and Windows platforms, if you have an Intel CPU
+which support the VT-x extension. It does not conflict with KVM.
+ETEXI
+
 STEXI
 @item -disable-hax
-Disable HAX (Hardware-based Acceleration eXecution) support. When HAX
-support is detected, the emulator will enable it by default. This
+Disable HAX (Hardware-based Acceleration eXecution) support. This
 option will disable the default action. HAX is supported only on Mac OS X
 and Windows platforms (if VT is present), and it does not conflict
 with KVM.
diff --git a/vl-android.c b/vl-android.c
index 87cb06b..be33559 100644
--- a/vl-android.c
+++ b/vl-android.c
@@ -295,7 +295,7 @@
 const char *vnc_display;
 int acpi_enabled = 1;
 int no_hpet = 0;
-int hax_disabled = 0;
+int hax_disabled = 1;
 int no_virtio_balloon = 0;
 int fd_bootchk = 1;
 int no_reboot = 0;
@@ -3068,9 +3068,14 @@
                 break;
 
 #endif
+#ifdef CONFIG_HAX
+            case QEMU_OPTION_enable_hax:
+                hax_disabled = 0;
+                break;
             case QEMU_OPTION_disable_hax:
                 hax_disabled = 1;
                 break;
+#endif
             case QEMU_OPTION_android_ports:
                 android_op_ports = (char*)optarg;
                 break;