1 /* SPDX-License-Identifier: GPL-2.0 */
3 * Copyright (C) 2012 Regents of the University of California
4 * Copyright (C) 2017 SiFive
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.
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.
16 #include <linux/linkage.h>
20 #include <asm/asm-offsets.h>
22 SYM_FUNC_START(__fstate_save)
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)
63 SYM_FUNC_END(__fstate_save)
65 SYM_FUNC_START(__fstate_restore)
69 lw t0, TASK_THREAD_FCSR_F0(a0)
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)
106 SYM_FUNC_END(__fstate_restore)
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
114 # define get_f64(which) fsd which, 0(a1); j 2f
115 # define put_f64(which) fld which, 0(a1); j 2f
118 .macro fp_access_prologue
120 * Compute jump offset to store the correct FP register since we don't
121 * have indirect FP register access
132 .macro fp_access_epilogue
138 #define fp_access_body(__access_func) \
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); \
173 #ifdef CONFIG_RISCV_SCALAR_MISALIGNED
176 * Disable compressed instructions set to keep a constant offset between FP
177 * load/store/move instructions
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
185 SYM_FUNC_START(put_f32_reg)
187 fp_access_body(put_f32)
189 SYM_FUNC_END(put_f32_reg)
192 * get_f32_reg - Get a FP register value and return it
193 * a0 = FP register index to be retrieved
195 SYM_FUNC_START(get_f32_reg)
197 fp_access_body(get_f32)
199 SYM_FUNC_END(get_f32_reg)
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).
207 SYM_FUNC_START(put_f64_reg)
209 fp_access_body(put_f64)
211 SYM_FUNC_END(put_f64_reg)
214 * get_f64_reg - Get a 64 bits FP register value and returned it or store it to
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
221 SYM_FUNC_START(get_f64_reg)
223 fp_access_body(get_f64)
225 SYM_FUNC_END(get_f64_reg)
227 #endif /* CONFIG_RISCV_SCALAR_MISALIGNED */