aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPalmer Dabbelt <palmer@dabbelt.com>2017-07-10 21:07:09 -0400
committerPalmer Dabbelt <palmer@dabbelt.com>2017-09-26 18:26:48 -0400
commite2c0cdfba7f69925afc92b20cd9835d81e11a4f1 (patch)
tree2c501638321da451423b385652183d60da02db5c
parent07037db5d479f90377c998259a4f9a469c404edf (diff)
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>
-rw-r--r--arch/riscv/include/asm/mmu.h26
-rw-r--r--arch/riscv/include/asm/ptrace.h118
-rw-r--r--arch/riscv/include/asm/syscall.h102
-rw-r--r--arch/riscv/include/asm/unistd.h16
-rw-r--r--arch/riscv/include/asm/vdso.h41
-rw-r--r--arch/riscv/include/uapi/asm/Kbuild27
-rw-r--r--arch/riscv/include/uapi/asm/auxvec.h24
-rw-r--r--arch/riscv/include/uapi/asm/bitsperlong.h25
-rw-r--r--arch/riscv/include/uapi/asm/byteorder.h23
-rw-r--r--arch/riscv/include/uapi/asm/elf.h83
-rw-r--r--arch/riscv/include/uapi/asm/hwcap.h36
-rw-r--r--arch/riscv/include/uapi/asm/ptrace.h90
-rw-r--r--arch/riscv/include/uapi/asm/sigcontext.h30
-rw-r--r--arch/riscv/include/uapi/asm/siginfo.h24
-rw-r--r--arch/riscv/include/uapi/asm/ucontext.h45
-rw-r--r--arch/riscv/kernel/cpufeature.c61
-rw-r--r--arch/riscv/kernel/module.c217
-rw-r--r--arch/riscv/kernel/ptrace.c125
-rw-r--r--arch/riscv/kernel/riscv_ksyms.c15
-rw-r--r--arch/riscv/kernel/signal.c292
-rw-r--r--arch/riscv/kernel/sys_riscv.c49
-rw-r--r--arch/riscv/kernel/syscall_table.c25
-rw-r--r--arch/riscv/kernel/vdso/.gitignore2
-rw-r--r--arch/riscv/kernel/vdso/Makefile63
-rw-r--r--arch/riscv/kernel/vdso/rt_sigreturn.S24
-rw-r--r--arch/riscv/kernel/vdso/vdso.S27
-rw-r--r--arch/riscv/kernel/vdso/vdso.lds.S77
27 files changed, 1687 insertions, 0 deletions
diff --git a/arch/riscv/include/asm/mmu.h b/arch/riscv/include/asm/mmu.h
new file mode 100644
index 000000000000..66805cba9a27
--- /dev/null
+++ b/arch/riscv/include/asm/mmu.h
@@ -0,0 +1,26 @@
1/*
2 * Copyright (C) 2012 Regents of the University of California
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation, version 2.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14
15#ifndef _ASM_RISCV_MMU_H
16#define _ASM_RISCV_MMU_H
17
18#ifndef __ASSEMBLY__
19
20typedef struct {
21 void *vdso;
22} mm_context_t;
23
24#endif /* __ASSEMBLY__ */
25
26#endif /* _ASM_RISCV_MMU_H */
diff --git a/arch/riscv/include/asm/ptrace.h b/arch/riscv/include/asm/ptrace.h
new file mode 100644
index 000000000000..93b8956e25e4
--- /dev/null
+++ b/arch/riscv/include/asm/ptrace.h
@@ -0,0 +1,118 @@
1/*
2 * Copyright (C) 2012 Regents of the University of California
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation, version 2.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#ifndef _ASM_RISCV_PTRACE_H
15#define _ASM_RISCV_PTRACE_H
16
17#include <uapi/asm/ptrace.h>
18#include <asm/csr.h>
19
20#ifndef __ASSEMBLY__
21
22struct pt_regs {
23 unsigned long sepc;
24 unsigned long ra;
25 unsigned long sp;
26 unsigned long gp;
27 unsigned long tp;
28 unsigned long t0;
29 unsigned long t1;
30 unsigned long t2;
31 unsigned long s0;
32 unsigned long s1;
33 unsigned long a0;
34 unsigned long a1;
35 unsigned long a2;
36 unsigned long a3;
37 unsigned long a4;
38 unsigned long a5;
39 unsigned long a6;
40 unsigned long a7;
41 unsigned long s2;
42 unsigned long s3;
43 unsigned long s4;
44 unsigned long s5;
45 unsigned long s6;
46 unsigned long s7;
47 unsigned long s8;
48 unsigned long s9;
49 unsigned long s10;
50 unsigned long s11;
51 unsigned long t3;
52 unsigned long t4;
53 unsigned long t5;
54 unsigned long t6;
55 /* Supervisor CSRs */
56 unsigned long sstatus;
57 unsigned long sbadaddr;
58 unsigned long scause;
59 /* a0 value before the syscall */
60 unsigned long orig_a0;
61};
62
63#ifdef CONFIG_64BIT
64#define REG_FMT "%016lx"
65#else
66#define REG_FMT "%08lx"
67#endif
68
69#define user_mode(regs) (((regs)->sstatus & SR_PS) == 0)
70
71
72/* Helpers for working with the instruction pointer */
73#define GET_IP(regs) ((regs)->sepc)
74#define SET_IP(regs, val) (GET_IP(regs) = (val))
75
76static inline unsigned long instruction_pointer(struct pt_regs *regs)
77{
78 return GET_IP(regs);
79}
80static inline void instruction_pointer_set(struct pt_regs *regs,
81 unsigned long val)
82{
83 SET_IP(regs, val);
84}
85
86#define profile_pc(regs) instruction_pointer(regs)
87
88/* Helpers for working with the user stack pointer */
89#define GET_USP(regs) ((regs)->sp)
90#define SET_USP(regs, val) (GET_USP(regs) = (val))
91
92static inline unsigned long user_stack_pointer(struct pt_regs *regs)
93{
94 return GET_USP(regs);
95}
96static inline void user_stack_pointer_set(struct pt_regs *regs,
97 unsigned long val)
98{
99 SET_USP(regs, val);
100}
101
102/* Helpers for working with the frame pointer */
103#define GET_FP(regs) ((regs)->s0)
104#define SET_FP(regs, val) (GET_FP(regs) = (val))
105
106static inline unsigned long frame_pointer(struct pt_regs *regs)
107{
108 return GET_FP(regs);
109}
110static inline void frame_pointer_set(struct pt_regs *regs,
111 unsigned long val)
112{
113 SET_FP(regs, val);
114}
115
116#endif /* __ASSEMBLY__ */
117
118#endif /* _ASM_RISCV_PTRACE_H */
diff --git a/arch/riscv/include/asm/syscall.h b/arch/riscv/include/asm/syscall.h
new file mode 100644
index 000000000000..8d25f8904c00
--- /dev/null
+++ b/arch/riscv/include/asm/syscall.h
@@ -0,0 +1,102 @@
1/*
2 * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
3 * Copyright 2010 Tilera Corporation. All Rights Reserved.
4 * Copyright 2015 Regents of the University of California, Berkeley
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation, version 2.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * See asm-generic/syscall.h for descriptions of what we must do here.
16 */
17
18#ifndef _ASM_RISCV_SYSCALL_H
19#define _ASM_RISCV_SYSCALL_H
20
21#include <linux/sched.h>
22#include <linux/err.h>
23
24/* The array of function pointers for syscalls. */
25extern void *sys_call_table[];
26
27/*
28 * Only the low 32 bits of orig_r0 are meaningful, so we return int.
29 * This importantly ignores the high bits on 64-bit, so comparisons
30 * sign-extend the low 32 bits.
31 */
32static inline int syscall_get_nr(struct task_struct *task,
33 struct pt_regs *regs)
34{
35 return regs->a7;
36}
37
38static inline void syscall_set_nr(struct task_struct *task,
39 struct pt_regs *regs,
40 int sysno)
41{
42 regs->a7 = sysno;
43}
44
45static inline void syscall_rollback(struct task_struct *task,
46 struct pt_regs *regs)
47{
48 regs->a0 = regs->orig_a0;
49}
50
51static inline long syscall_get_error(struct task_struct *task,
52 struct pt_regs *regs)
53{
54 unsigned long error = regs->a0;
55
56 return IS_ERR_VALUE(error) ? error : 0;
57}
58
59static inline long syscall_get_return_value(struct task_struct *task,
60 struct pt_regs *regs)
61{
62 return regs->a0;
63}
64
65static inline void syscall_set_return_value(struct task_struct *task,
66 struct pt_regs *regs,
67 int error, long val)
68{
69 regs->a0 = (long) error ?: val;
70}
71
72static inline void syscall_get_arguments(struct task_struct *task,
73 struct pt_regs *regs,
74 unsigned int i, unsigned int n,
75 unsigned long *args)
76{
77 BUG_ON(i + n > 6);
78 if (i == 0) {
79 args[0] = regs->orig_a0;
80 args++;
81 i++;
82 n--;
83 }
84 memcpy(args, &regs->a1 + i * sizeof(regs->a1), n * sizeof(args[0]));
85}
86
87static inline void syscall_set_arguments(struct task_struct *task,
88 struct pt_regs *regs,
89 unsigned int i, unsigned int n,
90 const unsigned long *args)
91{
92 BUG_ON(i + n > 6);
93 if (i == 0) {
94 regs->orig_a0 = args[0];
95 args++;
96 i++;
97 n--;
98 }
99 memcpy(&regs->a1 + i * sizeof(regs->a1), args, n * sizeof(regs->a0));
100}
101
102#endif /* _ASM_RISCV_SYSCALL_H */
diff --git a/arch/riscv/include/asm/unistd.h b/arch/riscv/include/asm/unistd.h
new file mode 100644
index 000000000000..9f250ed007cd
--- /dev/null
+++ b/arch/riscv/include/asm/unistd.h
@@ -0,0 +1,16 @@
1/*
2 * Copyright (C) 2012 Regents of the University of California
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation, version 2.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#define __ARCH_HAVE_MMU
15#define __ARCH_WANT_SYS_CLONE
16#include <uapi/asm/unistd.h>
diff --git a/arch/riscv/include/asm/vdso.h b/arch/riscv/include/asm/vdso.h
new file mode 100644
index 000000000000..602f61257553
--- /dev/null
+++ b/arch/riscv/include/asm/vdso.h
@@ -0,0 +1,41 @@
1/*
2 * Copyright (C) 2012 ARM Limited
3 * Copyright (C) 2014 Regents of the University of California
4 * Copyright (C) 2017 SiFive
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef _ASM_RISCV_VDSO_H
20#define _ASM_RISCV_VDSO_H
21
22#include <linux/types.h>
23
24struct vdso_data {
25};
26
27/*
28 * The VDSO symbols are mapped into Linux so we can just use regular symbol
29 * addressing to get their offsets in userspace. The symbols are mapped at an
30 * offset of 0, but since the linker must support setting weak undefined
31 * symbols to the absolute address 0 it also happens to support other low
32 * addresses even when the code model suggests those low addresses would not
33 * otherwise be availiable.
34 */
35#define VDSO_SYMBOL(base, name) \
36({ \
37 extern const char __vdso_##name[]; \
38 (void __user *)((unsigned long)(base) + __vdso_##name); \
39})
40
41#endif /* _ASM_RISCV_VDSO_H */
diff --git a/arch/riscv/include/uapi/asm/Kbuild b/arch/riscv/include/uapi/asm/Kbuild
new file mode 100644
index 000000000000..5ded96b06352
--- /dev/null
+++ b/arch/riscv/include/uapi/asm/Kbuild
@@ -0,0 +1,27 @@
1# UAPI Header export list
2include include/uapi/asm-generic/Kbuild.asm
3
4generic-y += setup.h
5generic-y += unistd.h
6generic-y += errno.h
7generic-y += fcntl.h
8generic-y += ioctl.h
9generic-y += ioctls.h
10generic-y += ipcbuf.h
11generic-y += mman.h
12generic-y += msgbuf.h
13generic-y += param.h
14generic-y += poll.h
15generic-y += posix_types.h
16generic-y += resource.h
17generic-y += sembuf.h
18generic-y += shmbuf.h
19generic-y += signal.h
20generic-y += socket.h
21generic-y += sockios.h
22generic-y += stat.h
23generic-y += statfs.h
24generic-y += swab.h
25generic-y += termbits.h
26generic-y += termios.h
27generic-y += types.h
diff --git a/arch/riscv/include/uapi/asm/auxvec.h b/arch/riscv/include/uapi/asm/auxvec.h
new file mode 100644
index 000000000000..1376515547cd
--- /dev/null
+++ b/arch/riscv/include/uapi/asm/auxvec.h
@@ -0,0 +1,24 @@
1/*
2 * Copyright (C) 2012 ARM Ltd.
3 * Copyright (C) 2015 Regents of the University of California
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef _UAPI_ASM_RISCV_AUXVEC_H
19#define _UAPI_ASM_RISCV_AUXVEC_H
20
21/* vDSO location */
22#define AT_SYSINFO_EHDR 33
23
24#endif /* _UAPI_ASM_RISCV_AUXVEC_H */
diff --git a/arch/riscv/include/uapi/asm/bitsperlong.h b/arch/riscv/include/uapi/asm/bitsperlong.h
new file mode 100644
index 000000000000..0b3cb52fd29d
--- /dev/null
+++ b/arch/riscv/include/uapi/asm/bitsperlong.h
@@ -0,0 +1,25 @@
1/*
2 * Copyright (C) 2012 ARM Ltd.
3 * Copyright (C) 2015 Regents of the University of California
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef _UAPI_ASM_RISCV_BITSPERLONG_H
19#define _UAPI_ASM_RISCV_BITSPERLONG_H
20
21#define __BITS_PER_LONG (__SIZEOF_POINTER__ * 8)
22
23#include <asm-generic/bitsperlong.h>
24
25#endif /* _UAPI_ASM_RISCV_BITSPERLONG_H */
diff --git a/arch/riscv/include/uapi/asm/byteorder.h b/arch/riscv/include/uapi/asm/byteorder.h
new file mode 100644
index 000000000000..4ca38af2cd32
--- /dev/null
+++ b/arch/riscv/include/uapi/asm/byteorder.h
@@ -0,0 +1,23 @@
1/*
2 * Copyright (C) 2012 ARM Ltd.
3 * Copyright (C) 2015 Regents of the University of California
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef _UAPI_ASM_RISCV_BYTEORDER_H
19#define _UAPI_ASM_RISCV_BYTEORDER_H
20
21#include <linux/byteorder/little_endian.h>
22
23#endif /* _UAPI_ASM_RISCV_BYTEORDER_H */
diff --git a/arch/riscv/include/uapi/asm/elf.h b/arch/riscv/include/uapi/asm/elf.h
new file mode 100644
index 000000000000..a510edfa8226
--- /dev/null
+++ b/arch/riscv/include/uapi/asm/elf.h
@@ -0,0 +1,83 @@
1/*
2 * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
3 * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
4 * Copyright (C) 2012 Regents of the University of California
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#ifndef _UAPI_ASM_ELF_H
13#define _UAPI_ASM_ELF_H
14
15#include <asm/ptrace.h>
16
17/* ELF register definitions */
18typedef unsigned long elf_greg_t;
19typedef struct user_regs_struct elf_gregset_t;
20#define ELF_NGREG (sizeof(elf_gregset_t) / sizeof(elf_greg_t))
21
22typedef union __riscv_fp_state elf_fpregset_t;
23
24#define ELF_RISCV_R_SYM(r_info) ((r_info) >> 32)
25#define ELF_RISCV_R_TYPE(r_info) ((r_info) & 0xffffffff)
26
27/*
28 * RISC-V relocation types
29 */
30
31/* Relocation types used by the dynamic linker */
32#define R_RISCV_NONE 0
33#define R_RISCV_32 1
34#define R_RISCV_64 2
35#define R_RISCV_RELATIVE 3
36#define R_RISCV_COPY 4
37#define R_RISCV_JUMP_SLOT 5
38#define R_RISCV_TLS_DTPMOD32 6
39#define R_RISCV_TLS_DTPMOD64 7
40#define R_RISCV_TLS_DTPREL32 8
41#define R_RISCV_TLS_DTPREL64 9
42#define R_RISCV_TLS_TPREL32 10
43#define R_RISCV_TLS_TPREL64 11
44
45/* Relocation types not used by the dynamic linker */
46#define R_RISCV_BRANCH 16
47#define R_RISCV_JAL 17
48#define R_RISCV_CALL 18
49#define R_RISCV_CALL_PLT 19
50#define R_RISCV_GOT_HI20 20
51#define R_RISCV_TLS_GOT_HI20 21
52#define R_RISCV_TLS_GD_HI20 22
53#define R_RISCV_PCREL_HI20 23
54#define R_RISCV_PCREL_LO12_I 24
55#define R_RISCV_PCREL_LO12_S 25
56#define R_RISCV_HI20 26
57#define R_RISCV_LO12_I 27
58#define R_RISCV_LO12_S 28
59#define R_RISCV_TPREL_HI20 29
60#define R_RISCV_TPREL_LO12_I 30
61#define R_RISCV_TPREL_LO12_S 31
62#define R_RISCV_TPREL_ADD 32
63#define R_RISCV_ADD8 33
64#define R_RISCV_ADD16 34
65#define R_RISCV_ADD32 35
66#define R_RISCV_ADD64 36
67#define R_RISCV_SUB8 37
68#define R_RISCV_SUB16 38
69#define R_RISCV_SUB32 39
70#define R_RISCV_SUB64 40
71#define R_RISCV_GNU_VTINHERIT 41
72#define R_RISCV_GNU_VTENTRY 42
73#define R_RISCV_ALIGN 43
74#define R_RISCV_RVC_BRANCH 44
75#define R_RISCV_RVC_JUMP 45
76#define R_RISCV_LUI 46
77#define R_RISCV_GPREL_I 47
78#define R_RISCV_GPREL_S 48
79#define R_RISCV_TPREL_I 49
80#define R_RISCV_TPREL_S 50
81#define R_RISCV_RELAX 51
82
83#endif /* _UAPI_ASM_ELF_H */
diff --git a/arch/riscv/include/uapi/asm/hwcap.h b/arch/riscv/include/uapi/asm/hwcap.h
new file mode 100644
index 000000000000..f333221c9ab2
--- /dev/null
+++ b/arch/riscv/include/uapi/asm/hwcap.h
@@ -0,0 +1,36 @@
1/*
2 * Copied from arch/arm64/include/asm/hwcap.h
3 *
4 * Copyright (C) 2012 ARM Ltd.
5 * Copyright (C) 2017 SiFive
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19#ifndef __UAPI_ASM_HWCAP_H
20#define __UAPI_ASM_HWCAP_H
21
22/*
23 * Linux saves the floating-point registers according to the ISA Linux is
24 * executing on, as opposed to the ISA the user program is compiled for. This
25 * is necessary for a handful of esoteric use cases: for example, userpsace
26 * threading libraries must be able to examine the actual machine state in
27 * order to fully reconstruct the state of a thread.
28 */
29#define COMPAT_HWCAP_ISA_I (1 << ('I' - 'A'))
30#define COMPAT_HWCAP_ISA_M (1 << ('M' - 'A'))
31#define COMPAT_HWCAP_ISA_A (1 << ('A' - 'A'))
32#define COMPAT_HWCAP_ISA_F (1 << ('F' - 'A'))
33#define COMPAT_HWCAP_ISA_D (1 << ('D' - 'A'))
34#define COMPAT_HWCAP_ISA_C (1 << ('C' - 'A'))
35
36#endif
diff --git a/arch/riscv/include/uapi/asm/ptrace.h b/arch/riscv/include/uapi/asm/ptrace.h
new file mode 100644
index 000000000000..1a9e4cdd37e2
--- /dev/null
+++ b/arch/riscv/include/uapi/asm/ptrace.h
@@ -0,0 +1,90 @@
1/*
2 * Copyright (C) 2012 Regents of the University of California
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation, version 2.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#ifndef _UAPI_ASM_RISCV_PTRACE_H
15#define _UAPI_ASM_RISCV_PTRACE_H
16
17#ifndef __ASSEMBLY__
18
19#include <linux/types.h>
20
21/*
22 * User-mode register state for core dumps, ptrace, sigcontext
23 *
24 * This decouples struct pt_regs from the userspace ABI.
25 * struct user_regs_struct must form a prefix of struct pt_regs.
26 */
27struct user_regs_struct {
28 unsigned long pc;
29 unsigned long ra;
30 unsigned long sp;
31 unsigned long gp;
32 unsigned long tp;
33 unsigned long t0;
34 unsigned long t1;
35 unsigned long t2;
36 unsigned long s0;
37 unsigned long s1;
38 unsigned long a0;
39 unsigned long a1;
40 unsigned long a2;
41 unsigned long a3;
42 unsigned long a4;
43 unsigned long a5;
44 unsigned long a6;
45 unsigned long a7;
46 unsigned long s2;
47 unsigned long s3;
48 unsigned long s4;
49 unsigned long s5;
50 unsigned long s6;
51 unsigned long s7;
52 unsigned long s8;
53 unsigned long s9;
54 unsigned long s10;
55 unsigned long s11;
56 unsigned long t3;
57 unsigned long t4;
58 unsigned long t5;
59 unsigned long t6;
60};
61
62struct __riscv_f_ext_state {
63 __u32 f[32];
64 __u32 fcsr;
65};
66
67struct __riscv_d_ext_state {
68 __u64 f[32];
69 __u32 fcsr;
70};
71
72struct __riscv_q_ext_state {
73 __u64 f[64] __attribute__((aligned(16)));
74 __u32 fcsr;
75 /*
76 * Reserved for expansion of sigcontext structure. Currently zeroed
77 * upon signal, and must be zero upon sigreturn.
78 */
79 __u32 reserved[3];
80};
81
82union __riscv_fp_state {
83 struct __riscv_f_ext_state f;
84 struct __riscv_d_ext_state d;
85 struct __riscv_q_ext_state q;
86};
87
88#endif /* __ASSEMBLY__ */
89
90#endif /* _UAPI_ASM_RISCV_PTRACE_H */
diff --git a/arch/riscv/include/uapi/asm/sigcontext.h b/arch/riscv/include/uapi/asm/sigcontext.h
new file mode 100644
index 000000000000..ed7372b277fa
--- /dev/null
+++ b/arch/riscv/include/uapi/asm/sigcontext.h
@@ -0,0 +1,30 @@
1/*
2 * Copyright (C) 2012 Regents of the University of California
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation, version 2.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#ifndef _UAPI_ASM_RISCV_SIGCONTEXT_H
15#define _UAPI_ASM_RISCV_SIGCONTEXT_H
16
17#include <asm/ptrace.h>
18
19/*
20 * Signal context structure
21 *
22 * This contains the context saved before a signal handler is invoked;
23 * it is restored by sys_sigreturn / sys_rt_sigreturn.
24 */
25struct sigcontext {
26 struct user_regs_struct sc_regs;
27 union __riscv_fp_state sc_fpregs;
28};
29
30#endif /* _UAPI_ASM_RISCV_SIGCONTEXT_H */
diff --git a/arch/riscv/include/uapi/asm/siginfo.h b/arch/riscv/include/uapi/asm/siginfo.h
new file mode 100644
index 000000000000..f96849aac662
--- /dev/null
+++ b/arch/riscv/include/uapi/asm/siginfo.h
@@ -0,0 +1,24 @@
1/*
2 * Copyright (C) 2012 ARM Ltd.
3 * Copyright (C) 2016 SiFive, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17#ifndef __ASM_SIGINFO_H
18#define __ASM_SIGINFO_H
19
20#define __ARCH_SI_PREAMBLE_SIZE (__SIZEOF_POINTER__ == 4 ? 12 : 16)
21
22#include <asm-generic/siginfo.h>
23
24#endif
diff --git a/arch/riscv/include/uapi/asm/ucontext.h b/arch/riscv/include/uapi/asm/ucontext.h
new file mode 100644
index 000000000000..1fae8b1697e0
--- /dev/null
+++ b/arch/riscv/include/uapi/asm/ucontext.h
@@ -0,0 +1,45 @@
1/*
2 * Copyright (C) 2012 ARM Ltd.
3 * Copyright (C) 2017 SiFive, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * This file was copied from arch/arm64/include/uapi/asm/ucontext.h
18 */
19#ifndef _UAPI__ASM_UCONTEXT_H
20#define _UAPI__ASM_UCONTEXT_H
21
22#include <linux/types.h>
23
24struct ucontext {
25 unsigned long uc_flags;
26 struct ucontext *uc_link;
27 stack_t uc_stack;
28 sigset_t uc_sigmask;
29 /* There's some padding here to allow sigset_t to be expanded in the
30 * future. Though this is unlikely, other architectures put uc_sigmask
31 * at the end of this structure and explicitly state it can be
32 * expanded, so we didn't want to box ourselves in here. */
33 __u8 __unused[1024 / 8 - sizeof(sigset_t)];
34 /* We can't put uc_sigmask at the end of this structure because we need
35 * to be able to expand sigcontext in the future. For example, the
36 * vector ISA extension will almost certainly add ISA state. We want
37 * to ensure all user-visible ISA state can be saved and restored via a
38 * ucontext, so we're putting this at the end in order to allow for
39 * infinite extensibility. Since we know this will be extended and we
40 * assume sigset_t won't be extended an extreme amount, we're
41 * prioritizing this. */
42 struct sigcontext uc_mcontext;
43};
44
45#endif /* _UAPI__ASM_UCONTEXT_H */
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
new file mode 100644
index 000000000000..17011a870044
--- /dev/null
+++ b/arch/riscv/kernel/cpufeature.c
@@ -0,0 +1,61 @@
1/*
2 * Copied from arch/arm64/kernel/cpufeature.c
3 *
4 * Copyright (C) 2015 ARM Ltd.
5 * Copyright (C) 2017 SiFive
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/of.h>
21#include <asm/processor.h>
22#include <asm/hwcap.h>
23
24unsigned long elf_hwcap __read_mostly;
25
26void riscv_fill_hwcap(void)
27{
28 struct device_node *node;
29 const char *isa;
30 size_t i;
31 static unsigned long isa2hwcap[256] = {0};
32
33 isa2hwcap['i'] = isa2hwcap['I'] = COMPAT_HWCAP_ISA_I;
34 isa2hwcap['m'] = isa2hwcap['M'] = COMPAT_HWCAP_ISA_M;
35 isa2hwcap['a'] = isa2hwcap['A'] = COMPAT_HWCAP_ISA_A;
36 isa2hwcap['f'] = isa2hwcap['F'] = COMPAT_HWCAP_ISA_F;
37 isa2hwcap['d'] = isa2hwcap['D'] = COMPAT_HWCAP_ISA_D;
38 isa2hwcap['c'] = isa2hwcap['C'] = COMPAT_HWCAP_ISA_C;
39
40 elf_hwcap = 0;
41
42 /*
43 * We don't support running Linux on hertergenous ISA systems. For
44 * now, we just check the ISA of the first processor.
45 */
46 node = of_find_node_by_type(NULL, "cpu");
47 if (!node) {
48 pr_warning("Unable to find \"cpu\" devicetree entry");
49 return;
50 }
51
52 if (of_property_read_string(node, "riscv,isa", &isa)) {
53 pr_warning("Unable to find \"riscv,isa\" devicetree entry");
54 return;
55 }
56
57 for (i = 0; i < strlen(isa); ++i)
58 elf_hwcap |= isa2hwcap[(unsigned char)(isa[i])];
59
60 pr_info("elf_hwcap is 0x%lx", elf_hwcap);
61}
diff --git a/arch/riscv/kernel/module.c b/arch/riscv/kernel/module.c
new file mode 100644
index 000000000000..e0f05034fc21
--- /dev/null
+++ b/arch/riscv/kernel/module.c
@@ -0,0 +1,217 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * Copyright (C) 2017 Zihao Yu
13 */
14
15#include <linux/elf.h>
16#include <linux/err.h>
17#include <linux/errno.h>
18#include <linux/moduleloader.h>
19
20static int apply_r_riscv_64_rela(struct module *me, u32 *location, Elf_Addr v)
21{
22 *(u64 *)location = v;
23 return 0;
24}
25
26static int apply_r_riscv_branch_rela(struct module *me, u32 *location,
27 Elf_Addr v)
28{
29 s64 offset = (void *)v - (void *)location;
30 u32 imm12 = (offset & 0x1000) << (31 - 12);
31 u32 imm11 = (offset & 0x800) >> (11 - 7);
32 u32 imm10_5 = (offset & 0x7e0) << (30 - 10);
33 u32 imm4_1 = (offset & 0x1e) << (11 - 4);
34
35 *location = (*location & 0x1fff07f) | imm12 | imm11 | imm10_5 | imm4_1;
36 return 0;
37}
38
39static int apply_r_riscv_jal_rela(struct module *me, u32 *location,
40 Elf_Addr v)
41{
42 s64 offset = (void *)v - (void *)location;
43 u32 imm20 = (offset & 0x100000) << (31 - 20);
44 u32 imm19_12 = (offset & 0xff000);
45 u32 imm11 = (offset & 0x800) << (20 - 11);
46 u32 imm10_1 = (offset & 0x7fe) << (30 - 10);
47
48 *location = (*location & 0xfff) | imm20 | imm19_12 | imm11 | imm10_1;
49 return 0;
50}
51
52static int apply_r_riscv_pcrel_hi20_rela(struct module *me, u32 *location,
53 Elf_Addr v)
54{
55 s64 offset = (void *)v - (void *)location;
56 s32 hi20;
57
58 if (offset != (s32)offset) {
59 pr_err(
60 "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
61 me->name, v, location);
62 return -EINVAL;
63 }
64
65 hi20 = (offset + 0x800) & 0xfffff000;
66 *location = (*location & 0xfff) | hi20;
67 return 0;
68}
69
70static int apply_r_riscv_pcrel_lo12_i_rela(struct module *me, u32 *location,
71 Elf_Addr v)
72{
73 /*
74 * v is the lo12 value to fill. It is calculated before calling this
75 * handler.
76 */
77 *location = (*location & 0xfffff) | ((v & 0xfff) << 20);
78 return 0;
79}
80
81static int apply_r_riscv_pcrel_lo12_s_rela(struct module *me, u32 *location,
82 Elf_Addr v)
83{
84 /*
85 * v is the lo12 value to fill. It is calculated before calling this
86 * handler.
87 */
88 u32 imm11_5 = (v & 0xfe0) << (31 - 11);
89 u32 imm4_0 = (v & 0x1f) << (11 - 4);
90
91 *location = (*location & 0x1fff07f) | imm11_5 | imm4_0;
92 return 0;
93}
94
95static int apply_r_riscv_call_plt_rela(struct module *me, u32 *location,
96 Elf_Addr v)
97{
98 s64 offset = (void *)v - (void *)location;
99 s32 fill_v = offset;
100 u32 hi20, lo12;
101
102 if (offset != fill_v) {
103 pr_err(
104 "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
105 me->name, v, location);
106 return -EINVAL;
107 }
108
109 hi20 = (offset + 0x800) & 0xfffff000;
110 lo12 = (offset - hi20) & 0xfff;
111 *location = (*location & 0xfff) | hi20;
112 *(location + 1) = (*(location + 1) & 0xfffff) | (lo12 << 20);
113 return 0;
114}
115
116static int apply_r_riscv_relax_rela(struct module *me, u32 *location,
117 Elf_Addr v)
118{
119 return 0;
120}
121
122static int (*reloc_handlers_rela[]) (struct module *me, u32 *location,
123 Elf_Addr v) = {
124 [R_RISCV_64] = apply_r_riscv_64_rela,
125 [R_RISCV_BRANCH] = apply_r_riscv_branch_rela,
126 [R_RISCV_JAL] = apply_r_riscv_jal_rela,
127 [R_RISCV_PCREL_HI20] = apply_r_riscv_pcrel_hi20_rela,
128 [R_RISCV_PCREL_LO12_I] = apply_r_riscv_pcrel_lo12_i_rela,
129 [R_RISCV_PCREL_LO12_S] = apply_r_riscv_pcrel_lo12_s_rela,
130 [R_RISCV_CALL_PLT] = apply_r_riscv_call_plt_rela,
131 [R_RISCV_RELAX] = apply_r_riscv_relax_rela,
132};
133
134int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
135 unsigned int symindex, unsigned int relsec,
136 struct module *me)
137{
138 Elf_Rela *rel = (void *) sechdrs[relsec].sh_addr;
139 int (*handler)(struct module *me, u32 *location, Elf_Addr v);
140 Elf_Sym *sym;
141 u32 *location;
142 unsigned int i, type;
143 Elf_Addr v;
144 int res;
145
146 pr_debug("Applying relocate section %u to %u\n", relsec,
147 sechdrs[relsec].sh_info);
148
149 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
150 /* This is where to make the change */
151 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
152 + rel[i].r_offset;
153 /* This is the symbol it is referring to */
154 sym = (Elf_Sym *)sechdrs[symindex].sh_addr
155 + ELF_RISCV_R_SYM(rel[i].r_info);
156 if (IS_ERR_VALUE(sym->st_value)) {
157 /* Ignore unresolved weak symbol */
158 if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
159 continue;
160 pr_warning("%s: Unknown symbol %s\n",
161 me->name, strtab + sym->st_name);
162 return -ENOENT;
163 }
164
165 type = ELF_RISCV_R_TYPE(rel[i].r_info);
166
167 if (type < ARRAY_SIZE(reloc_handlers_rela))
168 handler = reloc_handlers_rela[type];
169 else
170 handler = NULL;
171
172 if (!handler) {
173 pr_err("%s: Unknown relocation type %u\n",
174 me->name, type);
175 return -EINVAL;
176 }
177
178 v = sym->st_value + rel[i].r_addend;
179
180 if (type == R_RISCV_PCREL_LO12_I || type == R_RISCV_PCREL_LO12_S) {
181 unsigned int j;
182
183 for (j = 0; j < sechdrs[relsec].sh_size / sizeof(*rel); j++) {
184 u64 hi20_loc =
185 sechdrs[sechdrs[relsec].sh_info].sh_addr
186 + rel[j].r_offset;
187 /* Find the corresponding HI20 PC-relative relocation entry */
188 if (hi20_loc == sym->st_value) {
189 Elf_Sym *hi20_sym =
190 (Elf_Sym *)sechdrs[symindex].sh_addr
191 + ELF_RISCV_R_SYM(rel[j].r_info);
192 u64 hi20_sym_val =
193 hi20_sym->st_value
194 + rel[j].r_addend;
195 /* Calculate lo12 */
196 s64 offset = hi20_sym_val - hi20_loc;
197 s32 hi20 = (offset + 0x800) & 0xfffff000;
198 s32 lo12 = offset - hi20;
199 v = lo12;
200 break;
201 }
202 }
203 if (j == sechdrs[relsec].sh_size / sizeof(*rel)) {
204 pr_err(
205 "%s: Can not find HI20 PC-relative relocation information\n",
206 me->name);
207 return -EINVAL;
208 }
209 }
210
211 res = handler(me, location, v);
212 if (res)
213 return res;
214 }
215
216 return 0;
217}
diff --git a/arch/riscv/kernel/ptrace.c b/arch/riscv/kernel/ptrace.c
new file mode 100644
index 000000000000..ba3e80712797
--- /dev/null
+++ b/arch/riscv/kernel/ptrace.c
@@ -0,0 +1,125 @@
1/*
2 * Copyright 2010 Tilera Corporation. All Rights Reserved.
3 * Copyright 2015 Regents of the University of California
4 * Copyright 2017 SiFive
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation, version 2.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * Copied from arch/tile/kernel/ptrace.c
16 */
17
18#include <asm/ptrace.h>
19#include <asm/syscall.h>
20#include <asm/thread_info.h>
21#include <linux/ptrace.h>
22#include <linux/elf.h>
23#include <linux/regset.h>
24#include <linux/sched.h>
25#include <linux/sched/task_stack.h>
26#include <linux/tracehook.h>
27#include <trace/events/syscalls.h>
28
29enum riscv_regset {
30 REGSET_X,
31};
32
33static int riscv_gpr_get(struct task_struct *target,
34 const struct user_regset *regset,
35 unsigned int pos, unsigned int count,
36 void *kbuf, void __user *ubuf)
37{
38 struct pt_regs *regs;
39
40 regs = task_pt_regs(target);
41 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs, 0, -1);
42}
43
44static int riscv_gpr_set(struct task_struct *target,
45 const struct user_regset *regset,
46 unsigned int pos, unsigned int count,
47 const void *kbuf, const void __user *ubuf)
48{
49 int ret;
50 struct pt_regs *regs;
51
52 regs = task_pt_regs(target);
53 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &regs, 0, -1);
54 return ret;
55}
56
57
58static const struct user_regset riscv_user_regset[] = {
59 [REGSET_X] = {
60 .core_note_type = NT_PRSTATUS,
61 .n = ELF_NGREG,
62 .size = sizeof(elf_greg_t),
63 .align = sizeof(elf_greg_t),
64 .get = &riscv_gpr_get,
65 .set = &riscv_gpr_set,
66 },
67};
68
69static const struct user_regset_view riscv_user_native_view = {
70 .name = "riscv",
71 .e_machine = EM_RISCV,
72 .regsets = riscv_user_regset,
73 .n = ARRAY_SIZE(riscv_user_regset),
74};
75
76const struct user_regset_view *task_user_regset_view(struct task_struct *task)
77{
78 return &riscv_user_native_view;
79}
80
81void ptrace_disable(struct task_struct *child)
82{
83 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
84}
85
86long arch_ptrace(struct task_struct *child, long request,
87 unsigned long addr, unsigned long data)
88{
89 long ret = -EIO;
90
91 switch (request) {
92 default:
93 ret = ptrace_request(child, request, addr, data);
94 break;
95 }
96
97 return ret;
98}
99
100/*
101 * Allows PTRACE_SYSCALL to work. These are called from entry.S in
102 * {handle,ret_from}_syscall.
103 */
104void do_syscall_trace_enter(struct pt_regs *regs)
105{
106 if (test_thread_flag(TIF_SYSCALL_TRACE))
107 if (tracehook_report_syscall_entry(regs))
108 syscall_set_nr(current, regs, -1);
109
110#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
111 if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
112 trace_sys_enter(regs, syscall_get_nr(current, regs));
113#endif
114}
115
116void do_syscall_trace_exit(struct pt_regs *regs)
117{
118 if (test_thread_flag(TIF_SYSCALL_TRACE))
119 tracehook_report_syscall_exit(regs, 0);
120
121#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
122 if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
123 trace_sys_exit(regs, regs->regs[0]);
124#endif
125}
diff --git a/arch/riscv/kernel/riscv_ksyms.c b/arch/riscv/kernel/riscv_ksyms.c
new file mode 100644
index 000000000000..23cc81ec9e94
--- /dev/null
+++ b/arch/riscv/kernel/riscv_ksyms.c
@@ -0,0 +1,15 @@
1/*
2 * Copyright (C) 2017 Zihao Yu
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include <linux/export.h>
10#include <linux/uaccess.h>
11
12/*
13 * Assembly functions that may be used (directly or indirectly) by modules
14 */
15EXPORT_SYMBOL(__copy_user);
diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c
new file mode 100644
index 000000000000..718d0c984ef0
--- /dev/null
+++ b/arch/riscv/kernel/signal.c
@@ -0,0 +1,292 @@
1/*
2 * Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
3 * Chen Liqin <liqin.chen@sunplusct.com>
4 * Lennox Wu <lennox.wu@sunplusct.com>
5 * Copyright (C) 2012 Regents of the University of California
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see the file COPYING, or write
19 * to the Free Software Foundation, Inc.,
20 */
21
22#include <linux/signal.h>
23#include <linux/uaccess.h>
24#include <linux/syscalls.h>
25#include <linux/tracehook.h>
26#include <linux/linkage.h>
27
28#include <asm/ucontext.h>
29#include <asm/vdso.h>
30#include <asm/switch_to.h>
31#include <asm/csr.h>
32
33#define DEBUG_SIG 0
34
35struct rt_sigframe {
36 struct siginfo info;
37 struct ucontext uc;
38};
39
40static long restore_d_state(struct pt_regs *regs,
41 struct __riscv_d_ext_state __user *state)
42{
43 long err;
44 err = __copy_from_user(&current->thread.fstate, state, sizeof(*state));
45 if (likely(!err))
46 fstate_restore(current, regs);
47 return err;
48}
49
50static long save_d_state(struct pt_regs *regs,
51 struct __riscv_d_ext_state __user *state)
52{
53 fstate_save(current, regs);
54 return __copy_to_user(state, &current->thread.fstate, sizeof(*state));
55}
56
57static long restore_sigcontext(struct pt_regs *regs,
58 struct sigcontext __user *sc)
59{
60 long err;
61 size_t i;
62 /* sc_regs is structured the same as the start of pt_regs */
63 err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs));
64 if (unlikely(err))
65 return err;
66 /* Restore the floating-point state. */
67 err = restore_d_state(regs, &sc->sc_fpregs.d);
68 if (unlikely(err))
69 return err;
70 /* We support no other extension state at this time. */
71 for (i = 0; i < ARRAY_SIZE(sc->sc_fpregs.q.reserved); i++) {
72 u32 value;
73 err = __get_user(value, &sc->sc_fpregs.q.reserved[i]);
74 if (unlikely(err))
75 break;
76 if (value != 0)
77 return -EINVAL;
78 }
79 return err;
80}
81
82SYSCALL_DEFINE0(rt_sigreturn)
83{
84 struct pt_regs *regs = current_pt_regs();
85 struct rt_sigframe __user *frame;
86 struct task_struct *task;
87 sigset_t set;
88
89 /* Always make any pending restarted system calls return -EINTR */
90 current->restart_block.fn = do_no_restart_syscall;
91
92 frame = (struct rt_sigframe __user *)regs->sp;
93
94 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
95 goto badframe;
96
97 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
98 goto badframe;
99
100 set_current_blocked(&set);
101
102 if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
103 goto badframe;
104
105 if (restore_altstack(&frame->uc.uc_stack))
106 goto badframe;
107
108 return regs->a0;
109
110badframe:
111 task = current;
112 if (show_unhandled_signals) {
113 pr_info_ratelimited(
114 "%s[%d]: bad frame in %s: frame=%p pc=%p sp=%p\n",
115 task->comm, task_pid_nr(task), __func__,
116 frame, (void *)regs->sepc, (void *)regs->sp);
117 }
118 force_sig(SIGSEGV, task);
119 return 0;
120}
121
122static long setup_sigcontext(struct rt_sigframe __user *frame,
123 struct pt_regs *regs)
124{
125 struct sigcontext __user *sc = &frame->uc.uc_mcontext;
126 long err;
127 size_t i;
128 /* sc_regs is structured the same as the start of pt_regs */
129 err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs));
130 /* Save the floating-point state. */
131 err |= save_d_state(regs, &sc->sc_fpregs.d);
132 /* We support no other extension state at this time. */
133 for (i = 0; i < ARRAY_SIZE(sc->sc_fpregs.q.reserved); i++)
134 err |= __put_user(0, &sc->sc_fpregs.q.reserved[i]);
135 return err;
136}
137
138static inline void __user *get_sigframe(struct ksignal *ksig,
139 struct pt_regs *regs, size_t framesize)
140{
141 unsigned long sp;
142 /* Default to using normal stack */
143 sp = regs->sp;
144
145 /*
146 * If we are on the alternate signal stack and would overflow it, don't.
147 * Return an always-bogus address instead so we will die with SIGSEGV.
148 */
149 if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize)))
150 return (void __user __force *)(-1UL);
151
152 /* This is the X/Open sanctioned signal stack switching. */
153 sp = sigsp(sp, ksig) - framesize;
154
155 /* Align the stack frame. */
156 sp &= ~0xfUL;
157
158 return (void __user *)sp;
159}
160
161
162static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
163 struct pt_regs *regs)
164{
165 struct rt_sigframe __user *frame;
166 long err = 0;
167
168 frame = get_sigframe(ksig, regs, sizeof(*frame));
169 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
170 return -EFAULT;
171
172 err |= copy_siginfo_to_user(&frame->info, &ksig->info);
173
174 /* Create the ucontext. */
175 err |= __put_user(0, &frame->uc.uc_flags);
176 err |= __put_user(NULL, &frame->uc.uc_link);
177 err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
178 err |= setup_sigcontext(frame, regs);
179 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
180 if (err)
181 return -EFAULT;
182
183 /* Set up to return from userspace. */
184 regs->ra = (unsigned long)VDSO_SYMBOL(
185 current->mm->context.vdso, rt_sigreturn);
186
187 /*
188 * Set up registers for signal handler.
189 * Registers that we don't modify keep the value they had from
190 * user-space at the time we took the signal.
191 * We always pass siginfo and mcontext, regardless of SA_SIGINFO,
192 * since some things rely on this (e.g. glibc's debug/segfault.c).
193 */
194 regs->sepc = (unsigned long)ksig->ka.sa.sa_handler;
195 regs->sp = (unsigned long)frame;
196 regs->a0 = ksig->sig; /* a0: signal number */
197 regs->a1 = (unsigned long)(&frame->info); /* a1: siginfo pointer */
198 regs->a2 = (unsigned long)(&frame->uc); /* a2: ucontext pointer */
199
200#if DEBUG_SIG
201 pr_info("SIG deliver (%s:%d): sig=%d pc=%p ra=%p sp=%p\n",
202 current->comm, task_pid_nr(current), ksig->sig,
203 (void *)regs->sepc, (void *)regs->ra, frame);
204#endif
205
206 return 0;
207}
208
209static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
210{
211 sigset_t *oldset = sigmask_to_save();
212 int ret;
213
214 /* Are we from a system call? */
215 if (regs->scause == EXC_SYSCALL) {
216 /* If so, check system call restarting.. */
217 switch (regs->a0) {
218 case -ERESTART_RESTARTBLOCK:
219 case -ERESTARTNOHAND:
220 regs->a0 = -EINTR;
221 break;
222
223 case -ERESTARTSYS:
224 if (!(ksig->ka.sa.sa_flags & SA_RESTART)) {
225 regs->a0 = -EINTR;
226 break;
227 }
228 /* fallthrough */
229 case -ERESTARTNOINTR:
230 regs->a0 = regs->orig_a0;
231 regs->sepc -= 0x4;
232 break;
233 }
234 }
235
236 /* Set up the stack frame */
237 ret = setup_rt_frame(ksig, oldset, regs);
238
239 signal_setup_done(ret, ksig, 0);
240}
241
242static void do_signal(struct pt_regs *regs)
243{
244 struct ksignal ksig;
245
246 if (get_signal(&ksig)) {
247 /* Actually deliver the signal */
248 handle_signal(&ksig, regs);
249 return;
250 }
251
252 /* Did we come from a system call? */
253 if (regs->scause == EXC_SYSCALL) {
254 /* Restart the system call - no handlers present */
255 switch (regs->a0) {
256 case -ERESTARTNOHAND:
257 case -ERESTARTSYS:
258 case -ERESTARTNOINTR:
259 regs->a0 = regs->orig_a0;
260 regs->sepc -= 0x4;
261 break;
262 case -ERESTART_RESTARTBLOCK:
263 regs->a0 = regs->orig_a0;
264 regs->a7 = __NR_restart_syscall;
265 regs->sepc -= 0x4;
266 break;
267 }
268 }
269
270 /*
271 * If there is no signal to deliver, we just put the saved
272 * sigmask back.
273 */
274 restore_saved_sigmask();
275}
276
277/*
278 * notification of userspace execution resumption
279 * - triggered by the _TIF_WORK_MASK flags
280 */
281asmlinkage void do_notify_resume(struct pt_regs *regs,
282 unsigned long thread_info_flags)
283{
284 /* Handle pending signal delivery */
285 if (thread_info_flags & _TIF_SIGPENDING)
286 do_signal(regs);
287
288 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
289 clear_thread_flag(TIF_NOTIFY_RESUME);
290 tracehook_notify_resume(regs);
291 }
292}
diff --git a/arch/riscv/kernel/sys_riscv.c b/arch/riscv/kernel/sys_riscv.c
new file mode 100644
index 000000000000..4351be7d0533
--- /dev/null
+++ b/arch/riscv/kernel/sys_riscv.c
@@ -0,0 +1,49 @@
1/*
2 * Copyright (C) 2012 Regents of the University of California
3 * Copyright (C) 2014 Darius Rad <darius@bluespec.com>
4 * Copyright (C) 2017 SiFive
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation, version 2.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/syscalls.h>
17#include <asm/cmpxchg.h>
18#include <asm/unistd.h>
19
20static long riscv_sys_mmap(unsigned long addr, unsigned long len,
21 unsigned long prot, unsigned long flags,
22 unsigned long fd, off_t offset,
23 unsigned long page_shift_offset)
24{
25 if (unlikely(offset & (~PAGE_MASK >> page_shift_offset)))
26 return -EINVAL;
27 return sys_mmap_pgoff(addr, len, prot, flags, fd,
28 offset >> (PAGE_SHIFT - page_shift_offset));
29}
30
31#ifdef CONFIG_64BIT
32SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
33 unsigned long, prot, unsigned long, flags,
34 unsigned long, fd, off_t, offset)
35{
36 return riscv_sys_mmap(addr, len, prot, flags, fd, offset, 0);
37}
38#else
39SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len,
40 unsigned long, prot, unsigned long, flags,
41 unsigned long, fd, off_t, offset)
42{
43 /*
44 * Note that the shift for mmap2 is constant (12),
45 * regardless of PAGE_SIZE
46 */
47 return riscv_sys_mmap(addr, len, prot, flags, fd, offset, 12);
48}
49#endif /* !CONFIG_64BIT */
diff --git a/arch/riscv/kernel/syscall_table.c b/arch/riscv/kernel/syscall_table.c
new file mode 100644
index 000000000000..4e30dc5fb593
--- /dev/null
+++ b/arch/riscv/kernel/syscall_table.c
@@ -0,0 +1,25 @@
1/*
2 * Copyright (C) 2009 Arnd Bergmann <arnd@arndb.de>
3 * Copyright (C) 2012 Regents of the University of California
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation, version 2.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <linux/linkage.h>
16#include <linux/syscalls.h>
17#include <asm-generic/syscalls.h>
18
19#undef __SYSCALL
20#define __SYSCALL(nr, call) [nr] = (call),
21
22void *sys_call_table[__NR_syscalls] = {
23 [0 ... __NR_syscalls - 1] = sys_ni_syscall,
24#include <asm/unistd.h>
25};
diff --git a/arch/riscv/kernel/vdso/.gitignore b/arch/riscv/kernel/vdso/.gitignore
new file mode 100644
index 000000000000..97c2d69d0289
--- /dev/null
+++ b/arch/riscv/kernel/vdso/.gitignore
@@ -0,0 +1,2 @@
1vdso.lds
2*.tmp
diff --git a/arch/riscv/kernel/vdso/Makefile b/arch/riscv/kernel/vdso/Makefile
new file mode 100644
index 000000000000..523d0a8ac8db
--- /dev/null
+++ b/arch/riscv/kernel/vdso/Makefile
@@ -0,0 +1,63 @@
1# Copied from arch/tile/kernel/vdso/Makefile
2
3# Symbols present in the vdso
4vdso-syms = rt_sigreturn
5
6# Files to link into the vdso
7obj-vdso = $(patsubst %, %.o, $(vdso-syms))
8
9# Build rules
10targets := $(obj-vdso) vdso.so vdso.so.dbg vdso.lds vdso-dummy.o
11obj-vdso := $(addprefix $(obj)/, $(obj-vdso))
12
13obj-y += vdso.o vdso-syms.o
14CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
15
16# Disable gcov profiling for VDSO code
17GCOV_PROFILE := n
18
19# Force dependency
20$(obj)/vdso.o: $(obj)/vdso.so
21
22# link rule for the .so file, .lds has to be first
23SYSCFLAGS_vdso.so.dbg = $(c_flags)
24$(obj)/vdso.so.dbg: $(src)/vdso.lds $(obj-vdso) FORCE
25 $(call if_changed,vdsold)
26
27# We also create a special relocatable object that should mirror the symbol
28# table and layout of the linked DSO. With ld -R we can then refer to
29# these symbols in the kernel code rather than hand-coded addresses.
30
31SYSCFLAGS_vdso.so.dbg = -shared -s -Wl,-soname=linux-vdso.so.1 \
32 $(call cc-ldoption, -Wl$(comma)--hash-style=both)
33$(obj)/vdso-dummy.o: $(src)/vdso.lds $(obj)/rt_sigreturn.o FORCE
34 $(call if_changed,vdsold)
35
36LDFLAGS_vdso-syms.o := -r -R
37$(obj)/vdso-syms.o: $(obj)/vdso-dummy.o FORCE
38 $(call if_changed,ld)
39
40# strip rule for the .so file
41$(obj)/%.so: OBJCOPYFLAGS := -S
42$(obj)/%.so: $(obj)/%.so.dbg FORCE
43 $(call if_changed,objcopy)
44
45# actual build commands
46# The DSO images are built using a special linker script
47# Add -lgcc so rv32 gets static muldi3 and lshrdi3 definitions.
48# Make sure only to export the intended __vdso_xxx symbol offsets.
49quiet_cmd_vdsold = VDSOLD $@
50 cmd_vdsold = $(CC) $(KCFLAGS) -nostdlib $(SYSCFLAGS_$(@F)) \
51 -Wl,-T,$(filter-out FORCE,$^) -o $@.tmp -lgcc && \
52 $(CROSS_COMPILE)objcopy \
53 $(patsubst %, -G __vdso_%, $(vdso-syms)) $@.tmp $@
54
55# install commands for the unstripped file
56quiet_cmd_vdso_install = INSTALL $@
57 cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@
58
59vdso.so: $(obj)/vdso.so.dbg
60 @mkdir -p $(MODLIB)/vdso
61 $(call cmd,vdso_install)
62
63vdso_install: vdso.so
diff --git a/arch/riscv/kernel/vdso/rt_sigreturn.S b/arch/riscv/kernel/vdso/rt_sigreturn.S
new file mode 100644
index 000000000000..f5aa3d72acfb
--- /dev/null
+++ b/arch/riscv/kernel/vdso/rt_sigreturn.S
@@ -0,0 +1,24 @@
1/*
2 * Copyright (C) 2014 Regents of the University of California
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation, version 2.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/linkage.h>
15#include <asm/unistd.h>
16
17 .text
18ENTRY(__vdso_rt_sigreturn)
19 .cfi_startproc
20 .cfi_signal_frame
21 li a7, __NR_rt_sigreturn
22 scall
23 .cfi_endproc
24ENDPROC(__vdso_rt_sigreturn)
diff --git a/arch/riscv/kernel/vdso/vdso.S b/arch/riscv/kernel/vdso/vdso.S
new file mode 100644
index 000000000000..7055de5f9174
--- /dev/null
+++ b/arch/riscv/kernel/vdso/vdso.S
@@ -0,0 +1,27 @@
1/*
2 * Copyright (C) 2014 Regents of the University of California
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation, version 2.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/init.h>
15#include <linux/linkage.h>
16#include <asm/page.h>
17
18 __PAGE_ALIGNED_DATA
19
20 .globl vdso_start, vdso_end
21 .balign PAGE_SIZE
22vdso_start:
23 .incbin "arch/riscv/kernel/vdso/vdso.so"
24 .balign PAGE_SIZE
25vdso_end:
26
27 .previous
diff --git a/arch/riscv/kernel/vdso/vdso.lds.S b/arch/riscv/kernel/vdso/vdso.lds.S
new file mode 100644
index 000000000000..8c9dce95c11d
--- /dev/null
+++ b/arch/riscv/kernel/vdso/vdso.lds.S
@@ -0,0 +1,77 @@
1/*
2 * Copyright (C) 2012 Regents of the University of California
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation, version 2.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14OUTPUT_ARCH(riscv)
15
16SECTIONS
17{
18 . = SIZEOF_HEADERS;
19
20 .hash : { *(.hash) } :text
21 .gnu.hash : { *(.gnu.hash) }
22 .dynsym : { *(.dynsym) }
23 .dynstr : { *(.dynstr) }
24 .gnu.version : { *(.gnu.version) }
25 .gnu.version_d : { *(.gnu.version_d) }
26 .gnu.version_r : { *(.gnu.version_r) }
27
28 .note : { *(.note.*) } :text :note
29 .dynamic : { *(.dynamic) } :text :dynamic
30
31 .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
32 .eh_frame : { KEEP (*(.eh_frame)) } :text
33
34 .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
35
36 /*
37 * This linker script is used both with -r and with -shared.
38 * For the layouts to match, we need to skip more than enough
39 * space for the dynamic symbol table, etc. If this amount is
40 * insufficient, ld -shared will error; simply increase it here.
41 */
42 . = 0x800;
43 .text : { *(.text .text.*) } :text
44
45 .data : {
46 *(.got.plt) *(.got)
47 *(.data .data.* .gnu.linkonce.d.*)
48 *(.dynbss)
49 *(.bss .bss.* .gnu.linkonce.b.*)
50 }
51}
52
53/*
54 * We must supply the ELF program headers explicitly to get just one
55 * PT_LOAD segment, and set the flags explicitly to make segments read-only.
56 */
57PHDRS
58{
59 text PT_LOAD FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */
60 dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
61 note PT_NOTE FLAGS(4); /* PF_R */
62 eh_frame_hdr PT_GNU_EH_FRAME;
63}
64
65/*
66 * This controls what symbols we export from the DSO.
67 */
68VERSION
69{
70 LINUX_4.15 {
71 global:
72 __vdso_rt_sigreturn;
73 __vdso_cmpxchg32;
74 __vdso_cmpxchg64;
75 local: *;
76 };
77}