1/* SPDX-License-Identifier: GPL-2.0-or-later */
2#ifndef _ASM_MIPS_UNALIGNED_EMUL_H
3#define _ASM_MIPS_UNALIGNED_EMUL_H
4
5#include <asm/asm.h>
6
7#ifdef __BIG_ENDIAN
8#define  _LoadHW(addr, value, res, type)  \
9do {                                                \
10	__asm__ __volatile__ (".set\tnoat\n"        \
11		"1:\t"type##_lb("%0", "0(%2)")"\n"  \
12		"2:\t"type##_lbu("$1", "1(%2)")"\n\t"\
13		"sll\t%0, 0x8\n\t"                  \
14		"or\t%0, $1\n\t"                    \
15		"li\t%1, 0\n"                       \
16		"3:\t.set\tat\n\t"                  \
17		".insn\n\t"                         \
18		".section\t.fixup,\"ax\"\n\t"       \
19		"4:\tli\t%1, %3\n\t"                \
20		"j\t3b\n\t"                         \
21		".previous\n\t"                     \
22		".section\t__ex_table,\"a\"\n\t"    \
23		STR(PTR_WD)"\t1b, 4b\n\t"           \
24		STR(PTR_WD)"\t2b, 4b\n\t"           \
25		".previous"                         \
26		: "=&r" (value), "=r" (res)         \
27		: "r" (addr), "i" (-EFAULT));       \
28} while (0)
29
30#ifndef CONFIG_CPU_NO_LOAD_STORE_LR
31#define  _LoadW(addr, value, res, type)   \
32do {                                                \
33	__asm__ __volatile__ (                      \
34		"1:\t"type##_lwl("%0", "(%2)")"\n"   \
35		"2:\t"type##_lwr("%0", "3(%2)")"\n\t"\
36		"li\t%1, 0\n"                       \
37		"3:\n\t"                            \
38		".insn\n\t"                         \
39		".section\t.fixup,\"ax\"\n\t"       \
40		"4:\tli\t%1, %3\n\t"                \
41		"j\t3b\n\t"                         \
42		".previous\n\t"                     \
43		".section\t__ex_table,\"a\"\n\t"    \
44		STR(PTR_WD)"\t1b, 4b\n\t"           \
45		STR(PTR_WD)"\t2b, 4b\n\t"           \
46		".previous"                         \
47		: "=&r" (value), "=r" (res)         \
48		: "r" (addr), "i" (-EFAULT));       \
49} while (0)
50
51#else /* CONFIG_CPU_NO_LOAD_STORE_LR */
52/* For CPUs without lwl instruction */
53#define  _LoadW(addr, value, res, type) \
54do {                                                \
55	__asm__ __volatile__ (			    \
56		".set\tpush\n"			    \
57		".set\tnoat\n\t"		    \
58		"1:"type##_lb("%0", "0(%2)")"\n\t"  \
59		"2:"type##_lbu("$1", "1(%2)")"\n\t" \
60		"sll\t%0, 0x8\n\t"		    \
61		"or\t%0, $1\n\t"		    \
62		"3:"type##_lbu("$1", "2(%2)")"\n\t" \
63		"sll\t%0, 0x8\n\t"		    \
64		"or\t%0, $1\n\t"		    \
65		"4:"type##_lbu("$1", "3(%2)")"\n\t" \
66		"sll\t%0, 0x8\n\t"		    \
67		"or\t%0, $1\n\t"		    \
68		"li\t%1, 0\n"			    \
69		".set\tpop\n"			    \
70		"10:\n\t"			    \
71		".insn\n\t"			    \
72		".section\t.fixup,\"ax\"\n\t"	    \
73		"11:\tli\t%1, %3\n\t"		    \
74		"j\t10b\n\t"			    \
75		".previous\n\t"			    \
76		".section\t__ex_table,\"a\"\n\t"    \
77		STR(PTR_WD)"\t1b, 11b\n\t"	    \
78		STR(PTR_WD)"\t2b, 11b\n\t"	    \
79		STR(PTR_WD)"\t3b, 11b\n\t"	    \
80		STR(PTR_WD)"\t4b, 11b\n\t"	    \
81		".previous"			    \
82		: "=&r" (value), "=r" (res)	    \
83		: "r" (addr), "i" (-EFAULT));       \
84} while (0)
85
86#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */
87
88#define  _LoadHWU(addr, value, res, type) \
89do {                                                \
90	__asm__ __volatile__ (                      \
91		".set\tnoat\n"                      \
92		"1:\t"type##_lbu("%0", "0(%2)")"\n" \
93		"2:\t"type##_lbu("$1", "1(%2)")"\n\t"\
94		"sll\t%0, 0x8\n\t"                  \
95		"or\t%0, $1\n\t"                    \
96		"li\t%1, 0\n"                       \
97		"3:\n\t"                            \
98		".insn\n\t"                         \
99		".set\tat\n\t"                      \
100		".section\t.fixup,\"ax\"\n\t"       \
101		"4:\tli\t%1, %3\n\t"                \
102		"j\t3b\n\t"                         \
103		".previous\n\t"                     \
104		".section\t__ex_table,\"a\"\n\t"    \
105		STR(PTR_WD)"\t1b, 4b\n\t"           \
106		STR(PTR_WD)"\t2b, 4b\n\t"           \
107		".previous"                         \
108		: "=&r" (value), "=r" (res)         \
109		: "r" (addr), "i" (-EFAULT));       \
110} while (0)
111
112#ifndef CONFIG_CPU_NO_LOAD_STORE_LR
113#define  _LoadWU(addr, value, res, type)  \
114do {                                                \
115	__asm__ __volatile__ (                      \
116		"1:\t"type##_lwl("%0", "(%2)")"\n"  \
117		"2:\t"type##_lwr("%0", "3(%2)")"\n\t"\
118		"dsll\t%0, %0, 32\n\t"              \
119		"dsrl\t%0, %0, 32\n\t"              \
120		"li\t%1, 0\n"                       \
121		"3:\n\t"                            \
122		".insn\n\t"                         \
123		"\t.section\t.fixup,\"ax\"\n\t"     \
124		"4:\tli\t%1, %3\n\t"                \
125		"j\t3b\n\t"                         \
126		".previous\n\t"                     \
127		".section\t__ex_table,\"a\"\n\t"    \
128		STR(PTR_WD)"\t1b, 4b\n\t"           \
129		STR(PTR_WD)"\t2b, 4b\n\t"           \
130		".previous"                         \
131		: "=&r" (value), "=r" (res)         \
132		: "r" (addr), "i" (-EFAULT));       \
133} while (0)
134
135#define  _LoadDW(addr, value, res)  \
136do {                                                \
137	__asm__ __volatile__ (                      \
138		"1:\tldl\t%0, (%2)\n"               \
139		"2:\tldr\t%0, 7(%2)\n\t"            \
140		"li\t%1, 0\n"                       \
141		"3:\n\t"                            \
142		".insn\n\t"                         \
143		"\t.section\t.fixup,\"ax\"\n\t"     \
144		"4:\tli\t%1, %3\n\t"                \
145		"j\t3b\n\t"                         \
146		".previous\n\t"                     \
147		".section\t__ex_table,\"a\"\n\t"    \
148		STR(PTR_WD)"\t1b, 4b\n\t"           \
149		STR(PTR_WD)"\t2b, 4b\n\t"           \
150		".previous"                         \
151		: "=&r" (value), "=r" (res)         \
152		: "r" (addr), "i" (-EFAULT));       \
153} while (0)
154
155#else /* CONFIG_CPU_NO_LOAD_STORE_LR */
156/* For CPUs without lwl and ldl instructions */
157#define  _LoadWU(addr, value, res, type) \
158do {                                                \
159	__asm__ __volatile__ (			    \
160		".set\tpush\n\t"		    \
161		".set\tnoat\n\t"		    \
162		"1:"type##_lbu("%0", "0(%2)")"\n\t" \
163		"2:"type##_lbu("$1", "1(%2)")"\n\t" \
164		"sll\t%0, 0x8\n\t"		    \
165		"or\t%0, $1\n\t"		    \
166		"3:"type##_lbu("$1", "2(%2)")"\n\t" \
167		"sll\t%0, 0x8\n\t"		    \
168		"or\t%0, $1\n\t"		    \
169		"4:"type##_lbu("$1", "3(%2)")"\n\t" \
170		"sll\t%0, 0x8\n\t"		    \
171		"or\t%0, $1\n\t"		    \
172		"li\t%1, 0\n"			    \
173		".set\tpop\n"			    \
174		"10:\n\t"			    \
175		".insn\n\t"			    \
176		".section\t.fixup,\"ax\"\n\t"	    \
177		"11:\tli\t%1, %3\n\t"		    \
178		"j\t10b\n\t"			    \
179		".previous\n\t"			    \
180		".section\t__ex_table,\"a\"\n\t"    \
181		STR(PTR_WD)"\t1b, 11b\n\t"	    \
182		STR(PTR_WD)"\t2b, 11b\n\t"	    \
183		STR(PTR_WD)"\t3b, 11b\n\t"	    \
184		STR(PTR_WD)"\t4b, 11b\n\t"	    \
185		".previous"			    \
186		: "=&r" (value), "=r" (res)	    \
187		: "r" (addr), "i" (-EFAULT));       \
188} while (0)
189
190#define  _LoadDW(addr, value, res)  \
191do {                                                \
192	__asm__ __volatile__ (			    \
193		".set\tpush\n\t"		    \
194		".set\tnoat\n\t"		    \
195		"1:lb\t%0, 0(%2)\n\t"		    \
196		"2:lbu\t $1, 1(%2)\n\t"		    \
197		"dsll\t%0, 0x8\n\t"		    \
198		"or\t%0, $1\n\t"		    \
199		"3:lbu\t$1, 2(%2)\n\t"		    \
200		"dsll\t%0, 0x8\n\t"		    \
201		"or\t%0, $1\n\t"		    \
202		"4:lbu\t$1, 3(%2)\n\t"		    \
203		"dsll\t%0, 0x8\n\t"		    \
204		"or\t%0, $1\n\t"		    \
205		"5:lbu\t$1, 4(%2)\n\t"		    \
206		"dsll\t%0, 0x8\n\t"		    \
207		"or\t%0, $1\n\t"		    \
208		"6:lbu\t$1, 5(%2)\n\t"		    \
209		"dsll\t%0, 0x8\n\t"		    \
210		"or\t%0, $1\n\t"		    \
211		"7:lbu\t$1, 6(%2)\n\t"		    \
212		"dsll\t%0, 0x8\n\t"		    \
213		"or\t%0, $1\n\t"		    \
214		"8:lbu\t$1, 7(%2)\n\t"		    \
215		"dsll\t%0, 0x8\n\t"		    \
216		"or\t%0, $1\n\t"		    \
217		"li\t%1, 0\n"			    \
218		".set\tpop\n\t"			    \
219		"10:\n\t"			    \
220		".insn\n\t"			    \
221		".section\t.fixup,\"ax\"\n\t"	    \
222		"11:\tli\t%1, %3\n\t"		    \
223		"j\t10b\n\t"			    \
224		".previous\n\t"			    \
225		".section\t__ex_table,\"a\"\n\t"    \
226		STR(PTR_WD)"\t1b, 11b\n\t"	    \
227		STR(PTR_WD)"\t2b, 11b\n\t"	    \
228		STR(PTR_WD)"\t3b, 11b\n\t"	    \
229		STR(PTR_WD)"\t4b, 11b\n\t"	    \
230		STR(PTR_WD)"\t5b, 11b\n\t"	    \
231		STR(PTR_WD)"\t6b, 11b\n\t"	    \
232		STR(PTR_WD)"\t7b, 11b\n\t"	    \
233		STR(PTR_WD)"\t8b, 11b\n\t"	    \
234		".previous"			    \
235		: "=&r" (value), "=r" (res)	    \
236		: "r" (addr), "i" (-EFAULT));       \
237} while (0)
238
239#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */
240
241
242#define  _StoreHW(addr, value, res, type) \
243do {                                                \
244	__asm__ __volatile__ (                      \
245		".set\tnoat\n"                      \
246		"1:\t"type##_sb("%1", "1(%2)")"\n"  \
247		"srl\t$1, %1, 0x8\n"                \
248		"2:\t"type##_sb("$1", "0(%2)")"\n"  \
249		".set\tat\n\t"                      \
250		"li\t%0, 0\n"                       \
251		"3:\n\t"                            \
252		".insn\n\t"                         \
253		".section\t.fixup,\"ax\"\n\t"       \
254		"4:\tli\t%0, %3\n\t"                \
255		"j\t3b\n\t"                         \
256		".previous\n\t"                     \
257		".section\t__ex_table,\"a\"\n\t"    \
258		STR(PTR_WD)"\t1b, 4b\n\t"           \
259		STR(PTR_WD)"\t2b, 4b\n\t"           \
260		".previous"                         \
261		: "=r" (res)                        \
262		: "r" (value), "r" (addr), "i" (-EFAULT));\
263} while (0)
264
265#ifndef CONFIG_CPU_NO_LOAD_STORE_LR
266#define  _StoreW(addr, value, res, type)  \
267do {                                                \
268	__asm__ __volatile__ (                      \
269		"1:\t"type##_swl("%1", "(%2)")"\n"  \
270		"2:\t"type##_swr("%1", "3(%2)")"\n\t"\
271		"li\t%0, 0\n"                       \
272		"3:\n\t"                            \
273		".insn\n\t"                         \
274		".section\t.fixup,\"ax\"\n\t"       \
275		"4:\tli\t%0, %3\n\t"                \
276		"j\t3b\n\t"                         \
277		".previous\n\t"                     \
278		".section\t__ex_table,\"a\"\n\t"    \
279		STR(PTR_WD)"\t1b, 4b\n\t"           \
280		STR(PTR_WD)"\t2b, 4b\n\t"           \
281		".previous"                         \
282		: "=r" (res)                                \
283		: "r" (value), "r" (addr), "i" (-EFAULT));  \
284} while (0)
285
286#define  _StoreDW(addr, value, res) \
287do {                                                \
288	__asm__ __volatile__ (                      \
289		"1:\tsdl\t%1,(%2)\n"                \
290		"2:\tsdr\t%1, 7(%2)\n\t"            \
291		"li\t%0, 0\n"                       \
292		"3:\n\t"                            \
293		".insn\n\t"                         \
294		".section\t.fixup,\"ax\"\n\t"       \
295		"4:\tli\t%0, %3\n\t"                \
296		"j\t3b\n\t"                         \
297		".previous\n\t"                     \
298		".section\t__ex_table,\"a\"\n\t"    \
299		STR(PTR_WD)"\t1b, 4b\n\t"           \
300		STR(PTR_WD)"\t2b, 4b\n\t"           \
301		".previous"                         \
302		: "=r" (res)                                \
303		: "r" (value), "r" (addr), "i" (-EFAULT));  \
304} while (0)
305
306#else /* CONFIG_CPU_NO_LOAD_STORE_LR */
307#define  _StoreW(addr, value, res, type)  \
308do {                                                \
309	__asm__ __volatile__ (                      \
310		".set\tpush\n\t"		    \
311		".set\tnoat\n\t"		    \
312		"1:"type##_sb("%1", "3(%2)")"\n\t"  \
313		"srl\t$1, %1, 0x8\n\t"		    \
314		"2:"type##_sb("$1", "2(%2)")"\n\t"  \
315		"srl\t$1, $1,  0x8\n\t"		    \
316		"3:"type##_sb("$1", "1(%2)")"\n\t"  \
317		"srl\t$1, $1, 0x8\n\t"		    \
318		"4:"type##_sb("$1", "0(%2)")"\n\t"  \
319		".set\tpop\n\t"			    \
320		"li\t%0, 0\n"			    \
321		"10:\n\t"			    \
322		".insn\n\t"			    \
323		".section\t.fixup,\"ax\"\n\t"	    \
324		"11:\tli\t%0, %3\n\t"		    \
325		"j\t10b\n\t"			    \
326		".previous\n\t"			    \
327		".section\t__ex_table,\"a\"\n\t"    \
328		STR(PTR_WD)"\t1b, 11b\n\t"	    \
329		STR(PTR_WD)"\t2b, 11b\n\t"	    \
330		STR(PTR_WD)"\t3b, 11b\n\t"	    \
331		STR(PTR_WD)"\t4b, 11b\n\t"	    \
332		".previous"			    \
333		: "=&r" (res)				    \
334		: "r" (value), "r" (addr), "i" (-EFAULT)    \
335		: "memory");                                \
336} while (0)
337
338#define  _StoreDW(addr, value, res) \
339do {                                                \
340	__asm__ __volatile__ (                      \
341		".set\tpush\n\t"		    \
342		".set\tnoat\n\t"		    \
343		"1:sb\t%1, 7(%2)\n\t"		    \
344		"dsrl\t$1, %1, 0x8\n\t"		    \
345		"2:sb\t$1, 6(%2)\n\t"		    \
346		"dsrl\t$1, $1, 0x8\n\t"		    \
347		"3:sb\t$1, 5(%2)\n\t"		    \
348		"dsrl\t$1, $1, 0x8\n\t"		    \
349		"4:sb\t$1, 4(%2)\n\t"		    \
350		"dsrl\t$1, $1, 0x8\n\t"		    \
351		"5:sb\t$1, 3(%2)\n\t"		    \
352		"dsrl\t$1, $1, 0x8\n\t"		    \
353		"6:sb\t$1, 2(%2)\n\t"		    \
354		"dsrl\t$1, $1, 0x8\n\t"		    \
355		"7:sb\t$1, 1(%2)\n\t"		    \
356		"dsrl\t$1, $1, 0x8\n\t"		    \
357		"8:sb\t$1, 0(%2)\n\t"		    \
358		"dsrl\t$1, $1, 0x8\n\t"		    \
359		".set\tpop\n\t"			    \
360		"li\t%0, 0\n"			    \
361		"10:\n\t"			    \
362		".insn\n\t"			    \
363		".section\t.fixup,\"ax\"\n\t"	    \
364		"11:\tli\t%0, %3\n\t"		    \
365		"j\t10b\n\t"			    \
366		".previous\n\t"			    \
367		".section\t__ex_table,\"a\"\n\t"    \
368		STR(PTR_WD)"\t1b, 11b\n\t"	    \
369		STR(PTR_WD)"\t2b, 11b\n\t"	    \
370		STR(PTR_WD)"\t3b, 11b\n\t"	    \
371		STR(PTR_WD)"\t4b, 11b\n\t"	    \
372		STR(PTR_WD)"\t5b, 11b\n\t"	    \
373		STR(PTR_WD)"\t6b, 11b\n\t"	    \
374		STR(PTR_WD)"\t7b, 11b\n\t"	    \
375		STR(PTR_WD)"\t8b, 11b\n\t"	    \
376		".previous"			    \
377		: "=&r" (res)				    \
378		: "r" (value), "r" (addr), "i" (-EFAULT)    \
379		: "memory");                                \
380} while (0)
381
382#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */
383
384#else /* __BIG_ENDIAN */
385
386#define  _LoadHW(addr, value, res, type)  \
387do {                                                \
388	__asm__ __volatile__ (".set\tnoat\n"        \
389		"1:\t"type##_lb("%0", "1(%2)")"\n"  \
390		"2:\t"type##_lbu("$1", "0(%2)")"\n\t"\
391		"sll\t%0, 0x8\n\t"                  \
392		"or\t%0, $1\n\t"                    \
393		"li\t%1, 0\n"                       \
394		"3:\t.set\tat\n\t"                  \
395		".insn\n\t"                         \
396		".section\t.fixup,\"ax\"\n\t"       \
397		"4:\tli\t%1, %3\n\t"                \
398		"j\t3b\n\t"                         \
399		".previous\n\t"                     \
400		".section\t__ex_table,\"a\"\n\t"    \
401		STR(PTR_WD)"\t1b, 4b\n\t"           \
402		STR(PTR_WD)"\t2b, 4b\n\t"           \
403		".previous"                         \
404		: "=&r" (value), "=r" (res)         \
405		: "r" (addr), "i" (-EFAULT));       \
406} while (0)
407
408#ifndef CONFIG_CPU_NO_LOAD_STORE_LR
409#define  _LoadW(addr, value, res, type)   \
410do {                                                \
411	__asm__ __volatile__ (                      \
412		"1:\t"type##_lwl("%0", "3(%2)")"\n" \
413		"2:\t"type##_lwr("%0", "(%2)")"\n\t"\
414		"li\t%1, 0\n"                       \
415		"3:\n\t"                            \
416		".insn\n\t"                         \
417		".section\t.fixup,\"ax\"\n\t"       \
418		"4:\tli\t%1, %3\n\t"                \
419		"j\t3b\n\t"                         \
420		".previous\n\t"                     \
421		".section\t__ex_table,\"a\"\n\t"    \
422		STR(PTR_WD)"\t1b, 4b\n\t"           \
423		STR(PTR_WD)"\t2b, 4b\n\t"           \
424		".previous"                         \
425		: "=&r" (value), "=r" (res)         \
426		: "r" (addr), "i" (-EFAULT));       \
427} while (0)
428
429#else /* CONFIG_CPU_NO_LOAD_STORE_LR */
430/* For CPUs without lwl instruction */
431#define  _LoadW(addr, value, res, type) \
432do {                                                \
433	__asm__ __volatile__ (			    \
434		".set\tpush\n"			    \
435		".set\tnoat\n\t"		    \
436		"1:"type##_lb("%0", "3(%2)")"\n\t"  \
437		"2:"type##_lbu("$1", "2(%2)")"\n\t" \
438		"sll\t%0, 0x8\n\t"		    \
439		"or\t%0, $1\n\t"		    \
440		"3:"type##_lbu("$1", "1(%2)")"\n\t" \
441		"sll\t%0, 0x8\n\t"		    \
442		"or\t%0, $1\n\t"		    \
443		"4:"type##_lbu("$1", "0(%2)")"\n\t" \
444		"sll\t%0, 0x8\n\t"		    \
445		"or\t%0, $1\n\t"		    \
446		"li\t%1, 0\n"			    \
447		".set\tpop\n"			    \
448		"10:\n\t"			    \
449		".insn\n\t"			    \
450		".section\t.fixup,\"ax\"\n\t"	    \
451		"11:\tli\t%1, %3\n\t"		    \
452		"j\t10b\n\t"			    \
453		".previous\n\t"			    \
454		".section\t__ex_table,\"a\"\n\t"    \
455		STR(PTR_WD)"\t1b, 11b\n\t"	    \
456		STR(PTR_WD)"\t2b, 11b\n\t"	    \
457		STR(PTR_WD)"\t3b, 11b\n\t"	    \
458		STR(PTR_WD)"\t4b, 11b\n\t"	    \
459		".previous"			    \
460		: "=&r" (value), "=r" (res)	    \
461		: "r" (addr), "i" (-EFAULT));       \
462} while (0)
463
464#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */
465
466
467#define  _LoadHWU(addr, value, res, type) \
468do {                                                \
469	__asm__ __volatile__ (                      \
470		".set\tnoat\n"                      \
471		"1:\t"type##_lbu("%0", "1(%2)")"\n" \
472		"2:\t"type##_lbu("$1", "0(%2)")"\n\t"\
473		"sll\t%0, 0x8\n\t"                  \
474		"or\t%0, $1\n\t"                    \
475		"li\t%1, 0\n"                       \
476		"3:\n\t"                            \
477		".insn\n\t"                         \
478		".set\tat\n\t"                      \
479		".section\t.fixup,\"ax\"\n\t"       \
480		"4:\tli\t%1, %3\n\t"                \
481		"j\t3b\n\t"                         \
482		".previous\n\t"                     \
483		".section\t__ex_table,\"a\"\n\t"    \
484		STR(PTR_WD)"\t1b, 4b\n\t"           \
485		STR(PTR_WD)"\t2b, 4b\n\t"           \
486		".previous"                         \
487		: "=&r" (value), "=r" (res)         \
488		: "r" (addr), "i" (-EFAULT));       \
489} while (0)
490
491#ifndef CONFIG_CPU_NO_LOAD_STORE_LR
492#define  _LoadWU(addr, value, res, type)  \
493do {                                                \
494	__asm__ __volatile__ (                      \
495		"1:\t"type##_lwl("%0", "3(%2)")"\n" \
496		"2:\t"type##_lwr("%0", "(%2)")"\n\t"\
497		"dsll\t%0, %0, 32\n\t"              \
498		"dsrl\t%0, %0, 32\n\t"              \
499		"li\t%1, 0\n"                       \
500		"3:\n\t"                            \
501		".insn\n\t"                         \
502		"\t.section\t.fixup,\"ax\"\n\t"     \
503		"4:\tli\t%1, %3\n\t"                \
504		"j\t3b\n\t"                         \
505		".previous\n\t"                     \
506		".section\t__ex_table,\"a\"\n\t"    \
507		STR(PTR_WD)"\t1b, 4b\n\t"           \
508		STR(PTR_WD)"\t2b, 4b\n\t"           \
509		".previous"                         \
510		: "=&r" (value), "=r" (res)         \
511		: "r" (addr), "i" (-EFAULT));       \
512} while (0)
513
514#define  _LoadDW(addr, value, res)  \
515do {                                                \
516	__asm__ __volatile__ (                      \
517		"1:\tldl\t%0, 7(%2)\n"              \
518		"2:\tldr\t%0, (%2)\n\t"             \
519		"li\t%1, 0\n"                       \
520		"3:\n\t"                            \
521		".insn\n\t"                         \
522		"\t.section\t.fixup,\"ax\"\n\t"     \
523		"4:\tli\t%1, %3\n\t"                \
524		"j\t3b\n\t"                         \
525		".previous\n\t"                     \
526		".section\t__ex_table,\"a\"\n\t"    \
527		STR(PTR_WD)"\t1b, 4b\n\t"           \
528		STR(PTR_WD)"\t2b, 4b\n\t"           \
529		".previous"                         \
530		: "=&r" (value), "=r" (res)         \
531		: "r" (addr), "i" (-EFAULT));       \
532} while (0)
533
534#else /* CONFIG_CPU_NO_LOAD_STORE_LR */
535/* For CPUs without lwl and ldl instructions */
536#define  _LoadWU(addr, value, res, type) \
537do {                                                \
538	__asm__ __volatile__ (			    \
539		".set\tpush\n\t"		    \
540		".set\tnoat\n\t"		    \
541		"1:"type##_lbu("%0", "3(%2)")"\n\t" \
542		"2:"type##_lbu("$1", "2(%2)")"\n\t" \
543		"sll\t%0, 0x8\n\t"		    \
544		"or\t%0, $1\n\t"		    \
545		"3:"type##_lbu("$1", "1(%2)")"\n\t" \
546		"sll\t%0, 0x8\n\t"		    \
547		"or\t%0, $1\n\t"		    \
548		"4:"type##_lbu("$1", "0(%2)")"\n\t" \
549		"sll\t%0, 0x8\n\t"		    \
550		"or\t%0, $1\n\t"		    \
551		"li\t%1, 0\n"			    \
552		".set\tpop\n"			    \
553		"10:\n\t"			    \
554		".insn\n\t"			    \
555		".section\t.fixup,\"ax\"\n\t"	    \
556		"11:\tli\t%1, %3\n\t"		    \
557		"j\t10b\n\t"			    \
558		".previous\n\t"			    \
559		".section\t__ex_table,\"a\"\n\t"    \
560		STR(PTR_WD)"\t1b, 11b\n\t"	    \
561		STR(PTR_WD)"\t2b, 11b\n\t"	    \
562		STR(PTR_WD)"\t3b, 11b\n\t"	    \
563		STR(PTR_WD)"\t4b, 11b\n\t"	    \
564		".previous"			    \
565		: "=&r" (value), "=r" (res)	    \
566		: "r" (addr), "i" (-EFAULT));       \
567} while (0)
568
569#define  _LoadDW(addr, value, res)  \
570do {                                                \
571	__asm__ __volatile__ (			    \
572		".set\tpush\n\t"		    \
573		".set\tnoat\n\t"		    \
574		"1:lb\t%0, 7(%2)\n\t"		    \
575		"2:lbu\t$1, 6(%2)\n\t"		    \
576		"dsll\t%0, 0x8\n\t"		    \
577		"or\t%0, $1\n\t"		    \
578		"3:lbu\t$1, 5(%2)\n\t"		    \
579		"dsll\t%0, 0x8\n\t"		    \
580		"or\t%0, $1\n\t"		    \
581		"4:lbu\t$1, 4(%2)\n\t"		    \
582		"dsll\t%0, 0x8\n\t"		    \
583		"or\t%0, $1\n\t"		    \
584		"5:lbu\t$1, 3(%2)\n\t"		    \
585		"dsll\t%0, 0x8\n\t"		    \
586		"or\t%0, $1\n\t"		    \
587		"6:lbu\t$1, 2(%2)\n\t"		    \
588		"dsll\t%0, 0x8\n\t"		    \
589		"or\t%0, $1\n\t"		    \
590		"7:lbu\t$1, 1(%2)\n\t"		    \
591		"dsll\t%0, 0x8\n\t"		    \
592		"or\t%0, $1\n\t"		    \
593		"8:lbu\t$1, 0(%2)\n\t"		    \
594		"dsll\t%0, 0x8\n\t"		    \
595		"or\t%0, $1\n\t"		    \
596		"li\t%1, 0\n"			    \
597		".set\tpop\n\t"			    \
598		"10:\n\t"			    \
599		".insn\n\t"			    \
600		".section\t.fixup,\"ax\"\n\t"	    \
601		"11:\tli\t%1, %3\n\t"		    \
602		"j\t10b\n\t"			    \
603		".previous\n\t"			    \
604		".section\t__ex_table,\"a\"\n\t"    \
605		STR(PTR_WD)"\t1b, 11b\n\t"	    \
606		STR(PTR_WD)"\t2b, 11b\n\t"	    \
607		STR(PTR_WD)"\t3b, 11b\n\t"	    \
608		STR(PTR_WD)"\t4b, 11b\n\t"	    \
609		STR(PTR_WD)"\t5b, 11b\n\t"	    \
610		STR(PTR_WD)"\t6b, 11b\n\t"	    \
611		STR(PTR_WD)"\t7b, 11b\n\t"	    \
612		STR(PTR_WD)"\t8b, 11b\n\t"	    \
613		".previous"			    \
614		: "=&r" (value), "=r" (res)	    \
615		: "r" (addr), "i" (-EFAULT));       \
616} while (0)
617#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */
618
619#define  _StoreHW(addr, value, res, type) \
620do {                                                 \
621	__asm__ __volatile__ (                      \
622		".set\tnoat\n"                      \
623		"1:\t"type##_sb("%1", "0(%2)")"\n"  \
624		"srl\t$1,%1, 0x8\n"                 \
625		"2:\t"type##_sb("$1", "1(%2)")"\n"  \
626		".set\tat\n\t"                      \
627		"li\t%0, 0\n"                       \
628		"3:\n\t"                            \
629		".insn\n\t"                         \
630		".section\t.fixup,\"ax\"\n\t"       \
631		"4:\tli\t%0, %3\n\t"                \
632		"j\t3b\n\t"                         \
633		".previous\n\t"                     \
634		".section\t__ex_table,\"a\"\n\t"    \
635		STR(PTR_WD)"\t1b, 4b\n\t"           \
636		STR(PTR_WD)"\t2b, 4b\n\t"           \
637		".previous"                         \
638		: "=r" (res)                        \
639		: "r" (value), "r" (addr), "i" (-EFAULT));\
640} while (0)
641
642#ifndef CONFIG_CPU_NO_LOAD_STORE_LR
643#define  _StoreW(addr, value, res, type)  \
644do {                                                \
645	__asm__ __volatile__ (                      \
646		"1:\t"type##_swl("%1", "3(%2)")"\n" \
647		"2:\t"type##_swr("%1", "(%2)")"\n\t"\
648		"li\t%0, 0\n"                       \
649		"3:\n\t"                            \
650		".insn\n\t"                         \
651		".section\t.fixup,\"ax\"\n\t"       \
652		"4:\tli\t%0, %3\n\t"                \
653		"j\t3b\n\t"                         \
654		".previous\n\t"                     \
655		".section\t__ex_table,\"a\"\n\t"    \
656		STR(PTR_WD)"\t1b, 4b\n\t"           \
657		STR(PTR_WD)"\t2b, 4b\n\t"           \
658		".previous"                         \
659		: "=r" (res)                                \
660		: "r" (value), "r" (addr), "i" (-EFAULT));  \
661} while (0)
662
663#define  _StoreDW(addr, value, res) \
664do {                                                \
665	__asm__ __volatile__ (                      \
666		"1:\tsdl\t%1, 7(%2)\n"              \
667		"2:\tsdr\t%1, (%2)\n\t"             \
668		"li\t%0, 0\n"                       \
669		"3:\n\t"                            \
670		".insn\n\t"                         \
671		".section\t.fixup,\"ax\"\n\t"       \
672		"4:\tli\t%0, %3\n\t"                \
673		"j\t3b\n\t"                         \
674		".previous\n\t"                     \
675		".section\t__ex_table,\"a\"\n\t"    \
676		STR(PTR_WD)"\t1b, 4b\n\t"           \
677		STR(PTR_WD)"\t2b, 4b\n\t"           \
678		".previous"                         \
679		: "=r" (res)                                \
680		: "r" (value), "r" (addr), "i" (-EFAULT));  \
681} while (0)
682
683#else /* CONFIG_CPU_NO_LOAD_STORE_LR */
684/* For CPUs without swl and sdl instructions */
685#define  _StoreW(addr, value, res, type)  \
686do {                                                \
687	__asm__ __volatile__ (                      \
688		".set\tpush\n\t"		    \
689		".set\tnoat\n\t"		    \
690		"1:"type##_sb("%1", "0(%2)")"\n\t"  \
691		"srl\t$1, %1, 0x8\n\t"		    \
692		"2:"type##_sb("$1", "1(%2)")"\n\t"  \
693		"srl\t$1, $1,  0x8\n\t"		    \
694		"3:"type##_sb("$1", "2(%2)")"\n\t"  \
695		"srl\t$1, $1, 0x8\n\t"		    \
696		"4:"type##_sb("$1", "3(%2)")"\n\t"  \
697		".set\tpop\n\t"			    \
698		"li\t%0, 0\n"			    \
699		"10:\n\t"			    \
700		".insn\n\t"			    \
701		".section\t.fixup,\"ax\"\n\t"	    \
702		"11:\tli\t%0, %3\n\t"		    \
703		"j\t10b\n\t"			    \
704		".previous\n\t"			    \
705		".section\t__ex_table,\"a\"\n\t"    \
706		STR(PTR_WD)"\t1b, 11b\n\t"	    \
707		STR(PTR_WD)"\t2b, 11b\n\t"	    \
708		STR(PTR_WD)"\t3b, 11b\n\t"	    \
709		STR(PTR_WD)"\t4b, 11b\n\t"	    \
710		".previous"			    \
711		: "=&r" (res)				    \
712		: "r" (value), "r" (addr), "i" (-EFAULT)    \
713		: "memory");                                \
714} while (0)
715
716#define  _StoreDW(addr, value, res) \
717do {                                                \
718	__asm__ __volatile__ (                      \
719		".set\tpush\n\t"		    \
720		".set\tnoat\n\t"		    \
721		"1:sb\t%1, 0(%2)\n\t"		    \
722		"dsrl\t$1, %1, 0x8\n\t"		    \
723		"2:sb\t$1, 1(%2)\n\t"		    \
724		"dsrl\t$1, $1, 0x8\n\t"		    \
725		"3:sb\t$1, 2(%2)\n\t"		    \
726		"dsrl\t$1, $1, 0x8\n\t"		    \
727		"4:sb\t$1, 3(%2)\n\t"		    \
728		"dsrl\t$1, $1, 0x8\n\t"		    \
729		"5:sb\t$1, 4(%2)\n\t"		    \
730		"dsrl\t$1, $1, 0x8\n\t"		    \
731		"6:sb\t$1, 5(%2)\n\t"		    \
732		"dsrl\t$1, $1, 0x8\n\t"		    \
733		"7:sb\t$1, 6(%2)\n\t"		    \
734		"dsrl\t$1, $1, 0x8\n\t"		    \
735		"8:sb\t$1, 7(%2)\n\t"		    \
736		"dsrl\t$1, $1, 0x8\n\t"		    \
737		".set\tpop\n\t"			    \
738		"li\t%0, 0\n"			    \
739		"10:\n\t"			    \
740		".insn\n\t"			    \
741		".section\t.fixup,\"ax\"\n\t"	    \
742		"11:\tli\t%0, %3\n\t"		    \
743		"j\t10b\n\t"			    \
744		".previous\n\t"			    \
745		".section\t__ex_table,\"a\"\n\t"    \
746		STR(PTR_WD)"\t1b, 11b\n\t"	    \
747		STR(PTR_WD)"\t2b, 11b\n\t"	    \
748		STR(PTR_WD)"\t3b, 11b\n\t"	    \
749		STR(PTR_WD)"\t4b, 11b\n\t"	    \
750		STR(PTR_WD)"\t5b, 11b\n\t"	    \
751		STR(PTR_WD)"\t6b, 11b\n\t"	    \
752		STR(PTR_WD)"\t7b, 11b\n\t"	    \
753		STR(PTR_WD)"\t8b, 11b\n\t"	    \
754		".previous"			    \
755		: "=&r" (res)				    \
756		: "r" (value), "r" (addr), "i" (-EFAULT)    \
757		: "memory");                                \
758} while (0)
759
760#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */
761#endif
762
763#define LoadHWU(addr, value, res)	_LoadHWU(addr, value, res, kernel)
764#define LoadHWUE(addr, value, res)	_LoadHWU(addr, value, res, user)
765#define LoadWU(addr, value, res)	_LoadWU(addr, value, res, kernel)
766#define LoadWUE(addr, value, res)	_LoadWU(addr, value, res, user)
767#define LoadHW(addr, value, res)	_LoadHW(addr, value, res, kernel)
768#define LoadHWE(addr, value, res)	_LoadHW(addr, value, res, user)
769#define LoadW(addr, value, res)		_LoadW(addr, value, res, kernel)
770#define LoadWE(addr, value, res)	_LoadW(addr, value, res, user)
771#define LoadDW(addr, value, res)	_LoadDW(addr, value, res)
772
773#define StoreHW(addr, value, res)	_StoreHW(addr, value, res, kernel)
774#define StoreHWE(addr, value, res)	_StoreHW(addr, value, res, user)
775#define StoreW(addr, value, res)	_StoreW(addr, value, res, kernel)
776#define StoreWE(addr, value, res)	_StoreW(addr, value, res, user)
777#define StoreDW(addr, value, res)	_StoreDW(addr, value, res)
778
779#endif /* _ASM_MIPS_UNALIGNED_EMUL_H */
780