Skip to contentSkip to conversation

Add HAX support

RFC PATCH Superseded Vincent Palatin 3 participants 18 messages Nov 8, 2016 – Nov 11, 2016 Kbuild

v1 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

cover Add HAX support

I took a stab at trying to rebase/upstream the support for Intel HAXM. (Hardware Accelerated Execution Manager).
Intel HAX is kernel-based hardware acceleration module for Windows and MacOSX.

I have based my work on the last version of the source code I found:
the emu-2.2-release branch in the external/qemu-android repository as used by the Android emulator.
In patch 2/3, I have forward-ported the core HAX code mostly unmodified from there, I just did some minor touch up to make it build and run properly. So it might contain some outdated constructs and probably requires more attention (thus the 'RFC' for this patchset).

In patch 3/3, I have put the plumbing into the QEMU code base, I did some clean up there and it is reasonably intrusive: i.e.

 Makefile.target           |   1 +
 configure                 |  18 +++++++
 cpu-exec.c                |  23 ++++++++-
 cpus.c                    | 125 ++++++++++++++++++++++++++++++++++++++++------
 exec.c                    |  16 ++++++
 hw/intc/apic_common.c     |   3 +-
 include/qom/cpu.h         |   5 ++
 include/sysemu/hw_accel.h |   9 ++++
 qemu-options.hx           |  11 ++++
 target-i386/Makefile.objs |   7 +++
 target-i386/seg_helper.c  |   5 ++
 target-i386/translate.c   |   8 +++
 vl.c                      |  17 +++++--
 13 files changed, 229 insertions(+), 19 deletions(-)

I'm not so happy with the qemu_cpu_kick_thread mess in cpus.c, if somebody can help/advise.

The patch 1/3 just extracts from KVM specific header the cpu_synchronize_ functions that HAX is also using.

I have tested the end result on a Windows 10 Pro machine (with UG support) with the Intel HAXM module 6.0.4 and a large ChromiumOS x86_64 image to exercise various code paths. It looks stable.
I also did a quick regression testing of the integration by running a Linux build with KVM enabled.

Vincent Palatin (3):
kvm: move cpu synchronization code
target-i386: Add Intel HAX files
Plumb the HAXM-based hardware acceleration support

 Makefile.target             |    1 +
 configure                   |   18 +
 cpu-exec.c                  |   23 +-
 cpus.c                      |  126 +++-
 exec.c                      |   16 +
 gdbstub.c                   |    1 +
 hax-stub.c                  |   66 ++
 hw/i386/kvm/apic.c          |    1 +
 hw/i386/kvmvapic.c          |    1 +
 hw/intc/apic_common.c       |    3 +-
 hw/misc/vmport.c            |    2 +-
 include/qom/cpu.h           |    5 +
 include/sysemu/hax.h        |   66 ++
 include/sysemu/hw_accel.h   |   48 ++
 include/sysemu/kvm.h        |   23 -
 monitor.c                   |    2 +-
 qemu-options.hx             |   11 +
 qom/cpu.c                   |    2 +-
 target-arm/cpu.c            |    2 +-
 target-i386/Makefile.objs   |    7 +
 target-i386/hax-all.c       | 1449 +++++++++++++++++++++++++++++++++++++++++++
 target-i386/hax-darwin.c    |  315 ++++++++++
 target-i386/hax-darwin.h    |   63 ++
 target-i386/hax-i386.h      |   94 +++
 target-i386/hax-interface.h |  357 +++++++++++
 target-i386/hax-slot.c      |  332 ++++++++++
 target-i386/hax-slot.h      |   58 ++
 target-i386/hax-windows.c   |  478 ++++++++++++++
 target-i386/hax-windows.h   |   89 +++
 target-i386/helper.c        |    1 +
 target-i386/kvm.c           |    1 +
 target-i386/seg_helper.c    |    5 +
 target-i386/translate.c     |    8 +
 vl.c                        |   17 +-
 34 files changed, 3645 insertions(+), 46 deletions(-)
 create mode 100644 hax-stub.c
 create mode 100644 include/sysemu/hax.h
 create mode 100644 include/sysemu/hw_accel.h
 create mode 100644 target-i386/hax-all.c
 create mode 100644 target-i386/hax-darwin.c
 create mode 100644 target-i386/hax-darwin.h
 create mode 100644 target-i386/hax-i386.h
 create mode 100644 target-i386/hax-interface.h
 create mode 100644 target-i386/hax-slot.c
 create mode 100644 target-i386/hax-slot.h
 create mode 100644 target-i386/hax-windows.c
 create mode 100644 target-i386/hax-windows.h
Signature · 1 line
2.8.0.rc3.226.g39d4020
#1 lore raw

PATCH 1/3 kvm: move cpu synchronization code

Move the generic cpu_synchronize_ functions to the common hw_accel.h header, in order to prepare for the addition of a second hardware accelerator.

---
 cpus.c                    |  1 +
 gdbstub.c                 |  1 +
 hw/i386/kvm/apic.c        |  1 +
 hw/i386/kvmvapic.c        |  1 +
 hw/misc/vmport.c          |  2 +-
 include/sysemu/hw_accel.h | 39 +++++++++++++++++++++++++++++++++++++++
 include/sysemu/kvm.h      | 23 -----------------------
 monitor.c                 |  2 +-
 qom/cpu.c                 |  2 +-
 target-arm/cpu.c          |  2 +-
 target-i386/helper.c      |  1 +
 target-i386/kvm.c         |  1 +
 12 files changed, 49 insertions(+), 27 deletions(-)
 create mode 100644 include/sysemu/hw_accel.h
cpus.c +1 -0
index 5213351..fc78502 100644
@@ -33,6 +33,7 @@
 #include "sysemu/block-backend.h"
 #include "exec/gdbstub.h"
 #include "sysemu/dma.h"
+#include "sysemu/hw_accel.h"
 #include "sysemu/kvm.h"
 #include "qmp-commands.h"
 #include "exec/exec-all.h"
gdbstub.c +1 -0
index de62d26..de9b62b 100644
@@ -32,6 +32,7 @@
 #define MAX_PACKET_LENGTH 4096
 
 #include "qemu/sockets.h"
+#include "sysemu/hw_accel.h"
 #include "sysemu/kvm.h"
 #include "exec/semihost.h"
 #include "exec/exec-all.h"
hw/i386/kvm/apic.c +1 -0
index 01cbaa8..328f80c 100644
@@ -14,6 +14,7 @@
 #include "cpu.h"
 #include "hw/i386/apic_internal.h"
 #include "hw/pci/msi.h"
+#include "sysemu/hw_accel.h"
 #include "sysemu/kvm.h"
 #include "target-i386/kvm_i386.h"
 
hw/i386/kvmvapic.c +1 -0
index b30d1b9..2f767b6 100644
@@ -14,6 +14,7 @@
 #include "exec/exec-all.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/cpus.h"
+#include "sysemu/hw_accel.h"
 #include "sysemu/kvm.h"
 #include "hw/i386/apic_internal.h"
 #include "hw/sysbus.h"
hw/misc/vmport.c +1 -1
index c763811..be40930 100644
@@ -25,7 +25,7 @@
 #include "hw/hw.h"
 #include "hw/isa/isa.h"
 #include "hw/i386/pc.h"
-#include "sysemu/kvm.h"
+#include "sysemu/hw_accel.h"
 #include "hw/qdev.h"
 
 //#define VMPORT_DEBUG
include/sysemu/hw_accel.h new file +39 -0
new file mode 100644
index 0000000..03812cf
@@ -0,0 +1,39 @@
+/*
+ * QEMU Hardware accelertors support
+ *
+ * Copyright 2016 Google, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_HW_ACCEL_H
+#define QEMU_HW_ACCEL_H
+
+#include "qom/cpu.h"
+#include "sysemu/hax.h"
+#include "sysemu/kvm.h"
+
+static inline void cpu_synchronize_state(CPUState *cpu)
+{
+    if (kvm_enabled()) {
+        kvm_cpu_synchronize_state(cpu);
+    }
+}
+
+static inline void cpu_synchronize_post_reset(CPUState *cpu)
+{
+    if (kvm_enabled()) {
+        kvm_cpu_synchronize_post_reset(cpu);
+    }
+}
+
+static inline void cpu_synchronize_post_init(CPUState *cpu)
+{
+    if (kvm_enabled()) {
+        kvm_cpu_synchronize_post_init(cpu);
+    }
+}
+
+#endif /* QEMU_HW_ACCEL_H */
include/sysemu/kvm.h +0 -23
index df67cc0..3045ee7 100644
@@ -461,29 +461,6 @@ void kvm_cpu_synchronize_state(CPUState *cpu);
 void kvm_cpu_synchronize_post_reset(CPUState *cpu);
 void kvm_cpu_synchronize_post_init(CPUState *cpu);
 
-/* generic hooks - to be moved/refactored once there are more users */
-
-static inline void cpu_synchronize_state(CPUState *cpu)
-{
-    if (kvm_enabled()) {
-        kvm_cpu_synchronize_state(cpu);
-    }
-}
-
-static inline void cpu_synchronize_post_reset(CPUState *cpu)
-{
-    if (kvm_enabled()) {
-        kvm_cpu_synchronize_post_reset(cpu);
-    }
-}
-
-static inline void cpu_synchronize_post_init(CPUState *cpu)
-{
-    if (kvm_enabled()) {
-        kvm_cpu_synchronize_post_init(cpu);
-    }
-}
-
 /**
  * kvm_irqchip_add_msi_route - Add MSI route for specific vector
  * @s:      KVM state
monitor.c +1 -1
index 0841d43..d38956f 100644
@@ -50,7 +50,7 @@
 #include "sysemu/balloon.h"
 #include "qemu/timer.h"
 #include "migration/migration.h"
-#include "sysemu/kvm.h"
+#include "sysemu/hw_accel.h"
 #include "qemu/acl.h"
 #include "sysemu/tpm.h"
 #include "qapi/qmp/qerror.h"
qom/cpu.c +1 -1
index 03d9190..2c5274f 100644
@@ -22,7 +22,7 @@
 #include "qapi/error.h"
 #include "qemu-common.h"
 #include "qom/cpu.h"
-#include "sysemu/kvm.h"
+#include "sysemu/hw_accel.h"
 #include "qemu/notify.h"
 #include "qemu/log.h"
 #include "exec/log.h"
target-arm/cpu.c +1 -1
index 99f0dbe..744cc11 100644
@@ -31,7 +31,7 @@
 #endif
 #include "hw/arm/arm.h"
 #include "sysemu/sysemu.h"
-#include "sysemu/kvm.h"
+#include "sysemu/hw_accel.h"
 #include "kvm_arm.h"
 
 static void arm_cpu_set_pc(CPUState *cs, vaddr value)
target-i386/helper.c +1 -0
index 4ecc091..7530280 100644
@@ -24,6 +24,7 @@
 #include "kvm_i386.h"
 #ifndef CONFIG_USER_ONLY
 #include "sysemu/sysemu.h"
+#include "sysemu/hw_accel.h"
 #include "monitor/monitor.h"
 #include "hw/i386/apic_internal.h"
 #endif
target-i386/kvm.c +1 -0
index 1c0864e..d9ad69e 100644
@@ -23,6 +23,7 @@
 #include "qemu-common.h"
 #include "cpu.h"
 #include "sysemu/sysemu.h"
+#include "sysemu/hw_accel.h"
 #include "sysemu/kvm_int.h"
 #include "kvm_i386.h"
 #include "hyperv.h"
Signature · 1 line
2.8.0.rc3.226.g39d4020
Reviewed-by on v1 1/3
#2 lore raw

Re: [Qemu-devel] [PATCH 1/3] kvm: move cpu synchronization code

Quoted 217 lines · Vincent Palatin

Move the generic cpu_synchronize_ functions to the common hw_accel.h header, in order to prepare for the addition of a second hardware accelerator.

---
 cpus.c                    |  1 +
 gdbstub.c                 |  1 +
 hw/i386/kvm/apic.c        |  1 +
 hw/i386/kvmvapic.c        |  1 +
 hw/misc/vmport.c          |  2 +-
 include/sysemu/hw_accel.h | 39 +++++++++++++++++++++++++++++++++++++++
 include/sysemu/kvm.h      | 23 -----------------------
 monitor.c                 |  2 +-
 qom/cpu.c                 |  2 +-
 target-arm/cpu.c          |  2 +-
 target-i386/helper.c      |  1 +
 target-i386/kvm.c         |  1 +
 12 files changed, 49 insertions(+), 27 deletions(-)
 create mode 100644 include/sysemu/hw_accel.h
cpus.c +1 -0
index 5213351..fc78502 100644
@@ -33,6 +33,7 @@
 #include "sysemu/block-backend.h"
 #include "exec/gdbstub.h"
 #include "sysemu/dma.h"
+#include "sysemu/hw_accel.h"
 #include "sysemu/kvm.h"
 #include "qmp-commands.h"
 #include "exec/exec-all.h"
gdbstub.c +1 -0
index de62d26..de9b62b 100644
@@ -32,6 +32,7 @@
 #define MAX_PACKET_LENGTH 4096
 
 #include "qemu/sockets.h"
+#include "sysemu/hw_accel.h"
 #include "sysemu/kvm.h"
 #include "exec/semihost.h"
 #include "exec/exec-all.h"
hw/i386/kvm/apic.c +1 -0
index 01cbaa8..328f80c 100644
@@ -14,6 +14,7 @@
 #include "cpu.h"
 #include "hw/i386/apic_internal.h"
 #include "hw/pci/msi.h"
+#include "sysemu/hw_accel.h"
 #include "sysemu/kvm.h"
 #include "target-i386/kvm_i386.h"
 
hw/i386/kvmvapic.c +1 -0
index b30d1b9..2f767b6 100644
@@ -14,6 +14,7 @@
 #include "exec/exec-all.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/cpus.h"
+#include "sysemu/hw_accel.h"
 #include "sysemu/kvm.h"
 #include "hw/i386/apic_internal.h"
 #include "hw/sysbus.h"
hw/misc/vmport.c +1 -1
index c763811..be40930 100644
@@ -25,7 +25,7 @@
 #include "hw/hw.h"
 #include "hw/isa/isa.h"
 #include "hw/i386/pc.h"
-#include "sysemu/kvm.h"
+#include "sysemu/hw_accel.h"
 #include "hw/qdev.h"
 
 //#define VMPORT_DEBUG
include/sysemu/hw_accel.h new file +39 -0
new file mode 100644
index 0000000..03812cf
@@ -0,0 +1,39 @@
+/*
+ * QEMU Hardware accelertors support
+ *
+ * Copyright 2016 Google, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_HW_ACCEL_H
+#define QEMU_HW_ACCEL_H
+
+#include "qom/cpu.h"
+#include "sysemu/hax.h"
+#include "sysemu/kvm.h"
+
+static inline void cpu_synchronize_state(CPUState *cpu)
+{
+    if (kvm_enabled()) {
+        kvm_cpu_synchronize_state(cpu);
+    }
+}
+
+static inline void cpu_synchronize_post_reset(CPUState *cpu)
+{
+    if (kvm_enabled()) {
+        kvm_cpu_synchronize_post_reset(cpu);
+    }
+}
+
+static inline void cpu_synchronize_post_init(CPUState *cpu)
+{
+    if (kvm_enabled()) {
+        kvm_cpu_synchronize_post_init(cpu);
+    }
+}
+
+#endif /* QEMU_HW_ACCEL_H */
include/sysemu/kvm.h +0 -23
index df67cc0..3045ee7 100644
@@ -461,29 +461,6 @@ void kvm_cpu_synchronize_state(CPUState *cpu);
 void kvm_cpu_synchronize_post_reset(CPUState *cpu);
 void kvm_cpu_synchronize_post_init(CPUState *cpu);
 
-/* generic hooks - to be moved/refactored once there are more users */
-
-static inline void cpu_synchronize_state(CPUState *cpu)
-{
-    if (kvm_enabled()) {
-        kvm_cpu_synchronize_state(cpu);
-    }
-}
-
-static inline void cpu_synchronize_post_reset(CPUState *cpu)
-{
-    if (kvm_enabled()) {
-        kvm_cpu_synchronize_post_reset(cpu);
-    }
-}
-
-static inline void cpu_synchronize_post_init(CPUState *cpu)
-{
-    if (kvm_enabled()) {
-        kvm_cpu_synchronize_post_init(cpu);
-    }
-}
-
 /**
  * kvm_irqchip_add_msi_route - Add MSI route for specific vector
  * @s:      KVM state
monitor.c +1 -1
index 0841d43..d38956f 100644
@@ -50,7 +50,7 @@
 #include "sysemu/balloon.h"
 #include "qemu/timer.h"
 #include "migration/migration.h"
-#include "sysemu/kvm.h"
+#include "sysemu/hw_accel.h"
 #include "qemu/acl.h"
 #include "sysemu/tpm.h"
 #include "qapi/qmp/qerror.h"
qom/cpu.c +1 -1
index 03d9190..2c5274f 100644
@@ -22,7 +22,7 @@
 #include "qapi/error.h"
 #include "qemu-common.h"
 #include "qom/cpu.h"
-#include "sysemu/kvm.h"
+#include "sysemu/hw_accel.h"
 #include "qemu/notify.h"
 #include "qemu/log.h"
 #include "exec/log.h"
target-arm/cpu.c +1 -1
index 99f0dbe..744cc11 100644
@@ -31,7 +31,7 @@
 #endif
 #include "hw/arm/arm.h"
 #include "sysemu/sysemu.h"
-#include "sysemu/kvm.h"
+#include "sysemu/hw_accel.h"
 #include "kvm_arm.h"
 
 static void arm_cpu_set_pc(CPUState *cs, vaddr value)
target-i386/helper.c +1 -0
index 4ecc091..7530280 100644
@@ -24,6 +24,7 @@
 #include "kvm_i386.h"
 #ifndef CONFIG_USER_ONLY
 #include "sysemu/sysemu.h"
+#include "sysemu/hw_accel.h"
 #include "monitor/monitor.h"
 #include "hw/i386/apic_internal.h"
 #endif
target-i386/kvm.c +0 -0
index 1c0864e..d9ad69e 100644

target-i386/kvm.c line 29

Quoted 7 lines
target-i386/kvm.c +1 -0
@@ -23,6 +23,7 @@
 #include "qemu-common.h"
 #include "cpu.h"
 #include "sysemu/sysemu.h"
+#include "sysemu/hw_accel.h"
 #include "sysemu/kvm_int.h"
 #include "kvm_i386.h"
 #include "hyperv.h"
#3 lore raw

PATCH 2/3 target-i386: Add Intel HAX files

In reply to Vincent Palatin

That's a forward port of the core HAX interface code mostly unmodified from emu-2.2-release branch in the external/qemu-android repository as used by the Android emulator.

The original commit was "target-i386: Add Intel HAX to android emulator" saying:
"""
Backport of 2b3098ff27bab079caab9b46b58546b5036f5c0c
from studio-1.4-dev into emu-master-dev

Intel HAX (harware acceleration) will enhance android emulator performance in Windows and Mac OS X in the systems powered by Intel processors with "Intel Hardware Accelerated Execution Manager" package installed when user runs android emulator with Intel target.

"""

It has minor modifications to build and run along with the current code base.

---
 hax-stub.c                  |   66 ++
 include/sysemu/hax.h        |   66 ++
 target-i386/hax-all.c       | 1449 +++++++++++++++++++++++++++++++++++++++++++
 target-i386/hax-darwin.c    |  315 ++++++++++
 target-i386/hax-darwin.h    |   63 ++
 target-i386/hax-i386.h      |   94 +++
 target-i386/hax-interface.h |  357 +++++++++++
 target-i386/hax-slot.c      |  332 ++++++++++
 target-i386/hax-slot.h      |   58 ++
 target-i386/hax-windows.c   |  478 ++++++++++++++
 target-i386/hax-windows.h   |   89 +++
 11 files changed, 3367 insertions(+)
 create mode 100644 hax-stub.c
 create mode 100644 include/sysemu/hax.h
 create mode 100644 target-i386/hax-all.c
 create mode 100644 target-i386/hax-darwin.c
 create mode 100644 target-i386/hax-darwin.h
 create mode 100644 target-i386/hax-i386.h
 create mode 100644 target-i386/hax-interface.h
 create mode 100644 target-i386/hax-slot.c
 create mode 100644 target-i386/hax-slot.h
 create mode 100644 target-i386/hax-windows.c
 create mode 100644 target-i386/hax-windows.h
hax-stub.c new file +66 -0
new file mode 100644
index 0000000..cbdf791
@@ -0,0 +1,66 @@
+/*
+ * QEMU HAXM support
+ *
+ * Copyright (c) 2015, Intel Corporation
+ *
+ * Copyright 2016 Google, Inc.
+ *
+ * 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.
+ *
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "cpu.h"
+#include "sysemu/hax.h"
+
+int hax_sync_vcpus(void)
+{
+    return 0;
+}
+
+void hax_disable(int disable)
+{
+   return;
+}
+
+int hax_pre_init(uint64_t ram_size)
+{
+   return 0;
+}
+
+int hax_get_max_ram(uint64_t *max_ram) {
+    return 0;
+}
+
+int hax_populate_ram(uint64_t va, uint32_t size) {
+    return -ENOSYS;
+}
+
+int hax_init_vcpu(CPUState *cpu) {
+    return -ENOSYS;
+}
+
+int hax_smp_cpu_exec(CPUState *cpu) {
+    return -ENOSYS;
+}
+
+int hax_vcpu_exec(CPUState *cpu) {
+    return -ENOSYS;
+}
+
+int hax_vcpu_emulation_mode(CPUState *cpu) {
+    return 0;
+}
+
+int hax_stop_emulation(CPUState *cpu) {
+    return 0;
+}
+
+int hax_stop_translate(CPUState *cpu) {
+    return 0;
+}
include/sysemu/hax.h new file +66 -0

66 lines not on this page · raw message

target-i386/hax-all.c new file +1449 -0

1,449 lines not on this page · raw message

target-i386/hax-darwin.c new file +315 -0

315 lines not on this page · raw message

target-i386/hax-darwin.h new file +63 -0

63 lines not on this page · raw message

target-i386/hax-i386.h new file +94 -0

94 lines not on this page · raw message

target-i386/hax-interface.h new file +357 -0

357 lines not on this page · raw message

target-i386/hax-slot.c new file +332 -0

332 lines not on this page · raw message

target-i386/hax-slot.h new file +58 -0

58 lines not on this page · raw message

target-i386/hax-windows.c new file +478 -0

200 lines not on this page · raw message

target-i386/hax-windows.h new file +89 -0

89 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

Signature · 1 line
2.8.0.rc3.226.g39d4020

Part of the diff is not shown here. View the raw message.

#4 lore raw

Re: [Qemu-devel] [PATCH 2/3] target-i386: Add Intel HAX files

target-i386/hax-all.c line 607

Quoted 4 lines · Vincent Palatin
target-i386/hax-all.c new file +4 -0
+        /* need tcg for non-UG platform in real mode */
+        if (!hax_ug_platform())
+           tcg_exec_init(tcg_tb_size * 1024 * 1024);
+

Oh, it does support unrestricted guest, and in fact without unrestricted guest you don't even have SMP!

Would you post a v2 that removes (after this patch 2) as much code as possible related to non-UG platforms?

Paolo

#5 lore raw

Re: [Qemu-devel] [PATCH 2/3] target-i386: Add Intel HAX files

Quoted 8 lines · Paolo Bonzini

target-i386/hax-all.c line 607

Quoted 4 lines · Vincent Palatin
target-i386/hax-all.c new file +4 -0
+        /* need tcg for non-UG platform in real mode */
+        if (!hax_ug_platform())
+           tcg_exec_init(tcg_tb_size * 1024 * 1024);
+
Quoted 5 lines

Oh, it does support unrestricted guest, and in fact without unrestricted guest you don't even have SMP!

Would you post a v2 that removes (after this patch 2) as much code as possible related to non-UG platforms?

Yes I can do this.

Signature · 1 line
Vincent
#6 lore raw

Re: [Qemu-devel] [PATCH 2/3] target-i386: Add Intel HAX files

In reply to Paolo Bonzini
Quoted 8 lines · Paolo Bonzini

target-i386/hax-all.c line 607

Quoted 4 lines · Vincent Palatin
target-i386/hax-all.c new file +4 -0
+        /* need tcg for non-UG platform in real mode */
+        if (!hax_ug_platform())
+           tcg_exec_init(tcg_tb_size * 1024 * 1024);
+
Quoted 5 lines

Oh, it does support unrestricted guest, and in fact without unrestricted guest you don't even have SMP!

Would you post a v2 that removes (after this patch 2) as much code as possible related to non-UG platforms?

I have prepared this, I will post it soon as part of my v2 series.

Signature · 1 line
Vincent
#7 lore raw

Re: [Qemu-devel] [PATCH 2/3] target-i386: Add Intel HAX files

In reply to Vincent Palatin

On Tue, Nov 08, 2016 at 04:39:28PM +0100, Vincent Palatin wrote:

Please run scripts/checkpatch.pl to verify that the code follows the QEMU coding style.

target-i386/hax-darwin.c line 224

Quoted 13 lines
target-i386/hax-darwin.c new file +13 -0
+hax_fd hax_host_open_vcpu(int vmid, int vcpuid)
+{
+    char *devfs_path = NULL;
+    hax_fd fd;
+
+    devfs_path = hax_vcpu_devfs_string(vmid, vcpuid);
+    if (!devfs_path) {
+        fprintf(stderr, "Failed to get the devfs\n");
+        return -EINVAL;
+    }
+
+    fd = open(devfs_path, O_RDWR);
+    qemu_vfree(devfs_path);

g_malloc(), g_new(), g_strdup(), etc must be matched with g_free(), not qemu_vfree(). There are probably other instances of this issue in the patches.

target-i386/hax-slot.c line 32

Quoted 9 lines
target-i386/hax-slot.c new file +9 -0
+//#define DEBUG_HAX_SLOT
+
+#ifdef DEBUG_HAX_SLOT
+#define DPRINTF(fmt, ...) \
+    do { fprintf(stdout, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif

Please consider using tracing instead of debug printfs. See docs/tracing.txt.

If you really want to keep macros, please use:

#define DEBUG_HAX_SLOT 0

#define DPRINTF(fmt, ...) \
    do { \
        if (DEBUG_HAX_SLOT) { \
            fprintf(stdout, fmt, ## __VA_ARGS__); \
        } \
    } while (0)

This approach prevents bitrot because it allows the compiler to syntax check the format string and arguments even when the printf is compiled out.

#8 lore raw

Re: [Qemu-devel] [PATCH 2/3] target-i386: Add Intel HAX files

Quoted 4 lines · Stefan Hajnoczi

On Tue, Nov 08, 2016 at 04:39:28PM +0100, Vincent Palatin wrote:

Please run scripts/checkpatch.pl to verify that the code follows the QEMU coding style.

My original plan was to import those files unmodified but this ship has probably long-sailed.
Fixed in the v2 of this patch.

Quoted 10 lines
Quoted 10 lines
target-i386/hax-darwin.c new file +9 -0
+hax_fd hax_host_open_vcpu(int vmid, int vcpuid)
+{
+    char *devfs_path = NULL;
+    hax_fd fd;
+
+    devfs_path = hax_vcpu_devfs_string(vmid, vcpuid);
+    if (!devfs_path) {
+        fprintf(stderr, "Failed to get the devfs\n");
+        return -EINVAL;
Quoted 8 lines

target-i386/hax-darwin.c line 224

Quoted 4 lines
target-i386/hax-darwin.c new file +4 -0
+    }
+
+    fd = open(devfs_path, O_RDWR);
+    qemu_vfree(devfs_path);

g_malloc(), g_new(), g_strdup(), etc must be matched with g_free(), not qemu_vfree(). There are probably other instances of this issue in the patches.

Found 2 instances by grepping and fixed them.

Quoted 23 lines

target-i386/hax-slot.c line 32

Quoted 10 lines
target-i386/hax-slot.c new file +9 -0
+//#define DEBUG_HAX_SLOT
+
+#ifdef DEBUG_HAX_SLOT
+#define DPRINTF(fmt, ...) \
+    do { fprintf(stdout, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif

Please consider using tracing instead of debug printfs. See docs/tracing.txt.

If you really want to keep macros, please use:

#define DEBUG_HAX_SLOT 0

#define DPRINTF(fmt, ...) \
    do { \
        if (DEBUG_HAX_SLOT) { \
            fprintf(stdout, fmt, ## __VA_ARGS__); \
        } \
    } while (0)
Quoted 3 lines

This approach prevents bitrot because it allows the compiler to syntax check the format string and arguments even when the printf is compiled out.

For the v2 of this patch, I will keep the macros and do your approach. Then I will review all the debug print statements, see what I should do with them in another patch (convert to tracing / remove).

#9 lore raw

PATCH 3/3 Plumb the HAXM-based hardware acceleration support

In reply to Vincent Palatin

Use the Intel HAX is kernel-based hardware acceleration module for Windows and MacOSX (similar to KVM on Linux).

Based on the "target-i386: Add Intel HAX to android emulator" patch from David Chou <[email protected]>

---
 Makefile.target           |   1 +
 configure                 |  18 +++++++
 cpu-exec.c                |  23 ++++++++-
 cpus.c                    | 125 ++++++++++++++++++++++++++++++++++++++++------
 exec.c                    |  16 ++++++
 hw/intc/apic_common.c     |   3 +-
 include/qom/cpu.h         |   5 ++
 include/sysemu/hw_accel.h |   9 ++++
 qemu-options.hx           |  11 ++++
 target-i386/Makefile.objs |   7 +++
 target-i386/seg_helper.c  |   5 ++
 target-i386/translate.c   |   8 +++
 vl.c                      |  17 +++++--
 13 files changed, 229 insertions(+), 19 deletions(-)
Makefile.target +1 -0
index 7a5080e..dab81e7 100644
@@ -96,6 +96,7 @@ obj-y += target-$(TARGET_BASE_ARCH)/
 obj-y += disas.o
 obj-y += tcg-runtime.o
 obj-$(call notempty,$(TARGET_XML_FILES)) += gdbstub-xml.o
+obj-$(call lnot,$(CONFIG_HAX)) += hax-stub.o
 obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
 
 obj-$(CONFIG_LIBDECNUMBER) += libdecnumber/decContext.o
configure +18 -0
index fd6f898..424453b 100755
@@ -230,6 +230,7 @@ vhost_net="no"
 vhost_scsi="no"
 vhost_vsock="no"
 kvm="no"
+hax="no"
 colo="yes"
 rdma=""
 gprof="no"
@@ -563,6 +564,7 @@ CYGWIN*)
 ;;
 MINGW32*)
   mingw32="yes"
+  hax="yes"
   audio_possible_drivers="dsound sdl"
   if check_include dsound.h; then
     audio_drv_list="dsound"
@@ -610,6 +612,7 @@ OpenBSD)
 Darwin)
   bsd="yes"
   darwin="yes"
+  hax="yes"
   LDFLAGS_SHARED="-bundle -undefined dynamic_lookup"
   if [ "$cpu" = "x86_64" ] ; then
     QEMU_CFLAGS="-arch x86_64 $QEMU_CFLAGS"
@@ -919,6 +922,10 @@ for opt do
   ;;
   --enable-kvm) kvm="yes"
   ;;
+  --disable-hax) hax="no"
+  ;;
+  --enable-hax) hax="yes"
+  ;;
   --disable-colo) colo="no"
   ;;
   --enable-colo) colo="yes"
@@ -1371,6 +1378,7 @@ disabled with --disable-FEATURE, default is enabled if available:
   fdt             fdt device tree
   bluez           bluez stack connectivity
   kvm             KVM acceleration support
+  hax             HAX acceleration support
   colo            COarse-grain LOck-stepping VM for Non-stop Service
   rdma            RDMA-based migration support
   vde             support for vde network
@@ -5038,6 +5046,7 @@ echo "ATTR/XATTR support $attr"
 echo "Install blobs     $blobs"
 echo "KVM support       $kvm"
 echo "COLO support      $colo"
+echo "HAX support       $hax"
 echo "RDMA support      $rdma"
 echo "TCG interpreter   $tcg_interpreter"
 echo "fdt support       $fdt"
@@ -6022,6 +6031,15 @@ case "$target_name" in
       fi
     fi
 esac
+if test "$hax" = "yes" ; then
+  if test "$target_softmmu" = "yes" ; then
+    case "$target_name" in
+    i386|x86_64)
+      echo "CONFIG_HAX=y" >> $config_target_mak
+    ;;
+    esac
+  fi
+fi
 if test "$target_bigendian" = "yes" ; then
   echo "TARGET_WORDS_BIGENDIAN=y" >> $config_target_mak
 fi
cpu-exec.c +22 -1
index 4188fed..4bd238b 100644
@@ -25,6 +25,7 @@
 #include "qemu/atomic.h"
 #include "sysemu/qtest.h"
 #include "qemu/timer.h"
+#include "sysemu/hax.h"
 #include "exec/address-spaces.h"
 #include "qemu/rcu.h"
 #include "exec/tb-hash.h"
@@ -461,11 +462,24 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
     return false;
 }
 
+/*
+ * QEMU emulate can happens because of MMIO or emulation mode, i.e. non-PG mode,
+ * when it's because of MMIO, the MMIO, the interrupt should not be emulated,
+ * because MMIO is emulated for only one instruction now and then back to
+ * HAX kernel
+ */
+static int need_handle_intr_request(CPUState *cpu)
+{
+    if (!hax_enabled() || hax_vcpu_emulation_mode(cpu))
+        return cpu->interrupt_request;
+    return 0;
+}
+
 static inline void cpu_handle_interrupt(CPUState *cpu,
                                         TranslationBlock **last_tb)
 {
     CPUClass *cc = CPU_GET_CLASS(cpu);
-    int interrupt_request = cpu->interrupt_request;
+    int interrupt_request = need_handle_intr_request(cpu);
 
     if (unlikely(interrupt_request)) {
         if (unlikely(cpu->singlestep_enabled & SSTEP_NOIRQ)) {
@@ -632,10 +646,17 @@ int cpu_exec(CPUState *cpu)
                 break;
             }
 
+            if (hax_enabled() && !hax_vcpu_exec(cpu))
+                longjmp(cpu->jmp_env, 1);
+
             for(;;) {
                 cpu_handle_interrupt(cpu, &last_tb);
                 tb = tb_find(cpu, last_tb, tb_exit);
                 cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit, &sc);
+
+                if (hax_enabled() && hax_stop_emulation(cpu))
+                    cpu_loop_exit(cpu);
+
                 /* Try to align the host and virtual clocks
                    if the guest is in advance */
                 align_clocks(&sc, cpu);
cpus.c +111 -14

175 lines not on this page · raw message

exec.c +16 -0
index 3d867f1..c46fabc 100644
@@ -31,6 +31,7 @@
 #include "hw/xen/xen.h"
 #endif
 #include "sysemu/kvm.h"
+#include "sysemu/hax.h"
 #include "sysemu/sysemu.h"
 #include "qemu/timer.h"
 #include "qemu/config-file.h"
@@ -1617,6 +1618,21 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
         } else {
             new_block->host = phys_mem_alloc(new_block->max_length,
                                              &new_block->mr->align);
+            /*
+             * In Hax, the qemu allocate the virtual address, and HAX kernel
+             * populate the memory with physical memory. Currently we have no
+             * paging, so user should make sure enough free memory in advance
+             */
+            if (hax_enabled()) {
+                int ret;
+                ret = hax_populate_ram((uint64_t)(uintptr_t)new_block->host,
+                                       new_block->max_length);
+                if (ret < 0) {
+                    error_setg(errp, "Hax failed to populate ram");
+                    return;
+                }
+            }
+
             if (!new_block->host) {
                 error_setg_errno(errp, errno,
                                  "cannot set up guest memory '%s'",
hw/intc/apic_common.c +2 -1
index d78c885..dd4cdc8 100644
@@ -316,9 +316,10 @@ static void apic_common_realize(DeviceState *dev, Error **errp)
 
     /* Note: We need at least 1M to map the VAPIC option ROM */
     if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK &&
-        ram_size >= 1024 * 1024) {
+        kvm_enabled() && ram_size >= 1024 * 1024) {
         vapic = sysbus_create_simple("kvmvapic", -1, NULL);
     }
+
     s->vapic = vapic;
     if (apic_report_tpr_access && info->enable_tpr_reporting) {
         info->enable_tpr_reporting(s, true);
include/qom/cpu.h +5 -0
index 3f79a8e..ca4d0fb 100644
@@ -227,6 +227,8 @@ struct CPUWatchpoint {
 struct KVMState;
 struct kvm_run;
 
+struct hax_vcpu_state;
+
 #define TB_JMP_CACHE_BITS 12
 #define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
 
@@ -392,6 +394,9 @@ struct CPUState {
        (absolute value) offset as small as possible.  This reduces code
        size, especially for hosts without large memory offsets.  */
     uint32_t tcg_exit_req;
+
+    bool hax_vcpu_dirty;
+    struct hax_vcpu_state *hax_vcpu;
 };
 
 QTAILQ_HEAD(CPUTailQ, CPUState);
include/sysemu/hw_accel.h +9 -0
index 03812cf..a0d5a9e 100644
@@ -20,6 +20,9 @@ static inline void cpu_synchronize_state(CPUState *cpu)
     if (kvm_enabled()) {
         kvm_cpu_synchronize_state(cpu);
     }
+    if (hax_enabled() && hax_ug_platform()) {
+        hax_cpu_synchronize_state(cpu);
+    }
 }
 
 static inline void cpu_synchronize_post_reset(CPUState *cpu)
@@ -27,6 +30,9 @@ static inline void cpu_synchronize_post_reset(CPUState *cpu)
     if (kvm_enabled()) {
         kvm_cpu_synchronize_post_reset(cpu);
     }
+    if (hax_enabled() && hax_ug_platform()) {
+        hax_cpu_synchronize_post_reset(cpu);
+    }
 }
 
 static inline void cpu_synchronize_post_init(CPUState *cpu)
@@ -34,6 +40,9 @@ static inline void cpu_synchronize_post_init(CPUState *cpu)
     if (kvm_enabled()) {
         kvm_cpu_synchronize_post_init(cpu);
     }
+    if (hax_enabled() && hax_ug_platform()) {
+        hax_cpu_synchronize_post_init(cpu);
+    }
 }
 
 #endif /* QEMU_HW_ACCEL_H */
qemu-options.hx +11 -0
index 4536e18..bd28219 100644
@@ -3259,6 +3259,17 @@ Enable KVM full virtualization support. This option is only available
 if KVM support is enabled when compiling.
 ETEXI
 
+DEF("enable-hax", 0, QEMU_OPTION_enable_hax, \
+    "-enable-hax     enable HAX virtualization support\n", QEMU_ARCH_I386)
+STEXI
+@item -enable-hax
+@findex -enable-hax
+Enable HAX (Hardware-based Acceleration eXecution) support. This option
+is only available if HAX support is enabled when compiling. HAX is only
+applicable to MAC and Windows platform, and thus does not conflict with
+KVM.
+ETEXI
+
 DEF("xen-domid", HAS_ARG, QEMU_OPTION_xen_domid,
     "-xen-domid id   specify xen guest domain id\n", QEMU_ARCH_ALL)
 DEF("xen-create", 0, QEMU_OPTION_xen_create,
target-i386/Makefile.objs +7 -0
index b223d79..8c53209 100644
@@ -5,3 +5,10 @@ obj-y += gdbstub.o
 obj-$(CONFIG_SOFTMMU) += machine.o arch_memory_mapping.o arch_dump.o monitor.o
 obj-$(CONFIG_KVM) += kvm.o hyperv.o
 obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
+# HAX support
+ifdef CONFIG_WIN32
+obj-$(CONFIG_HAX) += hax-all.o hax-slot.o hax-windows.o
+endif
+ifdef CONFIG_DARWIN
+obj-$(CONFIG_HAX) += hax-all.o hax-slot.o hax-darwin.o
+endif
target-i386/seg_helper.c +5 -0
index fb79f31..25b6003 100644
@@ -25,6 +25,7 @@
 #include "exec/exec-all.h"
 #include "exec/cpu_ldst.h"
 #include "exec/log.h"
+#include "sysemu/hax.h"
 
 //#define DEBUG_PCALL
 
@@ -1336,6 +1337,10 @@ bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
             !(env->hflags & HF_SMM_MASK)) {
             cpu_svm_check_intercept_param(env, SVM_EXIT_SMI, 0);
             cs->interrupt_request &= ~CPU_INTERRUPT_SMI;
+#ifdef CONFIG_HAX
+            if (hax_enabled())
+                cs->hax_vcpu->resync = 1;
+#endif
             do_smm_enter(cpu);
             ret = true;
         } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
target-i386/translate.c +8 -0
index 324103c..e027896 100644
@@ -30,6 +30,7 @@
 
 #include "trace-tcg.h"
 #include "exec/log.h"
+#include "sysemu/hax.h"
 
 
 #define PREFIX_REPZ   0x01
@@ -8421,6 +8422,13 @@ void gen_intermediate_code(CPUX86State *env, TranslationBlock *tb)
         }
 
         pc_ptr = disas_insn(env, dc, pc_ptr);
+
+        if (hax_enabled() && hax_stop_translate(cs)) {
+            gen_jmp_im(pc_ptr - dc->cs_base);
+            gen_eob(dc);
+            break;
+        }
+
         /* stop translation if indicated */
         if (dc->is_jmp)
             break;
vl.c +14 -3
index 319f641..3804b9b 100644
@@ -92,6 +92,7 @@ int main(int argc, char **argv)
 #include "sysemu/cpus.h"
 #include "migration/colo.h"
 #include "sysemu/kvm.h"
+#include "sysemu/hax.h"
 #include "qapi/qmp/qjson.h"
 #include "qemu/option.h"
 #include "qemu/config-file.h"
@@ -1959,7 +1960,7 @@ static void main_loop(void)
     int64_t ti;
 #endif
     do {
-        nonblocking = !kvm_enabled() && !xen_enabled() && last_io > 0;
+        nonblocking = !kvm_enabled() && !xen_enabled() && !hax_enabled() && last_io > 0;
 #ifdef CONFIG_PROFILER
         ti = profile_getclock();
 #endif
@@ -3724,6 +3725,11 @@ int main(int argc, char **argv, char **envp)
                 olist = qemu_find_opts("machine");
                 qemu_opts_parse_noisily(olist, "accel=kvm", false);
                 break;
+            case QEMU_OPTION_enable_hax:
+                olist = qemu_find_opts("machine");
+                qemu_opts_parse_noisily(olist, "accel=hax", false);
+                hax_disable(0);
+                break;
             case QEMU_OPTION_M:
             case QEMU_OPTION_machine:
                 olist = qemu_find_opts("machine");
@@ -4060,6 +4066,7 @@ int main(int argc, char **argv, char **envp)
     machine_class = select_machine();
 
     set_memory_options(&ram_slots, &maxram_size, machine_class);
+    hax_pre_init(ram_size);
 
     os_daemonize();
 
@@ -4418,8 +4425,8 @@ int main(int argc, char **argv, char **envp)
 
     cpu_ticks_init();
     if (icount_opts) {
-        if (kvm_enabled() || xen_enabled()) {
-            error_report("-icount is not allowed with kvm or xen");
+        if (kvm_enabled() || xen_enabled() || hax_enabled()) {
+            error_report("-icount is not allowed with kvm or xen or hax");
             exit(1);
         }
         configure_icount(icount_opts, &error_abort);
@@ -4555,6 +4562,10 @@ int main(int argc, char **argv, char **envp)
 
     numa_post_machine_init();
 
+    if (hax_enabled()) {
+        hax_sync_vcpus();
+    }
+
     if (qemu_opts_foreach(qemu_find_opts("fw_cfg"),
                           parse_fw_cfg, fw_cfg_find(), NULL) != 0) {
         exit(1);
Signature · 1 line
2.8.0.rc3.226.g39d4020
#10 lore raw

Re: [Qemu-devel] [PATCH 3/3] Plumb the HAXM-based hardware acceleration support

cpu-exec.c

Quoted 5 lines
cpu-exec.c +0 -0
index 4188fed..4bd238b 100644

All this should not be needed anymore with unrestricted guest support.

Quoted 79 lines
cpus.c +47 -9
index fc78502..6e0f572 100644
@@ -35,6 +35,7 @@
 #include "sysemu/dma.h"
 #include "sysemu/hw_accel.h"
 #include "sysemu/kvm.h"
+#include "sysemu/hax.h"
 #include "qmp-commands.h"
 #include "exec/exec-all.h"
 
@@ -1221,6 +1222,52 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
     return NULL;
 }
 
+static void *qemu_hax_cpu_thread_fn(void *arg)
+{
+    CPUState *cpu = arg;
+    int r;
+    qemu_thread_get_self(cpu->thread);
+    qemu_mutex_lock(&qemu_global_mutex);
+
+    cpu->thread_id = qemu_get_thread_id();
+    cpu->created = true;
+    cpu->halted = 0;
+    current_cpu = cpu;
+
+    hax_init_vcpu(cpu);
+    qemu_cond_signal(&qemu_cpu_cond);
+
+    while (1) {
+        if (cpu_can_run(cpu)) {
+            r = hax_smp_cpu_exec(cpu);
+            if (r == EXCP_DEBUG) {
+                cpu_handle_guest_debug(cpu);
+            }
+        }
+
+        while (cpu_thread_is_idle(cpu)) {
+            qemu_cond_wait(cpu->halt_cond, &qemu_global_mutex);
+        }
+
+        qemu_wait_io_event_common(cpu);
+    }
+    return NULL;
+}
+
+
+static void qemu_cpu_kick_no_halt(void)
+{
+    CPUState *cpu;
+    /* Ensure whatever caused the exit has reached the CPU threads before
+     * writing exit_request.
+     */
+    atomic_mb_set(&exit_request, 1);
+    cpu = atomic_mb_read(&tcg_current_cpu);
+    if (cpu) {
+        cpu_exit(cpu);
+    }
+}
+
 static void qemu_cpu_kick_thread(CPUState *cpu)
 {
 #ifndef _WIN32
@@ -1235,28 +1282,52 @@ static void qemu_cpu_kick_thread(CPUState *cpu)
         fprintf(stderr, "qemu:%s: %s", __func__, strerror(err));
         exit(1);
     }
-#else /* _WIN32 */
-    abort();
-#endif
-}
 
-static void qemu_cpu_kick_no_halt(void)
-{
-    CPUState *cpu;
-    /* Ensure whatever caused the exit has reached the CPU threads before
-     * writing exit_request.

cpus.c static void qemu_cpu_kick_thread(CPUState *cpu) · line 1291

Quoted 10 lines
cpus.c +5 -4
+#ifdef CONFIG_DARWIN
+    /* The cpu thread cannot catch it reliably when shutdown the guest on Mac.
+     * We can double check it and resend it
      */
-    atomic_mb_set(&exit_request, 1);
-    cpu = atomic_mb_read(&tcg_current_cpu);
-    if (cpu) {
-        cpu_exit(cpu);
+    if (!exit_request)
+        qemu_cpu_kick_no_halt();

This must be a conflict resolved wrong. exit_request is never read by the HAX code.

Quoted 20 lines
cpus.c +20 -0
+    if (hax_enabled() && hax_ug_platform())
+        cpu->exit_request = 1;
+#endif
+#else /* _WIN32 */
+    if (!qemu_cpu_is_self(cpu)) {
+        CONTEXT tcgContext;
+
+        if (SuspendThread(cpu->hThread) == (DWORD)-1) {
+            fprintf(stderr, "qemu:%s: GetLastError:%lu\n", __func__,
+                    GetLastError());
+            exit(1);
+        }
+
+        /* On multi-core systems, we are not sure that the thread is actually
+         * suspended until we can get the context.
+         */
+        tcgContext.ContextFlags = CONTEXT_CONTROL;
+        while (GetThreadContext(cpu->hThread, &tcgContext) != 0) {
+            continue;
+        }

cpus.c static void qemu_cpu_kick_thread(CPUState *cpu) · line 1322

Quoted 10 lines
cpus.c +10 -0
+
+        qemu_cpu_kick_no_halt();
+        if (hax_enabled() && hax_ug_platform())
+            cpu->exit_request = 1;
+
+        if (ResumeThread(cpu->hThread) == (DWORD)-1) {
+            fprintf(stderr, "qemu:%s: GetLastError:%lu\n", __func__,
+                    GetLastError());
+            exit(1);
+        }

This is weird too. The SuspendThread/ResumeThread dance comes from an old version of QEMU. It is not needed anymore and, again, qemu_cpu_kick_no_halt would only be useful if hax_ug_platform() is false.

Here, Linux/KVM uses a signal and pthread_kill. It's probably good for HAX on Darwin too, but not on Windows. It's possible that SuspendThread/ResumeThread just does the right thing (sort of by chance), in which case you can just keep it (removing qemu_cpu_kick_no_halt). However, there is a hax_raise_event in patch 2 that is unused. If you can figure out how to use it it would be better.

Quoted 8 lines
cpus.c +4 -0
@@ -1617,6 +1618,21 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
         } else {
             new_block->host = phys_mem_alloc(new_block->max_length,
                                              &new_block->mr->align);
+            /*
+             * In Hax, the qemu allocate the virtual address, and HAX kernel
+             * populate the memory with physical memory. Currently we have no
+             * paging, so user should make sure enough free memory in advance

cpus.c static void ram_block_add(RAMBlock *new_block, Error **errp) · line 1634

Quoted 10 lines
cpus.c +10 -0
+             */
+            if (hax_enabled()) {
+                int ret;
+                ret = hax_populate_ram((uint64_t)(uintptr_t)new_block->host,
+                                       new_block->max_length);
+                if (ret < 0) {
+                    error_setg(errp, "Hax failed to populate ram");
+                    return;
+                }
+            }

Please try removing this block and instead starting QEMU with -mem-prealloc. If it works, remove hax_populate_ram and just set mem_prealloc to 1 in hax_accel_init.

hw/intc/apic_common.c static void apic_common_realize(DeviceState *dev, Error **errp) · line 319

Quoted 13 lines
cpus.c +0 -0
             if (!new_block->host) {
                 error_setg_errno(errp, errno,
                                  "cannot set up guest memory '%s'",
hw/intc/apic_common.c +1 -1
index d78c885..dd4cdc8 100644
@@ -316,9 +316,10 @@ static void apic_common_realize(DeviceState *dev, Error **errp)
 
     /* Note: We need at least 1M to map the VAPIC option ROM */
     if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK &&
-        ram_size >= 1024 * 1024) {
+        kvm_enabled() && ram_size >= 1024 * 1024) {

This should rather be !hax_enabled(), despite the historical name mentions KVM.

Quoted 19 lines
hw/intc/apic_common.c +1 -0
         vapic = sysbus_create_simple("kvmvapic", -1, NULL);
     }
+
     s->vapic = vapic;
     if (apic_report_tpr_access && info->enable_tpr_reporting) {
         info->enable_tpr_reporting(s, true);
target-i386/seg_helper.c +1 -0
index fb79f31..25b6003 100644
@@ -25,6 +25,7 @@
 #include "exec/exec-all.h"
 #include "exec/cpu_ldst.h"
 #include "exec/log.h"
+#include "sysemu/hax.h"
 
 //#define DEBUG_PCALL
 

target-i386/seg_helper.c bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request) · line 1343

Quoted 7 lines
target-i386/seg_helper.c +4 -0
@@ -1336,6 +1337,10 @@ bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
             !(env->hflags & HF_SMM_MASK)) {
             cpu_svm_check_intercept_param(env, SVM_EXIT_SMI, 0);
             cs->interrupt_request &= ~CPU_INTERRUPT_SMI;
+#ifdef CONFIG_HAX
+            if (hax_enabled())
+                cs->hax_vcpu->resync = 1;
+#endif

Not needed for UG mode.

target-i386/translate.c

Quoted 7 lines
target-i386/seg_helper.c +0 -0
             do_smm_enter(cpu);
             ret = true;
         } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
target-i386/translate.c +0 -0
index 324103c..e027896 100644

Same.

target-i386/translate.c int main(int argc, char **argv, char **envp) · line 4069

Quoted 5 lines
target-i386/translate.c +1 -0
@@ -4060,6 +4066,7 @@ int main(int argc, char **argv, char **envp)
     machine_class = select_machine();
 
     set_memory_options(&ram_slots, &maxram_size, machine_class);
+    hax_pre_init(ram_size);

It should be possible to merge this with hax_accel_init.

target-i386/translate.c int main(int argc, char **argv, char **envp) · line 4429

Quoted 10 lines
target-i386/translate.c +2 -2
     os_daemonize();
 
@@ -4418,8 +4425,8 @@ int main(int argc, char **argv, char **envp)
 
     cpu_ticks_init();
     if (icount_opts) {
-        if (kvm_enabled() || xen_enabled()) {
-            error_report("-icount is not allowed with kvm or xen");
+        if (kvm_enabled() || xen_enabled() || hax_enabled()) {
+            error_report("-icount is not allowed with kvm or xen or hax");

Let's say it's only allowed with TCG. :) Again, thanks to UG mode if hax_enabled() you'll have !tcg_enabled().

Paolo

Quoted 15 lines
target-i386/translate.c +4 -0
             exit(1);
         }
         configure_icount(icount_opts, &error_abort);
@@ -4555,6 +4562,10 @@ int main(int argc, char **argv, char **envp)
 
     numa_post_machine_init();
 
+    if (hax_enabled()) {
+        hax_sync_vcpus();
+    }
+
     if (qemu_opts_foreach(qemu_find_opts("fw_cfg"),
                           parse_fw_cfg, fw_cfg_find(), NULL) != 0) {
         exit(1);
#11 lore raw

Re: [Qemu-devel] [PATCH 3/3] Plumb the HAXM-based hardware acceleration support

Quoted 7 lines · Paolo Bonzini

cpu-exec.c

Quoted 5 lines
cpu-exec.c +0 -0
index 4188fed..4bd238b 100644

All this should not be needed anymore with unrestricted guest support.

Removed in v2

Quoted 85 lines
Quoted 85 lines
cpus.c +50 -10
index fc78502..6e0f572 100644
@@ -35,6 +35,7 @@
 #include "sysemu/dma.h"
 #include "sysemu/hw_accel.h"
 #include "sysemu/kvm.h"
+#include "sysemu/hax.h"
 #include "qmp-commands.h"
 #include "exec/exec-all.h"
 
@@ -1221,6 +1222,52 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
     return NULL;
 }
 
+static void *qemu_hax_cpu_thread_fn(void *arg)
+{
+    CPUState *cpu = arg;
+    int r;
+    qemu_thread_get_self(cpu->thread);
+    qemu_mutex_lock(&qemu_global_mutex);
+
+    cpu->thread_id = qemu_get_thread_id();
+    cpu->created = true;
+    cpu->halted = 0;
+    current_cpu = cpu;
+
+    hax_init_vcpu(cpu);
+    qemu_cond_signal(&qemu_cpu_cond);
+
+    while (1) {
+        if (cpu_can_run(cpu)) {
+            r = hax_smp_cpu_exec(cpu);
+            if (r == EXCP_DEBUG) {
+                cpu_handle_guest_debug(cpu);
+            }
+        }
+
+        while (cpu_thread_is_idle(cpu)) {
+            qemu_cond_wait(cpu->halt_cond, &qemu_global_mutex);
+        }
+
+        qemu_wait_io_event_common(cpu);
+    }
+    return NULL;
+}
+
+
+static void qemu_cpu_kick_no_halt(void)
+{
+    CPUState *cpu;
+    /* Ensure whatever caused the exit has reached the CPU threads before
+     * writing exit_request.
+     */
+    atomic_mb_set(&exit_request, 1);
+    cpu = atomic_mb_read(&tcg_current_cpu);
+    if (cpu) {
+        cpu_exit(cpu);
+    }
+}
+
 static void qemu_cpu_kick_thread(CPUState *cpu)
 {
 #ifndef _WIN32
@@ -1235,28 +1282,52 @@ static void qemu_cpu_kick_thread(CPUState *cpu)
         fprintf(stderr, "qemu:%s: %s", __func__, strerror(err));
         exit(1);
     }
-#else /* _WIN32 */
-    abort();
-#endif
-}
 
-static void qemu_cpu_kick_no_halt(void)
-{
-    CPUState *cpu;
-    /* Ensure whatever caused the exit has reached the CPU threads before
-     * writing exit_request.
+#ifdef CONFIG_DARWIN
+    /* The cpu thread cannot catch it reliably when shutdown the guest on Mac.
+     * We can double check it and resend it
      */
-    atomic_mb_set(&exit_request, 1);
Quoted 8 lines

cpus.c static void qemu_cpu_kick_thread(CPUState *cpu) · line 1291

Quoted 5 lines
cpus.c +2 -3
-    cpu = atomic_mb_read(&tcg_current_cpu);
-    if (cpu) {
-        cpu_exit(cpu);
+    if (!exit_request)
+        qemu_cpu_kick_no_halt();

This must be a conflict resolved wrong. exit_request is never read by the HAX code.

Maybe, it already exists in the predating Android branch. I will need to sort out this.

Quoted 26 lines
Quoted 26 lines
cpus.c +25 -0
+    if (hax_enabled() && hax_ug_platform())
+        cpu->exit_request = 1;
+#endif
+#else /* _WIN32 */
+    if (!qemu_cpu_is_self(cpu)) {
+        CONTEXT tcgContext;
+
+        if (SuspendThread(cpu->hThread) == (DWORD)-1) {
+            fprintf(stderr, "qemu:%s: GetLastError:%lu\n", __func__,
+                    GetLastError());
+            exit(1);
+        }
+
+        /* On multi-core systems, we are not sure that the thread is actually
+         * suspended until we can get the context.
+         */
+        tcgContext.ContextFlags = CONTEXT_CONTROL;
+        while (GetThreadContext(cpu->hThread, &tcgContext) != 0) {
+            continue;
+        }
+
+        qemu_cpu_kick_no_halt();
+        if (hax_enabled() && hax_ug_platform())
+            cpu->exit_request = 1;
+
Quoted 8 lines

cpus.c static void qemu_cpu_kick_thread(CPUState *cpu) · line 1322

Quoted 5 lines
cpus.c +5 -0
+        if (ResumeThread(cpu->hThread) == (DWORD)-1) {
+            fprintf(stderr, "qemu:%s: GetLastError:%lu\n", __func__,
+                    GetLastError());
+            exit(1);
+        }

This is weird too. The SuspendThread/ResumeThread dance comes from an old version of QEMU. It is not needed anymore and,

Yes I knew I was re-introducing removed code, that's why my original message was reading "I'm not so happy with the qemu_cpu_kick_thread mess in cpus.c, if somebody can help/advise."
To be fair, your original commit message removing it was saying that this code was no longer useful for TCG, as there is no working support for KVM on Windows, I was not sure whether it might be useful in this case.

Quoted 9 lines

again,
qemu_cpu_kick_no_halt would only be useful if hax_ug_platform() is false.

Here, Linux/KVM uses a signal and pthread_kill. It's probably good for HAX on Darwin too, but not on Windows. It's possible that SuspendThread/ResumeThread just does the right thing (sort of by chance), in which case you can just keep it (removing qemu_cpu_kick_no_halt). However, there is a hax_raise_event in patch 2 that is unused. If you can figure out how to use it it would be better.

I still need to figure out this mess, I haven't made a working solution yet.

Quoted 16 lines
Quoted 16 lines
cpus.c +10 -0
@@ -1617,6 +1618,21 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
         } else {
             new_block->host = phys_mem_alloc(new_block->max_length,
                                              &new_block->mr->align);
+            /*
+             * In Hax, the qemu allocate the virtual address, and HAX kernel
+             * populate the memory with physical memory. Currently we have no
+             * paging, so user should make sure enough free memory in advance
+             */
+            if (hax_enabled()) {
+                int ret;
+                ret = hax_populate_ram((uint64_t)(uintptr_t)new_block->host,
+                                       new_block->max_length);
+                if (ret < 0) {
Quoted 8 lines

cpus.c static void ram_block_add(RAMBlock *new_block, Error **errp) · line 1634

Quoted 4 lines
cpus.c +4 -0
+                    error_setg(errp, "Hax failed to populate ram");
+                    return;
+                }
+            }

Please try removing this block and instead starting QEMU with -mem-prealloc. If it works, remove hax_populate_ram and just set mem_prealloc to 1 in hax_accel_init.

it's not working, later hax_set_ram() is unhappy about what it is finding the mappings.
By the way, even if it had worked at startup, under memory pressure, Windows might have evicted the physical pages (which is not supported by the HAXM kernel module)

I can try to move this in os_mem_prealloc() if you feel it's cleaner.

Quoted 10 lines
Quoted 10 lines
cpus.c +0 -0
             if (!new_block->host) {
                 error_setg_errno(errp, errno,
                                  "cannot set up guest memory '%s'",
hw/intc/apic_common.c +0 -0
index d78c885..dd4cdc8 100644
@@ -316,9 +316,10 @@ static void apic_common_realize(DeviceState *dev, Error **errp)
 
Quoted 7 lines

hw/intc/apic_common.c static void apic_common_realize(DeviceState *dev, Error **errp) · line 319

Quoted 4 lines
hw/intc/apic_common.c +1 -1
     /* Note: We need at least 1M to map the VAPIC option ROM */
     if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK &&
-        ram_size >= 1024 * 1024) {
+        kvm_enabled() && ram_size >= 1024 * 1024) {

This should rather be !hax_enabled(), despite the historical name mentions KVM.

Updated in v2, thanks for the hint.

Quoted 19 lines
Quoted 19 lines
hw/intc/apic_common.c +1 -0
         vapic = sysbus_create_simple("kvmvapic", -1, NULL);
     }
+
     s->vapic = vapic;
     if (apic_report_tpr_access && info->enable_tpr_reporting) {
         info->enable_tpr_reporting(s, true);
target-i386/seg_helper.c +1 -0
index fb79f31..25b6003 100644
@@ -25,6 +25,7 @@
 #include "exec/exec-all.h"
 #include "exec/cpu_ldst.h"
 #include "exec/log.h"
+#include "sysemu/hax.h"
 
 //#define DEBUG_PCALL
 
Quoted 10 lines

target-i386/seg_helper.c bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request) · line 1343

Quoted 8 lines
target-i386/seg_helper.c +4 -0
@@ -1336,6 +1337,10 @@ bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
             !(env->hflags & HF_SMM_MASK)) {
             cpu_svm_check_intercept_param(env, SVM_EXIT_SMI, 0);
             cs->interrupt_request &= ~CPU_INTERRUPT_SMI;
+#ifdef CONFIG_HAX
+            if (hax_enabled())
+                cs->hax_vcpu->resync = 1;
+#endif

Not needed for UG mode.

Removed in v2.

Quoted 11 lines

target-i386/translate.c

Quoted 8 lines
target-i386/seg_helper.c +0 -0
             do_smm_enter(cpu);
             ret = true;
         } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
target-i386/translate.c +0 -0
index 324103c..e027896 100644

Same.

Quoted 7 lines

target-i386/translate.c int main(int argc, char **argv, char **envp) · line 4069

Quoted 5 lines
target-i386/translate.c +1 -0
@@ -4060,6 +4066,7 @@ int main(int argc, char **argv, char **envp)
     machine_class = select_machine();
 
     set_memory_options(&ram_slots, &maxram_size, machine_class);
+    hax_pre_init(ram_size);

It should be possible to merge this with hax_accel_init.

Done in v2, I have added a new patch simplifying the init (i have also realized it contained Android specific code leftovers and was misusing the 'allowed' property of the AccelClass)

Quoted 5 lines
Quoted 5 lines
target-i386/translate.c +0 -0
     os_daemonize();
 
@@ -4418,8 +4425,8 @@ int main(int argc, char **argv, char **envp)
 
Quoted 9 lines

target-i386/translate.c int main(int argc, char **argv, char **envp) · line 4429

Quoted 6 lines
target-i386/translate.c +2 -2
     cpu_ticks_init();
     if (icount_opts) {
-        if (kvm_enabled() || xen_enabled()) {
-            error_report("-icount is not allowed with kvm or xen");
+        if (kvm_enabled() || xen_enabled() || hax_enabled()) {
+            error_report("-icount is not allowed with kvm or xen or hax");

Let's say it's only allowed with TCG. :) Again, thanks to UG mode if hax_enabled() you'll have !tcg_enabled().

Updated in v2.
I actually did not realize earlier that the interpreter mode was running with tcg_enabled

Quoted 18 lines

Paolo

Quoted 15 lines
target-i386/translate.c +4 -0
             exit(1);
         }
         configure_icount(icount_opts, &error_abort);
@@ -4555,6 +4562,10 @@ int main(int argc, char **argv, char **envp)
 
     numa_post_machine_init();
 
+    if (hax_enabled()) {
+        hax_sync_vcpus();
+    }
+
     if (qemu_opts_foreach(qemu_find_opts("fw_cfg"),
                           parse_fw_cfg, fw_cfg_find(), NULL) != 0) {
         exit(1);
#12 lore raw

Re: [Qemu-devel] [PATCH 3/3] Plumb the HAXM-based hardware acceleration support

Quoted 10 lines · Vincent Palatin
Quoted 3 lines
Quoted 3 lines

Please try removing this block and instead starting QEMU with -mem-prealloc. If it works, remove hax_populate_ram and just set mem_prealloc to 1 in hax_accel_init.

it's not working, later hax_set_ram() is unhappy about what it is finding the mappings.
By the way, even if it had worked at startup, under memory pressure, Windows might have evicted the physical pages (which is not supported by the HAXM kernel module)

I can try to move this in os_mem_prealloc() if you feel it's cleaner.

Yes, that would work!

Paolo

#13 lore raw

Re: [Qemu-devel] [PATCH 3/3] Plumb the HAXM-based hardware acceleration support

Quoted 12 lines · Paolo Bonzini
Quoted 9 lines · Vincent Palatin
Quoted 3 lines
Quoted 3 lines

Please try removing this block and instead starting QEMU with -mem-prealloc. If it works, remove hax_populate_ram and just set mem_prealloc to 1 in hax_accel_init.

it's not working, later hax_set_ram() is unhappy about what it is finding the mappings.
By the way, even if it had worked at startup, under memory pressure, Windows might have evicted the physical pages (which is not supported by the HAXM kernel module)

Quoted 3 lines
Quoted 1 line

I can try to move this in os_mem_prealloc() if you feel it's cleaner.

Yes, that would work!

Actually, os_mem_prealloc seems mostly no-op in the win32 version, I have postponed this change for after my v2 patchset.

Signature · 1 line
Vincent
#14 lore raw

Re: [Qemu-devel] [PATCH 3/3] Plumb the HAXM-based hardware acceleration support

Quoted 13 lines · Vincent Palatin
Quoted 12 lines · Paolo Bonzini
Quoted 9 lines · Vincent Palatin
Quoted 3 lines
Quoted 3 lines

Please try removing this block and instead starting QEMU with -mem-prealloc. If it works, remove hax_populate_ram and just set mem_prealloc to 1 in hax_accel_init.

it's not working, later hax_set_ram() is unhappy about what it is finding the mappings.
By the way, even if it had worked at startup, under memory pressure, Windows might have evicted the physical pages (which is not supported by the HAXM kernel module)

Quoted 6 lines
Quoted 3 lines
Quoted 1 line

I can try to move this in os_mem_prealloc() if you feel it's cleaner.

Yes, that would work!

Actually, os_mem_prealloc seems mostly no-op in the win32 version, I have postponed this change for after my v2 patchset.

Good, we'll sort it out during review.

Paolo

#15 lore raw
In reply to Vincent Palatin
Quoted 11 lines · Vincent Palatin

I took a stab at trying to rebase/upstream the support for Intel HAXM. (Hardware Accelerated Execution Manager).
Intel HAX is kernel-based hardware acceleration module for Windows and MacOSX.

I have based my work on the last version of the source code I found:
the emu-2.2-release branch in the external/qemu-android repository as used by the Android emulator.
In patch 2/3, I have forward-ported the core HAX code mostly unmodified from there, I just did some minor touch up to make it build and run properly. So it might contain some outdated constructs and probably requires more attention (thus the 'RFC' for this patchset).

Does HAXM support the "unrestricted guest" feature in Westmere and more recent processors? If so, I think we should only support those processors and slash all the part related to HAX_EMULATE_STATE_INITIAL and HAX_EMULATE_STATE_REAL. This would probably let us make patch 3 much less intrusive.

That said, patch 3's cpu-exec.c surgery is much nicer on the surface than if you look in depth, :) and since you don't look in depth if you steer clear of target-i386/hax*, I think it's okay to start with your patches and clean up progressively. Others may disagree... Also, we're now in soft freeze so the patches wouldn't be merged anyway for a few weeks.

Paolo

#16 lore raw
Quoted 16 lines · Paolo Bonzini
Quoted 11 lines · Vincent Palatin

I took a stab at trying to rebase/upstream the support for Intel HAXM. (Hardware Accelerated Execution Manager).
Intel HAX is kernel-based hardware acceleration module for Windows and MacOSX.

I have based my work on the last version of the source code I found:
the emu-2.2-release branch in the external/qemu-android repository as used by the Android emulator.
In patch 2/3, I have forward-ported the core HAX code mostly unmodified from there, I just did some minor touch up to make it build and run properly. So it might contain some outdated constructs and probably requires more attention (thus the 'RFC' for this patchset).

Quoted 2 lines

Does HAXM support the "unrestricted guest" feature in Westmere and more recent processors?

Yes it does, as mentioned in the last paragraph of my message, I have actually done a fair chunk of my testing in UG mode.

Quoted 5 lines

If so, I think we should only support those
processors and slash all the part related to HAX_EMULATE_STATE_INITIAL and HAX_EMULATE_STATE_REAL. This would probably let us make patch 3 much less intrusive.

Sure the whole patchset would be lighter, not sure which proportion of user have VT machines without UG support though.

Quoted 8 lines

That said, patch 3's cpu-exec.c surgery is much nicer on the surface than if you look in depth, :) and since you don't look in depth if you steer clear of target-i386/hax*, I think it's okay to start with your patches and clean up progressively. Others may disagree... Also, we're now in soft freeze so the patches wouldn't be merged anyway for a few weeks.

Paolo

#17 lore raw
Quoted 7 lines · Vincent Palatin
Quoted 4 lines

If so, I think we should only support those
processors and slash all the part related to HAX_EMULATE_STATE_INITIAL and HAX_EMULATE_STATE_REAL. This would probably let us make patch 3 much less intrusive.

Sure the whole patchset would be lighter, not sure which proportion of user have VT machines without UG support though.

All Intel machines sold after ~2010 should have unrestricted guest support. (HAX doesn't support AMD, but anyway AMD's virt extensions have always had the equivalent feature).

I'm not sure we want !UG support at all but, if we do, QEMU 2.9 will have multithreaded TCG so it would be possible to make it less intrusive. So it's worth starting with the minimum patchset and see what happens.

Thanks for working on this!

Paolo