diff mbox series

[3/3] riscv: add trap and emulation for RDCYCLE

Message ID 20240917130853.18657-4-ben.dooks@codethink.co.uk (mailing list archive)
State New
Headers show
Series [1/3] riscv: ptrace: add regs_set_register() | expand

Checks

Context Check Description
conchuod/vmtest-fixes-PR fail merge-conflict
conchuod/vmtest-for-next-PR fail PR summary
conchuod/patch-3-test-1 fail .github/scripts/patches/tests/build_rv32_defconfig.sh took 108.92s
conchuod/patch-3-test-2 fail .github/scripts/patches/tests/build_rv64_clang_allmodconfig.sh took 923.24s
conchuod/patch-3-test-3 fail .github/scripts/patches/tests/build_rv64_gcc_allmodconfig.sh took 1144.25s
conchuod/patch-3-test-4 fail .github/scripts/patches/tests/build_rv64_nommu_k210_defconfig.sh took 17.80s
conchuod/patch-3-test-5 fail .github/scripts/patches/tests/build_rv64_nommu_virt_defconfig.sh took 19.57s
conchuod/patch-3-test-6 warning .github/scripts/patches/tests/checkpatch.sh took 0.52s
conchuod/patch-3-test-7 success .github/scripts/patches/tests/dtb_warn_rv64.sh took 42.39s
conchuod/patch-3-test-8 success .github/scripts/patches/tests/header_inline.sh took 0.00s
conchuod/patch-3-test-9 success .github/scripts/patches/tests/kdoc.sh took 0.55s
conchuod/patch-3-test-10 success .github/scripts/patches/tests/module_param.sh took 0.01s
conchuod/patch-3-test-11 success .github/scripts/patches/tests/verify_fixes.sh took 0.00s
conchuod/patch-3-test-12 success .github/scripts/patches/tests/verify_signedoff.sh took 0.03s

Commit Message

Ben Dooks Sept. 17, 2024, 1:08 p.m. UTC
Add a trap for RDCYCLE and emulate it as RDTIME instruciton.

This is an initial PoC and should probably be made more generic
way of trapping and dealing with bad instructions

Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
---
 arch/riscv/kernel/traps.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

Comments

Ben Dooks Sept. 17, 2024, 2:08 p.m. UTC | #1
On 17/09/2024 14:08, Ben Dooks wrote:
> Add a trap for RDCYCLE and emulate it as RDTIME instruciton.
> 
> This is an initial PoC and should probably be made more generic
> way of trapping and dealing with bad instructions
> 
> Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
> ---
>   arch/riscv/kernel/traps.c | 31 +++++++++++++++++++++++++++++++
>   1 file changed, 31 insertions(+)
> 
> diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c
> index 1c3fab272fd1..51ea28ebf54d 100644
> --- a/arch/riscv/kernel/traps.c
> +++ b/arch/riscv/kernel/traps.c
> @@ -167,6 +167,35 @@ DO_ERROR_INFO(do_trap_insn_misaligned,
>   DO_ERROR_INFO(do_trap_insn_fault,
>   	SIGSEGV, SEGV_ACCERR, "instruction access fault");
>   
> +#define is_system(__i) (((__i) & 0x7f) == RVG_OPCODE_SYSTEM)
> +
> +static bool riscv_try_csr_fixup_user(struct pt_regs *regs, u32 insn)
> +{
> +	/* expecting a 4 byte CSR instruction (*/
> +	if (unlikely(GET_INSN_LENGTH(insn) != 4))
> +		return false;
> +
> +	if (is_system(insn)) {
> +		u32 csr = insn >> RVG_SYSTEM_CSR_OFF;
> +		u32 rd = (insn >> RVG_RD_OPOFF) & RVG_RD_MASK;
> +		u32 rs = (insn >> RVG_RS1_OPOFF) & RVG_RS1_MASK;
> +		u32 funct3 = (insn >> RV_INSN_FUNCT3_OPOFF) & 0x7;
> +
> +		if (rs == 0 && funct3 == 2 && csr == CSR_CYCLE) {
> +			u64 val = csr_read(CSR_TIME);
> +			/* we've got a RDCCLYE, emulated it with CSR_TIME */
> +
> +			printk_ratelimited("PID %d: process using RDCYCLE, emulating with RDTIME\n", current->pid);
> +
> +			regs_set_register(regs, rd*sizeof(unsigned long), val);
> +			regs->epc += 4;
> +			return true;
> +		}
> +	}
> +
> +	return false;
> +}
> +
>   asmlinkage __visible __trap_section void do_trap_insn_illegal(struct pt_regs *regs)
>   {
>   	bool handled;
> @@ -186,6 +215,8 @@ asmlinkage __visible __trap_section void do_trap_insn_illegal(struct pt_regs *re
>   		}
>   
>   		handled = riscv_v_first_use_handler(regs, insn);
> +		if (!handle)
> +			handled = riscv_try_csr_fixup_user(regs, insn);
>   
>   		local_irq_disable();
>   

oops, forgot to fold in a fix patch, this has 2 issues.
Andrew Jones Sept. 18, 2024, 6:45 a.m. UTC | #2
On Tue, Sep 17, 2024 at 02:08:53PM GMT, Ben Dooks wrote:
> Add a trap for RDCYCLE and emulate it as RDTIME instruciton.
> 
> This is an initial PoC and should probably be made more generic
> way of trapping and dealing with bad instructions
> 
> Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
> ---
>  arch/riscv/kernel/traps.c | 31 +++++++++++++++++++++++++++++++
>  1 file changed, 31 insertions(+)
> 
> diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c
> index 1c3fab272fd1..51ea28ebf54d 100644
> --- a/arch/riscv/kernel/traps.c
> +++ b/arch/riscv/kernel/traps.c
> @@ -167,6 +167,35 @@ DO_ERROR_INFO(do_trap_insn_misaligned,
>  DO_ERROR_INFO(do_trap_insn_fault,
>  	SIGSEGV, SEGV_ACCERR, "instruction access fault");
>  
> +#define is_system(__i) (((__i) & 0x7f) == RVG_OPCODE_SYSTEM)

We have riscv_insn_is_system()

> +
> +static bool riscv_try_csr_fixup_user(struct pt_regs *regs, u32 insn)
> +{
> +	/* expecting a 4 byte CSR instruction (*/
> +	if (unlikely(GET_INSN_LENGTH(insn) != 4))
> +		return false;
> +
> +	if (is_system(insn)) {
> +		u32 csr = insn >> RVG_SYSTEM_CSR_OFF;
> +		u32 rd = (insn >> RVG_RD_OPOFF) & RVG_RD_MASK;
> +		u32 rs = (insn >> RVG_RS1_OPOFF) & RVG_RS1_MASK;
> +		u32 funct3 = (insn >> RV_INSN_FUNCT3_OPOFF) & 0x7;

There are are a few other macros in asm/insn.h that can be applied, such
as RV_EXTRACT_RD_REG(), and more could be added if necessary.

> +
> +		if (rs == 0 && funct3 == 2 && csr == CSR_CYCLE) {

We could probably create a riscv_insn_is_csr_read() and RV_EXTRACT_CSR()
for this.

> +			u64 val = csr_read(CSR_TIME);
> +			/* we've got a RDCCLYE, emulated it with CSR_TIME */
> +
> +			printk_ratelimited("PID %d: process using RDCYCLE, emulating with RDTIME\n", current->pid);

If we add current->comm it may be easier to find applications that should
be converted to CSR_TIME.

> +
> +			regs_set_register(regs, rd*sizeof(unsigned long), val);

nit: spaces around the '*'

> +			regs->epc += 4;
> +			return true;
> +		}
> +	}
> +
> +	return false;
> +}
> +
>  asmlinkage __visible __trap_section void do_trap_insn_illegal(struct pt_regs *regs)
>  {
>  	bool handled;
> @@ -186,6 +215,8 @@ asmlinkage __visible __trap_section void do_trap_insn_illegal(struct pt_regs *re
>  		}
>  
>  		handled = riscv_v_first_use_handler(regs, insn);
> +		if (!handle)
                     ^handled?

> +			handled = riscv_try_csr_fixup_user(regs, insn);
>  
>  		local_irq_disable();
>  
> -- 
> 2.37.2.352.g3c44437643
> 
>

Thanks,
drew
Ben Dooks Sept. 18, 2024, 9:07 a.m. UTC | #3
On 18/09/2024 07:45, Andrew Jones wrote:
> On Tue, Sep 17, 2024 at 02:08:53PM GMT, Ben Dooks wrote:
>> Add a trap for RDCYCLE and emulate it as RDTIME instruciton.
>>
>> This is an initial PoC and should probably be made more generic
>> way of trapping and dealing with bad instructions
>>
>> Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
>> ---
>>   arch/riscv/kernel/traps.c | 31 +++++++++++++++++++++++++++++++
>>   1 file changed, 31 insertions(+)
>>
>> diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c
>> index 1c3fab272fd1..51ea28ebf54d 100644
>> --- a/arch/riscv/kernel/traps.c
>> +++ b/arch/riscv/kernel/traps.c
>> @@ -167,6 +167,35 @@ DO_ERROR_INFO(do_trap_insn_misaligned,
>>   DO_ERROR_INFO(do_trap_insn_fault,
>>   	SIGSEGV, SEGV_ACCERR, "instruction access fault");
>>   
>> +#define is_system(__i) (((__i) & 0x7f) == RVG_OPCODE_SYSTEM)
> 
> We have riscv_insn_is_system()

Ah, didn't notice that.

>> +
>> +static bool riscv_try_csr_fixup_user(struct pt_regs *regs, u32 insn)
>> +{
>> +	/* expecting a 4 byte CSR instruction (*/
>> +	if (unlikely(GET_INSN_LENGTH(insn) != 4))
>> +		return false;
>> +
>> +	if (is_system(insn)) {
>> +		u32 csr = insn >> RVG_SYSTEM_CSR_OFF;
>> +		u32 rd = (insn >> RVG_RD_OPOFF) & RVG_RD_MASK;
>> +		u32 rs = (insn >> RVG_RS1_OPOFF) & RVG_RS1_MASK;
>> +		u32 funct3 = (insn >> RV_INSN_FUNCT3_OPOFF) & 0x7;
> 
> There are are a few other macros in asm/insn.h that can be applied, such
> as RV_EXTRACT_RD_REG(), and more could be added if necessary.

will have a look at that.

>> +
>> +		if (rs == 0 && funct3 == 2 && csr == CSR_CYCLE) {
> 
> We could probably create a riscv_insn_is_csr_read() and RV_EXTRACT_CSR()
> for this.

Not sure if this is totally necessary. I will check for the relevant 
read/write type from the CSR acces instructions

>> +			u64 val = csr_read(CSR_TIME);
>> +			/* we've got a RDCCLYE, emulated it with CSR_TIME */
>> +
>> +			printk_ratelimited("PID %d: process using RDCYCLE, emulating with RDTIME\n", current->pid);
> 
> If we add current->comm it may be easier to find applications that should
> be converted to CSR_TIME.

ok, will add.

>> +
>> +			regs_set_register(regs, rd*sizeof(unsigned long), val);
> 
> nit: spaces around the '*'

oops. will fix

>> +			regs->epc += 4;
>> +			return true;
>> +		}
>> +	}
>> +
>> +	return false;
>> +}
>> +
>>   asmlinkage __visible __trap_section void do_trap_insn_illegal(struct pt_regs *regs)
>>   {
>>   	bool handled;
>> @@ -186,6 +215,8 @@ asmlinkage __visible __trap_section void do_trap_insn_illegal(struct pt_regs *re
>>   		}
>>   
>>   		handled = riscv_v_first_use_handler(regs, insn);
>> +		if (!handle)
>                       ^handled?
> 
>> +			handled = riscv_try_csr_fixup_user(regs, insn);
>>   
>>   		local_irq_disable();
>>   
>> -- 
>> 2.37.2.352.g3c44437643
>>
>>
> 
> Thanks,
> drew

Thanks.
Ben Dooks Sept. 18, 2024, 9:15 a.m. UTC | #4
On 18/09/2024 07:45, Andrew Jones wrote:
> On Tue, Sep 17, 2024 at 02:08:53PM GMT, Ben Dooks wrote:
>> Add a trap for RDCYCLE and emulate it as RDTIME instruciton.
>>
>> This is an initial PoC and should probably be made more generic
>> way of trapping and dealing with bad instructions
>>
>> Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
>> ---
>>   arch/riscv/kernel/traps.c | 31 +++++++++++++++++++++++++++++++
>>   1 file changed, 31 insertions(+)
>>
>> diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c
>> index 1c3fab272fd1..51ea28ebf54d 100644
>> --- a/arch/riscv/kernel/traps.c
>> +++ b/arch/riscv/kernel/traps.c
>> @@ -167,6 +167,35 @@ DO_ERROR_INFO(do_trap_insn_misaligned,
>>   DO_ERROR_INFO(do_trap_insn_fault,
>>   	SIGSEGV, SEGV_ACCERR, "instruction access fault");
>>   
>> +#define is_system(__i) (((__i) & 0x7f) == RVG_OPCODE_SYSTEM)
> 
> We have riscv_insn_is_system()
> 
>> +
>> +static bool riscv_try_csr_fixup_user(struct pt_regs *regs, u32 insn)
>> +{
>> +	/* expecting a 4 byte CSR instruction (*/
>> +	if (unlikely(GET_INSN_LENGTH(insn) != 4))
>> +		return false;
>> +
>> +	if (is_system(insn)) {
>> +		u32 csr = insn >> RVG_SYSTEM_CSR_OFF;
>> +		u32 rd = (insn >> RVG_RD_OPOFF) & RVG_RD_MASK;
>> +		u32 rs = (insn >> RVG_RS1_OPOFF) & RVG_RS1_MASK;
>> +		u32 funct3 = (insn >> RV_INSN_FUNCT3_OPOFF) & 0x7;
> 
> There are are a few other macros in asm/insn.h that can be applied, such
> as RV_EXTRACT_RD_REG(), and more could be added if necessary.
> 
>> +
>> +		if (rs == 0 && funct3 == 2 && csr == CSR_CYCLE) {
> 
> We could probably create a riscv_insn_is_csr_read() and RV_EXTRACT_CSR()
> for this.
> 
>> +			u64 val = csr_read(CSR_TIME);
>> +			/* we've got a RDCCLYE, emulated it with CSR_TIME */
>> +
>> +			printk_ratelimited("PID %d: process using RDCYCLE, emulating with RDTIME\n", current->pid);
> 
> If we add current->comm it may be easier to find applications that should
> be converted to CSR_TIME.

I guess I should have also checked for the 32bit case too, but i think
those are slightly different encodings for RDCYCLE/RDCYCLEH calls.


> 
>> +
>> +			regs_set_register(regs, rd*sizeof(unsigned long), val);
> 
> nit: spaces around the '*'
> 
>> +			regs->epc += 4;
>> +			return true;
>> +		}
>> +	}
>> +
>> +	return false;
>> +}
>> +
>>   asmlinkage __visible __trap_section void do_trap_insn_illegal(struct pt_regs *regs)
>>   {
>>   	bool handled;
>> @@ -186,6 +215,8 @@ asmlinkage __visible __trap_section void do_trap_insn_illegal(struct pt_regs *re
>>   		}
>>   
>>   		handled = riscv_v_first_use_handler(regs, insn);
>> +		if (!handle)
>                       ^handled?
> 
>> +			handled = riscv_try_csr_fixup_user(regs, insn);
>>   
>>   		local_irq_disable();
>>   
>> -- 
>> 2.37.2.352.g3c44437643
>>
>>
> 
> Thanks,
> drew
> 
> _______________________________________________
> 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/kernel/traps.c b/arch/riscv/kernel/traps.c
index 1c3fab272fd1..51ea28ebf54d 100644
--- a/arch/riscv/kernel/traps.c
+++ b/arch/riscv/kernel/traps.c
@@ -167,6 +167,35 @@  DO_ERROR_INFO(do_trap_insn_misaligned,
 DO_ERROR_INFO(do_trap_insn_fault,
 	SIGSEGV, SEGV_ACCERR, "instruction access fault");
 
+#define is_system(__i) (((__i) & 0x7f) == RVG_OPCODE_SYSTEM)
+
+static bool riscv_try_csr_fixup_user(struct pt_regs *regs, u32 insn)
+{
+	/* expecting a 4 byte CSR instruction (*/
+	if (unlikely(GET_INSN_LENGTH(insn) != 4))
+		return false;
+
+	if (is_system(insn)) {
+		u32 csr = insn >> RVG_SYSTEM_CSR_OFF;
+		u32 rd = (insn >> RVG_RD_OPOFF) & RVG_RD_MASK;
+		u32 rs = (insn >> RVG_RS1_OPOFF) & RVG_RS1_MASK;
+		u32 funct3 = (insn >> RV_INSN_FUNCT3_OPOFF) & 0x7;
+
+		if (rs == 0 && funct3 == 2 && csr == CSR_CYCLE) {
+			u64 val = csr_read(CSR_TIME);
+			/* we've got a RDCCLYE, emulated it with CSR_TIME */
+
+			printk_ratelimited("PID %d: process using RDCYCLE, emulating with RDTIME\n", current->pid);
+
+			regs_set_register(regs, rd*sizeof(unsigned long), val);
+			regs->epc += 4;
+			return true;
+		}
+	}
+
+	return false;
+}
+
 asmlinkage __visible __trap_section void do_trap_insn_illegal(struct pt_regs *regs)
 {
 	bool handled;
@@ -186,6 +215,8 @@  asmlinkage __visible __trap_section void do_trap_insn_illegal(struct pt_regs *re
 		}
 
 		handled = riscv_v_first_use_handler(regs, insn);
+		if (!handle)
+			handled = riscv_try_csr_fixup_user(regs, insn);
 
 		local_irq_disable();