diff mbox series

[16/17] riscv: clear the instruction cache and all registers when booting

Message ID 20190624054311.30256-17-hch@lst.de (mailing list archive)
State New, archived
Headers show
Series [01/17] mm: provide a print_vma_addr stub for !CONFIG_MMU | expand

Commit Message

Christoph Hellwig June 24, 2019, 5:43 a.m. UTC
When we get booted we want a clear slate without any leaks from previous
supervisors or the firmware.  Flush the instruction cache and then clear
all registers to known good values.  This is really important for the
upcoming nommu support that runs on M-mode, but can't really harm when
running in S-mode either.  Vaguely based on the concepts from opensbi.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 arch/riscv/kernel/head.S | 85 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 85 insertions(+)

Comments

Atish Patra July 1, 2019, 9:26 p.m. UTC | #1
On Mon, 2019-06-24 at 07:43 +0200, Christoph Hellwig wrote:
> When we get booted we want a clear slate without any leaks from
> previous
> supervisors or the firmware.  Flush the instruction cache and then
> clear
> all registers to known good values.  This is really important for the
> upcoming nommu support that runs on M-mode, but can't really harm
> when
> running in S-mode either.

That means it should be done for S-mode as well. Right ?
I see the reset code is enabled only for M-mode only.

>   Vaguely based on the concepts from opensbi.
> 
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
>  arch/riscv/kernel/head.S | 85
> ++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 85 insertions(+)
> 
> diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S
> index a4c170e41a34..74feb17737b4 100644
> --- a/arch/riscv/kernel/head.S
> +++ b/arch/riscv/kernel/head.S
> @@ -11,6 +11,7 @@
>  #include <asm/thread_info.h>
>  #include <asm/page.h>
>  #include <asm/csr.h>
> +#include <asm/hwcap.h>
>  
>  __INIT
>  ENTRY(_start)
> @@ -19,6 +20,12 @@ ENTRY(_start)
>  	csrw CSR_XIP, zero
>  
>  #ifdef CONFIG_M_MODE
> +	/* flush the instruction cache */
> +	fence.i
> +
> +	/* Reset all registers except ra, a0, a1 */
> +	call reset_regs
> +
>  	/*
>  	 * The hartid in a0 is expected later on, and we have no
> firmware
>  	 * to hand it to us.
> @@ -168,6 +175,84 @@ relocate:
>  	j .Lsecondary_park
>  END(_start)
>  
> +#ifdef CONFIG_M_MODE
> +ENTRY(reset_regs)
> +	li	sp, 0
> +	li	gp, 0
> +	li	tp, 0
> +	li	t0, 0
> +	li	t1, 0
> +	li	t2, 0
> +	li	s0, 0
> +	li	s1, 0
> +	li	a2, 0
> +	li	a3, 0
> +	li	a4, 0
> +	li	a5, 0
> +	li	a6, 0
> +	li	a7, 0
> +	li	s2, 0
> +	li	s3, 0
> +	li	s4, 0
> +	li	s5, 0
> +	li	s6, 0
> +	li	s7, 0
> +	li	s8, 0
> +	li	s9, 0
> +	li	s10, 0
> +	li	s11, 0
> +	li	t3, 0
> +	li	t4, 0
> +	li	t5, 0
> +	li	t6, 0
> +	csrw	sscratch, 0
> +
> +#ifdef CONFIG_FPU
> +	csrr	t0, misa
> +	andi	t0, t0, (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D)
> +	bnez	t0, .Lreset_regs_done
> +
> +	li	t1, SR_FS
> +	csrs	sstatus, t1
> +	fmv.s.x	f0, zero
> +	fmv.s.x	f1, zero
> +	fmv.s.x	f2, zero
> +	fmv.s.x	f3, zero
> +	fmv.s.x	f4, zero
> +	fmv.s.x	f5, zero
> +	fmv.s.x	f6, zero
> +	fmv.s.x	f7, zero
> +	fmv.s.x	f8, zero
> +	fmv.s.x	f9, zero
> +	fmv.s.x	f10, zero
> +	fmv.s.x	f11, zero
> +	fmv.s.x	f12, zero
> +	fmv.s.x	f13, zero
> +	fmv.s.x	f14, zero
> +	fmv.s.x	f15, zero
> +	fmv.s.x	f16, zero
> +	fmv.s.x	f17, zero
> +	fmv.s.x	f18, zero
> +	fmv.s.x	f19, zero
> +	fmv.s.x	f20, zero
> +	fmv.s.x	f21, zero
> +	fmv.s.x	f22, zero
> +	fmv.s.x	f23, zero
> +	fmv.s.x	f24, zero
> +	fmv.s.x	f25, zero
> +	fmv.s.x	f26, zero
> +	fmv.s.x	f27, zero
> +	fmv.s.x	f28, zero
> +	fmv.s.x	f29, zero
> +	fmv.s.x	f30, zero
> +	fmv.s.x	f31, zero
> +	csrw	fcsr, 0
> +#endif /* CONFIG_FPU */
> +.Lreset_regs_done:
> +	ret
> +END(reset_regs)
> +#endif /* CONFIG_M_MODE */
> +
>  __PAGE_ALIGNED_BSS
>  	/* Empty zero page */
>  	.balign PAGE_SIZE
Palmer Dabbelt July 8, 2019, 8:26 a.m. UTC | #2
On Mon, 01 Jul 2019 14:26:18 PDT (-0700), Atish Patra wrote:
> On Mon, 2019-06-24 at 07:43 +0200, Christoph Hellwig wrote:
>> When we get booted we want a clear slate without any leaks from
>> previous
>> supervisors or the firmware.  Flush the instruction cache and then
>> clear
>> all registers to known good values.  This is really important for the
>> upcoming nommu support that runs on M-mode, but can't really harm
>> when
>> running in S-mode either.
> 
> That means it should be done for S-mode as well. Right ?
> I see the reset code is enabled only for M-mode only.
> 
>>   Vaguely based on the concepts from opensbi.
>> 
>> Signed-off-by: Christoph Hellwig <hch@lst.de>
>> ---
>>  arch/riscv/kernel/head.S | 85
>> ++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 85 insertions(+)
>> 
>> diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S
>> index a4c170e41a34..74feb17737b4 100644
>> --- a/arch/riscv/kernel/head.S
>> +++ b/arch/riscv/kernel/head.S
>> @@ -11,6 +11,7 @@
>>  #include <asm/thread_info.h>
>>  #include <asm/page.h>
>>  #include <asm/csr.h>
>> +#include <asm/hwcap.h>
>>  
>>  __INIT
>>  ENTRY(_start)
>> @@ -19,6 +20,12 @@ ENTRY(_start)
>>  	csrw CSR_XIP, zero
>>  
>>  #ifdef CONFIG_M_MODE
>> +	/* flush the instruction cache */
>> +	fence.i
>> +
>> +	/* Reset all registers except ra, a0, a1 */
>> +	call reset_regs
>> +
>>  	/*
>>  	 * The hartid in a0 is expected later on, and we have no
>> firmware
>>  	 * to hand it to us.
>> @@ -168,6 +175,84 @@ relocate:
>>  	j .Lsecondary_park
>>  END(_start)
>>  
>> +#ifdef CONFIG_M_MODE
>> +ENTRY(reset_regs)
>> +	li	sp, 0
>> +	li	gp, 0
>> +	li	tp, 0
>> +	li	t0, 0
>> +	li	t1, 0
>> +	li	t2, 0
>> +	li	s0, 0
>> +	li	s1, 0
>> +	li	a2, 0
>> +	li	a3, 0
>> +	li	a4, 0
>> +	li	a5, 0
>> +	li	a6, 0
>> +	li	a7, 0
>> +	li	s2, 0
>> +	li	s3, 0
>> +	li	s4, 0
>> +	li	s5, 0
>> +	li	s6, 0
>> +	li	s7, 0
>> +	li	s8, 0
>> +	li	s9, 0
>> +	li	s10, 0
>> +	li	s11, 0
>> +	li	t3, 0
>> +	li	t4, 0
>> +	li	t5, 0
>> +	li	t6, 0
>> +	csrw	sscratch, 0
>> +
>> +#ifdef CONFIG_FPU
>> +	csrr	t0, misa
>> +	andi	t0, t0, (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D)
>> +	bnez	t0, .Lreset_regs_done
>> +
>> +	li	t1, SR_FS
>> +	csrs	sstatus, t1

You need to check that the write stuck and branch around the FP instructions.
Specifically, CONFIG_FPU means there may be an FPU, not there's definately an
FPU.  You should also turn the FPU back off after zeroing the state.

>> +	fmv.s.x	f0, zero
>> +	fmv.s.x	f1, zero
>> +	fmv.s.x	f2, zero
>> +	fmv.s.x	f3, zero
>> +	fmv.s.x	f4, zero
>> +	fmv.s.x	f5, zero
>> +	fmv.s.x	f6, zero
>> +	fmv.s.x	f7, zero
>> +	fmv.s.x	f8, zero
>> +	fmv.s.x	f9, zero
>> +	fmv.s.x	f10, zero
>> +	fmv.s.x	f11, zero
>> +	fmv.s.x	f12, zero
>> +	fmv.s.x	f13, zero
>> +	fmv.s.x	f14, zero
>> +	fmv.s.x	f15, zero
>> +	fmv.s.x	f16, zero
>> +	fmv.s.x	f17, zero
>> +	fmv.s.x	f18, zero
>> +	fmv.s.x	f19, zero
>> +	fmv.s.x	f20, zero
>> +	fmv.s.x	f21, zero
>> +	fmv.s.x	f22, zero
>> +	fmv.s.x	f23, zero
>> +	fmv.s.x	f24, zero
>> +	fmv.s.x	f25, zero
>> +	fmv.s.x	f26, zero
>> +	fmv.s.x	f27, zero
>> +	fmv.s.x	f28, zero
>> +	fmv.s.x	f29, zero
>> +	fmv.s.x	f30, zero
>> +	fmv.s.x	f31, zero
>> +	csrw	fcsr, 0
>> +#endif /* CONFIG_FPU */
>> +.Lreset_regs_done:
>> +	ret
>> +END(reset_regs)
>> +#endif /* CONFIG_M_MODE */
>> +
>>  __PAGE_ALIGNED_BSS
>>  	/* Empty zero page */
>>  	.balign PAGE_SIZE
> 
> -- 
> Regards,
> Atish
Christoph Hellwig Aug. 13, 2019, 3:37 p.m. UTC | #3
On Mon, Jul 01, 2019 at 09:26:18PM +0000, Atish Patra wrote:
> That means it should be done for S-mode as well. Right ?

For S-mode the bootloader/sbi should take care of it.
Christoph Hellwig Aug. 13, 2019, 3:40 p.m. UTC | #4
On Mon, Jul 08, 2019 at 01:26:33AM -0700, Palmer Dabbelt wrote:
>>> +	csrs	sstatus, t1
>
> You need to check that the write stuck and branch around the FP instructions.
> Specifically, CONFIG_FPU means there may be an FPU, not there's definately an
> FPU.  You should also turn the FPU back off after zeroing the state.

Well, that is why we check the hwcaps from misa just above and skip
this fp reg clearing if it doesn't contain the 'F' or 'D' extension.

The caller disables the FPU a few instructions later:

	/*
         * Disable FPU to detect illegal usage of
	 * floating point in kernel space
	 */
	li t0, SR_FS
	csrc CSR_XSTATUS, t0
diff mbox series

Patch

diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S
index a4c170e41a34..74feb17737b4 100644
--- a/arch/riscv/kernel/head.S
+++ b/arch/riscv/kernel/head.S
@@ -11,6 +11,7 @@ 
 #include <asm/thread_info.h>
 #include <asm/page.h>
 #include <asm/csr.h>
+#include <asm/hwcap.h>
 
 __INIT
 ENTRY(_start)
@@ -19,6 +20,12 @@  ENTRY(_start)
 	csrw CSR_XIP, zero
 
 #ifdef CONFIG_M_MODE
+	/* flush the instruction cache */
+	fence.i
+
+	/* Reset all registers except ra, a0, a1 */
+	call reset_regs
+
 	/*
 	 * The hartid in a0 is expected later on, and we have no firmware
 	 * to hand it to us.
@@ -168,6 +175,84 @@  relocate:
 	j .Lsecondary_park
 END(_start)
 
+#ifdef CONFIG_M_MODE
+ENTRY(reset_regs)
+	li	sp, 0
+	li	gp, 0
+	li	tp, 0
+	li	t0, 0
+	li	t1, 0
+	li	t2, 0
+	li	s0, 0
+	li	s1, 0
+	li	a2, 0
+	li	a3, 0
+	li	a4, 0
+	li	a5, 0
+	li	a6, 0
+	li	a7, 0
+	li	s2, 0
+	li	s3, 0
+	li	s4, 0
+	li	s5, 0
+	li	s6, 0
+	li	s7, 0
+	li	s8, 0
+	li	s9, 0
+	li	s10, 0
+	li	s11, 0
+	li	t3, 0
+	li	t4, 0
+	li	t5, 0
+	li	t6, 0
+	csrw	sscratch, 0
+
+#ifdef CONFIG_FPU
+	csrr	t0, misa
+	andi	t0, t0, (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D)
+	bnez	t0, .Lreset_regs_done
+
+	li	t1, SR_FS
+	csrs	sstatus, t1
+	fmv.s.x	f0, zero
+	fmv.s.x	f1, zero
+	fmv.s.x	f2, zero
+	fmv.s.x	f3, zero
+	fmv.s.x	f4, zero
+	fmv.s.x	f5, zero
+	fmv.s.x	f6, zero
+	fmv.s.x	f7, zero
+	fmv.s.x	f8, zero
+	fmv.s.x	f9, zero
+	fmv.s.x	f10, zero
+	fmv.s.x	f11, zero
+	fmv.s.x	f12, zero
+	fmv.s.x	f13, zero
+	fmv.s.x	f14, zero
+	fmv.s.x	f15, zero
+	fmv.s.x	f16, zero
+	fmv.s.x	f17, zero
+	fmv.s.x	f18, zero
+	fmv.s.x	f19, zero
+	fmv.s.x	f20, zero
+	fmv.s.x	f21, zero
+	fmv.s.x	f22, zero
+	fmv.s.x	f23, zero
+	fmv.s.x	f24, zero
+	fmv.s.x	f25, zero
+	fmv.s.x	f26, zero
+	fmv.s.x	f27, zero
+	fmv.s.x	f28, zero
+	fmv.s.x	f29, zero
+	fmv.s.x	f30, zero
+	fmv.s.x	f31, zero
+	csrw	fcsr, 0
+#endif /* CONFIG_FPU */
+.Lreset_regs_done:
+	ret
+END(reset_regs)
+#endif /* CONFIG_M_MODE */
+
 __PAGE_ALIGNED_BSS
 	/* Empty zero page */
 	.balign PAGE_SIZE