From patchwork Thu Feb 6 21:32:29 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Kamil Rytarowski X-Patchwork-Id: 11369263 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id F2429921 for ; Thu, 6 Feb 2020 21:42:57 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id A875721775 for ; Thu, 6 Feb 2020 21:42:57 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=gmx.net header.i=@gmx.net header.b="UGsEVrhH" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org A875721775 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=gmx.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:46682 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1izovI-0008DW-IY for patchwork-qemu-devel@patchwork.kernel.org; Thu, 06 Feb 2020 16:42:56 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:37845) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1izomT-0008QX-4D for qemu-devel@nongnu.org; Thu, 06 Feb 2020 16:33:50 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1izomR-0006bV-TA for qemu-devel@nongnu.org; Thu, 06 Feb 2020 16:33:49 -0500 Received: from mout.gmx.net ([212.227.17.20]:48093) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1izomR-0006W5-Jf for qemu-devel@nongnu.org; Thu, 06 Feb 2020 16:33:47 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.net; s=badeba3b8450; t=1581024807; bh=43JXsEqXoI6zRifZU5jbyKDtX8fN//Y4L0FT1Lm+1hc=; h=X-UI-Sender-Class:From:To:Cc:Subject:Date:In-Reply-To:References; b=UGsEVrhH+zMDyFFNCtm9UDE6S0Pz1BvLAmHOH1d4hoDKmmI7iLuYlYkwC7yCZJz8U E6ZaInwzf7uVr4LRH01RPMiC1uugpfk+uKlEX78hXwUo33NhLY1dc6ldCdqzzxAPh4 2d1THvhoQrz/NfLw3DLpuJvYG9+uDqa3fbQIFVCg= X-UI-Sender-Class: 01bb95c1-4bf8-414a-932a-4f6e2808ef9c Received: from localhost.localdomain ([89.71.135.231]) by mail.gmx.com (mrgmx105 [212.227.17.174]) with ESMTPSA (Nemesis) id 1MpUYu-1jIR4M3NUq-00ptFi; Thu, 06 Feb 2020 22:33:26 +0100 From: Kamil Rytarowski To: rth@twiddle.net, ehabkost@redhat.com, slp@redhat.com, pbonzini@redhat.com, peter.maydell@linaro.org, philmd@redhat.com, max@m00nbsd.net, jmcneill@invisible.ca Subject: [PATCH v4 1/4] Add the NVMM vcpu API Date: Thu, 6 Feb 2020 22:32:29 +0100 Message-Id: <20200206213232.1918-2-n54@gmx.com> X-Mailer: git-send-email 2.25.0 In-Reply-To: <20200206213232.1918-1-n54@gmx.com> References: <20200206115731.13552-1-n54@gmx.com> <20200206213232.1918-1-n54@gmx.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:AgzSK0caQx13eSEYxLFtblYd8SM6UX5HBNwDUW7ZkzkG9+tqdJW sbWaUHjvJVcRNnbB508Mp57RClxzeUei89fri4nxA/18TS9A85poms4FFeyl0kluF4u2+2p 6WzWTZ9445hOsmmG/qE7aoGzjOHAgG0dqH8maA0HrgqcLj+0jMKDqRrBl/pyokvNw9cj0Pq 4BoX/kl3eAA0nK7W23AKw== X-UI-Out-Filterresults: notjunk:1;V03:K0:b4Rc2p62CZc=:CDeVeIabajuyYd3rR8bFvK 3xLEpYnsI6RldasUVhytbRYoXqC27HlQcvHlHAzT7/D9quVXDWuugyfjHlEIPqB+XETDNRIvq CKyTA+Sopj7dpxZxiIQQNC74vDF/93d/ZIs3Nn1swVBSk0fpG/9S3nXDtZp9Fy8LTmTJ/RKGc 9kYEJ2eFMWgVBDrZheEPbeJle0vvO2MGX8pqo1PORzmFkZzauYvcnaMKzghfxMmvDuvqDwDxg igvzq4NxFZ96csiFDXZyOe6MorwgFl3sDz6bEbOPQ4Y95QZqyquHPevchsook+p9Y0mycS7mJ OiDYTTYHf5Q+yOUj3qLogWfHQ381MlLx5tmn5k66oVTMbhmK0yuD1IPxzAjQL5Y8xg73WCLVX hTdliG25n1VeGprkfqp8FFy2Bna/tIWGV9s4VGDJRJNgp6tPH2KQJez32DbRUy7OTwJFQHZ5m i2OIo7/X5Ukj+5WqlqRIXUqUKypjOZ8qD/wQLZvgj9Rz629EN4c66tP9LKS25MC3e3ga3dOJC JrNhNg6Kph9JLlJiHXrTjB/wDLR2Bpd7fSu/TZV31l9ZrB4apJ63JUGvGG6/1Z55FsRE6k+iB sUVunQ5rslnpUGiUMA/9uApHv8HqAGzPiVIvKAmReikWmT6EFPV6ocrtxMD+lAuw47MpSqINs +trAKQuvbmHDazyg0V1RSbLrH9v9hptrAw5j0CK4AH9BiQX5G9fLCpiCQSWP7IMbYtDxtvFHZ ub5vuRI3Z4HknlU3YJv1WWFSapsMZi+a28OtSQd8b7qW59fAxQyrAM5O3xcCzJ2zcZU85SsbR fvf04GfNTCYxDyWSalMtrtaJAPd+yd/XmvBbXzWKghhjU6vVc+0zjjBQWRE8bjaiA6BDvmuyg O4n3A2J7bqK/Nj6F/uQYZjQa/k5729ieoGoaaJh6aTQ4trOgHTPT14y1PQQ4qU4ST7jxB+vn/ TBmGJDXmFEcbPn9RYxLSVZ6uasbiACtV0vLLzrOisHixHw0lldNWHFV0tUDANQpDt4wi628Q2 P46E9/wUgBh/7iob0P0DETIqs7liNlvBtt6j0YwERW31W/WxnAuaHaI0RX8Xa27djvs0HRpNo mNYPaeEKaVcfqxpOAu2boFhlb4Oje2qrZPacC0hgnAtuxQncjj47D0Yg8kOyDedqteUNlutfh vXEW5H3wuaBbqv1SdmnNmj4dyALs5q5ILyFmCO1+aAmJjtJjI9jwIPeb0LUNuJ7f4lj0c= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 212.227.17.20 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kamil Rytarowski , qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" From: Maxime Villard Adds support for the NetBSD Virtual Machine Monitor (NVMM) stubs and introduces the nvmm.h sysemu API for managing the vcpu scheduling and management. Signed-off-by: Maxime Villard Signed-off-by: Kamil Rytarowski Reviewed-by: Sergio Lopez Reviewed-by: Philippe Mathieu-Daudé Tested-by: Jared McNeill --- accel/stubs/Makefile.objs | 1 + accel/stubs/nvmm-stub.c | 43 +++++++++++++++++++++++++++++++++++++++ include/sysemu/nvmm.h | 35 +++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 accel/stubs/nvmm-stub.c create mode 100644 include/sysemu/nvmm.h -- 2.25.0 diff --git a/accel/stubs/Makefile.objs b/accel/stubs/Makefile.objs index 3894caf95d..09f2d3e1dd 100644 --- a/accel/stubs/Makefile.objs +++ b/accel/stubs/Makefile.objs @@ -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 diff --git a/accel/stubs/nvmm-stub.c b/accel/stubs/nvmm-stub.c new file mode 100644 index 0000000000..c2208b84a3 --- /dev/null +++ b/accel/stubs/nvmm-stub.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018-2019 Maxime Villard, All rights reserved. + * + * NetBSD Virtual Machine Monitor (NVMM) accelerator stub. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#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_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) +{ +} diff --git a/include/sysemu/nvmm.h b/include/sysemu/nvmm.h new file mode 100644 index 0000000000..10496f3980 --- /dev/null +++ b/include/sysemu/nvmm.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018-2019 Maxime Villard, All rights reserved. + * + * NetBSD Virtual Machine Monitor (NVMM) accelerator support. + * + * 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_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_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 */ From patchwork Thu Feb 6 21:32:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Kamil Rytarowski X-Patchwork-Id: 11369291 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 92E3E92A for ; Thu, 6 Feb 2020 21:52:34 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 6A614214AF for ; Thu, 6 Feb 2020 21:52:34 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=gmx.net header.i=@gmx.net header.b="OpfoNEp9" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 6A614214AF Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=gmx.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:46852 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1izp4b-0004VW-EN for patchwork-qemu-devel@patchwork.kernel.org; Thu, 06 Feb 2020 16:52:33 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:37793) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1izomP-0008Ih-4j for qemu-devel@nongnu.org; Thu, 06 Feb 2020 16:33:46 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1izomN-0006KC-Dh for qemu-devel@nongnu.org; Thu, 06 Feb 2020 16:33:45 -0500 Received: from mout.gmx.net ([212.227.17.21]:49185) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1izomN-0006Dh-3d for qemu-devel@nongnu.org; Thu, 06 Feb 2020 16:33:43 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.net; s=badeba3b8450; t=1581024807; bh=Kf6PjNDz9KTNSeBVYDQemDGF/lneulLD8So5cZYZOpo=; h=X-UI-Sender-Class:From:To:Cc:Subject:Date:In-Reply-To:References; b=OpfoNEp9NGeurnIi62MflxEGOMU86AOmr/1Zm853LSuxPdAxKDk9y1aGhuzcwmWFu OmJ8SjMgL24EMcx/bXdr7HuKGifj9k7WvNYhyYhIu/8ztXTYpvj8p2YGHZcTF8TaaN 7FxMlpfGKArx/McjJH8ZpXTIiZDk7TxLIegTZb9s= X-UI-Sender-Class: 01bb95c1-4bf8-414a-932a-4f6e2808ef9c Received: from localhost.localdomain ([89.71.135.231]) by mail.gmx.com (mrgmx105 [212.227.17.174]) with ESMTPSA (Nemesis) id 1MG9kC-1ijNIh26DE-00GYV8; Thu, 06 Feb 2020 22:33:27 +0100 From: Kamil Rytarowski To: rth@twiddle.net, ehabkost@redhat.com, slp@redhat.com, pbonzini@redhat.com, peter.maydell@linaro.org, philmd@redhat.com, max@m00nbsd.net, jmcneill@invisible.ca Subject: [PATCH v4 2/4] Add the NetBSD Virtual Machine Monitor accelerator. Date: Thu, 6 Feb 2020 22:32:30 +0100 Message-Id: <20200206213232.1918-3-n54@gmx.com> X-Mailer: git-send-email 2.25.0 In-Reply-To: <20200206213232.1918-1-n54@gmx.com> References: <20200206115731.13552-1-n54@gmx.com> <20200206213232.1918-1-n54@gmx.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:C3Q726RK79xZjNh0XEi7RUkmSHG5tZojxZ72Eb0D5wxGuyjZ8de gYC4Kx3jGjwu3ITNzNRscbHS3MZt4f9q+Lks08yVlO0mbBHz4kCeMG/1YLFHbXCt7PbDUGD d2/4Kz9Be2lZhVzR6A5JURlgBUf10n+fmZ0jIXVyrPDnZyUO7oxCCzprjuB+NJihePz2V5s YK9s4tSfkVIJoh7w/yNkg== X-UI-Out-Filterresults: notjunk:1;V03:K0:iSZgP7mTPZw=:yAlYi7gdKrl8stbkGHuo1D FlAC3S+qGBG+oDEBUPR3AkaEoae/JeCHDwbePuAwuH57hgGiTqcR1VSlnANL0JF/ZVsXLWzrS xNELEsS53xMsv2Zrr2y9DE9RNvLw0DzOW46UtAr2TsMvDVX4VFR7/QO/SQUhePMQCQIDxzBpL QnxBA5jmcAmTkLv9Kdel2JemOp/gF/wOMKxGjy1jub/P34U2KIqPaJjM8VC4Vlj4dvVQzvP50 hkVexL/tkK5+87s0PQCZYev+bjx2vJGiWzdoVnts9crLP5OBZip1LbcoZ7rBIxtb7DTFF6kPV pb6hz49edwU5POtK0KZVbIoQnk8nr8hNwmsCjwX7aNz7684BA+gqzGu2m1APcADHTyn/KObpB 7TeAxSzNMS8enyZG3YqK+utd2MlhyIIJKPw0A03edgNCUYNkQuTl956w6FUe8Auhc5aOEAbJh BjwlarHfxYfRHCzYtLnR1vGbqqyjp323sZ0iBh3Zr40PHVWSKR5CB+goo5qSv7XnAA3vOcwyT JiixYBfc6klf8wVuhvZO7JwPDCj/ad5jEBRlolvSI1vdAuckWMSSp1tTCxRGv5Fw1nTfFcsuR iYHE6p+tAqdhvjKmHcR8ZfFhCuysVbHJyWmviIcUKaoSewXjqkaAgKu7kegxeo4oAbPabx3oU uYeOjDdda3CEIVxXUOPRDU28RM0mZnAHo8RVSv7V1YRDvVsdsNsh9wBXCrOzuEm+VPpqqG5hX Mfi+Kz92K/ahmnb6KAWhGflKnBcINM2PaC3hiQi+2ziOfvWNRlDNJ7/joH1i+warpg3cptatP BWgWxaX7aYME5NMxFEl0WLnjOIziLUkYomtFxSIux4wfBoYpvYGgk8T3nl5K9THTgoIsYWnvn jxlHPWWO1/W+OfBowkdXSDcSPIoDcU/RcbUgYp7jCd+MeZfHA2oTvA7QBxmkuewDX2GMlWzQg bN3RiKt+aPaCAyi6h8bZfJVeVPScMS/GKVQ7qyq0w55HXayFb+fyd6ALLsWhQhXSGvVRBKVaO 06kiDK6ZDRFqwFODzxgwXipr4teIoLbbIN0/c1RSC407Rq/Paye1ZaFgpW2j1K2cSX9kQ/E33 36NNwhLBJa6+wurPtvB+0xADPjDKjKdcQbpKTUv4lmIYbtSQiihAXF3vJsMaRw7HZGZ9FcwPR TqZTis1f0NNmfrhraUoP5R8fN4hCcdROxk+keIBLUF0XguqXB6f5bvWciWMDD3l2psa+w= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 212.227.17.21 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kamil Rytarowski , qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" From: Maxime Villard Introduces the configure support for the new NetBSD Virtual Machine Monitor that allows for hypervisor acceleration from usermode components on the NetBSD platform. Signed-off-by: Maxime Villard Signed-off-by: Kamil Rytarowski Reviewed-by: Sergio Lopez Reviewed-by: Philippe Mathieu-Daudé Tested-by: Jared McNeill --- configure | 37 +++++++++++++++++++++++++++++++++++++ qemu-options.hx | 16 ++++++++-------- 2 files changed, 45 insertions(+), 8 deletions(-) -- 2.25.0 diff --git a/configure b/configure index 115dc38085..d4a837cf9d 100755 --- a/configure +++ b/configure @@ -241,6 +241,17 @@ supported_whpx_target() { return 1 } +supported_nvmm_target() { + test "$nvmm" = "yes" || return 1 + glob "$1" "*-softmmu" || return 1 + case "${1%-softmmu}" in + i386|x86_64) + return 0 + ;; + esac + return 1 +} + supported_target() { case "$1" in *-softmmu) @@ -268,6 +279,7 @@ supported_target() { 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 } @@ -388,6 +400,7 @@ kvm="no" hax="no" hvf="no" whpx="no" +nvmm="no" rdma="" pvrdma="" gprof="no" @@ -823,6 +836,7 @@ DragonFly) NetBSD) bsd="yes" hax="yes" + nvmm="yes" make="${MAKE-gmake}" audio_drv_list="oss try-sdl" audio_possible_drivers="oss sdl" @@ -1169,6 +1183,10 @@ for opt do ;; --enable-whpx) whpx="yes" ;; + --disable-nvmm) nvmm="no" + ;; + --enable-nvmm) nvmm="yes" + ;; --disable-tcg-interpreter) tcg_interpreter="no" ;; --enable-tcg-interpreter) tcg_interpreter="yes" @@ -1773,6 +1791,7 @@ disabled with --disable-FEATURE, default is enabled if available: 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 pvrdma Enable PVRDMA support vde support for vde network @@ -2764,6 +2783,20 @@ if test "$whpx" != "no" ; then fi fi +########################################## +# NetBSD Virtual Machine Monitor (NVMM) accelerator check +if test "$nvmm" != "no" ; then + if check_include "nvmm.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 @@ -6543,6 +6576,7 @@ echo "KVM support $kvm" 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" @@ -7828,6 +7862,9 @@ fi if test "$target_aligned_only" = "yes" ; then echo "TARGET_ALIGNED_ONLY=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 diff --git a/qemu-options.hx b/qemu-options.hx index 224a8e8712..10c046c916 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -31,7 +31,7 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ "-machine [type=]name[,prop[=value][,...]]\n" " selects emulated machine ('-machine help' for list)\n" " property accel=accel1[:accel2[:...]] selects accelerator\n" - " supported accelerators are kvm, xen, hax, hvf, whpx or tcg (default: tcg)\n" + " supported accelerators are kvm, xen, hax, hvf, nvmm, whpx or tcg (default: tcg)\n" " vmport=on|off|auto controls emulation of vmport (default: auto)\n" " dump-guest-core=on|off include guest memory in a core dump (default=on)\n" " mem-merge=on|off controls memory merge support (default: on)\n" @@ -64,9 +64,9 @@ Supported machine properties are: @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 -more than one accelerator specified, the next one is used if the previous one -fails to initialize. +kvm, xen, hax, hvf, nvmm, whpx 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 vmport=on|off|auto Enables emulation of VMWare IO port, for vmmouse etc. auto says to select the value based on accel. For accel=xen the default is off otherwise the default @@ -114,7 +114,7 @@ ETEXI DEF("accel", HAS_ARG, QEMU_OPTION_accel, "-accel [accel=]accelerator[,prop[=value][,...]]\n" - " select accelerator (kvm, xen, hax, hvf, whpx or tcg; use 'help' for a list)\n" + " select accelerator (kvm, xen, hax, hvf, nvmm, whpx or tcg; use 'help' for a list)\n" " igd-passthru=on|off (enable Xen integrated Intel graphics passthrough, default=off)\n" " kernel-irqchip=on|off|split controls accelerated irqchip support (default=on)\n" " kvm-shadow-mem=size of KVM shadow MMU in bytes\n" @@ -124,9 +124,9 @@ 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 -more than one accelerator specified, the next one is used if the previous one -fails to initialize. +kvm, xen, hax, hvf, nvmm, whpx 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 @item igd-passthru=on|off When Xen is in use, this option controls whether Intel integrated graphics From patchwork Thu Feb 6 21:32:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kamil Rytarowski X-Patchwork-Id: 11369295 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4711714B4 for ; Thu, 6 Feb 2020 21:57:27 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id F0F50214AF for ; Thu, 6 Feb 2020 21:57:26 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=gmx.net header.i=@gmx.net header.b="ZcYuOAoL" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org F0F50214AF Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=gmx.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:46908 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1izp9K-0007RE-0n for patchwork-qemu-devel@patchwork.kernel.org; Thu, 06 Feb 2020 16:57:26 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:37935) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1izoma-0000Fw-7J for qemu-devel@nongnu.org; Thu, 06 Feb 2020 16:34:00 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1izomW-000707-2a for qemu-devel@nongnu.org; Thu, 06 Feb 2020 16:33:56 -0500 Received: from mout.gmx.net ([212.227.17.20]:42325) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1izomV-0006rF-JJ for qemu-devel@nongnu.org; Thu, 06 Feb 2020 16:33:52 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.net; s=badeba3b8450; t=1581024808; bh=a2F0qr52TkRe1SZ0/ZT8wBLkX80C6cksx9lBt/HD+Us=; h=X-UI-Sender-Class:From:To:Cc:Subject:Date:In-Reply-To:References; b=ZcYuOAoLazYAE99uvbVTQ1SE9wbsUx2Sw55WgFJaY7RMK5foIlkpjcFZV7b12Vb20 /+PZAAQqv9ta2qTMilG2IJCzHPrtdIfoH/RU4c420tHnn8tvjM9Oo239Qb6FbPHX5I hamm4ZWZnGFfkx/c6uYIddGwuYgPz9jPBNx3IKhg= X-UI-Sender-Class: 01bb95c1-4bf8-414a-932a-4f6e2808ef9c Received: from localhost.localdomain ([89.71.135.231]) by mail.gmx.com (mrgmx105 [212.227.17.174]) with ESMTPSA (Nemesis) id 1M6lpG-1isghq11PK-008H2m; Thu, 06 Feb 2020 22:33:28 +0100 From: Kamil Rytarowski To: rth@twiddle.net, ehabkost@redhat.com, slp@redhat.com, pbonzini@redhat.com, peter.maydell@linaro.org, philmd@redhat.com, max@m00nbsd.net, jmcneill@invisible.ca Subject: [PATCH v4 3/4] Introduce the NVMM impl Date: Thu, 6 Feb 2020 22:32:31 +0100 Message-Id: <20200206213232.1918-4-n54@gmx.com> X-Mailer: git-send-email 2.25.0 In-Reply-To: <20200206213232.1918-1-n54@gmx.com> References: <20200206115731.13552-1-n54@gmx.com> <20200206213232.1918-1-n54@gmx.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:a8xJ/NYy2xAOev3t3WHrEnvsD4ScD1BFxy0IGzT9oXCqrnzdxsD oVgP4djg5PvQNW/gL2uYXjT9Bn5TWo3c8nCZHViSBL4dMnmQRS/EaWlfUYxGAekGSQ49Qxk Jb9PhJnzB8JaboRSCmRXLrYYRwH+oFItc12jLRFkwHQ6oxFaiBk0/BxMEnWwnpg/RFlMR0f Qs3ojMWj0vjJP8GWqLbqw== X-UI-Out-Filterresults: notjunk:1;V03:K0:TiisJwSgG4I=:Zt9qf0sMCZkNWLYLhwufwL 1GO6nN883sGx+LBQZRRKqmaTvkWu39zKwbUh0CsHNmFlFsVWjCvsXwMOQdNusDGETm86JEuoJ PeXjtIbqmNzlIRSOhRZgpVNTOxEwTHr1s42FIsZHpksFg+u14+G+/+BpDZ5jiIn8dVrq7Tvck Sqd5iGXic1lVxlD0wwe2CghzPXP+Y2IKGuxmz57fghJDZcXxQw4QSN7FEoG/p31k8+MYihAKQ Gjm6UqvxHPLrVh8JPsvRDoP/uPOg7HDY7rZP7LDWtkRC1myCY5V/gZDTuC2PGufhYcPJhhVc4 S6iwMGnsRgTZWbjs+RL5Fo3yPACjusT+fcZmz9PGtU1PcmRMR/hDJIULfKY+K5PFnxyc0TQvZ lb6u0Hi8GtaCJTZo/H6bwyGUkhLax36/SEwypVcESUdVqWMeUWRoK/EM+GzEKTnAGxtqqSudu X0aNGcyc1mTg1gprXswnbVpUmCaWqQvYLc0yky0ReoL/NgYLeNwq1TGr9W2A291YrVzWS72JB Jbddryif2vh9GQErnFO039tXSQh1TCGN0PvNcqAui6a2OZeLzodipSXffFrumbniBA8lxC0Pn 3GaBWX46DgHT/SRfBs6QftuSD/9OuUuXxTB8MD2hE0Lqkr1qNUs+Q6OdwzXS7SnrkxSGeXg12 tICHYFvTgnFxo1FL15Frrqz0SJFYh9ZYS7EZ+xv95AyFHNZjLrH2i74gonCE/O9PG4lRlVUVQ LgEGMaJRvpMUgqM9J46OVCm43sIq00ieDi9Vf71Qegbs3iTD2MAlfRV+yv8V/ySbLw0M9spCD MLIXw8p1Xgdl3B+1sYTkq6/fHdfWbV+QF5PIjwztAUHTUbUW0d4JW5han8qexSHbi16/I9RZm sp0bZuJgzSWJTIBWBfN8IdcG/+bhtv0ybD1j7eJMIDWarDuMW0gh0/TcCL2jRLTHqBNtf0kXs bh1DY+gW+ZgXWKGlXTb1O3APXsOvwoFGUGLkD5NTCFuHZgys+O40482Ib3zLZvnjy7mAM98t0 OsHGuIPuHWeaZOE4M6kAIZyISUSJl6q3zKIFrjJbSe6K1fqAldnIPbJP6HxZB8IQ5vLomBoNv iO0RcuA+qQgfCHrBaAINPUpHK4mbvcQzqvOfdcLAO41d+iiBUOlVnGRLJ3LcPjMWIZX7k69/Q wmDEfPA1wt6SNVdi6y+dQ1SrDF4jYQsq7Bw/oadbEF5KDEv9w540qDRJ5o9qtq9sMKX0c= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 212.227.17.20 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kamil Rytarowski , qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" From: Maxime Villard Implements the NetBSD Virtual Machine Monitor (NVMM) target. Which acts as a hypervisor accelerator for QEMU on the NetBSD platform. This enables QEMU much greater speed over the emulated x86_64 path's that are taken on NetBSD today. Signed-off-by: Maxime Villard Signed-off-by: Kamil Rytarowski Reviewed-by: Sergio Lopez Tested-by: Jared McNeill --- target/i386/Makefile.objs | 1 + target/i386/nvmm-all.c | 1226 +++++++++++++++++++++++++++++++++++++ 2 files changed, 1227 insertions(+) create mode 100644 target/i386/nvmm-all.c -- 2.25.0 diff --git a/target/i386/Makefile.objs b/target/i386/Makefile.objs index 48e0c28434..bdcdb32e93 100644 --- a/target/i386/Makefile.objs +++ b/target/i386/Makefile.objs @@ -17,6 +17,7 @@ obj-$(CONFIG_HAX) += hax-all.o hax-mem.o hax-posix.o endif obj-$(CONFIG_HVF) += hvf/ obj-$(CONFIG_WHPX) += whpx-all.o +obj-$(CONFIG_NVMM) += nvmm-all.o endif obj-$(CONFIG_SEV) += sev.o obj-$(call lnot,$(CONFIG_SEV)) += sev-stub.o diff --git a/target/i386/nvmm-all.c b/target/i386/nvmm-all.c new file mode 100644 index 0000000000..a21908f46a --- /dev/null +++ b/target/i386/nvmm-all.c @@ -0,0 +1,1226 @@ +/* + * Copyright (c) 2018-2019 Maxime Villard, All rights reserved. + * + * NetBSD Virtual Machine Monitor (NVMM) accelerator for QEMU. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#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/runstate.h" +#include "sysemu/sysemu.h" +#include "sysemu/cpus.h" +#include "qemu/main-loop.h" +#include "qemu/error-report.h" +#include "qemu/queue.h" +#include "qapi/error.h" +#include "migration/blocker.h" + +#include + +struct qemu_vcpu { + struct nvmm_vcpu vcpu; + uint8_t tpr; + bool stop; + + /* Window-exiting for INTs/NMIs. */ + bool int_window_exit; + bool nmi_window_exit; + + /* The guest is in an interrupt shadow (POP SS, etc). */ + bool int_shadow; +}; + +struct qemu_machine { + struct nvmm_capability cap; + struct nvmm_machine mach; +}; + +/* -------------------------------------------------------------------------- */ + +static bool nvmm_allowed; +static struct qemu_machine qemu_mach; + +static struct qemu_vcpu * +get_qemu_vcpu(CPUState *cpu) +{ + return (struct qemu_vcpu *)cpu->hax_vcpu; +} + +static struct nvmm_machine * +get_nvmm_mach(void) +{ + return &qemu_mach.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_TYPE_MASK); + nseg->attrib.s = __SHIFTOUT(attrib, DESC_S_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.l = __SHIFTOUT(attrib, DESC_L_MASK); + nseg->attrib.def = __SHIFTOUT(attrib, DESC_B_MASK); + nseg->attrib.g = __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 qemu_vcpu *qcpu = get_qemu_vcpu(cpu); + struct nvmm_vcpu *vcpu = &qcpu->vcpu; + struct nvmm_x64_state *state = vcpu->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] = env->regs[R_EAX]; + state->gprs[NVMM_X64_GPR_RCX] = env->regs[R_ECX]; + state->gprs[NVMM_X64_GPR_RDX] = env->regs[R_EDX]; + state->gprs[NVMM_X64_GPR_RBX] = env->regs[R_EBX]; + state->gprs[NVMM_X64_GPR_RSP] = env->regs[R_ESP]; + state->gprs[NVMM_X64_GPR_RBP] = env->regs[R_EBP]; + state->gprs[NVMM_X64_GPR_RSI] = env->regs[R_ESI]; + state->gprs[NVMM_X64_GPR_RDI] = env->regs[R_EDI]; +#ifdef TARGET_X86_64 + state->gprs[NVMM_X64_GPR_R8] = env->regs[R_R8]; + state->gprs[NVMM_X64_GPR_R9] = env->regs[R_R9]; + state->gprs[NVMM_X64_GPR_R10] = env->regs[R_R10]; + state->gprs[NVMM_X64_GPR_R11] = env->regs[R_R11]; + state->gprs[NVMM_X64_GPR_R12] = env->regs[R_R12]; + state->gprs[NVMM_X64_GPR_R13] = env->regs[R_R13]; + state->gprs[NVMM_X64_GPR_R14] = env->regs[R_R14]; + state->gprs[NVMM_X64_GPR_R15] = env->regs[R_R15]; +#endif + + /* RIP and RFLAGS. */ + state->gprs[NVMM_X64_GPR_RIP] = env->eip; + state->gprs[NVMM_X64_GPR_RFLAGS] = 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] = env->cr[0]; + state->crs[NVMM_X64_CR_CR2] = env->cr[2]; + state->crs[NVMM_X64_CR_CR3] = env->cr[3]; + state->crs[NVMM_X64_CR_CR4] = env->cr[4]; + state->crs[NVMM_X64_CR_CR8] = qcpu->tpr; + state->crs[NVMM_X64_CR_XCR0] = env->xcr0; + + /* Debug registers. */ + state->drs[NVMM_X64_DR_DR0] = env->dr[0]; + state->drs[NVMM_X64_DR_DR1] = env->dr[1]; + state->drs[NVMM_X64_DR_DR2] = env->dr[2]; + state->drs[NVMM_X64_DR_DR3] = env->dr[3]; + state->drs[NVMM_X64_DR_DR6] = env->dr[6]; + state->drs[NVMM_X64_DR_DR7] = 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 < 16; 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_esp; + state->msrs[NVMM_X64_MSR_SYSENTER_EIP] = env->sysenter_eip; + state->msrs[NVMM_X64_MSR_PAT] = env->pat; + state->msrs[NVMM_X64_MSR_TSC] = env->tsc; + + 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, 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((uint32_t)nseg->attrib.type, DESC_TYPE_MASK) | + __SHIFTIN((uint32_t)nseg->attrib.s, DESC_S_MASK) | + __SHIFTIN((uint32_t)nseg->attrib.dpl, DESC_DPL_MASK) | + __SHIFTIN((uint32_t)nseg->attrib.p, DESC_P_MASK) | + __SHIFTIN((uint32_t)nseg->attrib.avl, DESC_AVL_MASK) | + __SHIFTIN((uint32_t)nseg->attrib.l, DESC_L_MASK) | + __SHIFTIN((uint32_t)nseg->attrib.def, DESC_B_MASK) | + __SHIFTIN((uint32_t)nseg->attrib.g, 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 qemu_vcpu *qcpu = get_qemu_vcpu(cpu); + struct nvmm_vcpu *vcpu = &qcpu->vcpu; + X86CPU *x86_cpu = X86_CPU(cpu); + struct nvmm_x64_state *state = vcpu->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, 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]; +#ifdef TARGET_X86_64 + 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]; +#endif + + /* 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_ES], &state->segs[NVMM_X64_SEG_ES]); + nvmm_get_segment(&env->segs[R_CS], &state->segs[NVMM_X64_SEG_CS]); + nvmm_get_segment(&env->segs[R_SS], &state->segs[NVMM_X64_SEG_SS]); + nvmm_get_segment(&env->segs[R_DS], &state->segs[NVMM_X64_SEG_DS]); + 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]); + + /* 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 != qcpu->tpr) { + qcpu->tpr = tpr; + cpu_set_apic_tpr(x86_cpu->apic_state, tpr); + } + env->xcr0 = state->crs[NVMM_X64_CR_XCR0]; + + /* Debug registers. */ + env->dr[0] = state->drs[NVMM_X64_DR_DR0]; + 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 < 16; 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_esp = state->msrs[NVMM_X64_MSR_SYSENTER_ESP]; + env->sysenter_eip = state->msrs[NVMM_X64_MSR_SYSENTER_EIP]; + env->pat = state->msrs[NVMM_X64_MSR_PAT]; + env->tsc = state->msrs[NVMM_X64_MSR_TSC]; + + x86_update_hflags(env); +} + +static bool +nvmm_can_take_int(CPUState *cpu) +{ + struct CPUX86State *env = (CPUArchState *)cpu->env_ptr; + struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu); + struct nvmm_vcpu *vcpu = &qcpu->vcpu; + struct nvmm_machine *mach = get_nvmm_mach(); + + if (qcpu->int_window_exit) { + return false; + } + + if (qcpu->int_shadow || !(env->eflags & IF_MASK)) { + struct nvmm_x64_state *state = vcpu->state; + + /* Exit on interrupt window. */ + nvmm_vcpu_getstate(mach, vcpu, NVMM_X64_STATE_INTR); + state->intr.int_window_exiting = 1; + nvmm_vcpu_setstate(mach, vcpu, NVMM_X64_STATE_INTR); + + return false; + } + + return true; +} + +static bool +nvmm_can_take_nmi(CPUState *cpu) +{ + struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu); + + /* + * Contrary to INTs, NMIs always schedule an exit when they are + * completed. Therefore, if window-exiting is enabled, it means + * NMIs are blocked. + */ + if (qcpu->nmi_window_exit) { + return false; + } + + return true; +} + +/* + * 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 qemu_vcpu *qcpu = get_qemu_vcpu(cpu); + struct nvmm_vcpu *vcpu = &qcpu->vcpu; + X86CPU *x86_cpu = X86_CPU(cpu); + struct nvmm_x64_state *state = vcpu->state; + struct nvmm_vcpu_event *event = vcpu->event; + bool has_event = false; + bool sync_tpr = false; + uint8_t tpr; + int ret; + + qemu_mutex_lock_iothread(); + + tpr = cpu_get_apic_tpr(x86_cpu->apic_state); + if (tpr != qcpu->tpr) { + qcpu->tpr = tpr; + sync_tpr = true; + } + + /* + * 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; + } + + if (!has_event && (cpu->interrupt_request & CPU_INTERRUPT_NMI)) { + if (nvmm_can_take_nmi(cpu)) { + cpu->interrupt_request &= ~CPU_INTERRUPT_NMI; + event->type = NVMM_VCPU_EVENT_INTR; + event->vector = 2; + has_event = true; + } + } + + if (!has_event && (cpu->interrupt_request & CPU_INTERRUPT_HARD)) { + if (nvmm_can_take_int(cpu)) { + cpu->interrupt_request &= ~CPU_INTERRUPT_HARD; + event->type = NVMM_VCPU_EVENT_INTR; + 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; + } + + if (sync_tpr) { + ret = nvmm_vcpu_getstate(mach, vcpu, NVMM_X64_STATE_CRS); + if (ret == -1) { + error_report("NVMM: Failed to get CPU state," + " error=%d", errno); + } + + state->crs[NVMM_X64_CR_CR8] = qcpu->tpr; + + ret = nvmm_vcpu_setstate(mach, vcpu, 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); + if (ret == -1) { + error_report("NVMM: Failed to inject event," + " error=%d", errno); + } + } + + qemu_mutex_unlock_iothread(); +} + +/* + * Called after the VCPU ran. We synchronize the host view of the TPR and + * RFLAGS. + */ +static void +nvmm_vcpu_post_run(CPUState *cpu, struct nvmm_vcpu_exit *exit) +{ + struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu); + struct CPUX86State *env = (CPUArchState *)cpu->env_ptr; + X86CPU *x86_cpu = X86_CPU(cpu); + uint64_t tpr; + + env->eflags = exit->exitstate.rflags; + qcpu->int_shadow = exit->exitstate.int_shadow; + qcpu->int_window_exit = exit->exitstate.int_window_exiting; + qcpu->nmi_window_exit = exit->exitstate.nmi_window_exiting; + + tpr = exit->exitstate.cr8; + if (qcpu->tpr != tpr) { + qcpu->tpr = tpr; + qemu_mutex_lock_iothread(); + cpu_set_apic_tpr(x86_cpu->apic_state, qcpu->tpr); + qemu_mutex_unlock_iothread(); + } +} + +/* -------------------------------------------------------------------------- */ + +static void +nvmm_io_callback(struct nvmm_io *io) +{ + MemTxAttrs attrs = { 0 }; + int ret; + + ret = address_space_rw(&address_space_io, io->port, attrs, io->data, + io->size, !io->in); + if (ret != MEMTX_OK) { + error_report("NVMM: I/O Transaction Failed " + "[%s, port=%u, size=%zu]", (io->in ? "in" : "out"), + io->port, io->size); + } + + /* Needed, otherwise infinite loop. */ + current_cpu->vcpu_dirty = false; +} + +static void +nvmm_mem_callback(struct nvmm_mem *mem) +{ + cpu_physical_memory_rw(mem->gpa, mem->data, mem->size, mem->write); + + /* XXX Needed, otherwise infinite loop. */ + current_cpu->vcpu_dirty = false; +} + +static struct nvmm_assist_callbacks nvmm_callbacks = { + .io = nvmm_io_callback, + .mem = nvmm_mem_callback +}; + +/* -------------------------------------------------------------------------- */ + +static int +nvmm_handle_mem(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu) +{ + int ret; + + ret = nvmm_assist_mem(mach, vcpu); + if (ret == -1) { + error_report("NVMM: Mem Assist Failed [gpa=%p]", + (void *)vcpu->exit->u.mem.gpa); + } + + return ret; +} + +static int +nvmm_handle_io(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu) +{ + int ret; + + ret = nvmm_assist_io(mach, vcpu); + if (ret == -1) { + error_report("NVMM: I/O Assist Failed [port=%d]", + (int)vcpu->exit->u.io.port); + } + + return ret; +} + +static int +nvmm_handle_rdmsr(struct nvmm_machine *mach, CPUState *cpu, + struct nvmm_vcpu_exit *exit) +{ + struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu); + struct nvmm_vcpu *vcpu = &qcpu->vcpu; + X86CPU *x86_cpu = X86_CPU(cpu); + struct nvmm_x64_state *state = vcpu->state; + uint64_t val; + int ret; + + switch (exit->u.rdmsr.msr) { + case MSR_IA32_APICBASE: + val = cpu_get_apic_base(x86_cpu->apic_state); + break; + case MSR_MTRRcap: + case MSR_MTRRdefType: + case MSR_MCG_CAP: + case MSR_MCG_STATUS: + val = 0; + break; + default: /* More MSRs to add? */ + val = 0; + error_report("NVMM: Unexpected RDMSR 0x%x, ignored", + exit->u.rdmsr.msr); + break; + } + + ret = nvmm_vcpu_getstate(mach, vcpu, NVMM_X64_STATE_GPRS); + if (ret == -1) { + return -1; + } + + state->gprs[NVMM_X64_GPR_RAX] = (val & 0xFFFFFFFF); + state->gprs[NVMM_X64_GPR_RDX] = (val >> 32); + state->gprs[NVMM_X64_GPR_RIP] = exit->u.rdmsr.npc; + + ret = nvmm_vcpu_setstate(mach, vcpu, NVMM_X64_STATE_GPRS); + if (ret == -1) { + return -1; + } + + return 0; +} + +static int +nvmm_handle_wrmsr(struct nvmm_machine *mach, CPUState *cpu, + struct nvmm_vcpu_exit *exit) +{ + struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu); + struct nvmm_vcpu *vcpu = &qcpu->vcpu; + X86CPU *x86_cpu = X86_CPU(cpu); + struct nvmm_x64_state *state = vcpu->state; + uint64_t val; + int ret; + + val = exit->u.wrmsr.val; + + switch (exit->u.wrmsr.msr) { + case MSR_IA32_APICBASE: + cpu_set_apic_base(x86_cpu->apic_state, val); + break; + case MSR_MTRRdefType: + case MSR_MCG_STATUS: + break; + default: /* More MSRs to add? */ + error_report("NVMM: Unexpected WRMSR 0x%x [val=0x%lx], ignored", + exit->u.wrmsr.msr, val); + break; + } + + ret = nvmm_vcpu_getstate(mach, vcpu, NVMM_X64_STATE_GPRS); + if (ret == -1) { + return -1; + } + + state->gprs[NVMM_X64_GPR_RIP] = exit->u.wrmsr.npc; + + ret = nvmm_vcpu_setstate(mach, vcpu, NVMM_X64_STATE_GPRS); + if (ret == -1) { + return -1; + } + + return 0; +} + +static int +nvmm_handle_halted(struct nvmm_machine *mach, CPUState *cpu, + struct nvmm_vcpu_exit *exit) +{ + 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_vcpu_event *event = vcpu->event; + + event->type = NVMM_VCPU_EVENT_EXCP; + event->vector = 6; + event->u.excp.error = 0; + + return nvmm_vcpu_inject(mach, vcpu); +} + +static int +nvmm_vcpu_loop(CPUState *cpu) +{ + struct CPUX86State *env = (CPUArchState *)cpu->env_ptr; + struct nvmm_machine *mach = get_nvmm_mach(); + struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu); + struct nvmm_vcpu *vcpu = &qcpu->vcpu; + X86CPU *x86_cpu = X86_CPU(cpu); + struct nvmm_vcpu_exit *exit = vcpu->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) { + nvmm_cpu_synchronize_state(cpu); + do_cpu_init(x86_cpu); + /* set int/nmi windows back to the reset state */ + } + 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) { + nvmm_cpu_synchronize_state(cpu); + do_cpu_sipi(x86_cpu); + } + if (cpu->interrupt_request & CPU_INTERRUPT_TPR) { + cpu->interrupt_request &= ~CPU_INTERRUPT_TPR; + nvmm_cpu_synchronize_state(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; + } + + if (qcpu->stop) { + cpu->exception_index = EXCP_INTERRUPT; + qcpu->stop = false; + ret = 1; + break; + } + + nvmm_vcpu_pre_run(cpu); + + if (atomic_read(&cpu->exit_request)) { + qemu_cpu_kick_self(); + } + + ret = nvmm_vcpu_run(mach, vcpu); + 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_VCPU_EXIT_NONE: + break; + case NVMM_VCPU_EXIT_MEMORY: + ret = nvmm_handle_mem(mach, vcpu); + break; + case NVMM_VCPU_EXIT_IO: + ret = nvmm_handle_io(mach, vcpu); + break; + case NVMM_VCPU_EXIT_INT_READY: + case NVMM_VCPU_EXIT_NMI_READY: + case NVMM_VCPU_EXIT_TPR_CHANGED: + break; + case NVMM_VCPU_EXIT_HALTED: + ret = nvmm_handle_halted(mach, cpu, exit); + break; + case NVMM_VCPU_EXIT_SHUTDOWN: + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + cpu->exception_index = EXCP_INTERRUPT; + ret = 1; + break; + case NVMM_VCPU_EXIT_RDMSR: + ret = nvmm_handle_rdmsr(mach, cpu, exit); + break; + case NVMM_VCPU_EXIT_WRMSR: + ret = nvmm_handle_wrmsr(mach, cpu, exit); + break; + case NVMM_VCPU_EXIT_MONITOR: + case NVMM_VCPU_EXIT_MWAIT: + ret = nvmm_inject_ud(mach, vcpu); + break; + default: + error_report("NVMM: Unexpected VM exit code 0x%lx [hw=0x%lx]", + exit->reason, exit->u.inv.hwcode); + 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; + +static void +nvmm_ipi_signal(int sigcpu) +{ + struct qemu_vcpu *qcpu; + + if (current_cpu) { + qcpu = get_qemu_vcpu(current_cpu); + qcpu->stop = true; + } +} + +static void +nvmm_init_cpu_signals(void) +{ + struct sigaction sigact; + sigset_t set; + + /* Install the IPI handler. */ + memset(&sigact, 0, sizeof(sigact)); + sigact.sa_handler = nvmm_ipi_signal; + sigaction(SIG_IPI, &sigact, NULL); + + /* Allow IPIs on the current thread. */ + sigprocmask(SIG_BLOCK, NULL, &set); + sigdelset(&set, SIG_IPI); + pthread_sigmask(SIG_SETMASK, &set, NULL); +} + +int +nvmm_init_vcpu(CPUState *cpu) +{ + struct nvmm_machine *mach = get_nvmm_mach(); + struct nvmm_vcpu_conf_cpuid cpuid; + struct nvmm_vcpu_conf_tpr tpr; + Error *local_error = NULL; + struct qemu_vcpu *qcpu; + int ret, err; + + nvmm_init_cpu_signals(); + + 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; + } + } + + qcpu = g_malloc0(sizeof(*qcpu)); + if (qcpu == NULL) { + error_report("NVMM: Failed to allocate VCPU context."); + return -ENOMEM; + } + + ret = nvmm_vcpu_create(mach, cpu->cpu_index, &qcpu->vcpu); + if (ret == -1) { + err = errno; + error_report("NVMM: Failed to create a virtual processor," + " error=%d", err); + g_free(qcpu); + return -err; + } + + memset(&cpuid, 0, sizeof(cpuid)); + cpuid.mask = 1; + cpuid.leaf = 0x00000001; + cpuid.u.mask.set.edx = CPUID_MCE | CPUID_MCA | CPUID_MTRR; + ret = nvmm_vcpu_configure(mach, &qcpu->vcpu, NVMM_VCPU_CONF_CPUID, + &cpuid); + if (ret == -1) { + err = errno; + error_report("NVMM: Failed to configure a virtual processor," + " error=%d", err); + g_free(qcpu); + return -err; + } + + ret = nvmm_vcpu_configure(mach, &qcpu->vcpu, NVMM_VCPU_CONF_CALLBACKS, + &nvmm_callbacks); + if (ret == -1) { + err = errno; + error_report("NVMM: Failed to configure a virtual processor," + " error=%d", err); + g_free(qcpu); + return -err; + } + + if (qemu_mach.cap.arch.vcpu_conf_support & NVMM_CAP_ARCH_VCPU_CONF_TPR) { + memset(&tpr, 0, sizeof(tpr)); + tpr.exit_changed = 1; + ret = nvmm_vcpu_configure(mach, &qcpu->vcpu, NVMM_VCPU_CONF_TPR, &tpr); + if (ret == -1) { + err = errno; + error_report("NVMM: Failed to configure a virtual processor," + " error=%d", err); + g_free(qcpu); + return -err; + } + } + + cpu->vcpu_dirty = true; + cpu->hax_vcpu = (struct hax_vcpu_state *)qcpu; + + 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 qemu_vcpu *qcpu = get_qemu_vcpu(cpu); + + nvmm_vcpu_destroy(mach, &qcpu->vcpu); + 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, prot; + + if (add) { + prot = PROT_READ | PROT_EXEC; + if (!rom) { + prot |= PROT_WRITE; + } + ret = nvmm_gpa_map(mach, hva, start_pa, size, prot); + } 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_ram_block_added(RAMBlockNotifier *n, void *host, size_t size) +{ + struct nvmm_machine *mach = get_nvmm_mach(); + uintptr_t hva = (uintptr_t)host; + int ret; + + ret = nvmm_hva_map(mach, hva, size); + + if (ret == -1) { + error_report("NVMM: Failed to map HVA, HostVA:%p " + "Size:%p bytes, error=%d", + (void *)hva, (void *)size, errno); + } +} + +static struct RAMBlockNotifier nvmm_ram_notifier = { + .ram_block_added = nvmm_ram_block_added +}; + +/* -------------------------------------------------------------------------- */ + +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_init(MachineState *ms) +{ + int ret, err; + + ret = nvmm_init(); + if (ret == -1) { + err = errno; + error_report("NVMM: Initialization failed, error=%d", errno); + return -err; + } + + ret = nvmm_capability(&qemu_mach.cap); + if (ret == -1) { + err = errno; + error_report("NVMM: Unable to fetch capability, error=%d", errno); + return -err; + } + if (qemu_mach.cap.version != 1) { + error_report("NVMM: Unsupported version %u", qemu_mach.cap.version); + return -EPROGMISMATCH; + } + if (qemu_mach.cap.state_size != sizeof(struct nvmm_x64_state)) { + error_report("NVMM: Wrong state size %u", qemu_mach.cap.state_size); + return -EPROGMISMATCH; + } + + ret = nvmm_machine_create(&qemu_mach.mach); + if (ret == -1) { + err = errno; + error_report("NVMM: Machine creation failed, error=%d", errno); + return -err; + } + + memory_listener_register(&nvmm_memory_listener, &address_space_memory); + ram_block_notifier_add(&nvmm_ram_notifier); + + 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); From patchwork Thu Feb 6 21:32:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Kamil Rytarowski X-Patchwork-Id: 11369293 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CE900109A for ; Thu, 6 Feb 2020 21:56:46 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 993AB214AF for ; Thu, 6 Feb 2020 21:56:46 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=gmx.net header.i=@gmx.net header.b="iR0Q0QqT" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 993AB214AF Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=gmx.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:46906 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1izp8f-000701-KX for patchwork-qemu-devel@patchwork.kernel.org; Thu, 06 Feb 2020 16:56:45 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:37968) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1izome-0000Q4-5d for qemu-devel@nongnu.org; Thu, 06 Feb 2020 16:34:01 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1izomc-0007ho-Ls for qemu-devel@nongnu.org; Thu, 06 Feb 2020 16:34:00 -0500 Received: from mout.gmx.net ([212.227.17.21]:41359) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1izomc-0007Zb-BT for qemu-devel@nongnu.org; Thu, 06 Feb 2020 16:33:58 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.net; s=badeba3b8450; t=1581024809; bh=VRV1PLovQkLA2qojKHfddY9U+AMu/FeCVYXqj8PmJxM=; h=X-UI-Sender-Class:From:To:Cc:Subject:Date:In-Reply-To:References; b=iR0Q0QqTYtX/XFK4+azsps5SYYtwkrgtyi2XIpmYxHD+bOVJOJEKF4Qk7kX0Z1hMf BDUGxtiiUJkQbYxoCA6BQrnY82zLvwTvfnsoKayMvT5xm8JTmfs5jK7NLEtVjQlytd VTBN0UaR1hliRxdYB3h84/nJ5TV/GXIHbpdi9tMo= X-UI-Sender-Class: 01bb95c1-4bf8-414a-932a-4f6e2808ef9c Received: from localhost.localdomain ([89.71.135.231]) by mail.gmx.com (mrgmx105 [212.227.17.174]) with ESMTPSA (Nemesis) id 1M3lYB-1j0dr803b1-000prB; Thu, 06 Feb 2020 22:33:29 +0100 From: Kamil Rytarowski To: rth@twiddle.net, ehabkost@redhat.com, slp@redhat.com, pbonzini@redhat.com, peter.maydell@linaro.org, philmd@redhat.com, max@m00nbsd.net, jmcneill@invisible.ca Subject: [PATCH v4 4/4] Add the NVMM acceleration enlightenments Date: Thu, 6 Feb 2020 22:32:32 +0100 Message-Id: <20200206213232.1918-5-n54@gmx.com> X-Mailer: git-send-email 2.25.0 In-Reply-To: <20200206213232.1918-1-n54@gmx.com> References: <20200206115731.13552-1-n54@gmx.com> <20200206213232.1918-1-n54@gmx.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:OdBHL44EfDbSDZKlcbBmW0xhsojvD2OKhQPP1npKozZsxRfPcF5 FSwhU6xtCyRgghT3HzLqj82ZF9qTnGPe/GZv00Lm/WgGbYUjO5ryEfhiF9vBIW2CO6w7ETC wMqZL1T9LBQXXwLh3Z0cxtcNHgU6te0Ye23GDMsfLsrNR9heCGIy+6X5qQ0Uwy40/ltaHvq KOMG5zqIdvlRYcd78Q6dg== X-UI-Out-Filterresults: notjunk:1;V03:K0:0ld6lYGcVUk=:ML9y4oRUTByKeYDHhBcnus P0/JTHpJ2jrYLpxH8VLlCXF6gYMXImKcGcpE+nDINAbZy0vowwVKvurX9enhfYFyEgFSpppzv gSFjAwz+SXOcBIZX+f1flJl3StacY64hzkEgRN4+iVr9b5uyd7w3kPdIxbIyeBW6xLCwxD0W5 0tBiVxKNNI/CO4/+FgvqDv4YzVnpNrtATYw2WFiv6FqnT3AcVHrQWQLKHhTE41I7PefupLj1N PyjBya9hsC396bMuGJ2B6CVwjBHP3ax/Q/zSCwYEM53upPSZRWMCmFk2vjVJ0Ls1XAl5CW+cm ei7k7LXw+HbxV+Aeljwk/+Rf9yVR0aEkiHMZui5m9/szTIZKgIKlLxx/qPjiPdkDP7OKMS/mt c1wDORBfGLhLLHT98DG+K4N4tGmGJ8g446xxfDuPwlbzTWCuYB/xQJZXlw0IXvKtJswIJrQrb kffWgiYAFlN1mVsm62ULyQRkpmTku1Umzx+35+GgSpRae0OZA3Jpa3jkfySm87LssiEMQ7vlU 24V6+XeuZ+zpRqUAZSr6swsAiqKY9YeET0L7V0MmqXtaj9pi2lYR67xQTXmi6+uPxZ7ZEAhO4 vSxvBtk5Ownjjiq+FJNk00SyeyOLKl70pxCeZLpazfy482S2Yk4JwnM6t7MvwJE5V3K5whaJb uSsqY+uES+WiCO+LDkyL+G2ZmV8eSOj8zZKhzuSy15/6NvnWtQLGuXjYrCnz/9eNVfwWkuGNf VU8lLudGMDDKrsuLClkTZio0K5Osq6sVGLGrDSitlK2jdsBFSa8qJBneAlMzkMb2QsxbfYgbD y3udzA1/lt4q8OP7pdIme2SF+fWrNkFemZPnjkjEbBdbQp7j79z5jI2HdcXbsTV28/yUQ6Gbt aS/xP5BTrOVruN9LAbZ31364b1qp3/n7hWL9sGvJ77AJp5EOEg3Q1WZ4PUjWRJ1VNSf2qJYDA jJKUSL8lWIEFcBvi/r/2DPTSFQ2L5tD9ctzjlhuAG6LhBU7AL2XHsGUldq+befEvmRWh3T0Wm nzIUuk9ZFHxkKt5VDKfWyqmrmA2Xi2EtXcFYQ1abW1DN33/NDRAxZQdUX7R7uEuPEfliCJWs4 5+EFqDl768cyMw09y95r3lEaP3I4JPCuHzJxa7f8a6p2+OSXFBwXbuXkqMo2C9Qy6ZCkczQ3b H5RFeXTlM8b0G1NuqTGH+Irwh/iY47NhKRFFQaLjN7y4Vc5fn3awLMFJ4NkuG2xZh9gVk= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 212.227.17.21 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kamil Rytarowski , qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" From: Maxime Villard Implements the NVMM accelerator cpu enlightenments to actually use the nvmm-all accelerator on NetBSD platforms. Signed-off-by: Maxime Villard Signed-off-by: Kamil Rytarowski Reviewed-by: Sergio Lopez Reviewed-by: Philippe Mathieu-Daudé Tested-by: Jared McNeill --- cpus.c | 58 +++++++++++++++++++++++++++++++++++++++ include/sysemu/hw_accel.h | 14 ++++++++++ target/i386/helper.c | 2 +- 3 files changed, 73 insertions(+), 1 deletion(-) -- 2.25.0 diff --git a/cpus.c b/cpus.c index b4f8b84b61..f833da4a60 100644 --- a/cpus.c +++ b/cpus.c @@ -42,6 +42,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" @@ -1670,6 +1671,48 @@ static void *qemu_whpx_cpu_thread_fn(void *arg) return NULL; } +static void *qemu_nvmm_cpu_thread_fn(void *arg) +{ + CPUState *cpu = arg; + int r; + + assert(nvmm_enabled()); + + 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); + } + } + qemu_wait_io_event(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) { @@ -2038,6 +2081,19 @@ static void qemu_whpx_start_vcpu(CPUState *cpu) #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]; @@ -2078,6 +2134,8 @@ void qemu_init_vcpu(CPUState *cpu) 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); } diff --git a/include/sysemu/hw_accel.h b/include/sysemu/hw_accel.h index 0ec2372477..dbfa7a02f9 100644 --- a/include/sysemu/hw_accel.h +++ b/include/sysemu/hw_accel.h @@ -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 @@ static inline void cpu_synchronize_state(CPUState *cpu) 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,10 @@ static inline void cpu_synchronize_post_reset(CPUState *cpu) 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 +61,9 @@ static inline void cpu_synchronize_post_init(CPUState *cpu) 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 +77,9 @@ static inline void cpu_synchronize_pre_loadvm(CPUState *cpu) if (whpx_enabled()) { whpx_cpu_synchronize_pre_loadvm(cpu); } + if (nvmm_enabled()) { + nvmm_cpu_synchronize_pre_loadvm(cpu); + } } #endif /* QEMU_HW_ACCEL_H */ diff --git a/target/i386/helper.c b/target/i386/helper.c index c3a6e4fabe..2e79d61329 100644 --- a/target/i386/helper.c +++ b/target/i386/helper.c @@ -981,7 +981,7 @@ void cpu_report_tpr_access(CPUX86State *env, TPRAccess access) X86CPU *cpu = env_archcpu(env); CPUState *cs = env_cpu(env); - if (kvm_enabled() || whpx_enabled()) { + if (kvm_enabled() || whpx_enabled() || nvmm_enabled()) { env->tpr_access_type = access; cpu_interrupt(cs, CPU_INTERRUPT_TPR);