powerpc/tm: Add TM Unavailable Exception
authorCyril Bur <cyrilbur@gmail.com>
Wed, 14 Sep 2016 08:02:15 +0000 (18:02 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Tue, 4 Oct 2016 09:33:17 +0000 (20:33 +1100)
If the kernel disables transactional memory (TM) and userspace still
tries TM related actions (TM instructions or TM SPR accesses) TM aware
hardware will cause the kernel to take a facility unavailable
exception.

Add checks for the exception being caused by illegal TM access in
userspace.

Signed-off-by: Cyril Bur <cyrilbur@gmail.com>
[mpe: Rewrite comment entirely, bugs in it are mine]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/kernel/traps.c

index 487e1b4..2f5ef5a 100644 (file)
@@ -1390,6 +1390,13 @@ void vsx_unavailable_exception(struct pt_regs *regs)
 }
 
 #ifdef CONFIG_PPC64
+static void tm_unavailable(struct pt_regs *regs)
+{
+       pr_emerg("Unrecoverable TM Unavailable Exception "
+                       "%lx at %lx\n", regs->trap, regs->nip);
+       die("Unrecoverable TM Unavailable Exception", regs, SIGABRT);
+}
+
 void facility_unavailable_exception(struct pt_regs *regs)
 {
        static char *facility_strings[] = {
@@ -1469,6 +1476,27 @@ void facility_unavailable_exception(struct pt_regs *regs)
                return;
        }
 
+       if (status == FSCR_TM_LG) {
+               /*
+                * If we're here then the hardware is TM aware because it
+                * generated an exception with FSRM_TM set.
+                *
+                * If cpu_has_feature(CPU_FTR_TM) is false, then either firmware
+                * told us not to do TM, or the kernel is not built with TM
+                * support.
+                *
+                * If both of those things are true, then userspace can spam the
+                * console by triggering the printk() below just by continually
+                * doing tbegin (or any TM instruction). So in that case just
+                * send the process a SIGILL immediately.
+                */
+               if (!cpu_has_feature(CPU_FTR_TM))
+                       goto out;
+
+               tm_unavailable(regs);
+               return;
+       }
+
        if ((status < ARRAY_SIZE(facility_strings)) &&
            facility_strings[status])
                facility = facility_strings[status];
@@ -1481,6 +1509,7 @@ void facility_unavailable_exception(struct pt_regs *regs)
                "%sFacility '%s' unavailable, exception at 0x%lx, MSR=%lx\n",
                hv ? "Hypervisor " : "", facility, regs->nip, regs->msr);
 
+out:
        if (user_mode(regs)) {
                _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
                return;