git: 06faad1de2c9 - main - dtrace: handle page faults in riscv dtrace_trap()

From: Mitchell Horne <mhorne_at_FreeBSD.org>
Date: Mon, 06 Feb 2023 19:28:07 UTC
The branch main has been updated by mhorne:

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

commit 06faad1de2c9aadcfd606d5f7121b201dbfbaa9d
Author:     Mitchell Horne <mhorne@FreeBSD.org>
AuthorDate: 2023-02-06 18:08:35 +0000
Commit:     Mitchell Horne <mhorne@FreeBSD.org>
CommitDate: 2023-02-06 19:26:53 +0000

    dtrace: handle page faults in riscv dtrace_trap()
    
    We must detect the correct amount to increment sepc, as it may have been
    a compressed instruction that triggered the fault.
    
    Reviewed by:    markj
    MFC after:      1 week
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D38299
---
 sys/cddl/dev/dtrace/riscv/dtrace_subr.c | 21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/sys/cddl/dev/dtrace/riscv/dtrace_subr.c b/sys/cddl/dev/dtrace/riscv/dtrace_subr.c
index 1e24a88f6c75..f32bb3a2343e 100644
--- a/sys/cddl/dev/dtrace/riscv/dtrace_subr.c
+++ b/sys/cddl/dev/dtrace/riscv/dtrace_subr.c
@@ -63,6 +63,8 @@ typedef struct dtrace_invop_hdlr {
 
 dtrace_invop_hdlr_t *dtrace_invop_hdlr;
 
+static int match_opcode(uint32_t insn, int match, int mask);
+
 int
 dtrace_invop(uintptr_t addr, struct trapframe *frame)
 {
@@ -188,6 +190,8 @@ dtrace_gethrestime(void)
 int
 dtrace_trap(struct trapframe *frame, u_int type)
 {
+	uint16_t insn;
+
 	/*
 	 * A trap can occur while DTrace executes a probe. Before
 	 * executing the probe, DTrace blocks re-scheduling and sets
@@ -196,9 +200,7 @@ dtrace_trap(struct trapframe *frame, u_int type)
 	 * flag is cleared and finally re-scheduling is enabled.
 	 *
 	 * Check if DTrace has enabled 'no-fault' mode:
-	 *
 	 */
-
 	if ((cpu_core[curcpu].cpuc_dtrace_flags & CPU_DTRACE_NOFAULT) != 0) {
 		/*
 		 * There are only a couple of trap types that are expected.
@@ -208,15 +210,24 @@ dtrace_trap(struct trapframe *frame, u_int type)
 		case SCAUSE_LOAD_ACCESS_FAULT:
 		case SCAUSE_STORE_ACCESS_FAULT:
 		case SCAUSE_INST_ACCESS_FAULT:
+		case SCAUSE_INST_PAGE_FAULT:
+		case SCAUSE_LOAD_PAGE_FAULT:
+		case SCAUSE_STORE_PAGE_FAULT:
 			/* Flag a bad address. */
 			cpu_core[curcpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR;
-			cpu_core[curcpu].cpuc_dtrace_illval = 0;
+			cpu_core[curcpu].cpuc_dtrace_illval = frame->tf_stval;
 
 			/*
 			 * Offset the instruction pointer to the instruction
-			 * following the one causing the fault.
+			 * following the one causing the fault. Check if the
+			 * instruction is compressed or not. Standard
+			 * instructions always have bits [1:0] == 11.
 			 */
-			frame->tf_sepc += 4;
+			insn = *(uint16_t *)frame->tf_sepc;
+			if (match_opcode(insn, 0x3, 0x3))
+				frame->tf_sepc += INSN_SIZE;
+			else
+				frame->tf_sepc += INSN_C_SIZE;
 
 			return (1);
 		default: