xtensa: support artificial division by 0 exception
authorMax Filippov <jcmvbkbc@gmail.com>
Fri, 13 May 2022 15:11:14 +0000 (08:11 -0700)
committerMax Filippov <jcmvbkbc@gmail.com>
Tue, 17 May 2022 10:35:43 +0000 (03:35 -0700)
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 <jcmvbkbc@gmail.com>
arch/xtensa/kernel/traps.c

index 24d11b44fa572d5bfbfa36282781c1f6060797ea..2b75b252b62664790cf1fc49e33558155e024739 100644 (file)
@@ -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. */