From nobody Mon Oct 6 10:16:38 2025 Received: from mail-qv1-f49.google.com (mail-qv1-f49.google.com [209.85.219.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3AA6020C00D for ; Tue, 22 Jul 2025 17:38:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753205916; cv=none; b=neBBNBT1DaXCgpbjehSMtaY/fOGjwFtR/LnUWUswnyMX4kSauFg/y8dK4qtTsJDKbOfhVgNlA4zZRdDxspqRuhScflxotYM3WRgBEDjk46rzY2ME+J0YXMkFdgbDLLJRaYVgAKPf1qHZDeM5sxlRoFxAl9Dns/tnDPu3IIHro48= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753205916; c=relaxed/simple; bh=BQ592p7PwXl9SFmmTfEQ1OdgncbyCGbbmHAPjifbH9w=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tYqbz9vEVi6IMsoT4vq9fmmyx7N8sZJnLcpN9P6tLgC85dF1wIgExT476ZCTurrolrIBSfYhC10vRzWejivFU+PZkhb0bXPe+Bemt0CcRzw/a/nPDVIFdMthz+T5J9mz5r4K5ZLEpBZXTXe94ZRHaW8JTXJBYIynuSSxtUMf8FQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=rivosinc.com; spf=pass smtp.mailfrom=rivosinc.com; dkim=pass (2048-bit key) header.d=rivosinc-com.20230601.gappssmtp.com header.i=@rivosinc-com.20230601.gappssmtp.com header.b=eI/D8Crh; arc=none smtp.client-ip=209.85.219.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=rivosinc.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rivosinc.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=rivosinc-com.20230601.gappssmtp.com header.i=@rivosinc-com.20230601.gappssmtp.com header.b="eI/D8Crh" Received: by mail-qv1-f49.google.com with SMTP id 6a1803df08f44-6fd1b2a57a0so54829046d6.1 for ; Tue, 22 Jul 2025 10:38:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20230601.gappssmtp.com; s=20230601; t=1753205913; x=1753810713; 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; bh=lF2rPu7KbwKu1G1EJXgm7uTWq6XbeLZ2EiP3dWLRelk=; b=eI/D8CrhxZUcVbpSJN3+6E4ZtTyd1rLcLS82S875/OqcYwTsGjzldd82u1snO2+MkU mvutqXX7rtbb7s2SNTg9jbZP+s1rGUrHxN0sP+dsBom8PR5/49VsmU9i34zoSNOH+FQb HMzYATtzNkoJEyXOPV2N9PLQjJ+mujr0SG9bwfKdc+MSq7KXv2cKFrF7ctZOx8k8U7dr IG+fgzFrtZASGoQ/R9VILSxy4fc7VTpMi+hzfDhVVgwzuhWPbVDBLjVFer/Pg3ivyvyb EqrZC9xMOW+P58RZTJ4xmko70onid4yzON1Pl8W+PWGZAcGywypzU6JKvBSZ/ePC1HzX 9G2Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753205913; x=1753810713; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=lF2rPu7KbwKu1G1EJXgm7uTWq6XbeLZ2EiP3dWLRelk=; b=NBfv6e2HZxNIh4imgdP43bPW8Wz+SSUwGkMETrD3kaWX5hOY47lnrdm+BOzp55X/Qf XsyO2dBpC2pP1/E/5i7LpOEC8BeK/3N/P2eKGE41IxpAICc/85GTsqrXa1h0urk6Im0b VFMsJExLq8Tr8r5RIEqPG2PHO9bUFYMcDQrOigtTNYJfl2t4nZfE40IMoIuQdRLmANmr XapiBLdBLrcs121VjgRxiAaG2pBVfVdx2+n+KnXNzNhVnez1ZZ9XgcQNfGoU5nogz1x8 mU27hYmpO3ngZsv//+ja/tk/+ZDjAsDO2ZdGuqeXbIg9XHQIz8O8n92eeZ7FqflKbl/l npNg== X-Forwarded-Encrypted: i=1; AJvYcCWZaXWQ2X9BEREjMSIaCMQszqmQNplM5PrgkWDL4TpM852XLZGFMr3TCPAzOCUM7S7GTVDxq1jzGo+K7ik=@vger.kernel.org X-Gm-Message-State: AOJu0Yw//C7JVRBMFo1/Q7Ub7tFXdBbBQ/y7Tz6MB0e6aPLPQm54bbXd Pfz+SM1Uy6HpjOkjxvNityNJC+Q7Pw2MipKA9i7C4vol6EI+vhpiWpVc6uOuMXbsGi4= X-Gm-Gg: ASbGncs4qVvZaUIq0PgCex33Du0akU4kAB7biP6JcHtfEzUJJh+v86DuDfm4WmSR4CP vl6umqJBzQvxQyb0mPdZAjB11Xl+hV/NCfJoNYJxCJHRyYKuT28ql3/Ep2e0dZWoGrjNGwyWe0n TzJatVvhnRNK71WvRRW333kuQ/5BP5ZwcDrQo1J0+s1XK+pi5yEoJWk7F2IwJFcNNOKvFHAwCkw yop0qKeYnsreI14urymTdqkGl9JKP/1JE2cbmdqP6zS7dtdH/31622epjgMsxaWg3IQSMN365lQ l/0yDAojD4RZlOcvV213VkfJWGBRW8PJcUspAcBV/aNeZF95MWwW6qYDz/GmYiZu3d1c5JovadR gghIxc7CO1GApO+NwQan8AAvFwuAHN9Fpl+y5H1YWp/Xjc1qohv5fGS4peeO91t1qxh8KyDT5N4 gFCiME27qH5XM= X-Google-Smtp-Source: AGHT+IG9PYMJy870prymFTkYBTC1dFU4iW8i6f5Zd2WHEGlOX8Oy3bThYaXRDZuiA6jV3HXXHOwS6Q== X-Received: by 2002:ad4:5605:0:b0:705:45f:af8d with SMTP id 6a1803df08f44-705045fb42cmr245928436d6.45.1753205912884; Tue, 22 Jul 2025 10:38:32 -0700 (PDT) Received: from jesse-lt.ba.rivosinc.com (pool-108-26-215-125.bstnma.fios.verizon.net. [108.26.215.125]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-7051ba6b783sm54184536d6.73.2025.07.22.10.38.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 22 Jul 2025 10:38:32 -0700 (PDT) From: Jesse Taube To: linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org Cc: Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Oleg Nesterov , Jesse Taube , Himanshu Chauhan , Charlie Jenkins , Samuel Holland , Deepak Gupta , Andrew Jones , Atish Patra , Anup Patel , Mayuresh Chitale , Conor Dooley , WangYuli , Huacai Chen , Nam Cao , Andrew Morton , "Mike Rapoport (Microsoft)" , Luis Chamberlain , Yunhui Cui , Joel Granados , =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= , Celeste Liu , Evan Green , Nylon Chen Subject: [RFC PATCH 1/6] riscv: Add insn.c, consolidate instruction decoding Date: Tue, 22 Jul 2025 10:38:24 -0700 Message-ID: <20250722173829.984082-2-jesse@rivosinc.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250722173829.984082-1-jesse@rivosinc.com> References: <20250722173829.984082-1-jesse@rivosinc.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 Content-Type: text/plain; charset="utf-8" Various parts of the kernel decode and read instruction from memory. Functions like get_insn, GET_INSN_LENGTH and riscv_insn_is_c are defined in multiple places. Consolidate these functions into the insn.h and the newly added insn.c. Signed-off-by: Jesse Taube --- arch/riscv/include/asm/bug.h | 12 --- arch/riscv/include/asm/insn.h | 131 ++++++++++++++++++++++- arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/insn.c | 151 +++++++++++++++++++++++++++ arch/riscv/kernel/kgdb.c | 102 +----------------- arch/riscv/kernel/probes/kprobes.c | 1 + arch/riscv/kernel/traps.c | 5 +- arch/riscv/kernel/traps_misaligned.c | 93 ++++------------- 8 files changed, 309 insertions(+), 187 deletions(-) create mode 100644 arch/riscv/kernel/insn.c diff --git a/arch/riscv/include/asm/bug.h b/arch/riscv/include/asm/bug.h index 1aaea81fb141..a2777eb67ad1 100644 --- a/arch/riscv/include/asm/bug.h +++ b/arch/riscv/include/asm/bug.h @@ -12,21 +12,9 @@ =20 #include =20 -#define __INSN_LENGTH_MASK _UL(0x3) -#define __INSN_LENGTH_32 _UL(0x3) -#define __COMPRESSED_INSN_MASK _UL(0xffff) - #define __BUG_INSN_32 _UL(0x00100073) /* ebreak */ #define __BUG_INSN_16 _UL(0x9002) /* c.ebreak */ =20 -#define GET_INSN_LENGTH(insn) \ -({ \ - unsigned long __len; \ - __len =3D ((insn & __INSN_LENGTH_MASK) =3D=3D __INSN_LENGTH_32) ? \ - 4UL : 2UL; \ - __len; \ -}) - typedef u32 bug_insn_t; =20 #ifdef CONFIG_GENERIC_BUG_RELATIVE_POINTERS diff --git a/arch/riscv/include/asm/insn.h b/arch/riscv/include/asm/insn.h index 09fde95a5e8f..ba74e5b8262c 100644 --- a/arch/riscv/include/asm/insn.h +++ b/arch/riscv/include/asm/insn.h @@ -64,6 +64,7 @@ #define RVG_RS2_OPOFF 20 #define RVG_RD_OPOFF 7 #define RVG_RS1_MASK GENMASK(4, 0) +#define RVG_RS2_MASK GENMASK(4, 0) #define RVG_RD_MASK GENMASK(4, 0) =20 /* The bit field of immediate value in RVC J instruction */ @@ -121,17 +122,27 @@ #define RVC_C0_RS1_OPOFF 7 #define RVC_C0_RS2_OPOFF 2 #define RVC_C0_RD_OPOFF 2 +#define RVC_C0_RS1_MASK GENMASK(2, 0) +#define RVC_C0_RS2_MASK GENMASK(2, 0) +#define RVC_C0_RD_MASK GENMASK(2, 0) +#define RVC_C0_REG_OFFSET 8 =20 /* The register offset in RVC op=3DC1 instruction */ #define RVC_C1_RS1_OPOFF 7 #define RVC_C1_RS2_OPOFF 2 #define RVC_C1_RD_OPOFF 7 +#define RVC_C1_RS1_MASK GENMASK(2, 0) +#define RVC_C1_RS2_MASK GENMASK(2, 0) +#define RVC_C1_RD_MASK GENMASK(2, 0) +#define RVC_C1_REG_OFFSET 8 =20 /* The register offset in RVC op=3DC2 instruction */ #define RVC_C2_RS1_OPOFF 7 #define RVC_C2_RS2_OPOFF 2 #define RVC_C2_RD_OPOFF 7 #define RVC_C2_RS1_MASK GENMASK(4, 0) +#define RVC_C2_RS2_MASK GENMASK(4, 0) +#define RVC_C2_RD_MASK GENMASK(4, 0) =20 /* parts of opcode for RVG*/ #define RVG_OPCODE_FENCE 0x0f @@ -226,12 +237,26 @@ #define RVC_MASK_C_EBREAK 0xffff #define RVG_MASK_EBREAK 0xffffffff #define RVG_MASK_SRET 0xffffffff +#define RVC_MASK_C GENMASK(15, 0) =20 #define __INSN_LENGTH_MASK _UL(0x3) #define __INSN_LENGTH_GE_32 _UL(0x3) #define __INSN_OPCODE_MASK _UL(0x7F) #define __INSN_BRANCH_OPCODE _UL(RVG_OPCODE_BRANCH) =20 +#define GET_INSN_LENGTH(insn) \ +({ \ + unsigned long __len; \ + __len =3D ((insn & __INSN_LENGTH_MASK) =3D=3D __INSN_LENGTH_GE_32) ? \ + 4UL : 2UL; \ + __len; \ +}) + +static __always_inline bool riscv_insn_is_c(u32 code) +{ + return (code & (__INSN_LENGTH_MASK)) !=3D (__INSN_LENGTH_GE_32); +} + #define __RISCV_INSN_FUNCS(name, mask, val) \ static __always_inline bool riscv_insn_is_##name(u32 code) \ { \ @@ -260,7 +285,7 @@ __RISCV_INSN_FUNCS(c_bnez, RVC_MASK_C_BNEZ, RVC_MATCH_C= _BNEZ) __RISCV_INSN_FUNCS(c_ebreak, RVC_MASK_C_EBREAK, RVC_MATCH_C_EBREAK) __RISCV_INSN_FUNCS(ebreak, RVG_MASK_EBREAK, RVG_MATCH_EBREAK) __RISCV_INSN_FUNCS(sret, RVG_MASK_SRET, RVG_MATCH_SRET) -__RISCV_INSN_FUNCS(fence, RVG_MASK_FENCE, RVG_MATCH_FENCE); +__RISCV_INSN_FUNCS(fence, RVG_MASK_FENCE, RVG_MATCH_FENCE) =20 /* special case to catch _any_ system instruction */ static __always_inline bool riscv_insn_is_system(u32 code) @@ -295,6 +320,10 @@ static __always_inline bool riscv_insn_is_c_jalr(u32 c= ode) ({typeof(x) x_ =3D (x); \ (RV_X(x_, RVG_RS1_OPOFF, RVG_RS1_MASK)); }) =20 +#define RV_EXTRACT_RS2_REG(x) \ + ({typeof(x) x_ =3D (x); \ + (RV_X(x_, RVG_RS2_OPOFF, RVG_RS2_MASK)); }) + #define RV_EXTRACT_RD_REG(x) \ ({typeof(x) x_ =3D (x); \ (RV_X(x_, RVG_RD_OPOFF, RVG_RD_MASK)); }) @@ -322,9 +351,41 @@ static __always_inline bool riscv_insn_is_c_jalr(u32 c= ode) (RV_X(x_, RV_B_IMM_11_OPOFF, RV_B_IMM_11_MASK) << RV_B_IMM_11_OFF) | \ (RV_IMM_SIGN(x_) << RV_B_IMM_SIGN_OFF); }) =20 +#define RVC_EXTRACT_C0_RS1_REG(x) \ + ({typeof(x) x_ =3D (x); \ + (RVC_X(x_, RVC_C0_RS1_OPOFF, RVC_C0_RS1_MASK)); }) + +#define RVC_EXTRACT_C0_RS2_REG(x) \ + ({typeof(x) x_ =3D (x); \ + (RVC_X(x_, RVC_C0_RS2_OPOFF, RVC_C0_RS2_MASK)); }) + +#define RVC_EXTRACT_C0_RD_REG(x) \ + ({typeof(x) x_ =3D (x); \ + (RVC_X(x_, RVC_C0_RD_OPOFF, RVC_C0_RD_MASK)); }) + +#define RVC_EXTRACT_C1_RS1_REG(x) \ + ({typeof(x) x_ =3D (x); \ + (RVC_X(x_, RVC_C1_RS1_OPOFF, RVC_C1_RS1_MASK)); }) + +#define RVC_EXTRACT_C1_RS2_REG(x) \ + ({typeof(x) x_ =3D (x); \ + (RVC_X(x_, RVC_C1_RS2_OPOFF, RVC_C1_RS2_MASK)); }) + +#define RVC_EXTRACT_C1_RD_REG(x) \ + ({typeof(x) x_ =3D (x); \ + (RVC_X(x_, RVC_C1_RD_OPOFF, RVC_C1_RD_MASK)); }) + #define RVC_EXTRACT_C2_RS1_REG(x) \ ({typeof(x) x_ =3D (x); \ - (RV_X(x_, RVC_C2_RS1_OPOFF, RVC_C2_RS1_MASK)); }) + (RVC_X(x_, RVC_C2_RS1_OPOFF, RVC_C2_RS1_MASK)); }) + +#define RVC_EXTRACT_C2_RS2_REG(x) \ + ({typeof(x) x_ =3D (x); \ + (RVC_X(x_, RVC_C2_RS2_OPOFF, RVC_C2_RS2_MASK)); }) + +#define RVC_EXTRACT_C2_RD_REG(x) \ + ({typeof(x) x_ =3D (x); \ + (RVC_X(x_, RVC_C2_RD_OPOFF, RVC_C2_RD_MASK)); }) =20 #define RVC_EXTRACT_JTYPE_IMM(x) \ ({typeof(x) x_ =3D (x); \ @@ -354,6 +415,66 @@ static __always_inline bool riscv_insn_is_c_jalr(u32 c= ode) =20 #define RVV_EXRACT_VL_VS_WIDTH(x) RVFDQ_EXTRACT_FL_FS_WIDTH(x) =20 +/* + * Get the rs1 register number from RV or RVC instruction. + * + * @insn: instruction to process + * Return: rs1 register + */ +static inline unsigned int riscv_insn_extract_rs1_reg(u32 insn) +{ + switch (RVC_INSN_OPCODE_MASK & insn) { + case RVC_OPCODE_C0: + return RVC_EXTRACT_C0_RS1_REG(insn) + RVC_C0_REG_OFFSET; + case RVC_OPCODE_C1: + return RVC_EXTRACT_C1_RS1_REG(insn) + RVC_C1_REG_OFFSET; + case RVC_OPCODE_C2: + return RVC_EXTRACT_C2_RS1_REG(insn); + default: + return RV_EXTRACT_RS1_REG(insn); + } +} + +/* + * Get the rs2 register number from RV or RVC instruction. + * + * @insn: instruction to process + * Return: rs2 register + */ +static inline unsigned int riscv_insn_extract_rs2_reg(u32 insn) +{ + switch (RVC_INSN_OPCODE_MASK & insn) { + case RVC_OPCODE_C0: + return RVC_EXTRACT_C0_RS2_REG(insn) + RVC_C0_REG_OFFSET; + case RVC_OPCODE_C1: + return RVC_EXTRACT_C1_RS2_REG(insn) + RVC_C1_REG_OFFSET; + case RVC_OPCODE_C2: + return RVC_EXTRACT_C2_RS2_REG(insn); + default: + return RV_EXTRACT_RS2_REG(insn); + } +} + +/* + * Get the rd register number from RV or RVC instruction. + * + * @insn: instruction to process + * Return: rd register + */ +static inline unsigned int riscv_insn_extract_rd_reg(u32 insn) +{ + switch (RVC_INSN_OPCODE_MASK & insn) { + case RVC_OPCODE_C0: + return RVC_EXTRACT_C0_RD_REG(insn) + RVC_C0_REG_OFFSET; + case RVC_OPCODE_C1: + return RVC_EXTRACT_C1_RD_REG(insn) + RVC_C1_REG_OFFSET; + case RVC_OPCODE_C2: + return RVC_EXTRACT_C2_RD_REG(insn); + default: + return RV_EXTRACT_RD_REG(insn); + } +} + /* * Get the immediate from a J-type instruction. * @@ -428,4 +549,10 @@ 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); } + +#include + +int get_insn(struct pt_regs *regs, ulong epc, ulong *r_insn); +unsigned long get_step_address(struct pt_regs *regs, u32 code); + #endif /* _ASM_RISCV_INSN_H */ diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index f7480c9c6f8d..4f719b09e5ad 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_RISCV_ALTERNATIVE) +=3D alternative.o obj-y +=3D cpu.o obj-y +=3D cpufeature.o obj-y +=3D entry.o +obj-y +=3D insn.o obj-y +=3D irq.o obj-y +=3D process.o obj-y +=3D ptrace.o diff --git a/arch/riscv/kernel/insn.c b/arch/riscv/kernel/insn.c new file mode 100644 index 000000000000..dd2a6ef9fd25 --- /dev/null +++ b/arch/riscv/kernel/insn.c @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2025 Rivos, Inc + */ +#include +#include +#include + +#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; \ +}) + +/* + * Update a set of two instructions (U-type + I-type) with an immediate va= lue. + * + * Used for example in auipc+jalrs pairs the U-type instructions contains + * a 20bit upper immediate representing bits[31:12], while the I-type + * instruction contains a 12bit immediate representing bits[11:0]. + * + * This also takes into account that both separate immediates are + * considered as signed values, so if the I-type immediate becomes + * negative (BIT(11) set) the U-type part gets adjusted. + * + * @regs: pointer to the utype instruction of the pair + * @epc: pointer to the itype instruction of the pair + * @r_insn: the immediate to insert into the two instructions + * Return: combined immediate + */ +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 RVC_MASK_C; + if (riscv_insn_is_c(insn)) { + *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 (!riscv_insn_is_c(insn)) { + *r_insn =3D insn; + return 0; + } + insn &=3D RVC_MASK_C; + *r_insn =3D insn; + + return 0; + } +} + +/* Calculate the new address for after a step */ +unsigned long get_step_address(struct pt_regs *regs, u32 code) +{ + unsigned long pc =3D regs->epc; + unsigned int rs1_num, rs2_num; + + if ((code & __INSN_LENGTH_MASK) !=3D __INSN_LENGTH_GE_32) { + if (riscv_insn_is_c_jalr(code) || + riscv_insn_is_c_jr(code)) { + rs1_num =3D riscv_insn_extract_rs1_reg(code); + return regs_get_register(regs, rs1_num); + } else if (riscv_insn_is_c_j(code) || + riscv_insn_is_c_jal(code)) { + return RVC_EXTRACT_JTYPE_IMM(code) + pc; + } else if (riscv_insn_is_c_beqz(code)) { + rs1_num =3D riscv_insn_extract_rs1_reg(code); + if (!rs1_num || regs_get_register(regs, rs1_num) =3D=3D 0) + return RVC_EXTRACT_BTYPE_IMM(code) + pc; + else + return pc + 2; + } else if (riscv_insn_is_c_bnez(code)) { + rs1_num =3D riscv_insn_extract_rs1_reg(RVC_C1_RS1_OPOFF); + if (rs1_num && regs_get_register(regs, rs1_num) !=3D 0) + return RVC_EXTRACT_BTYPE_IMM(code) + pc; + else + return pc + 2; + } else { + return pc + 2; + } + } else { + if ((code & __INSN_OPCODE_MASK) =3D=3D __INSN_BRANCH_OPCODE) { + bool result =3D false; + long imm =3D RV_EXTRACT_BTYPE_IMM(code); + unsigned long rs1_val =3D 0, rs2_val =3D 0; + + rs1_num =3D riscv_insn_extract_rs1_reg(code); + rs2_num =3D riscv_insn_extract_rs2_reg(code); + if (rs1_num) + rs1_val =3D regs_get_register(regs, rs1_num); + if (rs2_num) + rs2_val =3D regs_get_register(regs, rs2_num); + + if (riscv_insn_is_beq(code)) + result =3D (rs1_val =3D=3D rs2_val) ? true : false; + else if (riscv_insn_is_bne(code)) + result =3D (rs1_val !=3D rs2_val) ? true : false; + else if (riscv_insn_is_blt(code)) + result =3D + ((long)rs1_val < + (long)rs2_val) ? true : false; + else if (riscv_insn_is_bge(code)) + result =3D + ((long)rs1_val >=3D + (long)rs2_val) ? true : false; + else if (riscv_insn_is_bltu(code)) + result =3D (rs1_val < rs2_val) ? true : false; + else if (riscv_insn_is_bgeu(code)) + result =3D (rs1_val >=3D rs2_val) ? true : false; + if (result) + return imm + pc; + else + return pc + 4; + } else if (riscv_insn_is_jal(code)) { + return RV_EXTRACT_JTYPE_IMM(code) + pc; + } else if (riscv_insn_is_jalr(code)) { + rs1_num =3D riscv_insn_extract_rs1_reg(code); + return RV_EXTRACT_ITYPE_IMM(code) + + (rs1_num ? regs_get_register(regs, rs1_num) : 0); + } else if (riscv_insn_is_sret(code)) { + return pc; + } else { + return pc + 4; + } + } +} diff --git a/arch/riscv/kernel/kgdb.c b/arch/riscv/kernel/kgdb.c index 9f3db3503dab..aafc1424fc81 100644 --- a/arch/riscv/kernel/kgdb.c +++ b/arch/riscv/kernel/kgdb.c @@ -23,111 +23,19 @@ enum { static unsigned long stepped_address; static unsigned int stepped_opcode; =20 -static int decode_register_index(unsigned long opcode, int offset) -{ - return (opcode >> offset) & 0x1F; -} - -static int decode_register_index_short(unsigned long opcode, int offset) -{ - return ((opcode >> offset) & 0x7) + 8; -} - -/* Calculate the new address for after a step */ -static int get_step_address(struct pt_regs *regs, unsigned long *next_addr) -{ - unsigned long pc =3D regs->epc; - unsigned long *regs_ptr =3D (unsigned long *)regs; - unsigned int rs1_num, rs2_num; - int op_code; - - if (get_kernel_nofault(op_code, (void *)pc)) - return -EINVAL; - if ((op_code & __INSN_LENGTH_MASK) !=3D __INSN_LENGTH_GE_32) { - if (riscv_insn_is_c_jalr(op_code) || - riscv_insn_is_c_jr(op_code)) { - rs1_num =3D decode_register_index(op_code, RVC_C2_RS1_OPOFF); - *next_addr =3D regs_ptr[rs1_num]; - } else if (riscv_insn_is_c_j(op_code) || - riscv_insn_is_c_jal(op_code)) { - *next_addr =3D RVC_EXTRACT_JTYPE_IMM(op_code) + pc; - } else if (riscv_insn_is_c_beqz(op_code)) { - rs1_num =3D decode_register_index_short(op_code, - RVC_C1_RS1_OPOFF); - if (!rs1_num || regs_ptr[rs1_num] =3D=3D 0) - *next_addr =3D RVC_EXTRACT_BTYPE_IMM(op_code) + pc; - else - *next_addr =3D pc + 2; - } else if (riscv_insn_is_c_bnez(op_code)) { - rs1_num =3D - decode_register_index_short(op_code, RVC_C1_RS1_OPOFF); - if (rs1_num && regs_ptr[rs1_num] !=3D 0) - *next_addr =3D RVC_EXTRACT_BTYPE_IMM(op_code) + pc; - else - *next_addr =3D pc + 2; - } else { - *next_addr =3D pc + 2; - } - } else { - if ((op_code & __INSN_OPCODE_MASK) =3D=3D __INSN_BRANCH_OPCODE) { - bool result =3D false; - long imm =3D RV_EXTRACT_BTYPE_IMM(op_code); - unsigned long rs1_val =3D 0, rs2_val =3D 0; - - rs1_num =3D decode_register_index(op_code, RVG_RS1_OPOFF); - rs2_num =3D decode_register_index(op_code, RVG_RS2_OPOFF); - if (rs1_num) - rs1_val =3D regs_ptr[rs1_num]; - if (rs2_num) - rs2_val =3D regs_ptr[rs2_num]; - - if (riscv_insn_is_beq(op_code)) - result =3D (rs1_val =3D=3D rs2_val) ? true : false; - else if (riscv_insn_is_bne(op_code)) - result =3D (rs1_val !=3D rs2_val) ? true : false; - else if (riscv_insn_is_blt(op_code)) - result =3D - ((long)rs1_val < - (long)rs2_val) ? true : false; - else if (riscv_insn_is_bge(op_code)) - result =3D - ((long)rs1_val >=3D - (long)rs2_val) ? true : false; - else if (riscv_insn_is_bltu(op_code)) - result =3D (rs1_val < rs2_val) ? true : false; - else if (riscv_insn_is_bgeu(op_code)) - result =3D (rs1_val >=3D rs2_val) ? true : false; - if (result) - *next_addr =3D imm + pc; - else - *next_addr =3D pc + 4; - } else if (riscv_insn_is_jal(op_code)) { - *next_addr =3D RV_EXTRACT_JTYPE_IMM(op_code) + pc; - } else if (riscv_insn_is_jalr(op_code)) { - rs1_num =3D decode_register_index(op_code, RVG_RS1_OPOFF); - if (rs1_num) - *next_addr =3D ((unsigned long *)regs)[rs1_num]; - *next_addr +=3D RV_EXTRACT_ITYPE_IMM(op_code); - } else if (riscv_insn_is_sret(op_code)) { - *next_addr =3D pc; - } else { - *next_addr =3D pc + 4; - } - } - return 0; -} - static int do_single_step(struct pt_regs *regs) { /* Determine where the target instruction will send us to */ - unsigned long addr =3D 0; - int error =3D get_step_address(regs, &addr); + unsigned long addr, insn; + int error =3D get_insn(regs, regs->epc, &insn); =20 if (error) return error; =20 + addr =3D get_step_address(regs, insn); + /* Store the op code in the stepped address */ - error =3D get_kernel_nofault(stepped_opcode, (void *)addr); + error =3D get_insn(regs, addr, stepped_opcode); if (error) return error; =20 diff --git a/arch/riscv/kernel/probes/kprobes.c b/arch/riscv/kernel/probes/= kprobes.c index c0738d6c6498..6a9cfb0b664a 100644 --- a/arch/riscv/kernel/probes/kprobes.c +++ b/arch/riscv/kernel/probes/kprobes.c @@ -12,6 +12,7 @@ #include #include #include +#include #include =20 #include "decode-insn.h" diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c index 9c83848797a7..938a8b841f94 100644 --- a/arch/riscv/kernel/traps.c +++ b/arch/riscv/kernel/traps.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -409,10 +410,10 @@ int is_valid_bugaddr(unsigned long pc) return 0; if (get_kernel_nofault(insn, (bug_insn_t *)pc)) return 0; - if ((insn & __INSN_LENGTH_MASK) =3D=3D __INSN_LENGTH_32) + if ((insn & __INSN_LENGTH_MASK) =3D=3D __INSN_LENGTH_GE_32) return (insn =3D=3D __BUG_INSN_32); else - return ((insn & __COMPRESSED_INSN_MASK) =3D=3D __BUG_INSN_16); + return ((insn & RVC_MASK_C) =3D=3D __BUG_INSN_16); } #endif /* CONFIG_GENERIC_BUG */ =20 diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps= _misaligned.c index 77c788660223..42a50e21b1d2 100644 --- a/arch/riscv/kernel/traps_misaligned.c +++ b/arch/riscv/kernel/traps_misaligned.c @@ -10,12 +10,13 @@ #include #include =20 -#include -#include +#include #include #include #include -#include +#include +#include +#include #include =20 #define INSN_MATCH_LB 0x3 @@ -112,25 +113,22 @@ #define SH_RS2 20 #define SH_RS2C 2 =20 -#define RV_X(x, s, n) (((x) >> (s)) & ((1 << (n)) - 1)) -#define RVC_LW_IMM(x) ((RV_X(x, 6, 1) << 2) | \ - (RV_X(x, 10, 3) << 3) | \ - (RV_X(x, 5, 1) << 6)) -#define RVC_LD_IMM(x) ((RV_X(x, 10, 3) << 3) | \ - (RV_X(x, 5, 2) << 6)) -#define RVC_LWSP_IMM(x) ((RV_X(x, 4, 3) << 2) | \ +#define RVC_LW_IMM(x) ((RV_X(x, 6, 0x1) << 2) | \ + (RV_X(x, 10, 0x7) << 3) | \ + (RV_X(x, 5, 0x1) << 6)) +#define RVC_LD_IMM(x) ((RV_X(x, 10, 0x7) << 3) | \ + (RV_X(x, 5, 0x3) << 6)) +#define RVC_LWSP_IMM(x) ((RV_X(x, 4, 0x7) << 2) | \ + (RV_X(x, 12, 0x1) << 5) | \ + (RV_X(x, 2, 0x3) << 6)) +#define RVC_LDSP_IMM(x) ((RV_X(x, 5, 0x3) << 3) | \ (RV_X(x, 12, 1) << 5) | \ - (RV_X(x, 2, 2) << 6)) -#define RVC_LDSP_IMM(x) ((RV_X(x, 5, 2) << 3) | \ - (RV_X(x, 12, 1) << 5) | \ - (RV_X(x, 2, 3) << 6)) -#define RVC_SWSP_IMM(x) ((RV_X(x, 9, 4) << 2) | \ - (RV_X(x, 7, 2) << 6)) -#define RVC_SDSP_IMM(x) ((RV_X(x, 10, 3) << 3) | \ - (RV_X(x, 7, 3) << 6)) -#define RVC_RS1S(insn) (8 + RV_X(insn, SH_RD, 3)) -#define RVC_RS2S(insn) (8 + RV_X(insn, SH_RS2C, 3)) -#define RVC_RS2(insn) RV_X(insn, SH_RS2C, 5) + (RV_X(x, 2, 0x7) << 6)) +#define RVC_SWSP_IMM(x) ((RV_X(x, 9, 0xf) << 2) | \ + (RV_X(x, 7, 0x3) << 6)) +#define RVC_SDSP_IMM(x) ((RV_X(x, 10, 0x7) << 3) | \ + (RV_X(x, 7, 0x7) << 6)) +#define RVC_RS2S(insn) (8 + RV_X(insn, SH_RS2C, 0x7)) =20 #define SHIFT_RIGHT(x, y) \ ((y) < 0 ? ((x) << -(y)) : ((x) >> (y))) @@ -146,7 +144,6 @@ =20 #define GET_RS1(insn, regs) (*REG_PTR(insn, SH_RS1, regs)) #define GET_RS2(insn, regs) (*REG_PTR(insn, SH_RS2, regs)) -#define GET_RS1S(insn, regs) (*REG_PTR(RVC_RS1S(insn), 0, regs)) #define GET_RS2S(insn, regs) (*REG_PTR(RVC_RS2S(insn), 0, regs)) #define GET_RS2C(insn, regs) (*REG_PTR(insn, SH_RS2C, regs)) #define GET_SP(regs) (*REG_PTR(2, 0, regs)) @@ -270,58 +267,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; - } -} - union reg_data { u8 data_bytes[8]; ulong data_ulong; --=20 2.43.0 From nobody Mon Oct 6 10:16:38 2025 Received: from mail-qv1-f43.google.com (mail-qv1-f43.google.com [209.85.219.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 788F627FD74 for ; Tue, 22 Jul 2025 17:38:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753205918; cv=none; b=oJfohOpWCiO3kLYvDl5eOV4c+B+qnvuJBL/d4H/Rc5DiwiunYLGFroQu3iN30Vwp/hxWetPAJHVom3sxu9naoJ+dmvR+wlclvYPqEKm+0jgBmuXpsfOBzxcHl8bWs6F3dl70uOEHnox3nSpCyxHCTK/CjpvITY/72THfV13ag6w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753205918; c=relaxed/simple; bh=wEqKxN712kAbJrD4t8wAg0usjJ7fv4C0L79Sr+jBBaQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=BGpoFI3g2DgrCTW6GRbhfr4HhZdJrSjkvTnyrsPasWgUlYfxw1hLChQw804ofvClbQ+jc8WOBG91TMuaEMyv0K/egd5LuTPRANFuQmINznteWxH1fb1jjR86lX/Ua2ZfY+BlgKowu/M8ISCkZfoCl3K9nWvbPeFfaSEG/ZcohT8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=rivosinc.com; spf=pass smtp.mailfrom=rivosinc.com; dkim=pass (2048-bit key) header.d=rivosinc-com.20230601.gappssmtp.com header.i=@rivosinc-com.20230601.gappssmtp.com header.b=c0M6sqdg; arc=none smtp.client-ip=209.85.219.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=rivosinc.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rivosinc.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=rivosinc-com.20230601.gappssmtp.com header.i=@rivosinc-com.20230601.gappssmtp.com header.b="c0M6sqdg" Received: by mail-qv1-f43.google.com with SMTP id 6a1803df08f44-6fad4e6d949so23522366d6.0 for ; Tue, 22 Jul 2025 10:38:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20230601.gappssmtp.com; s=20230601; t=1753205914; x=1753810714; 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; bh=2+/QVWVAbMlmawQzvkdd/uW3i3+BBW5J3oIOfjWO0MU=; b=c0M6sqdgemkgGGy8VfPnldSDVVuRK2ICu+FPepPL2VHbaC63Gz/lOYkv7WvP1AYhfd OjHJNW/n/ASPLwOtOE1e2ryC7DbXdxV4OeMGHWD2S0T3HoVPHl5tYhFemPkudqKIuOvT 1Lxni6m0OQeXNlxzgyit/b94XkgNaG/iLE+LHU+KLxOlQ7+6o1M/hx7nL14KeAvFx53w iHAdNlqvE1nZKY4yKFzlB6jRcbeY2lb5bFcSSDoK+9ZggDCqQR8LWhdgQ2v69ob9ucre Fpks+f7G1YRHzIc0ssso1nKq/Vi5DPwnBuehrSp3fNHYBo+XJw9TUZR6t+7ET0VAUXcG nUMQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753205914; x=1753810714; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=2+/QVWVAbMlmawQzvkdd/uW3i3+BBW5J3oIOfjWO0MU=; b=vddo8LhbTNpaZP2yNDpga8YBYAE38tfuHj9QZzRQO9jl0sp4Ob/43k7wwtvntyIRPk DvU7ZgbeZjGvTk/1fGBfZ08BPK0TJn9258KSeHV9DeJ8Z0Z0y7ocXgExrqO0HGoPyHpW KwmaeoynMSuD2La8u2GBNLJ7Dllp2EWywS9q2hxMCa+ufVtXBUHf4uRBw9voHRlBufeT HZNQIDZ0hw2OXdzpr4L7OTBJuXUlYCWhNAvxwRJUZRgRL8hsrs9h0/6BRnFeqU8C01cu +MpD5ny7JbmPjL+ejfGNxTBzUiv9UmrzMPfpkxV0OkrtUSBBXTwUPWfhqIfJcC0sMNuY EX9A== X-Forwarded-Encrypted: i=1; AJvYcCVA18ApoL0Vn2e6f6ulwHwjz9QRXC/FXe0U+1pL3XEODEunQ52sI6uZPeYKKc8PklBacSELwFjXrELZxoY=@vger.kernel.org X-Gm-Message-State: AOJu0YzAursiPmfncHXDtxR4F949tmlD00waBlofmrOcGCnm/4Ne2pgC 0zjaMvGqfvJtqY/YNDSOYXW4KP1P93N+R4ylfVG5BJKX9hDxqpR6z5mjD7+nzYFqXCY= X-Gm-Gg: ASbGncv8rZhiLSm28WFY2WkfHgKEVQA1uMGZL49rDuJfkxwNYylBuQ9KlyLXLD7I6FN MHuEFeYAUWEujzGWXesDULX59S1sOjEy4j/SCE2ny/E/KnwKbjpF9pv5Gs0qtay0+ihWPITcakI 9rg5puRwu4k0nsC5d+8gV7bI7prTnZEYR0bp96gu18054DSIqSQGmjjsCEWX+a1xnaMLTMoFDgM Ywt/P0G8ZUdLAtatR5p6SSVPkAVWU+l0JSpGHg5TE6plB5y1yZidcNX0qWIYAtOlUyVz95FbReZ bHM+qK28UHT4SC5M0CovrhJYDgVueh+8A7GwsG6r7Ej6UFE2wJ2tLtQ9WMIESybopd5/sMKCoj6 rqnmXAXPESCr3ZTdsEaSaZxnvKczbfRDH0E6Xe8IKNfGm+aFINcXwyBcw5DbiniHxVfA0/ujz8p Q2AgBL/JdCEsA= X-Google-Smtp-Source: AGHT+IG6SNdAeEQgHa32J5nhXO7PW8gNm0clufSPeGcbDvffqcuVjPUUxogWKFcpPDYTBay+0VPNTw== X-Received: by 2002:ad4:4ea6:0:b0:704:999b:e5a0 with SMTP id 6a1803df08f44-704f6ad3e7cmr422679046d6.34.1753205914143; Tue, 22 Jul 2025 10:38:34 -0700 (PDT) Received: from jesse-lt.ba.rivosinc.com (pool-108-26-215-125.bstnma.fios.verizon.net. [108.26.215.125]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-7051ba6b783sm54184536d6.73.2025.07.22.10.38.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 22 Jul 2025 10:38:33 -0700 (PDT) From: Jesse Taube To: linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org Cc: Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Oleg Nesterov , Jesse Taube , Himanshu Chauhan , Charlie Jenkins , Samuel Holland , Deepak Gupta , Andrew Jones , Atish Patra , Anup Patel , Mayuresh Chitale , Conor Dooley , WangYuli , Huacai Chen , Nam Cao , Andrew Morton , "Mike Rapoport (Microsoft)" , Luis Chamberlain , Yunhui Cui , Joel Granados , =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= , Celeste Liu , Evan Green , Nylon Chen Subject: [RFC PATCH 2/6] riscv: Add SBI debug trigger extension and function ids Date: Tue, 22 Jul 2025 10:38:25 -0700 Message-ID: <20250722173829.984082-3-jesse@rivosinc.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250722173829.984082-1-jesse@rivosinc.com> References: <20250722173829.984082-1-jesse@rivosinc.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 Content-Type: text/plain; charset="utf-8" From: Himanshu Chauhan Debug trigger extension is a proposed SBI extension to support native debugging in S-mode and VS-mode. The proposal for the extension can be found at: https://lists.riscv.org/g/sig-hypervisors/message/361 This patch adds the extension and the function IDs defined by the extension. Signed-off-by: Himanshu Chauhan --- arch/riscv/include/asm/sbi.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index 3d250824178b..be2ca8e8a49e 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -35,6 +35,7 @@ enum sbi_ext_id { SBI_EXT_DBCN =3D 0x4442434E, SBI_EXT_STA =3D 0x535441, SBI_EXT_NACL =3D 0x4E41434C, + SBI_EXT_DBTR =3D 0x44425452, =20 /* Experimentals extensions must lie within this range */ SBI_EXT_EXPERIMENTAL_START =3D 0x08000000, @@ -402,6 +403,34 @@ enum sbi_ext_nacl_feature { #define SBI_NACL_SHMEM_SRET_X(__i) ((__riscv_xlen / 8) * (__i)) #define SBI_NACL_SHMEM_SRET_X_LAST 31 =20 +/* SBI debug triggers function IDs */ +enum sbi_ext_dbtr_fid { + SBI_EXT_DBTR_NUM_TRIGGERS =3D 0, + SBI_EXT_DBTR_SETUP_SHMEM, + SBI_EXT_DBTR_TRIG_READ, + SBI_EXT_DBTR_TRIG_INSTALL, + SBI_EXT_DBTR_TRIG_UPDATE, + SBI_EXT_DBTR_TRIG_UNINSTALL, + SBI_EXT_DBTR_TRIG_ENABLE, + SBI_EXT_DBTR_TRIG_DISABLE, +}; + +struct sbi_dbtr_data_msg { + unsigned long tstate; + unsigned long tdata1; + unsigned long tdata2; + unsigned long tdata3; +}; + +struct sbi_dbtr_id_msg { + unsigned long idx; +}; + +union sbi_dbtr_shmem_entry { + struct sbi_dbtr_data_msg data; + struct sbi_dbtr_id_msg id; +}; + /* SBI spec version fields */ #define SBI_SPEC_VERSION_DEFAULT 0x1 #define SBI_SPEC_VERSION_MAJOR_SHIFT 24 --=20 2.43.0 From nobody Mon Oct 6 10:16:38 2025 Received: from mail-qv1-f46.google.com (mail-qv1-f46.google.com [209.85.219.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AAFA3280330 for ; Tue, 22 Jul 2025 17:38:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753205920; cv=none; b=RUzyzdooeWkOdhb6SrlKKMc/nEhEu9M/dNslQk4s7DNeDxLmldsMJlkY/G5UKVeLJ0cEV8MBUkBczT9SR5PdrLaQwljFJy9/izXzeZ+InhXCIoJ3kb6tIZ6VNcRdlxHL9ZHnJp61eMm2FZDAiSPrqFTfOVCut55m52G/WC8Tnmw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753205920; c=relaxed/simple; bh=Yqrau/0pHwWcYxpJTRYRGqV2PXfF/+2IqvWOBxUtYqA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=rw4EbRdgH1Fl7yXQvUFne9EFEvaqA+VtekG0LXruPt/2y9cOY0H0kxwix1afL4W/Z3BrtDlN5KAH0JrEc4H/vsS/MZqhiRiclUwmXFdC4LRcHYrm7YhXtO/+e3RZci8IAVv3XyE/WNAnpWVfrtKJFfubQtfvKUuZ2s2c5u/YkEs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=rivosinc.com; spf=pass smtp.mailfrom=rivosinc.com; dkim=pass (2048-bit key) header.d=rivosinc-com.20230601.gappssmtp.com header.i=@rivosinc-com.20230601.gappssmtp.com header.b=SP3nOb1G; arc=none smtp.client-ip=209.85.219.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=rivosinc.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rivosinc.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=rivosinc-com.20230601.gappssmtp.com header.i=@rivosinc-com.20230601.gappssmtp.com header.b="SP3nOb1G" Received: by mail-qv1-f46.google.com with SMTP id 6a1803df08f44-6fafb6899c2so1666806d6.0 for ; Tue, 22 Jul 2025 10:38:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20230601.gappssmtp.com; s=20230601; t=1753205915; x=1753810715; 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; bh=G0zO9q5RHjrpTuBAsZGCPwDy4LSegspYm+5gaPuuIvs=; b=SP3nOb1Gb6ORDxOWg7ob7KjXi689yjJzx2UKk5sEH2huJKBDubueqX8x5+FGEAV9Gx S+K00tjmZfZCA/EX9dhSKlJ6eeC8P1Wr2xTfiEj6bQw80n4GZpL322rmO1Ae/VrrT7ZK azcFG6EhJCZjw9bzR0iPLimBDMmyAYxtLFOU4Cn7IObfE8MCEnfvPHADY/BbxqKKPxAJ StTCRhNEbsBXhFLdvYN1Lz0JqDKHak7Q6tFnbNX3X64u5ItJ+AXVhz7WjM/R6OzBkyHE JScmZ2E+0fiaLaRfWm7lKnK4BJSW0BcLVT5Ysy2rFxBMBOatpq++vvO8GGpl8ZNgHxsR lQgg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753205915; x=1753810715; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=G0zO9q5RHjrpTuBAsZGCPwDy4LSegspYm+5gaPuuIvs=; b=ukHcpw16/vWjaChPNtbrXkINWYXUOJjuH6poPp6z8bVV4e7XwEIJvf6N5rOI7L4SyQ NWMDWbcW+s3w8oo4089f06+SLxY9jD3KuVOoF5TX9QkzuZARD4yUnghKxKsalRWh/2uH 4NxzG50znN2VQFtX+H3u810MQpE3ooxQ395T05CuVTYslooxGzj2UIFi/V7cpPJz6Iqy RrQWbdZll8rF2j5BjY2gg8VuA6NGZLacFQ5oMXYA2klyjPs2eJ553Nad4GFX7B7IYaMO BD5KeaG1+gqZkqGXdshzpG2Z8xaUnUzxVn3RTNljVQF3CsN4VF8bH/EQdtcBs4sbbFpl 9gMg== X-Forwarded-Encrypted: i=1; AJvYcCWB2B3Gq5rHz+hS3jLhupgQXoVawSwKyBeBPYkJEHC+NkKCJ3lZCk904mi/n6d6xjwmRarDejM7U2NMQmc=@vger.kernel.org X-Gm-Message-State: AOJu0Yw6H4neFEEwSO0f9d2qe8GFF0BN1AsVzI7UY4oBD77dzVrGXmWR 7xLudypU0PUDtoz1DmZqcp0yR0i6DKfycemty8FivJpMOsSMSALBm7Vuv8N95NKgMrA= X-Gm-Gg: ASbGncvfshK1XGO+n0yz2P+Ux3c7/y0vZGKz0iy2NyVNcJZwJJW/IWscVOc1jGkd+Qb sFtHAsTNPwquuoLk2EIfbkv2auD1BJpDMUGrxZ/2W2QI4HB+uQGbAOzISzJEGuUwuOmsIvaC7Tb ZgmvmjFZJTMCNVrz0bC66raeTnGU5yUGL9a0zCoPNXi5S3w2vOw7pATpWS/JzFKXV9JvAv6vmem ej6fPFNZQmwnsrmR/oefjPSpuQxGakqDh2VTn39Ct5In6BEBfgL1q0uqm27zIi8dzY2rzP3/pwI fv6W7XtWjEUWK+r4HJZYwBSl7HMmY7XRB+OsaVNNQUTXsSuvkD45JPAG6FLSoSFrdbUtI7QWC1p thQ+uko43HDe1tHPYu7nwU5EbkM5ti6lzkQx21MV7v5ApjA0BUG8BuiDEv96UD0BnxwIL9vNjtD VH7N4gkqjbD08= X-Google-Smtp-Source: AGHT+IHCokx4YHdCLRfoDwTLrDfS3sucjtTIvZ9hf2c8wFkhh0tDPdS/VDHIEe87OwXUJyu9QNOD4A== X-Received: by 2002:ad4:5d6f:0:b0:704:7dfa:3fd with SMTP id 6a1803df08f44-706eb692e9cmr53112496d6.4.1753205915406; Tue, 22 Jul 2025 10:38:35 -0700 (PDT) Received: from jesse-lt.ba.rivosinc.com (pool-108-26-215-125.bstnma.fios.verizon.net. [108.26.215.125]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-7051ba6b783sm54184536d6.73.2025.07.22.10.38.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 22 Jul 2025 10:38:35 -0700 (PDT) From: Jesse Taube To: linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org Cc: Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Oleg Nesterov , Jesse Taube , Himanshu Chauhan , Charlie Jenkins , Samuel Holland , Deepak Gupta , Andrew Jones , Atish Patra , Anup Patel , Mayuresh Chitale , Conor Dooley , WangYuli , Huacai Chen , Nam Cao , Andrew Morton , "Mike Rapoport (Microsoft)" , Luis Chamberlain , Yunhui Cui , Joel Granados , =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= , Celeste Liu , Evan Green , Nylon Chen Subject: [RFC PATCH 3/6] riscv: insn: __read_insn use copy_from_X_nofault Date: Tue, 22 Jul 2025 10:38:26 -0700 Message-ID: <20250722173829.984082-4-jesse@rivosinc.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250722173829.984082-1-jesse@rivosinc.com> References: <20250722173829.984082-1-jesse@rivosinc.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 Content-Type: text/plain; charset="utf-8" __read_insn was using get_user for user space reads and direct dereferencing for kernel space reads. Update to use copy_from_user_nofault, copy_from_kernel_nofault for this as get_user is user context only and may sleep. Signed-off-by: Jesse Taube --- Squash with previous commit as it's breaks bisectability. Separated as i'm unsure if copy_from_user_nofault is an acceptable replacement. --- arch/riscv/kernel/insn.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/riscv/kernel/insn.c b/arch/riscv/kernel/insn.c index dd2a6ef9fd25..b8e5202ddced 100644 --- a/arch/riscv/kernel/insn.c +++ b/arch/riscv/kernel/insn.c @@ -2,6 +2,9 @@ /* * Copyright 2025 Rivos, Inc */ + +#include + #include #include #include @@ -11,10 +14,9 @@ int __ret; \ \ if (user_mode(regs)) { \ - __ret =3D get_user(insn, (type __user *) insn_addr); \ + __ret =3D copy_from_user_nofault(&insn, (const type __user *) insn_addr,= sizeof(type)); \ } else { \ - insn =3D *(type *)insn_addr; \ - __ret =3D 0; \ + __ret =3D copy_from_kernel_nofault(&insn, (const type *) insn_addr, size= of(type)); \ } \ \ __ret; \ --=20 2.43.0 From nobody Mon Oct 6 10:16:38 2025 Received: from mail-qv1-f51.google.com (mail-qv1-f51.google.com [209.85.219.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1526028031C for ; Tue, 22 Jul 2025 17:38:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753205920; cv=none; b=SAnNE8Ue9NrWxYa74JmLp5U5wLL+I4sC4BHDlC0N/ZCK8elbI4POo6SixcE+y7PoriyPcG4VXKZ9xQj2AOsiDdUQqa80j99nrDzFXCx8AxUtm5ryaBZnk81wEZoOSrkw9ymV+ZuQKVAcxVF/KScvamOoqihdlteYTUigpAlNBuQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753205920; c=relaxed/simple; bh=X0nYrS4JALaj/fpgpCsXuXix6lXWM6RhMXvsIL5A6Hc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZDXSTCfk6amFfaD9ZuYCNSzkLwKdDkX1jeVkMAxNNkRZQ5y6KTNFaQkdsKCOKEGASjV9lQsrd9JE2BxxSU0tPWfLXXBE+aT19gNMlz+yKhgiPOrkO10lj0lJbEvE1jdrhMEHpHfaNlu4RSzMG4nUKlm/VucicWtPP3vxxxyrqcA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=rivosinc.com; spf=pass smtp.mailfrom=rivosinc.com; dkim=pass (2048-bit key) header.d=rivosinc-com.20230601.gappssmtp.com header.i=@rivosinc-com.20230601.gappssmtp.com header.b=O/VldrfG; arc=none smtp.client-ip=209.85.219.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=rivosinc.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rivosinc.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=rivosinc-com.20230601.gappssmtp.com header.i=@rivosinc-com.20230601.gappssmtp.com header.b="O/VldrfG" Received: by mail-qv1-f51.google.com with SMTP id 6a1803df08f44-6fd0a7d3949so76189676d6.0 for ; Tue, 22 Jul 2025 10:38:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20230601.gappssmtp.com; s=20230601; t=1753205917; x=1753810717; 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; bh=ZXqZufAwOynwVDtOm/mGtjNRKy10BDBSIzmTZQmFVT0=; b=O/VldrfGjsUDBzNSusIgwjoZjSNF1oW4Zlr7lwnr07ltllxkwLxab/dRc7y+GbcFX+ xZVUsknLXaCTfn5hwkuUMKykmVacBAjjtaBtv++bGAhdxyMZqr/OJfAJ3AuWa0/r0xJz cgwIAEwN9NlA9DtPqytE8FFJlFPQTypcpwNppzEFhAX5SZivAW0IZz9YQdsKLfF/4EQB 3OOYw9pwe/khpeMQeKh5l7vGiiHJF73I3VqF1UgNF5/I+v3+WlPmIMbw3FAYtgISi2Yv MM8NpjHbw4TQI83EX/EtaApewz/gZnQ2PVGvl7WzJeafgR5NOZAqSS+pwecTD57lJRFG SsQA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753205917; x=1753810717; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ZXqZufAwOynwVDtOm/mGtjNRKy10BDBSIzmTZQmFVT0=; b=WLU9/PI76FIhZkUNGb4NCjtESwriBFuAHmZBn/iDMadmKpx+w6yMsrNxA0DiXq2dtK JkpYee++Pd+sOqj26Yjy+JHif6APpxMAWYCZKkQ9GuWXNvC7F6rG2SND2fpzMmFLUoy8 phdh+y+4xCCRkhouF+u+4zf3soDf7AIcpxjO17O15ZrsrTb1dYHM6e3Ov9kAoRMNDhs4 rc1IwxMxvXAITBGanIsy/BF55YWZodRzcKkY0A677JhNCGH+fAy2OsCPkuHiH6J75zdT RwFhxEbaSWGaaopXqq6ebywgqaOVsaMTtztJzXUD3Ewx5RN8MewFd+Elp6yZTIcP9Fhz i0MA== X-Forwarded-Encrypted: i=1; AJvYcCW9XSwiK6gJSdX7ab0iVNRfB02k9l/4Uo1Dl2a0qVsgIaVvyNz6edgSXiz2qJBZ/CcFou+aE0lJfQsulbA=@vger.kernel.org X-Gm-Message-State: AOJu0YyUVQ6+A5WIhAjwNEsMpN4uRRmz6BAXHJFexy/sHLPdq7+UdjPp 7aqcZzEx7pYRb9MchjUOBWHoT1r7pNK1344Sc2RuLyzCYrqs5GFodLv2C+Qm842OTs4= X-Gm-Gg: ASbGncuLKWjp/a2sBBXW41WzJN4RpXKKQ7goeshuJ7FLOcc/qyn4Lg3p6FW8MamQdht AqtJGdC24bsjOtJDRtxGqPr+pndfvzLAaLUEY5QSUGoDO3bUyLTf9G+BzYyk2mEolZX5NBFw/mc EVVfVXLnWhEXnXiBjgj05+OlWZr3g4KUHhPDkammOHIYL7OEZGNvN/pe8roBLYh20lFDZakC1Y2 wl11s+/HhpBVKv9N3HFUCsxxK5RZWeN8UUU5o4WfY0cHGuEppKf1jqH6UndazlfRfaJHfExG60o puEw30uMtZtUS7ds+4M2e9UPVlrXcnvJnu+bY+47slrCk3FAXiq4CJSnRshnrbS7KmlD47Y066S ZA1M47L9W2e46z1phYYlcUMWAP0sSblSXBSYMVvwk/EGCHV5w6wvDclrKKFkz3tQyRcs3nQiNZe Y2ARSegLhq2QY= X-Google-Smtp-Source: AGHT+IFl5MdnALhnFlAPeUqJjc0LiQr4y0cJ3FIOSwIVt0xu3nkZkMzLnHNIn0BMb25QIizG2QBzmg== X-Received: by 2002:a05:6214:226c:b0:704:8fa0:969e with SMTP id 6a1803df08f44-7051a17b191mr204722796d6.41.1753205916756; Tue, 22 Jul 2025 10:38:36 -0700 (PDT) Received: from jesse-lt.ba.rivosinc.com (pool-108-26-215-125.bstnma.fios.verizon.net. [108.26.215.125]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-7051ba6b783sm54184536d6.73.2025.07.22.10.38.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 22 Jul 2025 10:38:36 -0700 (PDT) From: Jesse Taube To: linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org Cc: Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Oleg Nesterov , Jesse Taube , Himanshu Chauhan , Charlie Jenkins , Samuel Holland , Deepak Gupta , Andrew Jones , Atish Patra , Anup Patel , Mayuresh Chitale , Conor Dooley , WangYuli , Huacai Chen , Nam Cao , Andrew Morton , "Mike Rapoport (Microsoft)" , Luis Chamberlain , Yunhui Cui , Joel Granados , =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= , Celeste Liu , Evan Green , Nylon Chen Subject: [RFC PATCH 4/6] riscv: Introduce support for hardware break/watchpoints Date: Tue, 22 Jul 2025 10:38:27 -0700 Message-ID: <20250722173829.984082-5-jesse@rivosinc.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250722173829.984082-1-jesse@rivosinc.com> References: <20250722173829.984082-1-jesse@rivosinc.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 Content-Type: text/plain; charset="utf-8" From: Himanshu Chauhan RISC-V hardware breakpoint framework is built on top of perf subsystem and = uses SBI debug trigger extension to install/uninstall/update/enable/disable hard= ware triggers as specified in Sdtrig ISA extension. Signed-off-by: Himanshu Chauhan Signed-off-by: Jesse Taube --- arch/riscv/Kconfig | 1 + arch/riscv/include/asm/hw_breakpoint.h | 60 +++ arch/riscv/include/asm/kdebug.h | 3 +- arch/riscv/include/asm/sbi.h | 4 +- arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/hw_breakpoint.c | 620 +++++++++++++++++++++++++ arch/riscv/kernel/traps.c | 6 + 7 files changed, 693 insertions(+), 2 deletions(-) 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 bbec87b79309..95d3047cab10 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -163,6 +163,7 @@ config RISCV select HAVE_FUNCTION_ERROR_INJECTION select HAVE_GCC_PLUGINS select HAVE_GENERIC_VDSO if MMU && 64BIT + select HAVE_HW_BREAKPOINT if PERF_EVENTS && RISCV_SBI select HAVE_IRQ_TIME_ACCOUNTING select HAVE_KERNEL_BZIP2 if !XIP_KERNEL && !EFI_ZBOOT select HAVE_KERNEL_GZIP if !XIP_KERNEL && !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..8efa3921c535 --- /dev/null +++ b/arch/riscv/include/asm/hw_breakpoint.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2024 Ventana Micro Systems Inc. + */ + +#ifndef __RISCV_HW_BREAKPOINT_H +#define __RISCV_HW_BREAKPOINT_H + +struct task_struct; + +#ifdef CONFIG_HAVE_HW_BREAKPOINT + +#include + +#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 + +struct arch_hw_breakpoint { + unsigned long address; + unsigned long len; + + /* Callback info */ + unsigned long next_addr; + bool in_callback; + + + /* Trigger configuration data */ + unsigned long tdata1; + unsigned long tdata2; + unsigned long tdata3; +}; + +/* Maximum number of hardware breakpoints supported */ +#define RV_MAX_TRIGGERS 32 + +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); +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); + +#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/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index be2ca8e8a49e..64fa7a82aa45 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -282,7 +282,9 @@ struct sbi_sta_struct { u8 pad[47]; } __packed; =20 -#define SBI_SHMEM_DISABLE -1 +#define SBI_SHMEM_DISABLE (-1UL) +#define SBI_SHMEM_LO(pa) ((unsigned long)lower_32_bits(pa)) +#define SBI_SHMEM_HI(pa) ((unsigned long)upper_32_bits(pa)) =20 enum sbi_ext_nacl_fid { SBI_EXT_NACL_PROBE_FEATURE =3D 0x0, diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index 4f719b09e5ad..3e72505734bd 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -99,6 +99,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..9e3a3b82d300 --- /dev/null +++ b/arch/riscv/kernel/hw_breakpoint.c @@ -0,0 +1,620 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2024 Ventana Micro Systems Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DBTR_TDATA1_TYPE_SHIFT (__riscv_xlen - 4) +#define DBTR_TDATA1_DMODE BIT_UL(__riscv_xlen - 5) + +#define DBTR_TDATA1_TYPE_MCONTROL (2UL << DBTR_TDATA1_TYPE_SHIFT) +#define DBTR_TDATA1_TYPE_MCONTROL6 (6UL << DBTR_TDATA1_TYPE_SHIFT) + +#define DBTR_TDATA1_MCONTROL6_LOAD BIT(0) +#define DBTR_TDATA1_MCONTROL6_STORE BIT(1) +#define DBTR_TDATA1_MCONTROL6_EXECUTE BIT(2) +#define DBTR_TDATA1_MCONTROL6_U BIT(3) +#define DBTR_TDATA1_MCONTROL6_S BIT(4) +#define DBTR_TDATA1_MCONTROL6_M BIT(6) +#define DBTR_TDATA1_MCONTROL6_SIZE_FIELD GENMASK(18, 16) +#define DBTR_TDATA1_MCONTROL6_SELECT BIT(21) +#define DBTR_TDATA1_MCONTROL6_VU BIT(23) +#define DBTR_TDATA1_MCONTROL6_VS BIT(24) + +#define DBTR_TDATA1_MCONTROL6_SIZE_8BIT 1 +#define DBTR_TDATA1_MCONTROL6_SIZE_16BIT 2 +#define DBTR_TDATA1_MCONTROL6_SIZE_32BIT 3 +#define DBTR_TDATA1_MCONTROL6_SIZE_64BIT 5 + +#define DBTR_TDATA1_MCONTROL_LOAD BIT(0) +#define DBTR_TDATA1_MCONTROL_STORE BIT(1) +#define DBTR_TDATA1_MCONTROL_EXECUTE BIT(2) +#define DBTR_TDATA1_MCONTROL_U BIT(3) +#define DBTR_TDATA1_MCONTROL_S BIT(4) +#define DBTR_TDATA1_MCONTROL_M BIT(6) +#define DBTR_TDATA1_MCONTROL_SIZELO_FIELD GENMASK(17, 16) +#define DBTR_TDATA1_MCONTROL_SELECT BIT(19) +#define DBTR_TDATA1_MCONTROL_SIZEHI_FIELD GENMASK(22, 21) + +#define DBTR_TDATA1_MCONTROL_SIZELO_8BIT 1 +#define DBTR_TDATA1_MCONTROL_SIZELO_16BIT 2 +#define DBTR_TDATA1_MCONTROL_SIZELO_32BIT 3 +/* value of 5 split across HI and LO */ +#define DBTR_TDATA1_MCONTROL_SIZELO_64BIT 1 +#define DBTR_TDATA1_MCONTROL_SIZEHI_64BIT 1 + +/* Registered per-cpu bp/wp */ +static DEFINE_PER_CPU(struct perf_event *, pcpu_hw_bp_events[RV_MAX_TRIGGE= RS]); +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 DEFINE_PER_CPU(union sbi_dbtr_shmem_entry, sbi_dbtr_shmem); + +/* number of debug triggers on this cpu . */ +static int dbtr_total_num __ro_after_init; +static unsigned long dbtr_type __ro_after_init; +static unsigned long dbtr_init __ro_after_init; + +static int arch_smp_setup_sbi_shmem(unsigned int cpu) +{ + union sbi_dbtr_shmem_entry *dbtr_shmem; + unsigned long shmem_pa; + struct sbiret ret; + int rc; + + dbtr_shmem =3D per_cpu_ptr(&sbi_dbtr_shmem, cpu); + if (!dbtr_shmem) { + pr_err("Invalid per-cpu shared memory for debug triggers\n"); + return -ENODEV; + } + + shmem_pa =3D virt_to_phys(dbtr_shmem); + + ret =3D sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_SETUP_SHMEM, + SBI_SHMEM_LO(shmem_pa), SBI_SHMEM_HI(shmem_pa), 0, 0, 0, 0); + + if (ret.error) { + switch (ret.error) { + case SBI_ERR_DENIED: + pr_warn("%s: Access denied for shared memory at %lx\n", + __func__, shmem_pa); + rc =3D -EPERM; + break; + + case SBI_ERR_INVALID_PARAM: + case SBI_ERR_INVALID_ADDRESS: + pr_warn("%s: Invalid address parameter (%ld)\n", + __func__, ret.error); + rc =3D -EINVAL; + break; + + case SBI_ERR_ALREADY_AVAILABLE: + pr_warn("%s: Shared memory is already set\n", + __func__); + rc =3D -EADDRINUSE; + break; + + case SBI_ERR_FAILURE: + pr_err("%s: Internal sdtrig state error\n", + __func__); + rc =3D -ENXIO; + break; + + default: + pr_warn("%s: Unknown error %lu\n", __func__, ret.error); + rc =3D -ENXIO; + break; + } + } + + pr_debug("CPU %d: HW Breakpoint shared memory registered.\n", cpu); + + return rc; +} + +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) { + switch (ret.error) { + case SBI_ERR_DENIED: + pr_err("%s: Access denied for shared memory.\n", + __func__); + break; + + case SBI_ERR_INVALID_PARAM: + case SBI_ERR_INVALID_ADDRESS: + pr_err("%s: Invalid address parameter (%lu)\n", + __func__, ret.error); + break; + + case SBI_ERR_ALREADY_AVAILABLE: + pr_err("%s: Shared memory is already set\n", + __func__); + break; + case SBI_ERR_FAILURE: + pr_err("%s: Internal sdtrig state error\n", + __func__); + break; + default: + pr_err("%s: Unknown error %lu\n", __func__, ret.error); + break; + } + } + + pr_debug("CPU %d: HW Breakpoint shared memory disabled.\n", cpu); + + return 0; +} + +static void init_sbi_dbtr(void) +{ + struct sbiret ret; + + /* + * Called by hw_breakpoint_slots and arch_hw_breakpoint_init. + * Only proceed if this is the first CPU to reach this code. + */ + if (test_and_set_bit(0, &dbtr_init)) + return; + + if (sbi_probe_extension(SBI_EXT_DBTR) <=3D 0) { + pr_debug("%s: SBI_EXT_DBTR is not supported\n", __func__); + dbtr_total_num =3D 0; + return; + } + + ret =3D sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_NUM_TRIGGERS, + DBTR_TDATA1_TYPE_MCONTROL6, 0, 0, 0, 0, 0); + if (ret.error) { + pr_warn("%s: failed to detect mcontrol6 triggers. error: %ld.\n", + __func__, ret.error); + } else if (!ret.value) { + pr_warn("%s: No mcontrol6 triggers available.\n", __func__); + } else { + dbtr_total_num =3D ret.value; + dbtr_type =3D DBTR_TDATA1_TYPE_MCONTROL6; + return; + } + + /* fallback to legacy mcontrol triggers if mcontrol6 is not available */ + ret =3D sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_NUM_TRIGGERS, + DBTR_TDATA1_TYPE_MCONTROL, 0, 0, 0, 0, 0); + if (ret.error) { + pr_warn("%s: failed to detect mcontrol triggers. error: %ld.\n", + __func__, ret.error); + } else if (!ret.value) { + pr_err("%s: No mcontrol triggers available.\n", __func__); + dbtr_total_num =3D 0; + } else { + dbtr_total_num =3D ret.value; + dbtr_type =3D DBTR_TDATA1_TYPE_MCONTROL; + } +} + +int hw_breakpoint_slots(int type) +{ + /* + * We can be called early, so don't rely on + * static variables being initialised. + */ + 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) +{ + unsigned long tdata1 =3D DBTR_TDATA1_TYPE_MCONTROL; + + switch (attr->bp_type) { + case HW_BREAKPOINT_X: + tdata1 |=3D DBTR_TDATA1_MCONTROL_EXECUTE; + break; + case HW_BREAKPOINT_R: + tdata1 |=3D DBTR_TDATA1_MCONTROL_LOAD; + break; + case HW_BREAKPOINT_W: + tdata1 |=3D DBTR_TDATA1_MCONTROL_STORE; + break; + case HW_BREAKPOINT_RW: + tdata1 |=3D DBTR_TDATA1_MCONTROL_STORE | DBTR_TDATA1_MCONTROL_LOAD; + break; + default: + return -EINVAL; + } + + switch (attr->bp_len) { + case HW_BREAKPOINT_LEN_1: + hw->len =3D 1; + tdata1 |=3D FIELD_PREP(DBTR_TDATA1_MCONTROL_SIZELO_FIELD, + DBTR_TDATA1_MCONTROL_SIZELO_8BIT); + break; + case HW_BREAKPOINT_LEN_2: + hw->len =3D 2; + tdata1 |=3D FIELD_PREP(DBTR_TDATA1_MCONTROL_SIZELO_FIELD, + DBTR_TDATA1_MCONTROL_SIZELO_16BIT); + break; + case HW_BREAKPOINT_LEN_4: + hw->len =3D 4; + tdata1 |=3D FIELD_PREP(DBTR_TDATA1_MCONTROL_SIZELO_FIELD, + DBTR_TDATA1_MCONTROL_SIZELO_32BIT); + break; +#if __riscv_xlen >=3D 64 + case HW_BREAKPOINT_LEN_8: + hw->len =3D 8; + tdata1 |=3D FIELD_PREP(DBTR_TDATA1_MCONTROL_SIZELO_FIELD, + DBTR_TDATA1_MCONTROL_SIZELO_64BIT) | + FIELD_PREP(DBTR_TDATA1_MCONTROL_SIZEHI_FIELD, + DBTR_TDATA1_MCONTROL_SIZEHI_64BIT); + break; +#endif + default: + return -EINVAL; + } + + tdata1 |=3D DBTR_TDATA1_MCONTROL_U; + + hw->tdata1 =3D tdata1; + + return 0; +} + +static int rv_init_mcontrol6_trigger(const struct perf_event_attr *attr, + struct arch_hw_breakpoint *hw) +{ + unsigned long tdata1 =3D DBTR_TDATA1_TYPE_MCONTROL; + + switch (attr->bp_type) { + case HW_BREAKPOINT_X: + tdata1 |=3D DBTR_TDATA1_MCONTROL6_EXECUTE; + break; + case HW_BREAKPOINT_R: + tdata1 |=3D DBTR_TDATA1_MCONTROL6_LOAD; + break; + case HW_BREAKPOINT_W: + tdata1 |=3D DBTR_TDATA1_MCONTROL6_STORE; + break; + case HW_BREAKPOINT_RW: + tdata1 |=3D DBTR_TDATA1_MCONTROL6_STORE | DBTR_TDATA1_MCONTROL6_LOAD; + break; + default: + return -EINVAL; + } + + switch (attr->bp_len) { + case HW_BREAKPOINT_LEN_1: + hw->len =3D 1; + tdata1 |=3D FIELD_PREP(DBTR_TDATA1_MCONTROL6_SIZE_FIELD, + DBTR_TDATA1_MCONTROL6_SIZE_8BIT); + break; + case HW_BREAKPOINT_LEN_2: + hw->len =3D 2; + tdata1 |=3D FIELD_PREP(DBTR_TDATA1_MCONTROL6_SIZE_FIELD, + DBTR_TDATA1_MCONTROL6_SIZE_16BIT); + break; + case HW_BREAKPOINT_LEN_4: + hw->len =3D 4; + tdata1 |=3D FIELD_PREP(DBTR_TDATA1_MCONTROL6_SIZE_FIELD, + DBTR_TDATA1_MCONTROL6_SIZE_32BIT); + break; + case HW_BREAKPOINT_LEN_8: + hw->len =3D 8; + tdata1 |=3D FIELD_PREP(DBTR_TDATA1_MCONTROL6_SIZE_FIELD, + DBTR_TDATA1_MCONTROL6_SIZE_64BIT); + break; + default: + return -EINVAL; + } + + tdata1 |=3D DBTR_TDATA1_MCONTROL6_U; + + hw->tdata1 =3D tdata1; + + 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; + hw->next_addr =3D 0x0; + hw->in_callback =3D false; + + switch (dbtr_type) { + case DBTR_TDATA1_TYPE_MCONTROL: + ret =3D rv_init_mcontrol_trigger(attr, hw); + break; + case DBTR_TDATA1_TYPE_MCONTROL6: + ret =3D rv_init_mcontrol6_trigger(attr, hw); + break; + default: + pr_warn("Unsupported trigger type %lu.\n", dbtr_type >> DBTR_TDATA1_TYPE= _SHIFT); + ret =3D -EOPNOTSUPP; + break; + } + + return ret; +} + +/* + * Set breakpoint to next insruction after breakpoint. + * Returns 0 if success + * Returns < 0 on error + */ +static int setup_singlestep(struct perf_event *event, struct pt_regs *regs) +{ + struct arch_hw_breakpoint *bp =3D counter_arch_bp(event); + struct arch_hw_breakpoint old_hw_bp; + struct perf_event_attr bp_insn; + unsigned long next_addr, insn; + int ret; + + /* Remove breakpoint even if return error as not to loop */ + arch_uninstall_hw_breakpoint(event); + + ret =3D get_insn(regs, regs->epc, &insn); + if (ret < 0) + return ret; + + next_addr =3D get_step_address(regs, insn); + + ret =3D get_insn(regs, next_addr, &insn); + if (ret < 0) + return ret; + + bp_insn.bp_type =3D HW_BREAKPOINT_X; + bp_insn.bp_addr =3D next_addr; + /* Get the size of the intruction */ + bp_insn.bp_len =3D GET_INSN_LENGTH(insn); + + ret =3D hw_breakpoint_arch_parse(NULL, &bp_insn, bp); + if (ret) + return ret; + + ret =3D arch_install_hw_breakpoint(event); + if (ret) + return ret; + + bp->in_callback =3D true; + bp->next_addr =3D next_addr; + return 0; +} + +/* + * HW Breakpoint/watchpoint handler + */ +static int hw_breakpoint_handler(struct pt_regs *regs) +{ + struct perf_event *event; + struct arch_hw_breakpoint *bp; + int ret, 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); + if (bp->in_callback) { + /* Reset changed breakpoint data */ + bp->in_callback =3D false; + if (regs->epc =3D=3D bp->next_addr) { + arch_uninstall_hw_breakpoint(event); + /* Restore original breakpoint */ + if (hw_breakpoint_arch_parse(NULL, &event->attr, bp)) + return NOTIFY_DONE; + if (arch_install_hw_breakpoint(event)) + return NOTIFY_DONE; + return NOTIFY_STOP; + } + + pr_err("%s: in_callback was set, but epc(%lx) was not next " + "address(%lx).\n", __func__, regs->epc, bp->next_addr); + bp->next_addr =3D 0x0; + return NOTIFY_DONE; + } + + switch (event->attr.bp_type) { + /* Breakpoint */ + case HW_BREAKPOINT_X: + if (event->attr.bp_addr =3D=3D regs->epc) { + ret =3D setup_singlestep(event, regs); + if (ret < 0) { + pr_err("%s: setup_singlestep failed %d.\n", __func__, ret); + return NOTIFY_DONE; + } + + perf_bp_event(event, regs); + return NOTIFY_STOP; + } + break; + + /* Watchpoint */ + case HW_BREAKPOINT_W: + case HW_BREAKPOINT_R: + case HW_BREAKPOINT_RW: + if (event->attr.bp_addr =3D=3D regs->badaddr) { + ret =3D setup_singlestep(event, regs); + if (ret < 0) { + pr_err("%s: setup_singlestep failed %d.\n", __func__, ret); + return NOTIFY_DONE; + } + + perf_bp_event(event, regs); + return NOTIFY_STOP; + } + break; + + default: + pr_warn("%s: Unknown type: %u\n", __func__, event->attr.bp_type); + break; + } + } + + return NOTIFY_DONE; +} + +int hw_breakpoint_exceptions_notify(struct notifier_block *unused, + unsigned long val, void *data) +{ + struct die_args *args =3D data; + + if (val !=3D DIE_DEBUG) + return NOTIFY_DONE; + + return hw_breakpoint_handler(args->regs); +} + +/* 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("%s: failed to install trigger. error: %ld\n", __func__, ret.err= or); + 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("%s: invalid trigger index %lu\n", __func__, idx); + err =3D -EINVAL; + goto done; + } + + slot =3D this_cpu_ptr(&pcpu_hw_bp_events[idx]); + if (*slot) { + pr_warn("%s: slot %lu is in use\n", __func__, idx); + err =3D -EBUSY; + goto done; + } + + pr_debug("Trigger 0x%lx installed at index 0x%lx\n", bp->tdata2, idx); + + /* 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; + + 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("%s: Breakpoint not installed.\n", __func__); + return; + } + + ret =3D sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_TRIG_UNINSTALL, + i, 1, 0, 0, 0, 0); + if (ret.error) + pr_warn("%s: Failed to uninstall trigger %d. error: %ld\n", __func__, i,= ret.error); +} + +void flush_ptrace_hw_breakpoint(struct task_struct *tsk) { } + +void hw_breakpoint_pmu_read(struct perf_event *bp) { } + +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)); + + init_sbi_dbtr(); + + if (dbtr_total_num) { + pr_debug("%s: total number of type %lu triggers: %u\n", + __func__, dbtr_type >> DBTR_TDATA1_TYPE_SHIFT, dbtr_total_num); + } else { + pr_debug("%s: No hardware triggers available\n", __func__); + return rc; + } + + /* 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("%s: Failed to setup CPU hotplug state\n", __func__); + + return rc; +} +arch_initcall(arch_hw_breakpoint_init); diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c index 938a8b841f94..2ac471ec79a8 100644 --- a/arch/riscv/kernel/traps.c +++ b/arch/riscv/kernel/traps.c @@ -289,6 +289,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 Mon Oct 6 10:16:38 2025 Received: from mail-qk1-f180.google.com (mail-qk1-f180.google.com [209.85.222.180]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 31FA0280339 for ; Tue, 22 Jul 2025 17:38:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.180 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753205920; cv=none; b=GZjpg4T6ehNlRtu4cIAglUI2t55jAo31J/z9FTLvpF8G7CsuEIXuEN0cYBCKzeh/NYVQPGv13XuasTooMmi501vii6qq1GMz+Qb2lvLsOAqrRbzaKLqTyHyejZrwwUcRoCW0q40l7gQq1evlwMjLeOe926BRedU2i4Dso/vkSKE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753205920; c=relaxed/simple; bh=YpxOG2TsBFmJTbwEppASaFu8JfCqJGH4+EWAhuNSceU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=MuE0rZCMw82TPWaGTC0/MpVSxVPDZIyDfP1lLlwvjCIXIey33wr7u1yUK/ACRKqsm3BwNnII3q6uzYyKSHVzyfcs2aegjNn3JiAa+oQW3tFqOH6mKNAT/uYgBN/dm+waT1/pj9U9euMm4/z0IkX3Cu25ZowzFUZDqeJxidn833I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=rivosinc.com; spf=pass smtp.mailfrom=rivosinc.com; dkim=pass (2048-bit key) header.d=rivosinc-com.20230601.gappssmtp.com header.i=@rivosinc-com.20230601.gappssmtp.com header.b=3fQihfSt; arc=none smtp.client-ip=209.85.222.180 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=rivosinc.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rivosinc.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=rivosinc-com.20230601.gappssmtp.com header.i=@rivosinc-com.20230601.gappssmtp.com header.b="3fQihfSt" Received: by mail-qk1-f180.google.com with SMTP id af79cd13be357-7e34399cdb2so607471485a.3 for ; Tue, 22 Jul 2025 10:38:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20230601.gappssmtp.com; s=20230601; t=1753205918; x=1753810718; 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; bh=KW4csVV0UWW4773SLdvTdDiMmcrFmADNMqZ78npo3qA=; b=3fQihfStllnAfwJz9gYUCpLHdyT7kZHAIoqPK3SdK0RwHFiVtOMFlKB0BWfOT7nN51 wLi9oDgoE03RYBu9PHZ+o7A0kxY0bhq8lpAwcGQEGiV4oiZUQYJBaLVyMkwaKDskr45K qCc9gaKDq1zgT9YIHB3OOgMwUMyAWu+upQnU4UiONt7ULA1DaaJgu6JFwCUPQEDNW/LV R6qQ6Y38vht8xF8x8js5Hf9yYcTDQr1gkbkyEFbCIXHeHfcD6JvdHD//9VI7aAcxh18W tvBPC5CJ57hRsCWCcoaM9mtaKcXcagSxLTo3/Jf5H05FyzJwGf/WNaqBRgvCQHqKImhZ 0bCA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753205918; x=1753810718; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=KW4csVV0UWW4773SLdvTdDiMmcrFmADNMqZ78npo3qA=; b=cJV/CbCyVR/wsTfcNovoiYHY7FI3VdMf4NZsi8P99iEYRfspFHC2fRIGkJ2RIlMpTz lsZtVcu5UanO8kc0/KkgzkSVh50GyNvE1FTZJ3e1Ao5FjNgVPpVkGPCJZmaZT/7J2qfr QRxwiCEs09/rkg+YiNmzatJsewPJce0NSoqhTWrVfzvM9PzhRtTnAU32x5PbEH1XDjQu T/WnxxnEFScW1nrTyk4lkZFPHOzglyfqVLGDcHbnnL59s6PMY5YrsdvrrjXpsMCfhr/h ioIFSJVU3nYZr2ulvL0FOFRGaBPAH89ynnpz8HU5bXgTDc74SxO3dZAXNSuWNOuAAbpu wyXA== X-Forwarded-Encrypted: i=1; AJvYcCV0VrJJQqraHFSPOs0ebA6X7dj7EDTIRqLfeCZQX2yKz1whrXzmsoofRZWHbXUHMSDI1KiVF24CslAWrFY=@vger.kernel.org X-Gm-Message-State: AOJu0YwOJSUVRE4IoiGXskKt23sMbIrQ2yottwwZMZ61AATx8/QinVps JosSHoaLbd4jeUAvhv60gI6C66+E0LcLOC8+wRAE2+SjGlJvnoexeB63T1N5VEVRCzk= X-Gm-Gg: ASbGncssZvJ1rO66It/caoNKoCg2KSpGP88jFiJ2iO+1hdaHZAMN1n7vgAQDWrv/SwH 2koMdbaAMNmAVcjZpOb3tgxvalCmKpVu3pk5E01KkGznoWIBcQznTYPspvmi6kmUWzf1keTmcks eWgCgk5ZFhGsGMM0ftIFkSpcBGpFzexLsSMKtyC3/lFWJt6edRNHuhH6NfeQsQ5XsLIMgvo/HnJ K1UrvZisKVkAcHkDmc/Zf2h0mzSWOb7fotoekrRb5+yLBfCwMpOWhJoRb8BEU/Dcx2Hz46b2gep Er9yX0rgjycH6qMdHe9gjCtrQ2BKZMZg7Zhe13MvkMAjpLeWTwyue0Mg+UIL/1ncMPBEkhoACwl jlN2f0+wG32tZHw0NSFMmTH5kl2/VEOocbPcfaWNNmw01tx5n/OSx4dP+FjT7XLld1DRxpN4JI3 fOjXcIPE0spuI= X-Google-Smtp-Source: AGHT+IGBDrTWn4V/STPt6DOLmJtCWDCzg0HfHNyXs5XppmVHnd6/xaUauxoLwI7I4C+gvMI7ST37gQ== X-Received: by 2002:a05:6214:62c:b0:6fd:61b6:3360 with SMTP id 6a1803df08f44-707004b3e11mr421686d6.5.1753205918060; Tue, 22 Jul 2025 10:38:38 -0700 (PDT) Received: from jesse-lt.ba.rivosinc.com (pool-108-26-215-125.bstnma.fios.verizon.net. [108.26.215.125]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-7051ba6b783sm54184536d6.73.2025.07.22.10.38.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 22 Jul 2025 10:38:37 -0700 (PDT) From: Jesse Taube To: linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org Cc: Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Oleg Nesterov , Jesse Taube , Himanshu Chauhan , Charlie Jenkins , Samuel Holland , Deepak Gupta , Andrew Jones , Atish Patra , Anup Patel , Mayuresh Chitale , Conor Dooley , WangYuli , Huacai Chen , Nam Cao , Andrew Morton , "Mike Rapoport (Microsoft)" , Luis Chamberlain , Yunhui Cui , Joel Granados , =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= , Celeste Liu , Evan Green , Nylon Chen Subject: [RFC PATCH 5/6] riscv: hw_breakpoint: Use icount for single stepping Date: Tue, 22 Jul 2025 10:38:28 -0700 Message-ID: <20250722173829.984082-6-jesse@rivosinc.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250722173829.984082-1-jesse@rivosinc.com> References: <20250722173829.984082-1-jesse@rivosinc.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 Content-Type: text/plain; charset="utf-8" The Sdtrig RISC-V ISA extension does not have a resume flag for returning to and executing the instruction at the breakpoint. To avoid skipping the instruction or looping, it is necessary to remove the hardware breakpoint and single step. Use the icount feature of Sdtrig to accomplish this. Use icount as default with an option to allow software-based single stepping when hardware or SBI does not have icount functionality, as it may cause unwanted side effects when reading the instruction from memory. Signed-off-by: Jesse Taube --- arch/riscv/Kconfig | 11 +++++ arch/riscv/kernel/hw_breakpoint.c | 81 +++++++++++++++++++++++++------ 2 files changed, 76 insertions(+), 16 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 95d3047cab10..bbde5e118470 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -1105,6 +1105,17 @@ config PARAVIRT_TIME_ACCOUNTING =20 If in doubt, say N here. =20 +config HW_BREAKPOINT_COMPUTE_STEP + bool "Allow computing hardware breakpoint step address" + default n + depends on HAVE_HW_BREAKPOINT + help + Select this option if hardware breakpoints are desired, but + hardware or SBI does not have icount functionality. This may cause + unwanted side affects when reading the instruction from memory. + + If unsure, say N. + config RELOCATABLE bool "Build a relocatable kernel" depends on !XIP_KERNEL diff --git a/arch/riscv/kernel/hw_breakpoint.c b/arch/riscv/kernel/hw_break= point.c index 9e3a3b82d300..437fd82b9590 100644 --- a/arch/riscv/kernel/hw_breakpoint.c +++ b/arch/riscv/kernel/hw_breakpoint.c @@ -20,6 +20,7 @@ #define DBTR_TDATA1_DMODE BIT_UL(__riscv_xlen - 5) =20 #define DBTR_TDATA1_TYPE_MCONTROL (2UL << DBTR_TDATA1_TYPE_SHIFT) +#define DBTR_TDATA1_TYPE_ICOUNT (3UL << DBTR_TDATA1_TYPE_SHIFT) #define DBTR_TDATA1_TYPE_MCONTROL6 (6UL << DBTR_TDATA1_TYPE_SHIFT) =20 #define DBTR_TDATA1_MCONTROL6_LOAD BIT(0) @@ -55,6 +56,14 @@ #define DBTR_TDATA1_MCONTROL_SIZELO_64BIT 1 #define DBTR_TDATA1_MCONTROL_SIZEHI_64BIT 1 =20 +#define DBTR_TDATA1_ICOUNT_U BIT(6) +#define DBTR_TDATA1_ICOUNT_S BIT(7) +#define DBTR_TDATA1_ICOUNT_PENDING BIT(8) +#define DBTR_TDATA1_ICOUNT_M BIT(9) +#define DBTR_TDATA1_ICOUNT_COUNT_FIELD GENMASK(23, 10) +#define DBTR_TDATA1_ICOUNT_VU BIT(25) +#define DBTR_TDATA1_ICOUNT_VS BIT(26) + /* Registered per-cpu bp/wp */ static DEFINE_PER_CPU(struct perf_event *, pcpu_hw_bp_events[RV_MAX_TRIGGE= RS]); static DEFINE_PER_CPU(unsigned long, ecall_lock_flags); @@ -65,6 +74,7 @@ static DEFINE_PER_CPU(union sbi_dbtr_shmem_entry, sbi_dbt= r_shmem); =20 /* number of debug triggers on this cpu . */ static int dbtr_total_num __ro_after_init; +static bool have_icount __ro_after_init; static unsigned long dbtr_type __ro_after_init; static unsigned long dbtr_init __ro_after_init; =20 @@ -168,6 +178,7 @@ static int arch_smp_teardown_sbi_shmem(unsigned int cpu) static void init_sbi_dbtr(void) { struct sbiret ret; + unsigned long dbtr_count =3D 0; =20 /* * Called by hw_breakpoint_slots and arch_hw_breakpoint_init. @@ -182,6 +193,25 @@ static void init_sbi_dbtr(void) return; } =20 + ret =3D sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_NUM_TRIGGERS, + DBTR_TDATA1_TYPE_ICOUNT, 0, 0, 0, 0, 0); + if (ret.error) { + pr_warn("%s: failed to detect icount triggers. error: %ld.\n", + __func__, ret.error); + } else if (!ret.value) { + if (IS_ENABLED(CONFIG_HW_BREAKPOINT_COMPUTE_STEP)) { + pr_warn("%s: No icount triggers available. " + "Falling-back to computing single step address.\n", __func__); + } else { + pr_err("%s: No icount triggers available.\n", __func__); + dbtr_total_num =3D 0; + return; + } + } else { + dbtr_count =3D ret.value; + have_icount =3D true; + } + ret =3D sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_NUM_TRIGGERS, DBTR_TDATA1_TYPE_MCONTROL6, 0, 0, 0, 0, 0); if (ret.error) { @@ -190,7 +220,7 @@ static void init_sbi_dbtr(void) } else if (!ret.value) { pr_warn("%s: No mcontrol6 triggers available.\n", __func__); } else { - dbtr_total_num =3D ret.value; + dbtr_total_num =3D min_not_zero((unsigned long)ret.value, dbtr_count); dbtr_type =3D DBTR_TDATA1_TYPE_MCONTROL6; return; } @@ -205,7 +235,7 @@ static void init_sbi_dbtr(void) pr_err("%s: No mcontrol triggers available.\n", __func__); dbtr_total_num =3D 0; } else { - dbtr_total_num =3D ret.value; + dbtr_total_num =3D min_not_zero((unsigned long)ret.value, dbtr_count); dbtr_type =3D DBTR_TDATA1_TYPE_MCONTROL; } } @@ -344,6 +374,21 @@ static int rv_init_mcontrol6_trigger(const struct perf= _event_attr *attr, return 0; } =20 +static int rv_init_icount_trigger(struct arch_hw_breakpoint *hw) +{ + unsigned long tdata1 =3D DBTR_TDATA1_TYPE_ICOUNT; + + /* Step one instruction */ + tdata1 |=3D FIELD_PREP(DBTR_TDATA1_ICOUNT_COUNT_FIELD, 1); + + tdata1 |=3D DBTR_TDATA1_ICOUNT_U; + + hw->tdata1 =3D tdata1; + hw->tdata2 =3D 0; + + return 0; +} + int hw_breakpoint_arch_parse(struct perf_event *bp, const struct perf_event_attr *attr, struct arch_hw_breakpoint *hw) @@ -389,24 +434,28 @@ static int setup_singlestep(struct perf_event *event,= struct pt_regs *regs) /* Remove breakpoint even if return error as not to loop */ arch_uninstall_hw_breakpoint(event); =20 - ret =3D get_insn(regs, regs->epc, &insn); - if (ret < 0) - return ret; + if (have_icount) { + rv_init_icount_trigger(bp); + } else { + ret =3D get_insn(regs, regs->epc, &insn); + if (ret < 0) + return ret; =20 - next_addr =3D get_step_address(regs, insn); + next_addr =3D get_step_address(regs, insn); =20 - ret =3D get_insn(regs, next_addr, &insn); - if (ret < 0) - return ret; + ret =3D get_insn(regs, next_addr, &insn); + if (ret < 0) + return ret; =20 - bp_insn.bp_type =3D HW_BREAKPOINT_X; - bp_insn.bp_addr =3D next_addr; - /* Get the size of the intruction */ - bp_insn.bp_len =3D GET_INSN_LENGTH(insn); + bp_insn.bp_type =3D HW_BREAKPOINT_X; + bp_insn.bp_addr =3D next_addr; + /* Get the size of the intruction */ + bp_insn.bp_len =3D GET_INSN_LENGTH(insn); =20 - ret =3D hw_breakpoint_arch_parse(NULL, &bp_insn, bp); - if (ret) - return ret; + ret =3D hw_breakpoint_arch_parse(NULL, &bp_insn, bp); + if (ret) + return ret; + } =20 ret =3D arch_install_hw_breakpoint(event); if (ret) --=20 2.43.0 From nobody Mon Oct 6 10:16:38 2025 Received: from mail-qv1-f43.google.com (mail-qv1-f43.google.com [209.85.219.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A7B8F280CD3 for ; Tue, 22 Jul 2025 17:38:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753205922; cv=none; b=Q0UySZXxRLiZguyCf64Q2BSSL6qgvtYVXZRb4KkTwZkb51sMk0GwKxUziRGBfdjzhF425INR1QeDQ0Lcbxu18sveC9XSWnaSaoMDfF9FdMLQn0LZa/u67IAY3nX250ZrDAEwcbLjxPpz3dLVK92l79/M6wIZai3yKb2qEIjSA/M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753205922; c=relaxed/simple; bh=sMLCGSmu8KncOlTxjhANnVEeXKxV6ZmjtWlYdkXHxgg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=PlSZ27toup+vwysg6K4cBTXMrrRGjlWAiYl8s0t9do+5iIyRvJx0+HZsOp/6ygigAR1BOAimzeTTq9jRXgNGYSaCMFBOIe6cw2XqkDK0gT9rmuYPuXeNtw7NlaA9692PpkAKGuvMocq9FHHavXavG8uVmqgiJfHP2tvuhfJNHnw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=rivosinc.com; spf=pass smtp.mailfrom=rivosinc.com; dkim=pass (2048-bit key) header.d=rivosinc-com.20230601.gappssmtp.com header.i=@rivosinc-com.20230601.gappssmtp.com header.b=bh5i/xhT; arc=none smtp.client-ip=209.85.219.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=rivosinc.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rivosinc.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=rivosinc-com.20230601.gappssmtp.com header.i=@rivosinc-com.20230601.gappssmtp.com header.b="bh5i/xhT" Received: by mail-qv1-f43.google.com with SMTP id 6a1803df08f44-6f8aa9e6ffdso57402166d6.3 for ; Tue, 22 Jul 2025 10:38:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20230601.gappssmtp.com; s=20230601; t=1753205919; x=1753810719; 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; bh=8pehe5qahEzM3t46HZmGT5lx1CIRt9G4s5EVYhqPzIU=; b=bh5i/xhTRRFP0VGklOZt1tCxF5agQ2N7q8F9RqcdNFTx226mwNjwd+Gtmj020baMxH Cw2kPdBAjHAvdD89MEvo+mxcLndPOplODgh0XsePuSx3sjhGon2/xhCgNzjKGpU3WZ4H JzsjZWJGOpeP2f6xP18aIm04dNGdmjxpRwegGKk1nOBwUqylJ9KGXf8TRG5g9761SfiN lJcGYVbDx2eY+AIMy8gOGTKXiIE9EWboLidIB+4Sn/T4F4uOsXVuD+doPUpB/JPlxWhA Kh62jxBDYgDl8DQYHbWR/OxUSR9PXtamdMltcZnk3mZhqavjAtqY2vBH4fSGNjxQ80wy bMyQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753205919; x=1753810719; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=8pehe5qahEzM3t46HZmGT5lx1CIRt9G4s5EVYhqPzIU=; b=PR8F1u+xf+6dg4UeORcip2enn2ckDmqGXVNQjfnQL0eDUwuTxbaQE5qJo8310ebQtQ +pwjJfoxHRLsW4rRZmN5EcsWd8joB1o1EGo1jHqlzdemDYEmQ6PUfPJ5UhIRQzGbz9DM LBQpaOg18C9rV6Ql6IUfZQ3Alap9zaDOkUYhoQClLCJo5dzueIUmYWcOsqvUzg30tGjk OtLBWIzA0Y2NQV/mo4t0WG4Dg4ehH/v/Blql0e7JJfet0USfl+/0Imw4oPVe1Rs6yYLI Wn7HppcRXZhrD0Xyica6YDbykPX06PklM7TdVTSVkvrgOedVL2zShxvxKvXLCMqmYaXg 2yWw== X-Forwarded-Encrypted: i=1; AJvYcCWtpBXXDJF3Ke0owvL+bwiKF86DE8narISujbdw+zHIlSwpZbmnBQk5ttxCSQfw37SrlqnvjfpGNor6ZIw=@vger.kernel.org X-Gm-Message-State: AOJu0Yz7CHOffiWCwsrBiJf2//wlosmbQpoddT0+0K2LG92c0+KnoGWB tyTtye8EtS8Zn++sVTnqwjjCxW11T/wxUgkkEvI6fHZmn/94Q9zOtYN93rJDeUVwl58= X-Gm-Gg: ASbGncsq+IKC8jI9eY5wMkmBdjVj/D5gyQnzQuJg2ru4IiEBWMhgji59UFLhm5wd3li 7Q0XGCTEsfeohYsD2laRdxcefk0RgcSMcqo9ajYjThmmLFSHWjC2KWV1BZyPFYRiVxtnWEm54yZ +E6J73QrzST5vsCdjByTSAfcKK3Ykc0jqjBTpTJ8XvD2I3U0xAnWM6wSyBfWOHqjx9Xz4qNCmto 0XGBUHpPCRiUscx4E3pQyfXxFOGbPeZOWoCVvTksR7QqgRBj7VfIhvOe1FPpBEVbBSmdgihLu+6 uhZBVnW18vjhr5yvPaZMqcB8UK+Wn730QoXnVtnanSR1kc49RxffeHp6p7xB5R8QT67JLRi2BIa EsWS/vYA/kAganYg6pWGu1DTWhBJnPONuOXAewOZohbDC02uk547v5nZHc/07wZ+cAy7Wl39yRz 2XpnF9fr0MVgU= X-Google-Smtp-Source: AGHT+IHNmIeff1tiB4Sc65YqOosgC6ntLXzFGJQ4ydDztiuS5x6ubxGzTt6eEnVnsJPxfjwF05Z/jw== X-Received: by 2002:a05:6214:e86:b0:704:a91e:2874 with SMTP id 6a1803df08f44-707005646e7mr176096d6.19.1753205919317; Tue, 22 Jul 2025 10:38:39 -0700 (PDT) Received: from jesse-lt.ba.rivosinc.com (pool-108-26-215-125.bstnma.fios.verizon.net. [108.26.215.125]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-7051ba6b783sm54184536d6.73.2025.07.22.10.38.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 22 Jul 2025 10:38:39 -0700 (PDT) From: Jesse Taube To: linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org Cc: Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Oleg Nesterov , Jesse Taube , Himanshu Chauhan , Charlie Jenkins , Samuel Holland , Deepak Gupta , Andrew Jones , Atish Patra , Anup Patel , Mayuresh Chitale , Conor Dooley , WangYuli , Huacai Chen , Nam Cao , Andrew Morton , "Mike Rapoport (Microsoft)" , Luis Chamberlain , Yunhui Cui , Joel Granados , =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= , Celeste Liu , Evan Green , Nylon Chen Subject: [RFC PATCH 6/6] riscv: ptrace: Add hw breakpoint support Date: Tue, 22 Jul 2025 10:38:29 -0700 Message-ID: <20250722173829.984082-7-jesse@rivosinc.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250722173829.984082-1-jesse@rivosinc.com> References: <20250722173829.984082-1-jesse@rivosinc.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 Content-Type: text/plain; charset="utf-8" Add ability to setup hw breakpoints to ptrace. Call defines a new structure of (ulong[3]){bp_addr, bp_len, bp_type} with bp_type being one of HW_BREAKPOINT_LEN_X and bp_len being one of HW_BREAKPOINT_X with a value of zero dissabling the breakpoint. Signed-off-by: Jesse Taube --- arch/riscv/include/asm/processor.h | 4 ++ arch/riscv/include/uapi/asm/ptrace.h | 3 +- arch/riscv/kernel/hw_breakpoint.c | 14 ++++- arch/riscv/kernel/process.c | 4 ++ arch/riscv/kernel/ptrace.c | 93 ++++++++++++++++++++++++++++ 5 files changed, 116 insertions(+), 2 deletions(-) diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/pr= ocessor.h index 5f56eb9d114a..488d956a951f 100644 --- a/arch/riscv/include/asm/processor.h +++ b/arch/riscv/include/asm/processor.h @@ -12,6 +12,7 @@ =20 #include =20 +#include #include =20 #define arch_get_mmap_end(addr, len, flags) \ @@ -108,6 +109,9 @@ struct thread_struct { struct __riscv_v_ext_state vstate; unsigned long align_ctl; struct __riscv_v_ext_state kernel_vstate; +#ifdef CONFIG_HAVE_HW_BREAKPOINT + struct perf_event *ptrace_bps[RV_MAX_TRIGGERS]; +#endif #ifdef CONFIG_SMP /* Flush the icache on migration */ bool force_icache_flush; diff --git a/arch/riscv/include/uapi/asm/ptrace.h b/arch/riscv/include/uapi= /asm/ptrace.h index a38268b19c3d..a7998ed41913 100644 --- a/arch/riscv/include/uapi/asm/ptrace.h +++ b/arch/riscv/include/uapi/asm/ptrace.h @@ -14,7 +14,8 @@ =20 #define PTRACE_GETFDPIC_EXEC 0 #define PTRACE_GETFDPIC_INTERP 1 - +#define PTRACE_GETHBPREGS 2 +#define PTRACE_SETHBPREGS 3 /* * User-mode register state for core dumps, ptrace, sigcontext * diff --git a/arch/riscv/kernel/hw_breakpoint.c b/arch/riscv/kernel/hw_break= point.c index 437fd82b9590..c58145464539 100644 --- a/arch/riscv/kernel/hw_breakpoint.c +++ b/arch/riscv/kernel/hw_breakpoint.c @@ -633,7 +633,19 @@ void arch_uninstall_hw_breakpoint(struct perf_event *e= vent) pr_warn("%s: Failed to uninstall trigger %d. error: %ld\n", __func__, i,= ret.error); } =20 -void flush_ptrace_hw_breakpoint(struct task_struct *tsk) { } +/* + * Release the user breakpoints used by ptrace + */ +void flush_ptrace_hw_breakpoint(struct task_struct *tsk) +{ + int i; + struct thread_struct *t =3D &tsk->thread; + + for (i =3D 0; i < dbtr_total_num; i++) { + unregister_hw_breakpoint(t->ptrace_bps[i]); + t->ptrace_bps[i] =3D NULL; + } +} =20 void hw_breakpoint_pmu_read(struct perf_event *bp) { } =20 diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index 15d8f75902f8..9cf07ecfb523 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -9,6 +9,7 @@ =20 #include #include +#include #include #include #include @@ -164,6 +165,7 @@ void start_thread(struct pt_regs *regs, unsigned long p= c, =20 void flush_thread(void) { + flush_ptrace_hw_breakpoint(current); #ifdef CONFIG_FPU /* * Reset FPU state and context @@ -218,6 +220,8 @@ int copy_thread(struct task_struct *p, const struct ker= nel_clone_args *args) set_bit(MM_CONTEXT_LOCK_PMLEN, &p->mm->context.flags); =20 memset(&p->thread.s, 0, sizeof(p->thread.s)); + if (IS_ENABLED(CONFIG_HAVE_HW_BREAKPOINT)) + memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); =20 /* p->thread holds context to be restored by __switch_to() */ if (unlikely(args->fn)) { diff --git a/arch/riscv/kernel/ptrace.c b/arch/riscv/kernel/ptrace.c index ea67e9fb7a58..b78cfb0f1c0e 100644 --- a/arch/riscv/kernel/ptrace.c +++ b/arch/riscv/kernel/ptrace.c @@ -9,11 +9,13 @@ =20 #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -336,12 +338,103 @@ void ptrace_disable(struct task_struct *child) { } =20 +#ifdef CONFIG_HAVE_HW_BREAKPOINT +static void 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); + int num =3D 0; + + force_sig_ptrace_errno_trap(num, (void __user *)bkpt->address); +} + +/* + * idx selects the breakpoint index. + * Both PTRACE_GETHBPREGS and PTRACE_SETHBPREGS transfer three 32-bit word= s: + * address (0), length (1), type (2). + * Instruction breakpoint length is one of HW_BREAKPOINT_LEN_X or 0. 0 will + * disable the breakpoint. + * Instruction breakpoint type is one of HW_BREAKPOINT_X. + */ + +static long ptrace_gethbpregs(struct task_struct *child, unsigned long idx, + unsigned long __user *datap) +{ + struct perf_event *bp; + unsigned long user_data[3] =3D {0}; + + if (idx >=3D RV_MAX_TRIGGERS) + return -EINVAL; + + bp =3D child->thread.ptrace_bps[idx]; + + if (!IS_ERR_OR_NULL(bp)) { + user_data[0] =3D bp->attr.bp_addr; + user_data[1] =3D bp->attr.disabled ? 0 : bp->attr.bp_len; + user_data[2] =3D bp->attr.bp_type; + } + + if (copy_to_user(datap, user_data, sizeof(user_data))) + return -EFAULT; + + return 0; +} + +static long ptrace_sethbpregs(struct task_struct *child, unsigned long idx, + unsigned long __user *datap) +{ + struct perf_event *bp; + struct perf_event_attr attr; + unsigned long user_data[3]; + + if (idx >=3D RV_MAX_TRIGGERS) + return -EINVAL; + + if (copy_from_user(user_data, datap, sizeof(user_data))) + return -EFAULT; + + bp =3D child->thread.ptrace_bps[idx]; + if (IS_ERR_OR_NULL(bp)) + attr =3D bp->attr; + else + ptrace_breakpoint_init(&attr); + + attr.bp_addr =3D user_data[0]; + attr.bp_len =3D user_data[1]; + attr.bp_type =3D user_data[2]; + attr.disabled =3D !attr.bp_len; + + if (IS_ERR_OR_NULL(bp)) { + bp =3D register_user_hw_breakpoint(&attr, ptrace_hbptriggered, NULL, + child); + if (IS_ERR(bp)) + return PTR_ERR(bp); + + child->thread.ptrace_bps[idx] =3D bp; + return 0; + } else { + return modify_user_hw_breakpoint(bp, &attr); + } +} +#endif + long arch_ptrace(struct task_struct *child, long request, unsigned long addr, unsigned long data) { long ret =3D -EIO; + unsigned long __user *datap =3D (unsigned long __user *) data; =20 switch (request) { +#ifdef CONFIG_HAVE_HW_BREAKPOINT + case PTRACE_GETHBPREGS: + ret =3D ptrace_gethbpregs(child, addr, datap); + break; + + case PTRACE_SETHBPREGS: + ret =3D ptrace_sethbpregs(child, addr, datap); + break; +#endif default: ret =3D ptrace_request(child, request, addr, data); break; --=20 2.43.0