161a6fcccSHuacai Chen // SPDX-License-Identifier: GPL-2.0
261a6fcccSHuacai Chen /*
361a6fcccSHuacai Chen * Handle unaligned accesses by emulation.
461a6fcccSHuacai Chen *
561a6fcccSHuacai Chen * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
661a6fcccSHuacai Chen *
761a6fcccSHuacai Chen * Derived from MIPS:
861a6fcccSHuacai Chen * Copyright (C) 1996, 1998, 1999, 2002 by Ralf Baechle
961a6fcccSHuacai Chen * Copyright (C) 1999 Silicon Graphics, Inc.
1061a6fcccSHuacai Chen * Copyright (C) 2014 Imagination Technologies Ltd.
1161a6fcccSHuacai Chen */
1261a6fcccSHuacai Chen #include <linux/mm.h>
1361a6fcccSHuacai Chen #include <linux/sched.h>
1461a6fcccSHuacai Chen #include <linux/signal.h>
1561a6fcccSHuacai Chen #include <linux/debugfs.h>
1661a6fcccSHuacai Chen #include <linux/perf_event.h>
1761a6fcccSHuacai Chen
1861a6fcccSHuacai Chen #include <asm/asm.h>
1961a6fcccSHuacai Chen #include <asm/branch.h>
2061a6fcccSHuacai Chen #include <asm/fpu.h>
2161a6fcccSHuacai Chen #include <asm/inst.h>
2261a6fcccSHuacai Chen
2361a6fcccSHuacai Chen #include "access-helper.h"
2461a6fcccSHuacai Chen
2561a6fcccSHuacai Chen #ifdef CONFIG_DEBUG_FS
2661a6fcccSHuacai Chen static u32 unaligned_instructions_user;
2761a6fcccSHuacai Chen static u32 unaligned_instructions_kernel;
2861a6fcccSHuacai Chen #endif
2961a6fcccSHuacai Chen
read_fpr(unsigned int idx)3061a6fcccSHuacai Chen static inline unsigned long read_fpr(unsigned int idx)
3161a6fcccSHuacai Chen {
3261a6fcccSHuacai Chen #define READ_FPR(idx, __value) \
3361a6fcccSHuacai Chen __asm__ __volatile__("movfr2gr.d %0, $f"#idx"\n\t" : "=r"(__value));
3461a6fcccSHuacai Chen
3561a6fcccSHuacai Chen unsigned long __value;
3661a6fcccSHuacai Chen
3761a6fcccSHuacai Chen switch (idx) {
3861a6fcccSHuacai Chen case 0:
3961a6fcccSHuacai Chen READ_FPR(0, __value);
4061a6fcccSHuacai Chen break;
4161a6fcccSHuacai Chen case 1:
4261a6fcccSHuacai Chen READ_FPR(1, __value);
4361a6fcccSHuacai Chen break;
4461a6fcccSHuacai Chen case 2:
4561a6fcccSHuacai Chen READ_FPR(2, __value);
4661a6fcccSHuacai Chen break;
4761a6fcccSHuacai Chen case 3:
4861a6fcccSHuacai Chen READ_FPR(3, __value);
4961a6fcccSHuacai Chen break;
5061a6fcccSHuacai Chen case 4:
5161a6fcccSHuacai Chen READ_FPR(4, __value);
5261a6fcccSHuacai Chen break;
5361a6fcccSHuacai Chen case 5:
5461a6fcccSHuacai Chen READ_FPR(5, __value);
5561a6fcccSHuacai Chen break;
5661a6fcccSHuacai Chen case 6:
5761a6fcccSHuacai Chen READ_FPR(6, __value);
5861a6fcccSHuacai Chen break;
5961a6fcccSHuacai Chen case 7:
6061a6fcccSHuacai Chen READ_FPR(7, __value);
6161a6fcccSHuacai Chen break;
6261a6fcccSHuacai Chen case 8:
6361a6fcccSHuacai Chen READ_FPR(8, __value);
6461a6fcccSHuacai Chen break;
6561a6fcccSHuacai Chen case 9:
6661a6fcccSHuacai Chen READ_FPR(9, __value);
6761a6fcccSHuacai Chen break;
6861a6fcccSHuacai Chen case 10:
6961a6fcccSHuacai Chen READ_FPR(10, __value);
7061a6fcccSHuacai Chen break;
7161a6fcccSHuacai Chen case 11:
7261a6fcccSHuacai Chen READ_FPR(11, __value);
7361a6fcccSHuacai Chen break;
7461a6fcccSHuacai Chen case 12:
7561a6fcccSHuacai Chen READ_FPR(12, __value);
7661a6fcccSHuacai Chen break;
7761a6fcccSHuacai Chen case 13:
7861a6fcccSHuacai Chen READ_FPR(13, __value);
7961a6fcccSHuacai Chen break;
8061a6fcccSHuacai Chen case 14:
8161a6fcccSHuacai Chen READ_FPR(14, __value);
8261a6fcccSHuacai Chen break;
8361a6fcccSHuacai Chen case 15:
8461a6fcccSHuacai Chen READ_FPR(15, __value);
8561a6fcccSHuacai Chen break;
8661a6fcccSHuacai Chen case 16:
8761a6fcccSHuacai Chen READ_FPR(16, __value);
8861a6fcccSHuacai Chen break;
8961a6fcccSHuacai Chen case 17:
9061a6fcccSHuacai Chen READ_FPR(17, __value);
9161a6fcccSHuacai Chen break;
9261a6fcccSHuacai Chen case 18:
9361a6fcccSHuacai Chen READ_FPR(18, __value);
9461a6fcccSHuacai Chen break;
9561a6fcccSHuacai Chen case 19:
9661a6fcccSHuacai Chen READ_FPR(19, __value);
9761a6fcccSHuacai Chen break;
9861a6fcccSHuacai Chen case 20:
9961a6fcccSHuacai Chen READ_FPR(20, __value);
10061a6fcccSHuacai Chen break;
10161a6fcccSHuacai Chen case 21:
10261a6fcccSHuacai Chen READ_FPR(21, __value);
10361a6fcccSHuacai Chen break;
10461a6fcccSHuacai Chen case 22:
10561a6fcccSHuacai Chen READ_FPR(22, __value);
10661a6fcccSHuacai Chen break;
10761a6fcccSHuacai Chen case 23:
10861a6fcccSHuacai Chen READ_FPR(23, __value);
10961a6fcccSHuacai Chen break;
11061a6fcccSHuacai Chen case 24:
11161a6fcccSHuacai Chen READ_FPR(24, __value);
11261a6fcccSHuacai Chen break;
11361a6fcccSHuacai Chen case 25:
11461a6fcccSHuacai Chen READ_FPR(25, __value);
11561a6fcccSHuacai Chen break;
11661a6fcccSHuacai Chen case 26:
11761a6fcccSHuacai Chen READ_FPR(26, __value);
11861a6fcccSHuacai Chen break;
11961a6fcccSHuacai Chen case 27:
12061a6fcccSHuacai Chen READ_FPR(27, __value);
12161a6fcccSHuacai Chen break;
12261a6fcccSHuacai Chen case 28:
12361a6fcccSHuacai Chen READ_FPR(28, __value);
12461a6fcccSHuacai Chen break;
12561a6fcccSHuacai Chen case 29:
12661a6fcccSHuacai Chen READ_FPR(29, __value);
12761a6fcccSHuacai Chen break;
12861a6fcccSHuacai Chen case 30:
12961a6fcccSHuacai Chen READ_FPR(30, __value);
13061a6fcccSHuacai Chen break;
13161a6fcccSHuacai Chen case 31:
13261a6fcccSHuacai Chen READ_FPR(31, __value);
13361a6fcccSHuacai Chen break;
13461a6fcccSHuacai Chen default:
13561a6fcccSHuacai Chen panic("unexpected idx '%d'", idx);
13661a6fcccSHuacai Chen }
13761a6fcccSHuacai Chen #undef READ_FPR
13861a6fcccSHuacai Chen return __value;
13961a6fcccSHuacai Chen }
14061a6fcccSHuacai Chen
write_fpr(unsigned int idx,unsigned long value)14161a6fcccSHuacai Chen static inline void write_fpr(unsigned int idx, unsigned long value)
14261a6fcccSHuacai Chen {
14361a6fcccSHuacai Chen #define WRITE_FPR(idx, value) \
14461a6fcccSHuacai Chen __asm__ __volatile__("movgr2fr.d $f"#idx", %0\n\t" :: "r"(value));
14561a6fcccSHuacai Chen
14661a6fcccSHuacai Chen switch (idx) {
14761a6fcccSHuacai Chen case 0:
14861a6fcccSHuacai Chen WRITE_FPR(0, value);
14961a6fcccSHuacai Chen break;
15061a6fcccSHuacai Chen case 1:
15161a6fcccSHuacai Chen WRITE_FPR(1, value);
15261a6fcccSHuacai Chen break;
15361a6fcccSHuacai Chen case 2:
15461a6fcccSHuacai Chen WRITE_FPR(2, value);
15561a6fcccSHuacai Chen break;
15661a6fcccSHuacai Chen case 3:
15761a6fcccSHuacai Chen WRITE_FPR(3, value);
15861a6fcccSHuacai Chen break;
15961a6fcccSHuacai Chen case 4:
16061a6fcccSHuacai Chen WRITE_FPR(4, value);
16161a6fcccSHuacai Chen break;
16261a6fcccSHuacai Chen case 5:
16361a6fcccSHuacai Chen WRITE_FPR(5, value);
16461a6fcccSHuacai Chen break;
16561a6fcccSHuacai Chen case 6:
16661a6fcccSHuacai Chen WRITE_FPR(6, value);
16761a6fcccSHuacai Chen break;
16861a6fcccSHuacai Chen case 7:
16961a6fcccSHuacai Chen WRITE_FPR(7, value);
17061a6fcccSHuacai Chen break;
17161a6fcccSHuacai Chen case 8:
17261a6fcccSHuacai Chen WRITE_FPR(8, value);
17361a6fcccSHuacai Chen break;
17461a6fcccSHuacai Chen case 9:
17561a6fcccSHuacai Chen WRITE_FPR(9, value);
17661a6fcccSHuacai Chen break;
17761a6fcccSHuacai Chen case 10:
17861a6fcccSHuacai Chen WRITE_FPR(10, value);
17961a6fcccSHuacai Chen break;
18061a6fcccSHuacai Chen case 11:
18161a6fcccSHuacai Chen WRITE_FPR(11, value);
18261a6fcccSHuacai Chen break;
18361a6fcccSHuacai Chen case 12:
18461a6fcccSHuacai Chen WRITE_FPR(12, value);
18561a6fcccSHuacai Chen break;
18661a6fcccSHuacai Chen case 13:
18761a6fcccSHuacai Chen WRITE_FPR(13, value);
18861a6fcccSHuacai Chen break;
18961a6fcccSHuacai Chen case 14:
19061a6fcccSHuacai Chen WRITE_FPR(14, value);
19161a6fcccSHuacai Chen break;
19261a6fcccSHuacai Chen case 15:
19361a6fcccSHuacai Chen WRITE_FPR(15, value);
19461a6fcccSHuacai Chen break;
19561a6fcccSHuacai Chen case 16:
19661a6fcccSHuacai Chen WRITE_FPR(16, value);
19761a6fcccSHuacai Chen break;
19861a6fcccSHuacai Chen case 17:
19961a6fcccSHuacai Chen WRITE_FPR(17, value);
20061a6fcccSHuacai Chen break;
20161a6fcccSHuacai Chen case 18:
20261a6fcccSHuacai Chen WRITE_FPR(18, value);
20361a6fcccSHuacai Chen break;
20461a6fcccSHuacai Chen case 19:
20561a6fcccSHuacai Chen WRITE_FPR(19, value);
20661a6fcccSHuacai Chen break;
20761a6fcccSHuacai Chen case 20:
20861a6fcccSHuacai Chen WRITE_FPR(20, value);
20961a6fcccSHuacai Chen break;
21061a6fcccSHuacai Chen case 21:
21161a6fcccSHuacai Chen WRITE_FPR(21, value);
21261a6fcccSHuacai Chen break;
21361a6fcccSHuacai Chen case 22:
21461a6fcccSHuacai Chen WRITE_FPR(22, value);
21561a6fcccSHuacai Chen break;
21661a6fcccSHuacai Chen case 23:
21761a6fcccSHuacai Chen WRITE_FPR(23, value);
21861a6fcccSHuacai Chen break;
21961a6fcccSHuacai Chen case 24:
22061a6fcccSHuacai Chen WRITE_FPR(24, value);
22161a6fcccSHuacai Chen break;
22261a6fcccSHuacai Chen case 25:
22361a6fcccSHuacai Chen WRITE_FPR(25, value);
22461a6fcccSHuacai Chen break;
22561a6fcccSHuacai Chen case 26:
22661a6fcccSHuacai Chen WRITE_FPR(26, value);
22761a6fcccSHuacai Chen break;
22861a6fcccSHuacai Chen case 27:
22961a6fcccSHuacai Chen WRITE_FPR(27, value);
23061a6fcccSHuacai Chen break;
23161a6fcccSHuacai Chen case 28:
23261a6fcccSHuacai Chen WRITE_FPR(28, value);
23361a6fcccSHuacai Chen break;
23461a6fcccSHuacai Chen case 29:
23561a6fcccSHuacai Chen WRITE_FPR(29, value);
23661a6fcccSHuacai Chen break;
23761a6fcccSHuacai Chen case 30:
23861a6fcccSHuacai Chen WRITE_FPR(30, value);
23961a6fcccSHuacai Chen break;
24061a6fcccSHuacai Chen case 31:
24161a6fcccSHuacai Chen WRITE_FPR(31, value);
24261a6fcccSHuacai Chen break;
24361a6fcccSHuacai Chen default:
24461a6fcccSHuacai Chen panic("unexpected idx '%d'", idx);
24561a6fcccSHuacai Chen }
24661a6fcccSHuacai Chen #undef WRITE_FPR
24761a6fcccSHuacai Chen }
24861a6fcccSHuacai Chen
emulate_load_store_insn(struct pt_regs * regs,void __user * addr,unsigned int * pc)24961a6fcccSHuacai Chen void emulate_load_store_insn(struct pt_regs *regs, void __user *addr, unsigned int *pc)
25061a6fcccSHuacai Chen {
25161a6fcccSHuacai Chen bool fp = false;
25261a6fcccSHuacai Chen bool sign, write;
25361a6fcccSHuacai Chen bool user = user_mode(regs);
25461a6fcccSHuacai Chen unsigned int res, size = 0;
25561a6fcccSHuacai Chen unsigned long value = 0;
25661a6fcccSHuacai Chen union loongarch_instruction insn;
25761a6fcccSHuacai Chen
25861a6fcccSHuacai Chen perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0);
25961a6fcccSHuacai Chen
26061a6fcccSHuacai Chen __get_inst(&insn.word, pc, user);
26161a6fcccSHuacai Chen
26261a6fcccSHuacai Chen switch (insn.reg2i12_format.opcode) {
26361a6fcccSHuacai Chen case ldh_op:
26461a6fcccSHuacai Chen size = 2;
26561a6fcccSHuacai Chen sign = true;
26661a6fcccSHuacai Chen write = false;
26761a6fcccSHuacai Chen break;
26861a6fcccSHuacai Chen case ldhu_op:
26961a6fcccSHuacai Chen size = 2;
27061a6fcccSHuacai Chen sign = false;
27161a6fcccSHuacai Chen write = false;
27261a6fcccSHuacai Chen break;
27361a6fcccSHuacai Chen case sth_op:
27461a6fcccSHuacai Chen size = 2;
27561a6fcccSHuacai Chen sign = true;
27661a6fcccSHuacai Chen write = true;
27761a6fcccSHuacai Chen break;
27861a6fcccSHuacai Chen case ldw_op:
27961a6fcccSHuacai Chen size = 4;
28061a6fcccSHuacai Chen sign = true;
28161a6fcccSHuacai Chen write = false;
28261a6fcccSHuacai Chen break;
28361a6fcccSHuacai Chen case ldwu_op:
28461a6fcccSHuacai Chen size = 4;
28561a6fcccSHuacai Chen sign = false;
28661a6fcccSHuacai Chen write = false;
28761a6fcccSHuacai Chen break;
28861a6fcccSHuacai Chen case stw_op:
28961a6fcccSHuacai Chen size = 4;
29061a6fcccSHuacai Chen sign = true;
29161a6fcccSHuacai Chen write = true;
29261a6fcccSHuacai Chen break;
29361a6fcccSHuacai Chen case ldd_op:
29461a6fcccSHuacai Chen size = 8;
29561a6fcccSHuacai Chen sign = true;
29661a6fcccSHuacai Chen write = false;
29761a6fcccSHuacai Chen break;
29861a6fcccSHuacai Chen case std_op:
29961a6fcccSHuacai Chen size = 8;
30061a6fcccSHuacai Chen sign = true;
30161a6fcccSHuacai Chen write = true;
30261a6fcccSHuacai Chen break;
30361a6fcccSHuacai Chen case flds_op:
30461a6fcccSHuacai Chen size = 4;
30561a6fcccSHuacai Chen fp = true;
30661a6fcccSHuacai Chen sign = true;
30761a6fcccSHuacai Chen write = false;
30861a6fcccSHuacai Chen break;
30961a6fcccSHuacai Chen case fsts_op:
31061a6fcccSHuacai Chen size = 4;
31161a6fcccSHuacai Chen fp = true;
31261a6fcccSHuacai Chen sign = true;
31361a6fcccSHuacai Chen write = true;
31461a6fcccSHuacai Chen break;
31561a6fcccSHuacai Chen case fldd_op:
31661a6fcccSHuacai Chen size = 8;
31761a6fcccSHuacai Chen fp = true;
31861a6fcccSHuacai Chen sign = true;
31961a6fcccSHuacai Chen write = false;
32061a6fcccSHuacai Chen break;
32161a6fcccSHuacai Chen case fstd_op:
32261a6fcccSHuacai Chen size = 8;
32361a6fcccSHuacai Chen fp = true;
32461a6fcccSHuacai Chen sign = true;
32561a6fcccSHuacai Chen write = true;
32661a6fcccSHuacai Chen break;
32761a6fcccSHuacai Chen }
32861a6fcccSHuacai Chen
32961a6fcccSHuacai Chen switch (insn.reg2i14_format.opcode) {
33061a6fcccSHuacai Chen case ldptrw_op:
33161a6fcccSHuacai Chen size = 4;
33261a6fcccSHuacai Chen sign = true;
33361a6fcccSHuacai Chen write = false;
33461a6fcccSHuacai Chen break;
33561a6fcccSHuacai Chen case stptrw_op:
33661a6fcccSHuacai Chen size = 4;
33761a6fcccSHuacai Chen sign = true;
33861a6fcccSHuacai Chen write = true;
33961a6fcccSHuacai Chen break;
34061a6fcccSHuacai Chen case ldptrd_op:
34161a6fcccSHuacai Chen size = 8;
34261a6fcccSHuacai Chen sign = true;
34361a6fcccSHuacai Chen write = false;
34461a6fcccSHuacai Chen break;
34561a6fcccSHuacai Chen case stptrd_op:
34661a6fcccSHuacai Chen size = 8;
34761a6fcccSHuacai Chen sign = true;
34861a6fcccSHuacai Chen write = true;
34961a6fcccSHuacai Chen break;
35061a6fcccSHuacai Chen }
35161a6fcccSHuacai Chen
35261a6fcccSHuacai Chen switch (insn.reg3_format.opcode) {
35361a6fcccSHuacai Chen case ldxh_op:
35461a6fcccSHuacai Chen size = 2;
35561a6fcccSHuacai Chen sign = true;
35661a6fcccSHuacai Chen write = false;
35761a6fcccSHuacai Chen break;
35861a6fcccSHuacai Chen case ldxhu_op:
35961a6fcccSHuacai Chen size = 2;
36061a6fcccSHuacai Chen sign = false;
36161a6fcccSHuacai Chen write = false;
36261a6fcccSHuacai Chen break;
36361a6fcccSHuacai Chen case stxh_op:
36461a6fcccSHuacai Chen size = 2;
36561a6fcccSHuacai Chen sign = true;
36661a6fcccSHuacai Chen write = true;
36761a6fcccSHuacai Chen break;
36861a6fcccSHuacai Chen case ldxw_op:
36961a6fcccSHuacai Chen size = 4;
37061a6fcccSHuacai Chen sign = true;
37161a6fcccSHuacai Chen write = false;
37261a6fcccSHuacai Chen break;
37361a6fcccSHuacai Chen case ldxwu_op:
37461a6fcccSHuacai Chen size = 4;
37561a6fcccSHuacai Chen sign = false;
37661a6fcccSHuacai Chen write = false;
37761a6fcccSHuacai Chen break;
37861a6fcccSHuacai Chen case stxw_op:
37961a6fcccSHuacai Chen size = 4;
38061a6fcccSHuacai Chen sign = true;
38161a6fcccSHuacai Chen write = true;
38261a6fcccSHuacai Chen break;
38361a6fcccSHuacai Chen case ldxd_op:
38461a6fcccSHuacai Chen size = 8;
38561a6fcccSHuacai Chen sign = true;
38661a6fcccSHuacai Chen write = false;
38761a6fcccSHuacai Chen break;
38861a6fcccSHuacai Chen case stxd_op:
38961a6fcccSHuacai Chen size = 8;
39061a6fcccSHuacai Chen sign = true;
39161a6fcccSHuacai Chen write = true;
39261a6fcccSHuacai Chen break;
39361a6fcccSHuacai Chen case fldxs_op:
39461a6fcccSHuacai Chen size = 4;
39561a6fcccSHuacai Chen fp = true;
39661a6fcccSHuacai Chen sign = true;
39761a6fcccSHuacai Chen write = false;
39861a6fcccSHuacai Chen break;
39961a6fcccSHuacai Chen case fstxs_op:
40061a6fcccSHuacai Chen size = 4;
40161a6fcccSHuacai Chen fp = true;
40261a6fcccSHuacai Chen sign = true;
40361a6fcccSHuacai Chen write = true;
40461a6fcccSHuacai Chen break;
40561a6fcccSHuacai Chen case fldxd_op:
40661a6fcccSHuacai Chen size = 8;
40761a6fcccSHuacai Chen fp = true;
40861a6fcccSHuacai Chen sign = true;
40961a6fcccSHuacai Chen write = false;
41061a6fcccSHuacai Chen break;
41161a6fcccSHuacai Chen case fstxd_op:
41261a6fcccSHuacai Chen size = 8;
41361a6fcccSHuacai Chen fp = true;
41461a6fcccSHuacai Chen sign = true;
41561a6fcccSHuacai Chen write = true;
41661a6fcccSHuacai Chen break;
41761a6fcccSHuacai Chen }
41861a6fcccSHuacai Chen
41961a6fcccSHuacai Chen if (!size)
42061a6fcccSHuacai Chen goto sigbus;
42161a6fcccSHuacai Chen if (user && !access_ok(addr, size))
42261a6fcccSHuacai Chen goto sigbus;
42361a6fcccSHuacai Chen
42461a6fcccSHuacai Chen if (!write) {
42561a6fcccSHuacai Chen res = unaligned_read(addr, &value, size, sign);
42661a6fcccSHuacai Chen if (res)
42761a6fcccSHuacai Chen goto fault;
42861a6fcccSHuacai Chen
42961a6fcccSHuacai Chen /* Rd is the same field in any formats */
43061a6fcccSHuacai Chen if (!fp)
43161a6fcccSHuacai Chen regs->regs[insn.reg3_format.rd] = value;
43261a6fcccSHuacai Chen else {
43361a6fcccSHuacai Chen if (is_fpu_owner())
43461a6fcccSHuacai Chen write_fpr(insn.reg3_format.rd, value);
43561a6fcccSHuacai Chen else
43661a6fcccSHuacai Chen set_fpr64(¤t->thread.fpu.fpr[insn.reg3_format.rd], 0, value);
43761a6fcccSHuacai Chen }
43861a6fcccSHuacai Chen } else {
43961a6fcccSHuacai Chen /* Rd is the same field in any formats */
44061a6fcccSHuacai Chen if (!fp)
44161a6fcccSHuacai Chen value = regs->regs[insn.reg3_format.rd];
44261a6fcccSHuacai Chen else {
44361a6fcccSHuacai Chen if (is_fpu_owner())
44461a6fcccSHuacai Chen value = read_fpr(insn.reg3_format.rd);
44561a6fcccSHuacai Chen else
44661a6fcccSHuacai Chen value = get_fpr64(¤t->thread.fpu.fpr[insn.reg3_format.rd], 0);
44761a6fcccSHuacai Chen }
44861a6fcccSHuacai Chen
44961a6fcccSHuacai Chen res = unaligned_write(addr, value, size);
45061a6fcccSHuacai Chen if (res)
45161a6fcccSHuacai Chen goto fault;
45261a6fcccSHuacai Chen }
45361a6fcccSHuacai Chen
45461a6fcccSHuacai Chen #ifdef CONFIG_DEBUG_FS
45561a6fcccSHuacai Chen if (user)
45661a6fcccSHuacai Chen unaligned_instructions_user++;
45761a6fcccSHuacai Chen else
45861a6fcccSHuacai Chen unaligned_instructions_kernel++;
45961a6fcccSHuacai Chen #endif
46061a6fcccSHuacai Chen
46161a6fcccSHuacai Chen compute_return_era(regs);
46261a6fcccSHuacai Chen
46361a6fcccSHuacai Chen return;
46461a6fcccSHuacai Chen
46561a6fcccSHuacai Chen fault:
46661a6fcccSHuacai Chen /* Did we have an exception handler installed? */
46761a6fcccSHuacai Chen if (fixup_exception(regs))
46861a6fcccSHuacai Chen return;
46961a6fcccSHuacai Chen
47061a6fcccSHuacai Chen die_if_kernel("Unhandled kernel unaligned access", regs);
47161a6fcccSHuacai Chen force_sig(SIGSEGV);
47261a6fcccSHuacai Chen
47361a6fcccSHuacai Chen return;
47461a6fcccSHuacai Chen
47561a6fcccSHuacai Chen sigbus:
47661a6fcccSHuacai Chen die_if_kernel("Unhandled kernel unaligned access", regs);
47761a6fcccSHuacai Chen force_sig(SIGBUS);
47861a6fcccSHuacai Chen
47961a6fcccSHuacai Chen return;
48061a6fcccSHuacai Chen }
48161a6fcccSHuacai Chen
48261a6fcccSHuacai Chen #ifdef CONFIG_DEBUG_FS
debugfs_unaligned(void)48361a6fcccSHuacai Chen static int __init debugfs_unaligned(void)
48461a6fcccSHuacai Chen {
48561a6fcccSHuacai Chen struct dentry *d;
48661a6fcccSHuacai Chen
48761a6fcccSHuacai Chen d = debugfs_create_dir("loongarch", NULL);
488*41efbb68SImmad Mir
48961a6fcccSHuacai Chen debugfs_create_u32("unaligned_instructions_user",
49061a6fcccSHuacai Chen S_IRUGO, d, &unaligned_instructions_user);
49161a6fcccSHuacai Chen debugfs_create_u32("unaligned_instructions_kernel",
49261a6fcccSHuacai Chen S_IRUGO, d, &unaligned_instructions_kernel);
49361a6fcccSHuacai Chen
49461a6fcccSHuacai Chen return 0;
49561a6fcccSHuacai Chen }
49661a6fcccSHuacai Chen arch_initcall(debugfs_unaligned);
49761a6fcccSHuacai Chen #endif
49861a6fcccSHuacai Chen