selftests/powerpc: Add FPU denormal test
authorNicholas Piggin <npiggin@gmail.com>
Wed, 8 Jul 2020 07:49:42 +0000 (17:49 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Wed, 15 Jul 2020 02:02:20 +0000 (12:02 +1000)
Add a testcase that tries to trigger the FPU denormal exception on
Power8 or earlier CPUs.

Prior to commit 4557ac6b344b ("powerpc/64s/exception: Fix 0x1500
interrupt handler crash") this would trigger a crash such as:

  Oops: Exception in kernel mode, sig: 5 [#1]
  LE PAGE_SIZE=64K MMU=Hash SMP NR_CPUS=2048 NUMA PowerNV
  Modules linked in: iptable_mangle xt_MASQUERADE iptable_nat nf_nat xt_conntrack nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 ipt_REJECT nf_reject_ipv4 xt_tcpudp tun bridge stp llc ip6table_filter ip6_tables iptable_filter fuse kvm_hv binfmt_misc squashfs mlx4_ib ib_uverbs dm_multipath scsi_dh_rdac scsi_dh_alua ib_core mlx4_en sr_mod cdrom bnx2x lpfc mlx4_core crc_t10dif scsi_transport_fc sg mdio vmx_crypto crct10dif_vpmsum leds_powernv powernv_rng rng_core led_class powernv_op_panel sunrpc ip_tables x_tables autofs4
  CPU: 159 PID: 6854 Comm: fpu_denormal Not tainted 5.8.0-rc2-gcc-8.2.0-00092-g4ec7aaab0828 #192
  NIP:  c0000000000100ec LR: c00000000001b85c CTR: 0000000000000000
  REGS: c000001dd818f770 TRAP: 1500   Not tainted  (5.8.0-rc2-gcc-8.2.0-00092-g4ec7aaab0828)
  MSR:  900000000290b033 <SF,HV,VEC,VSX,EE,FP,ME,IR,DR,RI,LE>  CR: 24002884  XER: 20000000
  CFAR: c00000000001005c IRQMASK: 1
  GPR00: c00000000001c4c8 c000001dd818fa00 c00000000171c200 c000001dd8101570
  GPR04: 0000000000000000 c000001dd818fe90 c000001dd8101590 000000000000001d
  GPR08: 0000000000000010 0000000000002000 c000001dd818fe90 fffffffffc48ac60
  GPR12: 0000000000002200 c000001ffff4f480 0000000000000000 0000000000000000
  GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
  GPR20: 0000000000000000 00007fffab225b40 0000000000000001 c000000001757168
  GPR24: c000001dd8101570 c0000018027b00f0 c000001dd8101570 c000000001496098
  GPR28: c00000000174ad05 c000001dd8100000 c000001dd8100000 c000001dd8100000
  NIP save_fpu+0xa8/0x2ac
  LR  __giveup_fpu+0x2c/0xd0
  Call Trace:
    0xc000001dd818fa80 (unreliable)
    giveup_all+0x118/0x120
    __switch_to+0x124/0x6c0
    __schedule+0x390/0xaf0
    do_task_dead+0x70/0x80
    do_exit+0x8fc/0xe10
    do_group_exit+0x64/0xd0
    sys_exit_group+0x24/0x30
    system_call_exception+0x164/0x270
    system_call_common+0xf0/0x278

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
[mpe: Split out of fix patch, add oops log]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20200708074942.1713396-1-npiggin@gmail.com
tools/testing/selftests/powerpc/math/.gitignore
tools/testing/selftests/powerpc/math/Makefile
tools/testing/selftests/powerpc/math/fpu_denormal.c [new file with mode: 0644]

index 11a10d7..4e2049d 100644 (file)
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
-TEST_GEN_PROGS := fpu_syscall fpu_preempt fpu_signal vmx_syscall vmx_preempt vmx_signal vsx_preempt
+TEST_GEN_PROGS := fpu_syscall fpu_preempt fpu_signal fpu_denormal vmx_syscall vmx_preempt vmx_signal vsx_preempt
 
 top_srcdir = ../../../../..
 include ../../lib.mk
diff --git a/tools/testing/selftests/powerpc/math/fpu_denormal.c b/tools/testing/selftests/powerpc/math/fpu_denormal.c
new file mode 100644 (file)
index 0000000..5f96682
--- /dev/null
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright IBM Corp. 2020
+ *
+ * This test attempts to cause a FP denormal exception on POWER8 CPUs. Unfortunately
+ * if the denormal handler is not configured or working properly, this can cause a bad
+ * crash in kernel mode when the kernel tries to save FP registers when the process
+ * exits.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "utils.h"
+
+static int test_denormal_fpu(void)
+{
+       unsigned int m32;
+       unsigned long m64;
+       volatile float f;
+       volatile double d;
+
+       /* try to induce lfs <denormal> ; stfd */
+
+       m32 = 0x00715fcf; /* random denormal */
+       memcpy((float *)&f, &m32, sizeof(f));
+       d = f;
+       memcpy(&m64, (double *)&d, sizeof(d));
+
+       FAIL_IF((long)(m64 != 0x380c57f3c0000000)); /* renormalised value */
+
+       return 0;
+}
+
+int main(int argc, char *argv[])
+{
+       return test_harness(test_denormal_fpu, "fpu_denormal");
+}