diff mbox series

[RFC,v2,riscv/for-next,5/5] riscv: align arch_static_branch function

Message ID 20220913094252.3555240-6-andy.chiu@sifive.com (mailing list archive)
State New, archived
Headers show
Series Enable ftrace with kernel preemption for RISC-V | expand

Commit Message

Andy Chiu Sept. 13, 2022, 9:42 a.m. UTC
runtime code patching must be done at a naturally aligned address, or we
may execute on a partial instruction.

Signed-off-by: Andy Chiu <andy.chiu@sifive.com>
Reviewed-by: Greentime Hu <greentime.hu@sifive.com>
---
 arch/riscv/include/asm/jump_label.h | 2 ++
 1 file changed, 2 insertions(+)

Comments

Guo Ren Sept. 14, 2022, 2:06 p.m. UTC | #1
Is this patch related to this series?

On Tue, Sep 13, 2022 at 5:44 PM Andy Chiu <andy.chiu@sifive.com> wrote:
>
> runtime code patching must be done at a naturally aligned address, or we
> may execute on a partial instruction.
If it's true, we can't use static branches at all. Have you
encountered a problem?

If you are right, arm64 ... csky all need the patch.


>
> Signed-off-by: Andy Chiu <andy.chiu@sifive.com>
> Reviewed-by: Greentime Hu <greentime.hu@sifive.com>
> ---
>  arch/riscv/include/asm/jump_label.h | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/arch/riscv/include/asm/jump_label.h b/arch/riscv/include/asm/jump_label.h
> index 38af2ec7b9bf..729991e8f782 100644
> --- a/arch/riscv/include/asm/jump_label.h
> +++ b/arch/riscv/include/asm/jump_label.h
> @@ -18,6 +18,7 @@ static __always_inline bool arch_static_branch(struct static_key *key,
>                                                bool branch)
>  {
>         asm_volatile_goto(
> +               "       .align          2                       \n\t"
>                 "       .option push                            \n\t"
>                 "       .option norelax                         \n\t"
>                 "       .option norvc                           \n\t"
> @@ -39,6 +40,7 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key,
>                                                     bool branch)
>  {
>         asm_volatile_goto(
> +               "       .align          2                       \n\t"
>                 "       .option push                            \n\t"
>                 "       .option norelax                         \n\t"
>                 "       .option norvc                           \n\t"
> --
> 2.36.0
>
Jessica Clarke Sept. 14, 2022, 2:24 p.m. UTC | #2
On 13 Sept 2022, at 10:42, Andy Chiu <andy.chiu@sifive.com> wrote:
> 
> runtime code patching must be done at a naturally aligned address, or we
> may execute on a partial instruction.
> 
> Signed-off-by: Andy Chiu <andy.chiu@sifive.com>
> Reviewed-by: Greentime Hu <greentime.hu@sifive.com>
> ---
> arch/riscv/include/asm/jump_label.h | 2 ++
> 1 file changed, 2 insertions(+)
> 
> diff --git a/arch/riscv/include/asm/jump_label.h b/arch/riscv/include/asm/jump_label.h
> index 38af2ec7b9bf..729991e8f782 100644
> --- a/arch/riscv/include/asm/jump_label.h
> +++ b/arch/riscv/include/asm/jump_label.h
> @@ -18,6 +18,7 @@ static __always_inline bool arch_static_branch(struct static_key *key,
> 					       bool branch)
> {
> 	asm_volatile_goto(
> +		"	.align		2			\n\t"

.align is a horrible directive whose meaning changes between
architectures and requires careful thought, especially when the
argument is a power of 2. Better to use .balign 4, or .p2align 2 if you
really want to for some reason.

Jess

> 		"	.option push				\n\t"
> 		"	.option norelax				\n\t"
> 		"	.option norvc				\n\t"
> @@ -39,6 +40,7 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key,
> 						    bool branch)
> {
> 	asm_volatile_goto(
> +		"	.align		2			\n\t"
> 		"	.option push				\n\t"
> 		"	.option norelax				\n\t"
> 		"	.option norvc				\n\t"
> -- 
> 2.36.0
> 
> 
> _______________________________________________
> linux-riscv mailing list
> linux-riscv@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv
Guo Ren Sept. 15, 2022, 1:47 a.m. UTC | #3
On Wed, Sep 14, 2022 at 10:24 PM Jessica Clarke <jrtc27@jrtc27.com> wrote:
>
> On 13 Sept 2022, at 10:42, Andy Chiu <andy.chiu@sifive.com> wrote:
> >
> > runtime code patching must be done at a naturally aligned address, or we
> > may execute on a partial instruction.
> >
> > Signed-off-by: Andy Chiu <andy.chiu@sifive.com>
> > Reviewed-by: Greentime Hu <greentime.hu@sifive.com>
> > ---
> > arch/riscv/include/asm/jump_label.h | 2 ++
> > 1 file changed, 2 insertions(+)
> >
> > diff --git a/arch/riscv/include/asm/jump_label.h b/arch/riscv/include/asm/jump_label.h
> > index 38af2ec7b9bf..729991e8f782 100644
> > --- a/arch/riscv/include/asm/jump_label.h
> > +++ b/arch/riscv/include/asm/jump_label.h
> > @@ -18,6 +18,7 @@ static __always_inline bool arch_static_branch(struct static_key *key,
> >                                              bool branch)
> > {
> >       asm_volatile_goto(
> > +             "       .align          2                       \n\t"
>
> .align is a horrible directive whose meaning changes between
> architectures and requires careful thought, especially when the
> argument is a power of 2. Better to use .balign 4, or .p2align 2 if you
> really want to for some reason.
Do we really need to align here? Should it be naturally done by the compiler?

>
> Jess
>
> >               "       .option push                            \n\t"
> >               "       .option norelax                         \n\t"
> >               "       .option norvc                           \n\t"
> > @@ -39,6 +40,7 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key,
> >                                                   bool branch)
> > {
> >       asm_volatile_goto(
> > +             "       .align          2                       \n\t"
> >               "       .option push                            \n\t"
> >               "       .option norelax                         \n\t"
> >               "       .option norvc                           \n\t"
> > --
> > 2.36.0
> >
> >
> > _______________________________________________
> > linux-riscv mailing list
> > linux-riscv@lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/linux-riscv
>
Jessica Clarke Sept. 15, 2022, 2:34 a.m. UTC | #4
On 15 Sept 2022, at 02:47, Guo Ren <guoren@kernel.org> wrote:
> 
> On Wed, Sep 14, 2022 at 10:24 PM Jessica Clarke <jrtc27@jrtc27.com> wrote:
>> 
>> On 13 Sept 2022, at 10:42, Andy Chiu <andy.chiu@sifive.com> wrote:
>>> 
>>> runtime code patching must be done at a naturally aligned address, or we
>>> may execute on a partial instruction.
>>> 
>>> Signed-off-by: Andy Chiu <andy.chiu@sifive.com>
>>> Reviewed-by: Greentime Hu <greentime.hu@sifive.com>
>>> ---
>>> arch/riscv/include/asm/jump_label.h | 2 ++
>>> 1 file changed, 2 insertions(+)
>>> 
>>> diff --git a/arch/riscv/include/asm/jump_label.h b/arch/riscv/include/asm/jump_label.h
>>> index 38af2ec7b9bf..729991e8f782 100644
>>> --- a/arch/riscv/include/asm/jump_label.h
>>> +++ b/arch/riscv/include/asm/jump_label.h
>>> @@ -18,6 +18,7 @@ static __always_inline bool arch_static_branch(struct static_key *key,
>>> bool branch)
>>> {
>>> asm_volatile_goto(
>>> + " .align 2 \n\t"
>> 
>> .align is a horrible directive whose meaning changes between
>> architectures and requires careful thought, especially when the
>> argument is a power of 2. Better to use .balign 4, or .p2align 2 if you
>> really want to for some reason.
> Do we really need to align here? Should it be naturally done by the compiler?

Compilers don’t add alignment do inline assembly beyond what’s needed.
And assemblers won’t align beyond what the architecture requires here
either as far as I know for .option rvc, since normally you still have
an RVC-capable processor you just don’t want compressed instructions at
that specific point.

Jess

>> 
>> Jess
>> 
>>> " .option push \n\t"
>>> " .option norelax \n\t"
>>> " .option norvc \n\t"
>>> @@ -39,6 +40,7 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key,
>>> bool branch)
>>> {
>>> asm_volatile_goto(
>>> + " .align 2 \n\t"
>>> " .option push \n\t"
>>> " .option norelax \n\t"
>>> " .option norvc \n\t"
>>> --
>>> 2.36.0
>>> 
>>> 
>>> _______________________________________________
>>> linux-riscv mailing list
>>> linux-riscv@lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/linux-riscv
>> 
> 
> 
> -- 
> Best Regards
> Guo Ren
Andy Chiu Sept. 16, 2022, 11:54 p.m. UTC | #5
Hi Guo,

Sorry for sending it again, I forgot to send in plain-text on the last mail.

On Wed, Sep 14, 2022 at 3:06 PM Guo Ren <guoren@kernel.org> wrote:
>
> Is this patch related to this series?
>

This is related to dynamic code patching but not the mechanism of
"function tracer" itself. You are right, I should submit another patch
for that.

> On Tue, Sep 13, 2022 at 5:44 PM Andy Chiu <andy.chiu@sifive.com> wrote:
> >
> > runtime code patching must be done at a naturally aligned address, or we
> > may execute on a partial instruction.
> If it's true, we can't use static branches at all. Have you
> encountered a problem?
>
> If you are right, arm64 ... csky all need the patch.
>
In fact we have run into problems that traced back to static jump
functions during the test. We switched tracer randomly for every 1~5
seconds on a dual-core QEMU setup and found the kernel stucking at a
static branch where it jumps to itself. The reason is that the static
branch was 2-byte but not 4-byte aligned. Then, the kernel would patch
the instruction, either J or NOP, with 2 half-word stores, if the
machine does not have efficient unaligned accesses. Thus, there exists
moments where a half of the NOP mixes with the other half of the J
when transitioning the branch. In our particular case, on a
little-endian machine, the upper half of the NOP was mixed with the
lower part of the J when enabling the branch, resulting in a jump that
jumped to itself. On the other way, it would result in a HINT
instruction when disabling the branch, but it might not be observable.

ARM64 does not have this problem since all instructions must be 4-byte aligned.

Regards,
Andy
Guo Ren Sept. 17, 2022, 12:22 a.m. UTC | #6
On Sat, Sep 17, 2022 at 7:54 AM Andy Chiu <andy.chiu@sifive.com> wrote:
>
> Hi Guo,
>
> Sorry for sending it again, I forgot to send in plain-text on the last mail.
>
> On Wed, Sep 14, 2022 at 3:06 PM Guo Ren <guoren@kernel.org> wrote:
> >
> > Is this patch related to this series?
> >
>
> This is related to dynamic code patching but not the mechanism of
> "function tracer" itself. You are right, I should submit another patch
> for that.
>
> > On Tue, Sep 13, 2022 at 5:44 PM Andy Chiu <andy.chiu@sifive.com> wrote:
> > >
> > > runtime code patching must be done at a naturally aligned address, or we
> > > may execute on a partial instruction.
> > If it's true, we can't use static branches at all. Have you
> > encountered a problem?
> >
> > If you are right, arm64 ... csky all need the patch.
> >
> In fact we have run into problems that traced back to static jump
> functions during the test. We switched tracer randomly for every 1~5
> seconds on a dual-core QEMU setup and found the kernel stucking at a
> static branch where it jumps to itself. The reason is that the static
> branch was 2-byte but not 4-byte aligned. Then, the kernel would patch
> the instruction, either J or NOP, with 2 half-word stores, if the
> machine does not have efficient unaligned accesses. Thus, there exists
> moments where a half of the NOP mixes with the other half of the J
> when transitioning the branch. In our particular case, on a
> little-endian machine, the upper half of the NOP was mixed with the
> lower part of the J when enabling the branch, resulting in a jump that
> jumped to itself. On the other way, it would result in a HINT
> instruction when disabling the branch, but it might not be observable.
How about limiting the static branch to 16-bit instruction? (nop16 - br16)

>
> ARM64 does not have this problem since all instructions must be 4-byte aligned.
But, csky does (16+32). Thx.
>
> Regards,
> Andy
Guo Ren Sept. 17, 2022, 6:38 p.m. UTC | #7
From: Guo Ren <guoren@linux.alibaba.com>

Reduce size of static branch.

Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
Signed-off-by: Guo Ren <guoren@kernel.org>
---
 arch/riscv/include/asm/jump_label.h | 17 ++++++++++-----
 arch/riscv/kernel/jump_label.c      | 32 +++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+), 5 deletions(-)

diff --git a/arch/riscv/include/asm/jump_label.h b/arch/riscv/include/asm/jump_label.h
index 38af2ec7b9bf..78f747dfa8a2 100644
--- a/arch/riscv/include/asm/jump_label.h
+++ b/arch/riscv/include/asm/jump_label.h
@@ -12,17 +12,21 @@
 #include <linux/types.h>
 #include <asm/asm.h>
 
+#ifdef CONFIG_RISCV_ISA_C
+#define JUMP_LABEL_NOP_SIZE 2
+#else
 #define JUMP_LABEL_NOP_SIZE 4
+#endif
 
 static __always_inline bool arch_static_branch(struct static_key *key,
 					       bool branch)
 {
 	asm_volatile_goto(
-		"	.option push				\n\t"
-		"	.option norelax				\n\t"
-		"	.option norvc				\n\t"
+#ifdef CONFIG_RISCV_ISA_C
+		"1:	c.nop					\n\t"
+#else
 		"1:	nop					\n\t"
-		"	.option pop				\n\t"
+#endif
 		"	.pushsection	__jump_table, \"aw\"	\n\t"
 		"	.align		" RISCV_LGPTR "		\n\t"
 		"	.long		1b - ., %l[label] - .	\n\t"
@@ -39,11 +43,14 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key,
 						    bool branch)
 {
 	asm_volatile_goto(
+#ifdef CONFIG_RISCV_ISA_C
+		"1:	c.j		%l[label]		\n\t"
+#else
 		"	.option push				\n\t"
 		"	.option norelax				\n\t"
-		"	.option norvc				\n\t"
 		"1:	jal		zero, %l[label]		\n\t"
 		"	.option pop				\n\t"
+#endif
 		"	.pushsection	__jump_table, \"aw\"	\n\t"
 		"	.align		" RISCV_LGPTR "		\n\t"
 		"	.long		1b - ., %l[label] - .	\n\t"
diff --git a/arch/riscv/kernel/jump_label.c b/arch/riscv/kernel/jump_label.c
index e6694759dbd0..64a4e5df093d 100644
--- a/arch/riscv/kernel/jump_label.c
+++ b/arch/riscv/kernel/jump_label.c
@@ -11,21 +11,52 @@
 #include <asm/bug.h>
 #include <asm/patch.h>
 
+#ifdef CONFIG_RISCV_ISA_C
+#define RISCV_INSN_C_NOP 0x0001U
+#define RISCV_INSN_C_JAL 0xa001U
+#else
 #define RISCV_INSN_NOP 0x00000013U
 #define RISCV_INSN_JAL 0x0000006fU
+#endif
 
 void arch_jump_label_transform(struct jump_entry *entry,
 			       enum jump_label_type type)
 {
 	void *addr = (void *)jump_entry_code(entry);
+#ifdef CONFIG_RISCV_ISA_C
+	u16 insn;
+#else
 	u32 insn;
+#endif
 
 	if (type == JUMP_LABEL_JMP) {
 		long offset = jump_entry_target(entry) - jump_entry_code(entry);
+#ifdef CONFIG_RISCV_ISA_C
+		if (WARN_ON(offset & 1 || offset < -2048 || offset >= 2048))
+			return;
 
+		/*
+		 * 001 | imm[11|4|9:8|10|6|7|3:1|5] 01 - C.JAL
+		 */
+		insn = RISCV_INSN_C_JAL |
+			(((u16)offset & GENMASK(5, 5)) >> (5 - 2)) |
+			(((u16)offset & GENMASK(3, 1)) << (3 - 1)) |
+			(((u16)offset & GENMASK(7, 7)) >> (7 - 6)) |
+			(((u16)offset & GENMASK(6, 6)) << (7 - 6)) |
+			(((u16)offset & GENMASK(10, 10)) >> (10 - 8)) |
+			(((u16)offset & GENMASK(9, 8)) << (9 - 8)) |
+			(((u16)offset & GENMASK(4, 4)) << (11 - 4)) |
+			(((u16)offset & GENMASK(11, 11)) << (12 - 11));
+	} else {
+		insn = RISCV_INSN_C_NOP;
+	}
+#else
 		if (WARN_ON(offset & 1 || offset < -524288 || offset >= 524288))
 			return;
 
+		/*
+		 * imm[20|10:1|11|19:12] | rd | 1101111 - JAL
+		 */
 		insn = RISCV_INSN_JAL |
 			(((u32)offset & GENMASK(19, 12)) << (12 - 12)) |
 			(((u32)offset & GENMASK(11, 11)) << (20 - 11)) |
@@ -34,6 +65,7 @@ void arch_jump_label_transform(struct jump_entry *entry,
 	} else {
 		insn = RISCV_INSN_NOP;
 	}
+#endif
 
 	mutex_lock(&text_mutex);
 	patch_text_nosync(addr, &insn, sizeof(insn));
Guo Ren Sept. 17, 2022, 11:49 p.m. UTC | #8
On Sun, Sep 18, 2022 at 2:39 AM <guoren@kernel.org> wrote:
>
> From: Guo Ren <guoren@linux.alibaba.com>
>
> Reduce size of static branch.
>
> Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
> Signed-off-by: Guo Ren <guoren@kernel.org>
> ---
>  arch/riscv/include/asm/jump_label.h | 17 ++++++++++-----
>  arch/riscv/kernel/jump_label.c      | 32 +++++++++++++++++++++++++++++
>  2 files changed, 44 insertions(+), 5 deletions(-)
>
> diff --git a/arch/riscv/include/asm/jump_label.h b/arch/riscv/include/asm/jump_label.h
> index 38af2ec7b9bf..78f747dfa8a2 100644
> --- a/arch/riscv/include/asm/jump_label.h
> +++ b/arch/riscv/include/asm/jump_label.h
> @@ -12,17 +12,21 @@
>  #include <linux/types.h>
>  #include <asm/asm.h>
>
> +#ifdef CONFIG_RISCV_ISA_C
> +#define JUMP_LABEL_NOP_SIZE 2
> +#else
>  #define JUMP_LABEL_NOP_SIZE 4
> +#endif
>
>  static __always_inline bool arch_static_branch(struct static_key *key,
>                                                bool branch)
>  {
>         asm_volatile_goto(
> -               "       .option push                            \n\t"
> -               "       .option norelax                         \n\t"
> -               "       .option norvc                           \n\t"
> +#ifdef CONFIG_RISCV_ISA_C
> +               "1:     c.nop                                   \n\t"
> +#else
>                 "1:     nop                                     \n\t"
> -               "       .option pop                             \n\t"
> +#endif
>                 "       .pushsection    __jump_table, \"aw\"    \n\t"
>                 "       .align          " RISCV_LGPTR "         \n\t"
>                 "       .long           1b - ., %l[label] - .   \n\t"
> @@ -39,11 +43,14 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key,
>                                                     bool branch)
>  {
>         asm_volatile_goto(
> +#ifdef CONFIG_RISCV_ISA_C
> +               "1:     c.j             %l[label]               \n\t"
> +#else
>                 "       .option push                            \n\t"
>                 "       .option norelax                         \n\t"
> -               "       .option norvc                           \n\t"
>                 "1:     jal             zero, %l[label]         \n\t"
>                 "       .option pop                             \n\t"
> +#endif
>                 "       .pushsection    __jump_table, \"aw\"    \n\t"
>                 "       .align          " RISCV_LGPTR "         \n\t"
>                 "       .long           1b - ., %l[label] - .   \n\t"
> diff --git a/arch/riscv/kernel/jump_label.c b/arch/riscv/kernel/jump_label.c
> index e6694759dbd0..64a4e5df093d 100644
> --- a/arch/riscv/kernel/jump_label.c
> +++ b/arch/riscv/kernel/jump_label.c
> @@ -11,21 +11,52 @@
>  #include <asm/bug.h>
>  #include <asm/patch.h>
>
> +#ifdef CONFIG_RISCV_ISA_C
> +#define RISCV_INSN_C_NOP 0x0001U
> +#define RISCV_INSN_C_JAL 0xa001U
> +#else
>  #define RISCV_INSN_NOP 0x00000013U
>  #define RISCV_INSN_JAL 0x0000006fU
> +#endif
>
>  void arch_jump_label_transform(struct jump_entry *entry,
>                                enum jump_label_type type)
>  {
>         void *addr = (void *)jump_entry_code(entry);
> +#ifdef CONFIG_RISCV_ISA_C
> +       u16 insn;
> +#else
>         u32 insn;
> +#endif
>
>         if (type == JUMP_LABEL_JMP) {
>                 long offset = jump_entry_target(entry) - jump_entry_code(entry);
> +#ifdef CONFIG_RISCV_ISA_C
> +               if (WARN_ON(offset & 1 || offset < -2048 || offset >= 2048))
> +                       return;
>
> +               /*
> +                * 001 | imm[11|4|9:8|10|6|7|3:1|5] 01 - C.JAL
> +                */
> +               insn = RISCV_INSN_C_JAL |
> +                       (((u16)offset & GENMASK(5, 5)) >> (5 - 2)) |
> +                       (((u16)offset & GENMASK(3, 1)) << (3 - 1)) |
> +                       (((u16)offset & GENMASK(7, 7)) >> (7 - 6)) |
> +                       (((u16)offset & GENMASK(6, 6)) << (7 - 6)) |
> +                       (((u16)offset & GENMASK(10, 10)) >> (10 - 8)) |
> +                       (((u16)offset & GENMASK(9, 8)) << (9 - 8)) |
> +                       (((u16)offset & GENMASK(4, 4)) << (11 - 4)) |
> +                       (((u16)offset & GENMASK(11, 11)) << (12 - 11));
> +       } else {
> +               insn = RISCV_INSN_C_NOP;
> +       }
> +#else
>                 if (WARN_ON(offset & 1 || offset < -524288 || offset >= 524288))
For the unify, it also should be:
if (WARN_ON(offset & 1 || offset < -2048 || offset >= 2048))



>                         return;
>
> +               /*
> +                * imm[20|10:1|11|19:12] | rd | 1101111 - JAL
> +                */
>                 insn = RISCV_INSN_JAL |
>                         (((u32)offset & GENMASK(19, 12)) << (12 - 12)) |
>                         (((u32)offset & GENMASK(11, 11)) << (20 - 11)) |
> @@ -34,6 +65,7 @@ void arch_jump_label_transform(struct jump_entry *entry,
>         } else {
>                 insn = RISCV_INSN_NOP;
>         }
> +#endif
>
>         mutex_lock(&text_mutex);
>         patch_text_nosync(addr, &insn, sizeof(insn));
> --
> 2.36.1
>
Guo Ren Sept. 17, 2022, 11:59 p.m. UTC | #9
On Sun, Sep 18, 2022 at 2:39 AM <guoren@kernel.org> wrote:
>
> From: Guo Ren <guoren@linux.alibaba.com>
>
> Reduce size of static branch.
>
> Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
> Signed-off-by: Guo Ren <guoren@kernel.org>
> ---
>  arch/riscv/include/asm/jump_label.h | 17 ++++++++++-----
>  arch/riscv/kernel/jump_label.c      | 32 +++++++++++++++++++++++++++++
>  2 files changed, 44 insertions(+), 5 deletions(-)
>
> diff --git a/arch/riscv/include/asm/jump_label.h b/arch/riscv/include/asm/jump_label.h
> index 38af2ec7b9bf..78f747dfa8a2 100644
> --- a/arch/riscv/include/asm/jump_label.h
> +++ b/arch/riscv/include/asm/jump_label.h
> @@ -12,17 +12,21 @@
>  #include <linux/types.h>
>  #include <asm/asm.h>
>
> +#ifdef CONFIG_RISCV_ISA_C
> +#define JUMP_LABEL_NOP_SIZE 2
> +#else
>  #define JUMP_LABEL_NOP_SIZE 4
> +#endif
>
>  static __always_inline bool arch_static_branch(struct static_key *key,
>                                                bool branch)
>  {
>         asm_volatile_goto(
> -               "       .option push                            \n\t"
> -               "       .option norelax                         \n\t"
> -               "       .option norvc                           \n\t"
> +#ifdef CONFIG_RISCV_ISA_C
> +               "1:     c.nop                                   \n\t"
> +#else
>                 "1:     nop                                     \n\t"
> -               "       .option pop                             \n\t"
> +#endif
>                 "       .pushsection    __jump_table, \"aw\"    \n\t"
>                 "       .align          " RISCV_LGPTR "         \n\t"
>                 "       .long           1b - ., %l[label] - .   \n\t"
We should check the range during compile time, here. Run-time checking
is the last and most painful method to prevent some errors.

> @@ -39,11 +43,14 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key,
>                                                     bool branch)
>  {
>         asm_volatile_goto(
> +#ifdef CONFIG_RISCV_ISA_C
> +               "1:     c.j             %l[label]               \n\t"
> +#else
>                 "       .option push                            \n\t"
>                 "       .option norelax                         \n\t"
> -               "       .option norvc                           \n\t"
>                 "1:     jal             zero, %l[label]         \n\t"
>                 "       .option pop                             \n\t"
> +#endif
>                 "       .pushsection    __jump_table, \"aw\"    \n\t"
>                 "       .align          " RISCV_LGPTR "         \n\t"
>                 "       .long           1b - ., %l[label] - .   \n\t"
> diff --git a/arch/riscv/kernel/jump_label.c b/arch/riscv/kernel/jump_label.c
> index e6694759dbd0..64a4e5df093d 100644
> --- a/arch/riscv/kernel/jump_label.c
> +++ b/arch/riscv/kernel/jump_label.c
> @@ -11,21 +11,52 @@
>  #include <asm/bug.h>
>  #include <asm/patch.h>
>
> +#ifdef CONFIG_RISCV_ISA_C
> +#define RISCV_INSN_C_NOP 0x0001U
> +#define RISCV_INSN_C_JAL 0xa001U
> +#else
>  #define RISCV_INSN_NOP 0x00000013U
>  #define RISCV_INSN_JAL 0x0000006fU
> +#endif
>
>  void arch_jump_label_transform(struct jump_entry *entry,
>                                enum jump_label_type type)
>  {
>         void *addr = (void *)jump_entry_code(entry);
> +#ifdef CONFIG_RISCV_ISA_C
> +       u16 insn;
> +#else
>         u32 insn;
> +#endif
>
>         if (type == JUMP_LABEL_JMP) {
>                 long offset = jump_entry_target(entry) - jump_entry_code(entry);
> +#ifdef CONFIG_RISCV_ISA_C
> +               if (WARN_ON(offset & 1 || offset < -2048 || offset >= 2048))
> +                       return;
>
> +               /*
> +                * 001 | imm[11|4|9:8|10|6|7|3:1|5] 01 - C.JAL
> +                */
> +               insn = RISCV_INSN_C_JAL |
> +                       (((u16)offset & GENMASK(5, 5)) >> (5 - 2)) |
> +                       (((u16)offset & GENMASK(3, 1)) << (3 - 1)) |
> +                       (((u16)offset & GENMASK(7, 7)) >> (7 - 6)) |
> +                       (((u16)offset & GENMASK(6, 6)) << (7 - 6)) |
> +                       (((u16)offset & GENMASK(10, 10)) >> (10 - 8)) |
> +                       (((u16)offset & GENMASK(9, 8)) << (9 - 8)) |
> +                       (((u16)offset & GENMASK(4, 4)) << (11 - 4)) |
> +                       (((u16)offset & GENMASK(11, 11)) << (12 - 11));
> +       } else {
> +               insn = RISCV_INSN_C_NOP;
> +       }
> +#else
>                 if (WARN_ON(offset & 1 || offset < -524288 || offset >= 524288))
For the unify, it also should be:
                   if (WARN_ON(offset & 1 || offset < -2048 || offset >= 2048))

After some tests, 2048 is enough for the current riscv Linux.

>                         return;
>
> +               /*
> +                * imm[20|10:1|11|19:12] | rd | 1101111 - JAL
> +                */
>                 insn = RISCV_INSN_JAL |
>                         (((u32)offset & GENMASK(19, 12)) << (12 - 12)) |
>                         (((u32)offset & GENMASK(11, 11)) << (20 - 11)) |
> @@ -34,6 +65,7 @@ void arch_jump_label_transform(struct jump_entry *entry,
>         } else {
>                 insn = RISCV_INSN_NOP;
>         }
> +#endif
>
>         mutex_lock(&text_mutex);
>         patch_text_nosync(addr, &insn, sizeof(insn));
> --
> 2.36.1
>
Jessica Clarke Sept. 18, 2022, 12:12 a.m. UTC | #10
On 17 Sept 2022, at 19:38, guoren@kernel.org wrote:
> 
> From: Guo Ren <guoren@linux.alibaba.com>
> 
> Reduce size of static branch.
> 
> Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
> Signed-off-by: Guo Ren <guoren@kernel.org>
> ---
> arch/riscv/include/asm/jump_label.h | 17 ++++++++++-----
> arch/riscv/kernel/jump_label.c      | 32 +++++++++++++++++++++++++++++
> 2 files changed, 44 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/riscv/include/asm/jump_label.h b/arch/riscv/include/asm/jump_label.h
> index 38af2ec7b9bf..78f747dfa8a2 100644
> --- a/arch/riscv/include/asm/jump_label.h
> +++ b/arch/riscv/include/asm/jump_label.h
> @@ -12,17 +12,21 @@
> #include <linux/types.h>
> #include <asm/asm.h>
> 
> +#ifdef CONFIG_RISCV_ISA_C
> +#define JUMP_LABEL_NOP_SIZE 2
> +#else
> #define JUMP_LABEL_NOP_SIZE 4
> +#endif
> 
> static __always_inline bool arch_static_branch(struct static_key *key,
> 					       bool branch)
> {
> 	asm_volatile_goto(
> -		"	.option push				\n\t"
> -		"	.option norelax				\n\t"
> -		"	.option norvc				\n\t"
> +#ifdef CONFIG_RISCV_ISA_C
> +		"1:	c.nop					\n\t"
> +#else
> 		"1:	nop					\n\t"
> -		"	.option pop				\n\t"
> +#endif
> 		"	.pushsection	__jump_table, \"aw\"	\n\t"
> 		"	.align		" RISCV_LGPTR "		\n\t"
> 		"	.long		1b - ., %l[label] - .	\n\t"
> @@ -39,11 +43,14 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key,
> 						    bool branch)
> {
> 	asm_volatile_goto(
> +#ifdef CONFIG_RISCV_ISA_C
> +		"1:	c.j		%l[label]		\n\t"
> +#else
> 		"	.option push				\n\t"
> 		"	.option norelax				\n\t"
> -		"	.option norvc				\n\t"
> 		"1:	jal		zero, %l[label]		\n\t"
> 		"	.option pop				\n\t"
> +#endif
> 		"	.pushsection	__jump_table, \"aw\"	\n\t"
> 		"	.align		" RISCV_LGPTR "		\n\t"
> 		"	.long		1b - ., %l[label] - .	\n\t"
> diff --git a/arch/riscv/kernel/jump_label.c b/arch/riscv/kernel/jump_label.c
> index e6694759dbd0..64a4e5df093d 100644
> --- a/arch/riscv/kernel/jump_label.c
> +++ b/arch/riscv/kernel/jump_label.c
> @@ -11,21 +11,52 @@
> #include <asm/bug.h>
> #include <asm/patch.h>
> 
> +#ifdef CONFIG_RISCV_ISA_C
> +#define RISCV_INSN_C_NOP 0x0001U
> +#define RISCV_INSN_C_JAL 0xa001U

This is C.J (i.e. JAL X0) not C.JAL (i.e. JAL RA, which is RV32-only
and not what you want since it clobbers RA).

Jess

> +#else
> #define RISCV_INSN_NOP 0x00000013U
> #define RISCV_INSN_JAL 0x0000006fU
> +#endif
> 
> void arch_jump_label_transform(struct jump_entry *entry,
> 			       enum jump_label_type type)
> {
> 	void *addr = (void *)jump_entry_code(entry);
> +#ifdef CONFIG_RISCV_ISA_C
> +	u16 insn;
> +#else
> 	u32 insn;
> +#endif
> 
> 	if (type == JUMP_LABEL_JMP) {
> 		long offset = jump_entry_target(entry) - jump_entry_code(entry);
> +#ifdef CONFIG_RISCV_ISA_C
> +		if (WARN_ON(offset & 1 || offset < -2048 || offset >= 2048))
> +			return;
> 
> +		/*
> +		 * 001 | imm[11|4|9:8|10|6|7|3:1|5] 01 - C.JAL
> +		 */
> +		insn = RISCV_INSN_C_JAL |
> +			(((u16)offset & GENMASK(5, 5)) >> (5 - 2)) |
> +			(((u16)offset & GENMASK(3, 1)) << (3 - 1)) |
> +			(((u16)offset & GENMASK(7, 7)) >> (7 - 6)) |
> +			(((u16)offset & GENMASK(6, 6)) << (7 - 6)) |
> +			(((u16)offset & GENMASK(10, 10)) >> (10 - 8)) |
> +			(((u16)offset & GENMASK(9, 8)) << (9 - 8)) |
> +			(((u16)offset & GENMASK(4, 4)) << (11 - 4)) |
> +			(((u16)offset & GENMASK(11, 11)) << (12 - 11));
> +	} else {
> +		insn = RISCV_INSN_C_NOP;
> +	}
> +#else
> 		if (WARN_ON(offset & 1 || offset < -524288 || offset >= 524288))
> 			return;
> 
> +		/*
> +		 * imm[20|10:1|11|19:12] | rd | 1101111 - JAL
> +		 */
> 		insn = RISCV_INSN_JAL |
> 			(((u32)offset & GENMASK(19, 12)) << (12 - 12)) |
> 			(((u32)offset & GENMASK(11, 11)) << (20 - 11)) |
> @@ -34,6 +65,7 @@ void arch_jump_label_transform(struct jump_entry *entry,
> 	} else {
> 		insn = RISCV_INSN_NOP;
> 	}
> +#endif
> 
> 	mutex_lock(&text_mutex);
> 	patch_text_nosync(addr, &insn, sizeof(insn));
> -- 
> 2.36.1
> 
> 
> _______________________________________________
> linux-riscv mailing list
> linux-riscv@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv
Guo Ren Sept. 18, 2022, 12:46 a.m. UTC | #11
On Sun, Sep 18, 2022 at 8:12 AM Jessica Clarke <jrtc27@jrtc27.com> wrote:
>
> On 17 Sept 2022, at 19:38, guoren@kernel.org wrote:
> >
> > From: Guo Ren <guoren@linux.alibaba.com>
> >
> > Reduce size of static branch.
> >
> > Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
> > Signed-off-by: Guo Ren <guoren@kernel.org>
> > ---
> > arch/riscv/include/asm/jump_label.h | 17 ++++++++++-----
> > arch/riscv/kernel/jump_label.c      | 32 +++++++++++++++++++++++++++++
> > 2 files changed, 44 insertions(+), 5 deletions(-)
> >
> > diff --git a/arch/riscv/include/asm/jump_label.h b/arch/riscv/include/asm/jump_label.h
> > index 38af2ec7b9bf..78f747dfa8a2 100644
> > --- a/arch/riscv/include/asm/jump_label.h
> > +++ b/arch/riscv/include/asm/jump_label.h
> > @@ -12,17 +12,21 @@
> > #include <linux/types.h>
> > #include <asm/asm.h>
> >
> > +#ifdef CONFIG_RISCV_ISA_C
> > +#define JUMP_LABEL_NOP_SIZE 2
> > +#else
> > #define JUMP_LABEL_NOP_SIZE 4
> > +#endif
> >
> > static __always_inline bool arch_static_branch(struct static_key *key,
> >                                              bool branch)
> > {
> >       asm_volatile_goto(
> > -             "       .option push                            \n\t"
> > -             "       .option norelax                         \n\t"
> > -             "       .option norvc                           \n\t"
> > +#ifdef CONFIG_RISCV_ISA_C
> > +             "1:     c.nop                                   \n\t"
> > +#else
> >               "1:     nop                                     \n\t"
> > -             "       .option pop                             \n\t"
> > +#endif
> >               "       .pushsection    __jump_table, \"aw\"    \n\t"
> >               "       .align          " RISCV_LGPTR "         \n\t"
> >               "       .long           1b - ., %l[label] - .   \n\t"
> > @@ -39,11 +43,14 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key,
> >                                                   bool branch)
> > {
> >       asm_volatile_goto(
> > +#ifdef CONFIG_RISCV_ISA_C
> > +             "1:     c.j             %l[label]               \n\t"
> > +#else
> >               "       .option push                            \n\t"
> >               "       .option norelax                         \n\t"
> > -             "       .option norvc                           \n\t"
> >               "1:     jal             zero, %l[label]         \n\t"
> >               "       .option pop                             \n\t"
> > +#endif
> >               "       .pushsection    __jump_table, \"aw\"    \n\t"
> >               "       .align          " RISCV_LGPTR "         \n\t"
> >               "       .long           1b - ., %l[label] - .   \n\t"
> > diff --git a/arch/riscv/kernel/jump_label.c b/arch/riscv/kernel/jump_label.c
> > index e6694759dbd0..64a4e5df093d 100644
> > --- a/arch/riscv/kernel/jump_label.c
> > +++ b/arch/riscv/kernel/jump_label.c
> > @@ -11,21 +11,52 @@
> > #include <asm/bug.h>
> > #include <asm/patch.h>
> >
> > +#ifdef CONFIG_RISCV_ISA_C
> > +#define RISCV_INSN_C_NOP 0x0001U
> > +#define RISCV_INSN_C_JAL 0xa001U
>
> This is C.J (i.e. JAL X0) not C.JAL (i.e. JAL RA, which is RV32-only
> and not what you want since it clobbers RA).

Sorry for the macro naming bug. I know I'm using c.j.


101 imm[11|4|9:8|10|6|7|3:1|5] 01 C.J

001 imm[11|4|9:8|10|6|7|3:1|5] 01 C.JAL (RV32)

Here is the correction:
-#define RISCV_INSN_C_JAL 0xa001U
+#define RISCV_INSN_C_J   0xa001U



>
> Jess
>
> > +#else
> > #define RISCV_INSN_NOP 0x00000013U
> > #define RISCV_INSN_JAL 0x0000006fU
> > +#endif
> >
> > void arch_jump_label_transform(struct jump_entry *entry,
> >                              enum jump_label_type type)
> > {
> >       void *addr = (void *)jump_entry_code(entry);
> > +#ifdef CONFIG_RISCV_ISA_C
> > +     u16 insn;
> > +#else
> >       u32 insn;
> > +#endif
> >
> >       if (type == JUMP_LABEL_JMP) {
> >               long offset = jump_entry_target(entry) - jump_entry_code(entry);
> > +#ifdef CONFIG_RISCV_ISA_C
> > +             if (WARN_ON(offset & 1 || offset < -2048 || offset >= 2048))
> > +                     return;
> >
> > +             /*
> > +              * 001 | imm[11|4|9:8|10|6|7|3:1|5] 01 - C.JAL
> > +              */
> > +             insn = RISCV_INSN_C_JAL |
> > +                     (((u16)offset & GENMASK(5, 5)) >> (5 - 2)) |
> > +                     (((u16)offset & GENMASK(3, 1)) << (3 - 1)) |
> > +                     (((u16)offset & GENMASK(7, 7)) >> (7 - 6)) |
> > +                     (((u16)offset & GENMASK(6, 6)) << (7 - 6)) |
> > +                     (((u16)offset & GENMASK(10, 10)) >> (10 - 8)) |
> > +                     (((u16)offset & GENMASK(9, 8)) << (9 - 8)) |
> > +                     (((u16)offset & GENMASK(4, 4)) << (11 - 4)) |
> > +                     (((u16)offset & GENMASK(11, 11)) << (12 - 11));
> > +     } else {
> > +             insn = RISCV_INSN_C_NOP;
> > +     }
> > +#else
> >               if (WARN_ON(offset & 1 || offset < -524288 || offset >= 524288))
> >                       return;
> >
> > +             /*
> > +              * imm[20|10:1|11|19:12] | rd | 1101111 - JAL
> > +              */
> >               insn = RISCV_INSN_JAL |
> >                       (((u32)offset & GENMASK(19, 12)) << (12 - 12)) |
> >                       (((u32)offset & GENMASK(11, 11)) << (20 - 11)) |
> > @@ -34,6 +65,7 @@ void arch_jump_label_transform(struct jump_entry *entry,
> >       } else {
> >               insn = RISCV_INSN_NOP;
> >       }
> > +#endif
> >
> >       mutex_lock(&text_mutex);
> >       patch_text_nosync(addr, &insn, sizeof(insn));
> > --
> > 2.36.1
> >
> >
> > _______________________________________________
> > linux-riscv mailing list
> > linux-riscv@lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/linux-riscv
>
diff mbox series

Patch

diff --git a/arch/riscv/include/asm/jump_label.h b/arch/riscv/include/asm/jump_label.h
index 38af2ec7b9bf..729991e8f782 100644
--- a/arch/riscv/include/asm/jump_label.h
+++ b/arch/riscv/include/asm/jump_label.h
@@ -18,6 +18,7 @@  static __always_inline bool arch_static_branch(struct static_key *key,
 					       bool branch)
 {
 	asm_volatile_goto(
+		"	.align		2			\n\t"
 		"	.option push				\n\t"
 		"	.option norelax				\n\t"
 		"	.option norvc				\n\t"
@@ -39,6 +40,7 @@  static __always_inline bool arch_static_branch_jump(struct static_key *key,
 						    bool branch)
 {
 	asm_volatile_goto(
+		"	.align		2			\n\t"
 		"	.option push				\n\t"
 		"	.option norelax				\n\t"
 		"	.option norvc				\n\t"