diff options
author | Palmer Dabbelt <palmer@dabbelt.com> | 2017-07-10 21:07:09 -0400 |
---|---|---|
committer | Palmer Dabbelt <palmer@dabbelt.com> | 2017-09-26 18:26:48 -0400 |
commit | e2c0cdfba7f69925afc92b20cd9835d81e11a4f1 (patch) | |
tree | 2c501638321da451423b385652183d60da02db5c | |
parent | 07037db5d479f90377c998259a4f9a469c404edf (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>
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 | |||
20 | typedef 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 | |||
22 | struct 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 | |||
76 | static inline unsigned long instruction_pointer(struct pt_regs *regs) | ||
77 | { | ||
78 | return GET_IP(regs); | ||
79 | } | ||
80 | static 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 | |||
92 | static inline unsigned long user_stack_pointer(struct pt_regs *regs) | ||
93 | { | ||
94 | return GET_USP(regs); | ||
95 | } | ||
96 | static 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 | |||
106 | static inline unsigned long frame_pointer(struct pt_regs *regs) | ||
107 | { | ||
108 | return GET_FP(regs); | ||
109 | } | ||
110 | static 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. */ | ||
25 | extern 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 | */ | ||
32 | static inline int syscall_get_nr(struct task_struct *task, | ||
33 | struct pt_regs *regs) | ||
34 | { | ||
35 | return regs->a7; | ||
36 | } | ||
37 | |||
38 | static inline void syscall_set_nr(struct task_struct *task, | ||
39 | struct pt_regs *regs, | ||
40 | int sysno) | ||
41 | { | ||
42 | regs->a7 = sysno; | ||
43 | } | ||
44 | |||
45 | static inline void syscall_rollback(struct task_struct *task, | ||
46 | struct pt_regs *regs) | ||
47 | { | ||
48 | regs->a0 = regs->orig_a0; | ||
49 | } | ||
50 | |||
51 | static 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 | |||
59 | static inline long syscall_get_return_value(struct task_struct *task, | ||
60 | struct pt_regs *regs) | ||
61 | { | ||
62 | return regs->a0; | ||
63 | } | ||
64 | |||
65 | static 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 | |||
72 | static 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, ®s->a1 + i * sizeof(regs->a1), n * sizeof(args[0])); | ||
85 | } | ||
86 | |||
87 | static 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(®s->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 | |||
24 | struct 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 | ||
2 | include include/uapi/asm-generic/Kbuild.asm | ||
3 | |||
4 | generic-y += setup.h | ||
5 | generic-y += unistd.h | ||
6 | generic-y += errno.h | ||
7 | generic-y += fcntl.h | ||
8 | generic-y += ioctl.h | ||
9 | generic-y += ioctls.h | ||
10 | generic-y += ipcbuf.h | ||
11 | generic-y += mman.h | ||
12 | generic-y += msgbuf.h | ||
13 | generic-y += param.h | ||
14 | generic-y += poll.h | ||
15 | generic-y += posix_types.h | ||
16 | generic-y += resource.h | ||
17 | generic-y += sembuf.h | ||
18 | generic-y += shmbuf.h | ||
19 | generic-y += signal.h | ||
20 | generic-y += socket.h | ||
21 | generic-y += sockios.h | ||
22 | generic-y += stat.h | ||
23 | generic-y += statfs.h | ||
24 | generic-y += swab.h | ||
25 | generic-y += termbits.h | ||
26 | generic-y += termios.h | ||
27 | generic-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 */ | ||
18 | typedef unsigned long elf_greg_t; | ||
19 | typedef struct user_regs_struct elf_gregset_t; | ||
20 | #define ELF_NGREG (sizeof(elf_gregset_t) / sizeof(elf_greg_t)) | ||
21 | |||
22 | typedef 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 | */ | ||
27 | struct 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 | |||
62 | struct __riscv_f_ext_state { | ||
63 | __u32 f[32]; | ||
64 | __u32 fcsr; | ||
65 | }; | ||
66 | |||
67 | struct __riscv_d_ext_state { | ||
68 | __u64 f[32]; | ||
69 | __u32 fcsr; | ||
70 | }; | ||
71 | |||
72 | struct __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 | |||
82 | union __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 | */ | ||
25 | struct 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 | |||
24 | struct 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 | |||
24 | unsigned long elf_hwcap __read_mostly; | ||
25 | |||
26 | void 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 | |||
20 | static int apply_r_riscv_64_rela(struct module *me, u32 *location, Elf_Addr v) | ||
21 | { | ||
22 | *(u64 *)location = v; | ||
23 | return 0; | ||
24 | } | ||
25 | |||
26 | static 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 | |||
39 | static 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 | |||
52 | static 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 | |||
70 | static 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 | |||
81 | static 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 | |||
95 | static 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 | |||
116 | static int apply_r_riscv_relax_rela(struct module *me, u32 *location, | ||
117 | Elf_Addr v) | ||
118 | { | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | static 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 | |||
134 | int 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 | |||
29 | enum riscv_regset { | ||
30 | REGSET_X, | ||
31 | }; | ||
32 | |||
33 | static 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 | |||
44 | static 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, ®s, 0, -1); | ||
54 | return ret; | ||
55 | } | ||
56 | |||
57 | |||
58 | static 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 | |||
69 | static 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 | |||
76 | const struct user_regset_view *task_user_regset_view(struct task_struct *task) | ||
77 | { | ||
78 | return &riscv_user_native_view; | ||
79 | } | ||
80 | |||
81 | void ptrace_disable(struct task_struct *child) | ||
82 | { | ||
83 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
84 | } | ||
85 | |||
86 | long 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 | */ | ||
104 | void 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 | |||
116 | void 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 | */ | ||
15 | EXPORT_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 | |||
35 | struct rt_sigframe { | ||
36 | struct siginfo info; | ||
37 | struct ucontext uc; | ||
38 | }; | ||
39 | |||
40 | static 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(¤t->thread.fstate, state, sizeof(*state)); | ||
45 | if (likely(!err)) | ||
46 | fstate_restore(current, regs); | ||
47 | return err; | ||
48 | } | ||
49 | |||
50 | static 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, ¤t->thread.fstate, sizeof(*state)); | ||
55 | } | ||
56 | |||
57 | static 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 | |||
82 | SYSCALL_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 | |||
110 | badframe: | ||
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 | |||
122 | static 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 | |||
138 | static 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 | |||
162 | static 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 | |||
209 | static 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 | |||
242 | static 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 | */ | ||
281 | asmlinkage 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 | |||
20 | static 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 | ||
32 | SYSCALL_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 | ||
39 | SYSCALL_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 | |||
22 | void *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 @@ | |||
1 | vdso.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 | ||
4 | vdso-syms = rt_sigreturn | ||
5 | |||
6 | # Files to link into the vdso | ||
7 | obj-vdso = $(patsubst %, %.o, $(vdso-syms)) | ||
8 | |||
9 | # Build rules | ||
10 | targets := $(obj-vdso) vdso.so vdso.so.dbg vdso.lds vdso-dummy.o | ||
11 | obj-vdso := $(addprefix $(obj)/, $(obj-vdso)) | ||
12 | |||
13 | obj-y += vdso.o vdso-syms.o | ||
14 | CPPFLAGS_vdso.lds += -P -C -U$(ARCH) | ||
15 | |||
16 | # Disable gcov profiling for VDSO code | ||
17 | GCOV_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 | ||
23 | SYSCFLAGS_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 | |||
31 | SYSCFLAGS_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 | |||
36 | LDFLAGS_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. | ||
49 | quiet_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 | ||
56 | quiet_cmd_vdso_install = INSTALL $@ | ||
57 | cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ | ||
58 | |||
59 | vdso.so: $(obj)/vdso.so.dbg | ||
60 | @mkdir -p $(MODLIB)/vdso | ||
61 | $(call cmd,vdso_install) | ||
62 | |||
63 | vdso_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 | ||
18 | ENTRY(__vdso_rt_sigreturn) | ||
19 | .cfi_startproc | ||
20 | .cfi_signal_frame | ||
21 | li a7, __NR_rt_sigreturn | ||
22 | scall | ||
23 | .cfi_endproc | ||
24 | ENDPROC(__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 | ||
22 | vdso_start: | ||
23 | .incbin "arch/riscv/kernel/vdso/vdso.so" | ||
24 | .balign PAGE_SIZE | ||
25 | vdso_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 | |||
14 | OUTPUT_ARCH(riscv) | ||
15 | |||
16 | SECTIONS | ||
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 | */ | ||
57 | PHDRS | ||
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 | */ | ||
68 | VERSION | ||
69 | { | ||
70 | LINUX_4.15 { | ||
71 | global: | ||
72 | __vdso_rt_sigreturn; | ||
73 | __vdso_cmpxchg32; | ||
74 | __vdso_cmpxchg64; | ||
75 | local: *; | ||
76 | }; | ||
77 | } | ||