Skip to content

Commit 61a6fcc

Browse files
committed
LoongArch: Add unaligned access support
Loongson-2 series (Loongson-2K500, Loongson-2K1000) don't support unaligned access in hardware, while Loongson-3 series (Loongson-3A5000, Loongson-3C5000) are configurable whether support unaligned access in hardware. This patch add unaligned access emulation for those LoongArch processors without hardware support. Signed-off-by: Huacai Chen <[email protected]>
1 parent dbcd7f5 commit 61a6fcc

File tree

9 files changed

+634
-7
lines changed

9 files changed

+634
-7
lines changed

Documentation/admin-guide/sysctl/kernel.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -433,8 +433,8 @@ ignore-unaligned-usertrap
433433

434434
On architectures where unaligned accesses cause traps, and where this
435435
feature is supported (``CONFIG_SYSCTL_ARCH_UNALIGN_NO_WARN``;
436-
currently, ``arc`` and ``ia64``), controls whether all unaligned traps
437-
are logged.
436+
currently, ``arc``, ``ia64`` and ``loongarch``), controls whether all
437+
unaligned traps are logged.
438438

439439
= =============================================================
440440
0 Log all unaligned accesses.
@@ -1457,8 +1457,8 @@ unaligned-trap
14571457

14581458
On architectures where unaligned accesses cause traps, and where this
14591459
feature is supported (``CONFIG_SYSCTL_ARCH_UNALIGN_ALLOW``; currently,
1460-
``arc`` and ``parisc``), controls whether unaligned traps are caught
1461-
and emulated (instead of failing).
1460+
``arc``, ``parisc`` and ``loongarch``), controls whether unaligned traps
1461+
are caught and emulated (instead of failing).
14621462

14631463
= ========================================================
14641464
0 Do not emulate unaligned accesses.

arch/loongarch/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ config LOONGARCH
121121
select RTC_LIB
122122
select SMP
123123
select SPARSE_IRQ
124+
select SYSCTL_ARCH_UNALIGN_ALLOW
125+
select SYSCTL_ARCH_UNALIGN_NO_WARN
124126
select SYSCTL_EXCEPTION_TRACE
125127
select SWIOTLB
126128
select TRACE_IRQFLAGS_SUPPORT

arch/loongarch/include/asm/inst.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ enum reg2i12_op {
7676
ldbu_op = 0xa8,
7777
ldhu_op = 0xa9,
7878
ldwu_op = 0xaa,
79+
flds_op = 0xac,
80+
fsts_op = 0xad,
81+
fldd_op = 0xae,
82+
fstd_op = 0xaf,
7983
};
8084

8185
enum reg2i14_op {
@@ -146,6 +150,10 @@ enum reg3_op {
146150
ldxbu_op = 0x7040,
147151
ldxhu_op = 0x7048,
148152
ldxwu_op = 0x7050,
153+
fldxs_op = 0x7060,
154+
fldxd_op = 0x7068,
155+
fstxs_op = 0x7070,
156+
fstxd_op = 0x7078,
149157
amswapw_op = 0x70c0,
150158
amswapd_op = 0x70c1,
151159
amaddw_op = 0x70c2,
@@ -566,4 +574,10 @@ static inline void emit_##NAME(union loongarch_instruction *insn, \
566574

567575
DEF_EMIT_REG3SA2_FORMAT(alsld, alsld_op)
568576

577+
struct pt_regs;
578+
579+
void emulate_load_store_insn(struct pt_regs *regs, void __user *addr, unsigned int *pc);
580+
unsigned long unaligned_read(void __user *addr, void *value, unsigned long n, bool sign);
581+
unsigned long unaligned_write(void __user *addr, unsigned long value, unsigned long n);
582+
569583
#endif /* _ASM_INST_H */

arch/loongarch/include/asm/thread_info.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ struct thread_info {
3838
#define INIT_THREAD_INFO(tsk) \
3939
{ \
4040
.task = &tsk, \
41-
.flags = 0, \
41+
.flags = _TIF_FIXADE, \
4242
.cpu = 0, \
4343
.preempt_count = INIT_PREEMPT_COUNT, \
4444
}

arch/loongarch/kernel/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ extra-y := vmlinux.lds
77

88
obj-y += head.o cpu-probe.o cacheinfo.o env.o setup.o entry.o genex.o \
99
traps.o irq.o idle.o process.o dma.o mem.o io.o reset.o switch.o \
10-
elf.o syscall.o signal.o time.o topology.o inst.o ptrace.o vdso.o
10+
elf.o syscall.o signal.o time.o topology.o inst.o ptrace.o vdso.o \
11+
unaligned.o
1112

1213
obj-$(CONFIG_ACPI) += acpi.o
1314
obj-$(CONFIG_EFI) += efi.o

arch/loongarch/kernel/traps.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,13 +368,40 @@ asmlinkage void noinstr do_ade(struct pt_regs *regs)
368368
irqentry_exit(regs, state);
369369
}
370370

371+
/* sysctl hooks */
372+
int unaligned_enabled __read_mostly = 1; /* Enabled by default */
373+
int no_unaligned_warning __read_mostly = 1; /* Only 1 warning by default */
374+
371375
asmlinkage void noinstr do_ale(struct pt_regs *regs)
372376
{
377+
unsigned int *pc;
373378
irqentry_state_t state = irqentry_enter(regs);
374379

380+
perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, regs->csr_badvaddr);
381+
382+
/*
383+
* Did we catch a fault trying to load an instruction?
384+
*/
385+
if (regs->csr_badvaddr == regs->csr_era)
386+
goto sigbus;
387+
if (user_mode(regs) && !test_thread_flag(TIF_FIXADE))
388+
goto sigbus;
389+
if (!unaligned_enabled)
390+
goto sigbus;
391+
if (!no_unaligned_warning)
392+
show_registers(regs);
393+
394+
pc = (unsigned int *)exception_era(regs);
395+
396+
emulate_load_store_insn(regs, (void __user *)regs->csr_badvaddr, pc);
397+
398+
goto out;
399+
400+
sigbus:
375401
die_if_kernel("Kernel ale access", regs);
376402
force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)regs->csr_badvaddr);
377403

404+
out:
378405
irqentry_exit(regs, state);
379406
}
380407

0 commit comments

Comments
 (0)