2019-05-23 11:14:57 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2017-07-10 18:04:30 -07:00
/*
* Copyright ( C ) 2009 Sunplus Core Technology Co . , Ltd .
* Chen Liqin < liqin . chen @ sunplusct . com >
* Lennox Wu < lennox . wu @ sunplusct . com >
* Copyright ( C ) 2012 Regents of the University of California
* Copyright ( C ) 2017 SiFive
*/
2019-10-17 15:21:28 -07:00
# include <linux/cpu.h>
2017-07-10 18:04:30 -07:00
# include <linux/kernel.h>
# include <linux/sched.h>
2021-03-05 19:33:30 +08:00
# include <linux/sched/debug.h>
2017-07-10 18:04:30 -07:00
# include <linux/sched/task_stack.h>
# include <linux/tick.h>
# include <linux/ptrace.h>
2017-12-04 18:01:01 -05:00
# include <linux/uaccess.h>
2017-07-10 18:04:30 -07:00
# include <asm/unistd.h>
# include <asm/processor.h>
# include <asm/csr.h>
2021-01-11 20:40:12 +08:00
# include <asm/stacktrace.h>
2017-07-10 18:04:30 -07:00
# include <asm/string.h>
# include <asm/switch_to.h>
2019-10-17 15:21:28 -07:00
# include <asm/thread_info.h>
2022-02-10 11:19:40 +05:30
# include <asm/cpuidle.h>
2023-06-05 11:07:07 +00:00
# include <asm/vector.h>
2017-07-10 18:04:30 -07:00
2020-05-21 13:28:26 -07:00
register unsigned long gp_in_global __asm__ ( " gp " ) ;
2020-02-27 11:07:28 -08:00
riscv: Enable per-task stack canaries
This enables the use of per-task stack canary values if GCC has
support for emitting the stack canary reference relative to the
value of tp, which holds the task struct pointer in the riscv
kernel.
After compare arm64 and x86 implementations, seems arm64's is more
flexible and readable. The key point is how gcc get the offset of
stack_canary from gs/el0_sp.
x86: Use a fix offset from gs, not flexible.
struct fixed_percpu_data {
/*
* GCC hardcodes the stack canary as %gs:40. Since the
* irq_stack is the object at %gs:0, we reserve the bottom
* 48 bytes of the irq stack for the canary.
*/
char gs_base[40]; // :(
unsigned long stack_canary;
};
arm64: Use -mstack-protector-guard-offset & guard-reg
gcc options:
-mstack-protector-guard=sysreg
-mstack-protector-guard-reg=sp_el0
-mstack-protector-guard-offset=xxx
riscv: Use -mstack-protector-guard-offset & guard-reg
gcc options:
-mstack-protector-guard=tls
-mstack-protector-guard-reg=tp
-mstack-protector-guard-offset=xxx
GCC's implementation has been merged:
commit c931e8d5a96463427040b0d11f9c4352ac22b2b0
Author: Cooper Qu <cooper.qu@linux.alibaba.com>
Date: Mon Jul 13 16:15:08 2020 +0800
RISC-V: Add support for TLS stack protector canary access
In the end, these codes are inserted by gcc before return:
* 0xffffffe00020b396 <+120>: ld a5,1008(tp) # 0x3f0
* 0xffffffe00020b39a <+124>: xor a5,a5,a4
* 0xffffffe00020b39c <+126>: mv a0,s5
* 0xffffffe00020b39e <+128>: bnez a5,0xffffffe00020b61c <_do_fork+766>
0xffffffe00020b3a2 <+132>: ld ra,136(sp)
0xffffffe00020b3a4 <+134>: ld s0,128(sp)
0xffffffe00020b3a6 <+136>: ld s1,120(sp)
0xffffffe00020b3a8 <+138>: ld s2,112(sp)
0xffffffe00020b3aa <+140>: ld s3,104(sp)
0xffffffe00020b3ac <+142>: ld s4,96(sp)
0xffffffe00020b3ae <+144>: ld s5,88(sp)
0xffffffe00020b3b0 <+146>: ld s6,80(sp)
0xffffffe00020b3b2 <+148>: ld s7,72(sp)
0xffffffe00020b3b4 <+150>: addi sp,sp,144
0xffffffe00020b3b6 <+152>: ret
...
* 0xffffffe00020b61c <+766>: auipc ra,0x7f8
* 0xffffffe00020b620 <+770>: jalr -1764(ra) # 0xffffffe000a02f38 <__stack_chk_fail>
Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
Signed-off-by: Cooper Qu <cooper.qu@linux.alibaba.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
2020-12-17 16:29:18 +00:00
# if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_STACKPROTECTOR_PER_TASK)
2020-07-10 16:19:57 +00:00
# include <linux/stackprotector.h>
unsigned long __stack_chk_guard __read_mostly ;
EXPORT_SYMBOL ( __stack_chk_guard ) ;
# endif
2017-07-10 18:04:30 -07:00
extern asmlinkage void ret_from_fork ( void ) ;
void arch_cpu_idle ( void )
{
2022-02-10 11:19:40 +05:30
cpu_do_idle ( ) ;
2017-07-10 18:04:30 -07:00
}
2021-01-11 20:40:12 +08:00
void __show_regs ( struct pt_regs * regs )
2017-07-10 18:04:30 -07:00
{
show_regs_print_info ( KERN_DEFAULT ) ;
2021-01-11 20:40:13 +08:00
if ( ! user_mode ( regs ) ) {
pr_cont ( " epc : %pS \n " , ( void * ) regs - > epc ) ;
pr_cont ( " ra : %pS \n " , ( void * ) regs - > ra ) ;
}
pr_cont ( " epc : " REG_FMT " ra : " REG_FMT " sp : " REG_FMT " \n " ,
2019-10-28 13:10:32 +01:00
regs - > epc , regs - > ra , regs - > sp ) ;
2017-07-10 18:04:30 -07:00
pr_cont ( " gp : " REG_FMT " tp : " REG_FMT " t0 : " REG_FMT " \n " ,
regs - > gp , regs - > tp , regs - > t0 ) ;
pr_cont ( " t1 : " REG_FMT " t2 : " REG_FMT " s0 : " REG_FMT " \n " ,
regs - > t1 , regs - > t2 , regs - > s0 ) ;
pr_cont ( " s1 : " REG_FMT " a0 : " REG_FMT " a1 : " REG_FMT " \n " ,
regs - > s1 , regs - > a0 , regs - > a1 ) ;
pr_cont ( " a2 : " REG_FMT " a3 : " REG_FMT " a4 : " REG_FMT " \n " ,
regs - > a2 , regs - > a3 , regs - > a4 ) ;
pr_cont ( " a5 : " REG_FMT " a6 : " REG_FMT " a7 : " REG_FMT " \n " ,
regs - > a5 , regs - > a6 , regs - > a7 ) ;
pr_cont ( " s2 : " REG_FMT " s3 : " REG_FMT " s4 : " REG_FMT " \n " ,
regs - > s2 , regs - > s3 , regs - > s4 ) ;
pr_cont ( " s5 : " REG_FMT " s6 : " REG_FMT " s7 : " REG_FMT " \n " ,
regs - > s5 , regs - > s6 , regs - > s7 ) ;
pr_cont ( " s8 : " REG_FMT " s9 : " REG_FMT " s10: " REG_FMT " \n " ,
regs - > s8 , regs - > s9 , regs - > s10 ) ;
pr_cont ( " s11: " REG_FMT " t3 : " REG_FMT " t4 : " REG_FMT " \n " ,
regs - > s11 , regs - > t3 , regs - > t4 ) ;
pr_cont ( " t5 : " REG_FMT " t6 : " REG_FMT " \n " ,
regs - > t5 , regs - > t6 ) ;
2019-10-28 13:10:32 +01:00
pr_cont ( " status: " REG_FMT " badaddr: " REG_FMT " cause: " REG_FMT " \n " ,
regs - > status , regs - > badaddr , regs - > cause ) ;
2017-07-10 18:04:30 -07:00
}
2021-01-11 20:40:12 +08:00
void show_regs ( struct pt_regs * regs )
{
__show_regs ( regs ) ;
if ( ! user_mode ( regs ) )
dump_backtrace ( regs , NULL , KERN_DEFAULT ) ;
}
2017-07-10 18:04:30 -07:00
2022-04-05 15:13:09 +08:00
# ifdef CONFIG_COMPAT
static bool compat_mode_supported __read_mostly ;
bool compat_elf_check_arch ( Elf32_Ehdr * hdr )
{
return compat_mode_supported & &
hdr - > e_machine = = EM_RISCV & &
hdr - > e_ident [ EI_CLASS ] = = ELFCLASS32 ;
}
static int __init compat_mode_detect ( void )
{
unsigned long tmp = csr_read ( CSR_STATUS ) ;
csr_write ( CSR_STATUS , ( tmp & ~ SR_UXL ) | SR_UXL_32 ) ;
compat_mode_supported =
( csr_read ( CSR_STATUS ) & SR_UXL ) = = SR_UXL_32 ;
csr_write ( CSR_STATUS , tmp ) ;
pr_info ( " riscv: ELF compat mode %s " ,
2022-08-21 22:18:19 +08:00
compat_mode_supported ? " supported " : " unsupported " ) ;
2022-04-05 15:13:09 +08:00
return 0 ;
}
early_initcall ( compat_mode_detect ) ;
# endif
2017-07-10 18:04:30 -07:00
void start_thread ( struct pt_regs * regs , unsigned long pc ,
unsigned long sp )
{
2019-10-28 13:10:32 +01:00
regs - > status = SR_PIE ;
2021-05-12 22:55:45 +08:00
if ( has_fpu ( ) ) {
2019-10-28 13:10:32 +01:00
regs - > status | = SR_FS_INITIAL ;
2019-08-14 16:23:52 +08:00
/*
* Restore the initial value to the FP register
* before starting the user program .
*/
fstate_restore ( current , regs ) ;
}
2019-10-28 13:10:32 +01:00
regs - > epc = pc ;
2017-07-10 18:04:30 -07:00
regs - > sp = sp ;
2022-04-05 15:13:07 +08:00
# ifdef CONFIG_64BIT
regs - > status & = ~ SR_UXL ;
if ( is_compat_task ( ) )
regs - > status | = SR_UXL_32 ;
else
regs - > status | = SR_UXL_64 ;
# endif
2017-07-10 18:04:30 -07:00
}
void flush_thread ( void )
{
2018-10-09 10:18:33 +08:00
# ifdef CONFIG_FPU
2017-07-10 18:04:30 -07:00
/*
2019-08-14 16:23:52 +08:00
* Reset FPU state and context
2017-07-10 18:04:30 -07:00
* frm : round to nearest , ties to even ( IEEE default )
* fflags : accrued exceptions cleared
*/
2019-08-14 16:23:52 +08:00
fstate_off ( current , task_pt_regs ( current ) ) ;
2017-07-10 18:04:30 -07:00
memset ( & current - > thread . fstate , 0 , sizeof ( current - > thread . fstate ) ) ;
2018-10-09 10:18:33 +08:00
# endif
2023-06-05 11:07:07 +00:00
# ifdef CONFIG_RISCV_ISA_V
/* Reset vector state */
2023-06-05 11:07:18 +00:00
riscv_v_vstate_ctrl_init ( current ) ;
2023-06-05 11:07:07 +00:00
riscv_v_vstate_off ( task_pt_regs ( current ) ) ;
kfree ( current - > thread . vstate . datap ) ;
memset ( & current - > thread . vstate , 0 , sizeof ( struct __riscv_v_ext_state ) ) ;
# endif
}
void arch_release_task_struct ( struct task_struct * tsk )
{
/* Free the vector context of datap. */
if ( has_vector ( ) )
kfree ( tsk - > thread . vstate . datap ) ;
2017-07-10 18:04:30 -07:00
}
int arch_dup_task_struct ( struct task_struct * dst , struct task_struct * src )
{
fstate_save ( src , task_pt_regs ( src ) ) ;
* dst = * src ;
2023-06-05 11:07:07 +00:00
/* clear entire V context, including datap for a new task */
memset ( & dst - > thread . vstate , 0 , sizeof ( struct __riscv_v_ext_state ) ) ;
2017-07-10 18:04:30 -07:00
return 0 ;
}
2022-04-08 18:07:50 -05:00
int copy_thread ( struct task_struct * p , const struct kernel_clone_args * args )
2017-07-10 18:04:30 -07:00
{
2022-04-08 18:07:50 -05:00
unsigned long clone_flags = args - > flags ;
unsigned long usp = args - > stack ;
unsigned long tls = args - > tls ;
2017-07-10 18:04:30 -07:00
struct pt_regs * childregs = task_pt_regs ( p ) ;
2022-10-29 19:34:50 +08:00
memset ( & p - > thread . s , 0 , sizeof ( p - > thread . s ) ) ;
2017-07-10 18:04:30 -07:00
/* p->thread holds context to be restored by __switch_to() */
2022-04-12 10:18:48 -05:00
if ( unlikely ( args - > fn ) ) {
2017-07-10 18:04:30 -07:00
/* Kernel thread */
memset ( childregs , 0 , sizeof ( struct pt_regs ) ) ;
2020-02-27 11:07:28 -08:00
childregs - > gp = gp_in_global ;
2019-10-28 13:10:32 +01:00
/* Supervisor/Machine, irqs on: */
childregs - > status = SR_PP | SR_PIE ;
2017-07-10 18:04:30 -07:00
2022-04-12 10:18:48 -05:00
p - > thread . s [ 0 ] = ( unsigned long ) args - > fn ;
p - > thread . s [ 1 ] = ( unsigned long ) args - > fn_arg ;
2017-07-10 18:04:30 -07:00
} else {
* childregs = * ( current_pt_regs ( ) ) ;
2023-06-05 11:07:07 +00:00
/* Turn off status.VS */
riscv_v_vstate_off ( childregs ) ;
2017-07-10 18:04:30 -07:00
if ( usp ) /* User fork */
childregs - > sp = usp ;
if ( clone_flags & CLONE_SETTLS )
2020-01-02 18:24:11 +01:00
childregs - > tp = tls ;
2017-07-10 18:04:30 -07:00
childregs - > a0 = 0 ; /* Return value of fork() */
2023-02-21 22:30:20 -05:00
p - > thread . s [ 0 ] = 0 ;
2017-07-10 18:04:30 -07:00
}
2023-02-21 22:30:20 -05:00
p - > thread . ra = ( unsigned long ) ret_from_fork ;
2017-07-10 18:04:30 -07:00
p - > thread . sp = ( unsigned long ) childregs ; /* kernel sp */
return 0 ;
}