From patchwork Tue Aug 11 13:01:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Kamil Rytarowski X-Patchwork-Id: 1343318 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=gmx.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; secure) header.d=gmx.net header.i=@gmx.net header.a=rsa-sha256 header.s=badeba3b8450 header.b=PgfsCV+L; dkim-atps=neutral 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 ozlabs.org (Postfix) with ESMTPS id 4BQtbk0H1bz9sTT for ; Tue, 11 Aug 2020 23:14:58 +1000 (AEST) Received: from localhost ([::1]:39822 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5U7D-0005pl-IS for incoming@patchwork.ozlabs.org; Tue, 11 Aug 2020 09:14:55 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45304) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5Tvp-00005T-NB for qemu-devel@nongnu.org; Tue, 11 Aug 2020 09:03:09 -0400 Received: from mout.gmx.net ([212.227.15.18]:38781) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5Tvj-0000v8-6t for qemu-devel@nongnu.org; Tue, 11 Aug 2020 09:03:09 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.net; s=badeba3b8450; t=1597150967; bh=UQC8hbt7Y63znu/ljFuJ4oYlMH3w497UZ5X8j02VolI=; h=X-UI-Sender-Class:From:To:Cc:Subject:Date:In-Reply-To:References; b=PgfsCV+LgzEuCZMbOQWoWMlQfddX652fsk3UO0AYILRbtwnAlDCZb6YAz6we7tZ0B XhFYV0UvBFuz8H8zcdGSOF+DDb82o5EO7xCPmcr+hfIPiCDazZOGKEVjlpbGsRSXkb cP2ikBJ+VvsotKH6d6dIns5g7+UQfRkCHThLAXm8= X-UI-Sender-Class: 01bb95c1-4bf8-414a-932a-4f6e2808ef9c Received: from localhost.localdomain ([89.79.191.25]) by mail.gmx.com (mrgmx004 [212.227.17.184]) with ESMTPSA (Nemesis) id 1MoO2E-1kTZGB0BAW-00on8q; Tue, 11 Aug 2020 15:02:47 +0200 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 v5 1/4] Add the NVMM vcpu API Date: Tue, 11 Aug 2020 15:01:50 +0200 Message-Id: <20200811130153.4948-1-n54@gmx.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200206213232.1918-2-n54@gmx.com> References: <20200206213232.1918-2-n54@gmx.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:FU/Bc3r7McX3ycozbLrXHSAtWOz3DLt96ut2qPnHS+A/wHcZeF3 tOYlloFxUG02zfj25s7Oaqzx3c5SXMZrBDZ6lKj0WgjCDuPMUkkxsKNCYLKsaqqIt22KTTi 8y3QuCvZmRMLD7ABvclj0c65MLYu4Azde3vgoxgZwoQRlsokdU+VhpMo1bI+JLEOL5XM9Wz N1UkKKftDkaldJ4bY2vYQ== X-UI-Out-Filterresults: notjunk:1;V03:K0:+6XTk8fVRTE=:4uv+Vz8132UryYHd/EITCT UDSPhJA/A41c8aAamjX9rHHe5ZnVra59vM9GqWtCXPzfxwnq2CaaqLIJlvDK6/ZEOhVei9/wl PZhSXotCgAsWEmm3s/x5TbC3VROqK+Vidh1tr9Dv8f4M+ch3NwLDi+9L8UDsQ8sPStg8wIK0l uS+AvAca1t2zbCjlH9n5WF2MKS1i7v9zJfpiHItaQEQCEFDb6kaJ6+jVkXm67E4H71f+Ta0ST LTVTzxeOpCEo2yLENPCoD/NI/ssO8YTXdQvwfEOAvcEpKi5H3BIs8qPgRzmBOBL6klmfXG8YB cekA+9fJjgPyL0a9Qb5q88G9T8cVSFeLq0KSCLyFZ7myxoOR/JSfPc66pdiHMJAadlji65p5E x0xxkQgi2yoozn6khHe5yQWIEE27BnctiWWD1wddE7MTaUiRnDPphxmLPMa4knvde6I1L9sCR a1tFIMtcipApfppZd/dDYv7ejXE59OJqqBVhPfxOo5Gw9LQCqXpLvRFE7P5uTM6NE+fPCrfvv xe82CnyNIaVY2N7IvRy1oaiqcsEMGdZdY0CVPPgi4GlxzadE+fEvmhA5P+3pLEE9vfU32v73m qFxyBQfynqvsW/8IWG/C8c+AHYFo+kk88h3E1C+H1f614AuTm694h6lMwCMOcRGlvUtVOAu10 8plA2Kj23RU+Xv45NZrxq3JMkuY+YI3gGK/5ozQtEnhhiBDQFmPBdIQiWUnMQAAStg1vxkrX5 uSLlY8iqzLjk655e2nF5wOYC33FSO6KvevTl1U1P0A7sf0absl1L7OfEdJshzrq6ns/5LH5uY dnGyt6qwPj9UXg2Oc0Zb4yvkkMkQGk1LctqjlXSul5nnS2G7UlBl7BNhgspDz5g31RjfLGkNC +1WOZuZi10JL6lBU9yk+xaU61bsZ/gl5JRKk9O0ecyuP9rpnIFy2xoUGaXpnIM4QklubLGfBX Q+jiEnv+RaCMiJrToUTxT4cRmv03hJuwqx7hTXRbAxeU3L7Z89MLEa0cC4D65CsqQS9CY37bx H3Q+Jvwz/26QlE0N0dtgfvWxH8iw7zzKMDwXGhnsmNXvUxvG0k5X38ADu9gugbZPZwPhuwU7N DY54LFm+4d4tkuF5d3vfU9Sm1Al/kOQGCTMrydzuM+Ar/kt6dNUD1BjWzrB+T0KshGNDj8PTm EWK53YrlKbk4W5y00xgEt5fsGfQ5iAZdtAKlSVXZAjB9E78HGcXnhWccjWlRNIm4pahNX1SxK bO56TrWnmMpczVuBt Received-SPF: pass client-ip=212.227.15.18; envelope-from=n54@gmx.com; helo=mout.gmx.net X-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/11 09:02:59 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] X-Spam_score_int: -32 X-Spam_score: -3.3 X-Spam_bar: --- X-Spam_report: (-3.3 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H2=-1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Tue, 11 Aug 2020 09:13:32 -0400 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+incoming=patchwork.ozlabs.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.28.0 diff --git a/accel/stubs/Makefile.objs b/accel/stubs/Makefile.objs index bbd14e71fb..38660a0b9b 100644 --- a/accel/stubs/Makefile.objs +++ b/accel/stubs/Makefile.objs @@ -1,6 +1,7 @@ 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 obj-$(call lnot,$(CONFIG_XEN)) += xen-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 Tue Aug 11 13:01:51 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Kamil Rytarowski X-Patchwork-Id: 1343324 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=gmx.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; secure) header.d=gmx.net header.i=@gmx.net header.a=rsa-sha256 header.s=badeba3b8450 header.b=K7DEz6FR; dkim-atps=neutral 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 ozlabs.org (Postfix) with ESMTPS id 4BQtq35WMWz9sTM for ; Tue, 11 Aug 2020 23:24:47 +1000 (AEST) Received: from localhost ([::1]:50244 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5UGj-0002BE-0n for incoming@patchwork.ozlabs.org; Tue, 11 Aug 2020 09:24:45 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45358) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5Tw2-00009H-VH for qemu-devel@nongnu.org; Tue, 11 Aug 2020 09:03:22 -0400 Received: from mout.gmx.net ([212.227.15.18]:53981) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5Tw0-0000wY-MH for qemu-devel@nongnu.org; Tue, 11 Aug 2020 09:03:22 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.net; s=badeba3b8450; t=1597150993; bh=ZKmjV+nVw1aJ6gZD2QzOEI785zynAMn0St417dViqGo=; h=X-UI-Sender-Class:From:To:Cc:Subject:Date:In-Reply-To:References; b=K7DEz6FRRd0Tq/ninwHrZLaPLNnIPIlWmu3hS0ZPt+TmLy1EZL+paj9dp2gOyduOg t006qn60SMG6wB3k7lm6VuOjsNE/W163DeDYhZhpuwWEL9zqoiNsxS8si47N4UyPjZ pv2W4yAZkcGqA9njnXsA0n9mFxgrwEGf1czWIPFA= X-UI-Sender-Class: 01bb95c1-4bf8-414a-932a-4f6e2808ef9c Received: from localhost.localdomain ([89.79.191.25]) by mail.gmx.com (mrgmx004 [212.227.17.184]) with ESMTPSA (Nemesis) id 1Msq2E-1kyQ2L0Ehc-00tCye; Tue, 11 Aug 2020 15:03:13 +0200 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 v5 2/4] Add the NetBSD Virtual Machine Monitor accelerator. Date: Tue, 11 Aug 2020 15:01:51 +0200 Message-Id: <20200811130153.4948-2-n54@gmx.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200811130153.4948-1-n54@gmx.com> References: <20200206213232.1918-2-n54@gmx.com> <20200811130153.4948-1-n54@gmx.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:5BOdXnJPvmwV9SRxtIJqAsCk02FdnU78VuEDhPMPTzqvSqJE9m7 aSv9Rao6GL44in2noDbfJ1NJYcKBVNst1EiwJmgLkI8EnYrgTj6+ar5Jfap1VSwZgVqYe8D LRfbmF+ZQrH+00iU04kh5i3evY6/UVTQK8+UvZ6i0PpsVQxVl7t1y6uLkFh4lsU1HiPHZjr 3w/ko9rgAU5EV2i90l6TQ== X-UI-Out-Filterresults: notjunk:1;V03:K0:zTsCPHH0A/w=:gpbtEZcTVwURgt8FqFW8ZF ed+wTOvWEwUbRQEKsPpCZCejzfwlJjI/Ox5eW+z4h5+I3Nw9T6urBIUHfsLfcIdSz2Qr5mEu2 UG+FocTsFj2CdpgWI6Wr546AvV/Fy8k1pwUQEG1sk21a/qOynMTLxoBFjjdhZPAPS9UGmWtOK fdRjSry2apP/dRFjaeHmV7AiePYT4LHgdISlC1PBCl8/lpfFT8/FP9uTVZHkKMv0ZNgGTl0i0 +EPpa+JBpizxSiNLD9dqHfcVjBKh5GzrUKVEsu0v1cWjk+qG49T43fmSZD6PtOJP7zs2C8Oif msGKU1lXaqbNANogwDDRDVVhEkJC9CqnHNh9/ne0b++jsnsb6Ap1f3lJ/TljoA7W1kJndkd9l PN6vCib5POGsheWHP3TW7UgIyTDvsGyiHLgjgHI2+QO4XAWaRu68gfwhk3heqIZzZgIBSbDEZ NCk+63rnOc8v7GIKSVrBLETmxHkMN6D4V6fN1L/jQ6rbHvkMvIudBlPZ8Iwo613BsVD45oPsT zoXY3I6IKtbWtNjrDDUJfZZYD8UNI1cUcF8o78U8gAPGx1xCPxpCLPP+9f1EgIhfOKX8VN7wl D2Di5PwNSumx8EwOsvWZgFiFiAUglpPZLY+F5ReAosQwYQQ5S5/9z9uJLV9ARTscIOOyInBnH F5tCOEOS7KQzBJ8HVUqvh2qeBX3DIaUITT4KAp3eFHxzqFZ0TvNtoly5psg/bnr9Oi/Gbhw9F 93Mkp49cN6Lz2KICteSfOHik8/mi5Pl+UUiyTp2dDrSipeA6F/IzJ+miRq4IAo1S9D+MxrbU4 slGZB3bLXXmEcCf+8rO6EClMSnB4fH8K5AdVOL3GFzc1VsIGnMfj7H5vgPJRQh8XmQjhFTvXI QNNtW6ddgFvUTtNpTKk5n5Wn7Ym++3/KFy0ST4beoy6nKbPVonT1U/a+ZAtIWv06pN5ycRROt lVwqBl6AdTGg1vWHaTEUy+JYDiRBcqJx/FtzaxoCzn5sfUDyV7cAByXghxh2UUdniiwU87pYa NqZVQehKqEFLFl0KMzT6kQZtEO7UdBKi9cqpMKX0uiy8norRpyNX+MUyIJEBdLbGvt4eUybMw n4GxhIfdy51U1rKt82sb+AdjUJLBfNExRfclrGUE+ocGJYoDuO772KsB9ocY6gjmZ/WstNi5j xLIOZ/E4zQ/B+o0qGN0FSf8FlySnShu3b/Njoqrcz9W87LjIOgwSDcZ1HNQiA92BAFQ4BrlA7 x2AgQ/fpF40454+z4UOYF+dqGaG2YFzNnLAHyVrPr6U6Hs79Jk8KcIB+yqOz5z6iCs/aKODV+ edftvSuawVn2l25skbTKtHoqfuN4e1czrCVbLZIgp3QFOkBuzAU4DwLHkw6h8cgfc8t/n+iJE ZH4ejKxE9Dqf2podvTefRWcXbGzBBIf8U/9j0v6So8FEzWOTtCeszZhZ++636Q1wAk4E0DqL3 7eYzrZYv9D7OA2jw6AcqWHuI/LjJqCR+TAT2Rl4+KqR3uubOBHmjYi/7Uhq8lpkg8FN1rOuX4 mAkF5TSaFjKNjnT08viIzykQ= Received-SPF: pass client-ip=212.227.15.18; envelope-from=n54@gmx.com; helo=mout.gmx.net X-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/11 09:02:59 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] X-Spam_score_int: -32 X-Spam_score: -3.3 X-Spam_bar: --- X-Spam_report: (-3.3 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H2=-1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Tue, 11 Aug 2020 09:13:33 -0400 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+incoming=patchwork.ozlabs.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 | 10 +++++----- 2 files changed, 42 insertions(+), 5 deletions(-) -- 2.28.0 diff --git a/configure b/configure index 2acc4d1465..fb9ffba2bf 100755 --- a/configure +++ b/configure @@ -246,6 +246,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) @@ -273,6 +284,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 } @@ -395,6 +407,7 @@ kvm="no" hax="no" hvf="no" whpx="no" +nvmm="no" rdma="" pvrdma="" gprof="no" @@ -847,6 +860,7 @@ DragonFly) NetBSD) bsd="yes" hax="yes" + nvmm="yes" make="${MAKE-gmake}" audio_drv_list="oss try-sdl" audio_possible_drivers="oss sdl" @@ -1233,6 +1247,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" @@ -1879,6 +1897,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 @@ -2965,6 +2984,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 @@ -6934,6 +6967,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" @@ -8332,6 +8366,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 708583b4ce..697accaa7e 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -26,7 +26,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" @@ -58,7 +58,7 @@ SRST ``accel=accels1[:accels2[:...]]`` This is used to enable an accelerator. Depending on the target - architecture, kvm, xen, hax, hvf, whpx or tcg can be available. + architecture, 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. @@ -119,7 +119,7 @@ ERST 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" @@ -128,8 +128,8 @@ DEF("accel", HAS_ARG, QEMU_OPTION_accel, SRST ``-accel name[,prop=value[,...]]`` 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 + architecture, 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. From patchwork Tue Aug 11 13:01:52 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kamil Rytarowski X-Patchwork-Id: 1343322 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=gmx.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; secure) header.d=gmx.net header.i=@gmx.net header.a=rsa-sha256 header.s=badeba3b8450 header.b=HS90rcj9; dkim-atps=neutral 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 ozlabs.org (Postfix) with ESMTPS id 4BQtjV6zBYz9sR4 for ; Tue, 11 Aug 2020 23:19:57 +1000 (AEST) Received: from localhost ([::1]:47496 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5UC1-0000nX-8h for incoming@patchwork.ozlabs.org; Tue, 11 Aug 2020 09:19:53 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45506) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5TwO-0000Aw-Uh for qemu-devel@nongnu.org; Tue, 11 Aug 2020 09:03:44 -0400 Received: from mout.gmx.net ([212.227.15.18]:52061) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5TwJ-0000ys-4M for qemu-devel@nongnu.org; Tue, 11 Aug 2020 09:03:44 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.net; s=badeba3b8450; t=1597150999; bh=aUBrCx4sXxdG+1ILPPgPFZrC8Y73fTamyWqAlWMdfPo=; h=X-UI-Sender-Class:From:To:Cc:Subject:Date:In-Reply-To:References; b=HS90rcj9oT+iXe6snxtwvVO3n/RL+H2jx/MuYWwGykSAZqPpyLYKxXTfj34+mHOCA 8n+mrI9lsRzNIwmsPA5kq3TvnwXEhGtIfqeF9iPojfNk9ZNpTnTLVoCLCln6TlMBUd UkfY4nbzXyTDreDPTUIyCxDvM/elE/Vp90KfNkQo= X-UI-Sender-Class: 01bb95c1-4bf8-414a-932a-4f6e2808ef9c Received: from localhost.localdomain ([89.79.191.25]) by mail.gmx.com (mrgmx004 [212.227.17.184]) with ESMTPSA (Nemesis) id 1MRCK6-1kJpQ21tES-00NC9E; Tue, 11 Aug 2020 15:03:18 +0200 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 v5 3/4] Introduce the NVMM impl Date: Tue, 11 Aug 2020 15:01:52 +0200 Message-Id: <20200811130153.4948-3-n54@gmx.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200811130153.4948-1-n54@gmx.com> References: <20200206213232.1918-2-n54@gmx.com> <20200811130153.4948-1-n54@gmx.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:+m6HwbGsfFo2znSzod9CGx/QmClrzhbqtHWv9u69nBIoxj9F4B9 rcKPMf3pG3NRR7/HjxOZp9aUd7YjJifHWlExZP7Pf5EvU7JZos9F1DUyxC/UKeKxC0f6EtU /mQJTt2LOtHG2DG4CntlOPnE2g+WK92nqLuhkl6b8pFV85nSn/S+6SONcIVoectbGbsXzvg IGVLrJUI9uqfKZYEcyeLg== X-UI-Out-Filterresults: notjunk:1;V03:K0:ssAOMXb2L2g=:GkvDdyUTGwDp2m7a+7JYej +zFcsobbFRfY/rPH18CV3D1ogzCvxvy0W5J6IhmUq5GFTMdKMuP9tbSsIfGm6AExVlgBo3TG4 TI2xfaeoSw9D5xJV7n/QDQZAXfaW1qODj1rs6XLJIjUlpWuayqX5dgBuIc0gONXr9YBZTbQ9D MGzRmgrjEjj+zwrvtXyzMy87CpgJtTjmv1U5eQV8gSUfXLWILI/uPt+YRiK6vg6YtWZ3dCOq4 ulkgEXVTsn5IH+UVk7gVLn7+PRu0B5NLYXbzPh6i8yg66bgZi2rG1J6ZHupR5Y8hFMBf90Be/ bTfmSJzTAsGyfikff0yE/lJO4XEypgU9rir9OcPXiriWR9Uy4Ez94PnLiJOzBRMvXGBre5qnE OyIrZMfmmTE1cAJQWqg/Tpt3EpaX9CxCjVJQQJ4dlAeVSFwEL/3t0dNIITPcCN9p6OwmH0NMY jmXryRyE5ntbY/Mj73R0+yzM53SWwk4NXrZLePOgcMt3uzyWWidZu+eX2sU4+zLtN+JEJUXRW u4goVhmiUTHyMK3QtC1iYvU25jT0DuG/nGipy8ErifL7qEQEm9STcmH1jDoC3xbVXWy0x5I3E gdqclY+Hi/L4N4ojoeoy6HT8zg1x0ftuIQvElZt6N4DJUZn3GCphT1tOXUJZWxc8dE5tD/sQv O0gexdt+gTPZZvKC2uSQsL2WaoITfBbH01jTVW74kj7+7a5ZCTlyeZBNgIuAiFvwAdMxqTx4v 6a1UeA+2ChNkO5ciC0DC8hL5XhTiB/TQOxPSm6kXgopvGrajl74/nave4GUkQLC7bSCpyJ8bT Qy0+LORBl79i+xo3Ej/raxPg+93zaxBUIm5o1b2B+ApVY+BrCqhs+PT1YlQpdm8sXaFIOlSPB F5Me/+szGGUK0DeN7cH6TdieKZhxSaD9dF7T96+p357FN5rWxsT7qRxUawiWCf0ZXJUq9nDeA 15GtRQFPgRkdfB4K5ZU0aOo0T+jftMkp7guP8E+w96pq+JpItBpBonJxR7dx8DaLOh5x1ZSpG ihA44sFHDlS0MLtke9DL6TRGvDJTiQPi6SBaibhAmFaAHdz8nqKd7CSHtYK7wLZwo0VmEXLon Jdl8mnuXeri7BtRPTiMLQki5xACXdoUgrwBnbFOGZH8C8tctgUEBjfm41pWuxfK/3WGzrgUP4 zy98e4PcDWYg+ng0aaWqMDiMVt+Jf2B8xbKyBhonyxnqPAOhQ3Zp+c+EDmAeJx/YC1vv6GR3q J8y47J7u51A2gmx8Q Received-SPF: pass client-ip=212.227.15.18; envelope-from=n54@gmx.com; helo=mout.gmx.net X-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/11 09:02:59 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] X-Spam_score_int: -32 X-Spam_score: -3.3 X-Spam_bar: --- X-Spam_report: (-3.3 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H2=-1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Tue, 11 Aug 2020 09:13:33 -0400 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+incoming=patchwork.ozlabs.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.28.0 diff --git a/target/i386/Makefile.objs b/target/i386/Makefile.objs index 0b93143e27..ff0df68404 100644 --- a/target/i386/Makefile.objs +++ b/target/i386/Makefile.objs @@ -18,6 +18,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..408f7305b9 --- /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 != NVMM_KERN_VERSION) { + 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 Tue Aug 11 13:01:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Kamil Rytarowski X-Patchwork-Id: 1343325 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=gmx.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; secure) header.d=gmx.net header.i=@gmx.net header.a=rsa-sha256 header.s=badeba3b8450 header.b=EMB+I8Xo; dkim-atps=neutral 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 ozlabs.org (Postfix) with ESMTPS id 4BQtwt3G83z9sTR for ; Tue, 11 Aug 2020 23:29:50 +1000 (AEST) Received: from localhost ([::1]:53402 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5ULb-0003iF-NS for incoming@patchwork.ozlabs.org; Tue, 11 Aug 2020 09:29:47 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45576) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5Twa-0000D9-28 for qemu-devel@nongnu.org; Tue, 11 Aug 2020 09:03:56 -0400 Received: from mout.gmx.net ([212.227.15.18]:49625) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5TwX-0000zu-PU for qemu-devel@nongnu.org; Tue, 11 Aug 2020 09:03:55 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.net; s=badeba3b8450; t=1597151022; bh=ZQ0DzVPA2iYTtjlzNojomsX+j/smyo/M5PvfBoj6A6E=; h=X-UI-Sender-Class:From:To:Cc:Subject:Date:In-Reply-To:References; b=EMB+I8XoKO6BKAS2cydc2csaj6Dx60Wcd+dpvaMG8mQGiBxzTSk/g0Aup7sWSWgpc 2Wny0L4bZ3yft60yUkwk6CqHlFSnTtr+dAYizAjchpG8sIRl8KzCOCaiqlysXdrEaw BmNOErkWM2fabTAjEkuVtiWJqQpedwMtJziwh+hc= X-UI-Sender-Class: 01bb95c1-4bf8-414a-932a-4f6e2808ef9c Received: from localhost.localdomain ([89.79.191.25]) by mail.gmx.com (mrgmx004 [212.227.17.184]) with ESMTPSA (Nemesis) id 1M2f9h-1k8VXd1LeJ-0047rT; Tue, 11 Aug 2020 15:03:42 +0200 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 v5 4/4] Add the NVMM acceleration enlightenments Date: Tue, 11 Aug 2020 15:01:53 +0200 Message-Id: <20200811130153.4948-4-n54@gmx.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200811130153.4948-1-n54@gmx.com> References: <20200206213232.1918-2-n54@gmx.com> <20200811130153.4948-1-n54@gmx.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:1m28CIjQ2yDBd7qC9MzSu3rPFL1yw0FCIsPwv899SpJW+YIpFU2 dKUxso9VtUFBJxqtaxtPchxtJyBaph3O6GdoZ6eYtf9pl7g+34iix4b5nj5lznEzPCEAwpr 86gOirZcnJKk3m2U4tcPGpTnFLhnSx7BfD/J+OcIHMQN9b4JRZG+WM5iWH61KJpMJ0FNAW6 rrpq1ZH6p67ioku/utPIQ== X-UI-Out-Filterresults: notjunk:1;V03:K0:i7L5jsnifqI=:fKC8Nb4d4hUq/WI9x3zY76 E8eg3m8Qupv2zKl5pgkoXWk1L4qw9h6F19mDvhXho66PiYwOTk/wrMwDAHOqkbQmw48dwf7u1 sB4MvnE/c9BVWJcJWHt+y9SqZ2hBo2yRMXU9vora3DgYE6vL4m+aLkgt+dLzbjgPHzdLAtMkj fXQCA/cX3koZhkKtOtQlz9m2xp1++dyuleCghDN0inSAaF2BWnQAzkQ847hl6W4shmOFRjn2T EDZR5Vb1yUMF9eZtRgVaU8Ak/+lbR8DhSRcAo38WJz3TVtkW51qNB/ZPOb6FmLS6936yef5j8 5Da2At2nSg3mUqWTNN/Y5pJ2XoE6IP5GOi3pLz535mwP6PF+grszgwoy7lmLFWZBn1rBmxr0r WmshQ9RfSFr9d743nk7qbaka2tnKPnfab5UqrYKg237P7xcHSFJ0nJUUUEGQ/uqTiw0Qds+9i DbC6gZ6+CxedDVbLCnUEF1i7FzJUOgW8nHi5APeSf1liiyOpr7t3fc50ViXbKzKHntNf7tDI2 Xs8Mz/TTf14aGioTL8tp6ZaiRys9L0k8XFnGdPKDh6EvYIyMDJouF3pF9qZ+bi0KuyWtHfiGR 78B9OO+oAItAu9SFHZC51VHPloxi8q69pXf92Wf7nVWeIp6Y75O35yey0J10YmCqIBlu7KufV 9jOXnJHlgX+KXFx4hiJier/UQBjGJaolBApAquD837ZpOHKqDLHuPo9SuY3yU5UkG+x6ZS5qS ubZCweImMrA5iNvmqJAGcPz/Rr/dZ8TM2etYF4LK1/+YrNdLujKca+al9zSTMAVyj41+LvJ4j RM9SDgC7O60tiyMRkWrUS/yk5G7MfkZKl++qRjfzdkrjtBYACKSV5wLiRqtpd6LPDjNxWFeR0 rnjO/PO3w/6xtMNUhAdADl/co9CDWVYuVpHbXT0Ma+GSvTC9DbgGupKQh5mx8NsBKt6Ll0aAO 5B//ZrFK8NmODApoqiAkbAF1bc+vtnW1jjuDpBQoT23We2+pFnfebjVtKxYmO73Q2QQHe2/I1 tKXRgoeVN47jnzkmCZctHJLUT8iTE9WP2fy5MGD/UamIOgJ8f30YLomEsVK1oVC6rBGg+aUt+ zMhr71rz77C5/JYfzOVMlOMf5BR1zHWRZbuqr80ll8PlF3/HZHUPUvgi79A8ixASgolzXjrGa CiG8czbOOoCn3WL1BzBUXXs6r+CvjRlO+9FIh/pciks91BMBELK3DMU28aHtwXfHhan0kJKxU 44ugDZozkRk35+T2R Received-SPF: pass client-ip=212.227.15.18; envelope-from=n54@gmx.com; helo=mout.gmx.net X-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/11 09:02:59 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] X-Spam_score_int: -32 X-Spam_score: -3.3 X-Spam_bar: --- X-Spam_report: (-3.3 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H2=-1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Tue, 11 Aug 2020 09:13:33 -0400 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+incoming=patchwork.ozlabs.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 --- include/sysemu/hw_accel.h | 14 ++++++++++ softmmu/cpus.c | 58 +++++++++++++++++++++++++++++++++++++++ target/i386/helper.c | 2 +- 3 files changed, 73 insertions(+), 1 deletion(-) -- 2.28.0 diff --git a/include/sysemu/hw_accel.h b/include/sysemu/hw_accel.h index e128f8b06b..9e19f5794c 100644 --- a/include/sysemu/hw_accel.h +++ b/include/sysemu/hw_accel.h @@ -16,6 +16,7 @@ #include "sysemu/kvm.h" #include "sysemu/hvf.h" #include "sysemu/whpx.h" +#include "sysemu/nvmm.h" static inline void cpu_synchronize_state(CPUState *cpu) { @@ -31,6 +32,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) @@ -47,6 +51,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) @@ -63,6 +71,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) @@ -79,6 +90,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/softmmu/cpus.c b/softmmu/cpus.c index a802e899ab..3b44b92830 100644 --- a/softmmu/cpus.c +++ b/softmmu/cpus.c @@ -43,6 +43,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" @@ -1621,6 +1622,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) { @@ -1998,6 +2041,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]; @@ -2038,6 +2094,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/target/i386/helper.c b/target/i386/helper.c index 70be53e2c3..c2f1aef65c 100644 --- a/target/i386/helper.c +++ b/target/i386/helper.c @@ -983,7 +983,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);