From nobody Tue Jun  4 20:06:30 2024
X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1])
	by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4Vv1ng0kssz5MQ8C;
	Tue, 04 Jun 2024 20:06:31 +0000 (UTC)
	(envelope-from git@FreeBSD.org)
Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3])
	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
	 key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256
	 client-signature RSA-PSS (4096 bits) client-digest SHA256)
	(Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK))
	by mx1.freebsd.org (Postfix) with ESMTPS id 4Vv1nf6vz5z4fcp;
	Tue,  4 Jun 2024 20:06:30 +0000 (UTC)
	(envelope-from git@FreeBSD.org)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim;
	t=1717531591;
	h=from:from:reply-to:subject:subject:date:date:message-id:message-id:
	 to:to:cc:mime-version:mime-version:content-type:content-type:
	 content-transfer-encoding:content-transfer-encoding;
	bh=lhWDlSSg6Q6S7OoP2DI7Qq9dNRIx5AB2R4/omjPWnu4=;
	b=OtafCPhdH9mYPdrGTtHrtLumJQy6JUdzd8m3Kayj4mjqcAynUYccXs008+jksuG4MHVxkI
	rIgq58907Zhg7pToAosr2tA77wg8DcSC0/zUmqmZtmCoMAt4UXcNzWUtYoA95zbVU/GFIh
	ui+uTnBnu+InoCbMLq+HD6rYVQ1nx5zLzAjtluVTE+KJtjegANggcTudhdNhK39gitzbOC
	CfrYE8aE+eV+uOPElsYHTqluJhQnjHUahBtXXCgfKIF4IZADEeQXP3YCHS9claLqLqrKTb
	+zBDf7FPyFnejetPNkWBpi9EmPBbbQqq4bEmxTpsbrsZpu1dywZF+jye4Arkpw==
ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1717531591; a=rsa-sha256; cv=none;
	b=H/rZRc7maK6/1wkVq/v/qoQB36RVdKsCtv9hP8yL583tuA8REarsLERm/kMGWzCSRayPDb
	/5mK1evjiPpAglOF+MSF3DSItkpqmXkNzS9DDQ1M4I51IuGx6ud9dLUCHgxWmGuDA3CFvu
	Bv91ltN9wOsfB9qHIEWRZI6T3e/MG/7906SiRumJ0YXAjklorn/r1yC5qv7emil2hYuuOJ
	18DZ58QkdtnJGzJNgEGMpRov7oheukt4nGL8L+hHikDN170/j1Azz8gSEr82uJdgjJ1FyV
	Rru/86VrIJNDn6U7O7ipgA3SWogMNuGmnO5X4iQnh2/5N+akMBA4O27i8kevfw==
ARC-Authentication-Results: i=1;
	mx1.freebsd.org;
	none
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org;
	s=dkim; t=1717531591;
	h=from:from:reply-to:subject:subject:date:date:message-id:message-id:
	 to:to:cc:mime-version:mime-version:content-type:content-type:
	 content-transfer-encoding:content-transfer-encoding;
	bh=lhWDlSSg6Q6S7OoP2DI7Qq9dNRIx5AB2R4/omjPWnu4=;
	b=EHzsFSZ8GoBs6X0TRpPec64N5wn+FGkh+f1I4DLaoPPXXwYJsq7KpWTxc698wuziw2cPSL
	EO9I95nNCHUtjGkkMCCyDhjGSiZF1ZveR4TL0tMfRVX7yEmTTr2StQA7PSAA8ghhadk31l
	dfLWKf8PMk908YwM9FG73y3x/22BOiBTFpAfSBAgvEqm35QDEE58MgplfXds7p2aVUKvPU
	9Qk8mMH8DBppPC5aynxrVtPG6KxeQxkeZxRAuvvvF2onDnXCzM2qDRcC7qpGrAc7nE2Dbc
	y+bgqPhIpF872wdNCU+XXHB2q2F7IjsOWqvzAPAug82yjrUFZ+sjh4blvwIA+A==
Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5])
	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
	 key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256)
	(Client did not present a certificate)
	by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4Vv1nf6W58zXls;
	Tue,  4 Jun 2024 20:06:30 +0000 (UTC)
	(envelope-from git@FreeBSD.org)
Received: from gitrepo.freebsd.org ([127.0.1.44])
	by gitrepo.freebsd.org (8.17.1/8.17.1) with ESMTP id 454K6U3N075071;
	Tue, 4 Jun 2024 20:06:30 GMT
	(envelope-from git@gitrepo.freebsd.org)
Received: (from git@localhost)
	by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 454K6UG9075068;
	Tue, 4 Jun 2024 20:06:30 GMT
	(envelope-from git)
Date: Tue, 4 Jun 2024 20:06:30 GMT
Message-Id: <202406042006.454K6UG9075068@gitrepo.freebsd.org>
To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org,
        dev-commits-src-main@FreeBSD.org
From: Mark Johnston <markj@FreeBSD.org>
Subject: git: 75cb949228bb - main - arm64/vmm: Add breakpoint and
  single-stepping support
List-Id: Commit messages for the main branch of the src repository <dev-commits-src-main.freebsd.org>
List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main
List-Help: <mailto:dev-commits-src-main+help@freebsd.org>
List-Post: <mailto:dev-commits-src-main@freebsd.org>
List-Subscribe: <mailto:dev-commits-src-main+subscribe@freebsd.org>
List-Unsubscribe: <mailto:dev-commits-src-main+unsubscribe@freebsd.org>
X-BeenThere: dev-commits-src-main@freebsd.org
Sender: owner-dev-commits-src-main@FreeBSD.org
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
X-Git-Committer: markj
X-Git-Repository: src
X-Git-Refname: refs/heads/main
X-Git-Reftype: branch
X-Git-Commit: 75cb949228bb97e49f35fd2b2585293a6b9212aa
Auto-Submitted: auto-generated

The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=75cb949228bb97e49f35fd2b2585293a6b9212aa

commit 75cb949228bb97e49f35fd2b2585293a6b9212aa
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2024-06-04 18:58:08 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2024-06-04 18:58:08 +0000

    arm64/vmm: Add breakpoint and single-stepping support
    
    This will be used to implement parts of bhyve's gdb stub.
    
    Three VM capabilities are added, similar to amd64 without monitor mode.
    Two cause breakpoint and single-step exceptions to be raised to EL2 and
    then down to bhyve.  One lets the gdb stub mask hardware interrupts
    while single-stepping, since otherwise the guest will handle a timer
    interrupt before executing the target instruction and thus fail
    to make progress.
    
    Reviewed by:    bnovkov, andrew
    Sponsored by:   Innovate UK
    Differential Revision:  https://reviews.freebsd.org/D44739
---
 sys/arm64/include/vmm.h   |  6 +++-
 sys/arm64/vmm/arm64.h     |  9 ++++++
 sys/arm64/vmm/vmm_arm64.c | 79 +++++++++++++++++++++++++++++++++++++++++++++--
 sys/arm64/vmm/vmm_stat.c  |  2 ++
 sys/arm64/vmm/vmm_stat.h  |  2 ++
 5 files changed, 95 insertions(+), 3 deletions(-)

diff --git a/sys/arm64/include/vmm.h b/sys/arm64/include/vmm.h
index 8e2c9c868635..c06d2ad947e4 100644
--- a/sys/arm64/include/vmm.h
+++ b/sys/arm64/include/vmm.h
@@ -295,9 +295,11 @@ struct vre {
  */
 enum vm_cap_type {
 	VM_CAP_HALT_EXIT,
-	VM_CAP_MTRAP_EXIT,
 	VM_CAP_PAUSE_EXIT,
 	VM_CAP_UNRESTRICTED_GUEST,
+	VM_CAP_BRK_EXIT,
+	VM_CAP_SS_EXIT,
+	VM_CAP_MASK_HWINTR,
 	VM_CAP_MAX
 };
 
@@ -312,6 +314,8 @@ enum vm_exitcode {
 	VM_EXITCODE_PAGING,
 	VM_EXITCODE_SMCCC,
 	VM_EXITCODE_DEBUG,
+	VM_EXITCODE_BRK,
+	VM_EXITCODE_SS,
 	VM_EXITCODE_MAX
 };
 
diff --git a/sys/arm64/vmm/arm64.h b/sys/arm64/vmm/arm64.h
index 43459d14e143..8cfe77dcde6f 100644
--- a/sys/arm64/vmm/arm64.h
+++ b/sys/arm64/vmm/arm64.h
@@ -39,6 +39,9 @@
 struct vgic_v3;
 struct vgic_v3_cpu;
 
+/*
+ * Per-vCPU hypervisor state.
+ */
 struct hypctx {
 	struct trapframe tf;
 
@@ -104,6 +107,12 @@ struct hypctx {
 
 	struct vtimer_cpu 	vtimer_cpu;
 
+	uint64_t		setcaps;	/* Currently enabled capabilities. */
+
+	/* vCPU state used to handle guest debugging. */
+	uint64_t		debug_spsr;		/* Saved guest SPSR */
+	uint64_t		debug_mdscr;		/* Saved guest MDSCR */
+
 	struct vgic_v3_regs	vgic_v3_regs;
 	struct vgic_v3_cpu	*vgic_cpu;
 	bool			has_exception;
diff --git a/sys/arm64/vmm/vmm_arm64.c b/sys/arm64/vmm/vmm_arm64.c
index e71761f9ccef..e0547bcef914 100644
--- a/sys/arm64/vmm/vmm_arm64.c
+++ b/sys/arm64/vmm/vmm_arm64.c
@@ -700,7 +700,14 @@ handle_el1_sync_excp(struct hypctx *hypctx, struct vm_exit *vme_ret,
 		arm64_gen_reg_emul_data(esr_iss, vme_ret);
 		vme_ret->exitcode = VM_EXITCODE_REG_EMUL;
 		break;
-
+	case EXCP_BRK:
+		vmm_stat_incr(hypctx->vcpu, VMEXIT_BRK, 1);
+		vme_ret->exitcode = VM_EXITCODE_BRK;
+		break;
+	case EXCP_SOFTSTP_EL0:
+		vmm_stat_incr(hypctx->vcpu, VMEXIT_SS, 1);
+		vme_ret->exitcode = VM_EXITCODE_SS;
+		break;
 	case EXCP_INSN_ABORT_L:
 	case EXCP_DATA_ABORT_L:
 		vmm_stat_incr(hypctx->vcpu, esr_ec == EXCP_DATA_ABORT_L ?
@@ -1313,6 +1320,7 @@ vmmops_exception(void *vcpui, uint64_t esr, uint64_t far)
 int
 vmmops_getcap(void *vcpui, int num, int *retval)
 {
+	struct hypctx *hypctx = vcpui;
 	int ret;
 
 	ret = ENOENT;
@@ -1322,6 +1330,11 @@ vmmops_getcap(void *vcpui, int num, int *retval)
 		*retval = 1;
 		ret = 0;
 		break;
+	case VM_CAP_BRK_EXIT:
+	case VM_CAP_SS_EXIT:
+	case VM_CAP_MASK_HWINTR:
+		*retval = (hypctx->setcaps & (1ul << num)) != 0;
+		break;
 	default:
 		break;
 	}
@@ -1332,6 +1345,68 @@ vmmops_getcap(void *vcpui, int num, int *retval)
 int
 vmmops_setcap(void *vcpui, int num, int val)
 {
+	struct hypctx *hypctx = vcpui;
+	int ret;
+
+	ret = 0;
 
-	return (ENOENT);
+	switch (num) {
+	case VM_CAP_BRK_EXIT:
+		if ((val != 0) == (hypctx->setcaps & (1ul << num)) != 0)
+			break;
+		if (val != 0)
+			hypctx->mdcr_el2 |= MDCR_EL2_TDE;
+		else
+			hypctx->mdcr_el2 &= ~MDCR_EL2_TDE;
+		break;
+	case VM_CAP_SS_EXIT:
+		if ((val != 0) == (hypctx->setcaps & (1ul << num)) != 0)
+			break;
+
+		if (val != 0) {
+			hypctx->debug_spsr |= (hypctx->tf.tf_spsr & PSR_SS);
+			hypctx->debug_mdscr |= hypctx->mdscr_el1 &
+			    (MDSCR_SS | MDSCR_KDE);
+
+			hypctx->tf.tf_spsr |= PSR_SS;
+			hypctx->mdscr_el1 |= MDSCR_SS | MDSCR_KDE;
+			hypctx->mdcr_el2 |= MDCR_EL2_TDE;
+		} else {
+			hypctx->tf.tf_spsr &= ~PSR_SS;
+			hypctx->tf.tf_spsr |= hypctx->debug_spsr;
+			hypctx->debug_spsr &= ~PSR_SS;
+			hypctx->mdscr_el1 &= ~(MDSCR_SS | MDSCR_KDE);
+			hypctx->mdscr_el1 |= hypctx->debug_mdscr;
+			hypctx->debug_mdscr &= ~(MDSCR_SS | MDSCR_KDE);
+			hypctx->mdcr_el2 &= ~MDCR_EL2_TDE;
+		}
+		break;
+	case VM_CAP_MASK_HWINTR:
+		if ((val != 0) == (hypctx->setcaps & (1ul << num)) != 0)
+			break;
+
+		if (val != 0) {
+			hypctx->debug_spsr |= (hypctx->tf.tf_spsr &
+			    (PSR_I | PSR_F));
+			hypctx->tf.tf_spsr |= PSR_I | PSR_F;
+		} else {
+			hypctx->tf.tf_spsr &= ~(PSR_I | PSR_F);
+			hypctx->tf.tf_spsr |= (hypctx->debug_spsr &
+			    (PSR_I | PSR_F));
+			hypctx->debug_spsr &= ~(PSR_I | PSR_F);
+		}
+		break;
+	default:
+		ret = ENOENT;
+		break;
+	}
+
+	if (ret == 0) {
+		if (val == 0)
+			hypctx->setcaps &= ~(1ul << num);
+		else
+			hypctx->setcaps |= (1ul << num);
+	}
+
+	return (ret);
 }
diff --git a/sys/arm64/vmm/vmm_stat.c b/sys/arm64/vmm/vmm_stat.c
index 858ce980843a..05ece6f30579 100644
--- a/sys/arm64/vmm/vmm_stat.c
+++ b/sys/arm64/vmm/vmm_stat.c
@@ -161,5 +161,7 @@ VMM_STAT(VMEXIT_INSN_ABORT, "number of vmexits for an instruction abort");
 VMM_STAT(VMEXIT_UNHANDLED_SYNC, "number of vmexits for an unhandled synchronous exception");
 VMM_STAT(VMEXIT_IRQ, "number of vmexits for an irq");
 VMM_STAT(VMEXIT_FIQ, "number of vmexits for an interrupt");
+VMM_STAT(VMEXIT_BRK, "number of vmexits for a breakpoint exception");
+VMM_STAT(VMEXIT_SS, "number of vmexits for a single-step exception");
 VMM_STAT(VMEXIT_UNHANDLED_EL2, "number of vmexits for an unhandled EL2 exception");
 VMM_STAT(VMEXIT_UNHANDLED, "number of vmexits for an unhandled exception");
diff --git a/sys/arm64/vmm/vmm_stat.h b/sys/arm64/vmm/vmm_stat.h
index b0a06ef79253..402fa2f1b1e4 100644
--- a/sys/arm64/vmm/vmm_stat.h
+++ b/sys/arm64/vmm/vmm_stat.h
@@ -140,6 +140,8 @@ VMM_STAT_DECLARE(VMEXIT_INSN_ABORT);
 VMM_STAT_DECLARE(VMEXIT_UNHANDLED_SYNC);
 VMM_STAT_DECLARE(VMEXIT_IRQ);
 VMM_STAT_DECLARE(VMEXIT_FIQ);
+VMM_STAT_DECLARE(VMEXIT_BRK);
+VMM_STAT_DECLARE(VMEXIT_SS);
 VMM_STAT_DECLARE(VMEXIT_UNHANDLED_EL2);
 VMM_STAT_DECLARE(VMEXIT_UNHANDLED);
 #endif