[v4,4/8] riscv/kprobe: Add common RVI and RVC instruction decoder code

Message ID 20221106100316.2803176-5-chenguokai17@mails.ucas.ac.cn
State New
Headers
Series Add OPTPROBES feature on RISCV |

Commit Message

Xim Nov. 6, 2022, 10:03 a.m. UTC
  From: Liao Chang <liaochang1@huawei.com>

From: Liao Chang <liaochang1@huawei.com>

This patch add code that can be used to decode RVI and RVC instructions
in searching one register for 'AUIPC/JALR'. As mentioned in previous
patch, kprobe can't be optimized until one free integer register can be
found out to save the jump target, in order to figure out the register
searching, all instructions starts from the kprobe to the last one of
function needs to decode and test if contains one candidate register.

For all RVI instruction format, the position and length of 'rs1', 'rs2'
,'rd' and 'opcode' part are uniform, but the rule of RVC instruction
format is more complicated, so it address a couple of inline functions
to decode rs1/rs2/rd for RVC.

These instruction decoder suppose to be consistent with the RVC and
RV32/RV64G instruction set list specified in the riscv instruction
reference published at August 25, 2022.

Signed-off-by: Liao Chang <liaochang1@huawei.com>
Co-developed-by: Chen Guokai <chenguokai17@mails.ucas.ac.cn>
Signed-off-by: Chen Guokai <chenguokai17@mails.ucas.ac.cn>
---
 arch/riscv/include/asm/bug.h             |   5 +-
 arch/riscv/kernel/probes/decode-insn.h   | 145 +++++++++++++++++++++++
 arch/riscv/kernel/probes/simulate-insn.h |  41 +++++++
 3 files changed, 190 insertions(+), 1 deletion(-)
  

Comments

kernel test robot Nov. 13, 2022, 4:15 a.m. UTC | #1
Hi Chen,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v6.1-rc4 next-20221111]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Chen-Guokai/Add-OPTPROBES-feature-on-RISCV/20221106-180613
patch link:    https://lore.kernel.org/r/20221106100316.2803176-5-chenguokai17%40mails.ucas.ac.cn
patch subject: [PATCH v4 4/8] riscv/kprobe: Add common RVI and RVC instruction decoder code
config: riscv-randconfig-p002-20221113
compiler: riscv32-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/0c2329bee63280ee1d9f257ed71b15e84f575344
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Chen-Guokai/Add-OPTPROBES-feature-on-RISCV/20221106-180613
        git checkout 0c2329bee63280ee1d9f257ed71b15e84f575344
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=riscv SHELL=/bin/bash arch/riscv/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   In file included from arch/riscv/kernel/probes/uprobes.c:7:
>> arch/riscv/kernel/probes/decode-insn.h:19:27: error: unknown type name 'kprobe_opcode_t'; did you mean 'uprobe_opcode_t'?
      19 | static inline u16 rvi_rs1(kprobe_opcode_t opcode)
         |                           ^~~~~~~~~~~~~~~
         |                           uprobe_opcode_t
   arch/riscv/kernel/probes/decode-insn.h:24:27: error: unknown type name 'kprobe_opcode_t'; did you mean 'uprobe_opcode_t'?
      24 | static inline u16 rvi_rs2(kprobe_opcode_t opcode)
         |                           ^~~~~~~~~~~~~~~
         |                           uprobe_opcode_t
   arch/riscv/kernel/probes/decode-insn.h:29:26: error: unknown type name 'kprobe_opcode_t'; did you mean 'uprobe_opcode_t'?
      29 | static inline u16 rvi_rd(kprobe_opcode_t opcode)
         |                          ^~~~~~~~~~~~~~~
         |                          uprobe_opcode_t
   arch/riscv/kernel/probes/decode-insn.h:34:35: error: unknown type name 'kprobe_opcode_t'; did you mean 'uprobe_opcode_t'?
      34 | static inline s32 rvi_branch_imme(kprobe_opcode_t opcode)
         |                                   ^~~~~~~~~~~~~~~
         |                                   uprobe_opcode_t
   arch/riscv/kernel/probes/decode-insn.h:46:32: error: unknown type name 'kprobe_opcode_t'; did you mean 'uprobe_opcode_t'?
      46 | static inline s32 rvi_jal_imme(kprobe_opcode_t opcode)
         |                                ^~~~~~~~~~~~~~~
         |                                uprobe_opcode_t
   arch/riscv/kernel/probes/decode-insn.h:59:29: error: unknown type name 'kprobe_opcode_t'; did you mean 'uprobe_opcode_t'?
      59 | static inline u16 rvc_r_rs1(kprobe_opcode_t opcode)
         |                             ^~~~~~~~~~~~~~~
         |                             uprobe_opcode_t
   arch/riscv/kernel/probes/decode-insn.h:64:29: error: unknown type name 'kprobe_opcode_t'; did you mean 'uprobe_opcode_t'?
      64 | static inline u16 rvc_r_rs2(kprobe_opcode_t opcode)
         |                             ^~~~~~~~~~~~~~~
         |                             uprobe_opcode_t
   arch/riscv/kernel/probes/decode-insn.h:69:28: error: unknown type name 'kprobe_opcode_t'; did you mean 'uprobe_opcode_t'?
      69 | static inline u16 rvc_r_rd(kprobe_opcode_t opcode)
         |                            ^~~~~~~~~~~~~~~
         |                            uprobe_opcode_t
   arch/riscv/kernel/probes/decode-insn.h:74:29: error: unknown type name 'kprobe_opcode_t'; did you mean 'uprobe_opcode_t'?
      74 | static inline u16 rvc_i_rs1(kprobe_opcode_t opcode)
         |                             ^~~~~~~~~~~~~~~
         |                             uprobe_opcode_t
   arch/riscv/kernel/probes/decode-insn.h:79:28: error: unknown type name 'kprobe_opcode_t'; did you mean 'uprobe_opcode_t'?
      79 | static inline u16 rvc_i_rd(kprobe_opcode_t opcode)
         |                            ^~~~~~~~~~~~~~~
         |                            uprobe_opcode_t
   arch/riscv/kernel/probes/decode-insn.h:84:30: error: unknown type name 'kprobe_opcode_t'; did you mean 'uprobe_opcode_t'?
      84 | static inline u16 rvc_ss_rs2(kprobe_opcode_t opcode)
         |                              ^~~~~~~~~~~~~~~
         |                              uprobe_opcode_t
   arch/riscv/kernel/probes/decode-insn.h:89:28: error: unknown type name 'kprobe_opcode_t'; did you mean 'uprobe_opcode_t'?
      89 | static inline u16 rvc_l_rd(kprobe_opcode_t opcode)
         |                            ^~~~~~~~~~~~~~~
         |                            uprobe_opcode_t
   arch/riscv/kernel/probes/decode-insn.h:94:28: error: unknown type name 'kprobe_opcode_t'; did you mean 'uprobe_opcode_t'?
      94 | static inline u16 rvc_l_rs(kprobe_opcode_t opcode)
         |                            ^~~~~~~~~~~~~~~
         |                            uprobe_opcode_t
   arch/riscv/kernel/probes/decode-insn.h:99:29: error: unknown type name 'kprobe_opcode_t'; did you mean 'uprobe_opcode_t'?
      99 | static inline u16 rvc_s_rs2(kprobe_opcode_t opcode)
         |                             ^~~~~~~~~~~~~~~
         |                             uprobe_opcode_t
   arch/riscv/kernel/probes/decode-insn.h:104:29: error: unknown type name 'kprobe_opcode_t'; did you mean 'uprobe_opcode_t'?
     104 | static inline u16 rvc_s_rs1(kprobe_opcode_t opcode)
         |                             ^~~~~~~~~~~~~~~
         |                             uprobe_opcode_t
   arch/riscv/kernel/probes/decode-insn.h:109:29: error: unknown type name 'kprobe_opcode_t'; did you mean 'uprobe_opcode_t'?
     109 | static inline u16 rvc_a_rs2(kprobe_opcode_t opcode)
         |                             ^~~~~~~~~~~~~~~
         |                             uprobe_opcode_t
   arch/riscv/kernel/probes/decode-insn.h:114:29: error: unknown type name 'kprobe_opcode_t'; did you mean 'uprobe_opcode_t'?
     114 | static inline u16 rvc_a_rs1(kprobe_opcode_t opcode)
         |                             ^~~~~~~~~~~~~~~
         |                             uprobe_opcode_t
   arch/riscv/kernel/probes/decode-insn.h:119:28: error: unknown type name 'kprobe_opcode_t'; did you mean 'uprobe_opcode_t'?
     119 | static inline u16 rvc_a_rd(kprobe_opcode_t opcode)
         |                            ^~~~~~~~~~~~~~~
         |                            uprobe_opcode_t
   arch/riscv/kernel/probes/decode-insn.h:124:28: error: unknown type name 'kprobe_opcode_t'; did you mean 'uprobe_opcode_t'?
     124 | static inline u16 rvc_b_rd(kprobe_opcode_t opcode)
         |                            ^~~~~~~~~~~~~~~
         |                            uprobe_opcode_t
   arch/riscv/kernel/probes/decode-insn.h:129:28: error: unknown type name 'kprobe_opcode_t'; did you mean 'uprobe_opcode_t'?
     129 | static inline u16 rvc_b_rs(kprobe_opcode_t opcode)
         |                            ^~~~~~~~~~~~~~~
         |                            uprobe_opcode_t
   arch/riscv/kernel/probes/decode-insn.h:134:35: error: unknown type name 'kprobe_opcode_t'; did you mean 'uprobe_opcode_t'?
     134 | static inline s32 rvc_branch_imme(kprobe_opcode_t opcode)
         |                                   ^~~~~~~~~~~~~~~
         |                                   uprobe_opcode_t
   arch/riscv/kernel/probes/decode-insn.h:147:32: error: unknown type name 'kprobe_opcode_t'; did you mean 'uprobe_opcode_t'?
     147 | static inline s32 rvc_jal_imme(kprobe_opcode_t opcode)
         |                                ^~~~~~~~~~~~~~~
         |                                uprobe_opcode_t


vim +19 arch/riscv/kernel/probes/decode-insn.h

    18	
  > 19	static inline u16 rvi_rs1(kprobe_opcode_t opcode)
    20	{
    21		return (u16)((opcode >> 15) & 0x1f);
    22	}
    23
  

Patch

diff --git a/arch/riscv/include/asm/bug.h b/arch/riscv/include/asm/bug.h
index 1aaea81fb141..9c33d3b58225 100644
--- a/arch/riscv/include/asm/bug.h
+++ b/arch/riscv/include/asm/bug.h
@@ -19,11 +19,14 @@ 
 #define __BUG_INSN_32	_UL(0x00100073) /* ebreak */
 #define __BUG_INSN_16	_UL(0x9002) /* c.ebreak */
 
+#define RVI_INSN_LEN	4UL
+#define RVC_INSN_LEN	2UL
+
 #define GET_INSN_LENGTH(insn)						\
 ({									\
 	unsigned long __len;						\
 	__len = ((insn & __INSN_LENGTH_MASK) == __INSN_LENGTH_32) ?	\
-		4UL : 2UL;						\
+		RVI_INSN_LEN : RVC_INSN_LEN;				\
 	__len;								\
 })
 
diff --git a/arch/riscv/kernel/probes/decode-insn.h b/arch/riscv/kernel/probes/decode-insn.h
index 42269a7d676d..1c202b0ac7d4 100644
--- a/arch/riscv/kernel/probes/decode-insn.h
+++ b/arch/riscv/kernel/probes/decode-insn.h
@@ -3,6 +3,7 @@ 
 #ifndef _RISCV_KERNEL_KPROBES_DECODE_INSN_H
 #define _RISCV_KERNEL_KPROBES_DECODE_INSN_H
 
+#include <linux/bitops.h>
 #include <asm/sections.h>
 #include <asm/kprobes.h>
 
@@ -15,4 +16,148 @@  enum probe_insn {
 enum probe_insn __kprobes
 riscv_probe_decode_insn(probe_opcode_t *addr, struct arch_probe_insn *asi);
 
+static inline u16 rvi_rs1(kprobe_opcode_t opcode)
+{
+	return (u16)((opcode >> 15) & 0x1f);
+}
+
+static inline u16 rvi_rs2(kprobe_opcode_t opcode)
+{
+	return (u16)((opcode >> 20) & 0x1f);
+}
+
+static inline u16 rvi_rd(kprobe_opcode_t opcode)
+{
+	return (u16)((opcode >> 7) & 0x1f);
+}
+
+static inline s32 rvi_branch_imme(kprobe_opcode_t opcode)
+{
+	u32 imme = 0;
+
+	imme |= (((opcode >> 8)  & 0xf)   << 1)  |
+		(((opcode >> 25) & 0x3f)  << 5)  |
+		(((opcode >> 7)  & 0x1)   << 11) |
+		(((opcode >> 31) & 0x1)   << 12);
+
+	return sign_extend32(imme, 13);
+}
+
+static inline s32 rvi_jal_imme(kprobe_opcode_t opcode)
+{
+	u32 imme = 0;
+
+	imme |= (((opcode >> 21) & 0x3ff) << 1)  |
+		(((opcode >> 20) & 0x1)   << 11) |
+		(((opcode >> 12) & 0xff)  << 12) |
+		(((opcode >> 31) & 0x1)   << 20);
+
+	return sign_extend32(imme, 21);
+}
+
+#ifdef CONFIG_RISCV_ISA_C
+static inline u16 rvc_r_rs1(kprobe_opcode_t opcode)
+{
+	return (u16)((opcode >> 2) & 0x1f);
+}
+
+static inline u16 rvc_r_rs2(kprobe_opcode_t opcode)
+{
+	return (u16)((opcode >> 2) & 0x1f);
+}
+
+static inline u16 rvc_r_rd(kprobe_opcode_t opcode)
+{
+	return rvc_r_rs1(opcode);
+}
+
+static inline u16 rvc_i_rs1(kprobe_opcode_t opcode)
+{
+	return (u16)((opcode >> 7) & 0x1f);
+}
+
+static inline u16 rvc_i_rd(kprobe_opcode_t opcode)
+{
+	return rvc_i_rs1(opcode);
+}
+
+static inline u16 rvc_ss_rs2(kprobe_opcode_t opcode)
+{
+	return (u16)((opcode >> 2) & 0x1f);
+}
+
+static inline u16 rvc_l_rd(kprobe_opcode_t opcode)
+{
+	return (u16)((opcode >> 2) & 0x7);
+}
+
+static inline u16 rvc_l_rs(kprobe_opcode_t opcode)
+{
+	return (u16)((opcode >> 7) & 0x7);
+}
+
+static inline u16 rvc_s_rs2(kprobe_opcode_t opcode)
+{
+	return (u16)((opcode >> 2) & 0x7);
+}
+
+static inline u16 rvc_s_rs1(kprobe_opcode_t opcode)
+{
+	return (u16)((opcode >> 7) & 0x7);
+}
+
+static inline u16 rvc_a_rs2(kprobe_opcode_t opcode)
+{
+	return (u16)((opcode >> 2) & 0x7);
+}
+
+static inline u16 rvc_a_rs1(kprobe_opcode_t opcode)
+{
+	return (u16)((opcode >> 7) & 0x7);
+}
+
+static inline u16 rvc_a_rd(kprobe_opcode_t opcode)
+{
+	return rvc_a_rs1(opcode);
+}
+
+static inline u16 rvc_b_rd(kprobe_opcode_t opcode)
+{
+	return (u16)((opcode >> 7) & 0x7);
+}
+
+static inline u16 rvc_b_rs(kprobe_opcode_t opcode)
+{
+	return rvc_b_rd(opcode);
+}
+
+static inline s32 rvc_branch_imme(kprobe_opcode_t opcode)
+{
+	u32 imme = 0;
+
+	imme |= (((opcode >> 3)  & 0x3) << 1) |
+		(((opcode >> 10) & 0x3) << 3) |
+		(((opcode >> 2)  & 0x1) << 5) |
+		(((opcode >> 5)  & 0x3) << 6) |
+		(((opcode >> 12) & 0x1) << 8);
+
+	return sign_extend32(imme, 9);
+}
+
+static inline s32 rvc_jal_imme(kprobe_opcode_t opcode)
+{
+	u32 imme = 0;
+
+	imme |= (((opcode >> 3)  & 0x3) << 1) |
+		(((opcode >> 11) & 0x1) << 4) |
+		(((opcode >> 2)  & 0x1) << 5) |
+		(((opcode >> 7)  & 0x1) << 6) |
+		(((opcode >> 6)  & 0x1) << 7) |
+		(((opcode >> 9)  & 0x3) << 8) |
+		(((opcode >> 8)  & 0x1) << 10) |
+		(((opcode >> 12) & 0x1) << 11);
+
+	return sign_extend32(imme, 12);
+}
+#endif /* CONFIG_RISCV_ISA_C */
 #endif /* _RISCV_KERNEL_KPROBES_DECODE_INSN_H */
diff --git a/arch/riscv/kernel/probes/simulate-insn.h b/arch/riscv/kernel/probes/simulate-insn.h
index cb6ff7dccb92..74d8c1ba9064 100644
--- a/arch/riscv/kernel/probes/simulate-insn.h
+++ b/arch/riscv/kernel/probes/simulate-insn.h
@@ -37,6 +37,40 @@  __RISCV_INSN_FUNCS(c_jalr,	0xf007, 0x9002);
 __RISCV_INSN_FUNCS(c_beqz,	0xe003, 0xc001);
 __RISCV_INSN_FUNCS(c_bnez,	0xe003, 0xe001);
 __RISCV_INSN_FUNCS(c_ebreak,	0xffff, 0x9002);
+/* RVC(S) instructions contain rs1 and rs2 */
+__RISCV_INSN_FUNCS(c_sq,	0xe003, 0xa000);
+__RISCV_INSN_FUNCS(c_sw,	0xe003, 0xc000);
+__RISCV_INSN_FUNCS(c_sd,	0xe003, 0xe000);
+/* RVC(A) instructions contain rs1 and rs2 */
+__RISCV_INSN_FUNCS(c_sub,	0xfc03, 0x8c01);
+__RISCV_INSN_FUNCS(c_subw,	0xfc43, 0x9c01);
+/* RVC(L) instructions contain rs1 */
+__RISCV_INSN_FUNCS(c_lq,	0xe003, 0x2000);
+__RISCV_INSN_FUNCS(c_lw,	0xe003, 0x4000);
+__RISCV_INSN_FUNCS(c_ld,	0xe003, 0x6000);
+/* RVC(I) instructions contain rs1 */
+__RISCV_INSN_FUNCS(c_addi,	0xe003, 0x0001);
+__RISCV_INSN_FUNCS(c_addiw,	0xe003, 0x2001);
+__RISCV_INSN_FUNCS(c_addi16sp,	0xe183, 0x6101);
+__RISCV_INSN_FUNCS(c_slli,	0xe003, 0x0002);
+/* RVC(B) instructions contain rs1 */
+__RISCV_INSN_FUNCS(c_sri,	0xe803, 0x8001);
+__RISCV_INSN_FUNCS(c_andi,	0xec03, 0x8801);
+/* RVC(SS) instructions contain rs2 */
+__RISCV_INSN_FUNCS(c_sqsp,	0xe003, 0xa002);
+__RISCV_INSN_FUNCS(c_swsp,	0xe003, 0xc002);
+__RISCV_INSN_FUNCS(c_sdsp,	0xe003, 0xe002);
+/* RVC(R) instructions contain rs2 and rd */
+__RISCV_INSN_FUNCS(c_mv,	0xe003, 0x8002);
+/* RVC(I) instructions contain sp and rd */
+__RISCV_INSN_FUNCS(c_lqsp,	0xe003, 0x2002);
+__RISCV_INSN_FUNCS(c_lwsp,	0xe003, 0x4002);
+__RISCV_INSN_FUNCS(c_ldsp,	0xe003, 0x6002);
+/* RVC(CW) instructions contain sp and rd */
+__RISCV_INSN_FUNCS(c_addi4spn,	0xe003, 0x0000);
+/* RVC(I) instructions contain rd */
+__RISCV_INSN_FUNCS(c_li,	0xe003, 0x4001);
+__RISCV_INSN_FUNCS(c_lui,	0xe003, 0x6001);
 
 __RISCV_INSN_FUNCS(auipc,	0x7f, 0x17);
 __RISCV_INSN_FUNCS(branch,	0x7f, 0x63);
@@ -44,4 +78,11 @@  __RISCV_INSN_FUNCS(branch,	0x7f, 0x63);
 __RISCV_INSN_FUNCS(jal,		0x7f, 0x6f);
 __RISCV_INSN_FUNCS(jalr,	0x707f, 0x67);
 
+__RISCV_INSN_FUNCS(arith_rr,	0x77, 0x33);
+__RISCV_INSN_FUNCS(arith_ri,	0x77, 0x13);
+__RISCV_INSN_FUNCS(lui,		0x7f, 0x37);
+__RISCV_INSN_FUNCS(load,	0x7f, 0x03);
+__RISCV_INSN_FUNCS(store,	0x7f, 0x23);
+__RISCV_INSN_FUNCS(amo,		0x7f, 0x2f);
+
 #endif /* _RISCV_KERNEL_PROBES_SIMULATE_INSN_H */