From nobody Mon Jun 15 03:52:55 2026 Received: from mail-pl1-f177.google.com (mail-pl1-f177.google.com [209.85.214.177]) (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 0F8AC27E045 for ; Tue, 7 Apr 2026 18:58:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.177 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775588307; cv=none; b=iNGf8upYx3/v8vyubfHubonCiBThwDDPq7iWGrXlKOPnvdzRYfZpc0k1J1+xuAYje8T6ND7G+QeobKOW/YXckJ8qWu/pGw7yvstOCiCh4C5ehdUBOXSJZf185W1b5UJ3ViFxnDTVBrOtDOxZgPoNHxMUsND8o+AwbPVmVu2IfzY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775588307; c=relaxed/simple; bh=2IKDEV2NvzggWkv/fIrblQNJBFwe2ulCsavfVPQSQqQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=SnKO6TzmxTJoDuEld9zVAhaNLPs4xBAPyTixeGjeUPcMsqR4CPvFVf3B20qN5xpyHwut2ZVwp5ETL9gsAL7IPM+FUaJsqJAGOFbL441/rU8+nWCUSxvE9ww0xgtTDF2+FcwZNWBsH/wBJN/bjWcYYrQRqO7BlaJFd6J3Kzv/kLM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=myNY7oc9; arc=none smtp.client-ip=209.85.214.177 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="myNY7oc9" Received: by mail-pl1-f177.google.com with SMTP id d9443c01a7336-2aaf43014d0so37833945ad.2 for ; Tue, 07 Apr 2026 11:58:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775588305; x=1776193105; 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=tENyS4UAhsyLXewunDkyxFOS4fIoNLiSb3W3F/WSw2w=; b=myNY7oc9DJzM88c/TMJsoxTHsKNKZUyARQi06TFfGS3GoxjRXfssCdm/8yttVFms1V QAANnqDJ2DANVrNZhlIzZTffp9uY7ZcEYxaOfHuB7LlhNYNTPOq77eQWLbFat+5SyKP7 80unuhNrSe9Y5+U147guJRgiAS/gcRDrMuWTQugQl8xUgfv6/x3wsgLDIsDw0zO1d/1i vx5tpqJCiEHQSv9NntKd+fUn8jFKX0dzP46FT4aGvNdSG8HgazOqIa+22ycLBEPsgQEe 2oXwV+mKnOqsG0xQ0duaE1a5yRmvUV1zkD4w8UTgc11U0pYhJkjqIm1r/2KykenUq6RG NFnw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775588305; x=1776193105; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=tENyS4UAhsyLXewunDkyxFOS4fIoNLiSb3W3F/WSw2w=; b=KxNUCj7Grm+qdJTlrk6BWiD1sqVF99mflBmTMVpNhJ/IqTRwXuesNcjlpbpvNU1Htf JJC+uQkDpQFHBTV+3/3aldvGUmMORZaQrkNKANJadsEsThyMbzeqPj/O2vc4gja0DZLK 00efn8HU2c+EgYEuSIxc3/TKwZi2GdBTdhrsvBtcLhcCsfyTGpNp7k5NmkxGC82W8pkc krmKl2yMgNiMTttxbdd8gmeDL0LNmp3VGD0EpAxzsVFXp8gSjKtrMuKBpYRIvr3r3/ir Pqvq5dIlMIgqLFg4+8DvI4PvfEgD0lI8rSCV9nYvsKFvTTkh9fewKi3WzAaduh/PbxZO 7Kzw== X-Forwarded-Encrypted: i=1; AJvYcCUvJv9rvmLhEFGYEi9OJau+mQoDL90gwNWwf8mSe6ZR5JTnyKbgvA8W6ZiEz8uskihpdU7xP1jgla8erNM=@vger.kernel.org X-Gm-Message-State: AOJu0YzxJOfnPiDeOU11VTQgvIiwpryXME6qXC0OSkbDzTknmOIVfpQV siGrb+o1sFnhxH7taPgYFUEgiJwH9zoik1A+31WPcdZDtiWQo4pACXUl X-Gm-Gg: AeBDievd2LjK0ICTW6G+b0kfVi0hQ/s50VlXbgmHNVee1E3n3CHHjvV8Z4hth8hLUOl 8Htf17N0DWSyuhjuy34exzCEQnULezuo5k0wvapCGRVOfb8OSTZoVzwwlctMHqr+68RAX79p5I9 P+HRdo7RgUpOEBD5L6m61nGH8WzFCw1r7EmRdFDxnVdm76uJtPpV4PPfraEX3Uos3W5eKHYXzhb 4NTm5/9YYN1GP6w7ioqZPFxciqG2EEe2AmXm6acauuCGrt8gCx9bI7S6tLG0+uhfiuUQSUW/h7N gspoPbUKoQLBc0bBvIteP+yPwzQ93xAlofUrHb6bXCe+EAgCd2l+WVH0Hb2RHjeFsh52NktaztX zavHwG5RHbT9VEFMHnfV54Epn6UKcuGlp5ulcft7OlxrCG6oBzAOuwSUh2aEuh8NuiGIR+ns1/H Y8CHpFWgxJM0sOTz/VTZicC5baohPby8c= X-Received: by 2002:a17:903:185:b0:2b2:41a9:8e10 with SMTP id d9443c01a7336-2b2819180d1mr189564715ad.23.1775588305331; Tue, 07 Apr 2026 11:58:25 -0700 (PDT) Received: from valdaarhun.localdomain ([2401:4900:1c45:a41c:c2d5:268a:232e:d07e]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2b2749ce29esm193486145ad.81.2026.04.07.11.58.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 07 Apr 2026 11:58:24 -0700 (PDT) From: Sahil Siddiq To: jonas@southpole.se, stefan.kristiansson@saunalahti.fi, shorne@gmail.com, naveen@kernel.org, davem@davemloft.net, mhiramat@kernel.org Cc: peterz@infradead.org, jpoimboe@kernel.org, jbaron@akamai.com, rostedt@goodmis.org, ardb@kernel.org, chenmiao.ku@gmail.com, johannes@sipsolutions.net, nsc@kernel.org, masahiroy@kernel.org, tytso@mit.edu, linux-openrisc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, Sahil Siddiq Subject: [RFC 1/2] openrisc: Add utilities and clean up simulation of instructions Date: Wed, 8 Apr 2026 00:26:49 +0530 Message-ID: <20260407185650.79816-2-sahilcdq0@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260407185650.79816-1-sahilcdq0@gmail.com> References: <20260407185650.79816-1-sahilcdq0@gmail.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" Introduce new instruction-related utilities and macros for OpenRISC. This is in preparation for patches that add tracing support such as KProbes. Simulate l.adrp. Fix bugs in simulation of l.jal and l.jalr. Earlier, PC was being updated and then saved in the link register r9, resulting in a corrupted page table (bad page map in process). Instead, update PC after storing it in r9. Move instruction simulation to its own file to enable reuse. Clean it up and replace hardcoded values with computed expressions. Link: https://raw.githubusercontent.com/openrisc/doc/master/openrisc-arch-1= .4-rev0.pdf Signed-off-by: Sahil Siddiq --- arch/openrisc/include/asm/insn-def.h | 61 +++++++++++++++++++++-- arch/openrisc/include/asm/spr_defs.h | 1 + arch/openrisc/kernel/Makefile | 2 +- arch/openrisc/kernel/insn.c | 74 ++++++++++++++++++++++++++++ arch/openrisc/kernel/jump_label.c | 2 +- arch/openrisc/kernel/traps.c | 41 +-------------- 6 files changed, 136 insertions(+), 45 deletions(-) create mode 100644 arch/openrisc/kernel/insn.c diff --git a/arch/openrisc/include/asm/insn-def.h b/arch/openrisc/include/a= sm/insn-def.h index 1e0c028a5b95..c98f9770c52e 100644 --- a/arch/openrisc/include/asm/insn-def.h +++ b/arch/openrisc/include/asm/insn-def.h @@ -3,13 +3,66 @@ * Copyright (C) 2025 Chen Miao */ =20 +#include +#include + #ifndef __ASM_OPENRISC_INSN_DEF_H #define __ASM_OPENRISC_INSN_DEF_H =20 -/* or1k instructions are always 32 bits. */ -#define OPENRISC_INSN_SIZE 4 - /* or1k nop instruction code */ -#define OPENRISC_INSN_NOP 0x15000000U +#define INSN_NOP 0x15000000U + +#define INSN_CSYNC 0x23000000U +#define INSN_MSYNC 0x22000000U +#define INSN_PSYNC 0x22800000U + +#define OPCODE_TRAP 0x21000000U +#define OPCODE_SYS 0x20000000U +#define OPCODE_MACRC 0x18010000U + +struct pt_regs; + +enum six_bit_opcodes { + l_rfe =3D 0x09, + l_lwa =3D 0x1b, + l_mfspr =3D 0x2d, + l_mtspr =3D 0x30, + l_swa =3D 0x33, + l_j =3D 0x00, + l_jal =3D 0x01, + l_adrp =3D 0x02, + l_bnf =3D 0x03, + l_bf =3D 0x04, + l_jr =3D 0x11, + l_jalr =3D 0x12, +}; + +struct insn { + unsigned int opcode: 6; + unsigned int operands: 26; +}; + +union openrisc_instruction { + unsigned int word; + struct insn opcodes_6bit; +}; + +#define OPENRISC_INSN_SIZE (sizeof(union openrisc_instruction)) + +/* Helpers for working with l.trap */ +static inline unsigned long __emit_trap(unsigned int code) +{ + return (code & 0xffff) | OPCODE_TRAP; +} + +static inline bool has_delay_slot(void) +{ + unsigned int cpucfgr =3D mfspr(SPR_CPUCFGR); + + return !(cpucfgr & SPR_CPUCFGR_ND); +} + +void simulate_pc(struct pt_regs *regs, unsigned int jmp); +void simulate_branch(struct pt_regs *regs, unsigned int jmp, bool has_dela= y_slot); =20 #endif /* __ASM_OPENRISC_INSN_DEF_H */ diff --git a/arch/openrisc/include/asm/spr_defs.h b/arch/openrisc/include/a= sm/spr_defs.h index f0b6b492e9f4..5d13a9b96263 100644 --- a/arch/openrisc/include/asm/spr_defs.h +++ b/arch/openrisc/include/asm/spr_defs.h @@ -179,6 +179,7 @@ #define SPR_CPUCFGR_OF32S 0x00000080 /* ORFPX32 supported */ #define SPR_CPUCFGR_OF64S 0x00000100 /* ORFPX64 supported */ #define SPR_CPUCFGR_OV64S 0x00000200 /* ORVDX64 supported */ +#define SPR_CPUCFGR_ND 0x00000400 /* No delay slot */ #define SPR_CPUCFGR_RES 0xfffffc00 /* Reserved */ =20 /* diff --git a/arch/openrisc/kernel/Makefile b/arch/openrisc/kernel/Makefile index 19e0eb94f2eb..150779fbf010 100644 --- a/arch/openrisc/kernel/Makefile +++ b/arch/openrisc/kernel/Makefile @@ -5,7 +5,7 @@ =20 always-$(KBUILD_BUILTIN) :=3D vmlinux.lds =20 -obj-y :=3D head.o setup.o or32_ksyms.o process.o dma.o \ +obj-y :=3D head.o insn.o setup.o or32_ksyms.o process.o dma.o \ traps.o time.o irq.o entry.o ptrace.o signal.o \ sys_call_table.o unwinder.o cacheinfo.o =20 diff --git a/arch/openrisc/kernel/insn.c b/arch/openrisc/kernel/insn.c new file mode 100644 index 000000000000..2c97eceee6d7 --- /dev/null +++ b/arch/openrisc/kernel/insn.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * OpenRISC instruction utils + * + * Linux architectural port borrowing liberally from similar works of + * others. All original copyrights apply as per the original source + * declaration. + * + * OpenRISC implementation: + * Copyright (C) 2026 Sahil Siddiq + */ + +#include +#include + +void simulate_pc(struct pt_regs *regs, unsigned int jmp) +{ + int displacement; + unsigned int rd, op; + + displacement =3D sign_extend32(((jmp) & 0x7ffff) << 13, 31); + rd =3D (jmp & 0x3ffffff) >> 21; + op =3D jmp >> 26; + + switch (op) { + case l_adrp: + regs->gpr[rd] =3D displacement + (regs->pc & (-8192)); + return; + default: + break; + } +} + +void simulate_branch(struct pt_regs *regs, unsigned int jmp_insn, bool has= _delay_slot) +{ + int displacement; + unsigned int rb, op, jmp; + + displacement =3D sign_extend32(((jmp_insn) & 0x3ffffff) << 2, 27); + rb =3D (jmp_insn & 0x0000ffff) >> 11; + op =3D jmp_insn >> 26; + jmp =3D has_delay_slot ? 2 * OPENRISC_INSN_SIZE : OPENRISC_INSN_SIZE; + + switch (op) { + case l_j: /* l.j */ + regs->pc +=3D displacement; + return; + case l_jal: /* l.jal */ + regs->gpr[9] =3D regs->pc + jmp; + regs->pc +=3D displacement; + return; + case l_bnf: /* l.bnf */ + if (regs->sr & SPR_SR_F) + regs->pc +=3D jmp; + else + regs->pc +=3D displacement; + return; + case l_bf: /* l.bf */ + if (regs->sr & SPR_SR_F) + regs->pc +=3D displacement; + else + regs->pc +=3D jmp; + return; + case l_jr: /* l.jr */ + regs->pc =3D regs->gpr[rb]; + return; + case l_jalr: /* l.jalr */ + regs->gpr[9] =3D regs->pc + jmp; + regs->pc =3D regs->gpr[rb]; + return; + default: + break; + } +} diff --git a/arch/openrisc/kernel/jump_label.c b/arch/openrisc/kernel/jump_= label.c index ab7137c23b46..fe082eb847a4 100644 --- a/arch/openrisc/kernel/jump_label.c +++ b/arch/openrisc/kernel/jump_label.c @@ -34,7 +34,7 @@ bool arch_jump_label_transform_queue(struct jump_entry *e= ntry, =20 insn =3D offset; } else { - insn =3D OPENRISC_INSN_NOP; + insn =3D INSN_NOP; } =20 if (early_boot_irqs_disabled) diff --git a/arch/openrisc/kernel/traps.c b/arch/openrisc/kernel/traps.c index c195be9cc9fc..ee87a3af34fc 100644 --- a/arch/openrisc/kernel/traps.c +++ b/arch/openrisc/kernel/traps.c @@ -32,6 +32,7 @@ =20 #include #include +#include #include #include #include @@ -269,47 +270,9 @@ static inline int in_delay_slot(struct pt_regs *regs) =20 static inline void adjust_pc(struct pt_regs *regs, unsigned long address) { - int displacement; - unsigned int rb, op, jmp; - if (unlikely(in_delay_slot(regs))) { /* In delay slot, instruction at pc is a branch, simulate it */ - jmp =3D *((unsigned int *)regs->pc); - - displacement =3D sign_extend32(((jmp) & 0x3ffffff) << 2, 27); - rb =3D (jmp & 0x0000ffff) >> 11; - op =3D jmp >> 26; - - switch (op) { - case 0x00: /* l.j */ - regs->pc +=3D displacement; - return; - case 0x01: /* l.jal */ - regs->pc +=3D displacement; - regs->gpr[9] =3D regs->pc + 8; - return; - case 0x03: /* l.bnf */ - if (regs->sr & SPR_SR_F) - regs->pc +=3D 8; - else - regs->pc +=3D displacement; - return; - case 0x04: /* l.bf */ - if (regs->sr & SPR_SR_F) - regs->pc +=3D displacement; - else - regs->pc +=3D 8; - return; - case 0x11: /* l.jr */ - regs->pc =3D regs->gpr[rb]; - return; - case 0x12: /* l.jalr */ - regs->pc =3D regs->gpr[rb]; - regs->gpr[9] =3D regs->pc + 8; - return; - default: - break; - } + simulate_branch(regs, *((unsigned int *)regs->pc), has_delay_slot()); } else { regs->pc +=3D 4; } --=20 2.53.0 From nobody Mon Jun 15 03:52:55 2026 Received: from mail-pl1-f170.google.com (mail-pl1-f170.google.com [209.85.214.170]) (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 4F9C333CE80 for ; Tue, 7 Apr 2026 18:58:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.170 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775588323; cv=none; b=DeSqD8q8ZiNNO621YQy6wmUcOJZDMnv4sLEtpkDFABbO5YZRQJdo7kRK8G/BMBkZIRou15lAPIZMJ0ZOYwZV0lVhS84N7bAEePQnb8VIHjD7qjnZ/1IuA6sfMVc47SGHthRVm1vNmncyq2r3hwF/NJP1/6Hoy9FoTgKPY/Nj19c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775588323; c=relaxed/simple; bh=M/kGRbL/4LArPoM4UqPQVrEqZbvE9S8tBqqRfQLPQ1g=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=fMxq0K4ou4G8BJ6OHo4w8LyO2pAGa56nl4V0IiIXT01x+1CRLIcFeWvj6+7Eurvk008WZHO5UpJ8ZDMpuhEVIVA2xNMuYXb/XBl4YLPFlFRT0U+1xbAj1+g2qfkxdyb640wsjdDocZ5PKMAX7pNVammRT7F6bLitvKJzvSPPOCQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=rU/Wm9sC; arc=none smtp.client-ip=209.85.214.170 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="rU/Wm9sC" Received: by mail-pl1-f170.google.com with SMTP id d9443c01a7336-2b23fcf90b2so53093575ad.3 for ; Tue, 07 Apr 2026 11:58:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775588321; x=1776193121; 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=Qpfl67BwNUGKz5mtCYNigYyMPxt2kbknFc7+Iynv6Hg=; b=rU/Wm9sCo/Jhqh9qJnKPsajXBNRW8kUPnXS3+t3DjjuYaA08Q3kXDU1Hp9N5x2zMn6 feNiWp9vUqkprr/d9IlOTXZnuMbxVyVZSbqY3uYOnShxXMs5WBKZiONBZL/6ekXdjAlz Qyyfcw7hRKQYURTlOuo9jK72hIZ+wIZvOHsWX4rE0pJO5l/vr2RpY8oKXo6aaE1jWl7a zn2BgJO77tuCj+UfL4yDsHWStC0GGX0wv2gqBnMfOFrtfme7ORkgatZW1RDseMBd1E/a 1dUeftD9lMR/++F2EVBWPDylzslx/0rP8SkCTGH1PojjadwXTR4BeGHARE6xgEEawm4B nCHQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775588321; x=1776193121; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=Qpfl67BwNUGKz5mtCYNigYyMPxt2kbknFc7+Iynv6Hg=; b=spYbsvL8KieBBuhd3GfvdNYyI1zm+/SOswoDzVjydYrIp4K2vrwfI/VN5BJ+2EbNSQ Y92WtJ38p1lkKqAYLV6O020SIjOmT0zl3wbcHJ2f6s3bWn3mwArJgHHmfts20Rr2MXhD 5jrZkoVzaBtLl2ap8KDMkqWl+eZ+hqaG6tLIbjGAXw1PIQV+ng/VhimH6HLDY6KlLFXB zqFRdsLbsqqTYtmWfRBYUv91DfsisP6ACezg1HRSX0Jp8nYt06Hc7Y5ye8mGXsqN/OXa q2UAYflzg7rzpcM6cKulztIUjG4pETn+iCejGd8doJqvze6+nRJ2t9uHQpBF8QMCsAFC t/bA== X-Forwarded-Encrypted: i=1; AJvYcCWYoL5M0b7TM4ox1y+Xq2USgPr2CABX7uRwZzmLAmDJG2YAZX9UBbthgtVMCZXxNoWIB8xGDp/0SKwnVOo=@vger.kernel.org X-Gm-Message-State: AOJu0YxAHkkByRATnd7bRk1uNETDD10FoC0AzcQbGdbmj8vAqMSUsRVZ 5K0gSDlox5ZQar6jhfvptIAkwrMm+RXWTuH9zXk89osq3fb3kuL5PK0b X-Gm-Gg: AeBDieuANYdac7eBGgYof4cuhEZgH7ErAHJbDm8xhdkKiyf5Vai8CY3klG2W+XgWIRi ZGK1rQ4HoiukJ7l/VMnflr6dntNrmEIvHxoED3t5+zMkNx2WO47oJGh5NcT0b892z0A25pEMLDV 5DVoc7ZIeeRW8eUHL0e4z3jxPSdMOXeohL4pBWpinnypOavJuK1bAsoomLVdkko4KXBaSqq7NoV 8QhmoaJPkqLHc69zOOEIofD/k+oEX4v2umE6HCXQkuUuGGljr94MNW1zJkDjXWBFKQX/Cf2DzoJ yVV76QXmsdb8eWgS8tjptO+UzztL6jnH7kWCTM/wUeK07eLGVuTIjUxvpC8e3MTHQzgzZwyrMGX ugixRVaC4k9nNR3x1mBDf1SAOjXgKcwGeQI0/lroTWAGz57KPovUHtggNmEpHiJ8pNPBrUW4fm7 YmIg71/6HNtMpeucQ096LUuXWIPJJ30Cs= X-Received: by 2002:a17:902:f541:b0:2b0:ac1e:973a with SMTP id d9443c01a7336-2b281889a3dmr174544395ad.39.1775588320486; Tue, 07 Apr 2026 11:58:40 -0700 (PDT) Received: from valdaarhun.localdomain ([2401:4900:1c45:a41c:c2d5:268a:232e:d07e]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2b2749ce29esm193486145ad.81.2026.04.07.11.58.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 07 Apr 2026 11:58:40 -0700 (PDT) From: Sahil Siddiq To: jonas@southpole.se, stefan.kristiansson@saunalahti.fi, shorne@gmail.com, naveen@kernel.org, davem@davemloft.net, mhiramat@kernel.org Cc: peterz@infradead.org, jpoimboe@kernel.org, jbaron@akamai.com, rostedt@goodmis.org, ardb@kernel.org, chenmiao.ku@gmail.com, johannes@sipsolutions.net, nsc@kernel.org, masahiroy@kernel.org, tytso@mit.edu, linux-openrisc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, Sahil Siddiq Subject: [RFC 2/2] openrisc: Add KProbes Date: Wed, 8 Apr 2026 00:26:50 +0530 Message-ID: <20260407185650.79816-3-sahilcdq0@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260407185650.79816-1-sahilcdq0@gmail.com> References: <20260407185650.79816-1-sahilcdq0@gmail.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 KProbes support for OpenRISC. This work is primarily based on similar work done for LoongArch, MIPS and RISC-V. KProbes make it possible to trap at almost any address in the kernel to collect performance/debugging info. Signed-off-by: Sahil Siddiq --- arch/openrisc/Kconfig | 1 + arch/openrisc/configs/or1ksim_defconfig | 2 + arch/openrisc/configs/virt_defconfig | 2 + arch/openrisc/include/asm/asm.h | 22 ++ arch/openrisc/include/asm/break.h | 19 ++ arch/openrisc/include/asm/kprobes.h | 76 +++++ arch/openrisc/kernel/Makefile | 1 + arch/openrisc/kernel/entry.S | 16 + arch/openrisc/kernel/kprobes.c | 381 ++++++++++++++++++++++++ arch/openrisc/kernel/traps.c | 26 ++ arch/openrisc/lib/memcpy.c | 2 + arch/openrisc/lib/memset.S | 4 + arch/openrisc/mm/fault.c | 5 + samples/kprobes/kprobe_example.c | 8 + 14 files changed, 565 insertions(+) create mode 100644 arch/openrisc/include/asm/asm.h create mode 100644 arch/openrisc/include/asm/break.h create mode 100644 arch/openrisc/include/asm/kprobes.h create mode 100644 arch/openrisc/kernel/kprobes.c diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig index 9156635dd264..d240533b424b 100644 --- a/arch/openrisc/Kconfig +++ b/arch/openrisc/Kconfig @@ -27,6 +27,7 @@ config OPENRISC select HAVE_ARCH_JUMP_LABEL select HAVE_ARCH_JUMP_LABEL_RELATIVE select HAVE_PCI + select HAVE_KPROBES select HAVE_UID16 select HAVE_PAGE_SIZE_8KB select HAVE_REGS_AND_STACK_ACCESS_API diff --git a/arch/openrisc/configs/or1ksim_defconfig b/arch/openrisc/config= s/or1ksim_defconfig index 769705ac24d5..24d2915e7609 100644 --- a/arch/openrisc/configs/or1ksim_defconfig +++ b/arch/openrisc/configs/or1ksim_defconfig @@ -10,7 +10,9 @@ CONFIG_EXPERT=3Dy # CONFIG_KALLSYMS is not set CONFIG_BUILTIN_DTB_NAME=3D"or1ksim" CONFIG_HZ_100=3Dy +CONFIG_OPENRISC=3Dy CONFIG_JUMP_LABEL=3Dy +CONFIG_KPROBES=3Dy CONFIG_MODULES=3Dy # CONFIG_BLOCK is not set CONFIG_SLUB_TINY=3Dy diff --git a/arch/openrisc/configs/virt_defconfig b/arch/openrisc/configs/v= irt_defconfig index 0b9979b35ca8..2eccb506032f 100644 --- a/arch/openrisc/configs/virt_defconfig +++ b/arch/openrisc/configs/virt_defconfig @@ -11,8 +11,10 @@ CONFIG_OPENRISC_HAVE_INST_SEXT=3Dy CONFIG_NR_CPUS=3D8 CONFIG_SMP=3Dy CONFIG_HZ_100=3Dy +CONFIG_OPENRISC=3Dy # CONFIG_OPENRISC_NO_SPR_SR_DSX is not set CONFIG_JUMP_LABEL=3Dy +CONFIG_KPROBES=3Dy # CONFIG_COMPAT_BRK is not set CONFIG_NET=3Dy CONFIG_PACKET=3Dy diff --git a/arch/openrisc/include/asm/asm.h b/arch/openrisc/include/asm/as= m.h new file mode 100644 index 000000000000..1a9c8bbb4430 --- /dev/null +++ b/arch/openrisc/include/asm/asm.h @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Macros for OpenRISC asm + * + * Linux architectural port borrowing nearly verbatim from + * LoongArch and Arm. All original copyrights apply as per + * the original source declaration. + */ + +#ifndef __ASM_ASM_H +#define __ASM_ASM_H + +#ifdef CONFIG_KPROBES +#define _ASM_NOKPROBE(symbol) \ + .pushsection "_kprobe_blacklist", "aw"; \ + .long symbol; \ + .popsection +#else +#define _ASM_NOKPROBE(symbol) +#endif + +#endif /* __ASM_ASM_H */ diff --git a/arch/openrisc/include/asm/break.h b/arch/openrisc/include/asm/= break.h new file mode 100644 index 000000000000..4bd04f4dd17a --- /dev/null +++ b/arch/openrisc/include/asm/break.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * OpenRISC trap codes used internally by the kernel + * + * Linux architectural port borrowing liberally from similar works of + * others. All original copyrights apply as per the original source + * declaration. + * + * Modifications for the OpenRISC architecture: + * Copyright (C) 2026 Sahil Siddiq + */ + +#ifndef __ASM_BREAK_H +#define __ASM_BREAK_H + +#define BRK_KPROBE_BP 512 /* Kprobe break */ +#define BRK_KPROBE_SSTEPBP 1024 /* Kprobe single-step software impleme= ntation */ + +#endif /* __ASM_BREAK_H */ diff --git a/arch/openrisc/include/asm/kprobes.h b/arch/openrisc/include/as= m/kprobes.h new file mode 100644 index 000000000000..50b6dc6d5a0c --- /dev/null +++ b/arch/openrisc/include/asm/kprobes.h @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * OpenRISC Linux + * + * Linux architectural port borrowing liberally from similar works of + * others. All original copyrights apply as per the original source + * declaration. + * + * OpenRISC implementation: + * Copyright (C) 2026 Sahil Siddiq + */ + +#ifndef __ASM_OPENRISC_KPROBES_H +#define __ASM_OPENRISC_KPROBES_H + +#include + +#ifdef CONFIG_KPROBES +#include +#include + +#define __ARCH_WANT_KPROBES_INSN_SLOT + +struct pt_regs; +struct kprobe; + +typedef u32 kprobe_opcode_t; + +/* + * MAX_INSN_SIZE is used as the number of slots in an executable + * page for single-stepping out of line (SSOL). We need two slots + * since we single-step using software breakpoints. The probed + * instruction is placed in the first slot with a breakpoint + * instruction in the second slot. + */ +#define MAX_INSN_SIZE 2 + +/* Architecture specific copy of original instruction */ +struct arch_specific_insn { + /* copy of original instruction */ + kprobe_opcode_t *insn; + /* address of next instruction in case of SSOL */ + unsigned long restore; +}; + +struct prev_kprobe { + struct kprobe *kp; + unsigned int status; +}; + +/* per-cpu kprobe control block */ +struct kprobe_ctlblk { + unsigned int kprobe_status; + unsigned long irq_flags; + struct prev_kprobe prev_kprobe; +}; + +#define flush_insn_slot(p) do { } while (0) +#define kretprobe_blacklist_size 0 + +void arch_remove_kprobe(struct kprobe *p); +int kprobe_fault_handler(struct pt_regs *regs, int trapnr); +bool kprobe_breakpoint_handler(struct pt_regs *regs); +bool kprobe_singlestep_handler(struct pt_regs *regs); +#else /* !CONFIG_KPROBES */ +static inline bool kprobe_breakpoint_handler(struct pt_regs *regs) +{ + return false; +} + +static inline bool kprobe_singlestep_handler(struct pt_regs *regs) +{ + return false; +} +#endif /* CONFIG_KPROBES */ +#endif /* __ASM_OPENRISC_KPROBES_H */ diff --git a/arch/openrisc/kernel/Makefile b/arch/openrisc/kernel/Makefile index 150779fbf010..2ac824867963 100644 --- a/arch/openrisc/kernel/Makefile +++ b/arch/openrisc/kernel/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_SMP) +=3D smp.o sync-timer.o obj-$(CONFIG_STACKTRACE) +=3D stacktrace.o obj-$(CONFIG_MODULES) +=3D module.o obj-$(CONFIG_OF) +=3D prom.o +obj-$(CONFIG_KPROBES) +=3D kprobes.o obj-y +=3D patching.o =20 clean: diff --git a/arch/openrisc/kernel/entry.S b/arch/openrisc/kernel/entry.S index c7e90b09645e..cd28bf1f7a3b 100644 --- a/arch/openrisc/kernel/entry.S +++ b/arch/openrisc/kernel/entry.S @@ -15,6 +15,7 @@ #include #include =20 +#include #include #include #include @@ -640,6 +641,7 @@ ENTRY(_sys_call_handler) /* r30 is the only register we clobber in the fast path */ /* r30 already saved */ /* l.sw PT_GPR30(r1),r30 */ +_ASM_NOKPROBE(_sys_call_handler) =20 _syscall_check_trace_enter: /* syscalls run with interrupts enabled */ @@ -652,12 +654,14 @@ _syscall_check_trace_enter: l.sfne r30,r0 l.bf _syscall_trace_enter l.nop +_ASM_NOKPROBE(_syscall_check_trace_enter) =20 _syscall_check: /* Ensure that the syscall number is reasonable */ l.sfgeui r11,__NR_syscalls l.bf _syscall_badsys l.nop +_ASM_NOKPROBE(_syscall_check) =20 _syscall_call: l.movhi r29,hi(sys_call_table) @@ -668,12 +672,14 @@ _syscall_call: =20 l.jalr r29 l.nop +_ASM_NOKPROBE(_syscall_call) =20 _syscall_return: /* All syscalls return here... just pay attention to ret_from_fork * which does it in a round-about way. */ l.sw PT_GPR11(r1),r11 // save return value +_ASM_NOKPROBE(_syscall_return) =20 #if 0 _syscall_debug: @@ -708,6 +714,7 @@ _syscall_check_trace_leave: l.sfne r30,r0 l.bf _syscall_trace_leave l.nop +_ASM_NOKPROBE(_syscall_check_trace_leave) =20 /* This is where the exception-return code begins... interrupts need to be * disabled the rest of the way here because we can't afford to miss any @@ -744,6 +751,7 @@ _syscall_check_work: /* _work_pending needs to be called with interrupts disabled */ l.j _work_pending l.nop +_ASM_NOKPROBE(_syscall_check_work) =20 _syscall_resume_userspace: // ENABLE_INTERRUPTS(r29) @@ -800,6 +808,7 @@ _syscall_resume_userspace: l.mtspr r0,r13,SPR_EPCR_BASE l.mtspr r0,r15,SPR_ESR_BASE l.rfe +_ASM_NOKPROBE(_syscall_resume_userspace) =20 /* End of hot path! * Keep the below tracing and error handling out of the hot path... @@ -829,6 +838,7 @@ _syscall_trace_enter: =20 l.j _syscall_check l.lwz r8,PT_GPR8(r1) +_ASM_NOKPROBE(_syscall_trace_enter) =20 _syscall_trace_leave: l.jal do_syscall_trace_leave @@ -836,6 +846,7 @@ _syscall_trace_leave: =20 l.j _syscall_check_work l.nop +_ASM_NOKPROBE(_syscall_trace_leave) =20 _syscall_badsys: /* Here we effectively pretend to have executed an imaginary @@ -845,6 +856,7 @@ _syscall_badsys: */ l.j _syscall_return l.addi r11,r0,-ENOSYS +_ASM_NOKPROBE(_syscall_badsys) =20 /******* END SYSCALL HANDLING *******/ =20 @@ -870,6 +882,7 @@ EXCEPTION_ENTRY(_trap_handler) =20 l.j _ret_from_exception l.nop +_ASM_NOKPROBE(_trap_handler) =20 /* ---[ 0xf00: Reserved exception ]-------------------------------------- = */ =20 @@ -1004,6 +1017,8 @@ ENTRY(_ret_from_exception) l.nop l.j _resume_userspace l.nop +_ASM_NOKPROBE(_ret_from_exception) +_ASM_NOKPROBE(_ret_from_intr) =20 ENTRY(ret_from_fork) l.jal schedule_tail @@ -1038,6 +1053,7 @@ ENTRY(ret_from_fork) =20 l.j _syscall_return l.nop +_ASM_NOKPROBE(ret_from_fork) =20 /* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D[ switch ] =3D=3D=3D */ =20 diff --git a/arch/openrisc/kernel/kprobes.c b/arch/openrisc/kernel/kprobes.c new file mode 100644 index 000000000000..f9073a1cb6eb --- /dev/null +++ b/arch/openrisc/kernel/kprobes.c @@ -0,0 +1,381 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Kernel probes (KProbes) for OpenRISC + * + * Linux architectural port borrowing liberally from similar works of + * others. All original copyrights apply as per the original source + * declaration. + * + * OpenRISC implementation: + * Copyright (C) 2026 Sahil Siddiq + */ + +#include +#include +#include + +DEFINE_PER_CPU(struct kprobe *, current_kprobe); +DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); + +#define KPROBE_BP_INSN __emit_trap(BRK_KPROBE_BP) +#define KPROBE_SSTEPBP_INSN __emit_trap(BRK_KPROBE_SSTEPBP) + +static bool insn_not_supported(union openrisc_instruction insn) +{ + switch (insn.word) { + case INSN_CSYNC: + case INSN_MSYNC: + case INSN_PSYNC: + return true; + } + + if ((insn.word & 0xffff0000) =3D=3D OPCODE_SYS) + return true; + + if ((insn.word & 0xfc01ffff) =3D=3D OPCODE_MACRC) + return true; + + switch (insn.opcodes_6bit.opcode) { + case l_rfe: + case l_lwa: + case l_mfspr: + case l_mtspr: + case l_swa: + return true; + } + + return false; +} +NOKPROBE_SYMBOL(insn_not_supported) + +static bool is_branch_insn(union openrisc_instruction insn) +{ + switch (insn.opcodes_6bit.opcode) { + case l_j: + case l_jal: + case l_bnf: + case l_bf: + case l_jr: + case l_jalr: + return true; + } + + return false; +} +NOKPROBE_SYMBOL(is_branch_insn) + +static bool is_pc_insn(union openrisc_instruction insn) +{ + if (insn.opcodes_6bit.opcode =3D=3D l_adrp) + return true; + + return false; +} +NOKPROBE_SYMBOL(is_pc_insn) + +static bool insns_need_simulation(union openrisc_instruction insn, bool *e= xec_delay_slot) +{ + if (is_branch_insn(insn)) { + *exec_delay_slot =3D has_delay_slot(); + return true; + } + + if (is_pc_insn(insn)) { + *exec_delay_slot =3D false; + return true; + } + + *exec_delay_slot =3D false; + return false; +} +NOKPROBE_SYMBOL(insns_need_simulation) + +int arch_prepare_kprobe(struct kprobe *p) +{ + union openrisc_instruction insn; + union openrisc_instruction prev_insn; + unsigned int cpucfgr =3D mfspr(SPR_CPUCFGR); + bool ss_delay_slot =3D false, exec_delay_slot =3D false; + + /* Attempt to probe at unaligned address */ + if ((unsigned long)p->addr & 0x3) + return -EILSEQ; + + p->opcode =3D *p->addr; + insn.word =3D p->opcode; + + if (insn_not_supported(insn)) { + pr_notice("Can't insert KProbe at blacklisted instruction.\n"); + return -EINVAL; + } + + if (copy_from_kernel_nofault(&prev_insn, p->addr - 1, + OPENRISC_INSN_SIZE) =3D=3D 0 && + insns_need_simulation(prev_insn, &exec_delay_slot) && exec_delay_slot) { + pr_notice("Can't insert KProbe in delay slot.\n"); + return -EINVAL; + } + + if (insns_need_simulation(insn, &exec_delay_slot) && !exec_delay_slot) { + p->ainsn.insn =3D NULL; + p->ainsn.restore =3D 0; + } else { + /* + * Single step probed instruction or, in case of branch instructions, si= ngle + * step instruction in delay slot. + */ + p->ainsn.insn =3D get_insn_slot(); + if (!p->ainsn.insn) + return -ENOMEM; + + if (exec_delay_slot) { + patch_insn_write(p->ainsn.insn, *(p->addr + 1)); + p->ainsn.restore =3D 0; + } else { + patch_insn_write(p->ainsn.insn, p->opcode); + p->ainsn.restore =3D (unsigned long)p->addr + OPENRISC_INSN_SIZE; + } + patch_insn_write(&p->ainsn.insn[1], KPROBE_SSTEPBP_INSN); + } + + return 0; +} +NOKPROBE_SYMBOL(arch_prepare_kprobe); + +void arch_arm_kprobe(struct kprobe *p) +{ + patch_insn_write(p->addr, KPROBE_BP_INSN); + flush_insn_slot(p); +} +NOKPROBE_SYMBOL(arch_arm_kprobe); + +void arch_disarm_kprobe(struct kprobe *p) +{ + patch_insn_write(p->addr, p->opcode); + flush_insn_slot(p); +} +NOKPROBE_SYMBOL(arch_disarm_kprobe); + +void arch_remove_kprobe(struct kprobe *p) +{ + if (p->ainsn.insn) { + free_insn_slot(p->ainsn.insn, 0); + p->ainsn.insn =3D NULL; + } +} +NOKPROBE_SYMBOL(arch_remove_kprobe); + +static void set_current_kprobe(struct kprobe *p) +{ + __this_cpu_write(current_kprobe, p); +} +NOKPROBE_SYMBOL(set_current_kprobe); + +static void save_previous_kprobe(struct kprobe_ctlblk *kcb) +{ + kcb->prev_kprobe.kp =3D kprobe_running(); + kcb->prev_kprobe.status =3D kcb->kprobe_status; +} +NOKPROBE_SYMBOL(save_previous_kprobe); + +static void restore_previous_kprobe(struct kprobe_ctlblk *kcb) +{ + kcb->kprobe_status =3D kcb->prev_kprobe.status; + set_current_kprobe(kcb->prev_kprobe.kp); +} +NOKPROBE_SYMBOL(restore_previous_kprobe); + +static void post_kprobe_handler(struct kprobe *cur, struct kprobe_ctlblk *= kcb, + struct pt_regs *regs) +{ + if (cur->ainsn.restore !=3D 0) + instruction_pointer_set(regs, (unsigned long)cur->ainsn.restore); + + if (kcb->kprobe_status =3D=3D KPROBE_REENTER) { + restore_previous_kprobe(kcb); + preempt_enable_no_resched(); + return; + } + + kcb->kprobe_status =3D KPROBE_HIT_SSDONE; + + if (cur->post_handler) + cur->post_handler(cur, regs, 0); + + reset_current_kprobe(); + preempt_enable_no_resched(); +} +NOKPROBE_SYMBOL(post_kprobe_handler); + +static void setup_singlestep(struct kprobe *p, struct pt_regs *regs, + struct kprobe_ctlblk *kcb, int reenter) +{ + union openrisc_instruction insn; + + if (reenter) { + save_previous_kprobe(kcb); + set_current_kprobe(p); + kcb->kprobe_status =3D KPROBE_REENTER; + } else { + kcb->kprobe_status =3D KPROBE_HIT_SS; + } + + /* Emulate instruction if required. */ + insn.word =3D p->opcode; + if (is_branch_insn(insn)) { + simulate_branch(regs, insn.word, has_delay_slot()); + /* Save target addr before updating PC to SSOL slot */ + p->ainsn.restore =3D regs->pc; + } else if (is_pc_insn(insn)) { + simulate_pc(regs, insn.word); + /* No SSOL is required here, so call post-process immediately. */ + post_kprobe_handler(p, kcb, regs); + return; + } + + if (p->ainsn.insn) { + /* Disable IRQs before single stepping */ + local_irq_save(kcb->irq_flags); + instruction_pointer_set(regs, (unsigned long)p->ainsn.insn); + } else { + /* + * The instruction is a branch but delay slots are disabled. + * Simply call the post-handler. + */ + post_kprobe_handler(p, kcb, regs); + } +} +NOKPROBE_SYMBOL(setup_singlestep); + +static bool reenter_kprobe(struct kprobe *p, struct pt_regs *regs, + struct kprobe_ctlblk *kcb) +{ + switch (kcb->kprobe_status) { + case KPROBE_HIT_SS: + case KPROBE_HIT_SSDONE: + case KPROBE_HIT_ACTIVE: + kprobes_inc_nmissed_count(p); + setup_singlestep(p, regs, kcb, 1); + break; + case KPROBE_REENTER: + pr_warn("Unrecoverable KProbe detected.\n"); + dump_kprobe(p); + WARN_ON_ONCE(1); + break; + default: + WARN_ON(1); + return false; + } + + return true; +} +NOKPROBE_SYMBOL(reenter_kprobe); + +bool kprobe_breakpoint_handler(struct pt_regs *regs) +{ + struct kprobe *p, *curr_kprobe; + struct kprobe_ctlblk *kcb; + kprobe_opcode_t *addr =3D (kprobe_opcode_t *)regs->pc; + + /* + * We don't want to be preempted for the entire + * duration of kprobe processing. + */ + preempt_disable(); + + kcb =3D get_kprobe_ctlblk(); + curr_kprobe =3D kprobe_running(); + p =3D get_kprobe(addr); + if (p) { + if (curr_kprobe) { + if (reenter_kprobe(p, regs, kcb)) + return true; + } else { + /* Probe hit */ + set_current_kprobe(p); + kcb->kprobe_status =3D KPROBE_HIT_ACTIVE; + /* + * If there's no pre-handler or it returns 0, continue + * processing the KProbe as usual. A non-zero return + * value implies the saved registers have been modified + * and the execution path might deviate from what's + * expected. Reset the KProbe and return. + */ + if (!p->pre_handler || !p->pre_handler(p, regs)) { + setup_singlestep(p, regs, kcb, 0); + } else { + reset_current_kprobe(); + preempt_enable_no_resched(); + } + return true; + } + } + + /* + * The breakpoint instruction was removed right after we hit it + * possibly by another cpu. If the original instruction was also + * a trap instruction then return to the trap handler for further + * processing, else no further processing is required. + */ + if ((*addr & 0xffff0000) !=3D OPCODE_TRAP) { + preempt_enable_no_resched(); + return true; + } + + preempt_enable_no_resched(); + return false; +} +NOKPROBE_SYMBOL(kprobe_breakpoint_handler); + +bool kprobe_singlestep_handler(struct pt_regs *regs) +{ + struct kprobe *cur =3D kprobe_running(); + struct kprobe_ctlblk *kcb =3D get_kprobe_ctlblk(); + unsigned long addr =3D instruction_pointer(regs); + + if (cur && (kcb->kprobe_status & (KPROBE_HIT_SS | KPROBE_REENTER)) && + ((unsigned long)&cur->ainsn.insn[1] =3D=3D addr)) { + /* Single stepping has been completed. Enable IRQs. */ + local_irq_restore(kcb->irq_flags); + post_kprobe_handler(cur, kcb, regs); + return true; + } + + preempt_enable_no_resched(); + return false; +} +NOKPROBE_SYMBOL(kprobe_singlestep_handler); + +int kprobe_fault_handler(struct pt_regs *regs, int trapnr) +{ + struct kprobe *cur =3D kprobe_running(); + struct kprobe_ctlblk *kcb =3D get_kprobe_ctlblk(); + + switch (kcb->kprobe_status) { + case KPROBE_HIT_SS: + case KPROBE_REENTER: + /* + * The instruction being single-stepped caused a page fault. + * Reset the current KProbe and set PC to the probe's address. + * Then allow the page fault handler to continue as usual. + */ + instruction_pointer_set(regs, (unsigned long)cur->addr); + + if (kcb->kprobe_status =3D=3D KPROBE_REENTER) { + restore_previous_kprobe(kcb); + } else { + local_irq_restore(kcb->irq_flags); + reset_current_kprobe(); + preempt_enable_no_resched(); + } + break; + } + + return 0; +} +NOKPROBE_SYMBOL(kprobe_fault_handler); + +int __init arch_init_kprobes(void) +{ + return 0; +} diff --git a/arch/openrisc/kernel/traps.c b/arch/openrisc/kernel/traps.c index ee87a3af34fc..ae6bfcca388e 100644 --- a/arch/openrisc/kernel/traps.c +++ b/arch/openrisc/kernel/traps.c @@ -30,10 +30,12 @@ #include #include =20 +#include #include #include #include #include +#include #include #include #include @@ -216,10 +218,34 @@ asmlinkage void do_trap(struct pt_regs *regs, unsigne= d long address) if (user_mode(regs)) { force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)regs->pc); } else { + unsigned int trap =3D *(unsigned int *)regs->pc, cpucfgr =3D mfspr(SPR_C= PUCFGR), bcode; + + /* + * Trap instruction was probably removed and no further processing + * is required. + */ + if ((trap & 0xffff0000) !=3D OPCODE_TRAP) + return; + + bcode =3D (trap & 0xffff); + switch (bcode) { + case BRK_KPROBE_BP: + if (kprobe_breakpoint_handler(regs)) + return; + break; + case BRK_KPROBE_SSTEPBP: + if (kprobe_singlestep_handler(regs)) + return; + break; + default: + break; + } + pr_emerg("KERNEL: Illegal trap exception 0x%.8lx\n", regs->pc); die("Die:", regs, SIGILL); } } +NOKPROBE_SYMBOL(do_trap) =20 asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long ad= dress) { diff --git a/arch/openrisc/lib/memcpy.c b/arch/openrisc/lib/memcpy.c index e2af9b510804..701262a40134 100644 --- a/arch/openrisc/lib/memcpy.c +++ b/arch/openrisc/lib/memcpy.c @@ -16,6 +16,7 @@ =20 #include =20 +#include #include =20 #ifdef CONFIG_OR1K_1200 @@ -122,4 +123,5 @@ void *memcpy(void *dest, __const void *src, __kernel_si= ze_t n) } #endif =20 +NOKPROBE_SYMBOL(memcpy); EXPORT_SYMBOL(memcpy); diff --git a/arch/openrisc/lib/memset.S b/arch/openrisc/lib/memset.S index c3ac2a8b68d3..14e63af12d73 100644 --- a/arch/openrisc/lib/memset.S +++ b/arch/openrisc/lib/memset.S @@ -9,6 +9,8 @@ * Copyright (C) 2015 Olof Kindgren */ =20 +#include + .global memset .type memset, @function memset: @@ -92,3 +94,5 @@ memset: =20 4: l.jr r9 l.ori r11, r3, 0 + +_ASM_NOKPROBE(memset) diff --git a/arch/openrisc/mm/fault.c b/arch/openrisc/mm/fault.c index 29e232d78d82..5263a832562f 100644 --- a/arch/openrisc/mm/fault.c +++ b/arch/openrisc/mm/fault.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include =20 @@ -55,6 +56,9 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsig= ned long address, =20 tsk =3D current; =20 + if (kprobe_page_fault(regs, vector)) + return; + /* * We fault-in kernel-space virtual memory on-demand. The * 'reference' page table is init_mm.pgd. @@ -351,3 +355,4 @@ asmlinkage void do_page_fault(struct pt_regs *regs, uns= igned long address, return; } } +NOKPROBE_SYMBOL(do_page_fault) diff --git a/samples/kprobes/kprobe_example.c b/samples/kprobes/kprobe_exam= ple.c index 53ec6c8b8c40..84e26ebef70b 100644 --- a/samples/kprobes/kprobe_example.c +++ b/samples/kprobes/kprobe_example.c @@ -59,6 +59,10 @@ static int __kprobes handler_pre(struct kprobe *p, struc= t pt_regs *regs) pr_info("<%s> p->addr =3D 0x%p, era =3D 0x%lx, estat =3D 0x%lx\n", p->symbol_name, p->addr, regs->csr_era, regs->csr_estat); #endif +#ifdef CONFIG_OPENRISC + pr_info("<%s> p->addr =3D 0x%p, pc =3D 0x%lx, status =3D 0x%lx\n", + p->symbol_name, p->addr, regs->pc, regs->sr); +#endif =20 /* A dump_stack() here will give a stack backtrace */ return 0; @@ -100,6 +104,10 @@ static void __kprobes handler_post(struct kprobe *p, s= truct pt_regs *regs, pr_info("<%s> p->addr =3D 0x%p, estat =3D 0x%lx\n", p->symbol_name, p->addr, regs->csr_estat); #endif +#ifdef CONFIG_OPENRISC + pr_info("<%s> p->addr =3D 0x%p, status =3D 0x%lx\n", + p->symbol_name, p->addr, regs->sr); +#endif } =20 static int __init kprobe_init(void) --=20 2.53.0