From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 51D353F104C for ; Wed, 30 Sep 2026 06:40:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.168.131 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790750405; cv=none; b=sYBABIRDbm/VBQxAq9dGAJZ3idz4U0i6nOkjDiPosVb7YevMRCNNriYBZWJL4QZTAdq4uHDVmRzEA7YDg076l8BYw4SqEaiaKpRr8rQUA/Pe//w6xZrB16cabGJSkmjA72i/Yt/xAuI4qO4TZTfPc5lhxUZIVlqHujWI3mQVejA= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790750405; c=relaxed/simple; bh=/9lKqHBhFb4p0Ucj2ys10zg54LDaYLBV4l2ZDIVpZmI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=HOLMez58EqwoeVO0WlUyODEUqpGvYvz54s3jQXuY+Mf4jbGncaYf3/wy452XYy1HIufjhMPhszWXZVfYrywayjF8XYzFJWBKVoxWHdFWDPJtvw46KCIbN0daTYBzGDwXt+GlhqPoSo8QRTmH5vAd65YqwHC/bVRfPoqEb+QLtNc= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=lRb3Rp2w; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=iQw9RUT4; arc=none smtp.client-ip=205.220.168.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="lRb3Rp2w"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="iQw9RUT4" Received: from pps.filterd (m0279865.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 68U6R7852876480 for ; Wed, 30 Sep 2026 06:40:02 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=qcppdkim1; bh=8OWABlvWmQD eWp98OxpVQtoQURxY/W2DmFEPy2By3PM=; b=lRb3Rp2wgIxmPSVMCNFwHXkXpTX HZB6EToy7MxH8sWWVGqsHe2yReb3X6wNA3AqacT94Zb7juXIWo391RyeG41UeA+f XArqXMRx5Xh5T7ae092ODNQzmPaPjtfY1KrYC/Uldq66O529gz39z65KzydmFzws bKsD8OcEnsNMvV3sEK0wgs3FSva/QKf77UgDlAEX42pFAMBPnYknhuFVMu0rLnrQ 2u2RY6lQHBpmqx19Fn+VdFbU9RQiTbYjVozJYUBaxWyQEVfULIh1nQRh4pFMoqra UwdqdLXBcFrKGNFnpwjCRZHpLJh/SHp/ZN8C6yXYB8iCD+8pW25B2NT/Low== Received: from mail-dy1-f197.google.com (mail-dy1-f197.google.com [74.125.82.197]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4h0et2bvk9-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Wed, 30 Sep 2026 06:40:02 +0000 (GMT) Received: by mail-dy1-f197.google.com with SMTP id 5a478bee46e88-30c0d568830so9892032eec.1 for ; Tue, 29 Sep 2026 23:40:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1790750402; x=1791355202; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=8OWABlvWmQDeWp98OxpVQtoQURxY/W2DmFEPy2By3PM=; b=iQw9RUT4c08meQ7kUX0pqZH/DzfSw7PpZkjEeMxjmWdCwPK+md37+5/YCvXCZuf5xs +oXRdj+0SNoaj/J2AHMfcg7h1nizj6+bBhrP6JaJz4I9dDmTLU0URhW7KiD8yIiY31KH xUW3H50QlfnrHelVIXwSDnCEmZxubEWZ3AePRNaqyTvIyd6f+gw6hRfb8ePl6hjZu8wa Xyb8KgbEshd0BB2mLTmWZLiI55F5rLW3kMQ4ZET9xQku8l003CWtUm4fRSg7v6VzB3L3 fyDt//6RyjG+fqqzCkNpM791zMZ4wetWHlYswiHreF+ymg+5P3o2wJpcTF6i0+qdz6Q4 pAcw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790750402; x=1791355202; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=8OWABlvWmQDeWp98OxpVQtoQURxY/W2DmFEPy2By3PM=; b=bcBHEIaymKnAqXiAmaRX6DFuo+WCgq3GTwUQK0QxEgME94v0RLtCADkTiZeGVEMAXu l6cTvx9DJx/BlZtcdb8hNmLTljDZcLtYJFiiSUtxk7xR/jsa+oy1kNRq0ZGDlzmx1TuC gwhvNVk6nvCCdwUN8TPW+egIVl0DXNe+NgvNxhS13DaluD/6yP4KsaHXaOUuOf3jcnyL mAPUw6GeqI5EEh+aJdJ0UpLqZUMJEgXqgT3X3kyUkquMDFX2sXeHOrUljkvY/NtiB6Dg 4RSXW1HRMHimT37uah2ukYh6KGGWs4LdKwPAM8SdB0e/ECfH1PtfCyPw8QK4fk1kSqvU hT/Q== X-Gm-Message-State: AFuF++kOAmt3yPGkeL2PQZ2Rt2Fz4dLxODmr9WH4vd2vILssEuijMM5m n5YutogQTYG7SEvbgKJ2T4KjuIbOGNTCtMZk1x13YJ78csArLxIPQILGWAeEN54bRLRgXhcc67c dtGfMcdzDkjYCqtb6edOr8I6Rfubbn4xzRonL6n/omVosI5mygXSp3JUhnzRY2GTWMtTtljGlvb 0= X-Gm-Gg: AYBFou3msSreI2S4nuQuKFaJavp1OXJk4sgcljVxGs1U7WgIwmnXVxo/crMc/z+S1y+ CX8b0XStjHQ/QZCtoOJ+Uyv3aN4mht2YA9pvojrhdsw5RCD6tzQtBvrtetA/+9EcDn+XPwOCP6O jtpcFsc0SmdMzqtv97xKPSvwK34ncVw/GkK2X4UFGSrxnEVFsTHrv9swHXZH3YvD4jhKk5WgC6x STXwDpivr0AQb4rXM9GAkOEhhDoLv/PJv5V1rwNuc1PBlOYYyDpfiyWQJYD8MWbbTOt/9uest2W v207K2us4pPjVuZnXABasGIewmfwmC97QXP2q2/1J8qIOd0Qeb+9AazjJpSOkneyMXd70PJVMcW 0XaZAHcnHQTq0HEBPTWaUcBR5sBqQmbbHndjJZVJ7JADz7EyrcpySn28oVBBXcstrEqSsZQt9Ux 73MaRKEYqF7qKnQ9rQt+6dUTKc X-Received: by 2002:a05:7022:ea9c:b0:14b:2397:d8f1 with SMTP id a92af1059eb24-14d3204deb9mr213402c88.9.1790750401388; Tue, 29 Sep 2026 23:40:01 -0700 (PDT) X-Received: by 2002:a05:7022:ea9c:b0:14b:2397:d8f1 with SMTP id a92af1059eb24-14d3204deb9mr213360c88.9.1790750400667; Tue, 29 Sep 2026 23:40:00 -0700 (PDT) Received: from hu-himchau-blr.qualcomm.com (blr-bdr-fw-01_GlobalNAT_AllZones-Outside.qualcomm.com. [103.229.18.19]) by smtp.gmail.com with ESMTPSA id a92af1059eb24-14d08fb50f1sm2711531c88.13.2026.09.29.23.39.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 29 Sep 2026 23:40:00 -0700 (PDT) From: Himanshu Chauhan To: linux-kernel@vger.kernel.org, linux-riscv@lists.infradead.org, linux-perf-users@vger.kernel.org Cc: peterz@infradead.org, mingo@redhat.com, alex@ghiti.fr, aou@eecs.berkeley.edu, jtaubepe@redhat.com, palmer@dabbelt.com, pjw@kernel.org, qingfang.deng@linux.dev, shuah@kernel.org, thecharlesjenkins@gmail.com, cp0613@linux.alibaba.com, Himanshu Chauhan Subject: [PATCH v7 6/8] riscv: Add software supported single stepping with mc/mc6 triggers Date: Wed, 30 Sep 2026 12:09:17 +0530 Message-ID: <20260930063919.608911-7-himanshu.chauhan@oss.qualcomm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260930063919.608911-1-himanshu.chauhan@oss.qualcomm.com> References: <20260930063919.608911-1-himanshu.chauhan@oss.qualcomm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Proofpoint-GUID: y_cLb1DKGmLo5TrTHqi69R_kQmRw-Pxm X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTMwMDAyNiBTYWx0ZWRfXwPovlF4xcI9H 6AXhgsb/Xa60KA/dmNm4rJmJkt6i1FISfro6+DwUg/AeKTIFUy1CszD5x5M9yfy8DMUQirvYjFy 6kKS+Snctjl3bYYFUW3j/WlHdh0TXpWnC/fTitNVkLVhu/yv4UWjeHw1OCWg3T07RASBp8gWeNR bR+GHuaaEiU7yTqdD12nxT+nN9raEskTQevDDu4NWdM5Vkg+SGiBVtW3R9W0hltY6WY4jusFO5l +nHtHu09taZv9LIZLizYq6HDHetw65h2FtC5nCtvkf9AY7aO8rW4ZQSBSxVyBX5es56dbT6Kc4x skmXgkwh3u3kEQekN4H3JIzGLCLvwgyapkmrw/LNIYraurm7Xx4xW0cqn2axQMYCer7tq7tGqGr jvGf8QDqIQfmSIbqxiXTQQPZ4CkjuYxyZEhEzIG3VwYRtBm2crWbp55cyUYAEhKj0PnYM7RRt4S JqZMNJH/1nSYrVVk76A== X-Authority-Analysis: v=2.4 cv=cokOAF4i c=1 sm=1 tr=0 ts=6abcaec2 cx=c_pps a=Uww141gWH0fZj/3QKPojxA==:117 a=Ou0eQOY4+eZoSc0qltEV5Q==:17 a=VdqzKS8jKosA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=Um2Pa8k9VHT-vaBCBUpS:22 a=EUspDBNiAAAA:8 a=YfvAyfKA-KDybrY5ebIA:9 a=PxkB5W3o20Ba91AHUih5:22 X-Proofpoint-ORIG-GUID: y_cLb1DKGmLo5TrTHqi69R_kQmRw-Pxm X-Proofpoint-Spam-Info: AW1haW4tMjYwOTMwMDAyNiBTYWx0ZWRfX5EM26dAM7W7t fas3jGNtXiIw5nxAmmcRrZiUFz7ceT9LrCqm7V1mgpDQ6Tp1sZjnU1CPZdCuSXQdBh9St4U4r+r u2hT3ygEYbsHnNOmWO/Z3k4umpSUD+s= X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-09-29_05,2026-09-21_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 priorityscore=1501 lowpriorityscore=0 adultscore=0 malwarescore=0 suspectscore=0 phishscore=0 impostorscore=0 bulkscore=0 spamscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2609040000 definitions=main-2609300026 With mc/mc6 triggers, after handling breakpoint at current pc, there is no way to tell trigger to skip same breakpoint after the handler returns. This can cause loop of breakpoints at the same address until the trigger is disabled or uninstalled. Debugger may keep the breakpoints enabled and if kernel disables it, there is a loss of state coherency. To avoid the loop, software disables the current breakpoint, finds the next instruction that would be executed after pc and puts a breakpoint at that address. When this breakpoint hits, old breakpoint is reinstalled. Signed-off-by: Himanshu Chauhan --- arch/riscv/include/asm/hw_breakpoint.h | 9 + arch/riscv/kernel/hw_breakpoint.c | 256 +++++++++++++++++++------ 2 files changed, 202 insertions(+), 63 deletions(-) diff --git a/arch/riscv/include/asm/hw_breakpoint.h b/arch/riscv/include/asm/hw_breakpoint.h index ca2ef93c020c..93cbf39f4b4a 100644 --- a/arch/riscv/include/asm/hw_breakpoint.h +++ b/arch/riscv/include/asm/hw_breakpoint.h @@ -280,6 +280,10 @@ struct arch_hw_breakpoint { unsigned long address; unsigned long len; unsigned int type; + + /* Single-step callback info */ + unsigned long next_addr; + bool in_callback; unsigned int match; unsigned int chain; unsigned int select; @@ -289,6 +293,11 @@ struct arch_hw_breakpoint { unsigned long tdata1; unsigned long tdata2; unsigned long tdata3; + + /* Saved trigger config for single-step restore */ + unsigned long saved_tdata1; + unsigned long saved_tdata2; + unsigned long saved_tdata3; }; struct perf_event_attr; diff --git a/arch/riscv/kernel/hw_breakpoint.c b/arch/riscv/kernel/hw_breakpoint.c index dd6f63953969..9597ed362537 100644 --- a/arch/riscv/kernel/hw_breakpoint.c +++ b/arch/riscv/kernel/hw_breakpoint.c @@ -11,9 +11,12 @@ #include #include #include +#include +#include #include #include +#include #include /* Registered per-cpu bp/wp */ @@ -328,8 +331,11 @@ int hw_breakpoint_arch_parse(struct perf_event *bp, /* Breakpoint address */ hw->address = attr->bp_addr; + hw->tdata1 = 0; hw->tdata2 = attr->bp_addr; hw->tdata3 = 0x0; + hw->next_addr = 0x0; + hw->in_callback = false; switch (dbtr_type) { case RISCV_DBTR_TRIG_MCONTROL: @@ -347,6 +353,93 @@ int hw_breakpoint_arch_parse(struct perf_event *bp, return ret; } +static ulong get_step_address(struct pt_regs *regs, ulong insn) +{ + return get_next_insn_address(regs, insn, regs->epc); +} + +/* + * setup_singlestep - Set the breakpoint to next instruction after current breakpoint. + */ +static int setup_singlestep(struct perf_event *event, struct pt_regs *regs) +{ + struct arch_hw_breakpoint *bp = counter_arch_bp(event); + unsigned long insn, next_addr = 0; + int ret; + struct arch_hw_breakpoint tmp = {}; + + /* + * Save the original trigger configuration so we can restore it + * after the single-step fires. + */ + bp->saved_tdata1 = bp->tdata1; + bp->saved_tdata2 = bp->tdata2; + bp->saved_tdata3 = bp->tdata3; + + ret = get_insn_safe(regs, regs->epc, &insn); + if (ret < 0) + return ret; + + next_addr = get_step_address(regs, insn); + + /* + * Software path: update the trigger in-place to an execute + * breakpoint at next_addr. Build the tdata directly without + * calling hw_breakpoint_arch_parse() so that bp->len, bp->type + * and bp->address are not overwritten and remain valid for the + * handler's matching logic after restore. + */ + tmp.tdata1 = 0; + tmp.tdata2 = next_addr; + tmp.tdata3 = 0; + switch (dbtr_type) { + case RISCV_DBTR_TRIG_MCONTROL6: + RISCV_DBTR_SET_MC6_EXEC_BIT(tmp.tdata1); + tmp.tdata1 = RISCV_DBTR_SET_MC6_SIZE(tmp.tdata1, 0); + tmp.tdata1 = RISCV_DBTR_SET_MC6_TYPE(tmp.tdata1, + RISCV_DBTR_TRIG_MCONTROL6); + CLEAR_DBTR_BIT(tmp.tdata1, RISCV_DBTR_MC6_DMODE_BIT); + CLEAR_DBTR_BIT(tmp.tdata1, RISCV_DBTR_MC6_TIMING_BIT); + CLEAR_DBTR_BIT(tmp.tdata1, RISCV_DBTR_MC6_SELECT_BIT); + CLEAR_DBTR_BIT(tmp.tdata1, RISCV_DBTR_MC6_ACTION_BIT); + CLEAR_DBTR_BIT(tmp.tdata1, RISCV_DBTR_MC6_CHAIN_BIT); + CLEAR_DBTR_BIT(tmp.tdata1, RISCV_DBTR_MC6_MATCH_BIT); + CLEAR_DBTR_BIT(tmp.tdata1, RISCV_DBTR_MC6_M_BIT); + CLEAR_DBTR_BIT(tmp.tdata1, RISCV_DBTR_MC6_VS_BIT); + CLEAR_DBTR_BIT(tmp.tdata1, RISCV_DBTR_MC6_VU_BIT); + SET_DBTR_BIT(tmp.tdata1, RISCV_DBTR_MC6_S_BIT); + SET_DBTR_BIT(tmp.tdata1, RISCV_DBTR_MC6_U_BIT); + break; + case RISCV_DBTR_TRIG_MCONTROL: + RISCV_DBTR_SET_MC_EXEC_BIT(tmp.tdata1); + tmp.tdata1 = RISCV_DBTR_SET_MC_SIZELO(tmp.tdata1, 0); + tmp.tdata1 = RISCV_DBTR_SET_MC_SIZEHI(tmp.tdata1, 0); + tmp.tdata1 = RISCV_DBTR_SET_MC_TYPE(tmp.tdata1, + RISCV_DBTR_TRIG_MCONTROL); + CLEAR_DBTR_BIT(tmp.tdata1, RISCV_DBTR_MC_DMODE_BIT); + CLEAR_DBTR_BIT(tmp.tdata1, RISCV_DBTR_MC_TIMING_BIT); + CLEAR_DBTR_BIT(tmp.tdata1, RISCV_DBTR_MC_SELECT_BIT); + CLEAR_DBTR_BIT(tmp.tdata1, RISCV_DBTR_MC_ACTION_BIT); + CLEAR_DBTR_BIT(tmp.tdata1, RISCV_DBTR_MC_CHAIN_BIT); + CLEAR_DBTR_BIT(tmp.tdata1, RISCV_DBTR_MC_MATCH_BIT); + CLEAR_DBTR_BIT(tmp.tdata1, RISCV_DBTR_MC_M_BIT); + SET_DBTR_BIT(tmp.tdata1, RISCV_DBTR_MC_S_BIT); + SET_DBTR_BIT(tmp.tdata1, RISCV_DBTR_MC_U_BIT); + break; + default: + return -EOPNOTSUPP; + } + + bp->tdata1 = tmp.tdata1; + bp->tdata2 = next_addr; + bp->tdata3 = 0; + arch_update_hw_breakpoint(event); + + bp->in_callback = true; + bp->next_addr = next_addr; + return 0; +} + /* * Read mcontrol6's hit1:hit0 field for trigger @idx. If either bit is set, * clear it in hardware (the Debug spec requires the trigger user to do @@ -401,10 +494,10 @@ static unsigned int mc6_read_and_clear_hit(int idx) */ static int hw_breakpoint_handler(struct die_args *args) { - int ret = NOTIFY_DONE; + int i, ret = 0, bp_ret = NOTIFY_DONE; + bool expecting_callback = false; struct arch_hw_breakpoint *bp; struct perf_event *event; - int i; for (i = 0; i < dbtr_total_num; i++) { event = this_cpu_read(pcpu_hw_bp_events[i]); @@ -412,85 +505,122 @@ static int hw_breakpoint_handler(struct die_args *args) continue; bp = counter_arch_bp(event); - switch (bp->type) { - /* Breakpoint */ - case HW_BREAKPOINT_X: - { - bool hit = bp->address == args->regs->epc; - if (!hit && dbtr_type == RISCV_DBTR_TRIG_MCONTROL6) - hit = mc6_read_and_clear_hit(i) != RISCV_DBTR_MC6_HIT_FALSE; + if (bp->in_callback) { + expecting_callback = true; + if (args->regs->epc != bp->next_addr) + continue; + + arch_uninstall_hw_breakpoint(event); - if (hit) { - perf_bp_event(event, args->regs); - ret = NOTIFY_STOP; + /* Restore original breakpoint */ + if (hw_breakpoint_arch_parse(NULL, &event->attr, bp)) + goto exit; + + if (arch_install_hw_breakpoint(event)) + goto exit; + + bp->in_callback = false; + bp_ret = NOTIFY_STOP; + goto exit; + } + + switch (event->attr.bp_type) { + /* Breakpoint */ + case HW_BREAKPOINT_X: + { + bool hit = bp->address == args->regs->epc; + + if (!hit && dbtr_type == RISCV_DBTR_TRIG_MCONTROL6) + hit = mc6_read_and_clear_hit(i) != RISCV_DBTR_MC6_HIT_FALSE; + + if (hit) { + perf_bp_event(event, args->regs); + ret = setup_singlestep(event, args->regs); + if (ret < 0) { + pr_err("Single step setup failed: %d.\n", ret); + goto exit; + } + bp_ret = NOTIFY_STOP; + goto exit; + } } break; - } /* Watchpoint */ case HW_BREAKPOINT_W: case HW_BREAKPOINT_R: case HW_BREAKPOINT_RW: - { - unsigned long stval = args->regs->badaddr; - unsigned long bp_start = bp->address; - unsigned long bp_len = bp->len ?: 1; - unsigned long bp_end = bp_start + bp_len - 1; - unsigned long stval_end = stval + sizeof(long) - 1; - bool hit = false; - - if (bp_end < bp_start) - bp_end = ~0UL; - if (stval_end < stval) - stval_end = ~0UL; - - /* - * Prefer tdata1.hit from SBI trigger readout whenever - * possible. Fall back to address-based matching if HIT - * isn't observed/supported. - */ - if (dbtr_type == RISCV_DBTR_TRIG_MCONTROL) { - unsigned long tdata1; - struct sbiret sret; - union sbi_dbtr_shmem_entry *shmem; - - raw_spin_lock_irqsave(this_cpu_ptr(&ecall_lock), - *this_cpu_ptr(&ecall_lock_flags)); - shmem = this_cpu_ptr(sbi_dbtr_shmem); - sret = sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_TRIG_READ, - i, 1, 0, 0, 0, 0); - if (!sret.error) { - tdata1 = le_to_cpu(shmem->data.tdata1); - hit = !!(tdata1 & RISCV_DBTR_MC_HIT_BIT_MASK); + { + unsigned long stval = args->regs->badaddr; + unsigned long bp_start = bp->address; + unsigned long bp_len = bp->len ?: 1; + unsigned long bp_end = bp_start + bp_len - 1; + unsigned long stval_end = stval + sizeof(long) - 1; + bool hit = false; + + if (bp_end < bp_start) + bp_end = ~0UL; + if (stval_end < stval) + stval_end = ~0UL; + + /* + * Prefer tdata1.hit from SBI trigger readout whenever + * possible. Fall back to address-based matching if HIT + * isn't observed/supported. + */ + if (dbtr_type == RISCV_DBTR_TRIG_MCONTROL) { + unsigned long tdata1; + struct sbiret sret; + union sbi_dbtr_shmem_entry *shmem; + + raw_spin_lock_irqsave(this_cpu_ptr(&ecall_lock), + *this_cpu_ptr(&ecall_lock_flags)); + shmem = this_cpu_ptr(sbi_dbtr_shmem); + sret = sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_TRIG_READ, + i, 1, 0, 0, 0, 0); + if (!sret.error) { + tdata1 = le_to_cpu(shmem->data.tdata1); + hit = !!(tdata1 & RISCV_DBTR_MC_HIT_BIT_MASK); + } + raw_spin_unlock_irqrestore(this_cpu_ptr(&ecall_lock), + *this_cpu_ptr(&ecall_lock_flags)); + } else if (dbtr_type == RISCV_DBTR_TRIG_MCONTROL6) { + hit = mc6_read_and_clear_hit(i) != RISCV_DBTR_MC6_HIT_FALSE; } - raw_spin_unlock_irqrestore(this_cpu_ptr(&ecall_lock), - *this_cpu_ptr(&ecall_lock_flags)); - } else if (dbtr_type == RISCV_DBTR_TRIG_MCONTROL6) { - hit = mc6_read_and_clear_hit(i) != RISCV_DBTR_MC6_HIT_FALSE; - } - /* - * Sdtrig may report STVAL as the lowest accessed - * address while the watchpoint can match a higher byte - * in the same access. - */ - if (hit || - (stval >= bp_start && stval <= bp_end) || - (bp_start >= stval && bp_start <= stval_end)) { - perf_bp_event(event, args->regs); - ret = NOTIFY_STOP; + /* + * Sdtrig may report STVAL as the lowest accessed + * address while the watchpoint can match a higher byte + * in the same access. + */ + if (hit || + (stval >= bp_start && stval <= bp_end) || + (bp_start >= stval && bp_start <= stval_end)) { + perf_bp_event(event, args->regs); + ret = setup_singlestep(event, args->regs); + if (ret < 0) { + pr_err("setup_singlestep failed %d.\n", ret); + goto exit; + } + bp_ret = NOTIFY_STOP; + goto exit; + } } break; - } default: - pr_warn("Unknown type: %u\n", bp->type); - break; + pr_warn("Unknown type: %u\n", event->attr.bp_type); + goto exit; } } - return ret; + if (expecting_callback) { + pr_err("in_callback set but epc (%lx) not at next_addr (%lx).\n", + args->regs->epc, bp->next_addr); + } +exit: + return bp_ret; } int hw_breakpoint_exceptions_notify(struct notifier_block *unused, -- 2.43.0