RISC-V: User-facing API
This patch contains code that is in some way visible to the user: including via system calls, the VDSO, module loading and signal handling. It also contains some generic code that is ABI visible. Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
This commit is contained in:
		
							parent
							
								
									07037db5d4
								
							
						
					
					
						commit
						e2c0cdfba7
					
				
							
								
								
									
										26
									
								
								arch/riscv/include/asm/mmu.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								arch/riscv/include/asm/mmu.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | ||||
| /*
 | ||||
|  * Copyright (C) 2012 Regents of the University of California | ||||
|  * | ||||
|  *   This program is free software; you can redistribute it and/or | ||||
|  *   modify it under the terms of the GNU General Public License | ||||
|  *   as published by the Free Software Foundation, version 2. | ||||
|  * | ||||
|  *   This program is distributed in the hope that it will be useful, | ||||
|  *   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *   GNU General Public License for more details. | ||||
|  */ | ||||
| 
 | ||||
| 
 | ||||
| #ifndef _ASM_RISCV_MMU_H | ||||
| #define _ASM_RISCV_MMU_H | ||||
| 
 | ||||
| #ifndef __ASSEMBLY__ | ||||
| 
 | ||||
| typedef struct { | ||||
| 	void *vdso; | ||||
| } mm_context_t; | ||||
| 
 | ||||
| #endif /* __ASSEMBLY__ */ | ||||
| 
 | ||||
| #endif /* _ASM_RISCV_MMU_H */ | ||||
							
								
								
									
										118
									
								
								arch/riscv/include/asm/ptrace.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								arch/riscv/include/asm/ptrace.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,118 @@ | ||||
| /*
 | ||||
|  * Copyright (C) 2012 Regents of the University of California | ||||
|  * | ||||
|  *   This program is free software; you can redistribute it and/or | ||||
|  *   modify it under the terms of the GNU General Public License | ||||
|  *   as published by the Free Software Foundation, version 2. | ||||
|  * | ||||
|  *   This program is distributed in the hope that it will be useful, | ||||
|  *   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *   GNU General Public License for more details. | ||||
|  */ | ||||
| 
 | ||||
| #ifndef _ASM_RISCV_PTRACE_H | ||||
| #define _ASM_RISCV_PTRACE_H | ||||
| 
 | ||||
| #include <uapi/asm/ptrace.h> | ||||
| #include <asm/csr.h> | ||||
| 
 | ||||
| #ifndef __ASSEMBLY__ | ||||
| 
 | ||||
| struct pt_regs { | ||||
| 	unsigned long sepc; | ||||
| 	unsigned long ra; | ||||
| 	unsigned long sp; | ||||
| 	unsigned long gp; | ||||
| 	unsigned long tp; | ||||
| 	unsigned long t0; | ||||
| 	unsigned long t1; | ||||
| 	unsigned long t2; | ||||
| 	unsigned long s0; | ||||
| 	unsigned long s1; | ||||
| 	unsigned long a0; | ||||
| 	unsigned long a1; | ||||
| 	unsigned long a2; | ||||
| 	unsigned long a3; | ||||
| 	unsigned long a4; | ||||
| 	unsigned long a5; | ||||
| 	unsigned long a6; | ||||
| 	unsigned long a7; | ||||
| 	unsigned long s2; | ||||
| 	unsigned long s3; | ||||
| 	unsigned long s4; | ||||
| 	unsigned long s5; | ||||
| 	unsigned long s6; | ||||
| 	unsigned long s7; | ||||
| 	unsigned long s8; | ||||
| 	unsigned long s9; | ||||
| 	unsigned long s10; | ||||
| 	unsigned long s11; | ||||
| 	unsigned long t3; | ||||
| 	unsigned long t4; | ||||
| 	unsigned long t5; | ||||
| 	unsigned long t6; | ||||
| 	/* Supervisor CSRs */ | ||||
| 	unsigned long sstatus; | ||||
| 	unsigned long sbadaddr; | ||||
| 	unsigned long scause; | ||||
|         /* a0 value before the syscall */ | ||||
|         unsigned long orig_a0; | ||||
| }; | ||||
| 
 | ||||
| #ifdef CONFIG_64BIT | ||||
| #define REG_FMT "%016lx" | ||||
| #else | ||||
| #define REG_FMT "%08lx" | ||||
| #endif | ||||
| 
 | ||||
| #define user_mode(regs) (((regs)->sstatus & SR_PS) == 0) | ||||
| 
 | ||||
| 
 | ||||
| /* Helpers for working with the instruction pointer */ | ||||
| #define GET_IP(regs) ((regs)->sepc) | ||||
| #define SET_IP(regs, val) (GET_IP(regs) = (val)) | ||||
| 
 | ||||
| static inline unsigned long instruction_pointer(struct pt_regs *regs) | ||||
| { | ||||
| 	return GET_IP(regs); | ||||
| } | ||||
| static inline void instruction_pointer_set(struct pt_regs *regs, | ||||
| 					   unsigned long val) | ||||
| { | ||||
| 	SET_IP(regs, val); | ||||
| } | ||||
| 
 | ||||
| #define profile_pc(regs) instruction_pointer(regs) | ||||
| 
 | ||||
| /* Helpers for working with the user stack pointer */ | ||||
| #define GET_USP(regs) ((regs)->sp) | ||||
| #define SET_USP(regs, val) (GET_USP(regs) = (val)) | ||||
| 
 | ||||
| static inline unsigned long user_stack_pointer(struct pt_regs *regs) | ||||
| { | ||||
| 	return GET_USP(regs); | ||||
| } | ||||
| static inline void user_stack_pointer_set(struct pt_regs *regs, | ||||
| 					  unsigned long val) | ||||
| { | ||||
| 	SET_USP(regs, val); | ||||
| } | ||||
| 
 | ||||
| /* Helpers for working with the frame pointer */ | ||||
| #define GET_FP(regs) ((regs)->s0) | ||||
| #define SET_FP(regs, val) (GET_FP(regs) = (val)) | ||||
| 
 | ||||
| static inline unsigned long frame_pointer(struct pt_regs *regs) | ||||
| { | ||||
| 	return GET_FP(regs); | ||||
| } | ||||
| static inline void frame_pointer_set(struct pt_regs *regs, | ||||
| 				     unsigned long val) | ||||
| { | ||||
| 	SET_FP(regs, val); | ||||
| } | ||||
| 
 | ||||
| #endif /* __ASSEMBLY__ */ | ||||
| 
 | ||||
| #endif /* _ASM_RISCV_PTRACE_H */ | ||||
							
								
								
									
										102
									
								
								arch/riscv/include/asm/syscall.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								arch/riscv/include/asm/syscall.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,102 @@ | ||||
| /*
 | ||||
|  * Copyright (C) 2008-2009 Red Hat, Inc.  All rights reserved. | ||||
|  * Copyright 2010 Tilera Corporation. All Rights Reserved. | ||||
|  * Copyright 2015 Regents of the University of California, Berkeley | ||||
|  * | ||||
|  *   This program is free software; you can redistribute it and/or | ||||
|  *   modify it under the terms of the GNU General Public License | ||||
|  *   as published by the Free Software Foundation, version 2. | ||||
|  * | ||||
|  *   This program is distributed in the hope that it will be useful, | ||||
|  *   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *   GNU General Public License for more details. | ||||
|  * | ||||
|  * See asm-generic/syscall.h for descriptions of what we must do here. | ||||
|  */ | ||||
| 
 | ||||
| #ifndef _ASM_RISCV_SYSCALL_H | ||||
| #define _ASM_RISCV_SYSCALL_H | ||||
| 
 | ||||
| #include <linux/sched.h> | ||||
| #include <linux/err.h> | ||||
| 
 | ||||
| /* The array of function pointers for syscalls. */ | ||||
| extern void *sys_call_table[]; | ||||
| 
 | ||||
| /*
 | ||||
|  * Only the low 32 bits of orig_r0 are meaningful, so we return int. | ||||
|  * This importantly ignores the high bits on 64-bit, so comparisons | ||||
|  * sign-extend the low 32 bits. | ||||
|  */ | ||||
| static inline int syscall_get_nr(struct task_struct *task, | ||||
| 				 struct pt_regs *regs) | ||||
| { | ||||
| 	return regs->a7; | ||||
| } | ||||
| 
 | ||||
| static inline void syscall_set_nr(struct task_struct *task, | ||||
| 				  struct pt_regs *regs, | ||||
| 				  int sysno) | ||||
| { | ||||
| 	regs->a7 = sysno; | ||||
| } | ||||
| 
 | ||||
| static inline void syscall_rollback(struct task_struct *task, | ||||
| 				    struct pt_regs *regs) | ||||
| { | ||||
|         regs->a0 = regs->orig_a0; | ||||
| } | ||||
| 
 | ||||
| static inline long syscall_get_error(struct task_struct *task, | ||||
| 				     struct pt_regs *regs) | ||||
| { | ||||
| 	unsigned long error = regs->a0; | ||||
| 
 | ||||
| 	return IS_ERR_VALUE(error) ? error : 0; | ||||
| } | ||||
| 
 | ||||
| static inline long syscall_get_return_value(struct task_struct *task, | ||||
| 					    struct pt_regs *regs) | ||||
| { | ||||
| 	return regs->a0; | ||||
| } | ||||
| 
 | ||||
| static inline void syscall_set_return_value(struct task_struct *task, | ||||
| 					    struct pt_regs *regs, | ||||
| 					    int error, long val) | ||||
| { | ||||
| 	regs->a0 = (long) error ?: val; | ||||
| } | ||||
| 
 | ||||
| static inline void syscall_get_arguments(struct task_struct *task, | ||||
| 					 struct pt_regs *regs, | ||||
| 					 unsigned int i, unsigned int n, | ||||
| 					 unsigned long *args) | ||||
| { | ||||
| 	BUG_ON(i + n > 6); | ||||
| 	if (i == 0) { | ||||
| 		args[0] = regs->orig_a0; | ||||
| 		args++; | ||||
| 		i++; | ||||
| 		n--; | ||||
| 	} | ||||
| 	memcpy(args, ®s->a1 + i * sizeof(regs->a1), n * sizeof(args[0])); | ||||
| } | ||||
| 
 | ||||
| static inline void syscall_set_arguments(struct task_struct *task, | ||||
| 					 struct pt_regs *regs, | ||||
| 					 unsigned int i, unsigned int n, | ||||
| 					 const unsigned long *args) | ||||
| { | ||||
| 	BUG_ON(i + n > 6); | ||||
|         if (i == 0) { | ||||
|                 regs->orig_a0 = args[0]; | ||||
|                 args++; | ||||
|                 i++; | ||||
|                 n--; | ||||
|         } | ||||
| 	memcpy(®s->a1 + i * sizeof(regs->a1), args, n * sizeof(regs->a0)); | ||||
| } | ||||
| 
 | ||||
| #endif	/* _ASM_RISCV_SYSCALL_H */ | ||||
							
								
								
									
										16
									
								
								arch/riscv/include/asm/unistd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								arch/riscv/include/asm/unistd.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| /*
 | ||||
|  * Copyright (C) 2012 Regents of the University of California | ||||
|  * | ||||
|  *   This program is free software; you can redistribute it and/or | ||||
|  *   modify it under the terms of the GNU General Public License | ||||
|  *   as published by the Free Software Foundation, version 2. | ||||
|  * | ||||
|  *   This program is distributed in the hope that it will be useful, | ||||
|  *   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *   GNU General Public License for more details. | ||||
|  */ | ||||
| 
 | ||||
| #define __ARCH_HAVE_MMU | ||||
| #define __ARCH_WANT_SYS_CLONE | ||||
| #include <uapi/asm/unistd.h> | ||||
							
								
								
									
										41
									
								
								arch/riscv/include/asm/vdso.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								arch/riscv/include/asm/vdso.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | ||||
| /*
 | ||||
|  * Copyright (C) 2012 ARM Limited | ||||
|  * Copyright (C) 2014 Regents of the University of California | ||||
|  * Copyright (C) 2017 SiFive | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License version 2 as | ||||
|  * published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #ifndef _ASM_RISCV_VDSO_H | ||||
| #define _ASM_RISCV_VDSO_H | ||||
| 
 | ||||
| #include <linux/types.h> | ||||
| 
 | ||||
| struct vdso_data { | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * The VDSO symbols are mapped into Linux so we can just use regular symbol | ||||
|  * addressing to get their offsets in userspace.  The symbols are mapped at an | ||||
|  * offset of 0, but since the linker must support setting weak undefined | ||||
|  * symbols to the absolute address 0 it also happens to support other low | ||||
|  * addresses even when the code model suggests those low addresses would not | ||||
|  * otherwise be availiable. | ||||
|  */ | ||||
| #define VDSO_SYMBOL(base, name)							\ | ||||
| ({										\ | ||||
| 	extern const char __vdso_##name[];					\ | ||||
| 	(void __user *)((unsigned long)(base) + __vdso_##name);			\ | ||||
| }) | ||||
| 
 | ||||
| #endif /* _ASM_RISCV_VDSO_H */ | ||||
							
								
								
									
										27
									
								
								arch/riscv/include/uapi/asm/Kbuild
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								arch/riscv/include/uapi/asm/Kbuild
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| # UAPI Header export list | ||||
| include include/uapi/asm-generic/Kbuild.asm | ||||
| 
 | ||||
| generic-y += setup.h | ||||
| generic-y += unistd.h | ||||
| generic-y += errno.h | ||||
| generic-y += fcntl.h | ||||
| generic-y += ioctl.h | ||||
| generic-y += ioctls.h | ||||
| generic-y += ipcbuf.h | ||||
| generic-y += mman.h | ||||
| generic-y += msgbuf.h | ||||
| generic-y += param.h | ||||
| generic-y += poll.h | ||||
| generic-y += posix_types.h | ||||
| generic-y += resource.h | ||||
| generic-y += sembuf.h | ||||
| generic-y += shmbuf.h | ||||
| generic-y += signal.h | ||||
| generic-y += socket.h | ||||
| generic-y += sockios.h | ||||
| generic-y += stat.h | ||||
| generic-y += statfs.h | ||||
| generic-y += swab.h | ||||
| generic-y += termbits.h | ||||
| generic-y += termios.h | ||||
| generic-y += types.h | ||||
							
								
								
									
										24
									
								
								arch/riscv/include/uapi/asm/auxvec.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								arch/riscv/include/uapi/asm/auxvec.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| /*
 | ||||
|  * Copyright (C) 2012 ARM Ltd. | ||||
|  * Copyright (C) 2015 Regents of the University of California | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License version 2 as | ||||
|  * published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #ifndef _UAPI_ASM_RISCV_AUXVEC_H | ||||
| #define _UAPI_ASM_RISCV_AUXVEC_H | ||||
| 
 | ||||
| /* vDSO location */ | ||||
| #define AT_SYSINFO_EHDR 33 | ||||
| 
 | ||||
| #endif /* _UAPI_ASM_RISCV_AUXVEC_H */ | ||||
							
								
								
									
										25
									
								
								arch/riscv/include/uapi/asm/bitsperlong.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								arch/riscv/include/uapi/asm/bitsperlong.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| /*
 | ||||
|  * Copyright (C) 2012 ARM Ltd. | ||||
|  * Copyright (C) 2015 Regents of the University of California | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License version 2 as | ||||
|  * published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #ifndef _UAPI_ASM_RISCV_BITSPERLONG_H | ||||
| #define _UAPI_ASM_RISCV_BITSPERLONG_H | ||||
| 
 | ||||
| #define __BITS_PER_LONG (__SIZEOF_POINTER__ * 8) | ||||
| 
 | ||||
| #include <asm-generic/bitsperlong.h> | ||||
| 
 | ||||
| #endif /* _UAPI_ASM_RISCV_BITSPERLONG_H */ | ||||
							
								
								
									
										23
									
								
								arch/riscv/include/uapi/asm/byteorder.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								arch/riscv/include/uapi/asm/byteorder.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| /*
 | ||||
|  * Copyright (C) 2012 ARM Ltd. | ||||
|  * Copyright (C) 2015 Regents of the University of California | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License version 2 as | ||||
|  * published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #ifndef _UAPI_ASM_RISCV_BYTEORDER_H | ||||
| #define _UAPI_ASM_RISCV_BYTEORDER_H | ||||
| 
 | ||||
| #include <linux/byteorder/little_endian.h> | ||||
| 
 | ||||
| #endif /* _UAPI_ASM_RISCV_BYTEORDER_H */ | ||||
							
								
								
									
										83
									
								
								arch/riscv/include/uapi/asm/elf.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								arch/riscv/include/uapi/asm/elf.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,83 @@ | ||||
| /*
 | ||||
|  * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com> | ||||
|  * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se> | ||||
|  * Copyright (C) 2012 Regents of the University of California | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  */ | ||||
| 
 | ||||
| #ifndef _UAPI_ASM_ELF_H | ||||
| #define _UAPI_ASM_ELF_H | ||||
| 
 | ||||
| #include <asm/ptrace.h> | ||||
| 
 | ||||
| /* ELF register definitions */ | ||||
| typedef unsigned long elf_greg_t; | ||||
| typedef struct user_regs_struct elf_gregset_t; | ||||
| #define ELF_NGREG (sizeof(elf_gregset_t) / sizeof(elf_greg_t)) | ||||
| 
 | ||||
| typedef union __riscv_fp_state elf_fpregset_t; | ||||
| 
 | ||||
| #define ELF_RISCV_R_SYM(r_info) ((r_info) >> 32) | ||||
| #define ELF_RISCV_R_TYPE(r_info) ((r_info) & 0xffffffff) | ||||
| 
 | ||||
| /*
 | ||||
|  * RISC-V relocation types | ||||
|  */ | ||||
| 
 | ||||
| /* Relocation types used by the dynamic linker */ | ||||
| #define R_RISCV_NONE		0 | ||||
| #define R_RISCV_32		1 | ||||
| #define R_RISCV_64		2 | ||||
| #define R_RISCV_RELATIVE	3 | ||||
| #define R_RISCV_COPY		4 | ||||
| #define R_RISCV_JUMP_SLOT	5 | ||||
| #define R_RISCV_TLS_DTPMOD32	6 | ||||
| #define R_RISCV_TLS_DTPMOD64	7 | ||||
| #define R_RISCV_TLS_DTPREL32	8 | ||||
| #define R_RISCV_TLS_DTPREL64	9 | ||||
| #define R_RISCV_TLS_TPREL32	10 | ||||
| #define R_RISCV_TLS_TPREL64	11 | ||||
| 
 | ||||
| /* Relocation types not used by the dynamic linker */ | ||||
| #define R_RISCV_BRANCH		16 | ||||
| #define R_RISCV_JAL		17 | ||||
| #define R_RISCV_CALL		18 | ||||
| #define R_RISCV_CALL_PLT	19 | ||||
| #define R_RISCV_GOT_HI20	20 | ||||
| #define R_RISCV_TLS_GOT_HI20	21 | ||||
| #define R_RISCV_TLS_GD_HI20	22 | ||||
| #define R_RISCV_PCREL_HI20	23 | ||||
| #define R_RISCV_PCREL_LO12_I	24 | ||||
| #define R_RISCV_PCREL_LO12_S	25 | ||||
| #define R_RISCV_HI20		26 | ||||
| #define R_RISCV_LO12_I		27 | ||||
| #define R_RISCV_LO12_S		28 | ||||
| #define R_RISCV_TPREL_HI20	29 | ||||
| #define R_RISCV_TPREL_LO12_I	30 | ||||
| #define R_RISCV_TPREL_LO12_S	31 | ||||
| #define R_RISCV_TPREL_ADD	32 | ||||
| #define R_RISCV_ADD8		33 | ||||
| #define R_RISCV_ADD16		34 | ||||
| #define R_RISCV_ADD32		35 | ||||
| #define R_RISCV_ADD64		36 | ||||
| #define R_RISCV_SUB8		37 | ||||
| #define R_RISCV_SUB16		38 | ||||
| #define R_RISCV_SUB32		39 | ||||
| #define R_RISCV_SUB64		40 | ||||
| #define R_RISCV_GNU_VTINHERIT	41 | ||||
| #define R_RISCV_GNU_VTENTRY	42 | ||||
| #define R_RISCV_ALIGN		43 | ||||
| #define R_RISCV_RVC_BRANCH	44 | ||||
| #define R_RISCV_RVC_JUMP	45 | ||||
| #define R_RISCV_LUI		46 | ||||
| #define R_RISCV_GPREL_I		47 | ||||
| #define R_RISCV_GPREL_S		48 | ||||
| #define R_RISCV_TPREL_I		49 | ||||
| #define R_RISCV_TPREL_S		50 | ||||
| #define R_RISCV_RELAX		51 | ||||
| 
 | ||||
| #endif /* _UAPI_ASM_ELF_H */ | ||||
							
								
								
									
										36
									
								
								arch/riscv/include/uapi/asm/hwcap.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								arch/riscv/include/uapi/asm/hwcap.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | ||||
| /*
 | ||||
|  * Copied from arch/arm64/include/asm/hwcap.h | ||||
|  * | ||||
|  * Copyright (C) 2012 ARM Ltd. | ||||
|  * Copyright (C) 2017 SiFive | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License version 2 as | ||||
|  * published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| #ifndef __UAPI_ASM_HWCAP_H | ||||
| #define __UAPI_ASM_HWCAP_H | ||||
| 
 | ||||
| /*
 | ||||
|  * Linux saves the floating-point registers according to the ISA Linux is | ||||
|  * executing on, as opposed to the ISA the user program is compiled for.  This | ||||
|  * is necessary for a handful of esoteric use cases: for example, userpsace | ||||
|  * threading libraries must be able to examine the actual machine state in | ||||
|  * order to fully reconstruct the state of a thread. | ||||
|  */ | ||||
| #define COMPAT_HWCAP_ISA_I	(1 << ('I' - 'A')) | ||||
| #define COMPAT_HWCAP_ISA_M	(1 << ('M' - 'A')) | ||||
| #define COMPAT_HWCAP_ISA_A	(1 << ('A' - 'A')) | ||||
| #define COMPAT_HWCAP_ISA_F	(1 << ('F' - 'A')) | ||||
| #define COMPAT_HWCAP_ISA_D	(1 << ('D' - 'A')) | ||||
| #define COMPAT_HWCAP_ISA_C	(1 << ('C' - 'A')) | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										90
									
								
								arch/riscv/include/uapi/asm/ptrace.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								arch/riscv/include/uapi/asm/ptrace.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,90 @@ | ||||
| /*
 | ||||
|  * Copyright (C) 2012 Regents of the University of California | ||||
|  * | ||||
|  *   This program is free software; you can redistribute it and/or | ||||
|  *   modify it under the terms of the GNU General Public License | ||||
|  *   as published by the Free Software Foundation, version 2. | ||||
|  * | ||||
|  *   This program is distributed in the hope that it will be useful, | ||||
|  *   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *   GNU General Public License for more details. | ||||
|  */ | ||||
| 
 | ||||
| #ifndef _UAPI_ASM_RISCV_PTRACE_H | ||||
| #define _UAPI_ASM_RISCV_PTRACE_H | ||||
| 
 | ||||
| #ifndef __ASSEMBLY__ | ||||
| 
 | ||||
| #include <linux/types.h> | ||||
| 
 | ||||
| /*
 | ||||
|  * User-mode register state for core dumps, ptrace, sigcontext | ||||
|  * | ||||
|  * This decouples struct pt_regs from the userspace ABI. | ||||
|  * struct user_regs_struct must form a prefix of struct pt_regs. | ||||
|  */ | ||||
| struct user_regs_struct { | ||||
| 	unsigned long pc; | ||||
| 	unsigned long ra; | ||||
| 	unsigned long sp; | ||||
| 	unsigned long gp; | ||||
| 	unsigned long tp; | ||||
| 	unsigned long t0; | ||||
| 	unsigned long t1; | ||||
| 	unsigned long t2; | ||||
| 	unsigned long s0; | ||||
| 	unsigned long s1; | ||||
| 	unsigned long a0; | ||||
| 	unsigned long a1; | ||||
| 	unsigned long a2; | ||||
| 	unsigned long a3; | ||||
| 	unsigned long a4; | ||||
| 	unsigned long a5; | ||||
| 	unsigned long a6; | ||||
| 	unsigned long a7; | ||||
| 	unsigned long s2; | ||||
| 	unsigned long s3; | ||||
| 	unsigned long s4; | ||||
| 	unsigned long s5; | ||||
| 	unsigned long s6; | ||||
| 	unsigned long s7; | ||||
| 	unsigned long s8; | ||||
| 	unsigned long s9; | ||||
| 	unsigned long s10; | ||||
| 	unsigned long s11; | ||||
| 	unsigned long t3; | ||||
| 	unsigned long t4; | ||||
| 	unsigned long t5; | ||||
| 	unsigned long t6; | ||||
| }; | ||||
| 
 | ||||
| struct __riscv_f_ext_state { | ||||
| 	__u32 f[32]; | ||||
| 	__u32 fcsr; | ||||
| }; | ||||
| 
 | ||||
| struct __riscv_d_ext_state { | ||||
| 	__u64 f[32]; | ||||
| 	__u32 fcsr; | ||||
| }; | ||||
| 
 | ||||
| struct __riscv_q_ext_state { | ||||
| 	__u64 f[64] __attribute__((aligned(16))); | ||||
| 	__u32 fcsr; | ||||
| 	/*
 | ||||
| 	 * Reserved for expansion of sigcontext structure.  Currently zeroed | ||||
| 	 * upon signal, and must be zero upon sigreturn. | ||||
| 	 */ | ||||
| 	__u32 reserved[3]; | ||||
| }; | ||||
| 
 | ||||
| union __riscv_fp_state { | ||||
| 	struct __riscv_f_ext_state f; | ||||
| 	struct __riscv_d_ext_state d; | ||||
| 	struct __riscv_q_ext_state q; | ||||
| }; | ||||
| 
 | ||||
| #endif /* __ASSEMBLY__ */ | ||||
| 
 | ||||
| #endif /* _UAPI_ASM_RISCV_PTRACE_H */ | ||||
							
								
								
									
										30
									
								
								arch/riscv/include/uapi/asm/sigcontext.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								arch/riscv/include/uapi/asm/sigcontext.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | ||||
| /*
 | ||||
|  * Copyright (C) 2012 Regents of the University of California | ||||
|  * | ||||
|  *   This program is free software; you can redistribute it and/or | ||||
|  *   modify it under the terms of the GNU General Public License | ||||
|  *   as published by the Free Software Foundation, version 2. | ||||
|  * | ||||
|  *   This program is distributed in the hope that it will be useful, | ||||
|  *   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *   GNU General Public License for more details. | ||||
|  */ | ||||
| 
 | ||||
| #ifndef _UAPI_ASM_RISCV_SIGCONTEXT_H | ||||
| #define _UAPI_ASM_RISCV_SIGCONTEXT_H | ||||
| 
 | ||||
| #include <asm/ptrace.h> | ||||
| 
 | ||||
| /*
 | ||||
|  * Signal context structure | ||||
|  * | ||||
|  * This contains the context saved before a signal handler is invoked; | ||||
|  * it is restored by sys_sigreturn / sys_rt_sigreturn. | ||||
|  */ | ||||
| struct sigcontext { | ||||
| 	struct user_regs_struct sc_regs; | ||||
| 	union __riscv_fp_state sc_fpregs; | ||||
| }; | ||||
| 
 | ||||
| #endif /* _UAPI_ASM_RISCV_SIGCONTEXT_H */ | ||||
							
								
								
									
										24
									
								
								arch/riscv/include/uapi/asm/siginfo.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								arch/riscv/include/uapi/asm/siginfo.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| /*
 | ||||
|  * Copyright (C) 2012 ARM Ltd. | ||||
|  * Copyright (C) 2016 SiFive, Inc. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License version 2 as | ||||
|  * published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| #ifndef __ASM_SIGINFO_H | ||||
| #define __ASM_SIGINFO_H | ||||
| 
 | ||||
| #define __ARCH_SI_PREAMBLE_SIZE	(__SIZEOF_POINTER__ == 4 ? 12 : 16) | ||||
| 
 | ||||
| #include <asm-generic/siginfo.h> | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										45
									
								
								arch/riscv/include/uapi/asm/ucontext.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								arch/riscv/include/uapi/asm/ucontext.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| /*
 | ||||
|  * Copyright (C) 2012 ARM Ltd. | ||||
|  * Copyright (C) 2017 SiFive, Inc. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License version 2 as | ||||
|  * published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  * This file was copied from arch/arm64/include/uapi/asm/ucontext.h | ||||
|  */ | ||||
| #ifndef _UAPI__ASM_UCONTEXT_H | ||||
| #define _UAPI__ASM_UCONTEXT_H | ||||
| 
 | ||||
| #include <linux/types.h> | ||||
| 
 | ||||
| struct ucontext { | ||||
| 	unsigned long	  uc_flags; | ||||
| 	struct ucontext	 *uc_link; | ||||
| 	stack_t		  uc_stack; | ||||
| 	sigset_t	  uc_sigmask; | ||||
| 	/* There's some padding here to allow sigset_t to be expanded in the
 | ||||
| 	 * future.  Though this is unlikely, other architectures put uc_sigmask | ||||
| 	 * at the end of this structure and explicitly state it can be | ||||
| 	 * expanded, so we didn't want to box ourselves in here. */ | ||||
| 	__u8		  __unused[1024 / 8 - sizeof(sigset_t)]; | ||||
| 	/* We can't put uc_sigmask at the end of this structure because we need
 | ||||
| 	 * to be able to expand sigcontext in the future.  For example, the | ||||
| 	 * vector ISA extension will almost certainly add ISA state.  We want | ||||
| 	 * to ensure all user-visible ISA state can be saved and restored via a | ||||
| 	 * ucontext, so we're putting this at the end in order to allow for | ||||
| 	 * infinite extensibility.  Since we know this will be extended and we | ||||
| 	 * assume sigset_t won't be extended an extreme amount, we're | ||||
| 	 * prioritizing this. */ | ||||
| 	struct sigcontext uc_mcontext; | ||||
| }; | ||||
| 
 | ||||
| #endif /* _UAPI__ASM_UCONTEXT_H */ | ||||
							
								
								
									
										61
									
								
								arch/riscv/kernel/cpufeature.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								arch/riscv/kernel/cpufeature.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,61 @@ | ||||
| /*
 | ||||
|  * Copied from arch/arm64/kernel/cpufeature.c | ||||
|  * | ||||
|  * Copyright (C) 2015 ARM Ltd. | ||||
|  * Copyright (C) 2017 SiFive | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License version 2 as | ||||
|  * published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/of.h> | ||||
| #include <asm/processor.h> | ||||
| #include <asm/hwcap.h> | ||||
| 
 | ||||
| unsigned long elf_hwcap __read_mostly; | ||||
| 
 | ||||
| void riscv_fill_hwcap(void) | ||||
| { | ||||
| 	struct device_node *node; | ||||
| 	const char *isa; | ||||
| 	size_t i; | ||||
| 	static unsigned long isa2hwcap[256] = {0}; | ||||
| 
 | ||||
| 	isa2hwcap['i'] = isa2hwcap['I'] = COMPAT_HWCAP_ISA_I; | ||||
| 	isa2hwcap['m'] = isa2hwcap['M'] = COMPAT_HWCAP_ISA_M; | ||||
| 	isa2hwcap['a'] = isa2hwcap['A'] = COMPAT_HWCAP_ISA_A; | ||||
| 	isa2hwcap['f'] = isa2hwcap['F'] = COMPAT_HWCAP_ISA_F; | ||||
| 	isa2hwcap['d'] = isa2hwcap['D'] = COMPAT_HWCAP_ISA_D; | ||||
| 	isa2hwcap['c'] = isa2hwcap['C'] = COMPAT_HWCAP_ISA_C; | ||||
| 
 | ||||
| 	elf_hwcap = 0; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * We don't support running Linux on hertergenous ISA systems.  For | ||||
| 	 * now, we just check the ISA of the first processor. | ||||
| 	 */ | ||||
| 	node = of_find_node_by_type(NULL, "cpu"); | ||||
| 	if (!node) { | ||||
| 		pr_warning("Unable to find \"cpu\" devicetree entry"); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (of_property_read_string(node, "riscv,isa", &isa)) { | ||||
| 		pr_warning("Unable to find \"riscv,isa\" devicetree entry"); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < strlen(isa); ++i) | ||||
| 		elf_hwcap |= isa2hwcap[(unsigned char)(isa[i])]; | ||||
| 
 | ||||
| 	pr_info("elf_hwcap is 0x%lx", elf_hwcap); | ||||
| } | ||||
							
								
								
									
										217
									
								
								arch/riscv/kernel/module.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								arch/riscv/kernel/module.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,217 @@ | ||||
| /*
 | ||||
|  *  This program is free software; you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation; either version 2 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  This program is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  Copyright (C) 2017 Zihao Yu | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/elf.h> | ||||
| #include <linux/err.h> | ||||
| #include <linux/errno.h> | ||||
| #include <linux/moduleloader.h> | ||||
| 
 | ||||
| static int apply_r_riscv_64_rela(struct module *me, u32 *location, Elf_Addr v) | ||||
| { | ||||
| 	*(u64 *)location = v; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int apply_r_riscv_branch_rela(struct module *me, u32 *location, | ||||
| 				     Elf_Addr v) | ||||
| { | ||||
| 	s64 offset = (void *)v - (void *)location; | ||||
| 	u32 imm12 = (offset & 0x1000) << (31 - 12); | ||||
| 	u32 imm11 = (offset & 0x800) >> (11 - 7); | ||||
| 	u32 imm10_5 = (offset & 0x7e0) << (30 - 10); | ||||
| 	u32 imm4_1 = (offset & 0x1e) << (11 - 4); | ||||
| 
 | ||||
| 	*location = (*location & 0x1fff07f) | imm12 | imm11 | imm10_5 | imm4_1; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int apply_r_riscv_jal_rela(struct module *me, u32 *location, | ||||
| 				  Elf_Addr v) | ||||
| { | ||||
| 	s64 offset = (void *)v - (void *)location; | ||||
| 	u32 imm20 = (offset & 0x100000) << (31 - 20); | ||||
| 	u32 imm19_12 = (offset & 0xff000); | ||||
| 	u32 imm11 = (offset & 0x800) << (20 - 11); | ||||
| 	u32 imm10_1 = (offset & 0x7fe) << (30 - 10); | ||||
| 
 | ||||
| 	*location = (*location & 0xfff) | imm20 | imm19_12 | imm11 | imm10_1; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int apply_r_riscv_pcrel_hi20_rela(struct module *me, u32 *location, | ||||
| 					 Elf_Addr v) | ||||
| { | ||||
| 	s64 offset = (void *)v - (void *)location; | ||||
| 	s32 hi20; | ||||
| 
 | ||||
| 	if (offset != (s32)offset) { | ||||
| 		pr_err( | ||||
| 		  "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n", | ||||
| 		  me->name, v, location); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	hi20 = (offset + 0x800) & 0xfffff000; | ||||
| 	*location = (*location & 0xfff) | hi20; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int apply_r_riscv_pcrel_lo12_i_rela(struct module *me, u32 *location, | ||||
| 					   Elf_Addr v) | ||||
| { | ||||
| 	/*
 | ||||
| 	 * v is the lo12 value to fill. It is calculated before calling this | ||||
| 	 * handler. | ||||
| 	 */ | ||||
| 	*location = (*location & 0xfffff) | ((v & 0xfff) << 20); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int apply_r_riscv_pcrel_lo12_s_rela(struct module *me, u32 *location, | ||||
| 					   Elf_Addr v) | ||||
| { | ||||
| 	/*
 | ||||
| 	 * v is the lo12 value to fill. It is calculated before calling this | ||||
| 	 * handler. | ||||
| 	 */ | ||||
| 	u32 imm11_5 = (v & 0xfe0) << (31 - 11); | ||||
| 	u32 imm4_0 = (v & 0x1f) << (11 - 4); | ||||
| 
 | ||||
| 	*location = (*location & 0x1fff07f) | imm11_5 | imm4_0; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int apply_r_riscv_call_plt_rela(struct module *me, u32 *location, | ||||
| 				       Elf_Addr v) | ||||
| { | ||||
| 	s64 offset = (void *)v - (void *)location; | ||||
| 	s32 fill_v = offset; | ||||
| 	u32 hi20, lo12; | ||||
| 
 | ||||
| 	if (offset != fill_v) { | ||||
| 		pr_err( | ||||
| 		  "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n", | ||||
| 		  me->name, v, location); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	hi20 = (offset + 0x800) & 0xfffff000; | ||||
| 	lo12 = (offset - hi20) & 0xfff; | ||||
| 	*location = (*location & 0xfff) | hi20; | ||||
| 	*(location + 1) = (*(location + 1) & 0xfffff) | (lo12 << 20); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int apply_r_riscv_relax_rela(struct module *me, u32 *location, | ||||
| 				    Elf_Addr v) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int (*reloc_handlers_rela[]) (struct module *me, u32 *location, | ||||
| 				Elf_Addr v) = { | ||||
| 	[R_RISCV_64]			= apply_r_riscv_64_rela, | ||||
| 	[R_RISCV_BRANCH]		= apply_r_riscv_branch_rela, | ||||
| 	[R_RISCV_JAL]			= apply_r_riscv_jal_rela, | ||||
| 	[R_RISCV_PCREL_HI20]		= apply_r_riscv_pcrel_hi20_rela, | ||||
| 	[R_RISCV_PCREL_LO12_I]		= apply_r_riscv_pcrel_lo12_i_rela, | ||||
| 	[R_RISCV_PCREL_LO12_S]		= apply_r_riscv_pcrel_lo12_s_rela, | ||||
| 	[R_RISCV_CALL_PLT]		= apply_r_riscv_call_plt_rela, | ||||
| 	[R_RISCV_RELAX]			= apply_r_riscv_relax_rela, | ||||
| }; | ||||
| 
 | ||||
| int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, | ||||
| 		       unsigned int symindex, unsigned int relsec, | ||||
| 		       struct module *me) | ||||
| { | ||||
| 	Elf_Rela *rel = (void *) sechdrs[relsec].sh_addr; | ||||
| 	int (*handler)(struct module *me, u32 *location, Elf_Addr v); | ||||
| 	Elf_Sym *sym; | ||||
| 	u32 *location; | ||||
| 	unsigned int i, type; | ||||
| 	Elf_Addr v; | ||||
| 	int res; | ||||
| 
 | ||||
| 	pr_debug("Applying relocate section %u to %u\n", relsec, | ||||
| 	       sechdrs[relsec].sh_info); | ||||
| 
 | ||||
| 	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { | ||||
| 		/* This is where to make the change */ | ||||
| 		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr | ||||
| 			+ rel[i].r_offset; | ||||
| 		/* This is the symbol it is referring to */ | ||||
| 		sym = (Elf_Sym *)sechdrs[symindex].sh_addr | ||||
| 			+ ELF_RISCV_R_SYM(rel[i].r_info); | ||||
| 		if (IS_ERR_VALUE(sym->st_value)) { | ||||
| 			/* Ignore unresolved weak symbol */ | ||||
| 			if (ELF_ST_BIND(sym->st_info) == STB_WEAK) | ||||
| 				continue; | ||||
| 			pr_warning("%s: Unknown symbol %s\n", | ||||
| 				   me->name, strtab + sym->st_name); | ||||
| 			return -ENOENT; | ||||
| 		} | ||||
| 
 | ||||
| 		type = ELF_RISCV_R_TYPE(rel[i].r_info); | ||||
| 
 | ||||
| 		if (type < ARRAY_SIZE(reloc_handlers_rela)) | ||||
| 			handler = reloc_handlers_rela[type]; | ||||
| 		else | ||||
| 			handler = NULL; | ||||
| 
 | ||||
| 		if (!handler) { | ||||
| 			pr_err("%s: Unknown relocation type %u\n", | ||||
| 			       me->name, type); | ||||
| 			return -EINVAL; | ||||
| 		} | ||||
| 
 | ||||
| 		v = sym->st_value + rel[i].r_addend; | ||||
| 
 | ||||
| 		if (type == R_RISCV_PCREL_LO12_I || type == R_RISCV_PCREL_LO12_S) { | ||||
| 			unsigned int j; | ||||
| 
 | ||||
| 			for (j = 0; j < sechdrs[relsec].sh_size / sizeof(*rel); j++) { | ||||
| 				u64 hi20_loc = | ||||
| 					sechdrs[sechdrs[relsec].sh_info].sh_addr | ||||
| 					+ rel[j].r_offset; | ||||
| 				/* Find the corresponding HI20 PC-relative relocation entry */ | ||||
| 				if (hi20_loc == sym->st_value) { | ||||
| 					Elf_Sym *hi20_sym = | ||||
| 						(Elf_Sym *)sechdrs[symindex].sh_addr | ||||
| 						+ ELF_RISCV_R_SYM(rel[j].r_info); | ||||
| 					u64 hi20_sym_val = | ||||
| 						hi20_sym->st_value | ||||
| 						+ rel[j].r_addend; | ||||
| 					/* Calculate lo12 */ | ||||
| 					s64 offset = hi20_sym_val - hi20_loc; | ||||
| 					s32 hi20 = (offset + 0x800) & 0xfffff000; | ||||
| 					s32 lo12 = offset - hi20; | ||||
| 					v = lo12; | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 			if (j == sechdrs[relsec].sh_size / sizeof(*rel)) { | ||||
| 				pr_err( | ||||
| 				  "%s: Can not find HI20 PC-relative relocation information\n", | ||||
| 				  me->name); | ||||
| 				return -EINVAL; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		res = handler(me, location, v); | ||||
| 		if (res) | ||||
| 			return res; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
							
								
								
									
										125
									
								
								arch/riscv/kernel/ptrace.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								arch/riscv/kernel/ptrace.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,125 @@ | ||||
| /*
 | ||||
|  * Copyright 2010 Tilera Corporation. All Rights Reserved. | ||||
|  * Copyright 2015 Regents of the University of California | ||||
|  * Copyright 2017 SiFive | ||||
|  * | ||||
|  *   This program is free software; you can redistribute it and/or | ||||
|  *   modify it under the terms of the GNU General Public License | ||||
|  *   as published by the Free Software Foundation, version 2. | ||||
|  * | ||||
|  *   This program is distributed in the hope that it will be useful, | ||||
|  *   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *   GNU General Public License for more details. | ||||
|  * | ||||
|  * Copied from arch/tile/kernel/ptrace.c | ||||
|  */ | ||||
| 
 | ||||
| #include <asm/ptrace.h> | ||||
| #include <asm/syscall.h> | ||||
| #include <asm/thread_info.h> | ||||
| #include <linux/ptrace.h> | ||||
| #include <linux/elf.h> | ||||
| #include <linux/regset.h> | ||||
| #include <linux/sched.h> | ||||
| #include <linux/sched/task_stack.h> | ||||
| #include <linux/tracehook.h> | ||||
| #include <trace/events/syscalls.h> | ||||
| 
 | ||||
| enum riscv_regset { | ||||
| 	REGSET_X, | ||||
| }; | ||||
| 
 | ||||
| static int riscv_gpr_get(struct task_struct *target, | ||||
| 			 const struct user_regset *regset, | ||||
| 			 unsigned int pos, unsigned int count, | ||||
| 			 void *kbuf, void __user *ubuf) | ||||
| { | ||||
| 	struct pt_regs *regs; | ||||
| 
 | ||||
| 	regs = task_pt_regs(target); | ||||
| 	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs, 0, -1); | ||||
| } | ||||
| 
 | ||||
| static int riscv_gpr_set(struct task_struct *target, | ||||
| 			 const struct user_regset *regset, | ||||
| 			 unsigned int pos, unsigned int count, | ||||
| 			 const void *kbuf, const void __user *ubuf) | ||||
| { | ||||
| 	int ret; | ||||
| 	struct pt_regs *regs; | ||||
| 
 | ||||
| 	regs = task_pt_regs(target); | ||||
| 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®s, 0, -1); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static const struct user_regset riscv_user_regset[] = { | ||||
| 	[REGSET_X] = { | ||||
| 		.core_note_type = NT_PRSTATUS, | ||||
| 		.n = ELF_NGREG, | ||||
| 		.size = sizeof(elf_greg_t), | ||||
| 		.align = sizeof(elf_greg_t), | ||||
| 		.get = &riscv_gpr_get, | ||||
| 		.set = &riscv_gpr_set, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static const struct user_regset_view riscv_user_native_view = { | ||||
| 	.name = "riscv", | ||||
| 	.e_machine = EM_RISCV, | ||||
| 	.regsets = riscv_user_regset, | ||||
| 	.n = ARRAY_SIZE(riscv_user_regset), | ||||
| }; | ||||
| 
 | ||||
| const struct user_regset_view *task_user_regset_view(struct task_struct *task) | ||||
| { | ||||
| 	return &riscv_user_native_view; | ||||
| } | ||||
| 
 | ||||
| void ptrace_disable(struct task_struct *child) | ||||
| { | ||||
| 	clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||||
| } | ||||
| 
 | ||||
| long arch_ptrace(struct task_struct *child, long request, | ||||
| 		 unsigned long addr, unsigned long data) | ||||
| { | ||||
| 	long ret = -EIO; | ||||
| 
 | ||||
| 	switch (request) { | ||||
| 	default: | ||||
| 		ret = ptrace_request(child, request, addr, data); | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Allows PTRACE_SYSCALL to work.  These are called from entry.S in | ||||
|  * {handle,ret_from}_syscall. | ||||
|  */ | ||||
| void do_syscall_trace_enter(struct pt_regs *regs) | ||||
| { | ||||
| 	if (test_thread_flag(TIF_SYSCALL_TRACE)) | ||||
| 		if (tracehook_report_syscall_entry(regs)) | ||||
| 			syscall_set_nr(current, regs, -1); | ||||
| 
 | ||||
| #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS | ||||
| 	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) | ||||
| 		trace_sys_enter(regs, syscall_get_nr(current, regs)); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| void do_syscall_trace_exit(struct pt_regs *regs) | ||||
| { | ||||
| 	if (test_thread_flag(TIF_SYSCALL_TRACE)) | ||||
| 		tracehook_report_syscall_exit(regs, 0); | ||||
| 
 | ||||
| #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS | ||||
| 	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) | ||||
| 		trace_sys_exit(regs, regs->regs[0]); | ||||
| #endif | ||||
| } | ||||
							
								
								
									
										15
									
								
								arch/riscv/kernel/riscv_ksyms.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								arch/riscv/kernel/riscv_ksyms.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| /*
 | ||||
|  * Copyright (C) 2017 Zihao Yu | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License version 2 as | ||||
|  * published by the Free Software Foundation. | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/export.h> | ||||
| #include <linux/uaccess.h> | ||||
| 
 | ||||
| /*
 | ||||
|  * Assembly functions that may be used (directly or indirectly) by modules | ||||
|  */ | ||||
| EXPORT_SYMBOL(__copy_user); | ||||
							
								
								
									
										292
									
								
								arch/riscv/kernel/signal.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										292
									
								
								arch/riscv/kernel/signal.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,292 @@ | ||||
| /*
 | ||||
|  * 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 | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, see the file COPYING, or write | ||||
|  * to the Free Software Foundation, Inc., | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/signal.h> | ||||
| #include <linux/uaccess.h> | ||||
| #include <linux/syscalls.h> | ||||
| #include <linux/tracehook.h> | ||||
| #include <linux/linkage.h> | ||||
| 
 | ||||
| #include <asm/ucontext.h> | ||||
| #include <asm/vdso.h> | ||||
| #include <asm/switch_to.h> | ||||
| #include <asm/csr.h> | ||||
| 
 | ||||
| #define DEBUG_SIG 0 | ||||
| 
 | ||||
| struct rt_sigframe { | ||||
| 	struct siginfo info; | ||||
| 	struct ucontext uc; | ||||
| }; | ||||
| 
 | ||||
| static long restore_d_state(struct pt_regs *regs, | ||||
| 	struct __riscv_d_ext_state __user *state) | ||||
| { | ||||
| 	long err; | ||||
| 	err = __copy_from_user(¤t->thread.fstate, state, sizeof(*state)); | ||||
| 	if (likely(!err)) | ||||
| 		fstate_restore(current, regs); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static long save_d_state(struct pt_regs *regs, | ||||
| 	struct __riscv_d_ext_state __user *state) | ||||
| { | ||||
| 	fstate_save(current, regs); | ||||
| 	return __copy_to_user(state, ¤t->thread.fstate, sizeof(*state)); | ||||
| } | ||||
| 
 | ||||
| static long restore_sigcontext(struct pt_regs *regs, | ||||
| 	struct sigcontext __user *sc) | ||||
| { | ||||
| 	long err; | ||||
| 	size_t i; | ||||
| 	/* sc_regs is structured the same as the start of pt_regs */ | ||||
| 	err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs)); | ||||
| 	if (unlikely(err)) | ||||
| 		return err; | ||||
| 	/* Restore the floating-point state. */ | ||||
| 	err = restore_d_state(regs, &sc->sc_fpregs.d); | ||||
| 	if (unlikely(err)) | ||||
| 		return err; | ||||
| 	/* We support no other extension state at this time. */ | ||||
| 	for (i = 0; i < ARRAY_SIZE(sc->sc_fpregs.q.reserved); i++) { | ||||
| 		u32 value; | ||||
| 		err = __get_user(value, &sc->sc_fpregs.q.reserved[i]); | ||||
| 		if (unlikely(err)) | ||||
| 			break; | ||||
| 		if (value != 0) | ||||
| 			return -EINVAL; | ||||
| 	} | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| SYSCALL_DEFINE0(rt_sigreturn) | ||||
| { | ||||
| 	struct pt_regs *regs = current_pt_regs(); | ||||
| 	struct rt_sigframe __user *frame; | ||||
| 	struct task_struct *task; | ||||
| 	sigset_t set; | ||||
| 
 | ||||
| 	/* Always make any pending restarted system calls return -EINTR */ | ||||
| 	current->restart_block.fn = do_no_restart_syscall; | ||||
| 
 | ||||
| 	frame = (struct rt_sigframe __user *)regs->sp; | ||||
| 
 | ||||
| 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||||
| 		goto badframe; | ||||
| 
 | ||||
| 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | ||||
| 		goto badframe; | ||||
| 
 | ||||
| 	set_current_blocked(&set); | ||||
| 
 | ||||
| 	if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) | ||||
| 		goto badframe; | ||||
| 
 | ||||
| 	if (restore_altstack(&frame->uc.uc_stack)) | ||||
| 		goto badframe; | ||||
| 
 | ||||
| 	return regs->a0; | ||||
| 
 | ||||
| badframe: | ||||
| 	task = current; | ||||
| 	if (show_unhandled_signals) { | ||||
| 		pr_info_ratelimited( | ||||
| 			"%s[%d]: bad frame in %s: frame=%p pc=%p sp=%p\n", | ||||
| 			task->comm, task_pid_nr(task), __func__, | ||||
| 			frame, (void *)regs->sepc, (void *)regs->sp); | ||||
| 	} | ||||
| 	force_sig(SIGSEGV, task); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static long setup_sigcontext(struct rt_sigframe __user *frame, | ||||
| 	struct pt_regs *regs) | ||||
| { | ||||
| 	struct sigcontext __user *sc = &frame->uc.uc_mcontext; | ||||
| 	long err; | ||||
| 	size_t i; | ||||
| 	/* sc_regs is structured the same as the start of pt_regs */ | ||||
| 	err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs)); | ||||
| 	/* Save the floating-point state. */ | ||||
| 	err |= save_d_state(regs, &sc->sc_fpregs.d); | ||||
| 	/* We support no other extension state at this time. */ | ||||
| 	for (i = 0; i < ARRAY_SIZE(sc->sc_fpregs.q.reserved); i++) | ||||
| 		err |= __put_user(0, &sc->sc_fpregs.q.reserved[i]); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static inline void __user *get_sigframe(struct ksignal *ksig, | ||||
| 	struct pt_regs *regs, size_t framesize) | ||||
| { | ||||
| 	unsigned long sp; | ||||
| 	/* Default to using normal stack */ | ||||
| 	sp = regs->sp; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If we are on the alternate signal stack and would overflow it, don't. | ||||
| 	 * Return an always-bogus address instead so we will die with SIGSEGV. | ||||
| 	 */ | ||||
| 	if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize))) | ||||
| 		return (void __user __force *)(-1UL); | ||||
| 
 | ||||
| 	/* This is the X/Open sanctioned signal stack switching. */ | ||||
| 	sp = sigsp(sp, ksig) - framesize; | ||||
| 
 | ||||
| 	/* Align the stack frame. */ | ||||
| 	sp &= ~0xfUL; | ||||
| 
 | ||||
| 	return (void __user *)sp; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, | ||||
| 	struct pt_regs *regs) | ||||
| { | ||||
| 	struct rt_sigframe __user *frame; | ||||
| 	long err = 0; | ||||
| 
 | ||||
| 	frame = get_sigframe(ksig, regs, sizeof(*frame)); | ||||
| 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | ||||
| 		return -EFAULT; | ||||
| 
 | ||||
| 	err |= copy_siginfo_to_user(&frame->info, &ksig->info); | ||||
| 
 | ||||
| 	/* Create the ucontext. */ | ||||
| 	err |= __put_user(0, &frame->uc.uc_flags); | ||||
| 	err |= __put_user(NULL, &frame->uc.uc_link); | ||||
| 	err |= __save_altstack(&frame->uc.uc_stack, regs->sp); | ||||
| 	err |= setup_sigcontext(frame, regs); | ||||
| 	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | ||||
| 	if (err) | ||||
| 		return -EFAULT; | ||||
| 
 | ||||
| 	/* Set up to return from userspace. */ | ||||
| 	regs->ra = (unsigned long)VDSO_SYMBOL( | ||||
| 		current->mm->context.vdso, rt_sigreturn); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Set up registers for signal handler. | ||||
| 	 * Registers that we don't modify keep the value they had from | ||||
| 	 * user-space at the time we took the signal. | ||||
| 	 * We always pass siginfo and mcontext, regardless of SA_SIGINFO, | ||||
| 	 * since some things rely on this (e.g. glibc's debug/segfault.c). | ||||
| 	 */ | ||||
| 	regs->sepc = (unsigned long)ksig->ka.sa.sa_handler; | ||||
| 	regs->sp = (unsigned long)frame; | ||||
| 	regs->a0 = ksig->sig;                     /* a0: signal number */ | ||||
| 	regs->a1 = (unsigned long)(&frame->info); /* a1: siginfo pointer */ | ||||
| 	regs->a2 = (unsigned long)(&frame->uc);   /* a2: ucontext pointer */ | ||||
| 
 | ||||
| #if DEBUG_SIG | ||||
| 	pr_info("SIG deliver (%s:%d): sig=%d pc=%p ra=%p sp=%p\n", | ||||
| 		current->comm, task_pid_nr(current), ksig->sig, | ||||
| 		(void *)regs->sepc, (void *)regs->ra, frame); | ||||
| #endif | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) | ||||
| { | ||||
| 	sigset_t *oldset = sigmask_to_save(); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	/* Are we from a system call? */ | ||||
| 	if (regs->scause == EXC_SYSCALL) { | ||||
| 		/* If so, check system call restarting.. */ | ||||
| 		switch (regs->a0) { | ||||
| 		case -ERESTART_RESTARTBLOCK: | ||||
| 		case -ERESTARTNOHAND: | ||||
| 			regs->a0 = -EINTR; | ||||
| 			break; | ||||
| 
 | ||||
| 		case -ERESTARTSYS: | ||||
| 			if (!(ksig->ka.sa.sa_flags & SA_RESTART)) { | ||||
| 				regs->a0 = -EINTR; | ||||
| 				break; | ||||
| 			} | ||||
| 			/* fallthrough */ | ||||
| 		case -ERESTARTNOINTR: | ||||
|                         regs->a0 = regs->orig_a0; | ||||
| 			regs->sepc -= 0x4; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* Set up the stack frame */ | ||||
| 	ret = setup_rt_frame(ksig, oldset, regs); | ||||
| 
 | ||||
| 	signal_setup_done(ret, ksig, 0); | ||||
| } | ||||
| 
 | ||||
| static void do_signal(struct pt_regs *regs) | ||||
| { | ||||
| 	struct ksignal ksig; | ||||
| 
 | ||||
| 	if (get_signal(&ksig)) { | ||||
| 		/* Actually deliver the signal */ | ||||
| 		handle_signal(&ksig, regs); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Did we come from a system call? */ | ||||
| 	if (regs->scause == EXC_SYSCALL) { | ||||
| 		/* Restart the system call - no handlers present */ | ||||
| 		switch (regs->a0) { | ||||
| 		case -ERESTARTNOHAND: | ||||
| 		case -ERESTARTSYS: | ||||
| 		case -ERESTARTNOINTR: | ||||
|                         regs->a0 = regs->orig_a0; | ||||
| 			regs->sepc -= 0x4; | ||||
| 			break; | ||||
| 		case -ERESTART_RESTARTBLOCK: | ||||
|                         regs->a0 = regs->orig_a0; | ||||
| 			regs->a7 = __NR_restart_syscall; | ||||
| 			regs->sepc -= 0x4; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If there is no signal to deliver, we just put the saved | ||||
| 	 * sigmask back. | ||||
| 	 */ | ||||
| 	restore_saved_sigmask(); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * notification of userspace execution resumption | ||||
|  * - triggered by the _TIF_WORK_MASK flags | ||||
|  */ | ||||
| asmlinkage void do_notify_resume(struct pt_regs *regs, | ||||
| 	unsigned long thread_info_flags) | ||||
| { | ||||
| 	/* Handle pending signal delivery */ | ||||
| 	if (thread_info_flags & _TIF_SIGPENDING) | ||||
| 		do_signal(regs); | ||||
| 
 | ||||
| 	if (thread_info_flags & _TIF_NOTIFY_RESUME) { | ||||
| 		clear_thread_flag(TIF_NOTIFY_RESUME); | ||||
| 		tracehook_notify_resume(regs); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										49
									
								
								arch/riscv/kernel/sys_riscv.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								arch/riscv/kernel/sys_riscv.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | ||||
| /*
 | ||||
|  * Copyright (C) 2012 Regents of the University of California | ||||
|  * Copyright (C) 2014 Darius Rad <darius@bluespec.com> | ||||
|  * Copyright (C) 2017 SiFive | ||||
|  * | ||||
|  *   This program is free software; you can redistribute it and/or | ||||
|  *   modify it under the terms of the GNU General Public License | ||||
|  *   as published by the Free Software Foundation, version 2. | ||||
|  * | ||||
|  *   This program is distributed in the hope that it will be useful, | ||||
|  *   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *   GNU General Public License for more details. | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/syscalls.h> | ||||
| #include <asm/cmpxchg.h> | ||||
| #include <asm/unistd.h> | ||||
| 
 | ||||
| static long riscv_sys_mmap(unsigned long addr, unsigned long len, | ||||
| 			   unsigned long prot, unsigned long flags, | ||||
| 			   unsigned long fd, off_t offset, | ||||
| 			   unsigned long page_shift_offset) | ||||
| { | ||||
| 	if (unlikely(offset & (~PAGE_MASK >> page_shift_offset))) | ||||
| 		return -EINVAL; | ||||
| 	return sys_mmap_pgoff(addr, len, prot, flags, fd, | ||||
| 			      offset >> (PAGE_SHIFT - page_shift_offset)); | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_64BIT | ||||
| SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len, | ||||
| 	unsigned long, prot, unsigned long, flags, | ||||
| 	unsigned long, fd, off_t, offset) | ||||
| { | ||||
| 	return riscv_sys_mmap(addr, len, prot, flags, fd, offset, 0); | ||||
| } | ||||
| #else | ||||
| SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len, | ||||
| 	unsigned long, prot, unsigned long, flags, | ||||
| 	unsigned long, fd, off_t, offset) | ||||
| { | ||||
| 	/*
 | ||||
| 	 * Note that the shift for mmap2 is constant (12), | ||||
| 	 * regardless of PAGE_SIZE | ||||
| 	 */ | ||||
| 	return riscv_sys_mmap(addr, len, prot, flags, fd, offset, 12); | ||||
| } | ||||
| #endif /* !CONFIG_64BIT */ | ||||
							
								
								
									
										25
									
								
								arch/riscv/kernel/syscall_table.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								arch/riscv/kernel/syscall_table.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| /*
 | ||||
|  * Copyright (C) 2009 Arnd Bergmann <arnd@arndb.de> | ||||
|  * Copyright (C) 2012 Regents of the University of California | ||||
|  * | ||||
|  *   This program is free software; you can redistribute it and/or | ||||
|  *   modify it under the terms of the GNU General Public License | ||||
|  *   as published by the Free Software Foundation, version 2. | ||||
|  * | ||||
|  *   This program is distributed in the hope that it will be useful, | ||||
|  *   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *   GNU General Public License for more details. | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/linkage.h> | ||||
| #include <linux/syscalls.h> | ||||
| #include <asm-generic/syscalls.h> | ||||
| 
 | ||||
| #undef __SYSCALL | ||||
| #define __SYSCALL(nr, call)	[nr] = (call), | ||||
| 
 | ||||
| void *sys_call_table[__NR_syscalls] = { | ||||
| 	[0 ... __NR_syscalls - 1] = sys_ni_syscall, | ||||
| #include <asm/unistd.h> | ||||
| }; | ||||
							
								
								
									
										2
									
								
								arch/riscv/kernel/vdso/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								arch/riscv/kernel/vdso/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | ||||
| vdso.lds | ||||
| *.tmp | ||||
							
								
								
									
										63
									
								
								arch/riscv/kernel/vdso/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								arch/riscv/kernel/vdso/Makefile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | ||||
| # Copied from arch/tile/kernel/vdso/Makefile
 | ||||
| 
 | ||||
| # Symbols present in the vdso
 | ||||
| vdso-syms = rt_sigreturn | ||||
| 
 | ||||
| # Files to link into the vdso
 | ||||
| obj-vdso = $(patsubst %, %.o, $(vdso-syms)) | ||||
| 
 | ||||
| # Build rules
 | ||||
| targets := $(obj-vdso) vdso.so vdso.so.dbg vdso.lds vdso-dummy.o | ||||
| obj-vdso := $(addprefix $(obj)/, $(obj-vdso)) | ||||
| 
 | ||||
| obj-y += vdso.o vdso-syms.o | ||||
| CPPFLAGS_vdso.lds += -P -C -U$(ARCH) | ||||
| 
 | ||||
| # Disable gcov profiling for VDSO code
 | ||||
| GCOV_PROFILE := n | ||||
| 
 | ||||
| # Force dependency
 | ||||
| $(obj)/vdso.o: $(obj)/vdso.so | ||||
| 
 | ||||
| # link rule for the .so file, .lds has to be first
 | ||||
| SYSCFLAGS_vdso.so.dbg = $(c_flags) | ||||
| $(obj)/vdso.so.dbg: $(src)/vdso.lds $(obj-vdso) FORCE | ||||
| 	$(call if_changed,vdsold) | ||||
| 
 | ||||
| # We also create a special relocatable object that should mirror the symbol
 | ||||
| # table and layout of the linked DSO.  With ld -R we can then refer to
 | ||||
| # these symbols in the kernel code rather than hand-coded addresses.
 | ||||
| 
 | ||||
| SYSCFLAGS_vdso.so.dbg = -shared -s -Wl,-soname=linux-vdso.so.1 \
 | ||||
|                             $(call cc-ldoption, -Wl$(comma)--hash-style=both) | ||||
| $(obj)/vdso-dummy.o: $(src)/vdso.lds $(obj)/rt_sigreturn.o FORCE | ||||
| 	$(call if_changed,vdsold) | ||||
| 
 | ||||
| LDFLAGS_vdso-syms.o := -r -R | ||||
| $(obj)/vdso-syms.o: $(obj)/vdso-dummy.o FORCE | ||||
| 	$(call if_changed,ld) | ||||
| 
 | ||||
| # strip rule for the .so file
 | ||||
| $(obj)/%.so: OBJCOPYFLAGS := -S | ||||
| $(obj)/%.so: $(obj)/%.so.dbg FORCE | ||||
| 	$(call if_changed,objcopy) | ||||
| 
 | ||||
| # actual build commands
 | ||||
| # The DSO images are built using a special linker script
 | ||||
| # Add -lgcc so rv32 gets static muldi3 and lshrdi3 definitions.
 | ||||
| # Make sure only to export the intended __vdso_xxx symbol offsets.
 | ||||
| quiet_cmd_vdsold = VDSOLD  $@ | ||||
|       cmd_vdsold = $(CC) $(KCFLAGS) -nostdlib $(SYSCFLAGS_$(@F)) \
 | ||||
|                            -Wl,-T,$(filter-out FORCE,$^) -o $@.tmp -lgcc && \
 | ||||
|                    $(CROSS_COMPILE)objcopy \
 | ||||
|                            $(patsubst %, -G __vdso_%, $(vdso-syms)) $@.tmp $@ | ||||
| 
 | ||||
| # install commands for the unstripped file
 | ||||
| quiet_cmd_vdso_install = INSTALL $@ | ||||
|       cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ | ||||
| 
 | ||||
| vdso.so: $(obj)/vdso.so.dbg | ||||
| 	@mkdir -p $(MODLIB)/vdso | ||||
| 	$(call cmd,vdso_install) | ||||
| 
 | ||||
| vdso_install: vdso.so | ||||
							
								
								
									
										24
									
								
								arch/riscv/kernel/vdso/rt_sigreturn.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								arch/riscv/kernel/vdso/rt_sigreturn.S
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| /* | ||||
|  * Copyright (C) 2014 Regents of the University of California | ||||
|  * | ||||
|  *   This program is free software; you can redistribute it and/or
 | ||||
|  *   modify it under the terms of the GNU General Public License | ||||
|  *   as published by the Free Software Foundation, version 2. | ||||
|  * | ||||
|  *   This program is distributed in the hope that it will be useful, | ||||
|  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||
|  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *   GNU General Public License for more details. | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/linkage.h> | ||||
| #include <asm/unistd.h> | ||||
| 
 | ||||
| 	.text | ||||
| ENTRY(__vdso_rt_sigreturn) | ||||
| 	.cfi_startproc | ||||
| 	.cfi_signal_frame | ||||
| 	li a7, __NR_rt_sigreturn | ||||
| 	scall | ||||
| 	.cfi_endproc | ||||
| ENDPROC(__vdso_rt_sigreturn) | ||||
							
								
								
									
										27
									
								
								arch/riscv/kernel/vdso/vdso.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								arch/riscv/kernel/vdso/vdso.S
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| /* | ||||
|  * Copyright (C) 2014 Regents of the University of California | ||||
|  * | ||||
|  *   This program is free software; you can redistribute it and/or
 | ||||
|  *   modify it under the terms of the GNU General Public License | ||||
|  *   as published by the Free Software Foundation, version 2. | ||||
|  * | ||||
|  *   This program is distributed in the hope that it will be useful, | ||||
|  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||
|  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *   GNU General Public License for more details. | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/init.h> | ||||
| #include <linux/linkage.h> | ||||
| #include <asm/page.h> | ||||
| 
 | ||||
| 	__PAGE_ALIGNED_DATA | ||||
| 
 | ||||
| 	.globl vdso_start, vdso_end | ||||
| 	.balign PAGE_SIZE
 | ||||
| vdso_start: | ||||
| 	.incbin "arch/riscv/kernel/vdso/vdso.so" | ||||
| 	.balign PAGE_SIZE
 | ||||
| vdso_end: | ||||
| 
 | ||||
| 	.previous | ||||
							
								
								
									
										77
									
								
								arch/riscv/kernel/vdso/vdso.lds.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								arch/riscv/kernel/vdso/vdso.lds.S
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,77 @@ | ||||
| /* | ||||
|  * Copyright (C) 2012 Regents of the University of California | ||||
|  * | ||||
|  *   This program is free software; you can redistribute it and/or
 | ||||
|  *   modify it under the terms of the GNU General Public License | ||||
|  *   as published by the Free Software Foundation, version 2. | ||||
|  * | ||||
|  *   This program is distributed in the hope that it will be useful, | ||||
|  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||
|  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *   GNU General Public License for more details. | ||||
|  */ | ||||
| 
 | ||||
| OUTPUT_ARCH(riscv) | ||||
| 
 | ||||
| SECTIONS | ||||
| { | ||||
| 	. = SIZEOF_HEADERS;
 | ||||
| 
 | ||||
| 	.hash		: { *(.hash) }			:text | ||||
| 	.gnu.hash	: { *(.gnu.hash) } | ||||
| 	.dynsym		: { *(.dynsym) } | ||||
| 	.dynstr		: { *(.dynstr) } | ||||
| 	.gnu.version	: { *(.gnu.version) } | ||||
| 	.gnu.version_d	: { *(.gnu.version_d) } | ||||
| 	.gnu.version_r	: { *(.gnu.version_r) } | ||||
| 
 | ||||
| 	.note		: { *(.note.*) }		:text	:note | ||||
| 	.dynamic	: { *(.dynamic) }		:text	:dynamic | ||||
| 
 | ||||
| 	.eh_frame_hdr	: { *(.eh_frame_hdr) }		:text	:eh_frame_hdr | ||||
| 	.eh_frame	: { KEEP (*(.eh_frame)) }	:text | ||||
| 
 | ||||
| 	.rodata		: { *(.rodata .rodata.* .gnu.linkonce.r.*) } | ||||
| 
 | ||||
| 	/* | ||||
| 	 * This linker script is used both with -r and with -shared. | ||||
| 	 * For the layouts to match, we need to skip more than enough | ||||
| 	 * space for the dynamic symbol table, etc. If this amount is | ||||
| 	 * insufficient, ld -shared will error; simply increase it here.
 | ||||
| 	 */ | ||||
| 	. = 0x800;
 | ||||
| 	.text		: { *(.text .text.*) }		:text | ||||
| 
 | ||||
| 	.data		: { | ||||
| 		*(.got.plt) *(.got) | ||||
| 		*(.data .data.* .gnu.linkonce.d.*) | ||||
| 		*(.dynbss) | ||||
| 		*(.bss .bss.* .gnu.linkonce.b.*) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  * We must supply the ELF program headers explicitly to get just one | ||||
|  * PT_LOAD segment, and set the flags explicitly to make segments read-only. | ||||
|  */ | ||||
| PHDRS | ||||
| { | ||||
| 	text		PT_LOAD		FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */
 | ||||
| 	dynamic		PT_DYNAMIC	FLAGS(4);		/* PF_R */
 | ||||
| 	note		PT_NOTE		FLAGS(4);		/* PF_R */
 | ||||
| 	eh_frame_hdr	PT_GNU_EH_FRAME;
 | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  * This controls what symbols we export from the DSO. | ||||
|  */ | ||||
| VERSION | ||||
| { | ||||
| 	LINUX_4.15 { | ||||
| 	global: | ||||
| 		__vdso_rt_sigreturn;
 | ||||
| 		__vdso_cmpxchg32;
 | ||||
| 		__vdso_cmpxchg64;
 | ||||
| 	local: *;
 | ||||
| 	};
 | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user