From nobody Fri Oct 2 08:26:24 2026 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.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 C78E53EEAD7 for ; Wed, 30 Sep 2026 06:39:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790750381; cv=none; b=L+3N826u9BrdPmWfWrVKzEkCotfdvfBGunUz098FF6X7paKVbkM1NU5e77rnO4WV7R7c0Mwq6ATBp4i0lkEn/M7MO2Gr6eEp+D3/1ShpnPs87uZ3AN5vQg/ok302UiCglrFHb6Mt0psuBUJwghMDCHXZcdCw0LslWyzalbNKaRM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790750381; c=relaxed/simple; bh=xKnX/euCiK/QqaeXOzIScsgk8T7xfOv9BUYMjvYiHjg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=DIClA7wl48XwFjCEolZpB3IUXPydFm1SXIoJgKAkhYpo4BkiVvnvMu9LOibKxmTVC+4DXjL/acXeXbR3jKDXAGzQZiIMtCNKUF8C5nsBFN0nZeSQID2lK3jmhCsWdsaIFRAs8GbngzpLr4Nu64+cg6/0KZhqDe1cvbq0EZN5GkY= 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=DU6cKpdr; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=Nl9GLaMq; arc=none smtp.client-ip=205.220.180.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="DU6cKpdr"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="Nl9GLaMq" Received: from pps.filterd (m0279868.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 68U6F9ja1592835 for ; Wed, 30 Sep 2026 06:39:37 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=5ZZaESGLKRG RLOjYU42IQLznpJTnyGsm5Bd30n0iDFk=; b=DU6cKpdr9JziYA+f/jMU6sxrjNr G+Zn1PF8FFEJYjeog0vm5jW/Pw6vh3UIO5Oc9OKjUzIYw/7U18E3F3MdPtxifPwP wiKiORPmUoyZ3BPJYyURQGd8tDFAcZI0JbTpB1zOnRln0JqqH23GfoAVphGxZTKZ Z7MqSDk7odbAC1/OQBpN1GU25b/JOflPjQYMu5Xp2F4BpD1RpM3BhNJEF1diXjqr MelEXljKSFk7DLOqfsO9HT9U39Mvu3Slyw2HtbRWXEI0N+x/KdhayFSiXTvaIuVf MJCD0lrWLtxKcXgpuwv/xib9cnd+Hwr3/CaWzPn5tDrgwHGwpSCYHUMsBLg== Received: from mail-dy1-f198.google.com (mail-dy1-f198.google.com [74.125.82.198]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4h0hsh2u45-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Wed, 30 Sep 2026 06:39:37 +0000 (GMT) Received: by mail-dy1-f198.google.com with SMTP id 5a478bee46e88-34d18eee3dfso322497eec.0 for ; Tue, 29 Sep 2026 23:39:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1790750376; x=1791355176; 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=5ZZaESGLKRGRLOjYU42IQLznpJTnyGsm5Bd30n0iDFk=; b=Nl9GLaMqsov5gouqEmkQjfFUW+rp5P8V2BdRKZs8kei2dNGSfQXR7McdBHF4+CWA6D tycbrlnAEqgMjh1ev6J82CzeZhYYk/2hhlq9cAdHqRH9WqixyNXwIhdDX5FXAeb+VeB7 1DB/H0vjt5LlUhZDGxgdAaZ8imPhlFbJJelP3xqO0XLaZ+ILhPGA1v1L/GB6QdGiAHoN 78JWrZaAZ1Oeiu7GFKEubdfHCckNzQST20IZDxKzQ6N+DnG1wOwIFz8WthknBo5LzSLh sdYPLmBpAqlbmIb1fkNy4r3YuaWbpnXY7TCIWB1VedSar4qLf9cjFEfgbyMmRtvHND8J a+XA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790750376; x=1791355176; 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=5ZZaESGLKRGRLOjYU42IQLznpJTnyGsm5Bd30n0iDFk=; b=DKvMMRHZeOjHRYd8WsXq2DMXkl8+AK7NeiiMkJ9hGd1/fIGYAkeQXAZxeCOdXW9Zdt oG36tTnJ3xWKYXBKtqW9jdSb2b00XgHOE4qVyyBm2DHhyTrqOHfkbka1YqvTQz69IXEq 6iinj0LYWI6eyV3kWdx0678UXzTxg6lgifAHl3Mi8BTlOZRbZcrkSv6MvNyvYc1fJ/bk KP5xsPgnz1nogA70IX/7fsKR/gArrbomsbLAUOyPjzjlncVZNrZdlIlmkeSvMvxTwUS5 TNkZTGyqj2GmV9HWYk43uyXDZNHuoBFUxXhuForuJraOFZ/jfuXoDXIIkLP+iepXo9e+ oVdA== X-Gm-Message-State: AFuF++nwaCKT2qsML0+7zmLfoUPdfH4BzjI8jrcGOUnE2yg9lRnd4xo9 Kvhm1fE1P/mlTEmOXUSBdOZt7o3h9yTZQnWoLV/IIFkm5J6zFgtf8gg/fyolN5fCQtcbjs0Qo1V PSklpswKB2r1hBixh3iUQWk+xKMAQLVeYwy1+0o3j9vWoFDAULclSo6m7sTKWh7rzPWvpEPzhIk 4= X-Gm-Gg: AYBFou3SXOlOtWzlYORkL8C1510Lh+kEVlRmdXEkYluwRKteuqpqwxMpdZdFYVniVug 2D13M2pzBw7uRZV4W+uDYT02lhegDosl42KdhI/OCM5q8FsGbMP6mriJg25erGUNhlWN7xN0vk+ xbfhaGTkObPOnR9wGhdHl9X6C4COJPnHbj7bsMz/MhcINNbnZ5bjSHJXcRJwcbSNNFTJLLM0SKr nZD8LTS1XqGQDavQUH9/g+sSmk7XOZKz8lN0PRJNzTXJVHun8BK6ZLscccgGFSwLeJYNUnvDRqP cs5BEdNo6+a0QDdleMQ72ry0jpy9fnsiMR0ke/hohQCaYhewpkvyw/1/gEejRA+1TfVJiTRzhaW xCXwlum2PSAGJoMo0ViLvJ9fJD8bUcKsXXGCJXXH0TQ0LplFzeUIGeh8vsvr3Z8s7m0JQRmEc/0 GD3ZJHZGh3DUmvGHJP/9MGiK8l X-Received: by 2002:a05:7022:ed02:b0:145:7a:7765 with SMTP id a92af1059eb24-14d331a6544mr230620c88.36.1790750375675; Tue, 29 Sep 2026 23:39:35 -0700 (PDT) X-Received: by 2002:a05:7022:ed02:b0:145:7a:7765 with SMTP id a92af1059eb24-14d331a6544mr230562c88.36.1790750374688; Tue, 29 Sep 2026 23:39:34 -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.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 29 Sep 2026 23:39:34 -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 1/8] riscv: Introduce support for hardware break/watchpoints Date: Wed, 30 Sep 2026 12:09:12 +0530 Message-ID: <20260930063919.608911-2-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: quoted-printable X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTMwMDAyNiBTYWx0ZWRfXxEvrqmb18/R/ PVxH052UWQeXu6TCKpXrDyZ6WN6clqrCwc2ytWY7Hkov8dr8V8umQW1nrCmPVZosmm321fvfeQJ VRhKF68T4cKS7McUzJvYgbChpXqfIs5zf/4AenBTkXwa/sUkbrpeX6udr1TCu1EqsPQtTGi6Ekj sWzY/p3YLJHDziswe8fmMpZ1Selhou94fJAmVtZCjlS7C22Z2NtitPuzYlBP1YN1X6QdaGfQ2tA jepZBS7u284tN9jZU1h/HJsBFIjrfb7IW+6Ax3VvkJH0lcluQfgAKD4UKuxlKeIMMpZjclJNV2N wTV+a5BS8f2Np+qTaoCy2szaTOwuoTColLOVtLRSy7Ni3WGK39ewgFDUqT5jS6l6HMWE0Ph6I4K zTPoybZ2aHpcPwBahRGTzKAQBeeaWLO3J9h32JUsaxlEvLC5xxmJD1m76Pm3pvvPx2adpxlFU/y Kh18NgA074Ivc8x+MMQ== X-Proofpoint-GUID: nYsrqFcipXQsU7WLekaVYkyETR5VIc-M X-Proofpoint-ORIG-GUID: nYsrqFcipXQsU7WLekaVYkyETR5VIc-M X-Proofpoint-Spam-Info: AW1haW4tMjYwOTMwMDAyNiBTYWx0ZWRfX25vDWbs7iFM2 BGZFDqrfneO5khn2Rb7smp2XXm9s8TehJaC7peGhWuECeASCaJzvQNxnNPvqRXyLH/v3xAGz/HH C16sG2vSQ2p/ZjEsYODKjr3mOTqAqJE= X-Authority-Analysis: v=2.4 cv=cZZHPXDM c=1 sm=1 tr=0 ts=6abcaea9 cx=c_pps a=wEP8DlPgTf/vqF+yE6f9lg==:117 a=Ou0eQOY4+eZoSc0qltEV5Q==:17 a=VdqzKS8jKosA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=ZpdpYltYx_vBUK5n70dp:22 a=EUspDBNiAAAA:8 a=oxkvXMDg2opwoU6JHakA:9 a=bBxd6f-gb0O0v-kibOvt:22 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 phishscore=0 impostorscore=0 lowpriorityscore=0 spamscore=0 adultscore=0 bulkscore=0 malwarescore=0 suspectscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2609040000 definitions=main-2609300026 Content-Type: text/plain; charset="utf-8" RISC-V hardware breakpoint framework is built on top of perf subsystem and uses SBI debug trigger extension to install/uninstall/update/enable/dis= able hardware triggers as specified in Sdtrig ISA extension. While handling breakpoints, trust the hardware record, (hit[0-1]) bits, whe= n deciding if a trigger fired, and by clearing it once it's been read. Signed-off-by: Himanshu Chauhan --- arch/riscv/Kconfig | 2 + arch/riscv/include/asm/hw_breakpoint.h | 312 +++++++++++ arch/riscv/include/asm/kdebug.h | 3 +- arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/hw_breakpoint.c | 746 +++++++++++++++++++++++++ arch/riscv/kernel/traps.c | 6 + 6 files changed, 1069 insertions(+), 1 deletion(-) create mode 100644 arch/riscv/include/asm/hw_breakpoint.h create mode 100644 arch/riscv/kernel/hw_breakpoint.c diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index d6c2dbf8455c..17fa7d4f9729 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -174,6 +174,8 @@ config RISCV select HAVE_FUNCTION_ARG_ACCESS_API select HAVE_FUNCTION_ERROR_INJECTION select HAVE_GCC_PLUGINS + select HAVE_GENERIC_VDSO if MMU + select HAVE_HW_BREAKPOINT if PERF_EVENTS select HAVE_IRQ_TIME_ACCOUNTING select HAVE_KERNEL_BZIP2 if !EFI_ZBOOT select HAVE_KERNEL_GZIP if !EFI_ZBOOT diff --git a/arch/riscv/include/asm/hw_breakpoint.h b/arch/riscv/include/as= m/hw_breakpoint.h new file mode 100644 index 000000000000..a165bb9636de --- /dev/null +++ b/arch/riscv/include/asm/hw_breakpoint.h @@ -0,0 +1,312 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2026 Qualcomm Technologies, Inc. + */ + +#ifndef __RISCV_HW_BREAKPOINT_H +#define __RISCV_HW_BREAKPOINT_H + +struct task_struct; + +#ifdef CONFIG_HAVE_HW_BREAKPOINT + +#include + +/* Maximum number of hardware breakpoints supported */ +#define RISCV_HW_BP_NUM_MAX 32 + +#if __riscv_xlen =3D=3D 64 +#define cpu_to_le cpu_to_le64 +#define le_to_cpu le64_to_cpu +#elif __riscv_xlen =3D=3D 32 +#define cpu_to_le cpu_to_le32 +#define le_to_cpu le32_to_cpu +#else +#error "Unexpected __riscv_xlen" +#endif + +#define CLEAR_DBTR_BIT(_target, _bit) ((_target) &=3D ~BIT(_bit)) +#define SET_DBTR_BIT(_target, _bit) ((_target) |=3D BIT(_bit)) + +#define RISCV_DBTR_EXEC BIT(0) +#define RISCV_DBTR_LOAD BIT(1) +#define RISCV_DBTR_STORE BIT(2) +#define RISCV_DBTR_LDST (RISCV_DBTR_LOAD | RISCV_DBTR_STORE) + +enum { + RISCV_DBTR_TRIG_NONE =3D 0, + RISCV_DBTR_TRIG_LEGACY, + RISCV_DBTR_TRIG_MCONTROL, + RISCV_DBTR_TRIG_ICOUNT, + RISCV_DBTR_TRIG_ITRIGGER, + RISCV_DBTR_TRIG_ETRIGGER, + RISCV_DBTR_TRIG_MCONTROL6, +}; + +/* Trigger Data 1 */ +#define RISCV_DBTR_TDATA1_DATA_BIT 0 +#if __riscv_xlen =3D=3D 64 +#define RISCV_DBTR_TDATA1_DMODE_BIT 59 +#define RISCV_DBTR_TDATA1_TYPE_BIT 60 +#elif __riscv_xlen =3D=3D 32 +#define RISCV_DBTR_TDATA1_DMODE_BIT 27 +#define RISCV_DBTR_TDATA1_TYPE_BIT 28 +#else +#error "Unknown __riscv_xlen" +#endif + +#if __riscv_xlen =3D=3D 64 +#define RISCV_DBTR_TDATA1_DATA_BIT_MASK GENMASK(58, RISCV_DBTR_TDATA1_DAT= A_BIT) +#elif __riscv_xlen =3D=3D 32 +#define RISCV_DBTR_TDATA1_DATA_BIT_MASK GENMASK(26, RISCV_DBTR_TDATA1_DAT= A_BIT) +#else +#error "Unknown __riscv_xlen" +#endif +#define RISCV_DBTR_TDATA1_DMODE_BIT_MASK BIT(RISCV_DBTR_TDATA1_DMODE_BIT) +#define RISCV_DBTR_TDATA1_TYPE_BIT_MASK \ + GENMASK(RISCV_DBTR_TDATA1_TYPE_BIT + 3, RISCV_DBTR_TDATA1_TYPE_BIT) + +/* MC - Match Control Type Register */ +#define RISCV_DBTR_MC_LOAD_BIT 0 +#define RISCV_DBTR_MC_STORE_BIT 1 +#define RISCV_DBTR_MC_EXEC_BIT 2 +#define RISCV_DBTR_MC_U_BIT 3 +#define RISCV_DBTR_MC_S_BIT 4 +#define RISCV_DBTR_MC_RES2_BIT 5 +#define RISCV_DBTR_MC_M_BIT 6 +#define RISCV_DBTR_MC_MATCH_BIT 7 +#define RISCV_DBTR_MC_CHAIN_BIT 11 +#define RISCV_DBTR_MC_ACTION_BIT 12 +#define RISCV_DBTR_MC_SIZELO_BIT 16 +#define RISCV_DBTR_MC_TIMING_BIT 18 +#define RISCV_DBTR_MC_SELECT_BIT 19 +#define RISCV_DBTR_MC_HIT_BIT 20 +#if __riscv_xlen >=3D 64 +#define RISCV_DBTR_MC_SIZEHI_BIT 21 +#endif +#if __riscv_xlen =3D=3D 64 +#define RISCV_DBTR_MC_MASKMAX_BIT 53 +#define RISCV_DBTR_MC_DMODE_BIT 59 +#define RISCV_DBTR_MC_TYPE_BIT 60 +#elif __riscv_xlen =3D=3D 32 +#define RISCV_DBTR_MC_MASKMAX_BIT 21 +#define RISCV_DBTR_MC_DMODE_BIT 27 +#define RISCV_DBTR_MC_TYPE_BIT 28 +#else +#error "Unknown riscv xlen" +#endif + +#define RISCV_DBTR_MC_LOAD_BIT_MASK BIT(RISCV_DBTR_MC_LOAD_BIT) +#define RISCV_DBTR_MC_STORE_BIT_MASK BIT(RISCV_DBTR_MC_STORE_BIT) +#define RISCV_DBTR_MC_EXEC_BIT_MASK BIT(RISCV_DBTR_MC_EXEC_BIT) +#define RISCV_DBTR_MC_U_BIT_MASK BIT(RISCV_DBTR_MC_U_BIT) +#define RISCV_DBTR_MC_S_BIT_MASK BIT(RISCV_DBTR_MC_S_BIT) +#define RISCV_DBTR_MC_RES2_BIT_MASK BIT(RISCV_DBTR_MC_RES2_BIT) +#define RISCV_DBTR_MC_M_BIT_MASK BIT(RISCV_DBTR_MC_M_BIT) +#define RISCV_DBTR_MC_MATCH_BIT_MASK \ + GENMASK(RISCV_DBTR_MC_MATCH_BIT + 3, RISCV_DBTR_MC_MATCH_BIT) +#define RISCV_DBTR_MC_CHAIN_BIT_MASK BIT(RISCV_DBTR_MC_CHAIN_BIT) +#define RISCV_DBTR_MC_ACTION_BIT_MASK \ + GENMASK(RISCV_DBTR_MC_ACTION_BIT + 3, RISCV_DBTR_MC_ACTION_BIT) +#define RISCV_DBTR_MC_SIZELO_BIT_MASK \ + GENMASK(RISCV_DBTR_MC_SIZELO_BIT + 1, RISCV_DBTR_MC_SIZELO_BIT) +#define RISCV_DBTR_MC_TIMING_BIT_MASK BIT(RISCV_DBTR_MC_TIMING_BIT) +#define RISCV_DBTR_MC_SELECT_BIT_MASK BIT(RISCV_DBTR_MC_SELECT_BIT) +#define RISCV_DBTR_MC_HIT_BIT_MASK BIT(RISCV_DBTR_MC_HIT_BIT) +#if __riscv_xlen >=3D 64 +#define RISCV_DBTR_MC_SIZEHI_BIT_MASK \ + GENMASK(RISCV_DBTR_MC_SIZEHI_BIT + 1, RISCV_DBTR_MC_SIZEHI_BIT) +#endif +#define RISCV_DBTR_MC_MASKMAX_BIT_MASK \ + GENMASK(RISCV_DBTR_MC_MASKMAX_BIT + 5, RISCV_DBTR_MC_MASKMAX_BIT) +#define RISCV_DBTR_MC_DMODE_BIT_MASK BIT(RISCV_DBTR_MC_DMODE_BIT) +#define RISCV_DBTR_MC_TYPE_BIT_MASK GENMASK(RISCV_DBTR_MC_TYPE_BIT + 3, RI= SCV_DBTR_MC_TYPE_BIT) + +/* MC6 - Match Control 6 Type Register */ +#define RISCV_DBTR_MC6_LOAD_BIT 0 +#define RISCV_DBTR_MC6_STORE_BIT 1 +#define RISCV_DBTR_MC6_EXEC_BIT 2 +#define RISCV_DBTR_MC6_U_BIT 3 +#define RISCV_DBTR_MC6_S_BIT 4 +#define RISCV_DBTR_MC6_RES2_BIT 5 +#define RISCV_DBTR_MC6_M_BIT 6 +#define RISCV_DBTR_MC6_MATCH_BIT 7 +#define RISCV_DBTR_MC6_CHAIN_BIT 11 +#define RISCV_DBTR_MC6_ACTION_BIT 12 +#define RISCV_DBTR_MC6_SIZE_BIT 16 +#define RISCV_DBTR_MC6_TIMING_BIT 20 +#define RISCV_DBTR_MC6_SELECT_BIT 21 +#define RISCV_DBTR_MC6_HIT_BIT 22 +#define RISCV_DBTR_MC6_VU_BIT 23 +#define RISCV_DBTR_MC6_VS_BIT 24 +#if __riscv_xlen =3D=3D 64 +#define RISCV_DBTR_MC6_DMODE_BIT 59 +#define RISCV_DBTR_MC6_TYPE_BIT 60 +#elif __riscv_xlen =3D=3D 32 +#define RISCV_DBTR_MC6_DMODE_BIT 27 +#define RISCV_DBTR_MC6_TYPE_BIT 28 +#else +#error "Unknown riscv xlen" +#endif + +#define RISCV_DBTR_MC6_LOAD_BIT_MASK BIT(RISCV_DBTR_MC6_LOAD_BIT) +#define RISCV_DBTR_MC6_STORE_BIT_MASK BIT(RISCV_DBTR_MC6_STORE_BIT) +#define RISCV_DBTR_MC6_EXEC_BIT_MASK BIT(RISCV_DBTR_MC6_EXEC_BIT) +#define RISCV_DBTR_MC6_U_BIT_MASK BIT(RISCV_DBTR_MC6_U_BIT) +#define RISCV_DBTR_MC6_S_BIT_MASK BIT(RISCV_DBTR_MC6_S_BIT) +#define RISCV_DBTR_MC6_RES2_BIT_MASK BIT(RISCV_DBTR_MC6_RES2_BIT) +#define RISCV_DBTR_MC6_M_BIT_MASK BIT(RISCV_DBTR_MC6_M_BIT) +#define RISCV_DBTR_MC6_MATCH_BIT_MASK \ + GENMASK(RISCV_DBTR_MC6_MATCH_BIT + 3, RISCV_DBTR_MC6_MATCH_BIT) +#define RISCV_DBTR_MC6_CHAIN_BIT_MASK BIT(RISCV_DBTR_MC6_CHAIN_BIT) +#define RISCV_DBTR_MC6_ACTION_BIT_MASK \ + GENMASK(RISCV_DBTR_MC6_ACTION_BIT + 3, RISCV_DBTR_MC6_ACTION_BIT) +#define RISCV_DBTR_MC6_SIZE_BIT_MASK \ + GENMASK(RISCV_DBTR_MC6_SIZE_BIT + 3, RISCV_DBTR_MC6_SIZE_BIT) +#define RISCV_DBTR_MC6_TIMING_BIT_MASK BIT(RISCV_DBTR_MC6_TIMING_BIT) +#define RISCV_DBTR_MC6_SELECT_BIT_MASK BIT(RISCV_DBTR_MC6_SELECT_BIT) +#define RISCV_DBTR_MC6_HIT_BIT_MASK BIT(RISCV_DBTR_MC6_HIT_BIT) +#define RISCV_DBTR_MC6_VU_BIT_MASK BIT(RISCV_DBTR_MC6_VU_BIT) +#define RISCV_DBTR_MC6_VS_BIT_MASK BIT(RISCV_DBTR_MC6_VS_BIT) +#define RISCV_DBTR_MC6_DMODE_BIT_MASK BIT(RISCV_DBTR_MC6_DMODE_BIT) +#define RISCV_DBTR_MC6_TYPE_BIT_MASK \ + GENMASK(RISCV_DBTR_MC6_TYPE_BIT + 3, RISCV_DBTR_MC6_TYPE_BIT) + +/* + * mcontrol6 hit1:hit0 (ratified Debug spec v1.0). RISCV_DBTR_MC6_HIT_BIT + * above is hit0 (bit 22); hit1 (bit 25) is not adjacent to it but combines + * with it into a single 2-bit field, hit1 as MSB. + */ +#define RISCV_DBTR_MC6_HIT1_BIT 25 +#define RISCV_DBTR_MC6_HIT1_BIT_MASK BIT(RISCV_DBTR_MC6_HIT1_BIT) + +#define RISCV_DBTR_MC6_HIT_FALSE 0 /* trigger did not fire */ +#define RISCV_DBTR_MC6_HIT_BEFORE 1 /* fired before the instruction */ +#define RISCV_DBTR_MC6_HIT_AFTER 2 /* fired after, epc has moved past */ +#define RISCV_DBTR_MC6_HIT_IMM_AFTER 3 /* fired immediately after */ + +#define RISCV_DBTR_MC6_GET_HIT(_t1) \ + ({ \ + typeof(_t1) __t1 =3D (_t1); \ + (((__t1) & RISCV_DBTR_MC6_HIT1_BIT_MASK) ? 2 : 0) | \ + (((__t1) & RISCV_DBTR_MC6_HIT_BIT_MASK) ? 1 : 0); \ + }) + +#define RISCV_DBTR_MC6_CLEAR_HIT(_t1) \ + ((_t1) &=3D ~(RISCV_DBTR_MC6_HIT1_BIT_MASK | RISCV_DBTR_MC6_HIT_BIT_MASK)) + +#define RISCV_DBTR_SET_TDATA1_TYPE(_t1, _type) \ + ({ \ + typeof(_t1) (td1t1) =3D (_t1); \ + (td1t1) &=3D ~RISCV_DBTR_TDATA1_TYPE_BIT_MASK; \ + (td1t1) |=3D (((unsigned long)(_type) \ + << RISCV_DBTR_TDATA1_TYPE_BIT) \ + & RISCV_DBTR_TDATA1_TYPE_BIT_MASK); \ + (td1t1); \ + }) + +#define RISCV_DBTR_SET_MC_TYPE(_t1, _type) \ + ({ \ + typeof(_t1) (mct1) =3D (_t1); \ + (mct1) &=3D ~RISCV_DBTR_MC_TYPE_BIT_MASK; \ + (mct1) |=3D (((unsigned long)(_type) \ + << RISCV_DBTR_MC_TYPE_BIT) \ + & RISCV_DBTR_MC_TYPE_BIT_MASK); \ + (mct1); \ + }) + +#define RISCV_DBTR_SET_MC6_TYPE(_t1, _type) \ + ({ \ + typeof(_t1) (mc6t1) =3D (_t1); \ + (mc6t1) &=3D ~RISCV_DBTR_MC6_TYPE_BIT_MASK; \ + (mc6t1) |=3D (((unsigned long)(_type) \ + << RISCV_DBTR_MC6_TYPE_BIT) \ + & RISCV_DBTR_MC6_TYPE_BIT_MASK); \ + (mc6t1); \ + }) + +#define RISCV_DBTR_SET_MC_EXEC_BIT(_t1) \ + SET_DBTR_BIT(_t1, RISCV_DBTR_MC_EXEC_BIT) + +#define RISCV_DBTR_SET_MC_LOAD_BIT(_t1) \ + SET_DBTR_BIT(_t1, RISCV_DBTR_MC_LOAD_BIT) + +#define RISCV_DBTR_SET_MC_STORE_BIT(_t1) \ + SET_DBTR_BIT(_t1, RISCV_DBTR_MC_STORE_BIT) + +#define RISCV_DBTR_SET_MC_SIZELO(_t1, _val) \ + ({ \ + typeof(_t1) (mcslt1) =3D (_t1); \ + mcslt1 &=3D ~RISCV_DBTR_MC_SIZELO_BIT_MASK; \ + mcslt1 |=3D (((_val) << RISCV_DBTR_MC_SIZELO_BIT) \ + & RISCV_DBTR_MC_SIZELO_BIT_MASK); \ + (mcslt1); \ + }) + +#if __riscv_xlen >=3D 64 +#define RISCV_DBTR_SET_MC_SIZEHI(_t1, _val) \ + ({ \ + typeof(_t1) (mcsht1) =3D (_t1); \ + mcsht1 &=3D ~RISCV_DBTR_MC_SIZEHI_BIT_MASK; \ + mcsht1 |=3D (((_val) << RISCV_DBTR_MC_SIZEHI_BIT) \ + & RISCV_DBTR_MC_SIZEHI_BIT_MASK); \ + (mcsht1); \ + }) +#else +/* SIZEHI does not exist in the rv32 mcontrol layout; nothing to set. */ +#define RISCV_DBTR_SET_MC_SIZEHI(_t1, _val) ((void)(_val), (_t1)) +#endif + +#define RISCV_DBTR_SET_MC6_EXEC_BIT(_t1) \ + SET_DBTR_BIT(_t1, RISCV_DBTR_MC6_EXEC_BIT) + +#define RISCV_DBTR_SET_MC6_LOAD_BIT(_t1) \ + SET_DBTR_BIT(_t1, RISCV_DBTR_MC6_LOAD_BIT) + +#define RISCV_DBTR_SET_MC6_STORE_BIT(_t1) \ + SET_DBTR_BIT(_t1, RISCV_DBTR_MC6_STORE_BIT) + +#define RISCV_DBTR_SET_MC6_SIZE(_t1, _val) \ + ({ \ + typeof(_t1) (mc6szt1) =3D (_t1); \ + (mc6szt1) &=3D ~RISCV_DBTR_MC6_SIZE_BIT_MASK; \ + (mc6szt1) |=3D (((_val) << RISCV_DBTR_MC6_SIZE_BIT) \ + & RISCV_DBTR_MC6_SIZE_BIT_MASK); \ + (mc6szt1); \ + }) + +struct arch_hw_breakpoint { + unsigned long address; + unsigned long len; + unsigned int type; + + /* Trigger configuration data */ + unsigned long tdata1; + unsigned long tdata2; + unsigned long tdata3; +}; + +struct perf_event_attr; +struct notifier_block; +struct perf_event; +struct pt_regs; + +int hw_breakpoint_slots(int type); +int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw); +int hw_breakpoint_arch_parse(struct perf_event *bp, + const struct perf_event_attr *attr, + struct arch_hw_breakpoint *hw); +int hw_breakpoint_exceptions_notify(struct notifier_block *unused, + unsigned long val, void *data); + +void arch_enable_hw_breakpoint(struct perf_event *bp); +void arch_update_hw_breakpoint(struct perf_event *bp); +void arch_disable_hw_breakpoint(struct perf_event *bp); +int arch_install_hw_breakpoint(struct perf_event *bp); +void arch_uninstall_hw_breakpoint(struct perf_event *bp); +void hw_breakpoint_pmu_read(struct perf_event *bp); + +#else + +#endif /* CONFIG_HAVE_HW_BREAKPOINT */ +#endif /* __RISCV_HW_BREAKPOINT_H */ diff --git a/arch/riscv/include/asm/kdebug.h b/arch/riscv/include/asm/kdebu= g.h index 85ac00411f6e..53e989781aa1 100644 --- a/arch/riscv/include/asm/kdebug.h +++ b/arch/riscv/include/asm/kdebug.h @@ -6,7 +6,8 @@ enum die_val { DIE_UNUSED, DIE_TRAP, - DIE_OOPS + DIE_OOPS, + DIE_DEBUG }; =20 #endif diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index ebe1c3588177..a4197c3c36e8 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -100,6 +100,7 @@ obj-$(CONFIG_DYNAMIC_FTRACE) +=3D mcount-dyn.o =20 obj-$(CONFIG_PERF_EVENTS) +=3D perf_callchain.o obj-$(CONFIG_HAVE_PERF_REGS) +=3D perf_regs.o +obj-$(CONFIG_HAVE_HW_BREAKPOINT) +=3D hw_breakpoint.o obj-$(CONFIG_RISCV_SBI) +=3D sbi.o sbi_ecall.o ifeq ($(CONFIG_RISCV_SBI), y) obj-$(CONFIG_SMP) +=3D sbi-ipi.o diff --git a/arch/riscv/kernel/hw_breakpoint.c b/arch/riscv/kernel/hw_break= point.c new file mode 100644 index 000000000000..c2ab5e6008e7 --- /dev/null +++ b/arch/riscv/kernel/hw_breakpoint.c @@ -0,0 +1,746 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Qualcomm Technologies, Inc. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* Registered per-cpu bp/wp */ +static DEFINE_PER_CPU(struct perf_event *, pcpu_hw_bp_events[RISCV_HW_BP_N= UM_MAX]); +static DEFINE_PER_CPU(unsigned long, ecall_lock_flags); +static DEFINE_PER_CPU(raw_spinlock_t, ecall_lock); + +/* Per-cpu shared memory between S and M mode */ +static union sbi_dbtr_shmem_entry __percpu *sbi_dbtr_shmem; + +/* number of debug triggers on this cpu . */ +static int dbtr_total_num __ro_after_init; +static int dbtr_type __ro_after_init; +static int dbtr_init __ro_after_init; + +#define MEM_HI(_m) (0UL) +#define MEM_LO(_m) ((unsigned long)(_m)) + +static int arch_smp_setup_sbi_shmem(unsigned int cpu) +{ + union sbi_dbtr_shmem_entry *dbtr_shmem; + phys_addr_t shmem_pa; + struct sbiret ret; + + dbtr_shmem =3D per_cpu_ptr(sbi_dbtr_shmem, cpu); + + shmem_pa =3D per_cpu_ptr_to_phys(dbtr_shmem); + + ret =3D sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_SETUP_SHMEM, + MEM_LO(shmem_pa), MEM_HI(shmem_pa), 0, 0, 0, 0); + + if (ret.error) { + pr_warn("%s: failed to setup shared memory. error: %ld\n", + __func__, ret.error); + return sbi_err_map_linux_errno(ret.error); + } + + pr_info("CPU %d: HW Breakpoint shared memory registered.\n", cpu); + + return 0; +} + +static int arch_smp_teardown_sbi_shmem(unsigned int cpu) +{ + struct sbiret ret; + + /* Disable shared memory */ + ret =3D sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_SETUP_SHMEM, + SBI_SHMEM_DISABLE, SBI_SHMEM_DISABLE, 0, 0, 0, 0); + + if (ret.error) + pr_warn("%s: failed to disable shared memory. error: %ld\n", + __func__, ret.error); + else + pr_info("CPU %d: HW Breakpoint shared memory disabled.\n", cpu); + + return 0; +} + +static void init_sbi_dbtr(void) +{ + unsigned long tdata1; + struct sbiret ret; + + if (sbi_probe_extension(SBI_EXT_DBTR) <=3D 0) { + pr_warn("SBI_EXT_DBTR is not supported\n"); + dbtr_total_num =3D 0; + goto done; + } + + ret =3D sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_NUM_TRIGGERS, + 0, 0, 0, 0, 0, 0); + if (ret.error) { + pr_warn("Failed to detect triggers\n"); + dbtr_total_num =3D 0; + goto done; + } + + tdata1 =3D 0; + tdata1 =3D RISCV_DBTR_SET_TDATA1_TYPE(tdata1, RISCV_DBTR_TRIG_MCONTROL6); + + ret =3D sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_NUM_TRIGGERS, + tdata1, 0, 0, 0, 0, 0); + if (ret.error) { + pr_warn("Failed to detect mcontrol6 triggers\n"); + } else if (!ret.value) { + pr_warn("Type 6 triggers not available\n"); + } else { + dbtr_total_num =3D min_t(unsigned long, ret.value, + RISCV_HW_BP_NUM_MAX); + dbtr_type =3D RISCV_DBTR_TRIG_MCONTROL6; + pr_warn("Mcontrol6 trigger available.\n"); + goto done; + } + + /* fallback to type 2 triggers if type 6 is not available */ + + tdata1 =3D 0; + tdata1 =3D RISCV_DBTR_SET_TDATA1_TYPE(tdata1, RISCV_DBTR_TRIG_MCONTROL); + + ret =3D sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_NUM_TRIGGERS, + tdata1, 0, 0, 0, 0, 0); + if (ret.error) { + pr_warn("Failed to detect mcontrol triggers\n"); + } else if (!ret.value) { + pr_warn("Type 2 triggers not available\n"); + } else { + dbtr_total_num =3D min_t(unsigned long, ret.value, + RISCV_HW_BP_NUM_MAX); + dbtr_type =3D RISCV_DBTR_TRIG_MCONTROL; + goto done; + } + +done: + dbtr_init =3D 1; +} + +int hw_breakpoint_slots(int type) +{ + /* + * We can be called early, so don't rely on + * static variables being initialised. + */ + + if (!dbtr_init) + init_sbi_dbtr(); + + return dbtr_total_num; +} + +int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw) +{ + unsigned int len; + unsigned long va; + + va =3D hw->address; + len =3D hw->len; + + return (va >=3D TASK_SIZE) && ((va + len - 1) >=3D TASK_SIZE); +} + +static int rv_init_mcontrol_trigger(const struct perf_event_attr *attr, + struct arch_hw_breakpoint *hw) +{ + switch (attr->bp_type) { + case HW_BREAKPOINT_X: + hw->type =3D RISCV_DBTR_EXEC; + RISCV_DBTR_SET_MC_EXEC_BIT(hw->tdata1); + break; + case HW_BREAKPOINT_R: + hw->type =3D RISCV_DBTR_LOAD; + RISCV_DBTR_SET_MC_LOAD_BIT(hw->tdata1); + break; + case HW_BREAKPOINT_W: + hw->type =3D RISCV_DBTR_STORE; + RISCV_DBTR_SET_MC_STORE_BIT(hw->tdata1); + break; + case HW_BREAKPOINT_RW: + hw->type =3D RISCV_DBTR_LDST; + RISCV_DBTR_SET_MC_LOAD_BIT(hw->tdata1); + RISCV_DBTR_SET_MC_STORE_BIT(hw->tdata1); + break; + default: + return -EINVAL; + } + + if (attr->bp_type =3D=3D HW_BREAKPOINT_X) { + /* + * Userspace debuggers can request execute breakpoints with + * bp_len =3D=3D 2 for compressed/non-aligned instruction + * addresses. Program execute triggers with "match any size" + * to avoid missing valid instruction fetches. + */ + hw->len =3D 0; + hw->tdata1 =3D RISCV_DBTR_SET_MC_SIZELO(hw->tdata1, 0); + hw->tdata1 =3D RISCV_DBTR_SET_MC_SIZEHI(hw->tdata1, 0); + } else { + switch (attr->bp_len) { + case HW_BREAKPOINT_LEN_1: + hw->len =3D 1; + hw->tdata1 =3D RISCV_DBTR_SET_MC_SIZELO(hw->tdata1, 1); + break; + case HW_BREAKPOINT_LEN_2: + hw->len =3D 2; + hw->tdata1 =3D RISCV_DBTR_SET_MC_SIZELO(hw->tdata1, 2); + break; + case HW_BREAKPOINT_LEN_4: + hw->len =3D 4; + hw->tdata1 =3D RISCV_DBTR_SET_MC_SIZELO(hw->tdata1, 3); + break; +#if __riscv_xlen >=3D 64 + case HW_BREAKPOINT_LEN_8: + hw->len =3D 8; + hw->tdata1 =3D RISCV_DBTR_SET_MC_SIZELO(hw->tdata1, 1); + hw->tdata1 =3D RISCV_DBTR_SET_MC_SIZEHI(hw->tdata1, 1); + break; +#endif + /* Set to match any size */ + default: + hw->len =3D 0; + hw->tdata1 =3D RISCV_DBTR_SET_MC_SIZELO(hw->tdata1, 0); + hw->tdata1 =3D RISCV_DBTR_SET_MC_SIZEHI(hw->tdata1, 0); + break; + } + } + + hw->tdata1 =3D RISCV_DBTR_SET_MC_TYPE(hw->tdata1, RISCV_DBTR_TRIG_MCONTRO= L); + + CLEAR_DBTR_BIT(hw->tdata1, RISCV_DBTR_MC_DMODE_BIT); + CLEAR_DBTR_BIT(hw->tdata1, RISCV_DBTR_MC_TIMING_BIT); + CLEAR_DBTR_BIT(hw->tdata1, RISCV_DBTR_MC_SELECT_BIT); + CLEAR_DBTR_BIT(hw->tdata1, RISCV_DBTR_MC_ACTION_BIT); + CLEAR_DBTR_BIT(hw->tdata1, RISCV_DBTR_MC_CHAIN_BIT); + CLEAR_DBTR_BIT(hw->tdata1, RISCV_DBTR_MC_MATCH_BIT); + CLEAR_DBTR_BIT(hw->tdata1, RISCV_DBTR_MC_M_BIT); + + /* + * Match only the trigger's actual privilege-mode target. Setting + * both bits makes the kernel's own S-mode uaccess (e.g. SUM-enabled + * loads in strncpy_from_user()) spuriously fire a user-space watch. + */ + if (arch_check_bp_in_kernelspace(hw)) + SET_DBTR_BIT(hw->tdata1, RISCV_DBTR_MC_S_BIT); + else + SET_DBTR_BIT(hw->tdata1, RISCV_DBTR_MC_U_BIT); + + return 0; +} + +static int rv_init_mcontrol6_trigger(const struct perf_event_attr *attr, + struct arch_hw_breakpoint *hw) +{ + switch (attr->bp_type) { + case HW_BREAKPOINT_X: + hw->type =3D RISCV_DBTR_EXEC; + RISCV_DBTR_SET_MC6_EXEC_BIT(hw->tdata1); + break; + case HW_BREAKPOINT_R: + hw->type =3D RISCV_DBTR_LOAD; + RISCV_DBTR_SET_MC6_LOAD_BIT(hw->tdata1); + break; + case HW_BREAKPOINT_W: + hw->type =3D RISCV_DBTR_STORE; + RISCV_DBTR_SET_MC6_STORE_BIT(hw->tdata1); + break; + case HW_BREAKPOINT_RW: + hw->type =3D RISCV_DBTR_LDST; + RISCV_DBTR_SET_MC6_STORE_BIT(hw->tdata1); + RISCV_DBTR_SET_MC6_LOAD_BIT(hw->tdata1); + break; + default: + return -EINVAL; + } + + if (attr->bp_type =3D=3D HW_BREAKPOINT_X) { + /* See rv_init_mcontrol_trigger() for rationale. */ + hw->len =3D 0; + hw->tdata1 =3D RISCV_DBTR_SET_MC6_SIZE(hw->tdata1, 0); + } else { + switch (attr->bp_len) { + case HW_BREAKPOINT_LEN_1: + hw->len =3D 1; + hw->tdata1 =3D RISCV_DBTR_SET_MC6_SIZE(hw->tdata1, 1); + break; + case HW_BREAKPOINT_LEN_2: + hw->len =3D 2; + hw->tdata1 =3D RISCV_DBTR_SET_MC6_SIZE(hw->tdata1, 2); + break; + case HW_BREAKPOINT_LEN_4: + hw->len =3D 4; + hw->tdata1 =3D RISCV_DBTR_SET_MC6_SIZE(hw->tdata1, 3); + break; +#if __riscv_xlen >=3D 64 + case HW_BREAKPOINT_LEN_8: + hw->len =3D 8; + hw->tdata1 =3D RISCV_DBTR_SET_MC6_SIZE(hw->tdata1, 5); + break; +#endif + /* Set to match any size */ + default: + hw->len =3D 0; + hw->tdata1 =3D RISCV_DBTR_SET_MC6_SIZE(hw->tdata1, 0); + } + } + + hw->tdata1 =3D RISCV_DBTR_SET_MC6_TYPE(hw->tdata1, RISCV_DBTR_TRIG_MCONTR= OL6); + + CLEAR_DBTR_BIT(hw->tdata1, RISCV_DBTR_MC6_DMODE_BIT); + CLEAR_DBTR_BIT(hw->tdata1, RISCV_DBTR_MC6_TIMING_BIT); + CLEAR_DBTR_BIT(hw->tdata1, RISCV_DBTR_MC6_SELECT_BIT); + CLEAR_DBTR_BIT(hw->tdata1, RISCV_DBTR_MC6_ACTION_BIT); + CLEAR_DBTR_BIT(hw->tdata1, RISCV_DBTR_MC6_CHAIN_BIT); + CLEAR_DBTR_BIT(hw->tdata1, RISCV_DBTR_MC6_MATCH_BIT); + CLEAR_DBTR_BIT(hw->tdata1, RISCV_DBTR_MC6_M_BIT); + CLEAR_DBTR_BIT(hw->tdata1, RISCV_DBTR_MC6_VS_BIT); + CLEAR_DBTR_BIT(hw->tdata1, RISCV_DBTR_MC6_VU_BIT); + + /* See rv_init_mcontrol_trigger() for rationale. */ + if (arch_check_bp_in_kernelspace(hw)) + SET_DBTR_BIT(hw->tdata1, RISCV_DBTR_MC6_S_BIT); + else + SET_DBTR_BIT(hw->tdata1, RISCV_DBTR_MC6_U_BIT); + + return 0; +} + +int hw_breakpoint_arch_parse(struct perf_event *bp, + const struct perf_event_attr *attr, + struct arch_hw_breakpoint *hw) +{ + int ret; + + /* Breakpoint address */ + hw->address =3D attr->bp_addr; + hw->tdata2 =3D attr->bp_addr; + hw->tdata3 =3D 0x0; + + switch (dbtr_type) { + case RISCV_DBTR_TRIG_MCONTROL: + ret =3D rv_init_mcontrol_trigger(attr, hw); + break; + case RISCV_DBTR_TRIG_MCONTROL6: + ret =3D rv_init_mcontrol6_trigger(attr, hw); + break; + default: + pr_warn("Unsupported trigger type\n"); + ret =3D -EOPNOTSUPP; + break; + } + + return ret; +} + +/* + * 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 + * this; hardware only ever sets it). Returns the RISCV_DBTR_MC6_HIT_* + * value read (RISCV_DBTR_MC6_HIT_FALSE if unimplemented or unfired). + */ +static unsigned int mc6_read_and_clear_hit(int idx) +{ + union sbi_dbtr_shmem_entry *shmem =3D this_cpu_ptr(sbi_dbtr_shmem); + struct sbi_dbtr_data_msg *xmit; + unsigned long tdata1, tdata2, tdata3; + struct sbiret ret; + unsigned int hit; + + raw_spin_lock_irqsave(this_cpu_ptr(&ecall_lock), + *this_cpu_ptr(&ecall_lock_flags)); + + ret =3D sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_TRIG_READ, idx, 1, 0, 0, 0, = 0); + if (ret.error) { + pr_warn("Failed to read trigger %d. error: %ld\n", idx, ret.error); + hit =3D RISCV_DBTR_MC6_HIT_FALSE; + goto out; + } + + tdata1 =3D le_to_cpu(shmem->data.tdata1); + hit =3D RISCV_DBTR_MC6_GET_HIT(tdata1); + if (hit =3D=3D RISCV_DBTR_MC6_HIT_FALSE) + goto out; + + tdata2 =3D le_to_cpu(shmem->data.tdata2); + tdata3 =3D le_to_cpu(shmem->data.tdata3); + RISCV_DBTR_MC6_CLEAR_HIT(tdata1); + + xmit =3D &shmem->data; + xmit->tdata1 =3D cpu_to_le(tdata1); + xmit->tdata2 =3D cpu_to_le(tdata2); + xmit->tdata3 =3D cpu_to_le(tdata3); + + ret =3D sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_TRIG_UPDATE, idx, 1, 0, 0, 0= , 0); + if (ret.error) + pr_warn("Failed to clear hit bits on trigger %d. error: %ld\n", + idx, ret.error); + +out: + raw_spin_unlock_irqrestore(this_cpu_ptr(&ecall_lock), + *this_cpu_ptr(&ecall_lock_flags)); + return hit; +} + +/* + * HW Breakpoint/watchpoint handler + */ +static int hw_breakpoint_handler(struct die_args *args) +{ + int ret =3D NOTIFY_DONE; + struct arch_hw_breakpoint *bp; + struct perf_event *event; + int i; + + for (i =3D 0; i < dbtr_total_num; i++) { + event =3D this_cpu_read(pcpu_hw_bp_events[i]); + if (!event) + continue; + + bp =3D counter_arch_bp(event); + switch (bp->type) { + /* Breakpoint */ + case HW_BREAKPOINT_X: + { + bool hit =3D bp->address =3D=3D args->regs->epc; + + if (!hit && dbtr_type =3D=3D RISCV_DBTR_TRIG_MCONTROL6) + hit =3D mc6_read_and_clear_hit(i) !=3D RISCV_DBTR_MC6_HIT_FALSE; + + if (hit) { + perf_bp_event(event, args->regs); + ret =3D NOTIFY_STOP; + } + break; + } + + /* Watchpoint */ + case HW_BREAKPOINT_W: + case HW_BREAKPOINT_R: + case HW_BREAKPOINT_RW: + { + unsigned long stval =3D args->regs->badaddr; + unsigned long bp_start =3D bp->address; + unsigned long bp_len =3D bp->len ?: 1; + unsigned long bp_end =3D bp_start + bp_len - 1; + unsigned long stval_end =3D stval + sizeof(long) - 1; + bool hit =3D false; + + if (bp_end < bp_start) + bp_end =3D ~0UL; + if (stval_end < stval) + stval_end =3D ~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 =3D=3D 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 =3D this_cpu_ptr(sbi_dbtr_shmem); + sret =3D sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_TRIG_READ, + i, 1, 0, 0, 0, 0); + if (!sret.error) { + tdata1 =3D le_to_cpu(shmem->data.tdata1); + hit =3D !!(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 =3D=3D RISCV_DBTR_TRIG_MCONTROL6) { + hit =3D mc6_read_and_clear_hit(i) !=3D 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 >=3D bp_start && stval <=3D bp_end) || + (bp_start >=3D stval && bp_start <=3D stval_end)) { + perf_bp_event(event, args->regs); + ret =3D NOTIFY_STOP; + } + break; + } + + default: + pr_warn("Unknown type: %u\n", bp->type); + break; + } + } + + return ret; +} + +int hw_breakpoint_exceptions_notify(struct notifier_block *unused, + unsigned long val, void *data) +{ + if (val !=3D DIE_DEBUG) + return NOTIFY_DONE; + + return hw_breakpoint_handler(data); +} + +/* atomic: counter->ctx->lock is held */ +int arch_install_hw_breakpoint(struct perf_event *event) +{ + struct arch_hw_breakpoint *bp =3D counter_arch_bp(event); + union sbi_dbtr_shmem_entry *shmem =3D this_cpu_ptr(sbi_dbtr_shmem); + struct sbi_dbtr_data_msg *xmit; + struct sbi_dbtr_id_msg *recv; + struct perf_event **slot; + unsigned long idx; + struct sbiret ret; + int err =3D 0; + + raw_spin_lock_irqsave(this_cpu_ptr(&ecall_lock), + *this_cpu_ptr(&ecall_lock_flags)); + + xmit =3D &shmem->data; + recv =3D &shmem->id; + xmit->tdata1 =3D cpu_to_le(bp->tdata1); + xmit->tdata2 =3D cpu_to_le(bp->tdata2); + xmit->tdata3 =3D cpu_to_le(bp->tdata3); + + ret =3D sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_TRIG_INSTALL, + 1, 0, 0, 0, 0, 0); + + if (ret.error) { + pr_warn("Failed to install trigger\n"); + err =3D sbi_err_map_linux_errno(ret.error); + goto done; + } + + idx =3D le_to_cpu(recv->idx); + if (idx >=3D dbtr_total_num) { + pr_warn("Invalid trigger index %lu\n", idx); + err =3D -EINVAL; + goto done; + } + + slot =3D this_cpu_ptr(&pcpu_hw_bp_events[idx]); + if (*slot) { + pr_warn("Slot %lu is in use\n", idx); + err =3D -EBUSY; + goto done; + } + + /* Save the event - to be looked up in handler */ + *slot =3D event; + +done: + raw_spin_unlock_irqrestore(this_cpu_ptr(&ecall_lock), + *this_cpu_ptr(&ecall_lock_flags)); + return err; +} + +/* atomic: counter->ctx->lock is held */ +void arch_uninstall_hw_breakpoint(struct perf_event *event) +{ + struct sbiret ret; + int i; + + raw_spin_lock_irqsave(this_cpu_ptr(&ecall_lock), + *this_cpu_ptr(&ecall_lock_flags)); + + for (i =3D 0; i < dbtr_total_num; i++) { + struct perf_event **slot =3D this_cpu_ptr(&pcpu_hw_bp_events[i]); + + if (*slot =3D=3D event) { + *slot =3D NULL; + break; + } + } + + if (i =3D=3D dbtr_total_num) { + pr_warn("Breakpoint not installed.\n"); + goto out; + } + + ret =3D sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_TRIG_UNINSTALL, + i, 1, 0, 0, 0, 0); + + if (ret.error) { + pr_warn("Failed to uninstall trigger %d.\n", i); + goto out; + } + + out: + raw_spin_unlock_irqrestore(this_cpu_ptr(&ecall_lock), + *this_cpu_ptr(&ecall_lock_flags)); +} + +void arch_enable_hw_breakpoint(struct perf_event *event) +{ + struct sbiret ret; + int i; + struct perf_event **slot; + + raw_spin_lock_irqsave(this_cpu_ptr(&ecall_lock), + *this_cpu_ptr(&ecall_lock_flags)); + + for (i =3D 0; i < dbtr_total_num; i++) { + slot =3D this_cpu_ptr(&pcpu_hw_bp_events[i]); + + if (*slot =3D=3D event) + break; + } + + if (i =3D=3D dbtr_total_num) { + pr_warn("Breakpoint not installed.\n"); + goto out; + } + + ret =3D sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_TRIG_ENABLE, + i, 1, 0, 0, 0, 0); + + if (ret.error) { + pr_warn("Failed to install trigger %d\n", i); + goto out; + } + + out: + raw_spin_unlock_irqrestore(this_cpu_ptr(&ecall_lock), + *this_cpu_ptr(&ecall_lock_flags)); +} +EXPORT_SYMBOL_GPL(arch_enable_hw_breakpoint); + +void arch_update_hw_breakpoint(struct perf_event *event) +{ + struct arch_hw_breakpoint *bp =3D counter_arch_bp(event); + union sbi_dbtr_shmem_entry *shmem =3D this_cpu_ptr(sbi_dbtr_shmem); + struct sbi_dbtr_data_msg *xmit; + struct sbi_dbtr_id_msg *id; + struct perf_event **slot; + struct sbiret ret; + int i; + + for (i =3D 0; i < dbtr_total_num; i++) { + slot =3D this_cpu_ptr(&pcpu_hw_bp_events[i]); + + if (*slot =3D=3D event) + break; + } + + if (i =3D=3D dbtr_total_num) { + pr_warn("Breakpoint not installed.\n"); + return; + } + + raw_spin_lock_irqsave(this_cpu_ptr(&ecall_lock), + *this_cpu_ptr(&ecall_lock_flags)); + + id =3D &shmem->id; + xmit =3D &shmem->data; + id->idx =3D cpu_to_le(i); + xmit->tdata1 =3D cpu_to_le(bp->tdata1); + xmit->tdata2 =3D cpu_to_le(bp->tdata2); + xmit->tdata3 =3D cpu_to_le(bp->tdata3); + + ret =3D sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_TRIG_UPDATE, + 1, 0, 0, 0, 0, 0); + if (ret.error) + pr_warn("Failed to update trigger %d.\n", i); + + raw_spin_unlock_irqrestore(this_cpu_ptr(&ecall_lock), + *this_cpu_ptr(&ecall_lock_flags)); +} +EXPORT_SYMBOL_GPL(arch_update_hw_breakpoint); + +void arch_disable_hw_breakpoint(struct perf_event *event) +{ + struct perf_event **slot; + struct sbiret ret; + int i; + + for (i =3D 0; i < dbtr_total_num; i++) { + slot =3D this_cpu_ptr(&pcpu_hw_bp_events[i]); + + if (*slot =3D=3D event) + break; + } + + if (i =3D=3D dbtr_total_num) { + pr_warn("Breakpoint not installed.\n"); + return; + } + + ret =3D sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_TRIG_DISABLE, + i, 1, 0, 0, 0, 0); + + if (ret.error) { + pr_warn("Failed to uninstall trigger %d.\n", i); + return; + } +} +EXPORT_SYMBOL_GPL(arch_disable_hw_breakpoint); + +void hw_breakpoint_pmu_read(struct perf_event *bp) { } + +void flush_ptrace_hw_breakpoint(struct task_struct *tsk) { } + +static int __init arch_hw_breakpoint_init(void) +{ + unsigned int cpu; + int rc =3D 0; + + for_each_possible_cpu(cpu) + raw_spin_lock_init(&per_cpu(ecall_lock, cpu)); + + if (!dbtr_init) + init_sbi_dbtr(); + + if (dbtr_total_num) { + pr_info("Total number of type %d triggers: %u\n", + dbtr_type, dbtr_total_num); + } else { + pr_info("No hardware triggers available\n"); + goto out; + } + + /* Allocate per-cpu shared memory */ + sbi_dbtr_shmem =3D __alloc_percpu(sizeof(*sbi_dbtr_shmem) * dbtr_total_nu= m, + PAGE_SIZE); + + if (!sbi_dbtr_shmem) { + pr_warn("Failed to allocate shared memory.\n"); + rc =3D -ENOMEM; + goto out; + } + + /* Hotplug handler to register/unregister shared memory with SBI */ + rc =3D cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, + "riscv/hw_breakpoint:prepare", + arch_smp_setup_sbi_shmem, + arch_smp_teardown_sbi_shmem); + + if (rc < 0) { + pr_warn("Failed to setup CPU hotplug state\n"); + free_percpu(sbi_dbtr_shmem); + return rc; + } + out: + return rc; +} +arch_initcall(arch_hw_breakpoint_init); diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c index f8292adda099..1b9ccc0b6b8d 100644 --- a/arch/riscv/kernel/traps.c +++ b/arch/riscv/kernel/traps.c @@ -287,6 +287,12 @@ void handle_break(struct pt_regs *regs) if (probe_breakpoint_handler(regs)) return; =20 +#ifdef CONFIG_HAVE_HW_BREAKPOINT + if (notify_die(DIE_DEBUG, "EBREAK", regs, 0, regs->cause, SIGTRAP) + =3D=3D NOTIFY_STOP) + return; +#endif + current->thread.bad_cause =3D regs->cause; =20 if (user_mode(regs)) --=20 2.43.0 From nobody Fri Oct 2 08:26:24 2026 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.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 B93713F104C for ; Wed, 30 Sep 2026 06:39:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790750384; cv=none; b=hHn2u3IwgObUgbfnFraaZH3zqSB/qODQrkg1ejk3jUjxAZFU6ITbu4X1GSCof8eb8hnQL4PLfSbYoH538L79MjbJFkF/89LK7XVtTmasIoUKQRqZEVC8mxWaDh0M0TxO2tKEIm4C1LyXltbXPphQXLRLrQ4u1BrrSrIgwEw9qlo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790750384; c=relaxed/simple; bh=pMPMtfZB8VBITwn9uHDlV1BkaeFTtWFb4ZIRKS14VJ0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=XHkspU62EOwCR3ZjiMSH2P4E0yYxWxQdiPMkbylCzGTVKQLwpDbYe6g48WahNL1z4A2wAXD4gByCHWm1kr37pCSJIefdMDWReFFkopeJf/ueCsy0AeU/zxIlYrHQlTXku6q1EfJky9lT2mdRhZLW5VqqsPR6HYcQd5ypX7+SFbo= 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=h0PiS34F; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=BSXp0VX6; arc=none smtp.client-ip=205.220.180.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="h0PiS34F"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="BSXp0VX6" Received: from pps.filterd (m0279872.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 68U1AVvS1264150 for ; Wed, 30 Sep 2026 06:39:41 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=JDL8L5Ufeca w9rYAA5nxqMzomuFEvy76+Mr0sJjLj5Y=; b=h0PiS34F0bnhUpjKoN3WG2jxjFS vsDNMhlyfHLJx5cCT6oQxCVNS7e4uY815j/HS2XzKMojEowDQrI2BTT+rcN+QzkU yXmEJ0OmQFGEYlqQ93XexIe2HevxGP3NkFNOPhGbnZ3i/w4e/YtLKGMuChFll4cc rKFZSaOmZzFBImzSeatw4PKLiTr2ocJebm0JXmm7+QGrTh6TddkVUEoIiHG6On7I VB9dwRbBheiJFUbNCM78OOynRygywDrkKqjLajgo4oYwCcVudP8vLNwvEfs9qQC3 zWdoqMUSpAkLAQ3Soc9SGFGRdG03ktpbBWHb74PLRbROJ7hGQF1gLIwfRXw== 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 4h0rheh8xn-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Wed, 30 Sep 2026 06:39:41 +0000 (GMT) Received: by mail-dy1-f197.google.com with SMTP id 5a478bee46e88-342b66c0b06so1890465eec.0 for ; Tue, 29 Sep 2026 23:39:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1790750381; x=1791355181; 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=JDL8L5Ufecaw9rYAA5nxqMzomuFEvy76+Mr0sJjLj5Y=; b=BSXp0VX6T0e+GbdR7sKr3Ggfqz5Kb+VdA0Y9bXa8UiH8LBc2ZsIS5Bll6c8VhyOh29 9KTsYmYt0vzq450mXqE6kc4fEaCbyGChWJbrkgIslUy86zJnu1MwBax2TkB1apK+Uz/I d9RJ7wh2FJuB7KBTZZmGxVTpDwMft0+tuR9JpFnACGS6VxF1ePo6v80EJQHe3DtFSOAi otUvNtg6IqNvHNKUZVH24OqPogk3ZXOBlNuZp1tFHDYIBPaL6Pi8m5kZgAsdyNbjbeCP CJmhkO8GulaxQIiRsWLeFpn0e7DBR4dWp3v6qv8K/F0PgqeP6noCiXiG37xbdiWpRavi oSeA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790750381; x=1791355181; 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=JDL8L5Ufecaw9rYAA5nxqMzomuFEvy76+Mr0sJjLj5Y=; b=buw094qDbkMGwa8jq3LD/SAXvRS1Qug3isVvnX/wOEe/Z6PDmUTmlsT8xxX9Xd6IB1 J6LvD7dE1xlfa3r9BoFlF21OrkIvVUPAFWPFAZnHmZuTQ046kH8LcgtjvMlT9rahzf2z No4Ekf5mRi5egOwCO0UIsG0eMwu20Luw074Gm0kW+e9zIJg+XkVZwt6OQRuGvMTxtXcb 1QHNLmXAMUB7+8G/eXaFHSKteSN+liFNx4VcouNi/qxHKtqI5NHRl+79eqqGELl/fjTb ZuQThITw4b2SPRzo1dEZBCxzCWVPx8GulFu+19DgP0saAzxF3m8ZchrCKDUI0zGAfNiW rqTw== X-Gm-Message-State: AFuF++mmT8ZPQ65mWZiwsaUnkfJauS7Zr2pZRALd1uFqi0oFSP5AkRg1 Bu+ETvfbZD0wcAFS/30L1Ep762QSX10alXQNPd6LZtWgK9oy2VRNVHnLMNd1BTfYIvkLotPCvvO ntJAGirifWpNkTyEkGECsJSJO1xHRn4+7YgtGnkzbtQj0j5mXP9hIg4npXOzIzF/APW15MK4WDJ o= X-Gm-Gg: AYBFou1K9uWA29XmyUsUNaXPwdruKpNK4BJxYuMOiu0mzfkgjPW9bY5ud6jIakvpTdc 9duHQzLRmbicMU6ltrgGPOz35ed728PON/f7RAMNL9AqahtZFJHQKcLV3y9dvJ3Elr4cVQObLJc HgEf0DA6Rmm420dj/hkK3FrIZTXCzm3atwCeLGp04ma78HXg8cxVP9Q3I9ChKHVa9h6aK5KaBF8 uU+K8Wlpwv8Kt5WUUq20YWxvuzt0sJ9xu7xkno/YivisHvaViNroOjXH4Mg9oO1LU3Bo8VGUgcc CWAQC8pLL3hboUwVEbYq1gokzCJ9NcqKeRZyzd+9VBYAjI/EZXh75Qu4IpONZN8S73RHFM015eZ AY81Flr/vD/NlL2fm3JXaYOp1SaFRLANtFmvHl6GlGvFC+VNJ3smQp6l5X1g60msTmDOM4gKviX 9Er7sKLVrIqzJXvm3T7in4DYvf X-Received: by 2002:a05:7022:b902:b0:147:9ad0:cf15 with SMTP id a92af1059eb24-14d399e6230mr296178c88.22.1790750380509; Tue, 29 Sep 2026 23:39:40 -0700 (PDT) X-Received: by 2002:a05:7022:b902:b0:147:9ad0:cf15 with SMTP id a92af1059eb24-14d399e6230mr296154c88.22.1790750379906; Tue, 29 Sep 2026 23:39:39 -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.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 29 Sep 2026 23:39:39 -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 2/8] riscv: Add breakpoint and watchpoint test for riscv Date: Wed, 30 Sep 2026 12:09:13 +0530 Message-ID: <20260930063919.608911-3-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: quoted-printable X-Proofpoint-GUID: O_nda8ir2cVma0FD0amIMBIFofZAjxWA X-Proofpoint-ORIG-GUID: O_nda8ir2cVma0FD0amIMBIFofZAjxWA X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTMwMDAyNiBTYWx0ZWRfX71nhWMc8BlKH plyMg6cV5d7LM9I15lPKJvXPu26pty/6aCMV2Lm8Zytdr/u4PNPYibXakLjwJO9tzfKVDxsoV+S JoDuiQzTRtUfKAoPmDxWayUwl41ZERN0y5UYurd6Cyz761AlZ1oTz01lFqidPlY/OStdtCfDAYu WsB2zJyYrfhP48qlGck5oE/IGJLxuKJiy0+biH8gqKJOm1MT8vFKMQd/2JiUBYoi109UNBUs8ch C1G36YSe2+71X4ymKPynaIwKTtV7UzGjN4srOQtJtZT/7dqPmPpfX99FJiwcUsoBXV1du1eEyvd p0vb9toJka9i4H5lKen+OZR9DJ4IX6acgut5zbG97rFToCnb5tBkT/NoiI384+hH8LXdeO3dHyQ N2BlMBSOkrc0eTbcgH7FUNDRkOhLhkEZZBoDNxZjqY6vRkydjYuJxroHFX5CVU24DJWYddQXf8D nIQTDqAUehxuREqt/+g== X-Proofpoint-Spam-Info: AW1haW4tMjYwOTMwMDAyNiBTYWx0ZWRfX14dZs5QpnCT9 yF11Yso3TCO+RzG3AtRiUNUnpUjBCSrV6g/3mH3kpPwGURsm2ajKnjkUJGNsx7b34IBDtB6YJm1 vK3xKGfjOgsuAzoSm0XOsTDiXSzHwq8= X-Authority-Analysis: v=2.4 cv=Tu1zFzXh c=1 sm=1 tr=0 ts=6abcaead 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=yx91gb_oNiZeI1HMLzn7:22 a=EUspDBNiAAAA:8 a=qd3H3YWZb18LjlhzOR0A:9 a=PxkB5W3o20Ba91AHUih5:22 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 impostorscore=0 spamscore=0 malwarescore=0 suspectscore=0 phishscore=0 lowpriorityscore=0 adultscore=0 clxscore=1015 bulkscore=0 priorityscore=1501 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2609040000 definitions=main-2609300026 Content-Type: text/plain; charset="utf-8" Add self test for riscv architecture. It uses ptrace to ptrace framework to set/unset break/watchpoint and uses signals to check triggers. Also add $(KHDR_INCLUDES) to CFLAGS for the riscv test build so the UAPI headers exercised by the test can be located during compilation. Signed-off-by: Himanshu Chauhan --- tools/testing/selftests/breakpoints/Makefile | 5 + .../breakpoints/breakpoint_test_riscv.c | 219 ++++++++++++++++++ 2 files changed, 224 insertions(+) create mode 100644 tools/testing/selftests/breakpoints/breakpoint_test_ris= cv.c diff --git a/tools/testing/selftests/breakpoints/Makefile b/tools/testing/s= elftests/breakpoints/Makefile index 0b8f5acf7c78..b32c56b3c1db 100644 --- a/tools/testing/selftests/breakpoints/Makefile +++ b/tools/testing/selftests/breakpoints/Makefile @@ -12,5 +12,10 @@ ifneq (,$(filter $(ARCH),aarch64 arm64)) TEST_GEN_PROGS +=3D breakpoint_test_arm64 endif =20 +ifneq (,$(filter $(ARCH),riscv)) +CFLAGS +=3D -static $(KHDR_INCLUDES) +TEST_GEN_PROGS +=3D breakpoint_test_riscv +endif + include ../lib.mk =20 diff --git a/tools/testing/selftests/breakpoints/breakpoint_test_riscv.c b/= tools/testing/selftests/breakpoints/breakpoint_test_riscv.c new file mode 100644 index 000000000000..0649940b709e --- /dev/null +++ b/tools/testing/selftests/breakpoints/breakpoint_test_riscv.c @@ -0,0 +1,219 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Qualcomm Technologies, Inc. + * + * Author: Himanshu Chauhan + */ + +#define _GNU_SOURCE +#include /* Definition of PERF_* constants */ +#include /* Definition of HW_* constants */ +#include /* Definition of SYS_* constants */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef noinline +#define noinline __attribute__((noinline)) +#endif + +static int gfd; +sem_t ib_mtx, wp_mtx; +static int bp_triggered, wp_triggered; +static int test_func_sink; +static const int wait_timeout_sec =3D 5; + +int setup_bp(bool is_x, void *addr, int sig) +{ + struct perf_event_attr pe; + int fd; + + memset(&pe, 0, sizeof(struct perf_event_attr)); + pe.type =3D PERF_TYPE_BREAKPOINT; + pe.size =3D sizeof(struct perf_event_attr); + + pe.config =3D 0; + pe.bp_type =3D is_x ? HW_BREAKPOINT_X : HW_BREAKPOINT_W; + pe.bp_addr =3D (unsigned long)addr; + pe.bp_len =3D sizeof(long); + + pe.sample_period =3D 1; + pe.sample_type =3D PERF_SAMPLE_IP; + pe.wakeup_events =3D 1; + + pe.disabled =3D 1; + pe.exclude_kernel =3D 1; + pe.exclude_hv =3D 1; + + fd =3D syscall(SYS_perf_event_open, &pe, 0, -1, -1, 0); + if (fd < 0) { + printf("Failed to open event: %llx\n", pe.config); + return -1; + } + + fcntl(fd, F_SETFL, O_RDWR | O_NONBLOCK | O_ASYNC); + fcntl(fd, F_SETSIG, sig); + fcntl(fd, F_SETOWN, getpid()); + + ioctl(fd, PERF_EVENT_IOC_RESET, 0); + + return fd; +} + +static void sig_handler_bp(int signum, siginfo_t *oh, void *uc) +{ + int ret; + + bp_triggered++; + + printf("Breakpoint triggered!\n"); + ioctl(gfd, PERF_EVENT_IOC_DISABLE, 0); + ret =3D sem_post(&ib_mtx); + if (ret) { + printf("Failed to report BP success\n"); + return; + } +} + +static void sig_handler_wp(int signum, siginfo_t *oh, void *uc) +{ + int ret; + + printf("Watchpoint triggered!\n"); + ioctl(gfd, PERF_EVENT_IOC_DISABLE, 0); + wp_triggered++; + + ret =3D sem_post(&wp_mtx); + + if (ret) { + printf("Failed to report WP success\n"); + return; + } +} + +/* + * Keep a real instruction address for HW execute breakpoints: prevent inl= ining + * and force a visible side effect so the function can't be optimized away. + */ +static noinline void test_func(void) +{ + test_func_sink++; + __asm__ __volatile__("" : : "g" (test_func_sink)); +} + +static int trigger_bp(void) +{ + struct sigaction sa; + + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_sigaction =3D (void *)sig_handler_bp; + sa.sa_flags =3D SA_SIGINFO; + + if (sigaction(SIGIO, &sa, NULL) < 0) { + printf("Failed to setup signal handler\n"); + return -1; + } + + gfd =3D setup_bp(1, test_func, SIGIO); + + if (gfd < 0) { + printf("Failed to setup breakpoint.\n"); + return -1; + } + + ioctl(gfd, PERF_EVENT_IOC_ENABLE, 0); + + test_func(); + + ioctl(gfd, PERF_EVENT_IOC_DISABLE, 0); + + close(gfd); + + return 0; +} + +static int trigger_wp(void) +{ + struct sigaction sa; + unsigned long test_data; + + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_sigaction =3D (void *)sig_handler_wp; + sa.sa_flags =3D SA_SIGINFO; + + if (sigaction(SIGUSR1, &sa, NULL) < 0) { + printf("Failed to setup signal handler\n"); + return -1; + } + + gfd =3D setup_bp(0, &test_data, SIGUSR1); + + if (gfd < 0) { + printf("Failed to setup watchpoint\n"); + return -1; + } + + ioctl(gfd, PERF_EVENT_IOC_ENABLE, 0); + test_data =3D 0xdeadbeef; + ioctl(gfd, PERF_EVENT_IOC_DISABLE, 0); + + return 0; +} + +static int wait_event(sem_t *sem, const char *name) +{ + struct timespec ts; + + if (clock_gettime(CLOCK_REALTIME, &ts)) { + printf("%s: Failed to get current time\n", name); + return -1; + } + + /* + * Deadlock fix: avoid blocking forever on sem_wait() if the breakpoint/ + * watchpoint signal never arrives. Use a bounded wait and fail the test + * on timeout instead. + */ + ts.tv_sec +=3D wait_timeout_sec; + if (!sem_timedwait(sem, &ts)) + return 0; + + if (errno =3D=3D ETIMEDOUT) + printf("%s: Timed out waiting for event\n", name); + else + printf("%s: sem_timedwait() failed with %d\n", name, errno); + + return -1; +} + +int main(int argc, char *argv[]) +{ + sem_init(&ib_mtx, 0, 0); + if (trigger_bp() < 0) + return -1; + if (wait_event(&ib_mtx, "Breakpoint") < 0) + return -1; + + if (bp_triggered) + printf("Breakpoint test passed!\n"); + + sem_init(&wp_mtx, 0, 0); + if (trigger_wp() < 0) + return -1; + if (wait_event(&wp_mtx, "Watchpoint") < 0) + return -1; + + if (wp_triggered) + printf("Watchpoint test passed!\n"); + + return 0; +} --=20 2.43.0 From nobody Fri Oct 2 08:26:24 2026 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.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 83D4E3EFFC3 for ; Wed, 30 Sep 2026 06:39:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790750391; cv=none; b=TAls85l1gk8wP1KD+54t7yr+vml4Ew6iiDkT7YQsPW6UxAGpVNyfzAGQ1++g6cWCRpJ6ac6zzH/eXNgI94baWMYmzdo1XS6zVYId8r4S/qrE3PPdt15N7O1V9yJnE2LoiJVt6J+D6J2+CNHk6hPRtqqIj/6irRgrhn55rvnNcAk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790750391; c=relaxed/simple; bh=SXG3KQkHqWDCzYlucQtCn5BlTDP1qGP1sPjRBJwQ23E=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=EGszfP7EWXUTL+LdNfC1a5X9gP0SZ3m/MP1c8eZavGDbARnkbc9TrPio1/r7mCunkMQjDFb/vxTwLQ1f7pCoDT+NMpEQ/OcCkvf6BGosDmPYerJGSbik6hyiEb3lK8io+uIUAc/cUxGrfUkizCRL0jgdGX5zwRQPI+AU5J2wXTU= 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=FuOPjh3x; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=YccAylti; arc=none smtp.client-ip=205.220.180.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="FuOPjh3x"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="YccAylti" Received: from pps.filterd (m0279872.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 68U1ANDL1264007 for ; Wed, 30 Sep 2026 06:39:47 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=psYL54jmN9y cKhx2nDLaiBlGWatC/van2qwJIYKlQKQ=; b=FuOPjh3xNxFutzUopAcP299xbR4 8/1FNHNEp22sspN0N2/Vlq44e0P4Bdlwt6zZ6JWz88mmoav4BEotJ6u52Iu8SMhK gu/3ihPgHQOret7hiIoWkme9e0/UEuJ+LrZsKswNXz8m3Cm6sPu4W5JMK0fuf/MU O2pv4zRGbXKHRcpO15KsvqK5ewqLYmCPTGu/4OJhxCQvAClnZWY//sa7D2bSzNeY rN8Dnxia5mZdFmw7AobVjeQpvyGIiXHM+DlfiAqe6cQpDPLK4r0gsBRtZsXsXi7o MqCQs/lefKrHwOht9Pcp0CRkyw7GAn2P96okgJRBlStT9+qTbUDl2BrNgDg== Received: from mail-dy1-f198.google.com (mail-dy1-f198.google.com [74.125.82.198]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4h0rheh8y2-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Wed, 30 Sep 2026 06:39:47 +0000 (GMT) Received: by mail-dy1-f198.google.com with SMTP id 5a478bee46e88-34316295d86so8831100eec.0 for ; Tue, 29 Sep 2026 23:39:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1790750386; x=1791355186; 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=psYL54jmN9ycKhx2nDLaiBlGWatC/van2qwJIYKlQKQ=; b=YccAyltiD++J/tsZyI8fafvmnk6OB1Nip1QWe8MbZH9po1RmIWQv5BEVpmOxldXT/U N/QN50hbj4qA2S5/lKr+PiDy+coCShsuCoxQKL7s0HutgPdDNKOuXiN4kBqmRcvxo04H x/BOebbJu+UfWG/PqhN+BaRja/77NUbGsqQ61Rs0sx+8APGRDAx9t6rgc6H3A9gCZe8y j31SQgs/SkOwh3BP33/4hHZbUPjQfVcvRjcXQQOJ01WV7JR7bYtDoXgmFtHvQB7fBBhE YHeqchHMNSl8ce7IsXAYiCuV45ZgCs5Q7bzzJ3KSXhT1UcJER/Icix5Xy7FgvRLisOsk EBpw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790750386; x=1791355186; 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=psYL54jmN9ycKhx2nDLaiBlGWatC/van2qwJIYKlQKQ=; b=zNZXUpsRfx3lzWPZzc/2bApf/RMqDWCbroTXD06NOIM+JbsDFF8TNF5ek6NDuNYzry h2isITzzTBTIzU91Mrm5uUJD/15kn/vRopdgshOxgX1Qcbft6KdvcdGCq2UW8O1nr/eh 9AwxvJqXejnSGu7sTIZAuMtGgGh+qAtajR6h3Q03GlV2VQCBZb4EuG4zDIojaYi6aHdm /FEA74A4xcKy351zgfSC+1Kf7Iy3VLclR83zN+xEIgZuRjORULcO/mu1/1sTuae51ptP 3lVMPGgMu919Kx4FQIyQ2A6X8LIymAqJxVYqfZmzioHoINuSFidotalbAUO8azYWiREu CY8Q== X-Gm-Message-State: AFuF++lpkdldxUE8CywCFt4G4J9rFW6uJKXtaQhAfWodry1xZ75HTfez moEWCGTCfzI7FBeTcH2yO63WturX+CtMAMQZFdcychMkZ0RvqtTy1oagRqpNVTOimHn+Go6E6PL RhO/Dmywr7C0OseI2QjwV/emi7ldyWTn97MKyfpgrsr2IoaK0th5rxQMnaWET4zt5YgRnB5EGfw 8= X-Gm-Gg: AYBFou2bWGTxQNLELTjmH+rwUJ+WUjMZU7dBaTAoQfLjFQdu9GybO0xQjsnXeBPg9e0 FgWcSQOv0H1zRMqvrL9Gp8cyfEd3D+emDbhIEoUHYY2JYrytTOrTSk7PVDbBQHZm1yTGtDmdjPp 8Pej1m9HEkhaaUErHOF8bR3kE+HZFUJfBDYLITqtgHtOOv5RAh7plBz+UfvGVu8p/EtQWtS+Ijq M/Cd4Q34cxMgbtDlx2nJUA0dUmyFwhvngFdH6SaVEoBaZltkQ3Xy80JUaU5Klz1jgu7SikZUmUw TmdsjupWKSuHVHtk0HbUpBWpIZ1J2ztMCaKmObnd+W+rFSl/eII+/nLAIidGg2JA7VFuO3+pA21 TIGrlbBNH2FTVdOm/NRZ1lV8GoORmuBQVko+b6v5vpxQcLk7P0zrTuSPmDzyFUrBdWCHDXcXqOU yBp0/I5ANdLurMad/jYSpjV9hq X-Received: by 2002:a05:701b:2906:b0:143:298c:924e with SMTP id a92af1059eb24-14d359570f3mr254913c88.45.1790750385937; Tue, 29 Sep 2026 23:39:45 -0700 (PDT) X-Received: by 2002:a05:701b:2906:b0:143:298c:924e with SMTP id a92af1059eb24-14d359570f3mr254865c88.45.1790750385147; Tue, 29 Sep 2026 23:39:45 -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.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 29 Sep 2026 23:39:44 -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 3/8] riscv: ptrace support for hardware break/watchpoints Date: Wed, 30 Sep 2026 12:09:14 +0530 Message-ID: <20260930063919.608911-4-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: quoted-printable X-Proofpoint-GUID: I7hEDmcI8HBDWW_5fmI45wRQvnsurspx X-Proofpoint-ORIG-GUID: I7hEDmcI8HBDWW_5fmI45wRQvnsurspx X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTMwMDAyNiBTYWx0ZWRfXzP02f6FvHO7O CPeQ7tv4hmUTScg1s+KCRwtz3yO6CMIoEsKKEqWpDPbvB6smDC1VLH6zdrYRnK8xQVniAI3Ef5Q tmBSm6Wh1eqMQTKMt/Jf+kWiGd2uD/FQmbusrh4cRfeBuI7JuL018qKVJxb33LqRnIUfr3EsYWr LTjnnFDB06S7QgizQz9KOJGHCrqDaTRe8YEaewdPKV3DRW4YF983LIBvk7rjeXkqTl6Z2eB7UIZ 1ADv6rMQsg+Mcm4y4QDetefuVfIHq+vCYyIiW4bE4Qw4Wd4n4sTOl8uQM7jtdgKQmAPaFAHhmwl tgsAHjcwF8ZDnG1I11ry2sO9Wxd7vr4lrrTFr3tkkU6qWar0aOXvopBDOX97EFmkDXufrdl7H6U ICvG3jPTCsJYQO3hajTukj+T9CT5wPraX4r2zJ+tbreDqAKocqJVuUlf3viQNBornZLeiZS2eG9 6zs1G6T6ps5s8ezaMTw== X-Proofpoint-Spam-Info: AW1haW4tMjYwOTMwMDAyNiBTYWx0ZWRfX7/+hgp6LpAc3 jcXzrF21b8CznCFgBQEQVkwyMiecZYgp9WMHWClpyomRp138qZsBIhAGRD/i866ZPm/JCuCdbw8 5vD7eXxSsQaUYw0KRbKnolvT8dakJbw= X-Authority-Analysis: v=2.4 cv=Tu1zFzXh c=1 sm=1 tr=0 ts=6abcaeb3 cx=c_pps a=wEP8DlPgTf/vqF+yE6f9lg==:117 a=Ou0eQOY4+eZoSc0qltEV5Q==:17 a=VdqzKS8jKosA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=yx91gb_oNiZeI1HMLzn7:22 a=EUspDBNiAAAA:8 a=QnrZwGvzMrCbM2MBBQkA:9 a=bBxd6f-gb0O0v-kibOvt:22 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 impostorscore=0 spamscore=0 malwarescore=0 suspectscore=0 phishscore=0 lowpriorityscore=0 adultscore=0 clxscore=1015 bulkscore=0 priorityscore=1501 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2609040000 definitions=main-2609300026 Content-Type: text/plain; charset="utf-8" Add ptrace support for hardware breakpoints and watchpoints on RISC-V. Debuggers can now set and query hardware debug triggers through the standard PTRACE_GETREGSET/SETREGSET interface using new NT_RISCV_HW_BREAK/WATCH note types, backed by register_user_hw_breakpoint()/modify_user_hw_breakpoint() and delivering SIGTRAP/TRAP_HWBKPT to the tracee when a trigger fires. For convenience, also add a simpler PTRACE_GETHBPREGS/SETHBPREGS request pair that lets a tracer read or write a single breakpoint or watchpoint directly, without going through the regset machinery. These request numbers live in the arch-specific ptrace range (0x4210/0x4211) so they don't collide with the generic PTRACE_PEEKDATA/PTRACE_PEEKUSR codes. Breakpoints and watchpoints share the same trigger pool on this architecture, so select HAVE_MIXED_BREAKPOINTS_REGS. Hook up thread flush/copy so per-task breakpoints are cleaned up and cleared across fork/exec. Signed-off-by: Himanshu Chauhan --- arch/riscv/Kconfig | 1 + arch/riscv/include/asm/hw_breakpoint.h | 10 + arch/riscv/include/asm/processor.h | 18 + arch/riscv/include/uapi/asm/ptrace.h | 50 +++ arch/riscv/kernel/hw_breakpoint.c | 1 - arch/riscv/kernel/process.c | 5 + arch/riscv/kernel/ptrace.c | 507 +++++++++++++++++++++++++ include/uapi/linux/elf.h | 4 + tools/include/uapi/linux/elf.h | 2 + 9 files changed, 597 insertions(+), 1 deletion(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 17fa7d4f9729..d382f5d7b6a7 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -176,6 +176,7 @@ config RISCV select HAVE_GCC_PLUGINS select HAVE_GENERIC_VDSO if MMU select HAVE_HW_BREAKPOINT if PERF_EVENTS + select HAVE_MIXED_BREAKPOINTS_REGS if PERF_EVENTS select HAVE_IRQ_TIME_ACCOUNTING select HAVE_KERNEL_BZIP2 if !EFI_ZBOOT select HAVE_KERNEL_GZIP if !EFI_ZBOOT diff --git a/arch/riscv/include/asm/hw_breakpoint.h b/arch/riscv/include/as= m/hw_breakpoint.h index a165bb9636de..ca2ef93c020c 100644 --- a/arch/riscv/include/asm/hw_breakpoint.h +++ b/arch/riscv/include/asm/hw_breakpoint.h @@ -14,6 +14,7 @@ struct task_struct; =20 /* Maximum number of hardware breakpoints supported */ #define RISCV_HW_BP_NUM_MAX 32 +#define RISCV_MAX_BP 16 =20 #if __riscv_xlen =3D=3D 64 #define cpu_to_le cpu_to_le64 @@ -279,6 +280,10 @@ struct arch_hw_breakpoint { unsigned long address; unsigned long len; unsigned int type; + unsigned int match; + unsigned int chain; + unsigned int select; + unsigned int time; =20 /* Trigger configuration data */ unsigned long tdata1; @@ -305,8 +310,13 @@ void arch_disable_hw_breakpoint(struct perf_event *bp); int arch_install_hw_breakpoint(struct perf_event *bp); void arch_uninstall_hw_breakpoint(struct perf_event *bp); void hw_breakpoint_pmu_read(struct perf_event *bp); +void clear_ptrace_hw_breakpoint(struct task_struct *tsk); +void flush_ptrace_hw_breakpoint(struct task_struct *tsk); +void ptrace_hw_copy_thread(struct task_struct *task); =20 #else =20 +static inline void ptrace_hw_copy_thread(struct task_struct *task) { } + #endif /* CONFIG_HAVE_HW_BREAKPOINT */ #endif /* __RISCV_HW_BREAKPOINT_H */ diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/pr= ocessor.h index 815715c67f94..6f6186b9663e 100644 --- a/arch/riscv/include/asm/processor.h +++ b/arch/riscv/include/asm/processor.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include =20 @@ -110,6 +111,19 @@ struct pt_regs; #define RISCV_PREEMPT_V_NEED_RESTORE 0x40000000 #define RISCV_PREEMPT_V_IN_SCHEDULE 0x20000000 =20 +struct debug_info { +#ifdef CONFIG_HAVE_HW_BREAKPOINT + /* Have we suspended stepping by a debugger? */ + int suspended_step; + /* Allow breakpoints and watchpoints to be disabled for this thread. */ + int bp_disabled; + int wp_disabled; + /* Hardware breakpoints pinned to this task. */ + struct perf_event *hbp_break[RISCV_MAX_BP]; + struct perf_event *hbp_watch[RISCV_MAX_BP]; +#endif +}; + /* CPU-specific state of a task */ struct thread_struct { /* Callee-saved registers */ @@ -133,6 +147,10 @@ struct thread_struct { #endif #ifdef CONFIG_RISCV_ISA_SSQOSID u32 srmcfg; +#endif + struct debug_info debug; +#ifdef CONFIG_HAVE_HW_BREAKPOINT + struct perf_event *ptrace_bps[RISCV_HW_BP_NUM_MAX]; #endif }; =20 diff --git a/arch/riscv/include/uapi/asm/ptrace.h b/arch/riscv/include/uapi= /asm/ptrace.h index 3de2b7124aff..83e073dbbf6d 100644 --- a/arch/riscv/include/uapi/asm/ptrace.h +++ b/arch/riscv/include/uapi/asm/ptrace.h @@ -10,11 +10,14 @@ =20 #include #include +#include =20 #define PTRACE_GETFDPIC 33 =20 #define PTRACE_GETFDPIC_EXEC 0 #define PTRACE_GETFDPIC_INTERP 1 +#define PTRACE_GETHBPREGS 0x4210 +#define PTRACE_SETHBPREGS 0x4211 =20 /* * User-mode register state for core dumps, ptrace, sigcontext @@ -164,6 +167,53 @@ struct user_cfi_state { __u64 shstk_ptr; }; =20 +/* + * bit[3:0] Match + * bit[8:4] Size + * bit[11:9] When + * bit[12] Select + * bit[13] Chain + * bit[16:14] Type + * bit[XLEN-1:17] Reserved + */ +#define HWDEBUG_MATCH_MASK __GENMASK(3, 0) +#define HWDEBUG_SIZE_MASK __GENMASK(8, 4) +#define HWDEBUG_WHEN_MASK __GENMASK(11, 9) +#define HWDEBUG_SELECT_MASK _BITUL(12) +#define HWDEBUG_CHAIN_MASK _BITUL(13) +#define HWDEBUG_TYPE_MASK __GENMASK(16, 14) + +#define HWDEBUG_MATCH(_ctrl) (((_ctrl) & HWDEBUG_MATCH_MASK) >> 0) +#define HWDEBUG_SIZE(_ctrl) (((_ctrl) & HWDEBUG_SIZE_MASK) >> 4) +#define HWDEBUG_WHEN(_ctrl) (((_ctrl) & HWDEBUG_WHEN_MASK) >> 9) +#define HWDEBUG_SELECT(_ctrl) (((_ctrl) & HWDEBUG_SELECT_MASK) >> 12) +#define HWDEBUG_CHAIN(_ctrl) (((_ctrl) & HWDEBUG_CHAIN_MASK) >> 13) +#define HWDEBUG_TYPE(_ctrl) (((_ctrl) & HWDEBUG_TYPE_MASK) >> 14) + +#define HWDEBUG_MK_MATCH(_match) ((_match << 0) & HWDEBUG_MATCH_MASK) +#define HWDEBUG_MK_SIZE(_sz) ((_sz << 4) & HWDEBUG_SIZE_MASK) +#define HWDEBUG_MK_WHEN(_when) ((_when << 9) & HWDEBUG_WHEN_MASK) +#define HWDEBUG_MK_SELECT(_sel) ((_sel << 12) & HWDEBUG_SELECT_MASK) +#define HWDEBUG_MK_CHAIN(_chain) ((_chain << 13) & HWDEBUG_CHAIN_MASK) +#define HWDEBUG_MK_TYPE(_type) ((_type << 14) & HWDEBUG_TYPE_MASK) + +struct user_hwdebug_state { + __u32 info; + __u32 pad; + struct { + __u64 addr; + __u32 control; + __u32 pad; + } dbg_regs[16]; +}; + +struct __riscv_hwdebug_state { + __u64 addr; + __u64 type; + __u64 len; + __u64 ctrl; +}; + #endif /* __ASSEMBLER__ */ =20 #endif /* _UAPI_ASM_RISCV_PTRACE_H */ diff --git a/arch/riscv/kernel/hw_breakpoint.c b/arch/riscv/kernel/hw_break= point.c index c2ab5e6008e7..dd6f63953969 100644 --- a/arch/riscv/kernel/hw_breakpoint.c +++ b/arch/riscv/kernel/hw_breakpoint.c @@ -698,7 +698,6 @@ EXPORT_SYMBOL_GPL(arch_disable_hw_breakpoint); =20 void hw_breakpoint_pmu_read(struct perf_event *bp) { } =20 -void flush_ptrace_hw_breakpoint(struct task_struct *tsk) { } =20 static int __init arch_hw_breakpoint_init(void) { diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index 7cc5a6a5c020..bdcb0386cd0d 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -204,6 +204,7 @@ void flush_thread(void) if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SUPM)) envcfg_update_bits(current, ENVCFG_PMM, ENVCFG_PMM_PMLEN_0); #endif + flush_ptrace_hw_breakpoint(current); } =20 void arch_release_task_struct(struct task_struct *tsk) @@ -283,6 +284,10 @@ int copy_thread(struct task_struct *p, const struct ke= rnel_clone_args *args) p->thread.riscv_v_flags =3D 0; if (has_vector() || has_xtheadvector()) riscv_v_thread_alloc(p); + ptrace_hw_copy_thread(p); +#ifdef CONFIG_HAVE_HW_BREAKPOINT + memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); +#endif p->thread.sp =3D (unsigned long)childregs; /* kernel sp */ return 0; } diff --git a/arch/riscv/kernel/ptrace.c b/arch/riscv/kernel/ptrace.c index f336a183667e..2d4ee51e6859 100644 --- a/arch/riscv/kernel/ptrace.c +++ b/arch/riscv/kernel/ptrace.c @@ -18,8 +18,10 @@ #include #include #include +#include #include #include +#include =20 enum riscv_regset { REGSET_X, @@ -35,6 +37,10 @@ enum riscv_regset { #ifdef CONFIG_RISCV_USER_CFI REGSET_CFI, #endif +#ifdef CONFIG_HAVE_HW_BREAKPOINT + REGSET_RISCV_HW_BREAK, + REGSET_RISCV_HW_WATCH, +#endif }; =20 static int riscv_gpr_get(struct task_struct *target, @@ -372,6 +378,397 @@ static int riscv_cfi_set(struct task_struct *target, } #endif =20 +#ifdef CONFIG_HAVE_HW_BREAKPOINT +/* + * Handle hitting a HW-breakpoint. + */ +static void riscv_ptrace_hbptriggered(struct perf_event *bp, + struct perf_sample_data *data, + struct pt_regs *regs) +{ + struct arch_hw_breakpoint *bkpt =3D counter_arch_bp(bp); + + force_sig_fault(SIGTRAP, TRAP_HWBKPT, (void __user *)bkpt->address); +} + +/* + * Unregister breakpoints from this task and reset the pointers in + * the thread_struct. + */ +void flush_ptrace_hw_breakpoint(struct task_struct *tsk) +{ + int i; + struct thread_struct *t =3D &tsk->thread; + + for (i =3D 0; i < RISCV_MAX_BP; i++) { + if (t->debug.hbp_break[i]) { + unregister_hw_breakpoint(t->debug.hbp_break[i]); + t->debug.hbp_break[i] =3D NULL; + } + } + + for (i =3D 0; i < RISCV_MAX_BP; i++) { + if (t->debug.hbp_watch[i]) { + unregister_hw_breakpoint(t->debug.hbp_watch[i]); + t->debug.hbp_watch[i] =3D NULL; + } + } +} + +void ptrace_hw_copy_thread(struct task_struct *tsk) +{ + memset(&tsk->thread.debug, 0, sizeof(struct debug_info)); +} + +static struct perf_event *ptrace_hbp_get_event(unsigned int note_type, + struct task_struct *tsk, + unsigned long idx) +{ + struct perf_event *bp =3D ERR_PTR(-EINVAL); + + switch (note_type) { + case NT_RISCV_HW_BREAK: + if (idx >=3D RISCV_MAX_BP) + goto out; + idx =3D array_index_nospec(idx, RISCV_MAX_BP); + bp =3D tsk->thread.debug.hbp_break[idx]; + break; + case NT_RISCV_HW_WATCH: + if (idx >=3D RISCV_MAX_BP) + goto out; + idx =3D array_index_nospec(idx, RISCV_MAX_BP); + bp =3D tsk->thread.debug.hbp_watch[idx]; + break; + } + +out: + return bp; +} + +static int ptrace_hbp_set_event(unsigned int note_type, + struct task_struct *tsk, + unsigned long idx, + struct perf_event *bp) +{ + int err =3D -EINVAL; + + switch (note_type) { + case NT_RISCV_HW_BREAK: + if (idx >=3D RISCV_MAX_BP) + goto out; + idx =3D array_index_nospec(idx, RISCV_MAX_BP); + tsk->thread.debug.hbp_break[idx] =3D bp; + err =3D 0; + break; + case NT_RISCV_HW_WATCH: + if (idx >=3D RISCV_MAX_BP) + goto out; + idx =3D array_index_nospec(idx, RISCV_MAX_BP); + tsk->thread.debug.hbp_watch[idx] =3D bp; + err =3D 0; + break; + } + +out: + return err; +} + +static struct perf_event *ptrace_hbp_create(unsigned int note_type, + struct task_struct *tsk, + unsigned long idx) +{ + struct perf_event *bp; + struct perf_event_attr attr; + int err, type; + + switch (note_type) { + case NT_RISCV_HW_BREAK: + type =3D HW_BREAKPOINT_X; + break; + case NT_RISCV_HW_WATCH: + type =3D HW_BREAKPOINT_RW; + break; + default: + return ERR_PTR(-EINVAL); + } + + ptrace_breakpoint_init(&attr); + + /* + * Initialise fields to sane defaults + * (i.e. values that will pass validation). + */ + attr.bp_addr =3D 0; + attr.bp_len =3D HW_BREAKPOINT_LEN_4; + attr.bp_type =3D type; + attr.disabled =3D 1; + + bp =3D register_user_hw_breakpoint(&attr, riscv_ptrace_hbptriggered, NULL= , tsk); + if (IS_ERR(bp)) + return bp; + + err =3D ptrace_hbp_set_event(note_type, tsk, idx, bp); + if (err) + return ERR_PTR(err); + + return bp; +} + +static int ptrace_hbp_fill_attr_ctrl(unsigned int note_type, + struct arch_hw_breakpoint *bpctrl, + struct perf_event_attr *attr) +{ + int len, type; + + attr->disabled =3D 0; + type =3D bpctrl->type; + len =3D bpctrl->len; + + switch (note_type) { + case NT_RISCV_HW_BREAK: + if ((type & HW_BREAKPOINT_X) !=3D type) + return -EINVAL; + break; + case NT_RISCV_HW_WATCH: + if ((type & HW_BREAKPOINT_RW) !=3D type) + return -EINVAL; + break; + default: + return -EINVAL; + } + + attr->bp_len =3D len; + attr->bp_type =3D type; + attr->bp_addr =3D bpctrl->address; + + return 0; +} + +static int ptrace_hbp_get_resource_info(unsigned int note_type, u32 *info) +{ + u8 num; + + switch (note_type) { + case NT_RISCV_HW_BREAK: + num =3D hw_breakpoint_slots(TYPE_INST); + break; + case NT_RISCV_HW_WATCH: + num =3D hw_breakpoint_slots(TYPE_DATA); + break; + default: + return -EINVAL; + } + + *info =3D num; + + return 0; +} + +static u32 encode_ctrl_reg(struct perf_event *bp) +{ + struct arch_hw_breakpoint *bpctrl =3D counter_arch_bp(bp); + u32 ctrl =3D 0; + + /* Expose the generic UAPI bp_type values in ptrace control bits. */ + ctrl |=3D HWDEBUG_MK_TYPE(bp->attr.bp_type); + ctrl |=3D HWDEBUG_MK_MATCH(bpctrl->match); + ctrl |=3D HWDEBUG_MK_SELECT(bpctrl->select); + ctrl |=3D HWDEBUG_MK_WHEN(bpctrl->time); + ctrl |=3D HWDEBUG_MK_SIZE(bp->attr.bp_len); + ctrl |=3D HWDEBUG_MK_CHAIN(bpctrl->chain); + + return ctrl; +} + +static int ptrace_hbp_get_ctrl(unsigned int note_type, + struct task_struct *tsk, + unsigned long idx, + u32 *ctrl) +{ + struct perf_event *bp =3D ptrace_hbp_get_event(note_type, tsk, idx); + + if (IS_ERR(bp)) + return PTR_ERR(bp); + + *ctrl =3D bp ? encode_ctrl_reg(bp) : 0; + return 0; +} + +static int ptrace_hbp_get_addr(unsigned int note_type, + struct task_struct *tsk, + unsigned long idx, + u64 *addr) +{ + struct perf_event *bp =3D ptrace_hbp_get_event(note_type, tsk, idx); + + if (IS_ERR(bp)) + return PTR_ERR(bp); + + *addr =3D bp ? counter_arch_bp(bp)->address : 0; + return 0; +} + +static struct perf_event *ptrace_hbp_get_initialised_bp(unsigned int note_= type, + struct task_struct *tsk, + unsigned long idx) +{ + struct perf_event *bp =3D ptrace_hbp_get_event(note_type, tsk, idx); + + if (!bp) + bp =3D ptrace_hbp_create(note_type, tsk, idx); + + return bp; +} + +static void decode_ctrl_reg(u32 uctrl, struct arch_hw_breakpoint *bpctrl) +{ + bpctrl->type =3D HWDEBUG_TYPE(uctrl); + bpctrl->match =3D HWDEBUG_MATCH(uctrl); + bpctrl->select =3D HWDEBUG_SELECT(uctrl); + bpctrl->time =3D HWDEBUG_WHEN(uctrl); + bpctrl->len =3D HWDEBUG_SIZE(uctrl); + bpctrl->chain =3D HWDEBUG_CHAIN(uctrl); +} + +static int ptrace_hbp_set_ctrl(unsigned int note_type, + struct task_struct *tsk, + unsigned long idx, + u32 uctrl) +{ + int err; + struct perf_event *bp; + struct perf_event_attr attr; + struct arch_hw_breakpoint bpctrl; + + bp =3D ptrace_hbp_get_initialised_bp(note_type, tsk, idx); + if (IS_ERR(bp)) { + err =3D PTR_ERR(bp); + return err; + } + + attr =3D bp->attr; + decode_ctrl_reg(uctrl, &bpctrl); + bpctrl.address =3D attr.bp_addr; + err =3D ptrace_hbp_fill_attr_ctrl(note_type, &bpctrl, &attr); + if (err) + return err; + + return modify_user_hw_breakpoint(bp, &attr); +} + +static int ptrace_hbp_set_addr(unsigned int note_type, + struct task_struct *tsk, + unsigned long idx, + u64 addr) +{ + int err; + struct perf_event *bp; + struct perf_event_attr attr; + + bp =3D ptrace_hbp_get_initialised_bp(note_type, tsk, idx); + if (IS_ERR(bp)) { + err =3D PTR_ERR(bp); + return err; + } + + attr =3D bp->attr; + attr.bp_addr =3D addr; + err =3D modify_user_hw_breakpoint(bp, &attr); + return err; +} + +#define PTRACE_HBP_ADDR_SZ sizeof(u64) +#define PTRACE_HBP_CTRL_SZ sizeof(u32) +#define PTRACE_HBP_PAD_SZ sizeof(u32) + +static int riscv_hw_break_get(struct task_struct *target, + const struct user_regset *regset, + struct membuf to) +{ + unsigned int note_type =3D regset->core_note_type; + int ret, idx, num_slots; + u32 info, ctrl; + u64 addr; + + /* Resource info: number of available slots */ + ret =3D ptrace_hbp_get_resource_info(note_type, &info); + if (ret) + return ret; + + membuf_write(&to, &info, sizeof(info)); + membuf_zero(&to, sizeof(u32)); + + /* Emit one (address, ctrl, pad) entry per available slot */ + num_slots =3D (int)info; + for (idx =3D 0; idx < num_slots; idx++) { + ret =3D ptrace_hbp_get_addr(note_type, target, idx, &addr); + if (ret) + return ret; + ret =3D ptrace_hbp_get_ctrl(note_type, target, idx, &ctrl); + if (ret) + return ret; + membuf_store(&to, addr); + membuf_store(&to, ctrl); + membuf_zero(&to, sizeof(u32)); + } + return 0; +} + +static int riscv_hw_break_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + unsigned int note_type =3D regset->core_note_type; + int ret, idx =3D 0, offset, limit; + u32 ctrl; + u64 addr; + + /* Resource info and pad */ + offset =3D offsetof(struct user_hwdebug_state, dbg_regs); + user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 0, offset); + + /* (address, ctrl) registers */ + limit =3D regset->n * regset->size; + while (count && offset < limit) { + if (count < PTRACE_HBP_ADDR_SZ) + return -EINVAL; + + ret =3D user_regset_copyin(&pos, &count, &kbuf, &ubuf, &addr, + offset, offset + PTRACE_HBP_ADDR_SZ); + if (ret) + return ret; + + ret =3D ptrace_hbp_set_addr(note_type, target, idx, addr); + if (ret) + return ret; + + offset +=3D PTRACE_HBP_ADDR_SZ; + + if (!count) + break; + + ret =3D user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ctrl, + offset, offset + PTRACE_HBP_CTRL_SZ); + if (ret) + return ret; + + ret =3D ptrace_hbp_set_ctrl(note_type, target, idx, ctrl); + if (ret) + return ret; + + offset +=3D PTRACE_HBP_CTRL_SZ; + + user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + offset, offset + PTRACE_HBP_PAD_SZ); + offset +=3D PTRACE_HBP_PAD_SZ; + idx++; + } + + return 0; +} +#endif /* CONFIG_HAVE_HW_BREAKPOINT */ + static struct user_regset riscv_user_regset[] __ro_after_init =3D { [REGSET_X] =3D { USER_REGSET_NOTE_TYPE(PRSTATUS), @@ -421,6 +818,24 @@ static struct user_regset riscv_user_regset[] __ro_aft= er_init =3D { .set =3D riscv_cfi_set, }, #endif +#ifdef CONFIG_HAVE_HW_BREAKPOINT + [REGSET_RISCV_HW_BREAK] =3D { + USER_REGSET_NOTE_TYPE(RISCV_HW_BREAK), + .n =3D sizeof(struct user_hwdebug_state) / sizeof(u32), + .size =3D sizeof(u32), + .align =3D sizeof(u32), + .regset_get =3D riscv_hw_break_get, + .set =3D riscv_hw_break_set, + }, + [REGSET_RISCV_HW_WATCH] =3D { + USER_REGSET_NOTE_TYPE(RISCV_HW_WATCH), + .n =3D sizeof(struct user_hwdebug_state) / sizeof(u32), + .size =3D sizeof(u32), + .align =3D sizeof(u32), + .regset_get =3D riscv_hw_break_get, + .set =3D riscv_hw_break_set, + }, +#endif }; =20 static const struct user_regset_view riscv_user_native_view =3D { @@ -541,12 +956,104 @@ void ptrace_disable(struct task_struct *child) { } =20 +#ifdef CONFIG_HAVE_HW_BREAKPOINT +static int riscv_ptrace_bp_get(struct task_struct *child, unsigned long id= x, + struct __riscv_hwdebug_state *state) +{ + struct perf_event *bp; + + if (idx >=3D RISCV_HW_BP_NUM_MAX) + return -EINVAL; + + bp =3D child->thread.ptrace_bps[idx]; + if (!bp) + return -ENOENT; + + state->addr =3D bp->attr.bp_addr; + state->len =3D bp->attr.bp_len; + state->type =3D bp->attr.bp_type; + state->ctrl =3D bp->attr.disabled =3D=3D 1; + + return 0; +} + +static int riscv_ptrace_bp_set(struct task_struct *child, unsigned long id= x, + struct __riscv_hwdebug_state *state) +{ + struct perf_event *bp; + struct perf_event_attr attr; + + if (idx >=3D RISCV_HW_BP_NUM_MAX) + return -EINVAL; + + bp =3D child->thread.ptrace_bps[idx]; + if (bp) + attr =3D bp->attr; + else + ptrace_breakpoint_init(&attr); + + attr.bp_addr =3D state->addr; + attr.bp_len =3D state->len; + attr.bp_type =3D state->type; + /* Always register disabled; enable below if requested */ + attr.disabled =3D 1; + + if (!bp) { + bp =3D register_user_hw_breakpoint(&attr, riscv_ptrace_hbptriggered, NUL= L, child); + if (IS_ERR(bp)) + return PTR_ERR(bp); + child->thread.ptrace_bps[idx] =3D bp; + } + + /* Enable or disable as requested by ctrl (0 =3D enabled, 1 =3D disabled)= */ + attr.disabled =3D state->ctrl =3D=3D 1; + return modify_user_hw_breakpoint(bp, &attr); +} + +static long riscv_ptrace_gethbpregs(struct task_struct *child, unsigned lo= ng idx, + unsigned long __user *datap) +{ + struct __riscv_hwdebug_state state; + long ret; + + ret =3D riscv_ptrace_bp_get(child, idx, &state); + if (ret) + return ret; + if (copy_to_user(datap, &state, sizeof(state))) + return -EFAULT; + + return 0; +} + +static long riscv_ptrace_sethbpregs(struct task_struct *child, unsigned lo= ng idx, + unsigned long __user *datap) +{ + struct __riscv_hwdebug_state state; + + if (copy_from_user(&state, datap, sizeof(state))) + return -EFAULT; + + return riscv_ptrace_bp_set(child, idx, &state); +} +#endif /* CONFIG_HAVE_HW_BREAKPOINT */ + long arch_ptrace(struct task_struct *child, long request, unsigned long addr, unsigned long data) { long ret =3D -EIO; +#ifdef CONFIG_HAVE_HW_BREAKPOINT + unsigned long __user *datap =3D (unsigned long __user *)data; +#endif =20 switch (request) { +#ifdef CONFIG_HAVE_HW_BREAKPOINT + case PTRACE_GETHBPREGS: + ret =3D riscv_ptrace_gethbpregs(child, addr, datap); + break; + case PTRACE_SETHBPREGS: + ret =3D riscv_ptrace_sethbpregs(child, addr, datap); + break; +#endif default: ret =3D ptrace_request(child, request, addr, data); break; diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h index ee30dcd80901..1315ac35157c 100644 --- a/include/uapi/linux/elf.h +++ b/include/uapi/linux/elf.h @@ -547,6 +547,10 @@ typedef struct elf64_shdr { #define NT_RISCV_TAGGED_ADDR_CTRL 0x902 /* RISC-V tagged address control (= prctl()) */ #define NN_RISCV_USER_CFI "LINUX" #define NT_RISCV_USER_CFI 0x903 /* RISC-V shadow stack state */ +#define NN_RISCV_HW_BREAK "LINUX" +#define NT_RISCV_HW_BREAK 0x904 /* RISC-V hardware breakpoint registers */ +#define NN_RISCV_HW_WATCH "LINUX" +#define NT_RISCV_HW_WATCH 0x905 /* RISCV-V hardware watchpoint registers = */ #define NN_LOONGARCH_CPUCFG "LINUX" #define NT_LOONGARCH_CPUCFG 0xa00 /* LoongArch CPU config registers */ #define NN_LOONGARCH_CSR "LINUX" diff --git a/tools/include/uapi/linux/elf.h b/tools/include/uapi/linux/elf.h index 5834b83d7f9a..21f225502051 100644 --- a/tools/include/uapi/linux/elf.h +++ b/tools/include/uapi/linux/elf.h @@ -460,6 +460,8 @@ typedef struct elf64_shdr { #define NT_RISCV_CSR 0x900 /* RISC-V Control and Status Registers */ #define NT_RISCV_VECTOR 0x901 /* RISC-V vector registers */ #define NT_RISCV_TAGGED_ADDR_CTRL 0x902 /* RISC-V tagged address control (= prctl()) */ +#define NT_RISCV_HW_BREAK 0x904 +#define NT_RISCV_HW_WATCH 0x905 #define NT_LOONGARCH_CPUCFG 0xa00 /* LoongArch CPU config registers */ #define NT_LOONGARCH_CSR 0xa01 /* LoongArch control and status registers */ #define NT_LOONGARCH_LSX 0xa02 /* LoongArch Loongson SIMD Extension regist= ers */ --=20 2.43.0 From nobody Fri Oct 2 08:26:24 2026 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.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 7AAB41DF261 for ; Wed, 30 Sep 2026 06:39:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790750395; cv=none; b=SdYYgKFjK6uB+3F1en8nxIwrK5wBgWUi9EAcZ/HMluAwb5LmERGTlVpLKu9mPcgnVvfau06wstZ+u4TeNCv5XLDSjWwZScbUdgqIuIpErEkzniKHECJEfXUU5AkM4kcF2SCU4Rr2nKFvnXTd62J1MpSXi0NJeLrv9MwNqmmp3nQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790750395; c=relaxed/simple; bh=MnEHdRXB8Kx+Y4sIstudNAZykh2ay2IXR5jExQRD9FY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=q7XU2lL2ahXZZbaDsrArrtqR35whGuKQY/c81KBPw4sHpPdQ7KSKi5HZvMOUTJRw4x1V3OimXZhB3nsK9w5ruPFaAEvb+zln5eeIWh4LGz5oR3OOeh9gFHr8//KCMJWvUQEEsHsX4DwL664lqKccb8vO8d7XJqkKVJ8eNNxxhYM= 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=MS8wrvSI; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=NSnAzmuv; arc=none smtp.client-ip=205.220.180.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="MS8wrvSI"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="NSnAzmuv" Received: from pps.filterd (m0279869.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 68U64kUs2249803 for ; Wed, 30 Sep 2026 06:39:52 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=sMxi/Z81iYD fge4GQABNNwApMyHGie11g9z5WvCjmF8=; b=MS8wrvSIUKSQiabcLyM0T9GfncL s+vfF3c606Zs9oVevSqQHOCgwoT81pB8CCYiWVjJ4tbtjLhRlW4S0IV10jRP48q6 8GySLeIbXA00RTsul3zGyKXrdjyGlbL3pqdqMQhOPxzVtJW2/QZTDNSZCi0sOlxU zn9B/tYXM+T3+RyJhBIBeqNcKtBGOTP37YC46hDFuigDGMf+Fwfzfdl2hQe6DbEL E5mUwI/G+IQ09LBbJB0FIEGdS6yxzgXK5VOamRzbVXZXmMkU3R0zJilRvLS9jQAo zmARm3tx4cySanD+0uo3QOnYe7F+WbApK7r+7XpqURQS0HPJjlgR3UHQ3Uw== 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 4h0nm3hv83-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Wed, 30 Sep 2026 06:39:52 +0000 (GMT) Received: by mail-dy1-f197.google.com with SMTP id 5a478bee46e88-3282d5302ffso2896026eec.1 for ; Tue, 29 Sep 2026 23:39:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1790750391; x=1791355191; 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=sMxi/Z81iYDfge4GQABNNwApMyHGie11g9z5WvCjmF8=; b=NSnAzmuvHy+CmfLIz8KtEKDyvM7dJkRVo2UxvPaAVq1bTXUAaM1REKPlhylaRisbOW rHzroQo2d2/JUEaAaw7oS850cgkai5Ks7/f3oLkBzr3qIm0BTWBvUU65XTPBlWrmF7zj QX9+sO/EO0MwVHhZGI6xhjY6/FqIW6scI5nX6i1rbp0wJXPfw3e+3+Y7BP7Vt9tzcHjn ABrxHPG/SC2OIv8yzhyZ7GIKCXXhH1xGi+lRtoWRm6OZV9d2Ifc/pPxWvIa3pNwxeBLJ ZiYepv+f8WqztfFD83D64lFt7ZbXX2562s1aHqVgW5zan3L6ecDUfhL8644bZaCrFTEO VRdw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790750391; x=1791355191; 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=sMxi/Z81iYDfge4GQABNNwApMyHGie11g9z5WvCjmF8=; b=bW2fDgB65tD/tN3EfyDPt2s5TCYeOuSwKxwvsEG7escK6lz1IAVK21ALTAG7sfdFnF I0hWiDgqxpNeOUt8hfJzA8/n2m7bhLc8hhD3GWD5z9QQShu47nDAHK9K05g0k8/gJe5a 39+dLWpRjrAN6uV1HIWbEHbh5/oXG+89z79rRHwhq1IqckOaMp8vBTnCyKAEesT8Mc9w q9syBU/CDsO8y+ub4FkMB0AL6K8cXMNMNzcyoYFbpIum4+OFYO3ACzJ1XOM+YSud6RQa D/GbfVSSef+WPJ8PcnWPy9yINPCcZ1PELaPMLEwsYrjFpEYG/FKKRHDnN3CuPLz1pOid D7/w== X-Gm-Message-State: AFuF++ncDF+yGim13warDG6fGLYSLMoWxXwLu8DMMWjfZoieErulnQMu 89MFkAWui4kOouzchMI0100MLoCdFDoWAZupP1FJDA7SLD7uZ5ofehGR7b2aMMPGV1ubcGO3Ql4 1XAffmtTqGorK0pGyZLOiK9q5UqyO1LiOWNlU5iyJhSUHdhOb1tbROQfIdQfqL/bmc/N0tBMKvq 0= X-Gm-Gg: AYBFou2Yu0ZKsqbTzY8K2YYSIJbhh782KThlQUUtnX+Aez22/dHnoFOotmMqQNt0uMu k7aR6U0W5yfMjzKrZoRKLXjLde/1vQMGVjnhnX5PU3cK2iwc48quN7+GiiZ/Ww2ke4WUnzb6ZVp c7CVEyVFWjPPrTQJppwGjzWwHIsVUpB2JTfr+owlJP9p0iGSGCjUtfMhyLxA1xZkJscvKp5/rYZ qZrDsliBaApiEV8Fohb6b9KazbSJu8wOfichvBNxmclmU7MSoCrvBj8vac6CrAr2agm1yorab2/ yrVRQSAibio+iYwg/f9pZwdmoHGhVKB6ySGEswm2ZiyfRN6ko5CXWox9BkHIR/1Sou/BSCDGLYp /t0B9tgWrXtctLorgVO4gWxFUS1KJblvISmU7yXpVFQ9GaasT3ErVxz7/KWbgXfGodoAw4E5HFN eZRgtVMa+sj/eflQlA6a4Kltkj X-Received: by 2002:a05:7022:ba5:b0:147:5261:ee2e with SMTP id a92af1059eb24-14d398ed392mr413086c88.21.1790750390959; Tue, 29 Sep 2026 23:39:50 -0700 (PDT) X-Received: by 2002:a05:7022:ba5:b0:147:5261:ee2e with SMTP id a92af1059eb24-14d398ed392mr413022c88.21.1790750390306; Tue, 29 Sep 2026 23:39:50 -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.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 29 Sep 2026 23:39:49 -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 4/8] selftests/breakpoints: extend riscv test for ptrace hw break/watchpoints Date: Wed, 30 Sep 2026 12:09:15 +0530 Message-ID: <20260930063919.608911-5-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: quoted-printable X-Proofpoint-ORIG-GUID: geI9gjnSUblxGQ3B2jmqIzj6Vl1G_IaA X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTMwMDAyNiBTYWx0ZWRfX+DLV61vDhtqA iWC634JXfBS599FzeKYubvw9xxQxfI7pDfHcc5RZ8b882g0QetTmGxF2wc4EnQ6ZCdmMR1gf85P MFVh/I35/zsl6VSlQunyH2bQEsiR/ugTWm+KTkS+EZKYIR57M0PPzKBKbXrbKbUq3IIYNzOG5aK RzQKJtVuAvnKE9k0sGOlPhJVacSVCq1xux0+G96rYfLe5uBIPBJrCJG0Vzs0XRVq2bIl0PNgFsk benoqAVyqNiIt+FIp/PHwJlyXtNIlCLamU7RpXFy+jHuRnSnCe6GXjKgsqumK04OK8qQwuSQM3x 5jXKmthI/27kFKf+Dh+01YzHjobeqeTLcBoNlh2N3r3GurQK6mJ5HeqmFExFH7IkgpbXtXi0UXr FUALD/4o5JF/yBYVgic34nrUqYKSCFXvn9glIll9ABVnUiT/Sx7lIuiMdgChvAQj9wdT2c8jR8l SkOqzyTFAMEt3ZwY/Zw== X-Proofpoint-Spam-Info: AW1haW4tMjYwOTMwMDAyNiBTYWx0ZWRfXz33bby8xqwbC D8k3nUv1GYJbQjPIYzez8oajTkJStK9JSt4gJXg0K4Bklv3J7qTWCPuh90gd2XR1ueX8X2IXbEm EUDm6fdQ6MURhWqLlF+HbJ8G4fJSBsc= X-Proofpoint-GUID: geI9gjnSUblxGQ3B2jmqIzj6Vl1G_IaA X-Authority-Analysis: v=2.4 cv=fqxJ914f c=1 sm=1 tr=0 ts=6abcaeb8 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=_glEPmIy2e8OvE2BGh3C:22 a=EUspDBNiAAAA:8 a=07_doiqUAAAA:8 a=vV4cC3RZRCDA8ntysFEA:9 a=PxkB5W3o20Ba91AHUih5:22 a=S1vEknPFSxWy9jUyH7lK:22 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 adultscore=0 clxscore=1015 impostorscore=0 malwarescore=0 suspectscore=0 spamscore=0 bulkscore=0 priorityscore=1501 lowpriorityscore=0 phishscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2609040000 definitions=main-2609300026 Content-Type: text/plain; charset="utf-8" Cover the new ptrace-based hardware breakpoint/watchpoint support added for riscv: exercise the PTRACE_GETREGSET/SETREGSET regset path as well as the raw PTRACE_GETHBPREGS/SETHBPREGS interface, alongside the existing perf_event-based tests. Also drop a leftover #if 0 block duplicating the HWDEBUG_* control field macros already defined in uapi/asm/ptrace.h. Signed-off-by: Himanshu Chauhan --- .../breakpoints/breakpoint_test_riscv.c | 594 +++++++++++++++++- 1 file changed, 572 insertions(+), 22 deletions(-) diff --git a/tools/testing/selftests/breakpoints/breakpoint_test_riscv.c b/= tools/testing/selftests/breakpoints/breakpoint_test_riscv.c index 0649940b709e..13d6b3ff1b6e 100644 --- a/tools/testing/selftests/breakpoints/breakpoint_test_riscv.c +++ b/tools/testing/selftests/breakpoints/breakpoint_test_riscv.c @@ -9,6 +9,7 @@ #include /* Definition of PERF_* constants */ #include /* Definition of HW_* constants */ #include /* Definition of SYS_* constants */ +#include #include #include #include @@ -18,18 +19,576 @@ #include #include #include +#include +#include #include #include #include +#include +#include +#include =20 #ifndef noinline #define noinline __attribute__((noinline)) #endif =20 +#include "kselftest.h" + +static int test_func_sink; + +/* + * Keep a real instruction address for HW execute breakpoints: prevent inl= ining + * and force a visible side effect so the function can't be optimized away. + */ +static noinline void test_func(void) +{ + test_func_sink++; + __asm__ __volatile__("" : : "g" (test_func_sink)); +} + +/* + * BREAKPOINT TEST USING PTRACE + */ +static int do_wp_child(void *addr, size_t size) +{ + if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) !=3D 0) { + ksft_print_msg( + "ptrace(PTRACE_TRACEME) failed: %s\n", + strerror(errno)); + _exit(1); + } + + if (raise(SIGSTOP) !=3D 0) { + ksft_print_msg( + "raise(SIGSTOP) failed: %s\n", strerror(errno)); + _exit(1); + } + + sleep(1); + switch (size) { + case 1: + *(uint8_t *)addr =3D 47; + break; + case 2: + *(uint16_t *)addr =3D 47; + break; + case 4: + *(uint32_t *)addr =3D 47; + break; + case 8: + *(uint64_t *)addr =3D 47; + break; + default: + ksft_print_msg("Unknown watchpoint access size %u\n", size); + break; + } + + _exit(0); +} + +static int do_bp_child(void (*bp_func)(void)) +{ + if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) !=3D 0) { + ksft_print_msg( + "ptrace(PTRACE_TRACEME) failed: %s\n", + strerror(errno)); + _exit(1); + } + + if (raise(SIGSTOP) !=3D 0) { + ksft_print_msg( + "raise(SIGSTOP) failed: %s\n", strerror(errno)); + _exit(1); + } + + bp_func(); +} + +unsigned long var; + +static bool set_watchpoint(pid_t pid, int size) +{ + uint8_t *addr =3D (uint8_t *)&var; + unsigned int control =3D 0; + struct user_hwdebug_state dreg_state; + struct iovec iov; + + /* Write watchpoint */ + control =3D (HW_BREAKPOINT_W << 14) & ((0x7 << 14)); + control |=3D (HW_BREAKPOINT_LEN_8 << 4) & ((0x1f << 4)); + memset(&dreg_state, 0, sizeof(dreg_state)); + dreg_state.dbg_regs[0].addr =3D (uintptr_t)(addr); + dreg_state.dbg_regs[0].control =3D control; + iov.iov_base =3D &dreg_state; + iov.iov_len =3D offsetof(struct user_hwdebug_state, dbg_regs) + + sizeof(dreg_state.dbg_regs[0]); + + if (ptrace(PTRACE_SETREGSET, pid, NT_RISCV_HW_WATCH, &iov) =3D=3D 0) { + memset(&iov, 0, sizeof(iov)); + memset(&dreg_state, 0, sizeof(dreg_state)); + + iov.iov_base =3D &dreg_state; + iov.iov_len =3D offsetof(struct user_hwdebug_state, dbg_regs) + + sizeof(dreg_state.dbg_regs[0]); + + if (ptrace(PTRACE_GETREGSET, pid, NT_RISCV_HW_WATCH, &iov) =3D=3D 0) { + ksft_print_msg( + "ptrace(PTRACE_GETREGSET): Number of watchpoints: %u\n", + dreg_state.info); + ksft_print_msg( + "ptrace(PTRACE_GETREGSet): addr: 0x%lx control: 0x%x\n", + dreg_state.dbg_regs[0].addr, dreg_state.dbg_regs[0].control); + } else { + ksft_print_msg( + "ptrace(PTRACE_GETREGSET): Failed\n"); + return false; + } + + return true; + } + + if (errno =3D=3D EIO) + ksft_print_msg( + "ptrace(PTRACE_SETREGSET, NT_RISCV_HW_WATCH) not supported: %s\n= ", + strerror(errno)); + else + ksft_print_msg( + "ptrace(PTRACE_SETREGSET, NT_RISCV_HW_WATCH) failed: %s\n", + strerror(errno)); + return false; +} + +static bool set_breakpoint(pid_t pid, void (*bp_func)(void)) +{ + struct user_hwdebug_state dreg_state; + struct iovec iov; + unsigned int control =3D 0; + + control =3D (HW_BREAKPOINT_X << 14) & ((0x7 << 14)); + control |=3D (HW_BREAKPOINT_LEN_8 << 4) & ((0x1f << 4)); + memset(&dreg_state, 0, sizeof(dreg_state)); + dreg_state.dbg_regs[0].addr =3D (uintptr_t)bp_func; + dreg_state.dbg_regs[0].control =3D control; + iov.iov_base =3D &dreg_state; + iov.iov_len =3D offsetof(struct user_hwdebug_state, dbg_regs) + sizeof(dr= eg_state.dbg_regs[0]); + + if (ptrace(PTRACE_SETREGSET, pid, NT_RISCV_HW_BREAK, &iov) =3D=3D 0) + return true; + + if (errno =3D=3D EIO) + ksft_print_msg( + "ptrace(PTRACE_SETREGSET, NT_RISCV_HW_BREAK) not supported: %s\n= ", + strerror(errno)); + else + ksft_print_msg( + "ptrace(PTRACE_SETREGSET, NT_RISCV_HW_BREAK) failed: %s\n", + strerror(errno)); + + return false; +} + +static int run_ptrace_wp_test(void) +{ + pid_t pid =3D fork(); + pid_t wpid; + siginfo_t siginfo; + int status; + + if (pid =3D=3D 0) + do_wp_child(&var, 8); + + wpid =3D waitpid(pid, &status, __WALL); + if (wpid !=3D pid) { + ksft_print_msg( + "waitpid() failed: %s\n", strerror(errno)); + return false; + } + if (!WIFSTOPPED(status)) { + ksft_print_msg( + "child did not stop: %s\n", strerror(errno)); + return false; + } + if (WSTOPSIG(status) !=3D SIGSTOP) { + ksft_print_msg("child did not stop with SIGSTOP\n"); + return false; + } + + if (!set_watchpoint(pid, 8)) + return false; + + if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) { + ksft_print_msg( + "ptrace(PTRACE_CONT) failed: %s\n", + strerror(errno)); + return false; + } + + alarm(3); + wpid =3D waitpid(pid, &status, __WALL); + if (wpid !=3D pid) { + ksft_print_msg( + "waitpid() failed: %s\n", strerror(errno)); + return false; + } + alarm(0); + if (WIFEXITED(status)) { + ksft_print_msg("child exited prematurely\n"); + return false; + } + if (!WIFSTOPPED(status)) { + ksft_print_msg("child did not stop\n"); + return false; + } + if (WSTOPSIG(status) !=3D SIGTRAP) { + ksft_print_msg("child did not stop with SIGTRAP\n"); + return false; + } + if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo) !=3D 0) { + ksft_print_msg( + "ptrace(PTRACE_GETSIGINFO): %s\n", + strerror(errno)); + return false; + } + if (siginfo.si_code !=3D TRAP_HWBKPT) { + ksft_print_msg( + "Unexpected si_code %d\n", siginfo.si_code); + return false; + } + + kill(pid, SIGKILL); + wpid =3D waitpid(pid, &status, 0); + if (wpid !=3D pid) { + ksft_print_msg( + "waitpid() failed: %s\n", strerror(errno)); + return false; + } + + ksft_print_msg("[ptrace]: Watchpoint test passed!\n"); + + return true; +} + +static int run_ptrace_bp_test(void) +{ + pid_t pid =3D fork(); + pid_t wpid; + siginfo_t siginfo; + int status; + + if (pid =3D=3D 0) + do_bp_child(test_func); + + wpid =3D waitpid(pid, &status, __WALL); + if (wpid !=3D pid) { + ksft_print_msg( + "waitpid() failed: %s\n", strerror(errno)); + return false; + } + if (!WIFSTOPPED(status)) { + ksft_print_msg( + "child did not stop: %s\n", strerror(errno)); + return false; + } + if (WSTOPSIG(status) !=3D SIGSTOP) { + ksft_print_msg("child did not stop with SIGSTOP\n"); + return false; + } + + if (!set_breakpoint(pid, test_func)) + return false; + + if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) { + ksft_print_msg( + "ptrace(PTRACE_CONT) failed: %s\n", + strerror(errno)); + return false; + } + + alarm(3); + wpid =3D waitpid(pid, &status, __WALL); + if (wpid !=3D pid) { + ksft_print_msg( + "waitpid() failed: %s\n", strerror(errno)); + return false; + } + alarm(0); + if (WIFEXITED(status)) { + ksft_print_msg("child exited prematurely\n"); + return false; + } + if (!WIFSTOPPED(status)) { + ksft_print_msg("child did not stop\n"); + return false; + } + if (WSTOPSIG(status) !=3D SIGTRAP) { + ksft_print_msg("child did not stop with SIGTRAP\n"); + return false; + } + if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo) !=3D 0) { + ksft_print_msg( + "ptrace(PTRACE_GETSIGINFO): %s\n", + strerror(errno)); + return false; + } + if (siginfo.si_code !=3D TRAP_HWBKPT) { + ksft_print_msg( + "Unexpected si_code %d\n", siginfo.si_code); + return false; + } + + kill(pid, SIGKILL); + wpid =3D waitpid(pid, &status, 0); + if (wpid !=3D pid) { + ksft_print_msg( + "waitpid() failed: %s\n", strerror(errno)); + return false; + } + + ksft_print_msg("[ptrace]: Breakpoint test passed!\n"); + + return true; +} + +/* + * BREAKPOINT TEST USING PTRACE_SETHBPREGS / PTRACE_GETHBPREGS + */ +static bool set_hbpregs_watchpoint(pid_t pid) +{ + struct __riscv_hwdebug_state state; + + memset(&state, 0, sizeof(state)); + state.addr =3D (unsigned long)&var; + state.len =3D HW_BREAKPOINT_LEN_8; + state.type =3D HW_BREAKPOINT_W; + state.ctrl =3D 0; /* enabled */ + + if (ptrace(PTRACE_SETHBPREGS, pid, 0, &state) !=3D 0) { + ksft_print_msg( + "ptrace(PTRACE_SETHBPREGS) failed: %s\n", + strerror(errno)); + return false; + } + + /* Read back and verify */ + memset(&state, 0, sizeof(state)); + if (ptrace(PTRACE_GETHBPREGS, pid, 0, &state) !=3D 0) { + ksft_print_msg( + "ptrace(PTRACE_GETHBPREGS) failed: %s\n", + strerror(errno)); + return false; + } + + ksft_print_msg( + "[hbpregs] watchpoint readback: addr=3D0x%lx type=3D%lu len=3D%lu ctrl= =3D%lu\n", + state.addr, state.type, state.len, state.ctrl); + + return true; +} + +static bool set_hbpregs_breakpoint(pid_t pid, void (*bp_func)(void)) +{ + struct __riscv_hwdebug_state state; + + memset(&state, 0, sizeof(state)); + state.addr =3D (unsigned long)bp_func; + state.len =3D HW_BREAKPOINT_LEN_4; + state.type =3D HW_BREAKPOINT_X; + state.ctrl =3D 0; /* enabled */ + + if (ptrace(PTRACE_SETHBPREGS, pid, 0, &state) !=3D 0) { + ksft_print_msg( + "ptrace(PTRACE_SETHBPREGS) failed: %s\n", + strerror(errno)); + return false; + } + + /* Read back and verify */ + memset(&state, 0, sizeof(state)); + if (ptrace(PTRACE_GETHBPREGS, pid, 0, &state) !=3D 0) { + ksft_print_msg( + "ptrace(PTRACE_GETHBPREGS) failed: %s\n", + strerror(errno)); + return false; + } + + ksft_print_msg( + "[hbpregs] breakpoint readback: addr=3D0x%lx type=3D%lu len=3D%lu ctrl= =3D%lu\n", + state.addr, state.type, state.len, state.ctrl); + + return true; +} + +static int run_hbpregs_wp_test(void) +{ + pid_t pid =3D fork(); + pid_t wpid; + siginfo_t siginfo; + int status; + + if (pid =3D=3D 0) + do_wp_child(&var, 8); + + wpid =3D waitpid(pid, &status, __WALL); + if (wpid !=3D pid) { + ksft_print_msg("waitpid() failed: %s\n", strerror(errno)); + return false; + } + if (!WIFSTOPPED(status)) { + ksft_print_msg("child did not stop: %s\n", strerror(errno)); + return false; + } + if (WSTOPSIG(status) !=3D SIGSTOP) { + ksft_print_msg("child did not stop with SIGSTOP\n"); + return false; + } + + if (!set_hbpregs_watchpoint(pid)) + return false; + + if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) { + ksft_print_msg("ptrace(PTRACE_CONT) failed: %s\n", + strerror(errno)); + return false; + } + + alarm(3); + wpid =3D waitpid(pid, &status, __WALL); + if (wpid !=3D pid) { + ksft_print_msg("waitpid() failed: %s\n", strerror(errno)); + return false; + } + alarm(0); + if (WIFEXITED(status)) { + ksft_print_msg("child exited prematurely\n"); + return false; + } + if (!WIFSTOPPED(status)) { + ksft_print_msg("child did not stop\n"); + return false; + } + if (WSTOPSIG(status) !=3D SIGTRAP) { + ksft_print_msg("child did not stop with SIGTRAP\n"); + return false; + } + if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo) !=3D 0) { + ksft_print_msg("ptrace(PTRACE_GETSIGINFO): %s\n", + strerror(errno)); + return false; + } + if (siginfo.si_code !=3D TRAP_HWBKPT) { + ksft_print_msg("Unexpected si_code %d\n", siginfo.si_code); + return false; + } + + kill(pid, SIGKILL); + wpid =3D waitpid(pid, &status, 0); + if (wpid !=3D pid) { + ksft_print_msg("waitpid() failed: %s\n", strerror(errno)); + return false; + } + + ksft_print_msg("[hbpregs]: Watchpoint test passed!\n"); + return true; +} + +static int run_hbpregs_bp_test(void) +{ + pid_t pid =3D fork(); + pid_t wpid; + siginfo_t siginfo; + int status; + + if (pid =3D=3D 0) + do_bp_child(test_func); + + wpid =3D waitpid(pid, &status, __WALL); + if (wpid !=3D pid) { + ksft_print_msg("waitpid() failed: %s\n", strerror(errno)); + return false; + } + if (!WIFSTOPPED(status)) { + ksft_print_msg("child did not stop: %s\n", strerror(errno)); + return false; + } + if (WSTOPSIG(status) !=3D SIGSTOP) { + ksft_print_msg("child did not stop with SIGSTOP\n"); + return false; + } + + if (!set_hbpregs_breakpoint(pid, test_func)) + return false; + + if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) { + ksft_print_msg("ptrace(PTRACE_CONT) failed: %s\n", + strerror(errno)); + return false; + } + + alarm(3); + wpid =3D waitpid(pid, &status, __WALL); + if (wpid !=3D pid) { + ksft_print_msg("waitpid() failed: %s\n", strerror(errno)); + return false; + } + alarm(0); + if (WIFEXITED(status)) { + ksft_print_msg("child exited prematurely\n"); + return false; + } + if (!WIFSTOPPED(status)) { + ksft_print_msg("child did not stop\n"); + return false; + } + if (WSTOPSIG(status) !=3D SIGTRAP) { + ksft_print_msg("child did not stop with SIGTRAP\n"); + return false; + } + if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo) !=3D 0) { + ksft_print_msg("ptrace(PTRACE_GETSIGINFO): %s\n", + strerror(errno)); + return false; + } + if (siginfo.si_code !=3D TRAP_HWBKPT) { + ksft_print_msg("Unexpected si_code %d\n", siginfo.si_code); + return false; + } + + kill(pid, SIGKILL); + wpid =3D waitpid(pid, &status, 0); + if (wpid !=3D pid) { + ksft_print_msg("waitpid() failed: %s\n", strerror(errno)); + return false; + } + + ksft_print_msg("[hbpregs]: Breakpoint test passed!\n"); + return true; +} + +static void run_hbpregs_tests(void) +{ + run_hbpregs_bp_test(); + run_hbpregs_wp_test(); +} + +/* + * BREAKPOINT TEST USING PTRACE_SETHBPREGS / PTRACE_GETHBPREGS - END + */ +static void run_ptrace_tests(void) +{ + run_ptrace_bp_test(); + run_ptrace_wp_test(); +} + +/* + * BREAKPOINT TEST USING PTRACE - END + */ + +/* + * BREAKPOINT TEST USING perf events + */ static int gfd; sem_t ib_mtx, wp_mtx; static int bp_triggered, wp_triggered; -static int test_func_sink; static const int wait_timeout_sec =3D 5; =20 int setup_bp(bool is_x, void *addr, int sig) @@ -56,7 +615,7 @@ int setup_bp(bool is_x, void *addr, int sig) =20 fd =3D syscall(SYS_perf_event_open, &pe, 0, -1, -1, 0); if (fd < 0) { - printf("Failed to open event: %llx\n", pe.config); + ksft_print_msg("Failed to open event: %llx\n", pe.config); return -1; } =20 @@ -75,11 +634,10 @@ static void sig_handler_bp(int signum, siginfo_t *oh, = void *uc) =20 bp_triggered++; =20 - printf("Breakpoint triggered!\n"); ioctl(gfd, PERF_EVENT_IOC_DISABLE, 0); ret =3D sem_post(&ib_mtx); if (ret) { - printf("Failed to report BP success\n"); + ksft_print_msg("Failed to report BP success\n"); return; } } @@ -88,28 +646,17 @@ static void sig_handler_wp(int signum, siginfo_t *oh, = void *uc) { int ret; =20 - printf("Watchpoint triggered!\n"); ioctl(gfd, PERF_EVENT_IOC_DISABLE, 0); wp_triggered++; =20 ret =3D sem_post(&wp_mtx); =20 if (ret) { - printf("Failed to report WP success\n"); + ksft_print_msg("Failed to report WP success\n"); return; } } =20 -/* - * Keep a real instruction address for HW execute breakpoints: prevent inl= ining - * and force a visible side effect so the function can't be optimized away. - */ -static noinline void test_func(void) -{ - test_func_sink++; - __asm__ __volatile__("" : : "g" (test_func_sink)); -} - static int trigger_bp(void) { struct sigaction sa; @@ -119,14 +666,14 @@ static int trigger_bp(void) sa.sa_flags =3D SA_SIGINFO; =20 if (sigaction(SIGIO, &sa, NULL) < 0) { - printf("Failed to setup signal handler\n"); + ksft_print_msg("Failed to setup signal handler\n"); return -1; } =20 gfd =3D setup_bp(1, test_func, SIGIO); =20 if (gfd < 0) { - printf("Failed to setup breakpoint.\n"); + ksft_print_msg("Failed to setup breakpoint.\n"); return -1; } =20 @@ -151,14 +698,14 @@ static int trigger_wp(void) sa.sa_flags =3D SA_SIGINFO; =20 if (sigaction(SIGUSR1, &sa, NULL) < 0) { - printf("Failed to setup signal handler\n"); + ksft_print_msg("Failed to setup signal handler\n"); return -1; } =20 gfd =3D setup_bp(0, &test_data, SIGUSR1); =20 if (gfd < 0) { - printf("Failed to setup watchpoint\n"); + ksft_print_msg("Failed to setup watchpoint\n"); return -1; } =20 @@ -204,7 +751,7 @@ int main(int argc, char *argv[]) return -1; =20 if (bp_triggered) - printf("Breakpoint test passed!\n"); + ksft_print_msg("[perf_event]: Breakpoint test passed!\n"); =20 sem_init(&wp_mtx, 0, 0); if (trigger_wp() < 0) @@ -213,7 +760,10 @@ int main(int argc, char *argv[]) return -1; =20 if (wp_triggered) - printf("Watchpoint test passed!\n"); + ksft_print_msg("[perf_event]: Watchpoint test passed!\n"); + + run_ptrace_tests(); + run_hbpregs_tests(); =20 return 0; } --=20 2.43.0 From nobody Fri Oct 2 08:26:24 2026 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.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 EB1AC3F1AAD for ; Wed, 30 Sep 2026 06:39:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790750401; cv=none; b=VOx5E/1WB+AreGl7B5pLLbHDjK0QBnt0jESVsM8izxO2tvU/MmdbXzwUmBIZCZIM+zWUHEghSxJK1VfAzf4VXGgPcbHqSuUqAdi4QyIFakOsxwlEt9O60GXnsZIYKd6rZ9rEYgdvIUNtSX+iolO/Zjk9/Qrq6nWuUyjrebT+t94= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790750401; c=relaxed/simple; bh=HGxGXTXLvBaqhWYOpegzS4m5eh3oHIWzLhknBT8tLo4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=T9ubKG/U9MwkT+hrX28kOrzOk7q9c0ujWsP4IYMtN19F+pTpzBnsB1s+8qCyFV9QV3xMl8J1G0opC/8pR4TTjDgftf2zbn1V9J+siBu4mI+izYH1Y61OyfXO8gxX7dGJYfYuOKuTprQnQdFs9vHKb/mIM6Q8PHzh9ks5FCysd4s= 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=Rlt/F4xF; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=De74wb76; arc=none smtp.client-ip=205.220.180.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="Rlt/F4xF"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="De74wb76" Received: from pps.filterd (m0279869.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 68U67lm82250195 for ; Wed, 30 Sep 2026 06:39:57 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=e9SunJHY/49 eRz/XxwO9Hm0rNLEpbDgeen5GEOzxiJQ=; b=Rlt/F4xFMIe86HlRua1WEZLPU93 GqbRwtOGO+8PmO2LXSTlC2ERM5a/yk8FYyO1GgYwhGIP+Ihk0g4SxmfC8uQ/88tm tQFCDghmS4HyI/xldFweS+6j95aBOriE7rAsZhr0qir44GJiEb41Gm1wHDDCWx3l kSd8yKZJaef1NYnP5U+feqbjKvVphCdjFPd+WFQhwRxqNi5KrdJV5AUoNjM/f6/C cgnxiiqUXeE4XJ54N7OP4ocfpRSQFhJYYBAIMR4WM2UzEJ/axfDFk5xoNNyaWAb7 IIKWAU/yO4PqS3IoaFeX3oiX/P9JvTa9lTIVbKW1cRfMbs7aze9qQJQhG2Q== Received: from mail-dl1-f69.google.com (mail-dl1-f69.google.com [74.125.82.69]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4h0nm3hv8m-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Wed, 30 Sep 2026 06:39:57 +0000 (GMT) Received: by mail-dl1-f69.google.com with SMTP id a92af1059eb24-142f4306744so3888478c88.1 for ; Tue, 29 Sep 2026 23:39:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1790750397; x=1791355197; 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=e9SunJHY/49eRz/XxwO9Hm0rNLEpbDgeen5GEOzxiJQ=; b=De74wb76AXTMn0ajdsg8mWI3wc6Cg8jOssW+nAqKQBtpubMardN5dH9zJvsiAJIg8w KnHpcdLpOhkXlaFism/aUehVSk8Nb4H/rUEau/DTuDSqVCTxMkt6/Mcd9dKIpuoj1uCj Nv5ybDtOSpUY0RiEmYJIE2yb0tuTKJrVU97YsTCSp2ELueRiyIMIdjVZTT5nAZAKUmyx 2I8TMlzVOjGbR1pYZMF4dz5I7TZVkRRj/k6RGegH4eoP1ziXun5CXXiUHSj22bRwRFBx gAxTieZHUenY2m+v6GqxdXDBs+u8uaQUm4NLSvjwJ6YCRp4B0JKTRl2M4A+RpSSX6l6b bJhg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790750397; x=1791355197; 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=e9SunJHY/49eRz/XxwO9Hm0rNLEpbDgeen5GEOzxiJQ=; b=kgmZFNAQ4xQkWp1h96mH+6b2HW9Iav5xB9aORUPeYa+WRo1rTnErvpYOC8y7r6e1IH 5VbNgqEBMzoSZChKQ4ZrVg4RUoFJaEuvkg8IDTox1AWUysK7FZEN1JMSo3LCyp6Krn7p P0zTI1GPkObfSRIR1wk0ylFka2t4myhjDmv3sOZR/EBOUGhLj3WBPqtcVYADSXLSZWu9 jQrfOnvCNILd9GGRr/CuVX8nMJu2SWynXbq90DVpEY8HNc3deqXVWYDfP+8r0lFtTk+n UpK/wYPryemJSaLTHnmw8Hjru2ZCRGcgU04Dx3YYoap4Klxk8gkzotqwuStVXvXIhBlQ kASA== X-Gm-Message-State: AFuF++knMjVQv2wzDn7TsjctFjVQQ3gjNbJ4sMER0nxrJF37gio3agNI 8a9+WXcg9VYDmrZbJw7NdBgWQkATk5Iq2+kOIMQVGBN7Lp+VovpB5fxjncw/1V5CAA/CqWAutGu E6jHJUxHVGENot+shUbj77fDyqDJMU4gtYec/L3pLHPXF/zKhoODlYLRl56VT2GWhqiWEMlXIKR I= X-Gm-Gg: AYBFou0YBH1FkB+S+guEDQ8JTg2df8EwB6nDj0TkGxovFFARqFbQYGM/BZathF5bbp7 wYg6k2eUE3+OPiXWekBxn9TI38U1fcZEWSyd/WsOb2EiuEWTEWsuOZKuHUPC4BY+il1NMtuBq9p cA8L7jAm+kthp1PwW8KkZWv16XaT2NTMJgoPyu4MUY8YiURPYYhiTOlpdW+9JVRWocCFrMNRKzu uviwc9WM4JqSSK5eRZLu6OT6rkA5lisMDunkpYcUtgcY/srgFXrHGJ4nWTmT92FkDNgINOty0Z6 9nnIzaQg1axfglzLT4lM4Yoolj+N8OIh2fIzY+hdaIEdC9nmlNhdaHtYj9FShBbaj58OOglRI+G v+oPTFi6jIRWWxaVfoJ95tSL171dP5YU72gn/vH7c7L3GIqJYuY+7u0wu9cXUoXcQEua1+Gmb8f qC5P8HRWhPCkHRbPG8DxBWpykh X-Received: by 2002:a05:7022:238c:b0:143:46a6:b04f with SMTP id a92af1059eb24-14d32bde173mr538883c88.31.1790750396415; Tue, 29 Sep 2026 23:39:56 -0700 (PDT) X-Received: by 2002:a05:7022:238c:b0:143:46a6:b04f with SMTP id a92af1059eb24-14d32bde173mr538801c88.31.1790750395492; Tue, 29 Sep 2026 23:39:55 -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.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 29 Sep 2026 23:39:55 -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 5/8] RISC-V: Add fetch and decode helpers to a common file Date: Wed, 30 Sep 2026 12:09:16 +0530 Message-ID: <20260930063919.608911-6-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: quoted-printable X-Proofpoint-ORIG-GUID: o8t5iAwImYkRT1MKZPtSvWjv5IYgOboo X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTMwMDAyNiBTYWx0ZWRfX1W7VieJInpWT GzXdn8iQxm0C5KN2HRLCyuJPGRVw6GWbBHJYuugCrqpyKBy+YvAfn4kmDKytxnNciP+0lEBoldG ZjnMGI+9HiYhGc6bRayTEAuXrK1gJYbWN8/JkogyYrw9uETGp747DH6WVTh4lDA+YUvZ9ZH6oAx Sm3U2uY25P2xo6RSR0KRiDR+Bc1GLw2E3UaL7u/R1MofeEgGJgZwxchaQR2XmLzLQGrFkHFInQL H1VDz3EXcldOekFw8g2TA8fBhlIxNIXLS2owbaj9RenP5hDZ4dLwDHqRQJPhY7PWMFBcIl2WWw6 hKDHCr2MB84eoTciyHQQKlVc8wMYaSJTJLa2geTpq1DVS2u4cE+gSZ1XQ70t+mSIXczJdJtJXiU ifh645KifIQT8wsuC/zw5jF1TNtCAjaZYZBMMVKRBytHXpOxdBfApoJRkmWLPTw3vmhbeAhsTmC m/gIWi8qOcQK+0k3OjA== X-Proofpoint-Spam-Info: AW1haW4tMjYwOTMwMDAyNiBTYWx0ZWRfX7HEs4XvRF7dI HEkpnes5ltKRjUhcucBmGnnLscvgVzeaTMIYtrVRZ/HJE3N/6PbVTQF4UjLvYuyAFAV5+iMfBVI TorERQy02+xtjhomjRqfPUlN31LSbW4= X-Proofpoint-GUID: o8t5iAwImYkRT1MKZPtSvWjv5IYgOboo X-Authority-Analysis: v=2.4 cv=fqxJ914f c=1 sm=1 tr=0 ts=6abcaebd cx=c_pps a=kVLUcbK0zfr7ocalXnG1qA==:117 a=Ou0eQOY4+eZoSc0qltEV5Q==:17 a=VdqzKS8jKosA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=_glEPmIy2e8OvE2BGh3C:22 a=EUspDBNiAAAA:8 a=20KFwNOVAAAA:8 a=XkDl4Et5ty8ZtOCQo2QA:9 a=vr4QvYf-bLy2KjpDp97w:22 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 adultscore=0 clxscore=1015 impostorscore=0 malwarescore=0 suspectscore=0 spamscore=0 bulkscore=0 priorityscore=1501 lowpriorityscore=0 phishscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2609040000 definitions=main-2609300026 Content-Type: text/plain; charset="utf-8" Move get_insn() and __read_insn() from traps_misaligned.c Add helpers for RISC-V register access and control-flow emulation Add helpers to retrieve RISC-V register values, calcuate the next execution address based on current pc, register states and by evaluating conditional branch instructions. the helpers accommodate both compressed and standard instructions. Add helper to determine is brach will be taken by current pc. It supports register-based jumps, immediate jumps, BEQZ/BNEZ conditional branches, and signed and unsigned comparisons for standard conditional branch instructions. Signed-off-by: Himanshu Chauhan Co-developed-by: Jesse Taube --- arch/riscv/include/asm/insn.h | 15 ++ arch/riscv/kernel/traps_misaligned.c | 52 +----- arch/riscv/lib/Makefile | 1 + arch/riscv/lib/insn.c | 263 +++++++++++++++++++++++++++ 4 files changed, 280 insertions(+), 51 deletions(-) create mode 100644 arch/riscv/lib/insn.c diff --git a/arch/riscv/include/asm/insn.h b/arch/riscv/include/asm/insn.h index c3005573e8c9..b2125728d4e9 100644 --- a/arch/riscv/include/asm/insn.h +++ b/arch/riscv/include/asm/insn.h @@ -227,9 +227,16 @@ #define RVC_MASK_C_EBREAK 0xffff #define RVG_MASK_EBREAK 0xffffffff #define RVG_MASK_SRET 0xffffffff +#define RVC_MASK_INSN GENMASK(15, 0) =20 #define __INSN_LENGTH_MASK _UL(0x3) #define __INSN_LENGTH_GE_32 _UL(0x3) + +static __always_inline bool riscv_insn_is_compressed(u32 code) +{ + return (code & (__INSN_LENGTH_MASK)) !=3D (__INSN_LENGTH_GE_32); +} + #define __INSN_OPCODE_MASK _UL(0x7F) #define __INSN_BRANCH_OPCODE _UL(RVG_OPCODE_BRANCH) =20 @@ -600,4 +607,12 @@ static inline void riscv_insn_insert_utype_itype_imm(u= 32 *utype_insn, u32 *itype *utype_insn |=3D (imm & RV_U_IMM_31_12_MASK) + ((imm & BIT(11)) << 1); *itype_insn |=3D ((imm & RV_I_IMM_11_0_MASK) << RV_I_IMM_11_0_OPOFF); } +#ifndef __ASSEMBLY__ +#include + +int get_insn(struct pt_regs *regs, ulong epc, ulong *r_insn); +int get_insn_safe(struct pt_regs *regs, ulong epc, ulong *r_insn); +unsigned long get_next_insn_address(struct pt_regs *regs, ulong insn, ulon= g pc); +#endif /* __ASSEMBLY__ */ + #endif /* _ASM_RISCV_INSN_H */ diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps= _misaligned.c index 6e8ae6c66322..541e6a5b8039 100644 --- a/arch/riscv/kernel/traps_misaligned.c +++ b/arch/riscv/kernel/traps_misaligned.c @@ -10,6 +10,7 @@ #include #include =20 +#include #include #include #include @@ -129,57 +130,6 @@ static unsigned long get_f32_rs(unsigned long insn, u8= fp_reg_offset, #define GET_F32_RS2C(insn, regs) (get_f32_rs(insn, 2, regs)) #define GET_F32_RS2S(insn, regs) (get_f32_rs(RVC_RS2S(insn), 0, regs)) =20 -#define __read_insn(regs, insn, insn_addr, type) \ -({ \ - int __ret; \ - \ - if (user_mode(regs)) { \ - __ret =3D get_user(insn, (type __user *) insn_addr); \ - } else { \ - insn =3D *(type *)insn_addr; \ - __ret =3D 0; \ - } \ - \ - __ret; \ -}) - -static inline int get_insn(struct pt_regs *regs, ulong epc, ulong *r_insn) -{ - ulong insn =3D 0; - - if (epc & 0x2) { - ulong tmp =3D 0; - - if (__read_insn(regs, insn, epc, u16)) - return -EFAULT; - /* __get_user() uses regular "lw" which sign extend the loaded - * value make sure to clear higher order bits in case we "or" it - * below with the upper 16 bits half. - */ - insn &=3D GENMASK(15, 0); - if ((insn & __INSN_LENGTH_MASK) !=3D __INSN_LENGTH_32) { - *r_insn =3D insn; - return 0; - } - epc +=3D sizeof(u16); - if (__read_insn(regs, tmp, epc, u16)) - return -EFAULT; - *r_insn =3D (tmp << 16) | insn; - - return 0; - } else { - if (__read_insn(regs, insn, epc, u32)) - return -EFAULT; - if ((insn & __INSN_LENGTH_MASK) =3D=3D __INSN_LENGTH_32) { - *r_insn =3D insn; - return 0; - } - insn &=3D GENMASK(15, 0); - *r_insn =3D insn; - - return 0; - } -} =20 union reg_data { u8 data_bytes[8]; diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile index f668b98970bd..84cdd35afa42 100644 --- a/arch/riscv/lib/Makefile +++ b/arch/riscv/lib/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only lib-y +=3D delay.o +lib-y +=3D insn.o lib-y +=3D memcpy.o lib-y +=3D memset.o lib-y +=3D memmove.o diff --git a/arch/riscv/lib/insn.c b/arch/riscv/lib/insn.c new file mode 100644 index 000000000000..361cac7abe10 --- /dev/null +++ b/arch/riscv/lib/insn.c @@ -0,0 +1,263 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2026 Qualcomm Technoloies, Inc. + */ + +#include + +#include +#include +#include + +/** + * __fetch_insn() - Fetch a RISC-V instruction parcel from memory + * @regs: Register state used to determine the access context + * @insn: Variable receiving the instruction value + * @insn_addr: Address from which to read the instruction parcel + * @type: Instruction parcel type, either @u16 or @u32 + * + * Fetches an instruction parcel from user or kernel memory, depending on = the + * execution context indicated by @regs. RISC-V instruction parcels are + * stored in little-endian byte order, so the fetched value is converted f= rom + * little-endian to the native CPU representation before being assigned to + * @insn. + * + * The conversion is a no-op on little-endian targets and performs the + * required byte swap on big-endian targets. + * + * Return: 0 on success, or a negative error code if reading user memory + * fails. + */ +#define __fetch_insn(regs, insn, insn_addr, type) \ +({ \ + type __val; \ + int __ret; \ + \ + if (user_mode(regs)) \ + __ret =3D get_user(__val, \ + (type __user *)(insn_addr)); \ + else { \ + __val =3D *(type *)(insn_addr); \ + __ret =3D 0; \ + } \ + \ + if (!__ret) { \ + if (sizeof(type) =3D=3D sizeof(u16)) \ + (insn) =3D le16_to_cpu((__force __le16)__val); \ + else \ + (insn) =3D le32_to_cpu((__force __le32)__val); \ + } \ + \ + __ret; \ +}) + +/** + * get_insn() - Fetch and decode a RISC-V instruction + * @regs: Register state used for instruction access + * @epc: Address of the instruction to fetch + * @r_insn: Pointer to store the fetched instruction encoding + * + * Fetches the instruction at @epc and stores its encoding in @r_insn. + * Both standard 32-bit instructions and compressed 16-bit instructions are + * supported. If a 32-bit instruction is split across two 16-bit instructi= on + * accesses, the halfwords are combined into a single instruction encoding. + * + * Return: 0 on success, or %-EFAULT if instruction access fails. + */ +int get_insn(struct pt_regs *regs, ulong epc, ulong *r_insn) +{ + ulong insn, tmp; + + if (!(epc & 0x2)) { + if (__fetch_insn(regs, insn, epc, u32)) + return -EFAULT; + + if (riscv_insn_is_compressed(insn)) + insn &=3D RVC_MASK_INSN; + + *r_insn =3D insn; + return 0; + } + + if (__fetch_insn(regs, insn, epc, u16)) + return -EFAULT; + + insn &=3D RVC_MASK_INSN; + if (riscv_insn_is_compressed(insn)) { + *r_insn =3D insn; + return 0; + } + + if (__fetch_insn(regs, tmp, epc + sizeof(u16), u16)) + return -EFAULT; + + *r_insn =3D (tmp << 16) | insn; + + return 0; +} + +int get_insn_safe(struct pt_regs *regs, ulong epc, ulong *r_insn) +{ + int ret; + + pagefault_disable(); + ret =3D get_insn(regs, epc, r_insn); + pagefault_enable(); + + return ret; +} + +/** + * riscv_get_reg_value() - Get the value stored the given RISC-V register = number + * @regs: Register state containing the saved register values + * @regno: RISC-V register number + * + * Returns the value of the RISC-V register identified by @regno. Register + * x0 always returns zero, as required by the RISC-V ISA. + * + * Return: The register value, or zero if @regno is zero. + */ +static unsigned long riscv_get_reg_value(struct pt_regs *regs, unsigned in= t regno) +{ + return regno ? regs_get_register(regs, regno * sizeof(unsigned long)) : 0; +} + +/** + * get_next_insn_address_compressed() - Calculate the next address for a c= ompressed + * RISC-V instruction + * @regs: Register state used to evaluate indirect jumps and conditional + * branches + * @insn: Compressed RISC-V instruction encoding + * @pc: Current program counter + * + * Determines the address at which execution should continue after process= ing + * the compressed instruction in @insn. Indirect jumps use the value of the + * instruction's source register, unconditional jumps use the encoded + * immediate, and conditional branches evaluate the relevant register valu= e. + * + * For a branch that is not taken, or for an unsupported compressed + * instruction, the address of the following 16-bit instruction is returne= d. + * + * Return: The next instruction address. + */ +static unsigned long get_next_insn_address_compressed(struct pt_regs *regs= , u32 insn, + unsigned long pc) +{ + unsigned int rs1_num; + + if (riscv_insn_is_c_jalr(insn) || riscv_insn_is_c_jr(insn)) { + rs1_num =3D RV_X(insn, RVC_C2_RS1_OPOFF, 5); + return regs_get_register(regs, rs1_num * sizeof(unsigned long)); + } + + if (riscv_insn_is_c_j(insn) || riscv_insn_is_c_jal(insn)) + return RVC_EXTRACT_JTYPE_IMM(insn) + pc; + + if (riscv_insn_is_c_beqz(insn)) { + rs1_num =3D RV_X(insn, RVC_C1_RS1_OPOFF, 3) + 8; + if (!rs1_num || riscv_get_reg_value(regs, rs1_num) =3D=3D 0) + return RVC_EXTRACT_BTYPE_IMM(insn) + pc; + return pc + 2; + } + + if (riscv_insn_is_c_bnez(insn)) { + rs1_num =3D RV_X(insn, RVC_C1_RS1_OPOFF, 3) + 8; + if (rs1_num && riscv_get_reg_value(regs, rs1_num) !=3D 0) + return RVC_EXTRACT_BTYPE_IMM(insn) + pc; + return pc + 2; + } + + return pc + 2; +} + +/** + * riscv_branch_taken() - Determine whether a RISC-V conditional branch is= taken + * @regs: Register state used to obtain the source operand values + * @insn: RISC-V branch instruction encoding + * + * Evaluates the branch condition encoded in @insn using the values of its + * source registers from @regs. Signed comparisons are used for BLT and BG= E, + * while unsigned comparisons are used for BLTU and BGEU. + * + * Return: %true if the branch condition is satisfied, or %false otherwise. + * Unsupported branch instructions also return %false. + */ +static bool riscv_branch_taken(struct pt_regs *regs, u32 insn) +{ + unsigned int rs1_num =3D RV_X(insn, RVG_RS1_OPOFF, 5); + unsigned int rs2_num =3D RV_X(insn, RVG_RS2_OPOFF, 5); + unsigned long rs1_val =3D riscv_get_reg_value(regs, rs1_num); + unsigned long rs2_val =3D riscv_get_reg_value(regs, rs2_num); + + if (riscv_insn_is_beq(insn)) + return rs1_val =3D=3D rs2_val; + if (riscv_insn_is_bne(insn)) + return rs1_val !=3D rs2_val; + if (riscv_insn_is_blt(insn)) + return (long)rs1_val < (long)rs2_val; + if (riscv_insn_is_bge(insn)) + return (long)rs1_val >=3D (long)rs2_val; + if (riscv_insn_is_bltu(insn)) + return rs1_val < rs2_val; + if (riscv_insn_is_bgeu(insn)) + return rs1_val >=3D rs2_val; + + return false; +} + +/** +* get_next_insn_address_standard() - Compute the next PC for standard RISC= -V +* control-flow instructions +* +* @regs: Register state of the current context. +* @insn: Instruction located at @pc. +* @pc: Address of the current instruction. +* +* Determine the address of the next instruction to be executed after @insn. +* The function evaluates control-flow instructions whose target cannot be +* obtained by simply advancing the program counter: +* +* - Conditional branches: returns either the branch target or @pc + 4 +* depending on the branch outcome. +* - JAL: returns the jump target encoded in the instruction. +* - JALR: returns the computed indirect jump target using the instruction +* immediate and the value of the source register. +* - SRET: returns @pc, as control transfer is handled by the trap return +* mechanism. +* +* For all other instructions, execution is assumed to continue at the next +* sequential 32-bit instruction and @pc + 4 is returned. +* +* Return: Address of the next instruction to be executed. +*/ +static unsigned long get_next_insn_address_standard(struct pt_regs *regs, = u32 insn, + unsigned long pc) +{ + unsigned int rs1_num; + + if ((insn & __INSN_OPCODE_MASK) =3D=3D __INSN_BRANCH_OPCODE) + return riscv_branch_taken(regs, insn) ? + RV_EXTRACT_BTYPE_IMM(insn) + pc : pc + 4; + + if (riscv_insn_is_jal(insn)) + return RV_EXTRACT_JTYPE_IMM(insn) + pc; + + if (riscv_insn_is_jalr(insn)) { + rs1_num =3D RV_X(insn, RVG_RS1_OPOFF, 5); + return RV_EXTRACT_ITYPE_IMM(insn) + riscv_get_reg_value(regs, rs1_num); + } + + if (riscv_insn_is_sret(insn)) + return pc; + + return pc + 4; +} + +/* Calculate the new address for after a step */ +unsigned long get_next_insn_address(struct pt_regs *regs, ulong insn, ulon= g pc) +{ + if (riscv_insn_is_compressed(insn)) + return get_next_insn_address_compressed(regs, insn, pc); + + return get_next_insn_address_standard(regs, insn, pc); +} --=20 2.43.0 From nobody Fri Oct 2 08:26:24 2026 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: quoted-printable 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 Content-Type: text/plain; charset="utf-8" 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/as= m/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; }; =20 struct perf_event_attr; diff --git a/arch/riscv/kernel/hw_breakpoint.c b/arch/riscv/kernel/hw_break= point.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 =20 +#include #include =20 /* Registered per-cpu bp/wp */ @@ -328,8 +331,11 @@ int hw_breakpoint_arch_parse(struct perf_event *bp, =20 /* Breakpoint address */ hw->address =3D attr->bp_addr; + hw->tdata1 =3D 0; hw->tdata2 =3D attr->bp_addr; hw->tdata3 =3D 0x0; + hw->next_addr =3D 0x0; + hw->in_callback =3D false; =20 switch (dbtr_type) { case RISCV_DBTR_TRIG_MCONTROL: @@ -347,6 +353,93 @@ int hw_breakpoint_arch_parse(struct perf_event *bp, return ret; } =20 +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 =3D counter_arch_bp(event); + unsigned long insn, next_addr =3D 0; + int ret; + struct arch_hw_breakpoint tmp =3D {}; + + /* + * Save the original trigger configuration so we can restore it + * after the single-step fires. + */ + bp->saved_tdata1 =3D bp->tdata1; + bp->saved_tdata2 =3D bp->tdata2; + bp->saved_tdata3 =3D bp->tdata3; + + ret =3D get_insn_safe(regs, regs->epc, &insn); + if (ret < 0) + return ret; + + next_addr =3D 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 =3D 0; + tmp.tdata2 =3D next_addr; + tmp.tdata3 =3D 0; + switch (dbtr_type) { + case RISCV_DBTR_TRIG_MCONTROL6: + RISCV_DBTR_SET_MC6_EXEC_BIT(tmp.tdata1); + tmp.tdata1 =3D RISCV_DBTR_SET_MC6_SIZE(tmp.tdata1, 0); + tmp.tdata1 =3D 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 =3D RISCV_DBTR_SET_MC_SIZELO(tmp.tdata1, 0); + tmp.tdata1 =3D RISCV_DBTR_SET_MC_SIZEHI(tmp.tdata1, 0); + tmp.tdata1 =3D 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 =3D tmp.tdata1; + bp->tdata2 =3D next_addr; + bp->tdata3 =3D 0; + arch_update_hw_breakpoint(event); + + bp->in_callback =3D true; + bp->next_addr =3D 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 =3D NOTIFY_DONE; + int i, ret =3D 0, bp_ret =3D NOTIFY_DONE; + bool expecting_callback =3D false; struct arch_hw_breakpoint *bp; struct perf_event *event; - int i; =20 for (i =3D 0; i < dbtr_total_num; i++) { event =3D this_cpu_read(pcpu_hw_bp_events[i]); @@ -412,85 +505,122 @@ static int hw_breakpoint_handler(struct die_args *ar= gs) continue; =20 bp =3D counter_arch_bp(event); - switch (bp->type) { - /* Breakpoint */ - case HW_BREAKPOINT_X: - { - bool hit =3D bp->address =3D=3D args->regs->epc; =20 - if (!hit && dbtr_type =3D=3D RISCV_DBTR_TRIG_MCONTROL6) - hit =3D mc6_read_and_clear_hit(i) !=3D RISCV_DBTR_MC6_HIT_FALSE; + if (bp->in_callback) { + expecting_callback =3D true; + if (args->regs->epc !=3D bp->next_addr) + continue; + + arch_uninstall_hw_breakpoint(event); =20 - if (hit) { - perf_bp_event(event, args->regs); - ret =3D 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 =3D false; + bp_ret =3D NOTIFY_STOP; + goto exit; + } + + switch (event->attr.bp_type) { + /* Breakpoint */ + case HW_BREAKPOINT_X: + { + bool hit =3D bp->address =3D=3D args->regs->epc; + + if (!hit && dbtr_type =3D=3D RISCV_DBTR_TRIG_MCONTROL6) + hit =3D mc6_read_and_clear_hit(i) !=3D RISCV_DBTR_MC6_HIT_FALSE; + + if (hit) { + perf_bp_event(event, args->regs); + ret =3D setup_singlestep(event, args->regs); + if (ret < 0) { + pr_err("Single step setup failed: %d.\n", ret); + goto exit; + } + bp_ret =3D NOTIFY_STOP; + goto exit; + } } break; - } =20 /* Watchpoint */ case HW_BREAKPOINT_W: case HW_BREAKPOINT_R: case HW_BREAKPOINT_RW: - { - unsigned long stval =3D args->regs->badaddr; - unsigned long bp_start =3D bp->address; - unsigned long bp_len =3D bp->len ?: 1; - unsigned long bp_end =3D bp_start + bp_len - 1; - unsigned long stval_end =3D stval + sizeof(long) - 1; - bool hit =3D false; - - if (bp_end < bp_start) - bp_end =3D ~0UL; - if (stval_end < stval) - stval_end =3D ~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 =3D=3D 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 =3D this_cpu_ptr(sbi_dbtr_shmem); - sret =3D sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_TRIG_READ, - i, 1, 0, 0, 0, 0); - if (!sret.error) { - tdata1 =3D le_to_cpu(shmem->data.tdata1); - hit =3D !!(tdata1 & RISCV_DBTR_MC_HIT_BIT_MASK); + { + unsigned long stval =3D args->regs->badaddr; + unsigned long bp_start =3D bp->address; + unsigned long bp_len =3D bp->len ?: 1; + unsigned long bp_end =3D bp_start + bp_len - 1; + unsigned long stval_end =3D stval + sizeof(long) - 1; + bool hit =3D false; + + if (bp_end < bp_start) + bp_end =3D ~0UL; + if (stval_end < stval) + stval_end =3D ~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 =3D=3D 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 =3D this_cpu_ptr(sbi_dbtr_shmem); + sret =3D sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_TRIG_READ, + i, 1, 0, 0, 0, 0); + if (!sret.error) { + tdata1 =3D le_to_cpu(shmem->data.tdata1); + hit =3D !!(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 =3D=3D RISCV_DBTR_TRIG_MCONTROL6) { + hit =3D mc6_read_and_clear_hit(i) !=3D RISCV_DBTR_MC6_HIT_FALSE; } - raw_spin_unlock_irqrestore(this_cpu_ptr(&ecall_lock), - *this_cpu_ptr(&ecall_lock_flags)); - } else if (dbtr_type =3D=3D RISCV_DBTR_TRIG_MCONTROL6) { - hit =3D mc6_read_and_clear_hit(i) !=3D RISCV_DBTR_MC6_HIT_FALSE; - } =20 - /* - * Sdtrig may report STVAL as the lowest accessed - * address while the watchpoint can match a higher byte - * in the same access. - */ - if (hit || - (stval >=3D bp_start && stval <=3D bp_end) || - (bp_start >=3D stval && bp_start <=3D stval_end)) { - perf_bp_event(event, args->regs); - ret =3D 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 >=3D bp_start && stval <=3D bp_end) || + (bp_start >=3D stval && bp_start <=3D stval_end)) { + perf_bp_event(event, args->regs); + ret =3D setup_singlestep(event, args->regs); + if (ret < 0) { + pr_err("setup_singlestep failed %d.\n", ret); + goto exit; + } + bp_ret =3D NOTIFY_STOP; + goto exit; + } } break; - } =20 default: - pr_warn("Unknown type: %u\n", bp->type); - break; + pr_warn("Unknown type: %u\n", event->attr.bp_type); + goto exit; } } =20 - 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; } =20 int hw_breakpoint_exceptions_notify(struct notifier_block *unused, --=20 2.43.0 From nobody Fri Oct 2 08:26:24 2026 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 876E93F3272 for ; Wed, 30 Sep 2026 06:40:08 +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=1790750410; cv=none; b=KhBrlqNLunYVJPcyvE3RxZv4PPMQ4LsBi2Y1hgam5Jy5ENhBKUpea8PYc410m0UeKiojLv4/EuuLl1ljKBbIgMBV/N/YG+8VoxWTPQZV5Y0ZG5YsjHah0rgqlYouLRC0/WdAdRpi1SYqQnjsjixfP2Ak2vWDWow7M+4J96B5ThM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790750410; c=relaxed/simple; bh=FKb6BaGaOw+y5XBKoZBVYiEHstm1iw3inajCMM+zbvU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=nhB84eUQ5/MtZKnZUyhXEVUWIt665R9T7/IVKRyHNOO2SH5mjb8O1Sik4sGiIboE/wW15uQFOvBGODTNO4tnnZuZi02OVWKwlWFDj4up46MtUvavZomIpZj4LkoVhYuf+uCb9JlNzb2EG99mS9wZHmrWbbA1vI5zk+BgKr8ZQhE= 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=JB6bR8Sx; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=J94tN9fS; 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="JB6bR8Sx"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="J94tN9fS" Received: from pps.filterd (m0279862.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 68U3VZDq1887256 for ; Wed, 30 Sep 2026 06:40:07 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=A81eQh/mNmH iDTVrzFWMP6oC61Wb5fR8bGkTk+ZPckI=; b=JB6bR8SxkavlYwB2R2oAFmSYfik qKiA3JBjyRFOAPxaSr5FAZwumsoNDZ1EvxiRgA+4MI1J3Kx+qcfwsgvuB3f4H7KU 08cfYrOQlhiOXoiy+ydVHJZFv/78wYZAf/8UHvC6ERJXGTkExFi16p5V8ePitYqL glLVF3QnbZboWXc+TWf+vgs3xwqCytSL8jzaGmCYOHYfwJ3sCx23qV9Q+/yJr8uf dmWxEhQIBG/s/SPzgqx+ezFDxSvnIIHy/cGb1bd3WPkpErDxd81pq1HDv0oBWVZD ZCDmM0/3AT0B29KbG3EB5XNZvXGSt5rrJiEM6dQaMOfvJHXNy6osd4zq1KQ== Received: from mail-dy1-f200.google.com (mail-dy1-f200.google.com [74.125.82.200]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4h0tkn0p85-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Wed, 30 Sep 2026 06:40:07 +0000 (GMT) Received: by mail-dy1-f200.google.com with SMTP id 5a478bee46e88-34d18eee3dfso324192eec.0 for ; Tue, 29 Sep 2026 23:40:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1790750407; x=1791355207; 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=A81eQh/mNmHiDTVrzFWMP6oC61Wb5fR8bGkTk+ZPckI=; b=J94tN9fSJB+Anu5G6QIDE9Wpn41Nabh8F+M2l/BVUTEXEXZCMzkDBHsp/MgQiS+2cz entLSQlLk2ZgKtLAEEPisuK14/oSeXHKPSsAlFSllBJpXAq/oj7KnanSo5TlO0iLQ/VN WgjaXYBP0XTE6hM1mylva01LH2eW0vdsfKglqAkjD5xQ6PcFxTaTu/QgtFnYaKgrxho4 09PldGtMhXUgxsCZe0SKNsxXfO6gtWsobGcRNxY5HvMw0nJX+1xrNoUXGmrVdPVvDVOV btVZlkoK/tnBWE5Y9ASmwriSYFLI60iWjSxsBjlEkAm7R7XlTLgNblmwFvLU/np1DIMa 0+ZQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790750407; x=1791355207; 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=A81eQh/mNmHiDTVrzFWMP6oC61Wb5fR8bGkTk+ZPckI=; b=G56y5LuFFA5R0iDrCAOnDuY0bpHMhLkwkBwCbtRww8rVxC4aeUuikqu9+kW17rh+Jd UmESY3f06xR83V3VINVZyGTea4XxCydymQZM5+InwcgNA/nMcuY3NZ4UeDFa6MqMYbFg pF/jxRJReuqUNh4ZKB/lUkc/iu3pMh16Ln4+m2x+Rfy2m+2mdBPrI6ex+3ZDHw8TFiWz sz3/v4WdWexMQ2JvlR/EVvRIkDnr4QT6wdbg0ia0EHR8W4zRgLUXVP78ynyATvFgBxGJ jJMfvx+jlUaLr39oPx3k4oskmyQADVCE6ojmYfcrDKfCDY5qwFEmiPvXUFuDI6kaAbCw 5QWg== X-Gm-Message-State: AFuF++nzSLfNClMpAfnipUYBj2MwLA4kmRsYOulORE4GPtDuY4B807oS /xOjhPUNWvj/xBBG8eC6GRxP3sH+TcMcH+zzbbdW0K6vECnBkF3VPHVpWE0NAOnpZITvCHXQWvL ymLMSVj2zDuiqabV2/6OPZA/FZfwb2kZOLX2vWQlPTo3YPrScdhhxonR2PsJxRUb6+mox1mFapx g= X-Gm-Gg: AYBFou2AC+jnBSBhjpOYZMPedmLVJotuF9e90E6DJ62Zzv6BT4M7Tb+Xyav2Q22xcab r4w8+RsrWsK4BUG95L1fd/vftU0R58H2cDHonr24+bN1gbm6/vGHy1MoptO4Z18zbVeR2yDWOvV ZTNOe7evamD9K7A4CLfTuizO5fd5UWfTXKsE8LfMF1PJD/AZXdHO8wVGhoVkrQePAuAUet4veDW LNC7/28svxD23jphWE8G/v2p4N7yiE+yY3OZr5iAZVEZqTz5jMPmO0HqQVOmGZcWAoWcE0OGdP+ ogU9V4GBYZs3xaAVkuk+15cWZxPvTnJRmin0a/2fsS2Bk9OPtH6+T1vU55+6Upb0q2DzIxCxP3o ms0fmvpVwv1ZNsVbLz056SWllc0rbosWFHggF/M6GjMfnU1gU0qmr2Ap/e9p3l36lp4MLFVSbOZ Vq1o+oH25rO0j5U41bsFRTcXjN X-Received: by 2002:a05:701b:2515:b0:148:306c:971 with SMTP id a92af1059eb24-14d323344b3mr394990c88.22.1790750406465; Tue, 29 Sep 2026 23:40:06 -0700 (PDT) X-Received: by 2002:a05:701b:2515:b0:148:306c:971 with SMTP id a92af1059eb24-14d323344b3mr394953c88.22.1790750405907; Tue, 29 Sep 2026 23:40:05 -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.40.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 29 Sep 2026 23:40:05 -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 7/8] perf tests: add noinline to __test_function Date: Wed, 30 Sep 2026 12:09:18 +0530 Message-ID: <20260930063919.608911-8-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: quoted-printable X-Authority-Analysis: v=2.4 cv=CKy/zhrD c=1 sm=1 tr=0 ts=6abcaec7 cx=c_pps a=PfFC4Oe2JQzmKTvty2cRDw==:117 a=Ou0eQOY4+eZoSc0qltEV5Q==:17 a=VdqzKS8jKosA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=_K5XuSEh1TEqbUxoQ0s3:22 a=EUspDBNiAAAA:8 a=nkb_lb6KKDW8e-7fnV8A:9 a=O8hF6Hzn-FEA:10 a=6Ab_bkdmUrQuMsNx7PHu:22 X-Proofpoint-ORIG-GUID: qsG91SZLRaviStKKGyuwsGMPJgP8SMfJ X-Proofpoint-GUID: qsG91SZLRaviStKKGyuwsGMPJgP8SMfJ X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTMwMDAyNiBTYWx0ZWRfX3JKk7FpJyKT+ zoe3QNgL2++5QxVIRU0YVTbJrMdE3J6vdAlEW+LOtLtWqs9v2jcr+I7vLiWhIVt7OvzmzIJw3MX 2/tjim2Mu4JG5p6oG219GU1OP7OtUz8TOf5n+LbmHqG1y7tSK7CDDYQ7JufZ7fC33D3VCTMiJe0 Wa9WZ2qZUNLXf3Thgu+RRbe89X+aHCHUZApuOAKc11onHMENu5ysdq6qEBMrOcDIfn9ETlTv8O+ et6BSOnZYKSts90EO5rFiZChubsD5SK65Vq3X6SyTl0C517kKB7OjGVB4HnFmx26x+dCPWZ27V2 +1Hvqqd1bpVrdtRg8b+Dc8tgPqMP0iqprNcMVQAwP1OEaGZNfZDYcSwP7ZodHWstKT6KbwScuWI 6jEpp1AKLUYWuFyrrbtwywH51zkjFnb8wy3x9+eLgA46UXBrmI/NT9b38clh5jnqjyJ04MDLPXk VQvJCyqoCoNQMqhqYcw== X-Proofpoint-Spam-Info: AW1haW4tMjYwOTMwMDAyNiBTYWx0ZWRfX+3xoqL4pyOKq ElIV+s5G1mefym+deyDchqCV6kRr5tAWIN2kx2dwMmABNfo7q+sXshFPK/5cz8U+UgkSXnhhNsk M/et7/3GakG/37rhSi/jJcz/ZshCny4= 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 priorityscore=1501 adultscore=0 bulkscore=0 lowpriorityscore=0 clxscore=1015 phishscore=0 spamscore=0 malwarescore=0 suspectscore=0 impostorscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2609040000 definitions=main-2609300026 Content-Type: text/plain; charset="utf-8" In the breakpoint signal handler test, a breakpoint is set on __test_function. Compiler may optimize and inline __test_function. This causes failure in the test. Add noinline to __test_function so that it is not inlined. Signed-off-by: Himanshu Chauhan --- tools/perf/tests/bp_signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c index f580ba7486b1..cc4a27224884 100644 --- a/tools/perf/tests/bp_signal.c +++ b/tools/perf/tests/bp_signal.c @@ -54,7 +54,7 @@ asm ( "ret\n" ".popsection\n"); #else -static void __test_function(volatile long *ptr) +static noinline void __test_function(volatile long *ptr) { *ptr =3D 0x1234; } --=20 2.43.0 From nobody Fri Oct 2 08:26:24 2026 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.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 2A9C33F4858 for ; Wed, 30 Sep 2026 06:40:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790750415; cv=none; b=SPrA9MMAlFuPcEZWNj8IQumLXs5BLGp1io2OEMvmaoc1rEIWm06eb6KpEzzvsfOHRs20yVBIYs8hz3zJk7o/gXBz73YN3aSdgqpjyLvLK/5W8ICBFAA00EhdtWIC07kiiqi2pA5YzDJYGeL9Hp2x+u8+3Dv4SKY1iWd8ynHywiQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790750415; c=relaxed/simple; bh=jMjxyEeDs5Y6CJbbbYobZN/g6YT/qU/vWkkiXcZdUYI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=bIEF6AT5CIlziBKrhlU/68rqxnEmzG8qhJ27nmgrJGn2Q0KfSZrmbrG4cfZjqQER319+4GdaNvklwR6ufVbLVEJx/mMkKYO0DEUkztamyhzVkh0HORzE5TQwjCxC4kEsXHTxym8d/A0C5lZph/v64p2V4if1LUwU5a+qgbVynn4= 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=cTXtMncV; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=gmrQ79pd; arc=none smtp.client-ip=205.220.180.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="cTXtMncV"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="gmrQ79pd" Received: from pps.filterd (m0279872.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 68U1AcjE1264294 for ; Wed, 30 Sep 2026 06:40:13 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=s+fRCN/HDGv HbTVltets/a+FtP+655QYnFd7sM9T9IE=; b=cTXtMncVx8F9bZEKQ/5WPNqofvn H8hvw+EMPs1XuYSMyK2b1qKcaeTLGmsEBlIsDbNG7l69KFdiEf9g+p9g2ITntvP2 1Y8Ny3t0aitLBUNCYe4ySVOaOqBDHVa7xDX4bVpJWMy78sgRwwZDHep82RBNqVDt y9B4xYvvAFjHip/4FT+EI4HssNnxBNm2g9ioVTs2K/tdeshhuLWmCudnC/fXvUfr Rca8PiE412FQA221ZWRsIm4lgo+2QejOES524WTJUW/9872Ws8/702XFj21F4iqx W7nIOrPBDCiSSobgfByaCo9Lt+s3bHIsMuJLWf+vMpzzPyXI9MU1p6g6c1A== Received: from mail-dl1-f71.google.com (mail-dl1-f71.google.com [74.125.82.71]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4h0rheh912-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Wed, 30 Sep 2026 06:40:12 +0000 (GMT) Received: by mail-dl1-f71.google.com with SMTP id a92af1059eb24-139b62317d0so2565050c88.0 for ; Tue, 29 Sep 2026 23:40:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1790750412; x=1791355212; 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=s+fRCN/HDGvHbTVltets/a+FtP+655QYnFd7sM9T9IE=; b=gmrQ79pdFb7EiCZn+MyOpNRYJArV04TSCZzrcRDAieSp+9Ych1UkjQuf9/hQofmiFg hGy4MXah27Ix8Mg0ROkPp2eh90f5Nnm4TGRKIP3LBfHWJY7HuZy/ICF03FVi4ParpGA5 4Wsh6enmVzereBS2ocQQ0Qwm1otiK/F3xdvowvJ7YwogYViC0Z756ugdmYJ7PyB0Xu1u nid75vlWtNR7ozAfql6a7Sh1DkR/Djia/q5duj/Oxz6jXyKQzcLAPr5fYx/iRQqIoMh2 01+vAlRgMzHKT/w3pbya+f1dv8f9isNvyY5yAj9dZtujlLekXy2s5DqGO5t6phA+uJ2d vupw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790750412; x=1791355212; 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=s+fRCN/HDGvHbTVltets/a+FtP+655QYnFd7sM9T9IE=; b=Tvk0OjnhmmCaFFPnM4V5AloO9kKwgTpLieh4rwKfIfSwAAYQ9G/AJL/KHTwPhojITU 3QH6ywmxUz5s+oteOveIiV5J52+aCR6Dp+xOO4UV3dTisztBfDengdngnwAqK1x3a8vU u7z5yOCTsoXTFQP+p5PK1QG7sSh//hClrkevojARU5WUCG/cSgd0J3wj/YtQ54QglYTY YCEFlvTV2NnDvL9l+nE674LoOrzjfqVGDNPHNtxrreyUeUt1LaN2FBG8G2Efr1GantTV eYQqZhHh8w3Eh1NVhwb7S8dY6Df7J6mRPolSeePiNiaJd1iD+vKhDdl9anBFh3OVsikp 82lA== X-Gm-Message-State: AFuF++lLFevZyVv7faCGhVYQvTk0N+d0PrDJIXhofo6tCKzYMiUC2Q55 VQazPoQgNw82olnzvgc+nWfTJZpOt1IDlMueE3lXMTOKIzKRPDoYQRmF0nc5udjvSeueNLDlsq8 hUdsybiHXisIrWxn7vB9Xf/bxhKjnlL/SJ5ViiMZ7KbyIhgml33eeGWpYSELwA9UPAHY5MWRtkA A= X-Gm-Gg: AYBFou0qp+yThebkxDFknWtrb4xyjb09/32hI5pkaeTP9vcslQMYLrd8a6yX7mmyszZ l1Nsa5yClTl9ByY6N0cPBUgpsUSVCSbGrk1fFEzCGiezhVCRnuMPdz0wcDataiPDGN7Yl+KVmVW 4g4d4IC+ipwto+COZySRxzwmFFCyaElfTlq+lEI5q2wquvQBcyuIzhiWUAWZHaKT5pFzh9QcSJn X2VMU0no6ssdrBxAkhtyOkehfPB4dsBzr1dwwNoMbx1LGnWVBvl3aMWrqDmdW+KvT6mhZg7zwUt 3Vfa9ADjBy1hTYIQ7nmProo1ogmFc1TiPmiDE5EwbOaNZLoFw8m2bBCTT9zM+27A8pwXDulrJGU w7Vuojs54QhNP6mwonONaNF1QeyppB1a8L1lbGEU/ts5wvsI45FlmWiE4fr40xb5/t44AJYUdP6 rygTA3Ha2xRUFEnUPdj9UuVaGN X-Received: by 2002:a05:7022:eb51:10b0:143:271a:3df2 with SMTP id a92af1059eb24-14d33f3dbf2mr303338c88.44.1790750411675; Tue, 29 Sep 2026 23:40:11 -0700 (PDT) X-Received: by 2002:a05:7022:eb51:10b0:143:271a:3df2 with SMTP id a92af1059eb24-14d33f3dbf2mr303315c88.44.1790750411139; Tue, 29 Sep 2026 23:40:11 -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.40.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 29 Sep 2026 23:40:10 -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 8/8] MAINTAINERS: Add entry for RISC-V Debugging Date: Wed, 30 Sep 2026 12:09:19 +0530 Message-ID: <20260930063919.608911-9-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: quoted-printable X-Proofpoint-GUID: UYfoVN_2594CnWS9wJbstmIRNnnYf1-K X-Proofpoint-ORIG-GUID: UYfoVN_2594CnWS9wJbstmIRNnnYf1-K X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTMwMDAyNiBTYWx0ZWRfXzkLjisejk+vF drU3TP41EllOTQlNnzbklSsF7aZgIrsDvN/SA3wuZHove9m0S6H6+8E2Q8IE3RToEZMH0DTg/4q yyzpiMMX9jHCZ1KzF9dTNZam2wAr78PLpDvOndGtC/KCtBU0iUCRCpq88RNRhJD6vdmZHo+8nOt Fc0dk/aCJXbQMqT5NBw/Vjrw9JYox6zLigLvAZtaOOUbFsEHyI14Q4WaYY3E8TNgY5VioCJD2oh eQG9g653VLLFbeLgMg4LwuU7vNTXeTLNl8v4sdqHVwvffJ7UkxSf1DEVvHj0hrrVFF5kg8M1b4b eBPGlsvAHmo8pwOWxr7KpmEaVVQ1ALRwwZb0bWZwYjU9+4wvRDQ7G3EHqxCdiOmajpNpbt6WKiq zeQcEs7QixBzCqVwdvlAyVULctc9XzuuhxdGOWGqF4Mpoeecl9gv/cGOk1f3+7TSewFuFF3SrdW O99QuAiUgSjCfjEfjRg== X-Proofpoint-Spam-Info: AW1haW4tMjYwOTMwMDAyNiBTYWx0ZWRfXwrOfLanYmZbR KeN229G7udko3Q1AbP7RKyo4kOu26n0YRN2sob5J7MZvRVXXX1bNZ/DJ4UqwFgXJGS8pa8LDL9k rmqHN3kJV/58xSxpch70uSWWBkFJLVo= X-Authority-Analysis: v=2.4 cv=Tu1zFzXh c=1 sm=1 tr=0 ts=6abcaecc cx=c_pps a=JYo30EpNSr/tUYqK9jHPoA==:117 a=Ou0eQOY4+eZoSc0qltEV5Q==:17 a=VdqzKS8jKosA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=yx91gb_oNiZeI1HMLzn7:22 a=EUspDBNiAAAA:8 a=JfrnYn6hAAAA:8 a=VwQbUJbxAAAA:8 a=8h6Es3YqzoBqtYBhd2sA:9 a=Fk4IpSoW4aLDllm1B1p-:22 a=1CNFftbPRP8L7MoqJWF3:22 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 impostorscore=0 spamscore=0 malwarescore=0 suspectscore=0 phishscore=0 lowpriorityscore=0 adultscore=0 clxscore=1015 bulkscore=0 priorityscore=1501 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2609040000 definitions=main-2609300026 Content-Type: text/plain; charset="utf-8" Added myself as maintainer for the RISC-V inline debugging with sdtrig extension Signed-off-by: Himanshu Chauhan --- MAINTAINERS | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 72294ddfa5b7..01631359f0ee 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23586,6 +23586,17 @@ F: drivers/irqchip/irq-riscv-rpmi-sysmsi.c F: drivers/mailbox/riscv-sbi-mpxy-mbox.c F: include/linux/mailbox/riscv-rpmi-message.h =20 +RISC-V DEBUGGING +M: Himanshu Chauhan +L: linux-riscv@lists.infradead.org +F: arch/riscv/include/asm/hw_breakpoint.h +F: arch/riscv/include/asm/insn.h +F: arch/riscv/include/asm/perf_event.h +F: arch/riscv/kernel/hw_breakpoint.c +F: arch/riscv/kernel/perf_* +F: arch/riscv/lib/insn.c +F: drivers/perf/ + RISC-V SPACEMIT SoC Support M: Yixun Lan L: linux-riscv@lists.infradead.org --=20 2.43.0