From d74862007e0849fad8ba86447e6f05928f920640 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Fri, 13 May 2022 08:11:14 -0700 Subject: xtensa: support artificial division by 0 exception On xtensa cores wihout hardware division option division support functions from libgcc react to division by 0 attempt by executing illegal instruction followed by the characters 'DIV0'. Recognize this pattern in illegal instruction exception handler and convert it to division by 0. Signed-off-by: Max Filippov --- arch/xtensa/kernel/traps.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c index 24d11b44fa57..2b75b252b626 100644 --- a/arch/xtensa/kernel/traps.c +++ b/arch/xtensa/kernel/traps.c @@ -293,12 +293,35 @@ static void do_interrupt(struct pt_regs *regs) set_irq_regs(old_regs); } +static bool check_div0(struct pt_regs *regs) +{ + static const u8 pattern[] = {'D', 'I', 'V', '0'}; + const u8 *p; + u8 buf[5]; + + if (user_mode(regs)) { + if (copy_from_user(buf, (void __user *)regs->pc + 2, 5)) + return 0; + p = buf; + } else { + p = (const u8 *)regs->pc + 2; + } + + return memcmp(p, pattern, sizeof(pattern)) == 0 || + memcmp(p + 1, pattern, sizeof(pattern)) == 0; +} + /* * Illegal instruction. Fatal if in kernel space. */ static void do_illegal_instruction(struct pt_regs *regs) { + if (check_div0(regs)) { + do_div0(regs); + return; + } + __die_if_kernel("Illegal instruction in kernel", regs, SIGKILL); /* If in user mode, send SIGILL signal to current process. */ -- cgit v1.2.3-59-g8ed1b