git: a84653c5db25 - main - arm64: Don't enable interrupts when in a spinlock

From: Andrew Turner <andrew_at_FreeBSD.org>
Date: Thu, 24 Oct 2024 10:36:38 UTC
The branch main has been updated by andrew:

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

commit a84653c5db255bf28c19b64dd6ac20009ebcbce3
Author:     Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2024-10-24 09:52:37 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2024-10-24 10:20:48 +0000

    arm64: Don't enable interrupts when in a spinlock
    
    When we receive an exception while in a spinlock we shouldn't enable
    interrupts. When entering a spinlock we disable interrupts so enabling
    them here could cause surprising results.
    
    The three cases that could cause this are:
     1. A break-before-make sequence
     2. Accessing possibly unmapped code with a fault handler
     3. Buggy code
    
    1 and 2 are supported later in the data abort handler, and 3 should be
    fixed when found.
    
    Reviewed by:    mmel, kib, markj
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D46816
---
 sys/arm64/arm64/trap.c     | 12 ++++++++++--
 sys/arm64/include/armreg.h |  1 +
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/sys/arm64/arm64/trap.c b/sys/arm64/arm64/trap.c
index d6e316e7ae0a..544189964ef0 100644
--- a/sys/arm64/arm64/trap.c
+++ b/sys/arm64/arm64/trap.c
@@ -308,10 +308,18 @@ data_abort(struct thread *td, struct trapframe *frame, uint64_t esr,
 				break;
 			}
 		}
-		intr_enable();
+		if (td->td_md.md_spinlock_count == 0 &&
+		    (frame->tf_spsr & PSR_DAIF_INTR) != PSR_DAIF_INTR) {
+			MPASS((frame->tf_spsr & PSR_DAIF_INTR) == 0);
+			intr_enable();
+		}
 		map = kernel_map;
 	} else {
-		intr_enable();
+		if (td->td_md.md_spinlock_count == 0 &&
+		    (frame->tf_spsr & PSR_DAIF_INTR) != PSR_DAIF_INTR) {
+			MPASS((frame->tf_spsr & PSR_DAIF_INTR) == 0);
+			intr_enable();
+		}
 		map = &td->td_proc->p_vmspace->vm_map;
 		if (map == NULL)
 			map = kernel_map;
diff --git a/sys/arm64/include/armreg.h b/sys/arm64/include/armreg.h
index e26f9859947e..5e87fafbec31 100644
--- a/sys/arm64/include/armreg.h
+++ b/sys/arm64/include/armreg.h
@@ -2569,6 +2569,7 @@
 #define	PSR_DAIF	(PSR_D | PSR_A | PSR_I | PSR_F)
 /* The default DAIF mask. These bits are valid in spsr_el1 and daif */
 #define	PSR_DAIF_DEFAULT (0)
+#define	PSR_DAIF_INTR	(PSR_I | PSR_F)
 #define	PSR_BTYPE	0x00000c00UL
 #define	PSR_SSBS	0x00001000UL
 #define	PSR_ALLINT	0x00002000UL