GNU Linux-libre 6.7.9-gnu
[releases.git] / arch / riscv / kernel / fpu.S
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Copyright (C) 2012 Regents of the University of California
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/linkage.h>
17
18 #include <asm/asm.h>
19 #include <asm/csr.h>
20 #include <asm/asm-offsets.h>
21
22 SYM_FUNC_START(__fstate_save)
23         li  a2,  TASK_THREAD_F0
24         add a0, a0, a2
25         li t1, SR_FS
26         csrs CSR_STATUS, t1
27         frcsr t0
28         fsd f0,  TASK_THREAD_F0_F0(a0)
29         fsd f1,  TASK_THREAD_F1_F0(a0)
30         fsd f2,  TASK_THREAD_F2_F0(a0)
31         fsd f3,  TASK_THREAD_F3_F0(a0)
32         fsd f4,  TASK_THREAD_F4_F0(a0)
33         fsd f5,  TASK_THREAD_F5_F0(a0)
34         fsd f6,  TASK_THREAD_F6_F0(a0)
35         fsd f7,  TASK_THREAD_F7_F0(a0)
36         fsd f8,  TASK_THREAD_F8_F0(a0)
37         fsd f9,  TASK_THREAD_F9_F0(a0)
38         fsd f10, TASK_THREAD_F10_F0(a0)
39         fsd f11, TASK_THREAD_F11_F0(a0)
40         fsd f12, TASK_THREAD_F12_F0(a0)
41         fsd f13, TASK_THREAD_F13_F0(a0)
42         fsd f14, TASK_THREAD_F14_F0(a0)
43         fsd f15, TASK_THREAD_F15_F0(a0)
44         fsd f16, TASK_THREAD_F16_F0(a0)
45         fsd f17, TASK_THREAD_F17_F0(a0)
46         fsd f18, TASK_THREAD_F18_F0(a0)
47         fsd f19, TASK_THREAD_F19_F0(a0)
48         fsd f20, TASK_THREAD_F20_F0(a0)
49         fsd f21, TASK_THREAD_F21_F0(a0)
50         fsd f22, TASK_THREAD_F22_F0(a0)
51         fsd f23, TASK_THREAD_F23_F0(a0)
52         fsd f24, TASK_THREAD_F24_F0(a0)
53         fsd f25, TASK_THREAD_F25_F0(a0)
54         fsd f26, TASK_THREAD_F26_F0(a0)
55         fsd f27, TASK_THREAD_F27_F0(a0)
56         fsd f28, TASK_THREAD_F28_F0(a0)
57         fsd f29, TASK_THREAD_F29_F0(a0)
58         fsd f30, TASK_THREAD_F30_F0(a0)
59         fsd f31, TASK_THREAD_F31_F0(a0)
60         sw t0, TASK_THREAD_FCSR_F0(a0)
61         csrc CSR_STATUS, t1
62         ret
63 SYM_FUNC_END(__fstate_save)
64
65 SYM_FUNC_START(__fstate_restore)
66         li  a2,  TASK_THREAD_F0
67         add a0, a0, a2
68         li t1, SR_FS
69         lw t0, TASK_THREAD_FCSR_F0(a0)
70         csrs CSR_STATUS, t1
71         fld f0,  TASK_THREAD_F0_F0(a0)
72         fld f1,  TASK_THREAD_F1_F0(a0)
73         fld f2,  TASK_THREAD_F2_F0(a0)
74         fld f3,  TASK_THREAD_F3_F0(a0)
75         fld f4,  TASK_THREAD_F4_F0(a0)
76         fld f5,  TASK_THREAD_F5_F0(a0)
77         fld f6,  TASK_THREAD_F6_F0(a0)
78         fld f7,  TASK_THREAD_F7_F0(a0)
79         fld f8,  TASK_THREAD_F8_F0(a0)
80         fld f9,  TASK_THREAD_F9_F0(a0)
81         fld f10, TASK_THREAD_F10_F0(a0)
82         fld f11, TASK_THREAD_F11_F0(a0)
83         fld f12, TASK_THREAD_F12_F0(a0)
84         fld f13, TASK_THREAD_F13_F0(a0)
85         fld f14, TASK_THREAD_F14_F0(a0)
86         fld f15, TASK_THREAD_F15_F0(a0)
87         fld f16, TASK_THREAD_F16_F0(a0)
88         fld f17, TASK_THREAD_F17_F0(a0)
89         fld f18, TASK_THREAD_F18_F0(a0)
90         fld f19, TASK_THREAD_F19_F0(a0)
91         fld f20, TASK_THREAD_F20_F0(a0)
92         fld f21, TASK_THREAD_F21_F0(a0)
93         fld f22, TASK_THREAD_F22_F0(a0)
94         fld f23, TASK_THREAD_F23_F0(a0)
95         fld f24, TASK_THREAD_F24_F0(a0)
96         fld f25, TASK_THREAD_F25_F0(a0)
97         fld f26, TASK_THREAD_F26_F0(a0)
98         fld f27, TASK_THREAD_F27_F0(a0)
99         fld f28, TASK_THREAD_F28_F0(a0)
100         fld f29, TASK_THREAD_F29_F0(a0)
101         fld f30, TASK_THREAD_F30_F0(a0)
102         fld f31, TASK_THREAD_F31_F0(a0)
103         fscsr t0
104         csrc CSR_STATUS, t1
105         ret
106 SYM_FUNC_END(__fstate_restore)
107
108 #define get_f32(which) fmv.x.s a0, which; j 2f
109 #define put_f32(which) fmv.s.x which, a1; j 2f
110 #if __riscv_xlen == 64
111 # define get_f64(which) fmv.x.d a0, which; j 2f
112 # define put_f64(which) fmv.d.x which, a1; j 2f
113 #else
114 # define get_f64(which) fsd which, 0(a1); j 2f
115 # define put_f64(which) fld which, 0(a1); j 2f
116 #endif
117
118 .macro fp_access_prologue
119         /*
120          * Compute jump offset to store the correct FP register since we don't
121          * have indirect FP register access
122          */
123         sll t0, a0, 3
124         la t2, 1f
125         add t0, t0, t2
126         li t1, SR_FS
127         csrs CSR_STATUS, t1
128         jr t0
129 1:
130 .endm
131
132 .macro fp_access_epilogue
133 2:
134         csrc CSR_STATUS, t1
135         ret
136 .endm
137
138 #define fp_access_body(__access_func) \
139         __access_func(f0); \
140         __access_func(f1); \
141         __access_func(f2); \
142         __access_func(f3); \
143         __access_func(f4); \
144         __access_func(f5); \
145         __access_func(f6); \
146         __access_func(f7); \
147         __access_func(f8); \
148         __access_func(f9); \
149         __access_func(f10); \
150         __access_func(f11); \
151         __access_func(f12); \
152         __access_func(f13); \
153         __access_func(f14); \
154         __access_func(f15); \
155         __access_func(f16); \
156         __access_func(f17); \
157         __access_func(f18); \
158         __access_func(f19); \
159         __access_func(f20); \
160         __access_func(f21); \
161         __access_func(f22); \
162         __access_func(f23); \
163         __access_func(f24); \
164         __access_func(f25); \
165         __access_func(f26); \
166         __access_func(f27); \
167         __access_func(f28); \
168         __access_func(f29); \
169         __access_func(f30); \
170         __access_func(f31)
171
172
173 #ifdef CONFIG_RISCV_MISALIGNED
174
175 /*
176  * Disable compressed instructions set to keep a constant offset between FP
177  * load/store/move instructions
178  */
179 .option norvc
180 /*
181  * put_f32_reg - Set a FP register from a register containing the value
182  * a0 = FP register index to be set
183  * a1 = value to be loaded in the FP register
184  */
185 SYM_FUNC_START(put_f32_reg)
186         fp_access_prologue
187         fp_access_body(put_f32)
188         fp_access_epilogue
189 SYM_FUNC_END(put_f32_reg)
190
191 /*
192  * get_f32_reg - Get a FP register value and return it
193  * a0 = FP register index to be retrieved
194  */
195 SYM_FUNC_START(get_f32_reg)
196         fp_access_prologue
197         fp_access_body(get_f32)
198         fp_access_epilogue
199 SYM_FUNC_END(get_f32_reg)
200
201 /*
202  * put_f64_reg - Set a 64 bits FP register from a value or a pointer.
203  * a0 = FP register index to be set
204  * a1 = value/pointer to be loaded in the FP register (when xlen == 32 bits, we
205  * load the value to a pointer).
206  */
207 SYM_FUNC_START(put_f64_reg)
208         fp_access_prologue
209         fp_access_body(put_f64)
210         fp_access_epilogue
211 SYM_FUNC_END(put_f64_reg)
212
213 /*
214  * put_f64_reg - Get a 64 bits FP register value and returned it or store it to
215  *               a pointer.
216  * a0 = FP register index to be retrieved
217  * a1 = If xlen == 32, pointer which should be loaded with the FP register value
218  *      or unused if xlen == 64. In which case the FP register value is returned
219  *      through a0
220  */
221 SYM_FUNC_START(get_f64_reg)
222         fp_access_prologue
223         fp_access_body(get_f64)
224         fp_access_epilogue
225 SYM_FUNC_END(get_f64_reg)
226
227 #endif /* CONFIG_RISCV_MISALIGNED */