xref: /linux/arch/loongarch/kernel/unaligned.c (revision cdd5b5a9761fd66d17586e4f4ba6588c70e640ea)
1*61a6fcccSHuacai Chen // SPDX-License-Identifier: GPL-2.0
2*61a6fcccSHuacai Chen /*
3*61a6fcccSHuacai Chen  * Handle unaligned accesses by emulation.
4*61a6fcccSHuacai Chen  *
5*61a6fcccSHuacai Chen  * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
6*61a6fcccSHuacai Chen  *
7*61a6fcccSHuacai Chen  * Derived from MIPS:
8*61a6fcccSHuacai Chen  * Copyright (C) 1996, 1998, 1999, 2002 by Ralf Baechle
9*61a6fcccSHuacai Chen  * Copyright (C) 1999 Silicon Graphics, Inc.
10*61a6fcccSHuacai Chen  * Copyright (C) 2014 Imagination Technologies Ltd.
11*61a6fcccSHuacai Chen  */
12*61a6fcccSHuacai Chen #include <linux/mm.h>
13*61a6fcccSHuacai Chen #include <linux/sched.h>
14*61a6fcccSHuacai Chen #include <linux/signal.h>
15*61a6fcccSHuacai Chen #include <linux/debugfs.h>
16*61a6fcccSHuacai Chen #include <linux/perf_event.h>
17*61a6fcccSHuacai Chen 
18*61a6fcccSHuacai Chen #include <asm/asm.h>
19*61a6fcccSHuacai Chen #include <asm/branch.h>
20*61a6fcccSHuacai Chen #include <asm/fpu.h>
21*61a6fcccSHuacai Chen #include <asm/inst.h>
22*61a6fcccSHuacai Chen 
23*61a6fcccSHuacai Chen #include "access-helper.h"
24*61a6fcccSHuacai Chen 
25*61a6fcccSHuacai Chen #ifdef CONFIG_DEBUG_FS
26*61a6fcccSHuacai Chen static u32 unaligned_instructions_user;
27*61a6fcccSHuacai Chen static u32 unaligned_instructions_kernel;
28*61a6fcccSHuacai Chen #endif
29*61a6fcccSHuacai Chen 
read_fpr(unsigned int idx)30*61a6fcccSHuacai Chen static inline unsigned long read_fpr(unsigned int idx)
31*61a6fcccSHuacai Chen {
32*61a6fcccSHuacai Chen #define READ_FPR(idx, __value)		\
33*61a6fcccSHuacai Chen 	__asm__ __volatile__("movfr2gr.d %0, $f"#idx"\n\t" : "=r"(__value));
34*61a6fcccSHuacai Chen 
35*61a6fcccSHuacai Chen 	unsigned long __value;
36*61a6fcccSHuacai Chen 
37*61a6fcccSHuacai Chen 	switch (idx) {
38*61a6fcccSHuacai Chen 	case 0:
39*61a6fcccSHuacai Chen 		READ_FPR(0, __value);
40*61a6fcccSHuacai Chen 		break;
41*61a6fcccSHuacai Chen 	case 1:
42*61a6fcccSHuacai Chen 		READ_FPR(1, __value);
43*61a6fcccSHuacai Chen 		break;
44*61a6fcccSHuacai Chen 	case 2:
45*61a6fcccSHuacai Chen 		READ_FPR(2, __value);
46*61a6fcccSHuacai Chen 		break;
47*61a6fcccSHuacai Chen 	case 3:
48*61a6fcccSHuacai Chen 		READ_FPR(3, __value);
49*61a6fcccSHuacai Chen 		break;
50*61a6fcccSHuacai Chen 	case 4:
51*61a6fcccSHuacai Chen 		READ_FPR(4, __value);
52*61a6fcccSHuacai Chen 		break;
53*61a6fcccSHuacai Chen 	case 5:
54*61a6fcccSHuacai Chen 		READ_FPR(5, __value);
55*61a6fcccSHuacai Chen 		break;
56*61a6fcccSHuacai Chen 	case 6:
57*61a6fcccSHuacai Chen 		READ_FPR(6, __value);
58*61a6fcccSHuacai Chen 		break;
59*61a6fcccSHuacai Chen 	case 7:
60*61a6fcccSHuacai Chen 		READ_FPR(7, __value);
61*61a6fcccSHuacai Chen 		break;
62*61a6fcccSHuacai Chen 	case 8:
63*61a6fcccSHuacai Chen 		READ_FPR(8, __value);
64*61a6fcccSHuacai Chen 		break;
65*61a6fcccSHuacai Chen 	case 9:
66*61a6fcccSHuacai Chen 		READ_FPR(9, __value);
67*61a6fcccSHuacai Chen 		break;
68*61a6fcccSHuacai Chen 	case 10:
69*61a6fcccSHuacai Chen 		READ_FPR(10, __value);
70*61a6fcccSHuacai Chen 		break;
71*61a6fcccSHuacai Chen 	case 11:
72*61a6fcccSHuacai Chen 		READ_FPR(11, __value);
73*61a6fcccSHuacai Chen 		break;
74*61a6fcccSHuacai Chen 	case 12:
75*61a6fcccSHuacai Chen 		READ_FPR(12, __value);
76*61a6fcccSHuacai Chen 		break;
77*61a6fcccSHuacai Chen 	case 13:
78*61a6fcccSHuacai Chen 		READ_FPR(13, __value);
79*61a6fcccSHuacai Chen 		break;
80*61a6fcccSHuacai Chen 	case 14:
81*61a6fcccSHuacai Chen 		READ_FPR(14, __value);
82*61a6fcccSHuacai Chen 		break;
83*61a6fcccSHuacai Chen 	case 15:
84*61a6fcccSHuacai Chen 		READ_FPR(15, __value);
85*61a6fcccSHuacai Chen 		break;
86*61a6fcccSHuacai Chen 	case 16:
87*61a6fcccSHuacai Chen 		READ_FPR(16, __value);
88*61a6fcccSHuacai Chen 		break;
89*61a6fcccSHuacai Chen 	case 17:
90*61a6fcccSHuacai Chen 		READ_FPR(17, __value);
91*61a6fcccSHuacai Chen 		break;
92*61a6fcccSHuacai Chen 	case 18:
93*61a6fcccSHuacai Chen 		READ_FPR(18, __value);
94*61a6fcccSHuacai Chen 		break;
95*61a6fcccSHuacai Chen 	case 19:
96*61a6fcccSHuacai Chen 		READ_FPR(19, __value);
97*61a6fcccSHuacai Chen 		break;
98*61a6fcccSHuacai Chen 	case 20:
99*61a6fcccSHuacai Chen 		READ_FPR(20, __value);
100*61a6fcccSHuacai Chen 		break;
101*61a6fcccSHuacai Chen 	case 21:
102*61a6fcccSHuacai Chen 		READ_FPR(21, __value);
103*61a6fcccSHuacai Chen 		break;
104*61a6fcccSHuacai Chen 	case 22:
105*61a6fcccSHuacai Chen 		READ_FPR(22, __value);
106*61a6fcccSHuacai Chen 		break;
107*61a6fcccSHuacai Chen 	case 23:
108*61a6fcccSHuacai Chen 		READ_FPR(23, __value);
109*61a6fcccSHuacai Chen 		break;
110*61a6fcccSHuacai Chen 	case 24:
111*61a6fcccSHuacai Chen 		READ_FPR(24, __value);
112*61a6fcccSHuacai Chen 		break;
113*61a6fcccSHuacai Chen 	case 25:
114*61a6fcccSHuacai Chen 		READ_FPR(25, __value);
115*61a6fcccSHuacai Chen 		break;
116*61a6fcccSHuacai Chen 	case 26:
117*61a6fcccSHuacai Chen 		READ_FPR(26, __value);
118*61a6fcccSHuacai Chen 		break;
119*61a6fcccSHuacai Chen 	case 27:
120*61a6fcccSHuacai Chen 		READ_FPR(27, __value);
121*61a6fcccSHuacai Chen 		break;
122*61a6fcccSHuacai Chen 	case 28:
123*61a6fcccSHuacai Chen 		READ_FPR(28, __value);
124*61a6fcccSHuacai Chen 		break;
125*61a6fcccSHuacai Chen 	case 29:
126*61a6fcccSHuacai Chen 		READ_FPR(29, __value);
127*61a6fcccSHuacai Chen 		break;
128*61a6fcccSHuacai Chen 	case 30:
129*61a6fcccSHuacai Chen 		READ_FPR(30, __value);
130*61a6fcccSHuacai Chen 		break;
131*61a6fcccSHuacai Chen 	case 31:
132*61a6fcccSHuacai Chen 		READ_FPR(31, __value);
133*61a6fcccSHuacai Chen 		break;
134*61a6fcccSHuacai Chen 	default:
135*61a6fcccSHuacai Chen 		panic("unexpected idx '%d'", idx);
136*61a6fcccSHuacai Chen 	}
137*61a6fcccSHuacai Chen #undef READ_FPR
138*61a6fcccSHuacai Chen 	return __value;
139*61a6fcccSHuacai Chen }
140*61a6fcccSHuacai Chen 
write_fpr(unsigned int idx,unsigned long value)141*61a6fcccSHuacai Chen static inline void write_fpr(unsigned int idx, unsigned long value)
142*61a6fcccSHuacai Chen {
143*61a6fcccSHuacai Chen #define WRITE_FPR(idx, value)		\
144*61a6fcccSHuacai Chen 	__asm__ __volatile__("movgr2fr.d $f"#idx", %0\n\t" :: "r"(value));
145*61a6fcccSHuacai Chen 
146*61a6fcccSHuacai Chen 	switch (idx) {
147*61a6fcccSHuacai Chen 	case 0:
148*61a6fcccSHuacai Chen 		WRITE_FPR(0, value);
149*61a6fcccSHuacai Chen 		break;
150*61a6fcccSHuacai Chen 	case 1:
151*61a6fcccSHuacai Chen 		WRITE_FPR(1, value);
152*61a6fcccSHuacai Chen 		break;
153*61a6fcccSHuacai Chen 	case 2:
154*61a6fcccSHuacai Chen 		WRITE_FPR(2, value);
155*61a6fcccSHuacai Chen 		break;
156*61a6fcccSHuacai Chen 	case 3:
157*61a6fcccSHuacai Chen 		WRITE_FPR(3, value);
158*61a6fcccSHuacai Chen 		break;
159*61a6fcccSHuacai Chen 	case 4:
160*61a6fcccSHuacai Chen 		WRITE_FPR(4, value);
161*61a6fcccSHuacai Chen 		break;
162*61a6fcccSHuacai Chen 	case 5:
163*61a6fcccSHuacai Chen 		WRITE_FPR(5, value);
164*61a6fcccSHuacai Chen 		break;
165*61a6fcccSHuacai Chen 	case 6:
166*61a6fcccSHuacai Chen 		WRITE_FPR(6, value);
167*61a6fcccSHuacai Chen 		break;
168*61a6fcccSHuacai Chen 	case 7:
169*61a6fcccSHuacai Chen 		WRITE_FPR(7, value);
170*61a6fcccSHuacai Chen 		break;
171*61a6fcccSHuacai Chen 	case 8:
172*61a6fcccSHuacai Chen 		WRITE_FPR(8, value);
173*61a6fcccSHuacai Chen 		break;
174*61a6fcccSHuacai Chen 	case 9:
175*61a6fcccSHuacai Chen 		WRITE_FPR(9, value);
176*61a6fcccSHuacai Chen 		break;
177*61a6fcccSHuacai Chen 	case 10:
178*61a6fcccSHuacai Chen 		WRITE_FPR(10, value);
179*61a6fcccSHuacai Chen 		break;
180*61a6fcccSHuacai Chen 	case 11:
181*61a6fcccSHuacai Chen 		WRITE_FPR(11, value);
182*61a6fcccSHuacai Chen 		break;
183*61a6fcccSHuacai Chen 	case 12:
184*61a6fcccSHuacai Chen 		WRITE_FPR(12, value);
185*61a6fcccSHuacai Chen 		break;
186*61a6fcccSHuacai Chen 	case 13:
187*61a6fcccSHuacai Chen 		WRITE_FPR(13, value);
188*61a6fcccSHuacai Chen 		break;
189*61a6fcccSHuacai Chen 	case 14:
190*61a6fcccSHuacai Chen 		WRITE_FPR(14, value);
191*61a6fcccSHuacai Chen 		break;
192*61a6fcccSHuacai Chen 	case 15:
193*61a6fcccSHuacai Chen 		WRITE_FPR(15, value);
194*61a6fcccSHuacai Chen 		break;
195*61a6fcccSHuacai Chen 	case 16:
196*61a6fcccSHuacai Chen 		WRITE_FPR(16, value);
197*61a6fcccSHuacai Chen 		break;
198*61a6fcccSHuacai Chen 	case 17:
199*61a6fcccSHuacai Chen 		WRITE_FPR(17, value);
200*61a6fcccSHuacai Chen 		break;
201*61a6fcccSHuacai Chen 	case 18:
202*61a6fcccSHuacai Chen 		WRITE_FPR(18, value);
203*61a6fcccSHuacai Chen 		break;
204*61a6fcccSHuacai Chen 	case 19:
205*61a6fcccSHuacai Chen 		WRITE_FPR(19, value);
206*61a6fcccSHuacai Chen 		break;
207*61a6fcccSHuacai Chen 	case 20:
208*61a6fcccSHuacai Chen 		WRITE_FPR(20, value);
209*61a6fcccSHuacai Chen 		break;
210*61a6fcccSHuacai Chen 	case 21:
211*61a6fcccSHuacai Chen 		WRITE_FPR(21, value);
212*61a6fcccSHuacai Chen 		break;
213*61a6fcccSHuacai Chen 	case 22:
214*61a6fcccSHuacai Chen 		WRITE_FPR(22, value);
215*61a6fcccSHuacai Chen 		break;
216*61a6fcccSHuacai Chen 	case 23:
217*61a6fcccSHuacai Chen 		WRITE_FPR(23, value);
218*61a6fcccSHuacai Chen 		break;
219*61a6fcccSHuacai Chen 	case 24:
220*61a6fcccSHuacai Chen 		WRITE_FPR(24, value);
221*61a6fcccSHuacai Chen 		break;
222*61a6fcccSHuacai Chen 	case 25:
223*61a6fcccSHuacai Chen 		WRITE_FPR(25, value);
224*61a6fcccSHuacai Chen 		break;
225*61a6fcccSHuacai Chen 	case 26:
226*61a6fcccSHuacai Chen 		WRITE_FPR(26, value);
227*61a6fcccSHuacai Chen 		break;
228*61a6fcccSHuacai Chen 	case 27:
229*61a6fcccSHuacai Chen 		WRITE_FPR(27, value);
230*61a6fcccSHuacai Chen 		break;
231*61a6fcccSHuacai Chen 	case 28:
232*61a6fcccSHuacai Chen 		WRITE_FPR(28, value);
233*61a6fcccSHuacai Chen 		break;
234*61a6fcccSHuacai Chen 	case 29:
235*61a6fcccSHuacai Chen 		WRITE_FPR(29, value);
236*61a6fcccSHuacai Chen 		break;
237*61a6fcccSHuacai Chen 	case 30:
238*61a6fcccSHuacai Chen 		WRITE_FPR(30, value);
239*61a6fcccSHuacai Chen 		break;
240*61a6fcccSHuacai Chen 	case 31:
241*61a6fcccSHuacai Chen 		WRITE_FPR(31, value);
242*61a6fcccSHuacai Chen 		break;
243*61a6fcccSHuacai Chen 	default:
244*61a6fcccSHuacai Chen 		panic("unexpected idx '%d'", idx);
245*61a6fcccSHuacai Chen 	}
246*61a6fcccSHuacai Chen #undef WRITE_FPR
247*61a6fcccSHuacai Chen }
248*61a6fcccSHuacai Chen 
emulate_load_store_insn(struct pt_regs * regs,void __user * addr,unsigned int * pc)249*61a6fcccSHuacai Chen void emulate_load_store_insn(struct pt_regs *regs, void __user *addr, unsigned int *pc)
250*61a6fcccSHuacai Chen {
251*61a6fcccSHuacai Chen 	bool fp = false;
252*61a6fcccSHuacai Chen 	bool sign, write;
253*61a6fcccSHuacai Chen 	bool user = user_mode(regs);
254*61a6fcccSHuacai Chen 	unsigned int res, size = 0;
255*61a6fcccSHuacai Chen 	unsigned long value = 0;
256*61a6fcccSHuacai Chen 	union loongarch_instruction insn;
257*61a6fcccSHuacai Chen 
258*61a6fcccSHuacai Chen 	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0);
259*61a6fcccSHuacai Chen 
260*61a6fcccSHuacai Chen 	__get_inst(&insn.word, pc, user);
261*61a6fcccSHuacai Chen 
262*61a6fcccSHuacai Chen 	switch (insn.reg2i12_format.opcode) {
263*61a6fcccSHuacai Chen 	case ldh_op:
264*61a6fcccSHuacai Chen 		size = 2;
265*61a6fcccSHuacai Chen 		sign = true;
266*61a6fcccSHuacai Chen 		write = false;
267*61a6fcccSHuacai Chen 		break;
268*61a6fcccSHuacai Chen 	case ldhu_op:
269*61a6fcccSHuacai Chen 		size = 2;
270*61a6fcccSHuacai Chen 		sign = false;
271*61a6fcccSHuacai Chen 		write = false;
272*61a6fcccSHuacai Chen 		break;
273*61a6fcccSHuacai Chen 	case sth_op:
274*61a6fcccSHuacai Chen 		size = 2;
275*61a6fcccSHuacai Chen 		sign = true;
276*61a6fcccSHuacai Chen 		write = true;
277*61a6fcccSHuacai Chen 		break;
278*61a6fcccSHuacai Chen 	case ldw_op:
279*61a6fcccSHuacai Chen 		size = 4;
280*61a6fcccSHuacai Chen 		sign = true;
281*61a6fcccSHuacai Chen 		write = false;
282*61a6fcccSHuacai Chen 		break;
283*61a6fcccSHuacai Chen 	case ldwu_op:
284*61a6fcccSHuacai Chen 		size = 4;
285*61a6fcccSHuacai Chen 		sign = false;
286*61a6fcccSHuacai Chen 		write = false;
287*61a6fcccSHuacai Chen 		break;
288*61a6fcccSHuacai Chen 	case stw_op:
289*61a6fcccSHuacai Chen 		size = 4;
290*61a6fcccSHuacai Chen 		sign = true;
291*61a6fcccSHuacai Chen 		write = true;
292*61a6fcccSHuacai Chen 		break;
293*61a6fcccSHuacai Chen 	case ldd_op:
294*61a6fcccSHuacai Chen 		size = 8;
295*61a6fcccSHuacai Chen 		sign = true;
296*61a6fcccSHuacai Chen 		write = false;
297*61a6fcccSHuacai Chen 		break;
298*61a6fcccSHuacai Chen 	case std_op:
299*61a6fcccSHuacai Chen 		size = 8;
300*61a6fcccSHuacai Chen 		sign = true;
301*61a6fcccSHuacai Chen 		write = true;
302*61a6fcccSHuacai Chen 		break;
303*61a6fcccSHuacai Chen 	case flds_op:
304*61a6fcccSHuacai Chen 		size = 4;
305*61a6fcccSHuacai Chen 		fp = true;
306*61a6fcccSHuacai Chen 		sign = true;
307*61a6fcccSHuacai Chen 		write = false;
308*61a6fcccSHuacai Chen 		break;
309*61a6fcccSHuacai Chen 	case fsts_op:
310*61a6fcccSHuacai Chen 		size = 4;
311*61a6fcccSHuacai Chen 		fp = true;
312*61a6fcccSHuacai Chen 		sign = true;
313*61a6fcccSHuacai Chen 		write = true;
314*61a6fcccSHuacai Chen 		break;
315*61a6fcccSHuacai Chen 	case fldd_op:
316*61a6fcccSHuacai Chen 		size = 8;
317*61a6fcccSHuacai Chen 		fp = true;
318*61a6fcccSHuacai Chen 		sign = true;
319*61a6fcccSHuacai Chen 		write = false;
320*61a6fcccSHuacai Chen 		break;
321*61a6fcccSHuacai Chen 	case fstd_op:
322*61a6fcccSHuacai Chen 		size = 8;
323*61a6fcccSHuacai Chen 		fp = true;
324*61a6fcccSHuacai Chen 		sign = true;
325*61a6fcccSHuacai Chen 		write = true;
326*61a6fcccSHuacai Chen 		break;
327*61a6fcccSHuacai Chen 	}
328*61a6fcccSHuacai Chen 
329*61a6fcccSHuacai Chen 	switch (insn.reg2i14_format.opcode) {
330*61a6fcccSHuacai Chen 	case ldptrw_op:
331*61a6fcccSHuacai Chen 		size = 4;
332*61a6fcccSHuacai Chen 		sign = true;
333*61a6fcccSHuacai Chen 		write = false;
334*61a6fcccSHuacai Chen 		break;
335*61a6fcccSHuacai Chen 	case stptrw_op:
336*61a6fcccSHuacai Chen 		size = 4;
337*61a6fcccSHuacai Chen 		sign = true;
338*61a6fcccSHuacai Chen 		write = true;
339*61a6fcccSHuacai Chen 		break;
340*61a6fcccSHuacai Chen 	case ldptrd_op:
341*61a6fcccSHuacai Chen 		size = 8;
342*61a6fcccSHuacai Chen 		sign = true;
343*61a6fcccSHuacai Chen 		write = false;
344*61a6fcccSHuacai Chen 		break;
345*61a6fcccSHuacai Chen 	case stptrd_op:
346*61a6fcccSHuacai Chen 		size = 8;
347*61a6fcccSHuacai Chen 		sign = true;
348*61a6fcccSHuacai Chen 		write = true;
349*61a6fcccSHuacai Chen 		break;
350*61a6fcccSHuacai Chen 	}
351*61a6fcccSHuacai Chen 
352*61a6fcccSHuacai Chen 	switch (insn.reg3_format.opcode) {
353*61a6fcccSHuacai Chen 	case ldxh_op:
354*61a6fcccSHuacai Chen 		size = 2;
355*61a6fcccSHuacai Chen 		sign = true;
356*61a6fcccSHuacai Chen 		write = false;
357*61a6fcccSHuacai Chen 		break;
358*61a6fcccSHuacai Chen 	case ldxhu_op:
359*61a6fcccSHuacai Chen 		size = 2;
360*61a6fcccSHuacai Chen 		sign = false;
361*61a6fcccSHuacai Chen 		write = false;
362*61a6fcccSHuacai Chen 		break;
363*61a6fcccSHuacai Chen 	case stxh_op:
364*61a6fcccSHuacai Chen 		size = 2;
365*61a6fcccSHuacai Chen 		sign = true;
366*61a6fcccSHuacai Chen 		write = true;
367*61a6fcccSHuacai Chen 		break;
368*61a6fcccSHuacai Chen 	case ldxw_op:
369*61a6fcccSHuacai Chen 		size = 4;
370*61a6fcccSHuacai Chen 		sign = true;
371*61a6fcccSHuacai Chen 		write = false;
372*61a6fcccSHuacai Chen 		break;
373*61a6fcccSHuacai Chen 	case ldxwu_op:
374*61a6fcccSHuacai Chen 		size = 4;
375*61a6fcccSHuacai Chen 		sign = false;
376*61a6fcccSHuacai Chen 		write = false;
377*61a6fcccSHuacai Chen 		break;
378*61a6fcccSHuacai Chen 	case stxw_op:
379*61a6fcccSHuacai Chen 		size = 4;
380*61a6fcccSHuacai Chen 		sign = true;
381*61a6fcccSHuacai Chen 		write = true;
382*61a6fcccSHuacai Chen 		break;
383*61a6fcccSHuacai Chen 	case ldxd_op:
384*61a6fcccSHuacai Chen 		size = 8;
385*61a6fcccSHuacai Chen 		sign = true;
386*61a6fcccSHuacai Chen 		write = false;
387*61a6fcccSHuacai Chen 		break;
388*61a6fcccSHuacai Chen 	case stxd_op:
389*61a6fcccSHuacai Chen 		size = 8;
390*61a6fcccSHuacai Chen 		sign = true;
391*61a6fcccSHuacai Chen 		write = true;
392*61a6fcccSHuacai Chen 		break;
393*61a6fcccSHuacai Chen 	case fldxs_op:
394*61a6fcccSHuacai Chen 		size = 4;
395*61a6fcccSHuacai Chen 		fp = true;
396*61a6fcccSHuacai Chen 		sign = true;
397*61a6fcccSHuacai Chen 		write = false;
398*61a6fcccSHuacai Chen 		break;
399*61a6fcccSHuacai Chen 	case fstxs_op:
400*61a6fcccSHuacai Chen 		size = 4;
401*61a6fcccSHuacai Chen 		fp = true;
402*61a6fcccSHuacai Chen 		sign = true;
403*61a6fcccSHuacai Chen 		write = true;
404*61a6fcccSHuacai Chen 		break;
405*61a6fcccSHuacai Chen 	case fldxd_op:
406*61a6fcccSHuacai Chen 		size = 8;
407*61a6fcccSHuacai Chen 		fp = true;
408*61a6fcccSHuacai Chen 		sign = true;
409*61a6fcccSHuacai Chen 		write = false;
410*61a6fcccSHuacai Chen 		break;
411*61a6fcccSHuacai Chen 	case fstxd_op:
412*61a6fcccSHuacai Chen 		size = 8;
413*61a6fcccSHuacai Chen 		fp = true;
414*61a6fcccSHuacai Chen 		sign = true;
415*61a6fcccSHuacai Chen 		write = true;
416*61a6fcccSHuacai Chen 		break;
417*61a6fcccSHuacai Chen 	}
418*61a6fcccSHuacai Chen 
419*61a6fcccSHuacai Chen 	if (!size)
420*61a6fcccSHuacai Chen 		goto sigbus;
421*61a6fcccSHuacai Chen 	if (user && !access_ok(addr, size))
422*61a6fcccSHuacai Chen 		goto sigbus;
423*61a6fcccSHuacai Chen 
424*61a6fcccSHuacai Chen 	if (!write) {
425*61a6fcccSHuacai Chen 		res = unaligned_read(addr, &value, size, sign);
426*61a6fcccSHuacai Chen 		if (res)
427*61a6fcccSHuacai Chen 			goto fault;
428*61a6fcccSHuacai Chen 
429*61a6fcccSHuacai Chen 		/* Rd is the same field in any formats */
430*61a6fcccSHuacai Chen 		if (!fp)
431*61a6fcccSHuacai Chen 			regs->regs[insn.reg3_format.rd] = value;
432*61a6fcccSHuacai Chen 		else {
433*61a6fcccSHuacai Chen 			if (is_fpu_owner())
434*61a6fcccSHuacai Chen 				write_fpr(insn.reg3_format.rd, value);
435*61a6fcccSHuacai Chen 			else
436*61a6fcccSHuacai Chen 				set_fpr64(&current->thread.fpu.fpr[insn.reg3_format.rd], 0, value);
437*61a6fcccSHuacai Chen 		}
438*61a6fcccSHuacai Chen 	} else {
439*61a6fcccSHuacai Chen 		/* Rd is the same field in any formats */
440*61a6fcccSHuacai Chen 		if (!fp)
441*61a6fcccSHuacai Chen 			value = regs->regs[insn.reg3_format.rd];
442*61a6fcccSHuacai Chen 		else {
443*61a6fcccSHuacai Chen 			if (is_fpu_owner())
444*61a6fcccSHuacai Chen 				value = read_fpr(insn.reg3_format.rd);
445*61a6fcccSHuacai Chen 			else
446*61a6fcccSHuacai Chen 				value = get_fpr64(&current->thread.fpu.fpr[insn.reg3_format.rd], 0);
447*61a6fcccSHuacai Chen 		}
448*61a6fcccSHuacai Chen 
449*61a6fcccSHuacai Chen 		res = unaligned_write(addr, value, size);
450*61a6fcccSHuacai Chen 		if (res)
451*61a6fcccSHuacai Chen 			goto fault;
452*61a6fcccSHuacai Chen 	}
453*61a6fcccSHuacai Chen 
454*61a6fcccSHuacai Chen #ifdef CONFIG_DEBUG_FS
455*61a6fcccSHuacai Chen 	if (user)
456*61a6fcccSHuacai Chen 		unaligned_instructions_user++;
457*61a6fcccSHuacai Chen 	else
458*61a6fcccSHuacai Chen 		unaligned_instructions_kernel++;
459*61a6fcccSHuacai Chen #endif
460*61a6fcccSHuacai Chen 
461*61a6fcccSHuacai Chen 	compute_return_era(regs);
462*61a6fcccSHuacai Chen 
463*61a6fcccSHuacai Chen 	return;
464*61a6fcccSHuacai Chen 
465*61a6fcccSHuacai Chen fault:
466*61a6fcccSHuacai Chen 	/* Did we have an exception handler installed? */
467*61a6fcccSHuacai Chen 	if (fixup_exception(regs))
468*61a6fcccSHuacai Chen 		return;
469*61a6fcccSHuacai Chen 
470*61a6fcccSHuacai Chen 	die_if_kernel("Unhandled kernel unaligned access", regs);
471*61a6fcccSHuacai Chen 	force_sig(SIGSEGV);
472*61a6fcccSHuacai Chen 
473*61a6fcccSHuacai Chen 	return;
474*61a6fcccSHuacai Chen 
475*61a6fcccSHuacai Chen sigbus:
476*61a6fcccSHuacai Chen 	die_if_kernel("Unhandled kernel unaligned access", regs);
477*61a6fcccSHuacai Chen 	force_sig(SIGBUS);
478*61a6fcccSHuacai Chen 
479*61a6fcccSHuacai Chen 	return;
480*61a6fcccSHuacai Chen }
481*61a6fcccSHuacai Chen 
482*61a6fcccSHuacai Chen #ifdef CONFIG_DEBUG_FS
debugfs_unaligned(void)483*61a6fcccSHuacai Chen static int __init debugfs_unaligned(void)
484*61a6fcccSHuacai Chen {
485*61a6fcccSHuacai Chen 	struct dentry *d;
486*61a6fcccSHuacai Chen 
487*61a6fcccSHuacai Chen 	d = debugfs_create_dir("loongarch", NULL);
488*61a6fcccSHuacai Chen 
489*61a6fcccSHuacai Chen 	debugfs_create_u32("unaligned_instructions_user",
490*61a6fcccSHuacai Chen 				S_IRUGO, d, &unaligned_instructions_user);
491*61a6fcccSHuacai Chen 	debugfs_create_u32("unaligned_instructions_kernel",
492*61a6fcccSHuacai Chen 				S_IRUGO, d, &unaligned_instructions_kernel);
493*61a6fcccSHuacai Chen 
494*61a6fcccSHuacai Chen 	return 0;
495*61a6fcccSHuacai Chen }
496*61a6fcccSHuacai Chen arch_initcall(debugfs_unaligned);
497*61a6fcccSHuacai Chen #endif
498