From nobody Sun Oct 5 10:49:02 2025 Received: from mail-qk1-f169.google.com (mail-qk1-f169.google.com [209.85.222.169]) (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 96CAE22D7B9 for ; Tue, 5 Aug 2025 19:40:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.169 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754422804; cv=none; b=NtlTZhAs4anEi0RcfeMatbMmnbxR6u+5XL0W+7D8JYNXlAg7OUpGLmJi6XRZyketsZ5/QKQqnMfaqDBoYbhtVcrwNaNIJ386TksRsHQM+E48dj5xVyAztGVyhPKr0+UAXXunkMCiqM8vyFQCoeYi08ZO5pvh5rgePciHnCHmSMc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754422804; c=relaxed/simple; bh=skB5j4qU0UxQwMJZlojcI2At+B1XOkAG2Yy2X2lRHUY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=MSewv/N/WMQmfcziy3xmv0zuTmiQVnEdpkw+2B2xImhglnQSLN2YqyGum28SYkx3bdVgAyIWnRHF7QrbWmf9uzUbXOHOAeCDAjk+Df1pKLRZlZ3sbmxNbzwYtg7QNkdVX6wqC9gsqccjosxXFfzhkX+SpX1R2gy0O1FXnLBq6I0= 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 header.i=@rivosinc.com header.b=bYTu813n; arc=none smtp.client-ip=209.85.222.169 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 header.i=@rivosinc.com header.b="bYTu813n" Received: by mail-qk1-f169.google.com with SMTP id af79cd13be357-7e6399d0654so318021985a.0 for ; Tue, 05 Aug 2025 12:40:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc.com; s=google; t=1754422800; x=1755027600; 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=C9TqRmdHx0+XIdlIKQiKbhA+RODUHyjjv/NDNl/D8gI=; b=bYTu813njR0Q7beFXO7kCPpxEH2A7iX5FxCRoJ293HLtEge0aPo/2wiCxy+S+af6tn ZwDGK9fOStfRPSjQTJwqGzEDxEZ0AfBVylCYTcW6KDzkVG2lK+1M7Ibc2rjUaSC2TOFm jpdZMsEz1ek818nv485a4q2th2W/0AVmCDoqAUwdvCfJ0QTTkr/CiCHXxQhMIW9dlCdJ uecwGdd0BuCUzexTJr5WESLLiZtprQo+CpPRB3+gtxo/V3sH+5CkF+ysZ7L30R9dHKXx 3ahQ4mirMTc9gIkHPyUAL3f0WlwTfT0xKWIUeIydrqrazaDPnKOjhryPOv6/Z4sc6YfN zF8w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1754422800; x=1755027600; 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=C9TqRmdHx0+XIdlIKQiKbhA+RODUHyjjv/NDNl/D8gI=; b=REuE9HlMRJJZV04l6KOrkC2TTA2CzD14X4hqWNTAXcbzilfcHlxLaKdi1Uj68bpT6z epiD9KT0TsDMrYnEyO/CFjUeTCdshdXp1mvK4kBGVmESzXn/6GmEMmdSF2pUatrUAXp2 n4cxR+dsq0AEJ7qGi/aUaaQM4lJZ28qaTpGdjXzvBNr9jgS1MiS+t708NASZSpJB8Wyh bxG7IP8TBILDBJ2QbDhpYSrgbEingRFvVBbccZutXzXbcDhkrqkIeIYMb8Mw6iyZEUl2 nLVB2LyHCYtCZuviEUrMY3olh7WcW1pXDhBmkckwZcxoxSq6MvxOXzkZhUUsjYjmv6yA bDkw== X-Forwarded-Encrypted: i=1; AJvYcCUBSfqnqIMRCX+06cbpQFg0BTwS+Fa2fO72kdrnuHbNvrFaiD+8fO/ACOozDPQTWRkOk+oqrpZSkHe7r3Q=@vger.kernel.org X-Gm-Message-State: AOJu0Yy56otiKv5HyOi3vIcaoDsjkNwC8bmlZZqf1766VRiZ2kzYB3sN GdL9nlBXKoyPcV2ysPpk2UHt15oN7qlmZEinI+oVdzApFOgZv7cye1GU0LND6pHKSyE= X-Gm-Gg: ASbGncsdgGYqN//WSfhP1QDkVMNIsNmQZjIhVLNyok2mJOBiuyQHRbuEAKtGmAWC+xV 4L4MHF9Km5OOv37BI0fRVYd4bJxbHctDgC/3OH1jlanttW/K7usqeug6CIFOWf5QxmfQVE+4jFL xUMQ2iS+9ChElE6t+nch/Mir3Mbsoj5b+wdr3au9SIBk9I/BWpD9bgPhgwOiOIPNgl4cjcF1524 mEGyPMz9/D8Kuzqy/ft8W38V/c2ADyAitmVLll1OYA7Gmopa+S8F80Vfvm/T1dBPi4uZawjkzIv 7+NM539gqWZvwUEEpWXw0I4uUkJBfTN7SV2Aj+Cx9MGyKmOM9yOixugyVWSHAeSmW0/pmzKqujf T7m70tj7VPvvBEKPGvLDiJLlVhmddUUIuCQE46UP6mVS/O4FWPW+rEyxezZz6/MQ9YSdiFcRuKd ZZTLzyQbUjwxCKkSRv X-Google-Smtp-Source: AGHT+IEzHnlXMLFLFH7ARBb94c6v3DpzHk5tOCrNEnPmOxJKtABtAWgi9vM+SApe2NKHi7ctYrnBfg== X-Received: by 2002:a05:620a:a50a:b0:7e6:87fc:54b1 with SMTP id af79cd13be357-7e814e17d1cmr77758785a.66.1754422800100; Tue, 05 Aug 2025 12:40:00 -0700 (PDT) Received: from jesse-lt.jtp-bos.lab (pool-108-26-215-125.bstnma.fios.verizon.net. [108.26.215.125]) by smtp.gmail.com with ESMTPSA id af79cd13be357-7e67f7064b0sm717855685a.54.2025.08.05.12.39.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 Aug 2025 12:39:59 -0700 (PDT) From: Jesse Taube To: linux-riscv@lists.infradead.org Cc: Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Oleg Nesterov , Kees Cook , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , "Liang, Kan" , Shuah Khan , Jesse Taube , Himanshu Chauhan , Charlie Jenkins , Samuel Holland , Conor Dooley , Deepak Gupta , Andrew Jones , Atish Patra , Anup Patel , Mayuresh Chitale , Evan Green , WangYuli , Huacai Chen , Arnd Bergmann , Andrew Morton , Luis Chamberlain , "Mike Rapoport (Microsoft)" , Nam Cao , Yunhui Cui , Joel Granados , =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= , Sebastian Andrzej Siewior , Celeste Liu , Chunyan Zhang , Nylon Chen , Thomas Gleixner , =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= , Vincenzo Frascino , Joey Gouly , Akihiko Odaki , Ravi Bangoria , linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-perf-users@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH 1/8] riscv: Add insn.c, consolidate instruction decoding Date: Tue, 5 Aug 2025 12:39:48 -0700 Message-ID: <20250805193955.798277-2-jesse@rivosinc.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250805193955.798277-1-jesse@rivosinc.com> References: <20250805193955.798277-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 --- RFC -> V1: - No change --- 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 Sun Oct 5 10:49:02 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 49203242D9D for ; Tue, 5 Aug 2025 19:40:04 +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=1754422805; cv=none; b=CTvM05uF9kjOlD3NEYwu02t1e5K9zOSqt7+XgQnqgIUwbxJBg0BBYkSFMG7USgYgJbbih6DfErMHyh4ac3RyaHg/E96hoa9F0BSynyihuIq+LQGp4L4z91w2oXc6Oy7WZ4I1LXlhhyMIXV+gMMLN6TnhIXLtFZeG5nBm1v0CwJ0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754422805; c=relaxed/simple; bh=3yynwp5xkX2tlPXadX9UGBNDDBTvMVZycNKpFPtm3RY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=RasGMk1klMZnll9jH5n9MvU2wGljDoo9o7V9NJ02Qlw1kHPq5KmpDlA0pgZMFnipp99DNWn+/HGQlOUtm90AKQ25g1OVnsOR39dpScxi9biO7O27y9tQ6xyZM1v14utx4I9GlUXsYW4o5PDtNazrDI3KAlxIuaLr0NuXX5mccLg= 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 header.i=@rivosinc.com header.b=Lz6no2bh; 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 header.i=@rivosinc.com header.b="Lz6no2bh" Received: by mail-qk1-f180.google.com with SMTP id af79cd13be357-7e814f6fc57so13496385a.1 for ; Tue, 05 Aug 2025 12:40:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc.com; s=google; t=1754422803; x=1755027603; 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=MBx+S5U+eiCq8pUooPV2kB8TZrzcZaWUvNy/30cjCv8=; b=Lz6no2bhsa1jJH8jZxqPZzw3Dy+jEShkPkGbr2xpO7yZmfg/EmJmBTdU4AKMwF4SZ2 Jp1aH6/3uCD+GK5l2mnVRV+X2Mf2Ttn+dFLEIz3zQwfrZZhN8D0P+YmQQNFIIHaq04TF NjPS4cYh7xexa/uVR3g/EruKQLPo4FYuFg+UYyQrJHmbZ8OU7+ecTynfKoXfNjZgFTFX ifV+JOYl830td9WF3lnPdhjZBYJ7o/4IgAOZmetAhaNmcaOIrnssYivNasrwoj6ZE6ve fd7+2DDwDjdtWsQSgAYwsvtWk5CzUO3tIkGbyE3f4lLsPKU1ts7PkJF3VcRypCtllwM4 DYAA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1754422803; x=1755027603; 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=MBx+S5U+eiCq8pUooPV2kB8TZrzcZaWUvNy/30cjCv8=; b=bVWJprkLk9b9OEnZEJ3fnKrysgw5LLEb6Cp3erJ8ZeHvjEYvsfnqVy3JdUzQaSzaet 7k4jbGRIqR9n9wjpFtFWGYO5TdS9Tff9b39z7gYYmrhg03rsK2lmMB83/7d2kynFNt7t GwUqfrvLS+Rt7kod48f0zTWI3jV6mtQmTEaN1GTOqJA5bdTKLJzBWab4fNAkm2dygJP1 7Vc2mCtJR2ldsMqF3uALOffCgpltuUxJOvh26wUQ4my4INMDhjjWSaddghlbsZ/frI6X UzhOxsBMRh1aDVlvVoGmw+/tPKMn/y/u81uwKmGw5yspZhFumg8ALq6tpdEcdV+QyVaR NRqQ== X-Forwarded-Encrypted: i=1; AJvYcCWppZ3YAEHY8W1Zbr7qAxO4DHgFcHjjIfhJaAsUxnsiWNehySWtFc/Mt++LDX+i+bsEQCd+Ga8SNgtRNz8=@vger.kernel.org X-Gm-Message-State: AOJu0Yw43Ulm86rLcSVu9+PenRBAojTlynUW8/8pbctTmslDllGxuSy/ IPdFyhLPnFnL9KsHpOKgnx6PCbPRrj8Z/vhuc5yFPiAPmwiJJNSFNdVRGiFpFoPDZWw= X-Gm-Gg: ASbGnctu7TcIEF0IsZReK53XmQOeMXKpK8uB8t1cB8A04L9xic/wKnmroAah6g0FUtj H7OD9wU6v5S0vCOpXqaRr2mTDy/s313KHrao+4nCqn1B+aeqyhow00hbaNxM/Z6/pOK9Fj9YF6r F3GUg7izJe92N/qAZdw5vmnSY7Ekqht2M4zbdwTBQss7O3GWg2bsIe4xXiHWRNj2jm7KW9VCicg 0rHucwSlzOYpjXVpgggCboGXpW0FMgltFe+UNpw14AaGj0CI0Kvai0vKQE0M7QERgBAmDjF2MMK fPpGzMeTiOqcgzyN6jCwDssYDyspmxDIWJ0HXheij0PpaVHn0RlX4kxjMaocbAW5UHx/MqJnjcl iNnM37M3SVitLmXL8mHQPOgNFAlPHuCAyMt6ZxHEZD/G3BrBv7QoLylFcoX86MHVWkxUSLDCuwe cd4BFvxg== X-Google-Smtp-Source: AGHT+IGX7OQglHEEPOq98awptA6J/9DSpmeeKDOZlvbBLWPX9HQBX2UPCjNuTmMSORoLz+090C2k2w== X-Received: by 2002:a05:620a:424c:b0:7e6:99d7:3340 with SMTP id af79cd13be357-7e8156bcaacmr32337785a.12.1754422802272; Tue, 05 Aug 2025 12:40:02 -0700 (PDT) Received: from jesse-lt.jtp-bos.lab (pool-108-26-215-125.bstnma.fios.verizon.net. [108.26.215.125]) by smtp.gmail.com with ESMTPSA id af79cd13be357-7e67f7064b0sm717855685a.54.2025.08.05.12.40.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 Aug 2025 12:40:02 -0700 (PDT) From: Jesse Taube To: linux-riscv@lists.infradead.org Cc: Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Oleg Nesterov , Kees Cook , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , "Liang, Kan" , Shuah Khan , Jesse Taube , Himanshu Chauhan , Charlie Jenkins , Samuel Holland , Conor Dooley , Deepak Gupta , Andrew Jones , Atish Patra , Anup Patel , Mayuresh Chitale , Evan Green , WangYuli , Huacai Chen , Arnd Bergmann , Andrew Morton , Luis Chamberlain , "Mike Rapoport (Microsoft)" , Nam Cao , Yunhui Cui , Joel Granados , =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= , Sebastian Andrzej Siewior , Celeste Liu , Chunyan Zhang , Nylon Chen , Thomas Gleixner , =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= , Vincenzo Frascino , Joey Gouly , Akihiko Odaki , Ravi Bangoria , linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-perf-users@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH 2/8] riscv: Add SBI debug trigger extension and function ids Date: Tue, 5 Aug 2025 12:39:49 -0700 Message-ID: <20250805193955.798277-3-jesse@rivosinc.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250805193955.798277-1-jesse@rivosinc.com> References: <20250805193955.798277-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 --- RFC -> V1: - No change --- 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 Sun Oct 5 10:49:02 2025 Received: from mail-qk1-f178.google.com (mail-qk1-f178.google.com [209.85.222.178]) (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 2E66126CE12 for ; Tue, 5 Aug 2025 19:40:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754422808; cv=none; b=BhEVbilHZQG4Jgb+4iafZOOyc4y/TYYrgcgi0pALYuQamEgQ//S8kRoWJdthAnXvjUVRPUvsJ6aq+s+NfGyqk2KxQI5lVlWMT1zqh98X0rzM0RlzgpI65dKV90Xlh/cu/u/7qGD87sU5sHnjCGPFZYNuIOeET2RoWZWQbN15BfY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754422808; c=relaxed/simple; bh=Mw1HF+WYqrZH50B60QETN97Z6Qf9c2O3cgvwGI4nSFg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Z4N3MzQkHCBO6p84qJkzzXo+P9Ahi9IfkbaEKik4t/GgrcYpUDZxNs80i1ubIWow9BfWx3g8tXQe0ocuTbXk6hEZgK2/YVqGuVqgpTAc3/IQCldb6Qt3w94fNcZOFEXySEXGy3PrfM8ZEGyxVW7ZDWFJGtjc8YhE0rF6D77weuE= 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 header.i=@rivosinc.com header.b=WcrIQikb; arc=none smtp.client-ip=209.85.222.178 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 header.i=@rivosinc.com header.b="WcrIQikb" Received: by mail-qk1-f178.google.com with SMTP id af79cd13be357-7e7f940a386so171992985a.3 for ; Tue, 05 Aug 2025 12:40:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc.com; s=google; t=1754422805; x=1755027605; 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=CMI5Xwq0SqGXnmGRw5QTZMv+U2y6SNaFWej8c2zdngA=; b=WcrIQikb0VFMCoabuN1q9WZT2QVr9aFu9ytV5kdo8aLXFxoGSoJjFuEyYWaR9xt3NB ATrDEOAqwAaPCdLac/salE7Fmq73mMHJbpjHOaOL07Es7c9cVWGiWm+WZRvmbf7elDzF BA8E7SOpTN58Qnpph6STZtRFPR64WNZxS/GsU8nuGdUuWDEm4HD1pbYlI+TjbwRY265F CHO1yCnCbD2Eb/baWc/w2RTX5bElFPucouOGBDlyyFilTH14BdYJHZagOFWpmeX3QhOU nEBkxH+SdVdvPEMxBXfiodL5gB8fR4voQmEzr92H6FjisvLdpvZ44cDSvfjztiP15wR9 /fxA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1754422805; x=1755027605; 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=CMI5Xwq0SqGXnmGRw5QTZMv+U2y6SNaFWej8c2zdngA=; b=E2tKSveeRi5hy0VSNiTHYKrit3tuKaZWrkc+L65NWaKpQYjY/DJy4vQaZCJNbhZjtB aiWkhYuhzDAXGAi5YN4wTspZL8/YdonkIMVBsZGA2X14/j+MxRnS+9vOzfnTYBxce1Ob K9TztSDSEmAaI+ts/DQGc5+jy4XgXrnLG+spCEv8wKk0xgKmLfBmv+UBq9R82rAt68ER ByiaSK8jykZyk3DxRMkRkKY8LDD9Q2GNw3puSmjAhasRxhRC9/Qozm++MQJjEk4ELPN7 ybNaJ+IjPGvKG9V44goiNUainNH/h0fKi2vRQDATDRbj9TXgGymRVjGZEYcoZcfcEgrq cJtw== X-Forwarded-Encrypted: i=1; AJvYcCXCJg+z7tkWOOdJ4tp98qynvkcedVT8olQBxaJr9BARLdN4i6aJKu+LSwXeSomfGGLNYE9genCIk7Qha00=@vger.kernel.org X-Gm-Message-State: AOJu0Yw7iVpBYCLg8Lz9+a1Xv4wanGU9nfj23ANsB8Hsvq96uzfQtzH0 L/yO7C8htY1GaVH4WLEZUxP3855CC0IKNXK+phw6YAcV07XrlixYkTkea6bnP5Hh090= X-Gm-Gg: ASbGncuq6zqlOpbTxx8X+D3tIXmzsPXQzuqmnt2LST5qxISDSweGxvP6R+7t4whLJIh xTOTa5sDZpzkZVqh2ueKiqinY/Xzx0lIQBMF3SVd9OfS9/w+Wcu7bkrhyb7pf4pQ5s5mFemjGiU sDmb0C/sXq3KAAOnl6RBZ4LbDmgfBDwEoyL8RYFfJ/RXEK39xDyX8O7sRx6/4FSXng6IAHCysxu GTggdnZNgr1ijNlNLlFIodLPFKtlD2PufPvroemzwvDQ+C4iG7r9N/e33r6svBXpS35jcqrXZBf fHh+Zeibdc9REeqDX+aUR1c5yC4yQss4pLeuGiqAFEQ4ywrTR+FYAnx9ruuwmK7W5VqBCXBM7vd 0I9QPf5ZrpEKzYHTl1xtMqghgU1ixEgLSxDApY8aVbTbUW4FaQXc0xDS2JxkjcTjqS8jSon6Hjq cI5rKfTg== X-Google-Smtp-Source: AGHT+IGslZriZ3OsEZBWmVfkk5oCBsMISvqP0jsnyJuJf09cg7efSarv3MBZUu5//ACqxd//7g3UxQ== X-Received: by 2002:a05:620a:430a:b0:7e8:2e5:feb3 with SMTP id af79cd13be357-7e814cf9504mr90508985a.1.1754422804849; Tue, 05 Aug 2025 12:40:04 -0700 (PDT) Received: from jesse-lt.jtp-bos.lab (pool-108-26-215-125.bstnma.fios.verizon.net. [108.26.215.125]) by smtp.gmail.com with ESMTPSA id af79cd13be357-7e67f7064b0sm717855685a.54.2025.08.05.12.40.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 Aug 2025 12:40:04 -0700 (PDT) From: Jesse Taube To: linux-riscv@lists.infradead.org Cc: Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Oleg Nesterov , Kees Cook , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , "Liang, Kan" , Shuah Khan , Jesse Taube , Himanshu Chauhan , Charlie Jenkins , Samuel Holland , Conor Dooley , Deepak Gupta , Andrew Jones , Atish Patra , Anup Patel , Mayuresh Chitale , Evan Green , WangYuli , Huacai Chen , Arnd Bergmann , Andrew Morton , Luis Chamberlain , "Mike Rapoport (Microsoft)" , Nam Cao , Yunhui Cui , Joel Granados , =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= , Sebastian Andrzej Siewior , Celeste Liu , Chunyan Zhang , Nylon Chen , Thomas Gleixner , =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= , Vincenzo Frascino , Joey Gouly , Akihiko Odaki , Ravi Bangoria , linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-perf-users@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH 3/8] riscv: insn: Add get_insn_nofault Date: Tue, 5 Aug 2025 12:39:50 -0700 Message-ID: <20250805193955.798277-4-jesse@rivosinc.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250805193955.798277-1-jesse@rivosinc.com> References: <20250805193955.798277-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" get_insn_nofault uses get_insn with pagefaults dissabled, allowing it to be called in an atomic context. Signed-off-by: Jesse Taube --- Unsure if copy_from_kernel_nofault is an acceptable replacement for direct dereference in __read_insn. RFC -> V1: - Add new function instead of using copy_from_user_nofault --- arch/riscv/include/asm/insn.h | 1 + arch/riscv/kernel/insn.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/arch/riscv/include/asm/insn.h b/arch/riscv/include/asm/insn.h index ba74e5b8262c..f87e0a48f786 100644 --- a/arch/riscv/include/asm/insn.h +++ b/arch/riscv/include/asm/insn.h @@ -553,6 +553,7 @@ static inline void riscv_insn_insert_utype_itype_imm(u3= 2 *utype_insn, u32 *itype #include =20 int get_insn(struct pt_regs *regs, ulong epc, ulong *r_insn); +int get_insn_nofault(struct pt_regs *regs, ulong epc, ulong *r_insn); unsigned long get_step_address(struct pt_regs *regs, u32 code); =20 #endif /* _ASM_RISCV_INSN_H */ diff --git a/arch/riscv/kernel/insn.c b/arch/riscv/kernel/insn.c index dd2a6ef9fd25..c8f77c0093c9 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 @@ -74,6 +77,17 @@ int get_insn(struct pt_regs *regs, ulong epc, ulong *r_i= nsn) } } =20 +int get_insn_nofault(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; +} + /* Calculate the new address for after a step */ unsigned long get_step_address(struct pt_regs *regs, u32 code) { --=20 2.43.0 From nobody Sun Oct 5 10:49:02 2025 Received: from mail-qk1-f179.google.com (mail-qk1-f179.google.com [209.85.222.179]) (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 82396296170 for ; Tue, 5 Aug 2025 19:40:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.179 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754422811; cv=none; b=jIdFnPxQtkfe18Bw2V/0GMmbWtUNK9I58XlhP/uldZm2XsKVglLEk9eB+LpuQsNX8MgUOBQoE3JWHSYgBreNdtuAtceHb8/10MmMvDfx+Rh4bGtw3nwScC50zWAPYw8hk/Ev/idG5O27e42fOqcLWPSdLiwXbAJtlFJkdLsC50E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754422811; c=relaxed/simple; bh=0BcMwB1k4zZuF4CCoIsDa1R+ocm34FgwZnPVtYusAXU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=pNndvn3wO5Zra0+Tyzci2GnFSA+8gjqHmb/HRSqLnhcqSx4+4D7WJON40+W6r5rKz4Pcm8IfP3X4g3gUT7sQBNZPggbcPCb9DAWzHbV79UdffQPM8fojyhZhgq93JTsds3ECunXk6zZxX7t8zw3VrW//n1v5noa30gitaeU+C2Y= 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 header.i=@rivosinc.com header.b=WHJ1YYKa; arc=none smtp.client-ip=209.85.222.179 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 header.i=@rivosinc.com header.b="WHJ1YYKa" Received: by mail-qk1-f179.google.com with SMTP id af79cd13be357-7e182e4171bso501371385a.3 for ; Tue, 05 Aug 2025 12:40:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc.com; s=google; t=1754422807; x=1755027607; 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=jd0j40NMvbqtFat+ppI4UjxJvLFesei6/BN60ICM5XU=; b=WHJ1YYKaK1d8aFvRGcb4t1LGebaxpeoDkBktUBSkNRm+Tgfpvxp427nOxTqcAs+J/z 2/h6TXRtSV+RMX+Q0XM/L9eM2Lz2/BTIOsydrtCxPTsTyLeRkhZsCNDWLTH1cLAUBjWU +o533mIOy4CwqdVOUAoOj8wCxDFkQWkCr6n6rZZnZFR4IXe7m/HdJP6tMVWwjsDdoDEU MjlV6wNBMsHnNYgVZOMv8w6IeW6fv4giUEkSZEOO3To4oFUqSbjPTJzKqUMSSxcsw5zO VLhdl4gsQ0Zg9NeKhfIQYswLu0JcVF9YmMtKhFUAl/mYgKE3ks1hSsthwQ6Q5OYYNzh5 ZdFQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1754422807; x=1755027607; 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=jd0j40NMvbqtFat+ppI4UjxJvLFesei6/BN60ICM5XU=; b=CxTmp2lkG4SKZdvfZi4EN6qJi0ckjRtp/yJP7mdN2tW2BXpBuuM4RvAz+dIKpQHi3A 7PkM1M41kt8EfP5Z6z50j0+Vg/VmcUi6LQGo+lJwagIxqsZAl1Iv8IEI/g3tpLFhxnMv nOdRoMKr6xQbQeQudUqplhsEtAbHA8DomuElezggTSxU1WYqz9IHiH8jmAj7WMC7TpfZ fLBt7xu9QNUUVQmipDfuS2YvBu49uApDYL/1sXYcpqMKyEeEb+iE/ZovKFFRS+9FOphq bq3kS25vKU8evHszV/9W2cKI3i1ro4zlf9dbHyWtx7QEFp6Vpbn21Rc8RP0UYuobjO/f yfaw== X-Forwarded-Encrypted: i=1; AJvYcCW24dW4ZnsFlhWLJ1+FOjWr1A/vpGh0936zcj2k0Kx0/dfcm4TDXj+lG/Lsdq7+PSjCk4a/wybUGH/Pky8=@vger.kernel.org X-Gm-Message-State: AOJu0YzwNATBGwR2iDSMM6mPE/Pq+DiGDMXLylQwMPq3Fc+l1cylnlfE XLkrSDh00zuuJ2uXi4TjeiiokJKU2FMZVuBd6VjbHcHeHPPFtVUIr+JwSz5/mJ7+Z94= X-Gm-Gg: ASbGncvCIR7IVrdJQ6vVPEiCGRXJ1qHLKe1Vhfzyh5bTVNFleyOEZfsb3AYZ+9rcj/k oUlm+IAwlqu8EljPNg/vcuiSFMBH1Nwc/g5NXOLcXhMm2xgyRQTX9bBcK4U+p8L3igK8YrKchTe pZTO5dSqKFmw3Q0Dw077e/XhBuQ5JqeKNDIPWm8G2kPH+qONsS5tleD19JRZHMAV6j4QjvCrlKP 54BSUN89u0BCimwMSe1IN6ltpKNIjaVjZozg9QXevADc8ndzU7CzgXc5i3C2aOgmP7vG9dZW+IY njYCu2zwZSKK4LTvcx3QbZp12NNdLtolFBlB2fu5xVlid4aFApXp6iDyHZGlHV3k5PXY39LFdM4 dbvdLpfN6bqI2z5DbK88IcvDYCol4+Khsr2u7+0YXAGmRrAgLkoUFp+YCnto4b+6gEI+tfiF82b G2dMQ5ew== X-Google-Smtp-Source: AGHT+IHKOJjFyM5KJ7pzO51EYzVZUc5RjkyNVSAuGiES0xqtomHKqea1Tm5RWJX0zh7CqEqWLFNOAQ== X-Received: by 2002:a05:620a:a01c:b0:7e6:9c3a:80e9 with SMTP id af79cd13be357-7e814daa9a0mr61015885a.38.1754422807116; Tue, 05 Aug 2025 12:40:07 -0700 (PDT) Received: from jesse-lt.jtp-bos.lab (pool-108-26-215-125.bstnma.fios.verizon.net. [108.26.215.125]) by smtp.gmail.com with ESMTPSA id af79cd13be357-7e67f7064b0sm717855685a.54.2025.08.05.12.40.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 Aug 2025 12:40:06 -0700 (PDT) From: Jesse Taube To: linux-riscv@lists.infradead.org Cc: Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Oleg Nesterov , Kees Cook , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , "Liang, Kan" , Shuah Khan , Jesse Taube , Himanshu Chauhan , Charlie Jenkins , Samuel Holland , Conor Dooley , Deepak Gupta , Andrew Jones , Atish Patra , Anup Patel , Mayuresh Chitale , Evan Green , WangYuli , Huacai Chen , Arnd Bergmann , Andrew Morton , Luis Chamberlain , "Mike Rapoport (Microsoft)" , Nam Cao , Yunhui Cui , Joel Granados , =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= , Sebastian Andrzej Siewior , Celeste Liu , Chunyan Zhang , Nylon Chen , Thomas Gleixner , =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= , Vincenzo Frascino , Joey Gouly , Akihiko Odaki , Ravi Bangoria , linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-perf-users@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH 4/8] riscv: Introduce support for hardware break/watchpoints Date: Tue, 5 Aug 2025 12:39:51 -0700 Message-ID: <20250805193955.798277-5-jesse@rivosinc.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250805193955.798277-1-jesse@rivosinc.com> References: <20250805193955.798277-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 --- RFC -> V1: - Add dbtr_mode to rv_init_mcontrol(6)_trigger - Add select HAVE_MIXED_BREAKPOINTS_REGS - Add TDATA1_MCTRL_SZ and TDATA1_MCTRL6_SZ - Capitalize F in Fallback comment - Fix in_callback code to allow multiple breakpoints - Move perf_bp_event above setup_singlestep to save the correct state - Use sbi_err_map_linux_errno for arch_smp_teardown/setup_sbi_shmem --- arch/riscv/Kconfig | 2 + arch/riscv/include/asm/hw_breakpoint.h | 59 +++ 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 | 614 +++++++++++++++++++++++++ arch/riscv/kernel/traps.c | 6 + 7 files changed, 687 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..fd8b62cdc6f5 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 @@ -176,6 +177,7 @@ config RISCV select HAVE_KRETPROBES if !XIP_KERNEL # https://github.com/ClangBuiltLinux/linux/issues/1881 select HAVE_LD_DEAD_CODE_DATA_ELIMINATION if !LD_IS_LLD + select HAVE_MIXED_BREAKPOINTS_REGS select HAVE_MOVE_PMD select HAVE_MOVE_PUD select HAVE_PAGE_SIZE_4KB 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..cde6688b91d2 --- /dev/null +++ b/arch/riscv/include/asm/hw_breakpoint.h @@ -0,0 +1,59 @@ +/* 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..3f96e744a711 --- /dev/null +++ b/arch/riscv/kernel/hw_breakpoint.c @@ -0,0 +1,614 @@ +// 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 TDATA1_MCTRL6_SZ(sz) \ + FIELD_PREP(DBTR_TDATA1_MCONTROL6_SIZE_FIELD, sz) + +#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 + +#define TDATA1_MCTRL_SZ(lo, hi) \ + (FIELD_PREP(DBTR_TDATA1_MCONTROL_SIZELO_FIELD, lo) | \ + FIELD_PREP(DBTR_TDATA1_MCONTROL_SIZEHI_FIELD, hi)) + +enum dbtr_mode { + DBTR_MODE_U =3D 0, + DBTR_MODE_S, + DBTR_MODE_VS, + DBTR_MODE_VU, +}; + +/* 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) { + pr_warn("%s: failed to setup shared memory. error: %ld\n", __func__, ret= .error); + return sbi_err_map_linux_errno(ret.error); + } + + 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) { + pr_warn("%s: failed to teardown shared memory. error: %ld\n", __func__, = ret.error); + return sbi_err_map_linux_errno(ret.error); + } + + 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, enum dbtr_mode mode) +{ + 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 TDATA1_MCTRL_SZ(DBTR_TDATA1_MCONTROL_SIZELO_8BIT, 0); + break; + case HW_BREAKPOINT_LEN_2: + hw->len =3D 2; + tdata1 |=3D TDATA1_MCTRL_SZ(DBTR_TDATA1_MCONTROL_SIZELO_16BIT, 0); + break; + case HW_BREAKPOINT_LEN_4: + hw->len =3D 4; + tdata1 |=3D TDATA1_MCTRL_SZ(DBTR_TDATA1_MCONTROL_SIZELO_32BIT, 0); + break; +#if __riscv_xlen >=3D 64 + case HW_BREAKPOINT_LEN_8: + hw->len =3D 8; + tdata1 |=3D TDATA1_MCTRL_SZ(DBTR_TDATA1_MCONTROL_SIZELO_64BIT, + DBTR_TDATA1_MCONTROL_SIZEHI_64BIT); + break; +#endif + default: + return -EINVAL; + } + + switch (mode) { + case DBTR_MODE_U: + tdata1 |=3D DBTR_TDATA1_MCONTROL_U; + break; + case DBTR_MODE_S: + tdata1 |=3D DBTR_TDATA1_MCONTROL_S; + break; + default: + return -EINVAL; + } + + hw->tdata1 =3D tdata1; + + return 0; +} + +static int rv_init_mcontrol6_trigger(const struct perf_event_attr *attr, + struct arch_hw_breakpoint *hw, enum dbtr_mode mode) +{ + 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 TDATA1_MCTRL6_SZ(DBTR_TDATA1_MCONTROL6_SIZE_8BIT); + break; + case HW_BREAKPOINT_LEN_2: + hw->len =3D 2; + tdata1 |=3D TDATA1_MCTRL6_SZ(DBTR_TDATA1_MCONTROL6_SIZE_16BIT); + break; + case HW_BREAKPOINT_LEN_4: + hw->len =3D 4; + tdata1 |=3D TDATA1_MCTRL6_SZ(DBTR_TDATA1_MCONTROL6_SIZE_32BIT); + break; + case HW_BREAKPOINT_LEN_8: + hw->len =3D 8; + tdata1 |=3D TDATA1_MCTRL6_SZ(DBTR_TDATA1_MCONTROL6_SIZE_64BIT); + break; + default: + return -EINVAL; + } + + switch (mode) { + case DBTR_MODE_U: + tdata1 |=3D DBTR_TDATA1_MCONTROL6_U; + break; + case DBTR_MODE_S: + tdata1 |=3D DBTR_TDATA1_MCONTROL6_S; + break; + case DBTR_MODE_VS: + tdata1 |=3D DBTR_TDATA1_MCONTROL6_VS; + break; + case DBTR_MODE_VU: + tdata1 |=3D DBTR_TDATA1_MCONTROL6_VU; + break; + default: + return -EINVAL; + } + + 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, DBTR_MODE_U); + break; + case DBTR_TDATA1_TYPE_MCONTROL6: + ret =3D rv_init_mcontrol6_trigger(attr, hw, DBTR_MODE_U); + break; + default: + pr_warn("Unsupported trigger type %lu.\n", dbtr_type >> DBTR_TDATA1_TYPE= _SHIFT); + ret =3D -EOPNOTSUPP; + break; + } + + return ret; +} + +/** + * setup_singlestep - Update breakpoint to next instruction after breakpoi= nt. + * @event: Perf event to change + * @regs: regs at breakpoint + * + * Update breakpoint to next instruction that would have + * executed after the current breakpoint. + * + * This allows for single-stepping the instruction being debugged. + * Then restoring the original breakpoint. + * + * Returns Zero on success, negative on failure + */ +static int setup_singlestep(struct perf_event *event, struct pt_regs *regs) +{ + struct arch_hw_breakpoint *bp =3D counter_arch_bp(event); + struct perf_event_attr bp_insn; + unsigned long insn, next_addr =3D 0; + int ret; + + /* Remove breakpoint even if return error as not to loop */ + arch_uninstall_hw_breakpoint(event); + + ret =3D get_insn_nofault(regs, regs->epc, &insn); + if (ret < 0) + return ret; + + next_addr =3D get_step_address(regs, insn); + + ret =3D get_insn_nofault(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) +{ + int i, ret =3D 0, bp_ret =3D NOTIFY_DONE; + bool expecting_callback =3D false; + struct arch_hw_breakpoint *bp; + struct perf_event *event; + + 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 (event->attr.bp_type) { + /* Breakpoint */ + case HW_BREAKPOINT_X: + if (event->attr.bp_addr =3D=3D regs->epc) { + perf_bp_event(event, regs); + ret =3D setup_singlestep(event, regs); + if (ret < 0) { + pr_err("%s: setup_singlestep failed %d.\n", __func__, ret); + goto exit; + } + + bp_ret =3D NOTIFY_STOP; + goto exit; + } + break; + + /* Watchpoint */ + case HW_BREAKPOINT_W: + case HW_BREAKPOINT_R: + case HW_BREAKPOINT_RW: + /* Watchpoints will trigger on smaller loads than the given type. + * To allow for this, check if the load was within the size of + * the type. Cast badaddr to the type of bp_addr. + */ + if (abs_diff(event->attr.bp_addr, (__u64)regs->badaddr) < bp->len) { + perf_bp_event(event, regs); + ret =3D setup_singlestep(event, regs); + if (ret < 0) { + pr_err("%s: setup_singlestep failed %d.\n", __func__, ret); + goto exit; + } + + bp_ret =3D NOTIFY_STOP; + goto exit; + } + break; + + default: + pr_warn("%s: Unknown type: %u\n", __func__, event->attr.bp_type); + goto exit; + } + + if (bp->in_callback) { + expecting_callback =3D true; + if (regs->epc !=3D bp->next_addr) { + continue; + } + + arch_uninstall_hw_breakpoint(event); + /* Restore original breakpoint */ + if (hw_breakpoint_arch_parse(NULL, &event->attr, bp)) + goto exit; + if (arch_install_hw_breakpoint(event)) + goto exit; + + bp_ret =3D NOTIFY_STOP; + goto exit; + } + + } + + if (expecting_callback) { + pr_err("%s: in_callback was set, but epc (%lx) was not at next address(%= lx).\n", + __func__, regs->epc, bp->next_addr); + } +exit: + return bp_ret; + +} + +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; +} + +void arch_uninstall_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) { + *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 Sun Oct 5 10:49:02 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 96CA929A9C3 for ; Tue, 5 Aug 2025 19:40:10 +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=1754422813; cv=none; b=b8eyGrjOtVJL5AmY3pUyF/9738XXdWeg91tF6kMw8wcm4Av0K+b7k+0N+4XGSpSFY6JDBTVOH8DlNtx0HQB0WYH+VfQyDifLSTeChL861LJDdRLWyD0XWKPPLAigEKuVczB4IRGda/w7ad35jrRch5uVv9V0QrBVPX6rt/emA5Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754422813; c=relaxed/simple; bh=uyTuacP70BrJ2Os1lYqDvLJH/NGpV9gy074HUg8RPQA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=pQrtN/tM146WKqQS1qgQE7dGSm8r+cRuXd55iAQqjGFYN/yM89zuGh0jQTYJ53ZWCD/azU34xlsC5RYqX+Ayr29Z/ND4mMpRdNzP6moQnhqG2l1D9YbxxOV7dEEXIoPr6ya7hRylzRx0X2hbXMG7epUZHuVVZeLGulSim4EmX1s= 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 header.i=@rivosinc.com header.b=Mg3P791p; 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 header.i=@rivosinc.com header.b="Mg3P791p" Received: by mail-qk1-f180.google.com with SMTP id af79cd13be357-7e6696eb47bso638092185a.3 for ; Tue, 05 Aug 2025 12:40:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc.com; s=google; t=1754422809; x=1755027609; 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=thXWESjgb/asehL5NdNra0dnr/Mi+exiNBPp9wa9z9w=; b=Mg3P791pT+v64OUdeGJZNNz63798En1caGhzQMyseps0fy0/z9p8Wt70M9PckJ0cPD qY/d6dZLlcub4vaKg1WEB8MPoaOS8W0OHNxvGY9D9Jtt7v01dEBc3ptS7Dqb08aZd1Tr qp8/sfX+HXqT9zJFhBRfOaLvBf4zXYrUVUyQKQSq8jR2o6Cgxo7UfEW+jt2fC+q39NOC xvd2CDwjmDqC2VUjFTQmQX3rBWNW22iAIFCxOid53cpYAH9nqZKHAUVp8aICov9Jkzay Mj4LAE7GhCY0+HWajmcKgwGpDK4bIOTmynFXdUFJ6UKHLxvotyIIGC4jpo8wH3lpuheE Bxsw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1754422809; x=1755027609; 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=thXWESjgb/asehL5NdNra0dnr/Mi+exiNBPp9wa9z9w=; b=YQJVncKJFqWrcgofjsAb6tNVC0cgnN1t+WlEEqhrlPURfFeNjyuDihEkRD3re75kQz n2NLOUFxYXDs4587x7c1POQAYjjSL7vs4pO1xOWHZbBKACwu6cW/VLLbO6iMK0UKo+26 OhuNjX7zN5gbS/OwG6XdXvsYR8LqZZCwmW1iQyzdBiMnfDIpubXPo3W4Qus1Hbp83yMU c3XiuyrCGBxOSbBbmmx5+isK7DuU5vi8ss9or5ol/8++k/0ZiTlGWy70yndD2ck7QTQw ESpnIbHuW8JLcu2f2DRw8yTD81u8nBvnv/u93gfX03EVDgGlLvu7lwOK8rO4aBKN9fBQ +0AQ== X-Forwarded-Encrypted: i=1; AJvYcCVnk8h4SgzSbBjZMVgaNxY9JMxQPMeFaIb1B7ia1/ZBxx+w/o4ZqDYnh64whqqYgObOQgSy1ts3AbXHJzI=@vger.kernel.org X-Gm-Message-State: AOJu0Yww4ajsGNmbMaXa47/O8O3MN6Ac7gyOOIt5/6RZSlgxYk49o+8x Cj1thqBvKmhYnbQLIqo6tePuu6cCdXOg+9fCan3LXab4dAGxe2EumpJisoVAF2ECfvU= X-Gm-Gg: ASbGnctehlJ8QsMvS8CzO0gwxTznRw6Mj96UItMLFYkCxa4s3+omh+miKUVs8RNWTn3 f4NgtI6W/kOe9NgssF9ek1rbUtX9xeyemJTMrb02/4WWbBMMf8qh3wZYLkvtiymrWL35enDFZ5M 6uoHvd2TGeigDscJ4FeRZPmvoqdIiYtf/UqlhDHmLVqDwOPDwa853FBk6UQWDv2eeK7bDAW/5rt ORgX/Pwtte3JvuDqTCzd2Ohsr2B70GoLHWCpfzAhhw+PZ/Q94m+dKK8HBlJcgsDAnuCU5wvjnb7 pxDrQfEhSoQe9xQrv9Ig93kOfjFA3IY0NFyQU2zO1oll3RGvJQ/Q+7Tc9WRKcGn4suGiBVd0B2A QoBBQBa5UaQ6o3R1y/bucFcoiAXpzcc7Q21V95n4YTWIdKviKJcyFsmY0jRme5WcyBB6Q28rC5w uVXtRq1QyoJSNWLZbZ X-Google-Smtp-Source: AGHT+IHrWQTDjfjzvi15pRX0IO+g2I3D2NOE+Jn4xNMsUSUmEfPtUaNSg147K8LghQ8X7ApzfEv/sg== X-Received: by 2002:a05:620a:15a5:b0:7e6:8147:e683 with SMTP id af79cd13be357-7e814e1cd24mr62137585a.47.1754422809200; Tue, 05 Aug 2025 12:40:09 -0700 (PDT) Received: from jesse-lt.jtp-bos.lab (pool-108-26-215-125.bstnma.fios.verizon.net. [108.26.215.125]) by smtp.gmail.com with ESMTPSA id af79cd13be357-7e67f7064b0sm717855685a.54.2025.08.05.12.40.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 Aug 2025 12:40:08 -0700 (PDT) From: Jesse Taube To: linux-riscv@lists.infradead.org Cc: Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Oleg Nesterov , Kees Cook , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , "Liang, Kan" , Shuah Khan , Jesse Taube , Himanshu Chauhan , Charlie Jenkins , Samuel Holland , Conor Dooley , Deepak Gupta , Andrew Jones , Atish Patra , Anup Patel , Mayuresh Chitale , Evan Green , WangYuli , Huacai Chen , Arnd Bergmann , Andrew Morton , Luis Chamberlain , "Mike Rapoport (Microsoft)" , Nam Cao , Yunhui Cui , Joel Granados , =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= , Sebastian Andrzej Siewior , Celeste Liu , Chunyan Zhang , Nylon Chen , Thomas Gleixner , =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= , Vincenzo Frascino , Joey Gouly , Akihiko Odaki , Ravi Bangoria , linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-perf-users@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH 5/8] riscv: hw_breakpoint: Use icount for single stepping Date: Tue, 5 Aug 2025 12:39:52 -0700 Message-ID: <20250805193955.798277-6-jesse@rivosinc.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250805193955.798277-1-jesse@rivosinc.com> References: <20250805193955.798277-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 --- OpenSBI implementation of sbi_debug_read_triggers does not return the updated CSR values. There needs to be a check for working sbi_debug_read_triggers before this works. https://lists.riscv.org/g/tech-prs/message/1476 RFC -> V1: - Add dbtr_mode to rv_init_icount_trigger - Add icount_triggered to check which breakpoint was triggered - Fix typo: s/affects/effects - Move HW_BREAKPOINT_COMPUTE_STEP to Platform type --- arch/riscv/Kconfig | 11 ++ arch/riscv/kernel/hw_breakpoint.c | 179 +++++++++++++++++++++++++++--- 2 files changed, 172 insertions(+), 18 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index fd8b62cdc6f5..37f01ed199f3 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -546,6 +546,17 @@ config RISCV_COMBO_SPINLOCKS =20 endchoice =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 effects when reading the instruction from memory. + + If unsure, say N. + config RISCV_ALTERNATIVE bool depends on !XIP_KERNEL diff --git a/arch/riscv/kernel/hw_breakpoint.c b/arch/riscv/kernel/hw_break= point.c index 3f96e744a711..1e70ef9e6867 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) @@ -62,6 +63,14 @@ (FIELD_PREP(DBTR_TDATA1_MCONTROL_SIZELO_FIELD, lo) | \ FIELD_PREP(DBTR_TDATA1_MCONTROL_SIZEHI_FIELD, hi)) =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) + enum dbtr_mode { DBTR_MODE_U =3D 0, DBTR_MODE_S, @@ -79,6 +88,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 @@ -129,6 +139,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. @@ -143,6 +154,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) { @@ -151,7 +181,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; } @@ -166,7 +196,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; } } @@ -320,6 +350,36 @@ 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, enum dbtr= _mode mode) +{ + unsigned long tdata1 =3D DBTR_TDATA1_TYPE_ICOUNT; + + /* Step one instruction */ + tdata1 |=3D FIELD_PREP(DBTR_TDATA1_ICOUNT_COUNT_FIELD, 1); + + switch (mode) { + case DBTR_MODE_U: + tdata1 |=3D DBTR_TDATA1_ICOUNT_U; + break; + case DBTR_MODE_S: + tdata1 |=3D DBTR_TDATA1_ICOUNT_S; + break; + case DBTR_MODE_VS: + tdata1 |=3D DBTR_TDATA1_ICOUNT_VS; + break; + case DBTR_MODE_VU: + tdata1 |=3D DBTR_TDATA1_ICOUNT_VU; + break; + default: + return -EINVAL; + } + + 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) @@ -372,24 +432,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_nofault(regs, regs->epc, &insn); - if (ret < 0) - return ret; + if (have_icount) { + rv_init_icount_trigger(bp, DBTR_MODE_U); + } else { + ret =3D get_insn_nofault(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_nofault(regs, next_addr, &insn); - if (ret < 0) - return ret; + ret =3D get_insn_nofault(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) @@ -400,6 +464,79 @@ static int setup_singlestep(struct perf_event *event, = struct pt_regs *regs) return 0; } =20 +/** + * icount_triggered - Check if event's icount was triggered. + * @event: Perf event to check + * + * Check the given perf event's icount breakpoint was triggered. + * + * Returns: 1 if icount was triggered. + * 0 if icount was not triggered. + * negative on failure. + */ +static int icount_triggered(struct perf_event *event) +{ + union sbi_dbtr_shmem_entry *shmem =3D this_cpu_ptr(&sbi_dbtr_shmem); + struct sbiret ret; + struct perf_event **slot; + unsigned long tdata1; + 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("%s: Breakpoint not installed.\n", __func__); + return -ENOENT; + } + + 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, + i, 1, 0, 0, 0, 0); + tdata1 =3D shmem->data.tdata1; + + raw_spin_unlock_irqrestore(this_cpu_ptr(&ecall_lock), + *this_cpu_ptr(&ecall_lock_flags)); + if (ret.error) { + pr_warn("%s: failed to read trigger. error: %ld\n", __func__, ret.error); + return sbi_err_map_linux_errno(ret.error); + } + + /* + * The RISC-V Debug Specification + * Tim Newsome, Paul Donahue (Ventana Micro Systems) + * Version 1.0, Revised 2025-02-21: Ratified + * 5.7.13. Instruction Count (icount, at 0x7a1) + * When count is 1 and the trigger matches, then pending becomes set. + * In addition count will become 0 unless it is hard-wired to 1. + * When pending is set, the trigger fires just before any further + * instructions are executed in a mode where the trigger is enabled. + * As the trigger fires, pending is cleared. In addition, if count is + * hard-wired to 1 then m, s, u, vs, and vu are all cleared. + */ + if (FIELD_GET(DBTR_TDATA1_ICOUNT_COUNT_FIELD, tdata1) =3D=3D 0) + return 1; + + if (FIELD_GET(DBTR_TDATA1_ICOUNT_COUNT_FIELD, tdata1) !=3D 1) + return 0; + + if (tdata1 & DBTR_TDATA1_ICOUNT_U) + return 0; + if (tdata1 & DBTR_TDATA1_ICOUNT_S) + return 0; + if (tdata1 & DBTR_TDATA1_ICOUNT_VU) + return 0; + if (tdata1 & DBTR_TDATA1_ICOUNT_VU) + return 0; + return 1; +} + /* * HW Breakpoint/watchpoint handler */ @@ -460,7 +597,10 @@ static int hw_breakpoint_handler(struct pt_regs *regs) =20 if (bp->in_callback) { expecting_callback =3D true; - if (regs->epc !=3D bp->next_addr) { + if (have_icount) { + if (icount_triggered(event) !=3D 1) + continue; + } else if (regs->epc !=3D bp->next_addr) { continue; } =20 @@ -477,7 +617,10 @@ static int hw_breakpoint_handler(struct pt_regs *regs) =20 } =20 - if (expecting_callback) { + if (expecting_callback && have_icount) { + pr_err("%s: in_callback was set, but icount was not triggered, epc (%lx)= .\n", + __func__, regs->epc); + } else if (expecting_callback) { pr_err("%s: in_callback was set, but epc (%lx) was not at next address(%= lx).\n", __func__, regs->epc, bp->next_addr); } --=20 2.43.0 From nobody Sun Oct 5 10:49:02 2025 Received: from mail-qk1-f181.google.com (mail-qk1-f181.google.com [209.85.222.181]) (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 7DD3329ACCD for ; Tue, 5 Aug 2025 19:40:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754422814; cv=none; b=gt9HczJvK97peCUbEJOBHgPs39ue+lreUHMDvu9rb5ZHqYPWsszV6oja+GgjgQdgTklqrPq7jumbCRHElitvbKLo7Q4b5EeMYYIkNaIQm0ISeBt7YbK3CutjFSoD+Wu2g3nYxFN7NFDopFkqaC7Rn2I9M4VBWBB8+pK9wqXAqGs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754422814; c=relaxed/simple; bh=hOtHlwwaCunZLy54b11b3Gq48zk2xolvckSpC/bk7lE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=eCOZnqR6pyX3GdJwqnZ6MPxNE6xVWRbrROX9UXvXLWcv+du3Vx4u2EjPa9H0J/TPV4mwUM1wgzIMO4Vdp1FGQ3xZuWI6DzS1OTjpgoWfykYB4tpEd6qwWfq2VHl29ZUwsIYxlQI4E6rDlk1ZbcO9Klk4GrFefXySrX6ro5ge6FY= 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 header.i=@rivosinc.com header.b=d7cf2Dzx; arc=none smtp.client-ip=209.85.222.181 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 header.i=@rivosinc.com header.b="d7cf2Dzx" Received: by mail-qk1-f181.google.com with SMTP id af79cd13be357-7e811828b2fso88656685a.0 for ; Tue, 05 Aug 2025 12:40:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc.com; s=google; t=1754422811; x=1755027611; 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=5NaF/ZBQxTUv12deyQ9gwmEo84+EIUJjfCF9ZC+Wrs8=; b=d7cf2DzxC2/Wk/UIxCj6nt5CLuuRCzOgLeGyUQbAM+V7yK0TkVnS0/GVcXzvD3nJz6 2Wa+USeBQJaRZfKsqQf6XPxWqvMWsacJVidJL5WcPDMdrA4Iv6CdvWN1hjTrTmm4TDeR EB5yaeryvxHYRQ6iNJ17yhZuhqdxGBDpPNkUe0kl81abNwiyJbtRj6t4TzlCoPweM2mL sgHW41Y/h/IKns5C4smQ2j9Hx8z2ZQU0z5sbrPARE6gb1xQ5wLKektaEyM/tqe6UldMx dS8qNrtWhlgRsUU1qObc/0kcV+iZ6jOREtHN2RDrPSDCz4JO2NFdVOa662yIJSd77Lbw O4Bg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1754422811; x=1755027611; 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=5NaF/ZBQxTUv12deyQ9gwmEo84+EIUJjfCF9ZC+Wrs8=; b=g3XHd5AO/GWVks+B1h46xw7iQS4mK7hi4iF7Q3k2xCjBNrXMAECk2RHLEW6jj+faKH t3ppz36O3z7Ob017oYnXSqFTtTLsD4ZRy8WPBBMQrcoxxdRCgYxoeuVPg/ssin0HlH9X k0ojLA0f17eLVXoqCyr96AIwi/78ZI1YoESrCY27ikq6hAVNFNvj16xVse6h50Lb91pc ag8npha7yIqZnP0B5cMHGdrX0GkVa2j+loxXxb0GTyXKlqlYANr+LoQThwvWABqhjcWS f/EufmYRu8n0pCs2yHokGX6greeG3HQuQRIRxj3SEjm4wFPwknape2RaD0Fd0EmJ3k/w vg7A== X-Forwarded-Encrypted: i=1; AJvYcCXLn5lzDDHyYIE+ypPhdoX/pS+la9ktAliT2Al9qUWlL7UEHaVha1mazFJtrg9gsZIkyjEm5b5DMdVSu+A=@vger.kernel.org X-Gm-Message-State: AOJu0YzIK/2KbbUjO4vVWr/bnmIUWKaSIiQsxPl3goTGP5MHJWgBmqL9 B6pi2ftRTLOiYZ3U4CHorLtsqqMJGbFpIVywZTIinaqlryzd0ekZqjmp1NZroOPslQo= X-Gm-Gg: ASbGncvzE1EP6mIVJgha1Nfhpe4TLXP6ki1hvAyyG4vomO81uIvre5eO1mimL5nCmc9 ExF5cYiCiy3uJMQ4Wb6xMGJ4WSPUbi9VgqwswzDjWr7b+S4OdHATKkaISMxlthrwoM8ixttOXcS jDXXLIsB+noakp/icLHsnrNC9BduxCCMB5zj4/vkqKJy8kCOobHVHOtrpmxIZckPWRzj2CT73x/ djSr6LNQY6tsi0+SryRbxNW9wxQZJdJhLPW7NlJklxRE+Vt+xUkIdipontvnWIk+PtG/ddKHu5J RmtiO3OfC7amPt0Egc4PLJNtVTPUO0l4BJPSZjQgqi2US9poLKGgV58YlsJ/b0MzkIyqlbXUd1e oM44f0Kcl0YneDADl8kv61iuB/65CCIXOZplGWaNkVLyDhWbzAU4Q4G0Dw3fmxQYv0lZSTNM8i+ FX+dV9wg== X-Google-Smtp-Source: AGHT+IEiw5qn5MBLjumC4Tao3Un++oIx9bSGZnVNfPEZCF9kraUYTZzvHsq8Xt6WwLTbl66stoXsIA== X-Received: by 2002:a05:620a:4410:b0:7e6:2f06:aca5 with SMTP id af79cd13be357-7e814ef34d2mr82086785a.61.1754422811237; Tue, 05 Aug 2025 12:40:11 -0700 (PDT) Received: from jesse-lt.jtp-bos.lab (pool-108-26-215-125.bstnma.fios.verizon.net. [108.26.215.125]) by smtp.gmail.com with ESMTPSA id af79cd13be357-7e67f7064b0sm717855685a.54.2025.08.05.12.40.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 Aug 2025 12:40:10 -0700 (PDT) From: Jesse Taube To: linux-riscv@lists.infradead.org Cc: Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Oleg Nesterov , Kees Cook , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , "Liang, Kan" , Shuah Khan , Jesse Taube , Himanshu Chauhan , Charlie Jenkins , Samuel Holland , Conor Dooley , Deepak Gupta , Andrew Jones , Atish Patra , Anup Patel , Mayuresh Chitale , Evan Green , WangYuli , Huacai Chen , Arnd Bergmann , Andrew Morton , Luis Chamberlain , "Mike Rapoport (Microsoft)" , Nam Cao , Yunhui Cui , Joel Granados , =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= , Sebastian Andrzej Siewior , Celeste Liu , Chunyan Zhang , Nylon Chen , Thomas Gleixner , =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= , Vincenzo Frascino , Joey Gouly , Akihiko Odaki , Ravi Bangoria , linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-perf-users@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH 6/8] riscv: ptrace: Add hw breakpoint support Date: Tue, 5 Aug 2025 12:39:53 -0700 Message-ID: <20250805193955.798277-7-jesse@rivosinc.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250805193955.798277-1-jesse@rivosinc.com> References: <20250805193955.798277-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 __riscv_hwdebug_state which will be passed to ptrace. Signed-off-by: Jesse Taube --- RFC -> V1: - Add struct __riscv_hwdebug_state for ptrace_hbp_set/get - Break out ptrace_hbp_set/get so regset can use them - Check for NULL instead of IS_ERR_OR_NULL - Move ptrace_get/sethbpregs above user_regset --- arch/riscv/include/asm/processor.h | 4 + arch/riscv/include/uapi/asm/ptrace.h | 9 +++ arch/riscv/kernel/hw_breakpoint.c | 14 +++- arch/riscv/kernel/process.c | 4 + arch/riscv/kernel/ptrace.c | 110 +++++++++++++++++++++++++++ 5 files changed, 140 insertions(+), 1 deletion(-) 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..20d1aa595cbd 100644 --- a/arch/riscv/include/uapi/asm/ptrace.h +++ b/arch/riscv/include/uapi/asm/ptrace.h @@ -14,6 +14,8 @@ =20 #define PTRACE_GETFDPIC_EXEC 0 #define PTRACE_GETFDPIC_INTERP 1 +#define PTRACE_GETHBPREGS 2 +#define PTRACE_SETHBPREGS 3 =20 /* * User-mode register state for core dumps, ptrace, sigcontext @@ -120,6 +122,13 @@ struct __riscv_v_regset_state { char vreg[]; }; =20 +struct __riscv_hwdebug_state { + unsigned long addr; + unsigned long type; + unsigned long len; + unsigned long ctrl; +} __packed; + /* * According to spec: The number of bits in a single vector register, * VLEN >=3D ELEN, which must be a power of 2, and must be no greater than diff --git a/arch/riscv/kernel/hw_breakpoint.c b/arch/riscv/kernel/hw_break= point.c index 1e70ef9e6867..b1c9c40f5fde 100644 --- a/arch/riscv/kernel/hw_breakpoint.c +++ b/arch/riscv/kernel/hw_breakpoint.c @@ -721,7 +721,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..e097e6a61910 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 @@ -184,6 +186,104 @@ static int tagged_addr_ctrl_set(struct task_struct *t= arget, } #endif =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); +} + +static int ptrace_hbp_get(struct task_struct *child, unsigned long idx, + struct __riscv_hwdebug_state *state) +{ + struct perf_event *bp; + + if (idx >=3D RV_MAX_TRIGGERS) + 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 ptrace_hbp_set(struct task_struct *child, unsigned long idx, + struct __riscv_hwdebug_state *state) +{ + struct perf_event *bp; + struct perf_event_attr attr; + + if (idx >=3D RV_MAX_TRIGGERS) + 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; + attr.disabled =3D state->ctrl =3D=3D 1; + + if (!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; + } + + return modify_user_hw_breakpoint(bp, &attr); +} + +/* + * idx selects the breakpoint index. + * Both PTRACE_GETHBPREGS and PTRACE_SETHBPREGS transfer __riscv_hwdebug_s= tate + */ + +static long ptrace_gethbpregs(struct task_struct *child, unsigned long idx, + unsigned long __user *datap) +{ + struct __riscv_hwdebug_state state; + long ret; + + ret =3D ptrace_hbp_get(child, idx, &state); + if (ret) + return ret; + if (copy_to_user(datap, &state, sizeof(state))) + return -EFAULT; + + return 0; +} + +static long ptrace_sethbpregs(struct task_struct *child, unsigned long idx, + unsigned long __user *datap) +{ + struct __riscv_hwdebug_state state; + + if (copy_from_user(&state, datap, sizeof(state))) + return -EFAULT; + + return ptrace_hbp_set(child, idx, &state); + +} +#endif + static const struct user_regset riscv_user_regset[] =3D { [REGSET_X] =3D { .core_note_type =3D NT_PRSTATUS, @@ -340,8 +440,18 @@ long arch_ptrace(struct task_struct *child, long reque= st, 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 From nobody Sun Oct 5 10:49:02 2025 Received: from mail-qk1-f171.google.com (mail-qk1-f171.google.com [209.85.222.171]) (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 AD8E729B205 for ; Tue, 5 Aug 2025 19:40:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754422816; cv=none; b=dX1oHWQjMfhkSxplfjdHaEQm3abxhz55r4HQyBDh/pJZjI1BinYqvJIK6Gu5HexiKw/bsQ5BdSY9XrS0FyP058iavQ9X78vv6NWX/5c7iw/gt0HWPbwbq1e6ZJ8s9rxPpinu169bas2XdaTBRYktbuUROjV9vzh7B7IT9iGMVSE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754422816; c=relaxed/simple; bh=pH8wkOotqE0cBRSa0KbFERwDeYY+i5YxpVrEk0g2r9Q=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=sS0sqdVbszaT6QOIMwBEZyiniBQs56BuFfzhuyQLq/s83nuwtQEL8hNP6UKqnrKOPidB4MGxS7fmX6yfrGphxBVdnWwcS6SrpgcXrra1wLYZeordu+E2s45XLwahQ2nL1XOJeHqYWFfKWzIDRNZ4prT3A488ohp3cexYIhoOujQ= 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 header.i=@rivosinc.com header.b=Ydz0xc1k; arc=none smtp.client-ip=209.85.222.171 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 header.i=@rivosinc.com header.b="Ydz0xc1k" Received: by mail-qk1-f171.google.com with SMTP id af79cd13be357-7e6696eb47bso638101385a.3 for ; Tue, 05 Aug 2025 12:40:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc.com; s=google; t=1754422813; x=1755027613; 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=sy5rnGanwjtyLCbaD47CPjt7MxkuRZTNweHSGmibXvc=; b=Ydz0xc1kVfwyk/Z1z9QVrki0bvBb5DgxXoTDaHCYynsiWLWNvxPmTUWpc5qPGGyFvL Fkp61IGRhiVMOXo/bmiUJhou6fskdA+m+HYqjMrVJVkOcw+dUXrsmaCboCnzMHOUCsrT j6tf4TnCWyjzvqMhK8AWk6hBwyz4xeEF9QuInHuOW08WkylCX2D14PE5Yrww0OvvPgwK 4pcr4WvOZEMD328I7o+0vc3wuhybCa5gLmdfD7O39GhWCx5HmAwvTtZcrj7R+wPLiCHg 75eB3UKUoBWGCAxOhmix3X9WBJf+jd9vBoHsQlJs2p4I8TWO6Mc+32sq9d5RFeA3A1HD ytig== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1754422813; x=1755027613; 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=sy5rnGanwjtyLCbaD47CPjt7MxkuRZTNweHSGmibXvc=; b=f0F/T8K0Al/7JZP3dsNGnwj4whmykwDd4CiNsLtoXSWDSvEjKK0CRE08h/+sJekvzU 2rfZAO32YLZLw9VyzqTarOQthQsSbOPewqPNnIouGgE1TmfSYzfYgakRAGtTB4B2YMf9 5EhYSub9cXimpgflxRK2yBkf5y2IwtQtXWw82b+uBkuvBMbZvEzhFMTRddHzRFlPZUXR 5JVj3tTNo5Wvj2plwyqlg63m7V9j3vlH5kXfWBfykX59gh6PeyXy2YhFvSn2xPXX0iTF gH0Dd529/9cT3sKz1LqVKnceXnp/zl6xYc2CwSZfcNOCUc9hkiWGrJZlh4a+/jzS12NP spmQ== X-Forwarded-Encrypted: i=1; AJvYcCVMVNwWl+TW5gr8gPly+YdxV35FDtk2/CXhmhxEAdHUkoQLfZ0TfIY62/J1FC+g7hq25GyA4opm3xBB+CU=@vger.kernel.org X-Gm-Message-State: AOJu0YysEVNHKGVwVCs2yx0qipRtylT/1B16NNmmpZi13igI2z0VFIHZ auUESvPla5JsvpEONz1HupYGhPjIiMPsl7TX1UhvEN7HfyEItoV68+VCrZCWJAnYO/8= X-Gm-Gg: ASbGncttGuK6CP7GiKO4znjyO5cKn+N2IViDRY2Rp9zr415dchxH3201qLiRYtc8+Po BwJIpofaYXuf7Ss2hEq/A7gqsVTmznhxqhC5AUWI39f3BLtZxRT2qNrZakv+G8Urg2BYENWLNyB 9zgrjhNjPx09hXurl9ZEtsHvH92NGAY8PdcikrEnmrgMVnk42kh8dByxh7TF8952Hq/ZfoRdBAK COuS0LL9V0+X2pcEMw47DARvWPxSBXCnCgwKhWV2fULwJpxA1kAY8O4RCqoU3HX71N+3ugeOtbm CqXOr+qeZrUPyZ//uiq3+g1TPzWytVgGgfWmTn801t3X8hoEyNpuIT3x6jc7peYDjiBa7MWwcw0 812QkMCQ5A0VhGiaBYnstDC3/8ZYsTn2wzLRsmxRQneKUUKUKw55uI/tv11YYbdkjoWOrgVruF6 bWW2Vu0Q== X-Google-Smtp-Source: AGHT+IG6XA8VhHC/9Z5t7TyajoGN/5DDGuOO01JZMGKppPhvnVQsp/F8STKyDdgm3AlZG+FdD4n6KA== X-Received: by 2002:a05:620a:1707:b0:7e8:15b2:3f20 with SMTP id af79cd13be357-7e815b24106mr5235285a.1.1754422813351; Tue, 05 Aug 2025 12:40:13 -0700 (PDT) Received: from jesse-lt.jtp-bos.lab (pool-108-26-215-125.bstnma.fios.verizon.net. [108.26.215.125]) by smtp.gmail.com with ESMTPSA id af79cd13be357-7e67f7064b0sm717855685a.54.2025.08.05.12.40.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 Aug 2025 12:40:13 -0700 (PDT) From: Jesse Taube To: linux-riscv@lists.infradead.org Cc: Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Oleg Nesterov , Kees Cook , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , "Liang, Kan" , Shuah Khan , Jesse Taube , Himanshu Chauhan , Charlie Jenkins , Samuel Holland , Conor Dooley , Deepak Gupta , Andrew Jones , Atish Patra , Anup Patel , Mayuresh Chitale , Evan Green , WangYuli , Huacai Chen , Arnd Bergmann , Andrew Morton , Luis Chamberlain , "Mike Rapoport (Microsoft)" , Nam Cao , Yunhui Cui , Joel Granados , =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= , Sebastian Andrzej Siewior , Celeste Liu , Chunyan Zhang , Nylon Chen , Thomas Gleixner , =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= , Vincenzo Frascino , Joey Gouly , Akihiko Odaki , Ravi Bangoria , linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-perf-users@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH 7/8] riscv: ptrace: Add hw breakpoint regset Date: Tue, 5 Aug 2025 12:39:54 -0700 Message-ID: <20250805193955.798277-8-jesse@rivosinc.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250805193955.798277-1-jesse@rivosinc.com> References: <20250805193955.798277-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 using REGSET use the __riscv_hwdebug_state structure to configure breakpoints. Signed-off-by: Jesse Taube --- RFC -> V1: - New commit --- arch/riscv/kernel/ptrace.c | 59 ++++++++++++++++++++++++++++++++++ include/uapi/linux/elf.h | 2 ++ tools/include/uapi/linux/elf.h | 1 + 3 files changed, 62 insertions(+) diff --git a/arch/riscv/kernel/ptrace.c b/arch/riscv/kernel/ptrace.c index e097e6a61910..fbd0097ec168 100644 --- a/arch/riscv/kernel/ptrace.c +++ b/arch/riscv/kernel/ptrace.c @@ -33,6 +33,9 @@ enum riscv_regset { #ifdef CONFIG_RISCV_ISA_SUPM REGSET_TAGGED_ADDR_CTRL, #endif +#ifdef CONFIG_HAVE_HW_BREAKPOINT + REGSET_HW_BREAK +#endif }; =20 static int riscv_gpr_get(struct task_struct *target, @@ -280,7 +283,53 @@ static long ptrace_sethbpregs(struct task_struct *chil= d, unsigned long idx, return -EFAULT; =20 return ptrace_hbp_set(child, idx, &state); +} =20 +static int 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) +{ + struct __riscv_hwdebug_state state; + int ret, idx, offset, limit; + + idx =3D offset =3D 0; + limit =3D regset->n * regset->size; + while (count && offset < limit) { + if (count < sizeof(state)) + return -EINVAL; + + ret =3D user_regset_copyin(&pos, &count, &kbuf, &ubuf, &state, + offset, offset + sizeof(state)); + if (ret) + return ret; + ret =3D ptrace_hbp_set(target, idx, &state); + if (ret) + return ret; + offset +=3D sizeof(state); + idx++; + } + + return 0; +} + +static int hw_break_get(struct task_struct *target, + const struct user_regset *regset, + struct membuf to) +{ + int ret, idx =3D 0; + struct __riscv_hwdebug_state state; + + while (to.left) { + ret =3D ptrace_hbp_get(target, idx, &state); + if (ret) + return ret; + + membuf_write(&to, &state, sizeof(state)); + idx++; + } + + return 0; } #endif =20 @@ -324,6 +373,16 @@ static const struct user_regset riscv_user_regset[] = =3D { .set =3D tagged_addr_ctrl_set, }, #endif +#ifdef CONFIG_HAVE_HW_BREAKPOINT + [REGSET_HW_BREAK] =3D { + .core_note_type =3D NT_RISCV_HW_BREAK, + .n =3D sizeof(struct __riscv_hwdebug_state) / sizeof(unsigned long), + .size =3D sizeof(unsigned long), + .align =3D sizeof(unsigned long), + .regset_get =3D hw_break_get, + .set =3D hw_break_set, + }, +#endif }; =20 static const struct user_regset_view riscv_user_native_view =3D { diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h index 819ded2d39de..7a32073e0d68 100644 --- a/include/uapi/linux/elf.h +++ b/include/uapi/linux/elf.h @@ -545,6 +545,8 @@ typedef struct elf64_shdr { #define NT_RISCV_VECTOR 0x901 /* RISC-V vector registers */ #define NN_RISCV_TAGGED_ADDR_CTRL "LINUX" #define NT_RISCV_TAGGED_ADDR_CTRL 0x902 /* RISC-V tagged address control (= prctl()) */ +#define NN_RISCV_HW_BREAK "LINUX" +#define NT_RISCV_HW_BREAK 0x903 /* RISC-V hardware breakpoint 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..b5f35df1de7a 100644 --- a/tools/include/uapi/linux/elf.h +++ b/tools/include/uapi/linux/elf.h @@ -460,6 +460,7 @@ 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 0x903 /* RISC-V hardware breakpoint registers */ #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 Sun Oct 5 10:49:02 2025 Received: from mail-qk1-f172.google.com (mail-qk1-f172.google.com [209.85.222.172]) (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 8647229B778 for ; Tue, 5 Aug 2025 19:40:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754422818; cv=none; b=cu4YqUrOrkc6Xszszew/craiJ7e5nVuIp2ItHpYIKk4iLbfyTKoYf3Gwmz1I02oayc2NMDvWwVROcSaz+xZ+ltJ3WxFpIjCrQjkegn6v5Ysx5Js/itFOGsx5qYeH1aW6TvdpeC/9IYAnOZWOF4mKdE19CHiO/1UXTQ/6numaxj8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754422818; c=relaxed/simple; bh=j9sA+czqcz4x2GiB5kLwvA3PNWQyMhglgRj2XPvLFd8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=o+F3xGu04OPbKDy7QhWwZEmczFjQyPTcABSlmkpjF9OwbGaLqdIiWaS15yInyo+Tu3SyECps46FkZhu0Yf07+0lhFG5F5Ph6us40A3LHMzhy1ZFnB7H1R1dNZLyu2TKYsZ9UbxErIj9llxx/EKmCUOsKLyh+QwQzBxL0TkrQrgo= 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 header.i=@rivosinc.com header.b=YT9bdN96; arc=none smtp.client-ip=209.85.222.172 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 header.i=@rivosinc.com header.b="YT9bdN96" Received: by mail-qk1-f172.google.com with SMTP id af79cd13be357-7e7f940a386so172013385a.3 for ; Tue, 05 Aug 2025 12:40:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc.com; s=google; t=1754422815; x=1755027615; 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=vL4PFY0aOH8JnUAWFk8/IxlbUSq0aZKvwKplwC4IJQE=; b=YT9bdN96HLbIq3OSizYKnH9RR9KU9Pc90B57lo+5HgCQmdyCrelUUTIuPnlSWtv2Y9 Al11D7/I31VU9siNwTJFDb+qRGyEVKE6Y44rZJsiOqbbgAqEsKtQkuYMIDU9boW15z3b eZHFYXxHIyMPxHTyTYhAZlKdvgINC0EfUu/8TtZjsIFkd2xfIhjGElNB+cOzM+pwWRDX X84E56Z7104NiM7PkkXT6ji2LB7uwXSWo02YEVMcJEZq1oTWYRm89/Z0lc5L6Wq7LHEe +tqyrlLJfXeq6z8ezh4lFXORhHRVt4eRXoqi42x0b9fucOoyUU3jV8G150F3prlaR8XE y+BA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1754422815; x=1755027615; 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=vL4PFY0aOH8JnUAWFk8/IxlbUSq0aZKvwKplwC4IJQE=; b=ebY1Z/gHHPDQGRLpUnqfZcOgHhA6NznGX02xQnOMlF1/BeiNwmFVFBIJy14h7yLUDY E0eb1KWSGelFy69vhmewLhLMH3s7zLK3nZw+OnWrhwQj/svKTv6R0D5XBNDIQVy21ygW UykMUuidF6OwVTVn2Cflo6OTmjcorihRAo0boJNSisqa1UIAsMpeEt/KSQy9fbXpyg9Z WoM1ckv5XvPX3QQmkP1Bziw0XVd3/9qK0ec5kb9gQT/aj4upBqUX57mtPvhX9F/jXhmt kOnL5HO4F6GNmvJDNiLgq8LostptXjEB/58j2gEZiwKT1soDVMp7xe6DzmC183Ve0Kq1 VCmg== X-Forwarded-Encrypted: i=1; AJvYcCW+7zP9eD05cfXS3FtfsVjSjxyA0QyArAn5KQFxRXb3BqwypSUsaCVrTKEl4b0MGtt6mXe/1+ENLGpdqeo=@vger.kernel.org X-Gm-Message-State: AOJu0YyYjbL64S1UJHPjoGt2U4TTwWI4b1DSM6eQ5vYcGVz5u/5BXtc2 a4DhHdkrhGSAjaBwF613gvf83p4J5qYkPPgIMD0HmxkLaf2CA9s31uQONQBQQ4CUzWI= X-Gm-Gg: ASbGncsKsaLSIojrv5bTHIdYtwF8T3u6X3B/KQn1HDtkLj+LdrWHN0LNWW/DNwqqJsV 4lMuE+X3JqDer72zyKyHQyZS9G2s79xKQeT54LR2jd7rk03NQk8eJGDZaVvZI8CWLYMVIAg4ynX ilgomrnacQed+LqLfBgpW84W5N9gLAc0JnMttUU4ScAZT+WJdmGqZ3dASogcia11BXORdNlR60M q8IODkhs1vrzG2YiLhJkiBy4th6k5HQNuTW/Gw38Y56ugi9N+7LOLdbVH6kFFkUzqWo8ke1Q9GT EkjYYaMbAonAtdDmt5YRGpgJH8/sWcM4bleadOLA3YhO6zui67tygw0e6AMW1ubLmyHUweY4/T5 kDYaTLzJC/cR6wABo10Y0xEFYeIqdfTvgD0/QJXg6jBc2AyEmx3p2TTnL61r/PdDFj80Bu1w5P2 I9Z6oRfZaedeYPEuet X-Google-Smtp-Source: AGHT+IGXS15aibedECz6CkDF0iaK6CSzoEd5PRNEgnuhiSDuN9qkS/vQpcn9djWvm2zxOAxHWnrvxg== X-Received: by 2002:a05:620a:aa09:b0:7e6:969e:c54 with SMTP id af79cd13be357-7e814e175f0mr73691085a.63.1754422815267; Tue, 05 Aug 2025 12:40:15 -0700 (PDT) Received: from jesse-lt.jtp-bos.lab (pool-108-26-215-125.bstnma.fios.verizon.net. [108.26.215.125]) by smtp.gmail.com with ESMTPSA id af79cd13be357-7e67f7064b0sm717855685a.54.2025.08.05.12.40.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 Aug 2025 12:40:15 -0700 (PDT) From: Jesse Taube To: linux-riscv@lists.infradead.org Cc: Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Oleg Nesterov , Kees Cook , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , "Liang, Kan" , Shuah Khan , Jesse Taube , Himanshu Chauhan , Charlie Jenkins , Samuel Holland , Conor Dooley , Deepak Gupta , Andrew Jones , Atish Patra , Anup Patel , Mayuresh Chitale , Evan Green , WangYuli , Huacai Chen , Arnd Bergmann , Andrew Morton , Luis Chamberlain , "Mike Rapoport (Microsoft)" , Nam Cao , Yunhui Cui , Joel Granados , =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= , Sebastian Andrzej Siewior , Celeste Liu , Chunyan Zhang , Nylon Chen , Thomas Gleixner , =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= , Vincenzo Frascino , Joey Gouly , Akihiko Odaki , Ravi Bangoria , linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-perf-users@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH 8/8] selftests: riscv: Add test for hardware breakpoints Date: Tue, 5 Aug 2025 12:39:55 -0700 Message-ID: <20250805193955.798277-9-jesse@rivosinc.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250805193955.798277-1-jesse@rivosinc.com> References: <20250805193955.798277-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 riscv specific selftest for hardhardware breakpoints. These tests are based on: tools/testing/selftests/breakpoints/breakpoint_test_arm64.c Signed-off-by: Jesse Taube --- The selftest fails as register_user_hw_breakpoint seemingly does not call arch_install_hw_breakpoint. The test also seems to fail on arm64 in the same way when I tested it. RFC -> V1: - New commit --- tools/perf/tests/tests.h | 3 +- tools/testing/selftests/riscv/Makefile | 2 +- .../selftests/riscv/breakpoints/.gitignore | 1 + .../selftests/riscv/breakpoints/Makefile | 12 + .../riscv/breakpoints/breakpoint_test.c | 246 ++++++++++++++++++ 5 files changed, 262 insertions(+), 2 deletions(-) create mode 100644 tools/testing/selftests/riscv/breakpoints/.gitignore create mode 100644 tools/testing/selftests/riscv/breakpoints/Makefile create mode 100644 tools/testing/selftests/riscv/breakpoints/breakpoint_te= st.c diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index 8aea344536b8..5ff35304c11a 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -183,7 +183,8 @@ DECLARE_SUITE(util); * Just disable the test for these architectures until these issues are * resolved. */ -#if defined(__powerpc__) || defined(__s390x__) || defined(__arm__) || defi= ned(__aarch64__) +#if defined(__powerpc__) || defined(__s390x__) || defined(__arm__) || defi= ned(__aarch64__) || \ + defined(__riscv) #define BP_SIGNAL_IS_SUPPORTED 0 #else #define BP_SIGNAL_IS_SUPPORTED 1 diff --git a/tools/testing/selftests/riscv/Makefile b/tools/testing/selftes= ts/riscv/Makefile index 099b8c1f46f8..96aba246cb3e 100644 --- a/tools/testing/selftests/riscv/Makefile +++ b/tools/testing/selftests/riscv/Makefile @@ -5,7 +5,7 @@ ARCH ?=3D $(shell uname -m 2>/dev/null || echo not) =20 ifneq (,$(filter $(ARCH),riscv)) -RISCV_SUBTARGETS ?=3D abi hwprobe mm sigreturn vector +RISCV_SUBTARGETS ?=3D abi hwprobe mm sigreturn vector breakpoints else RISCV_SUBTARGETS :=3D endif diff --git a/tools/testing/selftests/riscv/breakpoints/.gitignore b/tools/t= esting/selftests/riscv/breakpoints/.gitignore new file mode 100644 index 000000000000..9b3193d06608 --- /dev/null +++ b/tools/testing/selftests/riscv/breakpoints/.gitignore @@ -0,0 +1 @@ +breakpoint_test diff --git a/tools/testing/selftests/riscv/breakpoints/Makefile b/tools/tes= ting/selftests/riscv/breakpoints/Makefile new file mode 100644 index 000000000000..91e1c02c0073 --- /dev/null +++ b/tools/testing/selftests/riscv/breakpoints/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2021 ARM Limited +# Originally tools/testing/arm64/abi/Makefile + +CFLAGS +=3D -I$(top_srcdir)/tools/include + +TEST_GEN_PROGS :=3D breakpoint_test + +include ../../lib.mk + +$(OUTPUT)/breakpoint_test: breakpoint_test.c + $(CC) -static -o$@ $(CFLAGS) $(LDFLAGS) $^ diff --git a/tools/testing/selftests/riscv/breakpoints/breakpoint_test.c b/= tools/testing/selftests/riscv/breakpoints/breakpoint_test.c new file mode 100644 index 000000000000..faeecc72da12 --- /dev/null +++ b/tools/testing/selftests/riscv/breakpoints/breakpoint_test.c @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2016 Google, Inc. + * + * Original Code by Pavel Labath + * + * Code modified by Pratyush Anand + * for testing different byte select for each access size. + * Originally tools/testing/selftests/breakpoints/breakpoint_test_arm64.c + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../kselftest.h" + +#define MAX_BP_SIZE 8 + +static volatile uint8_t var[3*MAX_BP_SIZE] __attribute__((__aligned__(MAX_= BP_SIZE))); + +static void child(int size, int wr) +{ + volatile uint8_t *addr =3D &var[MAX_BP_SIZE + wr]; + + 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); + } + + if ((uintptr_t) addr % size) { + ksft_print_msg( + "Wrong address write for the given size: %s\n", + strerror(errno)); + _exit(1); + } + + switch (size) { + case 1: + *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; + } + + _exit(0); +} + +static bool set_watchpoint(pid_t pid, int size, int wp) +{ + const volatile uint8_t *addr =3D &var[MAX_BP_SIZE + wp]; + const int offset =3D (uintptr_t)addr % 8; + const unsigned int type =3D 2; /* Write */ + const unsigned int enable =3D 1; + struct __riscv_hwdebug_state debug_state; + struct iovec iov; + + memset(&debug_state, 0, sizeof(debug_state)); + debug_state.addr =3D (uintptr_t)(addr - offset); + debug_state.len =3D size; + debug_state.ctrl =3D enable; + debug_state.type =3D type; + iov.iov_base =3D &debug_state; + iov.iov_len =3D sizeof(debug_state); + 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 on this hard= ware: %s\n", + strerror(errno)); + + ksft_print_msg( + "ptrace(PTRACE_SETREGSET, NT_RISCV_HW_BREAK) failed: %s\n", + strerror(errno)); + return false; +} + +static bool run_test(int wr_size, int wp_size, int wr, int wp) +{ + int status; + siginfo_t siginfo; + pid_t pid =3D fork(); + pid_t wpid; + + if (pid < 0) { + ksft_test_result_fail( + "fork() failed: %s\n", strerror(errno)); + return false; + } + if (pid =3D=3D 0) + child(wr_size, wr); + + 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, wp_size, wp)) + 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; + } + return true; +} + +static void sigalrm(int sig) +{ +} + +int main(int argc, char **argv) +{ + int opt; + bool succeeded =3D true; + struct sigaction act; + int wr, wp, size; + bool result; + + ksft_print_header(); + ksft_set_plan(213); + + act.sa_handler =3D sigalrm; + sigemptyset(&act.sa_mask); + act.sa_flags =3D 0; + sigaction(SIGALRM, &act, NULL); + for (size =3D 1; size <=3D MAX_BP_SIZE; size =3D size*2) { + for (wr =3D 0; wr <=3D MAX_BP_SIZE; wr =3D wr + size) { + for (wp =3D wr - size; wp <=3D wr + size; wp =3D wp + size) { + result =3D run_test(size, MIN(size, 8), wr, wp); + if ((result && wr =3D=3D wp) || + (!result && wr !=3D wp)) + ksft_test_result_pass( + "Test size =3D %d write offset =3D %d watchpoint offset =3D %d\n", + size, wr, wp); + else { + ksft_test_result_fail( + "Test size =3D %d write offset =3D %d watchpoint offset =3D %d\n", + size, wr, wp); + succeeded =3D false; + } + } + } + } + + for (size =3D 1; size <=3D MAX_BP_SIZE; size =3D size*2) { + if (run_test(size, 8, -size, -8)) + ksft_test_result_pass( + "Test size =3D %d write offset =3D %d watchpoint offset =3D -8\n", + size, -size); + else { + ksft_test_result_fail( + "Test size =3D %d write offset =3D %d watchpoint offset =3D -8\n", + size, -size); + succeeded =3D false; + } + } + + if (succeeded) + ksft_exit_pass(); + else + ksft_exit_fail(); +} --=20 2.43.0