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;