static long bus_error_jmp[JMP_BUF_LEN];
 static int catch_memory_errors;
+static int catch_spr_faults;
 static long *xmon_fault_jmp[NR_CPUS];
 
 /* Breakpoint stuff */
 static void flush_input(void);
 static int inchar(void);
 static void take_input(char *);
-static unsigned long read_spr(int);
+static int  read_spr(int, unsigned long *);
 static void write_spr(int, unsigned long);
 static void super_regs(void);
 static void remove_bpts(void);
   sdi #        disassemble spu local store for spu # (in hex)\n"
 #endif
 "  S   print special registers\n\
+  Sa    print all SPRs\n\
+  Sr # read SPR #\n\
+  Sw #v write v to SPR #\n\
   t    print backtrace\n\
   x    exit monitor and recover\n\
   X    exit monitor and don't recover\n"
 #ifdef CONFIG_SMP
        cpu = smp_processor_id();
        if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
+               /*
+                * We catch SPR read/write faults here because the 0x700, 0xf60
+                * etc. handlers don't call debugger_fault_handler().
+                */
+               if (catch_spr_faults)
+                       longjmp(bus_error_jmp, 1);
                get_output_lock();
                excprint(regs);
                printf("cpu 0x%x: Exception %lx %s in xmon, "
        catch_memory_errors = 0;
 }
 
-static unsigned long
-read_spr(int n)
+extern unsigned long xmon_mfspr(int spr, unsigned long default_value);
+extern void xmon_mtspr(int spr, unsigned long value);
+
+static int
+read_spr(int n, unsigned long *vp)
 {
-       unsigned int instrs[2];
-       unsigned long (*code)(void);
        unsigned long ret = -1UL;
-#ifdef CONFIG_PPC64
-       unsigned long opd[3];
-
-       opd[0] = (unsigned long)instrs;
-       opd[1] = 0;
-       opd[2] = 0;
-       code = (unsigned long (*)(void)) opd;
-#else
-       code = (unsigned long (*)(void)) instrs;
-#endif
-
-       /* mfspr r3,n; blr */
-       instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
-       instrs[1] = 0x4e800020;
-       store_inst(instrs);
-       store_inst(instrs+1);
+       int ok = 0;
 
        if (setjmp(bus_error_jmp) == 0) {
-               catch_memory_errors = 1;
+               catch_spr_faults = 1;
                sync();
 
-               ret = code();
+               ret = xmon_mfspr(n, *vp);
 
                sync();
-               /* wait a little while to see if we get a machine check */
-               __delay(200);
-               n = size;
+               *vp = ret;
+               ok = 1;
        }
+       catch_spr_faults = 0;
 
-       return ret;
+       return ok;
 }
 
 static void
 write_spr(int n, unsigned long val)
 {
-       unsigned int instrs[2];
-       unsigned long (*code)(unsigned long);
-#ifdef CONFIG_PPC64
-       unsigned long opd[3];
-
-       opd[0] = (unsigned long)instrs;
-       opd[1] = 0;
-       opd[2] = 0;
-       code = (unsigned long (*)(unsigned long)) opd;
-#else
-       code = (unsigned long (*)(unsigned long)) instrs;
-#endif
-
-       instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
-       instrs[1] = 0x4e800020;
-       store_inst(instrs);
-       store_inst(instrs+1);
-
        if (setjmp(bus_error_jmp) == 0) {
-               catch_memory_errors = 1;
+               catch_spr_faults = 1;
                sync();
 
-               code(val);
+               xmon_mtspr(n, val);
 
                sync();
-               /* wait a little while to see if we get a machine check */
-               __delay(200);
-               n = size;
+       } else {
+               printf("SPR 0x%03x (%4d) Faulted during write\n", n, n);
        }
+       catch_spr_faults = 0;
 }
 
 static unsigned long regno;
 extern char exc_prolog;
 extern char dec_exc;
 
+static void dump_one_spr(int spr, bool show_unimplemented)
+{
+       unsigned long val;
+
+       val = 0xdeadbeef;
+       if (!read_spr(spr, &val)) {
+               printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
+               return;
+       }
+
+       if (val == 0xdeadbeef) {
+               /* Looks like read was a nop, confirm */
+               val = 0x0badcafe;
+               if (!read_spr(spr, &val)) {
+                       printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
+                       return;
+               }
+
+               if (val == 0x0badcafe) {
+                       if (show_unimplemented)
+                               printf("SPR 0x%03x (%4d) Unimplemented\n", spr, spr);
+                       return;
+               }
+       }
+
+       printf("SPR 0x%03x (%4d) = 0x%lx\n", spr, spr, val);
+}
+
 static void super_regs(void)
 {
        int cmd;
-       unsigned long val;
+       int spr;
 
        cmd = skipbl();
-       if (cmd == '\n') {
+
+       switch (cmd) {
+       case '\n': {
                unsigned long sp, toc;
                asm("mr %0,1" : "=r" (sp) :);
                asm("mr %0,2" : "=r" (toc) :);
                       mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
                printf("sp   = "REG"  sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
                printf("toc  = "REG"  dar  = "REG"\n", toc, mfspr(SPRN_DAR));
-
                return;
        }
-
-       scanhex(®no);
-       switch (cmd) {
-       case 'w':
-               val = read_spr(regno);
+       case 'w': {
+               unsigned long val;
+               scanhex(®no);
+               val = 0;
+               read_spr(regno, &val);
                scanhex(&val);
                write_spr(regno, val);
-               /* fall through */
+               dump_one_spr(regno, true);
+               break;
+       }
        case 'r':
-               printf("spr %lx = %lx\n", regno, read_spr(regno));
+               scanhex(®no);
+               dump_one_spr(regno, true);
+               break;
+       case 'a':
+               /* dump ALL SPRs */
+               for (spr = 1; spr < 1024; ++spr)
+                       dump_one_spr(spr, false);
                break;
        }
+
        scannl();
 }