pkgsrc-WIP-changes archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Qemu with NVMM acceleration support.



Module Name:	pkgsrc-wip
Committed By:	user <user@localhost.localdomain>
Pushed By:	maxv
Date:		Sat Nov 3 17:53:48 2018 +0100
Changeset:	b86bdefe394d2f1c230d8a882370e90f7155481d

Added Files:
	qemu-nvmm/DESCR
	qemu-nvmm/Makefile
	qemu-nvmm/PLIST
	qemu-nvmm/distinfo
	qemu-nvmm/files/Makefile.multinode-NetBSD
	qemu-nvmm/options.mk
	qemu-nvmm/patches/patch-Makefile
	qemu-nvmm/patches/patch-audio_audio.c
	qemu-nvmm/patches/patch-block.c
	qemu-nvmm/patches/patch-contrib_ivshmem-client_ivshmem-client.c
	qemu-nvmm/patches/patch-contrib_ivshmem-server_ivshmem-server.c
	qemu-nvmm/patches/patch-hw_display_omap__dss.c
	qemu-nvmm/patches/patch-hw_net_etraxfs__eth.c
	qemu-nvmm/patches/patch-hw_net_xilinx__axienet.c
	qemu-nvmm/patches/patch-hw_usb_dev-mtp.c
	qemu-nvmm/patches/patch-nvmm-support
	qemu-nvmm/patches/patch-tests_Makefile.include

Log Message:
Qemu with NVMM acceleration support.

	qemu-system-x86_64 [... whatever ...] -accel nvmm

Same as the 'qemu' package, but with patch-nvmm-support applied, and only
x86_64 as target.

Builds, launches, but doesn't work yet. The second call to nvmm_gpa_map fails,
because qemu is trying to map twice the same gpa, and I don't understand what
is the expected behavior in this case. I guess I'll have to ask them.

Eventually the patch will be merged upstream, and our generic 'qemu' package
will be built with --enable-nvmm by default on NetBSD.

To see a diff of this commit:
https://wip.pkgsrc.org/cgi-bin/gitweb.cgi?p=pkgsrc-wip.git;a=commitdiff;h=b86bdefe394d2f1c230d8a882370e90f7155481d

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

diffstat:
 qemu-nvmm/DESCR                                    |   11 +
 qemu-nvmm/Makefile                                 |   97 ++
 qemu-nvmm/PLIST                                    |  108 ++
 qemu-nvmm/distinfo                                 |   17 +
 qemu-nvmm/files/Makefile.multinode-NetBSD          |   59 +
 qemu-nvmm/options.mk                               |   29 +
 qemu-nvmm/patches/patch-Makefile                   |   12 +
 qemu-nvmm/patches/patch-audio_audio.c              |   16 +
 qemu-nvmm/patches/patch-block.c                    |   42 +
 .../patch-contrib_ivshmem-client_ivshmem-client.c  |   37 +
 .../patch-contrib_ivshmem-server_ivshmem-server.c  |   36 +
 qemu-nvmm/patches/patch-hw_display_omap__dss.c     |   30 +
 qemu-nvmm/patches/patch-hw_net_etraxfs__eth.c      |   25 +
 qemu-nvmm/patches/patch-hw_net_xilinx__axienet.c   |   16 +
 qemu-nvmm/patches/patch-hw_usb_dev-mtp.c           |   17 +
 qemu-nvmm/patches/patch-nvmm-support               | 1479 ++++++++++++++++++++
 qemu-nvmm/patches/patch-tests_Makefile.include     |   17 +
 17 files changed, 2048 insertions(+)

diffs:
diff --git a/qemu-nvmm/DESCR b/qemu-nvmm/DESCR
new file mode 100644
index 0000000000..d939711a26
--- /dev/null
+++ b/qemu-nvmm/DESCR
@@ -0,0 +1,11 @@
+QEMU is a FAST! processor emulator using dynamic translation to achieve
+good emulation speed, QEMU has two operating modes:
+
+    * Full system emulation. In this mode, QEMU emulates a full system
+      (for example a PC), including a processor and various peripherals.
+      It can be used to launch different Operating Systems without rebooting
+      the PC or to debug system code.
+    * User mode emulation (Linux host only). In this mode, QEMU can launch
+      Linux processes compiled for one CPU on another CPU. It can be used
+      to launch the Wine Windows API emulator or to ease cross-compilation
+      and cross-debugging.
diff --git a/qemu-nvmm/Makefile b/qemu-nvmm/Makefile
new file mode 100644
index 0000000000..1b84067544
--- /dev/null
+++ b/qemu-nvmm/Makefile
@@ -0,0 +1,97 @@
+# $NetBSD: Makefile,v 1.191 2018/08/22 09:45:05 wiz Exp $
+
+DISTNAME=	qemu-3.0.0
+PKGREVISION=	2
+CATEGORIES=	emulators
+MASTER_SITES=	https://download.qemu.org/
+EXTRACT_SUFX=	.tar.xz
+
+MAINTAINER=	pkgsrc-users%NetBSD.org@localhost
+HOMEPAGE=	http://www.qemu-project.org/
+COMMENT=	CPU emulator using dynamic translation
+LICENSE=	gnu-gpl-v2 AND gnu-lgpl-v2.1 AND mit AND modified-bsd
+
+USE_CURSES=		resize_term wide
+USE_LANGUAGES+=		c c++
+USE_TOOLS+=		bison flex gmake makeinfo perl:build pkg-config
+FAKE_NCURSES=		yes
+UNLIMIT_RESOURCES=	datasize
+HAS_CONFIGURE=		yes
+
+BUILD_DEPENDS+=		texi2html-[0-9]*:../../textproc/texi2html
+
+SUBST_CLASSES+=			prefix
+SUBST_STAGE.prefix=		pre-configure
+SUBST_MESSAGE.prefix=		Setting PREFIX
+SUBST_FILES.prefix+=		configure
+SUBST_VARS.prefix+=		PREFIX
+
+.include "options.mk"
+
+.include "../../mk/bsd.prefs.mk"
+
+CONFIGURE_ARGS+=	--prefix=${PREFIX}
+CONFIGURE_ARGS+=	--interp-prefix=${PREFIX}/share/qemu
+CONFIGURE_ARGS+=	--sysconfdir=${PKG_SYSCONFDIR}
+CONFIGURE_ARGS+=	--python=${PYTHONBIN}
+CONFIGURE_ARGS+=	--smbd=${PREFIX}/sbin/smbd
+CONFIGURE_ARGS+=	--mandir=${PREFIX}/${PKGMANDIR}
+CONFIGURE_ARGS+=	--enable-curses
+CONFIGURE_ARGS+=	--enable-jemalloc
+CONFIGURE_ARGS+=	--disable-opengl
+CONFIGURE_ARGS+=	--target-list=x86_64-softmmu
+CONFIGURE_ARGS+=	--enable-nvmm
+CONFIGURE_ENV+=		mansuffix=/${PKGMANDIR}
+
+.if defined(PKGSRC_USE_SSP)
+# do not add flags to everything
+PKGSRC_USE_SSP=		no
+CONFIGURE_ARGS+=	--enable-stack-protector
+.endif
+
+NOT_PAX_MPROTECT_SAFE+=	bin/qemu-system-x86_64
+
+PKG_SYSCONFSUBDIR=	qemu
+
+REPLACE_PERL+=		scripts/texi2pod.pl
+
+PYTHON_VERSIONS_INCOMPATIBLE=	34 35 36 37 # not yet ported yet as of 2.10.0
+
+INSTALLATION_DIRS=	${PKGMANDIR}/man1 share/doc/qemu
+
+UE_ARCHS+=		x86_64
+
+.if ${OPSYS} == "NetBSD"
+USER_EMUL=		i386 x86_64 sparc sparc64
+PLIST.nbd=		YES
+.endif
+
+PLIST_VARS+=		${UE_ARCHS} nbd ivshmem
+.for pvar in ${USER_EMUL}
+PLIST.${pvar}=		YES
+.endfor
+
+TEST_TARGET=		check
+
+post-install:
+	${INSTALL_DATA} ${FILESDIR}/Makefile.multinode-NetBSD \
+		${DESTDIR}${PREFIX}/share/doc/qemu/
+
+# On Darwin, qemu uses Cocoa and CoreAudio
+.if ${OPSYS} != "Darwin"
+.include "../../mk/oss.buildlink3.mk"
+.endif
+.include "../../archivers/lzo/buildlink3.mk"
+.include "../../devel/glib2/buildlink3.mk"
+.include "../../devel/jemalloc/buildlink3.mk"
+.include "../../devel/snappy/buildlink3.mk"
+.include "../../devel/zlib/buildlink3.mk"
+.include "../../graphics/png/buildlink3.mk"
+.include "../../lang/python/extension.mk"
+.include "../../security/libgcrypt/buildlink3.mk"
+.include "../../www/curl/buildlink3.mk"
+.include "../../x11/pixman/buildlink3.mk"
+.include "../../mk/curses.buildlink3.mk"
+.include "../../mk/jpeg.buildlink3.mk"
+.include "../../mk/pthread.buildlink3.mk"
+.include "../../mk/bsd.pkg.mk"
diff --git a/qemu-nvmm/PLIST b/qemu-nvmm/PLIST
new file mode 100644
index 0000000000..d966b6499c
--- /dev/null
+++ b/qemu-nvmm/PLIST
@@ -0,0 +1,108 @@
+@comment $NetBSD$
+bin/qemu-ga
+bin/qemu-img
+bin/qemu-io
+bin/qemu-nbd
+bin/qemu-system-x86_64
+man/man1/qemu-img.1
+man/man1/qemu.1
+man/man7/qemu-block-drivers.7
+man/man7/qemu-ga-ref.7
+man/man7/qemu-qmp-ref.7
+man/man8/qemu-ga.8
+man/man8/qemu-nbd.8
+share/doc/qemu/Makefile.multinode-NetBSD
+share/doc/qemu/qemu-doc.html
+share/doc/qemu/qemu-doc.txt
+share/doc/qemu/qemu-ga-ref.html
+share/doc/qemu/qemu-ga-ref.txt
+share/doc/qemu/qemu-qmp-ref.html
+share/doc/qemu/qemu-qmp-ref.txt
+share/qemu/QEMU,cgthree.bin
+share/qemu/QEMU,tcx.bin
+share/qemu/bamboo.dtb
+share/qemu/bios-256k.bin
+share/qemu/bios.bin
+share/qemu/canyonlands.dtb
+share/qemu/efi-e1000.rom
+share/qemu/efi-e1000e.rom
+share/qemu/efi-eepro100.rom
+share/qemu/efi-ne2k_pci.rom
+share/qemu/efi-pcnet.rom
+share/qemu/efi-rtl8139.rom
+share/qemu/efi-virtio.rom
+share/qemu/efi-vmxnet3.rom
+share/qemu/hppa-firmware.img
+share/qemu/keymaps/ar
+share/qemu/keymaps/bepo
+share/qemu/keymaps/common
+share/qemu/keymaps/cz
+share/qemu/keymaps/da
+share/qemu/keymaps/de
+share/qemu/keymaps/de-ch
+share/qemu/keymaps/en-gb
+share/qemu/keymaps/en-us
+share/qemu/keymaps/es
+share/qemu/keymaps/et
+share/qemu/keymaps/fi
+share/qemu/keymaps/fo
+share/qemu/keymaps/fr
+share/qemu/keymaps/fr-be
+share/qemu/keymaps/fr-ca
+share/qemu/keymaps/fr-ch
+share/qemu/keymaps/hr
+share/qemu/keymaps/hu
+share/qemu/keymaps/is
+share/qemu/keymaps/it
+share/qemu/keymaps/ja
+share/qemu/keymaps/lt
+share/qemu/keymaps/lv
+share/qemu/keymaps/mk
+share/qemu/keymaps/modifiers
+share/qemu/keymaps/nl
+share/qemu/keymaps/nl-be
+share/qemu/keymaps/no
+share/qemu/keymaps/pl
+share/qemu/keymaps/pt
+share/qemu/keymaps/pt-br
+share/qemu/keymaps/ru
+share/qemu/keymaps/sl
+share/qemu/keymaps/sv
+share/qemu/keymaps/th
+share/qemu/keymaps/tr
+share/qemu/kvmvapic.bin
+share/qemu/linuxboot.bin
+share/qemu/linuxboot_dma.bin
+share/qemu/multiboot.bin
+share/qemu/openbios-ppc
+share/qemu/openbios-sparc32
+share/qemu/openbios-sparc64
+share/qemu/palcode-clipper
+share/qemu/petalogix-ml605.dtb
+share/qemu/petalogix-s3adsp1800.dtb
+share/qemu/ppc_rom.bin
+share/qemu/pxe-e1000.rom
+share/qemu/pxe-eepro100.rom
+share/qemu/pxe-ne2k_pci.rom
+share/qemu/pxe-pcnet.rom
+share/qemu/pxe-rtl8139.rom
+share/qemu/pxe-virtio.rom
+share/qemu/qemu-icon.bmp
+share/qemu/qemu_logo_no_text.svg
+share/qemu/qemu_vga.ndrv
+share/qemu/s390-ccw.img
+share/qemu/s390-netboot.img
+share/qemu/sgabios.bin
+share/qemu/skiboot.lid
+share/qemu/slof.bin
+share/qemu/spapr-rtas.bin
+share/qemu/trace-events-all
+share/qemu/u-boot-sam460-20100605.bin
+share/qemu/u-boot.e500
+share/qemu/vgabios-cirrus.bin
+share/qemu/vgabios-qxl.bin
+share/qemu/vgabios-stdvga.bin
+share/qemu/vgabios-virtio.bin
+share/qemu/vgabios-vmware.bin
+share/qemu/vgabios.bin
+@pkgdir var/run
diff --git a/qemu-nvmm/distinfo b/qemu-nvmm/distinfo
new file mode 100644
index 0000000000..d253dcb318
--- /dev/null
+++ b/qemu-nvmm/distinfo
@@ -0,0 +1,17 @@
+$NetBSD: distinfo,v 1.137 2018/08/16 10:15:09 adam Exp $
+
+SHA1 (qemu-3.0.0.tar.xz) = fffb4aa0139c7290295a129e040cec0df4468ea6
+RMD160 (qemu-3.0.0.tar.xz) = ea61cb8b6b144c7017c3a53161f883c3aeb15611
+SHA512 (qemu-3.0.0.tar.xz) = a764302f50b9aca4134bbbc1f361b98e71240cdc7b25600dfe733bf4cf17bd86000bd28357697b08f3b656899dceb9e459350b8d55557817444ed5d7fa380a5a
+Size (qemu-3.0.0.tar.xz) = 35624516 bytes
+SHA1 (patch-Makefile) = b3899fb8d0dd2f29bf3edd843836612e6e6c019c
+SHA1 (patch-audio_audio.c) = 98a1de2fd48638886b5d16f6a61dc72910e98b41
+SHA1 (patch-block.c) = 5eb15a87d6646719bf1e9277fbe73a99e4905481
+SHA1 (patch-contrib_ivshmem-client_ivshmem-client.c) = 40c8751607cbf66a37e4c4e08f2664b864e2e984
+SHA1 (patch-contrib_ivshmem-server_ivshmem-server.c) = d8f53432b5752f4263dc4ef96108a976a05147a3
+SHA1 (patch-hw_display_omap__dss.c) = 6b13242f28e32346bc70548c216c578d98fd3420
+SHA1 (patch-hw_net_etraxfs__eth.c) = e5dd1661d60dbcd27b332403e0843500ba9544bc
+SHA1 (patch-hw_net_xilinx__axienet.c) = ebcd2676d64ce6f31e4a8c976d4fdf530ad5e8b7
+SHA1 (patch-hw_usb_dev-mtp.c) = 66543b5559d92f8e2fa9a6eb85e5dfe7c1ad3339
+SHA1 (patch-nvmm-support) = 0058ec05dfcb8bd4ebbb416fd21e40c23ec9a3c1
+SHA1 (patch-tests_Makefile.include) = 42345d697cb2e324dccf1d68bd8d61e8001c6162
diff --git a/qemu-nvmm/files/Makefile.multinode-NetBSD b/qemu-nvmm/files/Makefile.multinode-NetBSD
new file mode 100644
index 0000000000..f4313832eb
--- /dev/null
+++ b/qemu-nvmm/files/Makefile.multinode-NetBSD
@@ -0,0 +1,59 @@
+# $Id: Makefile.multinode-NetBSD,v 1.4 2012/06/07 21:23:46 ryoon Exp $
+# Source: http://mail-index.NetBSD.org/netbsd-help/2005/03/25/0005.html
+#
+# Starts up two qemu instances and networks bridges them to the local
+# ethernet (ETHER_IF}.  Works best with NetBSD configured to use serial
+# consoles in DISK[12]
+#
+# Usage:
+#	sudo make netbsd1
+#	sudo make netbsd2
+#
+#  - Hubert Feyrer <hubert%feyrer.de@localhost>
+#
+
+#NETBSD_NOGFX=
+NETBSD_NOGFX=		-nographic
+
+ETHER_IF=	tlp0
+QEMU_RAM=	20
+DISK1=		harddisk.netbsd1
+DISK2=		harddisk.netbsd2
+
+
+all: netbsd1 netbsd2
+
+netbsd1: bridge 
+	ifconfig tap1 create up	     || echo tap1: already there
+	brconfig bridge0 add tap1 up || echo tap1: already on bridge0
+	brconfig bridge0 -learn tap1 # real hub mode, step 1b
+	brconfig bridge0 flush	# real hub more, step 2
+	qemu \	
+		-m ${QEMU_RAM} \
+		${NETBSD_NOGFX} \
+		-boot c \
+		-net tap,fd=3,ifname=tap1 3<>/dev/tap1 \
+		-net nic,macaddr=de:ad:be:ef:00:01 \
+		${DISK1}
+	brconfig bridge0 delete tap1 
+	ifconfig tap1 destroy
+
+netbsd2: bridge
+	ifconfig tap2 create up	     || echo tap2: already there
+	brconfig bridge0 add tap2 up || echo tap2: already on bridge0
+	brconfig bridge0 -learn tap2 # real hub mode, step 1c
+	brconfig bridge0 flush	     # real hub mode, step 2
+	qemu \
+		-m ${QEMU_RAM} \
+		${NETBSD_NOGFX} \
+		-boot c \
+		-net tap,fd=3,ifname=tap2 3<>/dev/tap2 \
+		-net nic,macaddr=de:ad:be:ef:00:02 \
+		${DISK2}
+	brconfig bridge0 delete tap2
+	ifconfig tap2 destroy
+	
+bridge:
+	ifconfig bridge0 create	  || echo bridge0: already there
+	brconfig bridge0 add ${ETHER_IF} || echo bridge0: ${ETHER_IF} already there
+	brconfig bridge0 -learn ${ETHER_IF} # real hub mode, step 1a
diff --git a/qemu-nvmm/options.mk b/qemu-nvmm/options.mk
new file mode 100644
index 0000000000..e7fbed3df6
--- /dev/null
+++ b/qemu-nvmm/options.mk
@@ -0,0 +1,29 @@
+# $NetBSD: options.mk,v 1.5 2018/08/14 06:57:26 adam Exp $
+
+PKG_OPTIONS_VAR=	PKG_OPTIONS.qemu
+PKG_SUPPORTED_OPTIONS=	gtk3 sdl
+
+.include "../../mk/bsd.fast.prefs.mk"
+
+.if ${OPSYS} != "Darwin"
+PKG_SUGGESTED_OPTIONS+=	sdl
+.endif
+
+.include "../../mk/bsd.options.mk"
+
+PLIST_VARS+=		gtk
+
+.if !empty(PKG_OPTIONS:Mgtk3)
+PLIST.gtk=		yes
+CONFIGURE_ARGS+=	--enable-gtk
+.include "../../x11/gtk3/buildlink3.mk"
+.else
+CONFIGURE_ARGS+=	--disable-gtk
+.endif
+
+.if !empty(PKG_OPTIONS:Msdl)
+CONFIGURE_ARGS+=	--enable-sdl
+.include "../../devel/SDL2/buildlink3.mk"
+.else
+CONFIGURE_ARGS+=	--disable-sdl
+.endif
diff --git a/qemu-nvmm/patches/patch-Makefile b/qemu-nvmm/patches/patch-Makefile
new file mode 100644
index 0000000000..76fa15ebb6
--- /dev/null
+++ b/qemu-nvmm/patches/patch-Makefile
@@ -0,0 +1,12 @@
+$NetBSD: patch-Makefile,v 1.1 2017/12/14 02:03:53 kamil Exp $
+
+--- Makefile.orig	2017-12-13 17:27:20.000000000 +0000
++++ Makefile
+@@ -385,6 +385,7 @@ subdir-%:
+ DTC_MAKE_ARGS=-I$(SRC_PATH)/dtc VPATH=$(SRC_PATH)/dtc -C dtc V="$(V)" LIBFDT_srcdir=$(SRC_PATH)/dtc/libfdt
+ DTC_CFLAGS=$(CFLAGS) $(QEMU_CFLAGS)
+ DTC_CPPFLAGS=-I$(BUILD_DIR)/dtc -I$(SRC_PATH)/dtc -I$(SRC_PATH)/dtc/libfdt
++ARFLAGS=	-rcs
+ 
+ subdir-dtc: .git-submodule-status dtc/libfdt dtc/tests
+ 	$(call quiet-command,$(MAKE) $(DTC_MAKE_ARGS) CPPFLAGS="$(DTC_CPPFLAGS)" CFLAGS="$(DTC_CFLAGS)" LDFLAGS="$(LDFLAGS)" ARFLAGS="$(ARFLAGS)" CC="$(CC)" AR="$(AR)" LD="$(LD)" $(SUBDIR_MAKEFLAGS) libfdt/libfdt.a,)
diff --git a/qemu-nvmm/patches/patch-audio_audio.c b/qemu-nvmm/patches/patch-audio_audio.c
new file mode 100644
index 0000000000..2d6d38ae53
--- /dev/null
+++ b/qemu-nvmm/patches/patch-audio_audio.c
@@ -0,0 +1,16 @@
+$NetBSD: patch-audio_audio.c,v 1.1 2017/12/14 08:01:10 adam Exp $
+
+Avoid conflicts with SSP read() macro in NetBSD's <ssp/unistd.h>
+(PR lib/43832: ssp causes common names to be defines)
+
+--- audio/audio.c.orig	2016-09-02 15:34:17.000000000 +0000
++++ audio/audio.c
+@@ -1156,7 +1156,7 @@ int AUD_read (SWVoiceIn *sw, void *buf, 
+         return 0;
+     }
+ 
+-    return sw->hw->pcm_ops->read(sw, buf, size);
++    return (sw->hw->pcm_ops->read)(sw, buf, size);
+ }
+ 
+ int AUD_get_buffer_size_out (SWVoiceOut *sw)
diff --git a/qemu-nvmm/patches/patch-block.c b/qemu-nvmm/patches/patch-block.c
new file mode 100644
index 0000000000..c32359b910
--- /dev/null
+++ b/qemu-nvmm/patches/patch-block.c
@@ -0,0 +1,42 @@
+$NetBSD: patch-block.c,v 1.2 2018/04/25 07:56:05 adam Exp $
+
+Remove block driver whitelisting logic; reasons being:
+- PkgSrc does not configure Qemu to use whitelisting
+- sometimes CONFIG...WHITELIST macros contain ["", NULL],
+  and bdrv_is_whitelisted() fails.
+
+--- block.c.orig	2018-03-27 22:29:23.000000000 +0000
++++ block.c
+@@ -373,31 +373,7 @@ BlockDriver *bdrv_find_format(const char
+ 
+ int bdrv_is_whitelisted(BlockDriver *drv, bool read_only)
+ {
+-    static const char *whitelist_rw[] = {
+-        CONFIG_BDRV_RW_WHITELIST
+-    };
+-    static const char *whitelist_ro[] = {
+-        CONFIG_BDRV_RO_WHITELIST
+-    };
+-    const char **p;
+-
+-    if (!whitelist_rw[0] && !whitelist_ro[0]) {
+-        return 1;               /* no whitelist, anything goes */
+-    }
+-
+-    for (p = whitelist_rw; *p; p++) {
+-        if (!strcmp(drv->format_name, *p)) {
+-            return 1;
+-        }
+-    }
+-    if (read_only) {
+-        for (p = whitelist_ro; *p; p++) {
+-            if (!strcmp(drv->format_name, *p)) {
+-                return 1;
+-            }
+-        }
+-    }
+-    return 0;
++    return 1;
+ }
+ 
+ bool bdrv_uses_whitelist(void)
diff --git a/qemu-nvmm/patches/patch-contrib_ivshmem-client_ivshmem-client.c b/qemu-nvmm/patches/patch-contrib_ivshmem-client_ivshmem-client.c
new file mode 100644
index 0000000000..8ed854c325
--- /dev/null
+++ b/qemu-nvmm/patches/patch-contrib_ivshmem-client_ivshmem-client.c
@@ -0,0 +1,37 @@
+$NetBSD: patch-contrib_ivshmem-client_ivshmem-client.c,v 1.1 2017/08/25 12:39:56 jperkin Exp $
+
+Avoid sun definition.
+
+--- contrib/ivshmem-client/ivshmem-client.c.orig	2017-04-20 14:57:00.000000000 +0000
++++ contrib/ivshmem-client/ivshmem-client.c
+@@ -179,7 +179,7 @@ ivshmem_client_init(IvshmemClient *clien
+ int
+ ivshmem_client_connect(IvshmemClient *client)
+ {
+-    struct sockaddr_un sun;
++    struct sockaddr_un sockun;
+     int fd, ret;
+     int64_t tmp;
+ 
+@@ -193,16 +193,16 @@ ivshmem_client_connect(IvshmemClient *cl
+         return -1;
+     }
+ 
+-    sun.sun_family = AF_UNIX;
+-    ret = snprintf(sun.sun_path, sizeof(sun.sun_path), "%s",
++    sockun.sun_family = AF_UNIX;
++    ret = snprintf(sockun.sun_path, sizeof(sockun.sun_path), "%s",
+                    client->unix_sock_path);
+-    if (ret < 0 || ret >= sizeof(sun.sun_path)) {
++    if (ret < 0 || ret >= sizeof(sockun.sun_path)) {
+         IVSHMEM_CLIENT_DEBUG(client, "could not copy unix socket path\n");
+         goto err_close;
+     }
+ 
+-    if (connect(client->sock_fd, (struct sockaddr *)&sun, sizeof(sun)) < 0) {
+-        IVSHMEM_CLIENT_DEBUG(client, "cannot connect to %s: %s\n", sun.sun_path,
++    if (connect(client->sock_fd, (struct sockaddr *)&sockun, sizeof(sockun)) < 0) {
++        IVSHMEM_CLIENT_DEBUG(client, "cannot connect to %s: %s\n", sockun.sun_path,
+                              strerror(errno));
+         goto err_close;
+     }
diff --git a/qemu-nvmm/patches/patch-contrib_ivshmem-server_ivshmem-server.c b/qemu-nvmm/patches/patch-contrib_ivshmem-server_ivshmem-server.c
new file mode 100644
index 0000000000..d773418cfe
--- /dev/null
+++ b/qemu-nvmm/patches/patch-contrib_ivshmem-server_ivshmem-server.c
@@ -0,0 +1,36 @@
+$NetBSD: patch-contrib_ivshmem-server_ivshmem-server.c,v 1.1 2017/08/25 12:39:56 jperkin Exp $
+
+Avoid sun definition.
+
+--- contrib/ivshmem-server/ivshmem-server.c.orig	2017-04-20 14:57:00.000000000 +0000
++++ contrib/ivshmem-server/ivshmem-server.c
+@@ -289,7 +289,7 @@ ivshmem_server_init(IvshmemServer *serve
+ int
+ ivshmem_server_start(IvshmemServer *server)
+ {
+-    struct sockaddr_un sun;
++    struct sockaddr_un sockun;
+     int shm_fd, sock_fd, ret;
+ 
+     /* open shm file */
+@@ -328,15 +328,15 @@ ivshmem_server_start(IvshmemServer *serv
+         goto err_close_shm;
+     }
+ 
+-    sun.sun_family = AF_UNIX;
+-    ret = snprintf(sun.sun_path, sizeof(sun.sun_path), "%s",
++    sockun.sun_family = AF_UNIX;
++    ret = snprintf(sockun.sun_path, sizeof(sockun.sun_path), "%s",
+                    server->unix_sock_path);
+-    if (ret < 0 || ret >= sizeof(sun.sun_path)) {
++    if (ret < 0 || ret >= sizeof(sockun.sun_path)) {
+         IVSHMEM_SERVER_DEBUG(server, "could not copy unix socket path\n");
+         goto err_close_sock;
+     }
+-    if (bind(sock_fd, (struct sockaddr *)&sun, sizeof(sun)) < 0) {
+-        IVSHMEM_SERVER_DEBUG(server, "cannot connect to %s: %s\n", sun.sun_path,
++    if (bind(sock_fd, (struct sockaddr *)&sockun, sizeof(sockun)) < 0) {
++        IVSHMEM_SERVER_DEBUG(server, "cannot connect to %s: %s\n", sockun.sun_path,
+                              strerror(errno));
+         goto err_close_sock;
+     }
diff --git a/qemu-nvmm/patches/patch-hw_display_omap__dss.c b/qemu-nvmm/patches/patch-hw_display_omap__dss.c
new file mode 100644
index 0000000000..fca1167bf3
--- /dev/null
+++ b/qemu-nvmm/patches/patch-hw_display_omap__dss.c
@@ -0,0 +1,30 @@
+$NetBSD: patch-hw_display_omap__dss.c,v 1.2 2014/01/15 18:26:20 wiz Exp $
+
+Avoid conflicts with SSP read() macro in NetBSD's <ssp/unistd.h>
+(PR lib/43832: ssp causes common names to be defines)
+
+--- hw/display/omap_dss.c.orig	2013-11-27 22:15:55.000000000 +0000
++++ hw/display/omap_dss.c
+@@ -791,18 +791,18 @@ static void omap_rfbi_write(void *opaque
+         break;
+     case 0x58:	/* RFBI_READ */
+         if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
+-            s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 1);
++            s->rfbi.rxbuf = (*s->rfbi.chip[0]->read)(s->rfbi.chip[0]->opaque, 1);
+         else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
+-            s->rfbi.rxbuf = s->rfbi.chip[1]->read(s->rfbi.chip[1]->opaque, 1);
++            s->rfbi.rxbuf = (*s->rfbi.chip[1]->read)(s->rfbi.chip[1]->opaque, 1);
+         if (!-- s->rfbi.pixels)
+             omap_rfbi_transfer_stop(s);
+         break;
+ 
+     case 0x5c:	/* RFBI_STATUS */
+         if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
+-            s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 0);
++            s->rfbi.rxbuf = (*s->rfbi.chip[0]->read)(s->rfbi.chip[0]->opaque, 0);
+         else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
+-            s->rfbi.rxbuf = s->rfbi.chip[1]->read(s->rfbi.chip[1]->opaque, 0);
++            s->rfbi.rxbuf = (*s->rfbi.chip[1]->read)(s->rfbi.chip[1]->opaque, 0);
+         if (!-- s->rfbi.pixels)
+             omap_rfbi_transfer_stop(s);
+         break;
diff --git a/qemu-nvmm/patches/patch-hw_net_etraxfs__eth.c b/qemu-nvmm/patches/patch-hw_net_etraxfs__eth.c
new file mode 100644
index 0000000000..834cf8dfb1
--- /dev/null
+++ b/qemu-nvmm/patches/patch-hw_net_etraxfs__eth.c
@@ -0,0 +1,25 @@
+$NetBSD: patch-hw_net_etraxfs__eth.c,v 1.3 2014/01/15 18:26:20 wiz Exp $
+
+Avoid conflicts with SSP read() macro in NetBSD's <ssp/unistd.h>
+(PR lib/43832: ssp causes common names to be defines)
+
+--- hw/net/etraxfs_eth.c.orig	2013-11-27 22:15:55.000000000 +0000
++++ hw/net/etraxfs_eth.c
+@@ -185,7 +185,7 @@ static void mdio_read_req(struct qemu_md
+ 
+     phy = bus->devs[bus->addr];
+     if (phy && phy->read) {
+-        bus->data = phy->read(phy, bus->req);
++        bus->data = (*phy->read)(phy, bus->req);
+     } else {
+         bus->data = 0xffff;
+     }
+@@ -364,7 +364,7 @@ static void eth_validate_duplex(ETRAXFSE
+     int new_mm = 0;
+ 
+     phy = eth->mdio_bus.devs[eth->phyaddr];
+-    phy_duplex = !!(phy->read(phy, 18) & (1 << 11));
++    phy_duplex = !!((*phy->read)(phy, 18) & (1 << 11));
+     mac_duplex = !!(eth->regs[RW_REC_CTRL] & 128);
+ 
+     if (mac_duplex != phy_duplex) {
diff --git a/qemu-nvmm/patches/patch-hw_net_xilinx__axienet.c b/qemu-nvmm/patches/patch-hw_net_xilinx__axienet.c
new file mode 100644
index 0000000000..af632b972d
--- /dev/null
+++ b/qemu-nvmm/patches/patch-hw_net_xilinx__axienet.c
@@ -0,0 +1,16 @@
+$NetBSD: patch-hw_net_xilinx__axienet.c,v 1.2 2014/01/15 18:26:20 wiz Exp $
+
+Avoid conflicts with SSP read() macro in NetBSD's <ssp/unistd.h>
+(PR lib/43832: ssp causes common names to be defines)
+
+--- hw/net/xilinx_axienet.c.orig	2013-11-27 22:15:55.000000000 +0000
++++ hw/net/xilinx_axienet.c
+@@ -207,7 +207,7 @@ static uint16_t mdio_read_req(struct MDI
+ 
+     phy = bus->devs[addr];
+     if (phy && phy->read) {
+-        data = phy->read(phy, reg);
++        data = (*phy->read)(phy, reg);
+     } else {
+         data = 0xffff;
+     }
diff --git a/qemu-nvmm/patches/patch-hw_usb_dev-mtp.c b/qemu-nvmm/patches/patch-hw_usb_dev-mtp.c
new file mode 100644
index 0000000000..6358e81a2b
--- /dev/null
+++ b/qemu-nvmm/patches/patch-hw_usb_dev-mtp.c
@@ -0,0 +1,17 @@
+$NetBSD: patch-hw_usb_dev-mtp.c,v 1.2 2018/08/16 10:15:09 adam Exp $
+
+Support NAME_MAX.
+
+--- hw/usb/dev-mtp.c.orig	2018-08-14 19:10:34.000000000 +0000
++++ hw/usb/dev-mtp.c
+@@ -26,6 +26,10 @@
+ #include "hw/usb.h"
+ #include "desc.h"
+ 
++#ifndef NAME_MAX
++#define NAME_MAX 255
++#endif
++
+ /* ----------------------------------------------------------------------- */
+ 
+ enum mtp_container_type {
diff --git a/qemu-nvmm/patches/patch-nvmm-support b/qemu-nvmm/patches/patch-nvmm-support
new file mode 100644
index 0000000000..e8591a533a
--- /dev/null
+++ b/qemu-nvmm/patches/patch-nvmm-support
@@ -0,0 +1,1479 @@
+$NetBSD: patch-nvmm_support,v 1.1 2018/10/29 00:00:00 maxv Exp $
+
+Add NVMM support.
+
+--- accel/stubs/Makefile.objs	2018-08-14 21:10:34.000000000 +0200
++++ accel/stubs/Makefile.objs	2018-10-30 10:53:45.520361253 +0100
+@@ -1,5 +1,6 @@
+ obj-$(call lnot,$(CONFIG_HAX))  += hax-stub.o
+ obj-$(call lnot,$(CONFIG_HVF))  += hvf-stub.o
+ obj-$(call lnot,$(CONFIG_WHPX)) += whpx-stub.o
++obj-$(call lnot,$(CONFIG_NVMM)) += nvmm-stub.o
+ obj-$(call lnot,$(CONFIG_KVM))  += kvm-stub.o
+ obj-$(call lnot,$(CONFIG_TCG))  += tcg-stub.o
+--- accel/stubs/nvmm-stub.c	1970-01-01 01:00:00.000000000 +0100
++++ accel/stubs/nvmm-stub.c	2018-10-28 15:27:35.991719000 +0100
+@@ -0,0 +1,71 @@
++/*
++ * Copyright (c) 2018 The NetBSD Foundation, Inc.
++ * All rights reserved.
++ *
++ * This code is derived from software contributed to The NetBSD Foundation
++ * by Maxime Villard.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
++ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/*
++ * QEMU NetBSD Virtual Machine Monitor accelerator (NVMM) stub
++ */
++
++#include "qemu/osdep.h"
++#include "qemu-common.h"
++#include "cpu.h"
++#include "sysemu/nvmm.h"
++
++int nvmm_init_vcpu(CPUState *cpu)
++{
++	return -1;
++}
++
++int nvmm_vcpu_exec(CPUState *cpu)
++{
++	return -1;
++}
++
++void nvmm_destroy_vcpu(CPUState *cpu)
++{
++}
++
++void nvmm_vcpu_kick(CPUState *cpu)
++{
++}
++
++void nvmm_cpu_synchronize_state(CPUState *cpu)
++{
++}
++
++void nvmm_cpu_synchronize_post_reset(CPUState *cpu)
++{
++}
++
++void nvmm_cpu_synchronize_post_init(CPUState *cpu)
++{
++}
++
++void nvmm_cpu_synchronize_pre_loadvm(CPUState *cpu)
++{
++}
+--- configure	2018-08-14 21:10:34.000000000 +0200
++++ configure	2018-11-01 18:01:36.390800199 +0100
+@@ -238,6 +238,17 @@
+     return 1
+ }
+ 
++supported_nvmm_target() {
++    test "$nvmm" = "yes" || return 1
++    glob "$1" "*-softmmu" || return 1
++    case "${1%-softmmu}" in
++        x86_64)
++            return 0
++        ;;
++    esac
++    return 1
++}
++
+ supported_target() {
+     case "$1" in
+         *-softmmu)
+@@ -265,6 +276,7 @@
+     supported_hax_target "$1" && return 0
+     supported_hvf_target "$1" && return 0
+     supported_whpx_target "$1" && return 0
++    supported_nvmm_target "$1" && return 0
+     print_error "TCG disabled, but hardware accelerator not available for '$target'"
+     return 1
+ }
+@@ -374,6 +386,7 @@
+ hax="no"
+ hvf="no"
+ whpx="no"
++nvmm="no"
+ rdma=""
+ gprof="no"
+ debug_tcg="no"
+@@ -1133,6 +1146,10 @@
+   ;;
+   --enable-whpx) whpx="yes"
+   ;;
++  --disable-nvmm) nvmm="no"
++  ;;
++  --enable-nvmm) nvmm="yes"
++  ;;
+   --disable-tcg-interpreter) tcg_interpreter="no"
+   ;;
+   --enable-tcg-interpreter) tcg_interpreter="yes"
+@@ -1669,6 +1686,7 @@
+   hax             HAX acceleration support
+   hvf             Hypervisor.framework acceleration support
+   whpx            Windows Hypervisor Platform acceleration support
++  nvmm            NetBSD Virtual Machine Monitor acceleration support
+   rdma            Enable RDMA-based migration and PVRDMA support
+   vde             support for vde network
+   netmap          support for netmap network
+@@ -2612,6 +2630,20 @@
+ fi
+ 
+ ##########################################
++# NetBSD Virtual Machine Monitor accelerator (NVMM) check
++if test "$nvmm" != "no" ; then
++    if check_include "libnvmm.h" && check_include "dev/nvmm/nvmm_x86.h"; then
++        nvmm="yes"
++        LIBS="-lnvmm $LIBS"
++    else
++        if test "$nvmm" = "yes"; then
++            feature_not_found "NVMM" "NVMM is not available"
++        fi
++        nvmm="no"
++    fi
++fi
++
++##########################################
+ # Sparse probe
+ if test "$sparse" != "no" ; then
+   if has cgcc; then
+@@ -5945,6 +5977,7 @@
+ echo "HAX support       $hax"
+ echo "HVF support       $hvf"
+ echo "WHPX support      $whpx"
++echo "NVMM support      $nvmm"
+ echo "TCG support       $tcg"
+ if test "$tcg" = "yes" ; then
+     echo "TCG debug enabled $debug_tcg"
+@@ -7162,6 +7195,9 @@
+ if supported_whpx_target $target; then
+     echo "CONFIG_WHPX=y" >> $config_target_mak
+ fi
++if supported_nvmm_target $target; then
++    echo "CONFIG_NVMM=y" >> $config_target_mak
++fi
+ if test "$target_bigendian" = "yes" ; then
+   echo "TARGET_WORDS_BIGENDIAN=y" >> $config_target_mak
+ fi
+--- cpus.c	2018-08-14 21:10:34.000000000 +0200
++++ cpus.c	2018-10-30 11:00:23.590887374 +0100
+@@ -40,6 +40,7 @@
+ #include "sysemu/hax.h"
+ #include "sysemu/hvf.h"
+ #include "sysemu/whpx.h"
++#include "sysemu/nvmm.h"
+ #include "exec/exec-all.h"
+ 
+ #include "qemu/thread.h"
+@@ -1616,6 +1617,49 @@
+     return NULL;
+ }
+ 
++static void *qemu_nvmm_cpu_thread_fn(void *arg)
++{
++    CPUState *cpu = arg;
++    int r;
++
++    rcu_register_thread();
++
++    qemu_mutex_lock_iothread();
++    qemu_thread_get_self(cpu->thread);
++    cpu->thread_id = qemu_get_thread_id();
++    current_cpu = cpu;
++
++    r = nvmm_init_vcpu(cpu);
++    if (r < 0) {
++        fprintf(stderr, "nvmm_init_vcpu failed: %s\n", strerror(-r));
++        exit(1);
++    }
++
++    /* signal CPU creation */
++    cpu->created = true;
++    qemu_cond_signal(&qemu_cpu_cond);
++
++    do {
++        if (cpu_can_run(cpu)) {
++            r = nvmm_vcpu_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);
++    } while (!cpu->unplug || cpu_can_run(cpu));
++
++    nvmm_destroy_vcpu(cpu);
++    cpu->created = false;
++    qemu_cond_signal(&qemu_cpu_cond);
++    qemu_mutex_unlock_iothread();
++    rcu_unregister_thread();
++    return NULL;
++}
++
+ #ifdef _WIN32
+ static void CALLBACK dummy_apc_func(ULONG_PTR unused)
+ {
+@@ -1970,6 +2014,19 @@
+ #endif
+ }
+ 
++static void qemu_nvmm_start_vcpu(CPUState *cpu)
++{
++    char thread_name[VCPU_THREAD_NAME_SIZE];
++
++    cpu->thread = g_malloc0(sizeof(QemuThread));
++    cpu->halt_cond = g_malloc0(sizeof(QemuCond));
++    qemu_cond_init(cpu->halt_cond);
++    snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/NVMM",
++             cpu->cpu_index);
++    qemu_thread_create(cpu->thread, thread_name, qemu_nvmm_cpu_thread_fn,
++                       cpu, QEMU_THREAD_JOINABLE);
++}
++
+ static void qemu_dummy_start_vcpu(CPUState *cpu)
+ {
+     char thread_name[VCPU_THREAD_NAME_SIZE];
+@@ -2007,6 +2064,8 @@
+         qemu_tcg_init_vcpu(cpu);
+     } else if (whpx_enabled()) {
+         qemu_whpx_start_vcpu(cpu);
++    } else if (nvmm_enabled()) {
++        qemu_nvmm_start_vcpu(cpu);
+     } else {
+         qemu_dummy_start_vcpu(cpu);
+     }
+--- include/sysemu/hw_accel.h	2018-08-14 21:10:34.000000000 +0200
++++ include/sysemu/hw_accel.h	2018-10-30 11:01:56.162918154 +0100
+@@ -15,6 +15,7 @@
+ #include "sysemu/hax.h"
+ #include "sysemu/kvm.h"
+ #include "sysemu/whpx.h"
++#include "sysemu/nvmm.h"
+ 
+ static inline void cpu_synchronize_state(CPUState *cpu)
+ {
+@@ -27,6 +28,9 @@
+     if (whpx_enabled()) {
+         whpx_cpu_synchronize_state(cpu);
+     }
++    if (nvmm_enabled()) {
++        nvmm_cpu_synchronize_state(cpu);
++    }
+ }
+ 
+ static inline void cpu_synchronize_post_reset(CPUState *cpu)
+@@ -40,6 +44,9 @@
+     if (whpx_enabled()) {
+         whpx_cpu_synchronize_post_reset(cpu);
+     }
++    if (nvmm_enabled()) {
++        nvmm_cpu_synchronize_post_reset(cpu);
++    }
+ }
+ 
+ static inline void cpu_synchronize_post_init(CPUState *cpu)
+@@ -53,6 +60,9 @@
+     if (whpx_enabled()) {
+         whpx_cpu_synchronize_post_init(cpu);
+     }
++    if (nvmm_enabled()) {
++        nvmm_cpu_synchronize_post_init(cpu);
++    }
+ }
+ 
+ static inline void cpu_synchronize_pre_loadvm(CPUState *cpu)
+@@ -66,6 +76,9 @@
+     if (whpx_enabled()) {
+         whpx_cpu_synchronize_pre_loadvm(cpu);
+     }
++    if (nvmm_enabled()) {
++        nvmm_cpu_synchronize_pre_loadvm(cpu);
++    }
+ }
+ 
+ #endif /* QEMU_HW_ACCEL_H */
+--- include/sysemu/nvmm.h	1970-01-01 01:00:00.000000000 +0100
++++ include/sysemu/nvmm.h	2018-10-28 15:32:34.120605000 +0100
+@@ -0,0 +1,60 @@
++/*
++ * Copyright (c) 2018 The NetBSD Foundation, Inc.
++ * All rights reserved.
++ *
++ * This code is derived from software contributed to The NetBSD Foundation
++ * by Maxime Villard.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
++ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/*
++ * QEMU NetBSD Virtual Machine Monitor accelerator (NVMM) support
++ */
++
++#ifndef QEMU_NVMM_H
++#define QEMU_NVMM_H
++
++#include "config-host.h"
++#include "qemu-common.h"
++
++int nvmm_init_vcpu(CPUState *);
++int nvmm_vcpu_exec(CPUState *);
++void nvmm_destroy_vcpu(CPUState *);
++void nvmm_vcpu_kick(CPUState *);
++
++void nvmm_cpu_synchronize_state(CPUState *);
++void nvmm_cpu_synchronize_post_reset(CPUState *);
++void nvmm_cpu_synchronize_post_init(CPUState *);
++void nvmm_cpu_synchronize_pre_loadvm(CPUState *);
++
++#ifdef CONFIG_NVMM
++
++int nvmm_enabled(void);
++
++#else /* CONFIG_NVMM */
++
++#define nvmm_enabled() (0)
++
++#endif /* CONFIG_NVMM */
++
++#endif /* CONFIG_NVMM */
+--- qemu-options.hx	2018-08-14 21:10:34.000000000 +0200
++++ qemu-options.hx	2018-10-30 11:03:36.343787082 +0100
+@@ -67,7 +67,7 @@
+ @table @option
+ @item accel=@var{accels1}[:@var{accels2}[:...]]
+ This is used to enable an accelerator. Depending on the target architecture,
+-kvm, xen, hax, hvf, whpx or tcg can be available. By default, tcg is used. If there is
++kvm, xen, hax, hvf, whpx, nvmm or tcg can be available. By default, tcg is used. If there is
+ more than one accelerator specified, the next one is used if the previous one
+ fails to initialize.
+ @item kernel_irqchip=on|off
+@@ -129,13 +129,13 @@
+ 
+ DEF("accel", HAS_ARG, QEMU_OPTION_accel,
+     "-accel [accel=]accelerator[,thread=single|multi]\n"
+-    "                select accelerator (kvm, xen, hax, hvf, whpx or tcg; use 'help' for a list)\n"
++    "                select accelerator (kvm, xen, hax, hvf, whpx, nvmm or tcg; use 'help' for a list)\n"
+     "                thread=single|multi (enable multi-threaded TCG)\n", QEMU_ARCH_ALL)
+ STEXI
+ @item -accel @var{name}[,prop=@var{value}[,...]]
+ @findex -accel
+ This is used to enable an accelerator. Depending on the target architecture,
+-kvm, xen, hax, hvf, whpx or tcg can be available. By default, tcg is used. If there is
++kvm, xen, hax, hvf, whpx, nvmm or tcg can be available. By default, tcg is used. If there is
+ more than one accelerator specified, the next one is used if the previous one
+ fails to initialize.
+ @table @option
+--- target/i386/helper.c	2018-08-14 21:10:35.000000000 +0200
++++ target/i386/helper.c	2018-10-30 11:04:55.680328352 +0100
+@@ -986,7 +986,7 @@
+     X86CPU *cpu = x86_env_get_cpu(env);
+     CPUState *cs = CPU(cpu);
+ 
+-    if (kvm_enabled() || whpx_enabled()) {
++    if (kvm_enabled() || whpx_enabled() || nvmm_enabled()) {
+         env->tpr_access_type = access;
+ 
+         cpu_interrupt(cs, CPU_INTERRUPT_TPR);
+--- target/i386/Makefile.objs	2018-08-14 21:10:35.000000000 +0200
++++ target/i386/Makefile.objs	2018-10-30 11:04:35.159682003 +0100
+@@ -17,3 +17,4 @@
+ obj-$(CONFIG_HVF) += hvf/
+ endif
+ obj-$(CONFIG_WHPX) += whpx-all.o
++obj-$(CONFIG_NVMM) += nvmm-all.o
+--- target/i386/nvmm-all.c	1970-01-01 01:00:00.000000000 +0100
++++ target/i386/nvmm-all.c	2018-11-03 13:59:52.058059097 +0100
+@@ -0,0 +1,1036 @@
++/*
++ * Copyright (c) 2018 The NetBSD Foundation, Inc.
++ * All rights reserved.
++ *
++ * This code is derived from software contributed to The NetBSD Foundation
++ * by Maxime Villard.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
++ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/*
++ * QEMU NetBSD Virtual Machine Monitor accelerator (NVMM)
++ */
++
++#include "qemu/osdep.h"
++#include "cpu.h"
++#include "exec/address-spaces.h"
++#include "exec/ioport.h"
++#include "qemu-common.h"
++#include "strings.h"
++#include "sysemu/accel.h"
++#include "sysemu/nvmm.h"
++#include "sysemu/sysemu.h"
++#include "sysemu/cpus.h"
++#include "qemu/main-loop.h"
++#include "hw/boards.h"
++#include "qemu/error-report.h"
++#include "qemu/queue.h"
++#include "qapi/error.h"
++#include "migration/blocker.h"
++
++#include <libnvmm.h>
++#include <dev/nvmm/nvmm_x86.h>
++
++static bool nvmm_allowed = false;
++
++struct nvmm_vcpu {
++	nvmm_cpuid_t cpuid;
++	bool int_waiting;
++	bool nmi_waiting;
++	uint8_t tpr;
++};
++
++static struct {
++	struct nvmm_machine mach;
++} nvmm_global;
++
++static struct nvmm_vcpu *
++get_nvmm_vcpu(CPUState *cpu)
++{
++	return (struct nvmm_vcpu *)cpu->hax_vcpu;
++}
++
++static struct nvmm_machine *
++get_nvmm_mach(void)
++{
++	return &nvmm_global.mach;
++}
++
++/* -------------------------------------------------------------------------- */
++
++static void
++nvmm_set_segment(struct nvmm_x64_state_seg *nseg, const SegmentCache *qseg)
++{
++	uint32_t attrib = qseg->flags;
++
++	nseg->selector = qseg->selector;
++	nseg->limit = qseg->limit;
++	nseg->base = qseg->base;
++
++	nseg->attrib.type =
++	    __SHIFTOUT(attrib, DESC_S_MASK) |
++	    __SHIFTOUT(attrib, DESC_TYPE_MASK);
++	nseg->attrib.dpl = __SHIFTOUT(attrib, DESC_DPL_MASK);
++	nseg->attrib.p = __SHIFTOUT(attrib, DESC_P_MASK);
++	nseg->attrib.avl = __SHIFTOUT(attrib, DESC_AVL_MASK);
++	nseg->attrib.lng = __SHIFTOUT(attrib, DESC_L_MASK);
++	nseg->attrib.def32 = __SHIFTOUT(attrib, DESC_B_MASK);
++	nseg->attrib.gran = __SHIFTOUT(attrib, DESC_G_MASK);
++}
++
++static void
++nvmm_set_registers(CPUState *cpu)
++{
++	struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr);
++	struct nvmm_machine *mach = get_nvmm_mach();
++	struct nvmm_vcpu *vcpu = get_nvmm_vcpu(cpu);
++	struct nvmm_x64_state state;
++	uint64_t bitmap;
++	size_t i;
++	int ret;
++
++	assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
++
++	/* GPRs. */
++	state.gprs[NVMM_X64_GPR_RAX] = (uint64_t)env->regs[R_EAX];
++	state.gprs[NVMM_X64_GPR_RCX] = (uint64_t)env->regs[R_ECX];
++	state.gprs[NVMM_X64_GPR_RDX] = (uint64_t)env->regs[R_EDX];
++	state.gprs[NVMM_X64_GPR_RBX] = (uint64_t)env->regs[R_EBX];
++	state.gprs[NVMM_X64_GPR_RSP] = (uint64_t)env->regs[R_ESP];
++	state.gprs[NVMM_X64_GPR_RBP] = (uint64_t)env->regs[R_EBP];
++	state.gprs[NVMM_X64_GPR_RSI] = (uint64_t)env->regs[R_ESI];
++	state.gprs[NVMM_X64_GPR_RDI] = (uint64_t)env->regs[R_EDI];
++	state.gprs[NVMM_X64_GPR_R8]  = (uint64_t)env->regs[R_R8];
++	state.gprs[NVMM_X64_GPR_R9]  = (uint64_t)env->regs[R_R9];
++	state.gprs[NVMM_X64_GPR_R10] = (uint64_t)env->regs[R_R10];
++	state.gprs[NVMM_X64_GPR_R11] = (uint64_t)env->regs[R_R11];
++	state.gprs[NVMM_X64_GPR_R12] = (uint64_t)env->regs[R_R12];
++	state.gprs[NVMM_X64_GPR_R13] = (uint64_t)env->regs[R_R13];
++	state.gprs[NVMM_X64_GPR_R14] = (uint64_t)env->regs[R_R14];
++	state.gprs[NVMM_X64_GPR_R15] = (uint64_t)env->regs[R_R15];
++
++	/* RIP and RFLAGS. */
++	state.gprs[NVMM_X64_GPR_RIP] = (uint64_t)env->eip;
++	state.gprs[NVMM_X64_GPR_RFLAGS] = (uint64_t)env->eflags;
++
++	/* Segments. */
++	nvmm_set_segment(&state.segs[NVMM_X64_SEG_CS], &env->segs[R_CS]);
++	nvmm_set_segment(&state.segs[NVMM_X64_SEG_DS], &env->segs[R_DS]);
++	nvmm_set_segment(&state.segs[NVMM_X64_SEG_ES], &env->segs[R_ES]);
++	nvmm_set_segment(&state.segs[NVMM_X64_SEG_FS], &env->segs[R_FS]);
++	nvmm_set_segment(&state.segs[NVMM_X64_SEG_GS], &env->segs[R_GS]);
++	nvmm_set_segment(&state.segs[NVMM_X64_SEG_SS], &env->segs[R_SS]);
++
++	/* Special segments. */
++	nvmm_set_segment(&state.segs[NVMM_X64_SEG_GDT], &env->gdt);
++	nvmm_set_segment(&state.segs[NVMM_X64_SEG_LDT], &env->ldt);
++	nvmm_set_segment(&state.segs[NVMM_X64_SEG_TR], &env->tr);
++	nvmm_set_segment(&state.segs[NVMM_X64_SEG_IDT], &env->idt);
++
++	/* Control registers. */
++	state.crs[NVMM_X64_CR_CR0] = (uint64_t)env->cr[0];
++	state.crs[NVMM_X64_CR_CR2] = (uint64_t)env->cr[2];
++	state.crs[NVMM_X64_CR_CR3] = (uint64_t)env->cr[3];
++	state.crs[NVMM_X64_CR_CR4] = (uint64_t)env->cr[4];
++	state.crs[NVMM_X64_CR_CR8] = (uint64_t)vcpu->tpr;
++
++	/* Debug registers. */
++	state.drs[NVMM_X64_DR_DR1] = (uint64_t)env->dr[1];
++	state.drs[NVMM_X64_DR_DR2] = (uint64_t)env->dr[2];
++	state.drs[NVMM_X64_DR_DR3] = (uint64_t)env->dr[3];
++	state.drs[NVMM_X64_DR_DR6] = (uint64_t)env->dr[6];
++	state.drs[NVMM_X64_DR_DR7] = (uint64_t)env->dr[7];
++
++	/* FPU. */
++	state.fpu.fx_cw = env->fpuc;
++	state.fpu.fx_sw = (env->fpus & ~0x3800) | ((env->fpstt & 0x7) << 11);
++	state.fpu.fx_tw = 0;
++	for (i = 0; i < 8; i++) {
++		state.fpu.fx_tw |= (!env->fptags[i]) << i;
++	}
++	state.fpu.fx_opcode = env->fpop;
++	state.fpu.fx_ip.fa_64 = env->fpip;
++	state.fpu.fx_dp.fa_64 = env->fpdp;
++	state.fpu.fx_mxcsr = env->mxcsr;
++	state.fpu.fx_mxcsr_mask = 0x0000FFFF;
++	assert(sizeof(state.fpu.fx_87_ac) == sizeof(env->fpregs));
++	memcpy(state.fpu.fx_87_ac, env->fpregs, sizeof(env->fpregs));
++	for (i = 0; i < sizeof(env->xmm_regs) / sizeof(ZMMReg); i++) {
++		memcpy(&state.fpu.fx_xmm[i].xmm_bytes[0],
++		    &env->xmm_regs[i].ZMM_Q(0), 8);
++		memcpy(&state.fpu.fx_xmm[i].xmm_bytes[8],
++		    &env->xmm_regs[i].ZMM_Q(1), 8);
++	}
++
++	/* MSRs. */
++	state.msrs[NVMM_X64_MSR_EFER] = env->efer;
++	state.msrs[NVMM_X64_MSR_STAR] = env->star;
++#ifdef TARGET_X86_64
++	state.msrs[NVMM_X64_MSR_LSTAR] = env->lstar;
++	state.msrs[NVMM_X64_MSR_CSTAR] = env->cstar;
++	state.msrs[NVMM_X64_MSR_SFMASK] = env->fmask;
++	state.msrs[NVMM_X64_MSR_KERNELGSBASE] = env->kernelgsbase;
++#endif
++	state.msrs[NVMM_X64_MSR_SYSENTER_CS]  = env->sysenter_cs;
++	state.msrs[NVMM_X64_MSR_SYSENTER_ESP] = env->sysenter_eip;
++	state.msrs[NVMM_X64_MSR_SYSENTER_EIP] = env->sysenter_esp;
++	state.msrs[NVMM_X64_MSR_PAT] = env->pat;
++
++	bitmap =
++	    NVMM_X64_STATE_SEGS |
++	    NVMM_X64_STATE_GPRS |
++	    NVMM_X64_STATE_CRS  |
++	    NVMM_X64_STATE_DRS  |
++	    NVMM_X64_STATE_MSRS |
++	    NVMM_X64_STATE_FPU;
++
++	ret = nvmm_vcpu_setstate(mach, vcpu->cpuid, &state, bitmap);
++	if (ret == -1) {
++		error_report("NVMM: Failed to set virtual processor context,"
++		    " error=%d", errno);
++	}
++}
++
++static void
++nvmm_get_segment(SegmentCache *qseg, const struct nvmm_x64_state_seg *nseg)
++{
++	qseg->selector = nseg->selector;
++	qseg->limit = nseg->limit;
++	qseg->base = nseg->base;
++
++	qseg->flags =
++	    __SHIFTIN(nseg->attrib.type, DESC_S_MASK) |
++	    __SHIFTIN(nseg->attrib.type, DESC_TYPE_MASK) |
++	    __SHIFTIN(nseg->attrib.dpl, DESC_DPL_MASK) |
++	    __SHIFTIN(nseg->attrib.p, DESC_P_MASK) |
++	    __SHIFTIN(nseg->attrib.avl, DESC_AVL_MASK) |
++	    __SHIFTIN(nseg->attrib.lng, DESC_L_MASK) |
++	    __SHIFTIN(nseg->attrib.def32, DESC_B_MASK) |
++	    __SHIFTIN(nseg->attrib.gran, DESC_G_MASK);
++}
++
++static void
++nvmm_get_registers(CPUState *cpu)
++{
++	struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr);
++	struct nvmm_machine *mach = get_nvmm_mach();
++	struct nvmm_vcpu *vcpu = get_nvmm_vcpu(cpu);
++	X86CPU *x86_cpu = X86_CPU(cpu);
++	struct nvmm_x64_state state;
++	uint64_t bitmap, tpr;
++	size_t i;
++	int ret;
++
++	assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
++
++	bitmap =
++	    NVMM_X64_STATE_SEGS |
++	    NVMM_X64_STATE_GPRS |
++	    NVMM_X64_STATE_CRS  |
++	    NVMM_X64_STATE_DRS  |
++	    NVMM_X64_STATE_MSRS |
++	    NVMM_X64_STATE_FPU;
++
++	ret = nvmm_vcpu_getstate(mach, vcpu->cpuid, &state, bitmap);
++	if (ret == -1) {
++		error_report("NVMM: Failed to get virtual processor context,"
++		    " error=%d", errno);
++	}
++
++	/* GPRs. */
++	env->regs[R_EAX] = state.gprs[NVMM_X64_GPR_RAX];
++	env->regs[R_ECX] = state.gprs[NVMM_X64_GPR_RCX];
++	env->regs[R_EDX] = state.gprs[NVMM_X64_GPR_RDX];
++	env->regs[R_EBX] = state.gprs[NVMM_X64_GPR_RBX];
++	env->regs[R_ESP] = state.gprs[NVMM_X64_GPR_RSP];
++	env->regs[R_EBP] = state.gprs[NVMM_X64_GPR_RBP];
++	env->regs[R_ESI] = state.gprs[NVMM_X64_GPR_RSI];
++	env->regs[R_EDI] = state.gprs[NVMM_X64_GPR_RDI];
++	env->regs[R_R8]  = state.gprs[NVMM_X64_GPR_R8];
++	env->regs[R_R9]  = state.gprs[NVMM_X64_GPR_R9];
++	env->regs[R_R10] = state.gprs[NVMM_X64_GPR_R10];
++	env->regs[R_R11] = state.gprs[NVMM_X64_GPR_R11];
++	env->regs[R_R12] = state.gprs[NVMM_X64_GPR_R12];
++	env->regs[R_R13] = state.gprs[NVMM_X64_GPR_R13];
++	env->regs[R_R14] = state.gprs[NVMM_X64_GPR_R14];
++	env->regs[R_R15] = state.gprs[NVMM_X64_GPR_R15];
++
++	/* RIP and RFLAGS. */
++	env->eip = state.gprs[NVMM_X64_GPR_RIP];
++	env->eflags = state.gprs[NVMM_X64_GPR_RFLAGS];
++
++	/* Segments. */
++	nvmm_get_segment(&env->segs[R_CS], &state.segs[NVMM_X64_SEG_CS]);
++	nvmm_get_segment(&env->segs[R_DS], &state.segs[NVMM_X64_SEG_DS]);
++	nvmm_get_segment(&env->segs[R_ES], &state.segs[NVMM_X64_SEG_ES]);
++	nvmm_get_segment(&env->segs[R_FS], &state.segs[NVMM_X64_SEG_FS]);
++	nvmm_get_segment(&env->segs[R_GS], &state.segs[NVMM_X64_SEG_GS]);
++	nvmm_get_segment(&env->segs[R_SS], &state.segs[NVMM_X64_SEG_SS]);
++
++	/* Special segments. */
++	nvmm_get_segment(&env->gdt, &state.segs[NVMM_X64_SEG_GDT]);
++	nvmm_get_segment(&env->ldt, &state.segs[NVMM_X64_SEG_LDT]);
++	nvmm_get_segment(&env->tr, &state.segs[NVMM_X64_SEG_TR]);
++	nvmm_get_segment(&env->idt, &state.segs[NVMM_X64_SEG_IDT]);
++
++	/* Control registers. */
++	env->cr[0] = state.crs[NVMM_X64_CR_CR0];
++	env->cr[2] = state.crs[NVMM_X64_CR_CR2];
++	env->cr[3] = state.crs[NVMM_X64_CR_CR3];
++	env->cr[4] = state.crs[NVMM_X64_CR_CR4];
++	tpr = state.crs[NVMM_X64_CR_CR8];
++	if (tpr != vcpu->tpr) {
++		vcpu->tpr = tpr;
++		cpu_set_apic_tpr(x86_cpu->apic_state, tpr);
++	}
++
++	/* Debug registers. */
++	env->dr[1] = state.drs[NVMM_X64_DR_DR1];
++	env->dr[2] = state.drs[NVMM_X64_DR_DR2];
++	env->dr[3] = state.drs[NVMM_X64_DR_DR3];
++	env->dr[6] = state.drs[NVMM_X64_DR_DR6];
++	env->dr[7] = state.drs[NVMM_X64_DR_DR7];
++
++	/* FPU. */
++	env->fpuc = state.fpu.fx_cw;
++	env->fpstt = (state.fpu.fx_sw >> 11) & 0x7;
++	env->fpus = state.fpu.fx_sw & ~0x3800;
++	for (i = 0; i < 8; i++) {
++		env->fptags[i] = !((state.fpu.fx_tw >> i) & 1);
++	}
++	env->fpop = state.fpu.fx_opcode;
++	env->fpip = state.fpu.fx_ip.fa_64;
++	env->fpdp = state.fpu.fx_dp.fa_64;
++	env->mxcsr = state.fpu.fx_mxcsr;
++	assert(sizeof(state.fpu.fx_87_ac) == sizeof(env->fpregs));
++	memcpy(env->fpregs, state.fpu.fx_87_ac, sizeof(env->fpregs));
++	for (i = 0; i < sizeof(env->xmm_regs) / sizeof(ZMMReg); i++) {
++		memcpy(&env->xmm_regs[i].ZMM_Q(0),
++		    &state.fpu.fx_xmm[i].xmm_bytes[0], 8);
++		memcpy(&env->xmm_regs[i].ZMM_Q(1),
++		    &state.fpu.fx_xmm[i].xmm_bytes[8], 8);
++	}
++
++	/* MSRs. */
++	env->efer = state.msrs[NVMM_X64_MSR_EFER];
++	env->star = state.msrs[NVMM_X64_MSR_STAR];
++#ifdef TARGET_X86_64
++	env->lstar = state.msrs[NVMM_X64_MSR_LSTAR];
++	env->cstar = state.msrs[NVMM_X64_MSR_CSTAR];
++	env->fmask = state.msrs[NVMM_X64_MSR_SFMASK];
++	env->kernelgsbase = state.msrs[NVMM_X64_MSR_KERNELGSBASE];
++#endif
++	env->sysenter_cs  = state.msrs[NVMM_X64_MSR_SYSENTER_CS];
++	env->sysenter_eip = state.msrs[NVMM_X64_MSR_SYSENTER_ESP];
++	env->sysenter_esp = state.msrs[NVMM_X64_MSR_SYSENTER_EIP];
++	env->pat = state.msrs[NVMM_X64_MSR_PAT];
++}
++
++/*
++ * Called before the VCPU is run. We inject events generated by the I/O
++ * thread, and synchronize the guest TPR.
++ */
++static void
++nvmm_vcpu_pre_run(CPUState *cpu)
++{
++	struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr);
++	struct nvmm_machine *mach = get_nvmm_mach();
++	struct nvmm_vcpu *vcpu = get_nvmm_vcpu(cpu);
++	X86CPU *x86_cpu = X86_CPU(cpu);
++	struct nvmm_x64_state state;
++	struct nvmm_event event;
++	bool has_event = false;
++	bool sync_tpr = false;
++	uint8_t tpr;
++	int ret;
++
++	memset(&event, 0, sizeof(event));
++
++	qemu_mutex_lock_iothread();
++
++	/*
++	 * Force the VCPU out of its inner loop to process any INIT requests
++	 * or commit pending TPR access.
++	 */
++	if (cpu->interrupt_request & (CPU_INTERRUPT_INIT|CPU_INTERRUPT_TPR)) {
++		cpu->exit_request = 1;
++	}
++
++	/* Inject NMI, if any. */
++	if (!has_event && !vcpu->nmi_waiting &&
++	    (cpu->interrupt_request & CPU_INTERRUPT_NMI)) {
++		cpu->interrupt_request &= ~CPU_INTERRUPT_NMI;
++		event.type = NVMM_EVENT_INTERRUPT_HW;
++		event.vector = 2;
++		has_event = true;
++	}
++
++	/* Inject INT, if any. */
++	if (!has_event && !vcpu->int_waiting &&
++	    (cpu->interrupt_request & CPU_INTERRUPT_HARD)) {
++		cpu->interrupt_request &= ~CPU_INTERRUPT_HARD;
++		event.type = NVMM_EVENT_INTERRUPT_HW;
++		event.vector = cpu_get_pic_interrupt(env);
++		has_event = true;
++	}
++
++	/* Don't want SMIs. */
++	if (cpu->interrupt_request & CPU_INTERRUPT_SMI) {
++		cpu->interrupt_request &= ~CPU_INTERRUPT_SMI;
++	}
++
++	/* Sync the TPR. */
++	tpr = cpu_get_apic_tpr(x86_cpu->apic_state);
++	if (tpr != vcpu->tpr) {
++		vcpu->tpr = tpr;
++		sync_tpr = true;
++	}
++
++	qemu_mutex_unlock_iothread();
++
++	if (sync_tpr) {
++		ret = nvmm_vcpu_getstate(mach, vcpu->cpuid, &state,
++		    NVMM_X64_STATE_CRS);
++		if (ret == -1) {
++			error_report("NVMM: Failed to get CPU state,"
++			    " error=%d", errno);
++		}
++
++		state.crs[NVMM_X64_CR_CR8] = vcpu->tpr;
++
++		ret = nvmm_vcpu_setstate(mach, vcpu->cpuid, &state,
++		    NVMM_X64_STATE_CRS);
++		if (ret == -1) {
++			error_report("NVMM: Failed to set CPU state,"
++			    " error=%d", errno);
++		}
++	}
++
++	if (has_event) {
++		ret = nvmm_vcpu_inject(mach, vcpu->cpuid, &event);
++		if (ret == -1) {
++			if (errno == EAGAIN) {
++				if (event.vector == 2)
++					vcpu->nmi_waiting = true;
++				else
++					vcpu->int_waiting = true;
++			} else {
++				error_report("NVMM: Failed to inject event,"
++				    " error=%d", errno);
++			}
++		}
++	}
++}
++
++/*
++ * Called after the VCPU ran. We synchronize the host view of the TPR.
++ */
++static void
++nvmm_vcpu_post_run(CPUState *cpu, struct nvmm_exit *exit)
++{
++	struct nvmm_vcpu *vcpu = get_nvmm_vcpu(cpu);
++	X86CPU *x86_cpu = X86_CPU(cpu);
++	uint64_t tpr;
++
++	tpr = exit->exitstate[NVMM_X64_EXITSTATE_CR8];
++
++	if (vcpu->tpr != tpr) {
++		vcpu->tpr = tpr;
++		qemu_mutex_lock_iothread();
++		cpu_set_apic_tpr(x86_cpu->apic_state, vcpu->tpr);
++		qemu_mutex_unlock_iothread();
++	}
++}
++
++/* -------------------------------------------------------------------------- */
++
++static void
++nvmm_mem_callback(struct nvmm_mem *mem)
++{
++	cpu_physical_memory_rw(mem->gpa, mem->data, mem->size, mem->write);
++}
++static int
++nvmm_handle_mem(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu,
++    struct nvmm_exit *exit)
++{
++	return nvmm_assist_mem(mach, vcpu->cpuid, exit, nvmm_mem_callback);
++}
++
++static void
++nvmm_io_callback(struct nvmm_io *io)
++{
++	MemTxAttrs attrs = { 0 };
++	address_space_rw(&address_space_io, io->port, attrs, io->data,
++	    io->size, !io->in);
++}
++static int
++nvmm_handle_io(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu,
++    struct nvmm_exit *exit)
++{
++	return nvmm_assist_io(mach, vcpu->cpuid, exit, nvmm_io_callback);
++}
++
++#define MSR_APICBASE		0x01b
++
++static int
++nvmm_handle_msr(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu,
++    X86CPU *x86_cpu, struct nvmm_exit *exit)
++{
++	struct nvmm_x64_state state;
++	uint64_t val;
++	int ret;
++
++	ret = nvmm_vcpu_getstate(mach, vcpu->cpuid, &state,
++	    NVMM_X64_STATE_GPRS);
++	if (ret == -1) {
++		return -1;
++	}
++
++	switch (exit->u.msr.msr) {
++	case MSR_APICBASE:
++		if (exit->u.msr.type == NVMM_EXIT_MSR_RDMSR) {
++			val = cpu_get_apic_base(x86_cpu->apic_state);
++			state.gprs[NVMM_X64_GPR_RAX] = (val & 0xFFFFFFFF);
++			state.gprs[NVMM_X64_GPR_RDX] = (val >> 32);
++		} else {
++			val = exit->u.msr.val;
++			cpu_set_apic_base(x86_cpu->apic_state, val);
++		}
++		break;
++	default:
++		// TODO: more MSRs to add?
++		error_report("NVMM: Unexpected MSR %lx", exit->u.msr.msr);
++		return -1;
++	}
++
++	state.gprs[NVMM_X64_GPR_RIP] = exit->u.msr.npc;
++
++	ret = nvmm_vcpu_setstate(mach, vcpu->cpuid, &state,
++	    NVMM_X64_STATE_GPRS);
++	if (ret == -1) {
++		return -1;
++	}
++
++	return 0;
++}
++
++static int
++nvmm_handle_hlt(CPUState *cpu)
++{
++	struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr);
++	int ret = 0;
++
++	qemu_mutex_lock_iothread();
++	if (!((cpu->interrupt_request & CPU_INTERRUPT_HARD) &&
++	      (env->eflags & IF_MASK)) &&
++	    !(cpu->interrupt_request & CPU_INTERRUPT_NMI)) {
++		cpu->exception_index = EXCP_HLT;
++		cpu->halted = true;
++		ret = 1;
++	}
++	qemu_mutex_unlock_iothread();
++
++	return ret;
++}
++
++static int
++nvmm_inject_ud(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu)
++{
++	struct nvmm_event event;
++
++	event.type = NVMM_EVENT_EXCEPTION;
++	event.vector = 6;
++	event.u.error = 0;
++
++	return nvmm_vcpu_inject(mach, vcpu->cpuid, &event);
++}
++
++static int
++nvmm_vcpu_loop(CPUState *cpu)
++{
++	struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr);
++	struct nvmm_machine *mach = get_nvmm_mach();
++	struct nvmm_vcpu *vcpu = get_nvmm_vcpu(cpu);
++	X86CPU *x86_cpu = X86_CPU(cpu);
++	struct nvmm_exit exit;
++	int ret;
++
++	/*
++	 * Some asynchronous events must be handled outside of the inner
++	 * VCPU loop. They are handled here.
++	 */
++	if (cpu->interrupt_request & CPU_INTERRUPT_INIT) {
++		do_cpu_init(x86_cpu);
++		cpu->vcpu_dirty = true;
++		vcpu->int_waiting = false;
++		vcpu->nmi_waiting = false;
++	}
++	if (cpu->interrupt_request & CPU_INTERRUPT_POLL) {
++		cpu->interrupt_request &= ~CPU_INTERRUPT_POLL;
++		apic_poll_irq(x86_cpu->apic_state);
++	}
++	if (((cpu->interrupt_request & CPU_INTERRUPT_HARD) &&
++	     (env->eflags & IF_MASK)) ||
++	    (cpu->interrupt_request & CPU_INTERRUPT_NMI)) {
++		cpu->halted = false;
++	}
++	if (cpu->interrupt_request & CPU_INTERRUPT_SIPI) {
++		if (!cpu->vcpu_dirty) {
++			nvmm_get_registers(cpu);
++		}
++		do_cpu_sipi(x86_cpu);
++	}
++	if (cpu->interrupt_request & CPU_INTERRUPT_TPR) {
++		cpu->interrupt_request &= ~CPU_INTERRUPT_TPR;
++		if (!cpu->vcpu_dirty) {
++			nvmm_get_registers(cpu);
++		}
++		apic_handle_tpr_access_report(x86_cpu->apic_state, env->eip,
++		    env->tpr_access_type);
++	}
++
++	if (cpu->halted) {
++		cpu->exception_index = EXCP_HLT;
++		atomic_set(&cpu->exit_request, false);
++		return 0;
++	}
++
++	qemu_mutex_unlock_iothread();
++	cpu_exec_start(cpu);
++
++	/*
++	 * Inner VCPU loop.
++	 */
++	do {
++		if (cpu->vcpu_dirty) {
++			nvmm_set_registers(cpu);
++			cpu->vcpu_dirty = false;
++		}
++
++		nvmm_vcpu_pre_run(cpu);
++
++		if (atomic_read(&cpu->exit_request)) {
++			ret = 1;
++			break;
++		}
++
++		ret = nvmm_vcpu_run(mach, vcpu->cpuid, &exit);
++		if (ret == -1) {
++			error_report("NVMM: Failed to exec a virtual processor,"
++			    " error=%d", errno);
++			break;
++		}
++
++		nvmm_vcpu_post_run(cpu, &exit);
++
++		switch (exit.reason) {
++		case NVMM_EXIT_NONE:
++			break;
++		case NVMM_EXIT_MEMORY:
++			ret = nvmm_handle_mem(mach, vcpu, &exit);
++			break;
++		case NVMM_EXIT_IO:
++			ret = nvmm_handle_io(mach, vcpu, &exit);
++			break;
++		case NVMM_EXIT_MSR:
++			ret = nvmm_handle_msr(mach, vcpu, x86_cpu, &exit);
++			break;
++		case NVMM_EXIT_INT_READY:
++			vcpu->int_waiting = false;
++			break;
++		case NVMM_EXIT_NMI_READY:
++			vcpu->nmi_waiting = false;
++			break;
++		case NVMM_EXIT_HLT:
++			ret = nvmm_handle_hlt(cpu);
++			break;
++		case NVMM_EXIT_MONITOR:
++		case NVMM_EXIT_MWAIT:
++		case NVMM_EXIT_MWAIT_COND:
++			ret = nvmm_inject_ud(mach, vcpu);
++			break;
++
++		case NVMM_EXIT_SHUTDOWN: /* XXX what to do? */
++		default:
++			error_report("NVMM: Unexpected VM exit code %lu",
++			    exit.reason);
++			nvmm_get_registers(cpu);
++			qemu_mutex_lock_iothread();
++			qemu_system_guest_panicked(cpu_get_crash_info(cpu));
++			qemu_mutex_unlock_iothread();
++			ret = -1;
++			break;
++		}
++	} while (ret == 0);
++
++	cpu_exec_end(cpu);
++	qemu_mutex_lock_iothread();
++	current_cpu = cpu;
++
++	atomic_set(&cpu->exit_request, false);
++
++	return ret < 0;
++}
++
++/* -------------------------------------------------------------------------- */
++
++static void
++do_nvmm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
++{
++	nvmm_get_registers(cpu);
++	cpu->vcpu_dirty = true;
++}
++
++static void
++do_nvmm_cpu_synchronize_post_reset(CPUState *cpu, run_on_cpu_data arg)
++{
++	nvmm_set_registers(cpu);
++	cpu->vcpu_dirty = false;
++}
++
++static void
++do_nvmm_cpu_synchronize_post_init(CPUState *cpu, run_on_cpu_data arg)
++{
++	nvmm_set_registers(cpu);
++	cpu->vcpu_dirty = false;
++}
++
++static void
++do_nvmm_cpu_synchronize_pre_loadvm(CPUState *cpu, run_on_cpu_data arg)
++{
++	cpu->vcpu_dirty = true;
++}
++
++void nvmm_cpu_synchronize_state(CPUState *cpu)
++{
++	if (!cpu->vcpu_dirty) {
++		run_on_cpu(cpu, do_nvmm_cpu_synchronize_state, RUN_ON_CPU_NULL);
++	}
++}
++
++void nvmm_cpu_synchronize_post_reset(CPUState *cpu)
++{
++	run_on_cpu(cpu, do_nvmm_cpu_synchronize_post_reset, RUN_ON_CPU_NULL);
++}
++
++void nvmm_cpu_synchronize_post_init(CPUState *cpu)
++{
++	run_on_cpu(cpu, do_nvmm_cpu_synchronize_post_init, RUN_ON_CPU_NULL);
++}
++
++void nvmm_cpu_synchronize_pre_loadvm(CPUState *cpu)
++{
++	run_on_cpu(cpu, do_nvmm_cpu_synchronize_pre_loadvm, RUN_ON_CPU_NULL);
++}
++
++/* -------------------------------------------------------------------------- */
++
++static Error *nvmm_migration_blocker;
++
++int
++nvmm_init_vcpu(CPUState *cpu)
++{
++	struct nvmm_machine *mach = get_nvmm_mach();
++	Error *local_error = NULL;
++	struct nvmm_vcpu *vcpu;
++	int ret;
++
++	if (nvmm_migration_blocker == NULL) {
++		error_setg(&nvmm_migration_blocker,
++		    "NVMM: Migration not supported");
++
++		(void)migrate_add_blocker(nvmm_migration_blocker, &local_error);
++		if (local_error) {
++			error_report_err(local_error);
++			migrate_del_blocker(nvmm_migration_blocker);
++			error_free(nvmm_migration_blocker);
++			return -EINVAL;
++		}
++	}
++
++	vcpu = g_malloc0(sizeof(struct nvmm_vcpu));
++	if (vcpu == NULL) {
++		error_report("NVMM: Failed to allocate VCPU context.");
++		return -ENOMEM;
++	}
++	vcpu->cpuid = cpu->cpu_index;
++
++	ret = nvmm_vcpu_create(mach, vcpu->cpuid);
++	if (ret == -1) {
++		error_report("NVMM: Failed to create a virtual processor,"
++		    " error=%d", errno);
++		g_free(vcpu);
++		return -EINVAL;
++	}
++
++	cpu->vcpu_dirty = true;
++	cpu->hax_vcpu = (struct hax_vcpu_state *)vcpu;
++
++	return 0;
++}
++
++int
++nvmm_vcpu_exec(CPUState *cpu)
++{
++	int ret, fatal;
++
++	while (1) {
++		if (cpu->exception_index >= EXCP_INTERRUPT) {
++			ret = cpu->exception_index;
++			cpu->exception_index = -1;
++			break;
++		}
++
++		fatal = nvmm_vcpu_loop(cpu);
++
++		if (fatal) {
++			error_report("NVMM: Failed to execute a VCPU.");
++			abort();
++		}
++	}
++
++	return ret;
++}
++
++void
++nvmm_destroy_vcpu(CPUState *cpu)
++{
++	struct nvmm_machine *mach = get_nvmm_mach();
++	struct nvmm_vcpu *vcpu = get_nvmm_vcpu(cpu);
++
++	nvmm_vcpu_destroy(mach, vcpu->cpuid);
++	g_free(cpu->hax_vcpu);
++}
++
++/* -------------------------------------------------------------------------- */
++
++static void
++nvmm_update_mapping(hwaddr start_pa, ram_addr_t size, uintptr_t hva,
++    bool add, bool rom, const char *name)
++{
++	struct nvmm_machine *mach = get_nvmm_mach();
++	int ret;
++
++	// TODO rom read-only?
++
++	if (add) {
++		ret = nvmm_gpa_map(mach, hva, start_pa, size, 0);
++	} else {
++		ret = nvmm_gpa_unmap(mach, hva, start_pa, size);
++	}
++
++	if (ret == -1) {
++		error_report("NVMM: Failed to %s GPA range '%s' PA:%p, "
++		    "Size:%p bytes, HostVA:%p, error=%d",
++		    (add ? "map" : "unmap"), name, (void *)(uintptr_t)start_pa,
++		    (void *)size, (void *)hva, errno);
++	}
++}
++
++static void
++nvmm_process_section(MemoryRegionSection *section, int add)
++{
++	MemoryRegion *mr = section->mr;
++	hwaddr start_pa = section->offset_within_address_space;
++	ram_addr_t size = int128_get64(section->size);
++	unsigned int delta;
++	uintptr_t hva;
++
++	if (!memory_region_is_ram(mr)) {
++		return;
++	}
++
++	/* Adjust start_pa and size so that they are page-aligned. */
++	delta = qemu_real_host_page_size - (start_pa & ~qemu_real_host_page_mask);
++	delta &= ~qemu_real_host_page_mask;
++	if (delta > size) {
++		return;
++	}
++	start_pa += delta;
++	size -= delta;
++	size &= qemu_real_host_page_mask;
++	if (!size || (start_pa & ~qemu_real_host_page_mask)) {
++		return;
++	}
++
++	hva = (uintptr_t)memory_region_get_ram_ptr(mr) +
++	    section->offset_within_region + delta;
++
++	nvmm_update_mapping(start_pa, size, hva, add,
++	    memory_region_is_rom(mr), mr->name);
++}
++
++static void
++nvmm_region_add(MemoryListener *listener, MemoryRegionSection *section)
++{
++	memory_region_ref(section->mr);
++	nvmm_process_section(section, 1);
++}
++
++static void
++nvmm_region_del(MemoryListener *listener, MemoryRegionSection *section)
++{
++	nvmm_process_section(section, 0);
++	memory_region_unref(section->mr);
++}
++
++static void
++nvmm_transaction_begin(MemoryListener *listener)
++{
++	/* nothing */
++}
++
++static void
++nvmm_transaction_commit(MemoryListener *listener)
++{
++	/* nothing */
++}
++
++static void
++nvmm_log_sync(MemoryListener *listener, MemoryRegionSection *section)
++{
++	MemoryRegion *mr = section->mr;
++
++	if (!memory_region_is_ram(mr)) {
++		return;
++	}
++
++	memory_region_set_dirty(mr, 0, int128_get64(section->size));
++}
++
++static MemoryListener nvmm_memory_listener = {
++	.begin = nvmm_transaction_begin,
++	.commit = nvmm_transaction_commit,
++	.region_add = nvmm_region_add,
++	.region_del = nvmm_region_del,
++	.log_sync = nvmm_log_sync,
++	.priority = 10,
++};
++
++/* -------------------------------------------------------------------------- */
++
++static void
++nvmm_handle_interrupt(CPUState *cpu, int mask)
++{
++	cpu->interrupt_request |= mask;
++
++	if (!qemu_cpu_is_self(cpu)) {
++		qemu_cpu_kick(cpu);
++	}
++}
++
++/* -------------------------------------------------------------------------- */
++
++static int
++nvmm_accel_configure(struct nvmm_machine *mach)
++{
++	struct nvmm_x86_conf_cpuid cpuid;
++	int ret;
++
++	/* Delete the Monitor bit, set the Hypervisor bit. */
++	memset(&cpuid, 0, sizeof(cpuid));
++	cpuid.leaf = 0x00000001;
++	cpuid.del.ecx = CPUID_EXT_MONITOR;
++	cpuid.set.ecx = CPUID_EXT_HYPERVISOR;
++
++	ret = nvmm_machine_configure(mach, NVMM_X86_CONF_CPUID, &cpuid);
++	if (ret == -1)
++		return -1;
++
++	/* Delete the OSVW bit. */
++	memset(&cpuid, 0, sizeof(cpuid));
++	cpuid.leaf = 0x80000001;
++	cpuid.del.ecx = CPUID_EXT3_OSVW;
++
++	ret = nvmm_machine_configure(mach, NVMM_X86_CONF_CPUID, &cpuid);
++	if (ret == -1)
++		return -1;
++
++	return 0;
++}
++
++static int
++nvmm_accel_init(MachineState *ms)
++{
++	struct nvmm_capability cap;
++	int ret;
++
++	ret = nvmm_capability(&cap);
++	if (ret == -1) {
++		error_report("NVMM: No accelerator found, error=%d", errno);
++		return -ENOSPC;
++	}
++	if (cap.version != 1) {
++		error_report("NVMM: Unsupported version %lu", cap.version);
++		return -ENOSPC;
++	}
++
++	ret = nvmm_machine_create(&nvmm_global.mach);
++	if (ret == -1) {
++		error_report("NVMM: Machine creation failed, error=%d", errno);
++		return -ENOSPC;
++	}
++
++	ret = nvmm_accel_configure(&nvmm_global.mach);
++	if (ret == -1) {
++		error_report("NVMM: Machine configuration failed, error=%d",
++		    errno);
++		return -ENOSPC;
++	}
++
++	memory_listener_register(&nvmm_memory_listener, &address_space_memory);
++
++	cpu_interrupt_handler = nvmm_handle_interrupt;
++
++	printf("NetBSD Virtual Machine Monitor accelerator is operational\n");
++	return 0;
++}
++
++int
++nvmm_enabled(void)
++{
++	return nvmm_allowed;
++}
++
++static void
++nvmm_accel_class_init(ObjectClass *oc, void *data)
++{
++	AccelClass *ac = ACCEL_CLASS(oc);
++	ac->name = "NVMM";
++	ac->init_machine = nvmm_accel_init;
++	ac->allowed = &nvmm_allowed;
++}
++
++static const TypeInfo nvmm_accel_type = {
++	.name = ACCEL_CLASS_NAME("nvmm"),
++	.parent = TYPE_ACCEL,
++	.class_init = nvmm_accel_class_init,
++};
++
++static void
++nvmm_type_init(void)
++{
++	type_register_static(&nvmm_accel_type);
++}
++
++type_init(nvmm_type_init);
+--- vl.c	2018-08-14 21:10:35.000000000 +0200
++++ vl.c	2018-11-01 11:34:34.466762381 +0100
+@@ -3620,7 +3620,8 @@
+                                                      optarg, true);
+                 optarg = qemu_opt_get(accel_opts, "accel");
+                 if (!optarg || is_help_option(optarg)) {
+-                    error_printf("Possible accelerators: kvm, xen, hax, tcg\n");
++                    error_printf("Possible accelerators: "
++                        "kvm, xen, hax, nvmm, tcg\n");
+                     exit(0);
+                 }
+                 opts = qemu_opts_create(qemu_find_opts("machine"), NULL,
diff --git a/qemu-nvmm/patches/patch-tests_Makefile.include b/qemu-nvmm/patches/patch-tests_Makefile.include
new file mode 100644
index 0000000000..9921005155
--- /dev/null
+++ b/qemu-nvmm/patches/patch-tests_Makefile.include
@@ -0,0 +1,17 @@
+$NetBSD: patch-tests_Makefile.include,v 1.1 2016/09/04 09:21:04 ryoon Exp $
+
+* Don't link -lutil on SunOS
+
+--- tests/Makefile.include.orig	2016-09-02 15:34:24.000000000 +0000
++++ tests/Makefile.include
+@@ -645,8 +645,10 @@ tests/migration/initrd-stress.img: tests
+ 	rmdir $(INITRD_WORK_DIR)
+ 
+ ifeq ($(CONFIG_POSIX),y)
++ifneq ($(CONFIG_SOLARIS),y)
+ LIBS += -lutil
+ endif
++endif
+ 
+ # QTest rules
+ 


Home | Main Index | Thread Index | Old Index