Skip to content

Commit

Permalink
LoongArch: Add unaligned access support
Browse files Browse the repository at this point in the history
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 <chenhuacai@loongson.cn>
  • Loading branch information
Huacai Chen committed Dec 14, 2022
1 parent dbcd7f5 commit 61a6fcc
Show file tree
Hide file tree
Showing 9 changed files with 634 additions and 7 deletions.
8 changes: 4 additions & 4 deletions Documentation/admin-guide/sysctl/kernel.rst
Original file line number Diff line number Diff line change
Expand Up @@ -433,8 +433,8 @@ ignore-unaligned-usertrap

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

= =============================================================
0 Log all unaligned accesses.
Expand Down Expand Up @@ -1457,8 +1457,8 @@ unaligned-trap

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

= ========================================================
0 Do not emulate unaligned accesses.
Expand Down
2 changes: 2 additions & 0 deletions arch/loongarch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ config LOONGARCH
select RTC_LIB
select SMP
select SPARSE_IRQ
select SYSCTL_ARCH_UNALIGN_ALLOW
select SYSCTL_ARCH_UNALIGN_NO_WARN
select SYSCTL_EXCEPTION_TRACE
select SWIOTLB
select TRACE_IRQFLAGS_SUPPORT
Expand Down
14 changes: 14 additions & 0 deletions arch/loongarch/include/asm/inst.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ enum reg2i12_op {
ldbu_op = 0xa8,
ldhu_op = 0xa9,
ldwu_op = 0xaa,
flds_op = 0xac,
fsts_op = 0xad,
fldd_op = 0xae,
fstd_op = 0xaf,
};

enum reg2i14_op {
Expand Down Expand Up @@ -146,6 +150,10 @@ enum reg3_op {
ldxbu_op = 0x7040,
ldxhu_op = 0x7048,
ldxwu_op = 0x7050,
fldxs_op = 0x7060,
fldxd_op = 0x7068,
fstxs_op = 0x7070,
fstxd_op = 0x7078,
amswapw_op = 0x70c0,
amswapd_op = 0x70c1,
amaddw_op = 0x70c2,
Expand Down Expand Up @@ -566,4 +574,10 @@ static inline void emit_##NAME(union loongarch_instruction *insn, \

DEF_EMIT_REG3SA2_FORMAT(alsld, alsld_op)

struct pt_regs;

void emulate_load_store_insn(struct pt_regs *regs, void __user *addr, unsigned int *pc);
unsigned long unaligned_read(void __user *addr, void *value, unsigned long n, bool sign);
unsigned long unaligned_write(void __user *addr, unsigned long value, unsigned long n);

#endif /* _ASM_INST_H */
2 changes: 1 addition & 1 deletion arch/loongarch/include/asm/thread_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ struct thread_info {
#define INIT_THREAD_INFO(tsk) \
{ \
.task = &tsk, \
.flags = 0, \
.flags = _TIF_FIXADE, \
.cpu = 0, \
.preempt_count = INIT_PREEMPT_COUNT, \
}
Expand Down
3 changes: 2 additions & 1 deletion arch/loongarch/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ extra-y := vmlinux.lds

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

obj-$(CONFIG_ACPI) += acpi.o
obj-$(CONFIG_EFI) += efi.o
Expand Down
27 changes: 27 additions & 0 deletions arch/loongarch/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -368,13 +368,40 @@ asmlinkage void noinstr do_ade(struct pt_regs *regs)
irqentry_exit(regs, state);
}

/* sysctl hooks */
int unaligned_enabled __read_mostly = 1; /* Enabled by default */
int no_unaligned_warning __read_mostly = 1; /* Only 1 warning by default */

asmlinkage void noinstr do_ale(struct pt_regs *regs)
{
unsigned int *pc;
irqentry_state_t state = irqentry_enter(regs);

perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, regs->csr_badvaddr);

/*
* Did we catch a fault trying to load an instruction?
*/
if (regs->csr_badvaddr == regs->csr_era)
goto sigbus;
if (user_mode(regs) && !test_thread_flag(TIF_FIXADE))
goto sigbus;
if (!unaligned_enabled)
goto sigbus;
if (!no_unaligned_warning)
show_registers(regs);

pc = (unsigned int *)exception_era(regs);

emulate_load_store_insn(regs, (void __user *)regs->csr_badvaddr, pc);

goto out;

sigbus:
die_if_kernel("Kernel ale access", regs);
force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)regs->csr_badvaddr);

out:
irqentry_exit(regs, state);
}

Expand Down
Loading

0 comments on commit 61a6fcc

Please sign in to comment.