]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
MIPS: handle Loongson-specific GSExc exception
authorWANG Xuerui <git@xen0n.name>
Wed, 29 Jul 2020 13:14:17 +0000 (21:14 +0800)
committerThomas Bogendoerfer <tsbogend@alpha.franken.de>
Fri, 31 Jul 2020 15:52:47 +0000 (17:52 +0200)
Newer Loongson cores (Loongson-3A R2 and newer) use the
implementation-dependent ExcCode 16 to signal Loongson-specific
exceptions. The extended cause is put in the non-standard CP0.Diag1
register which is CP0 Register 22 Select 1, called GSCause in Loongson
manuals. Inside is an exception code bitfield called GSExcCode, only
codes 0 to 6 inclusive are documented (so far, in the Loongson 3A3000
User Manual, Volume 2).

During experiments, it was found that some undocumented unprivileged
instructions can trigger the also-undocumented GSExcCode 8 on Loongson
3A4000. Processor state is not corrupted, but we cannot continue without
further knowledge, and Loongson is not providing that information as of
this writing. So we send SIGILL on seeing this exception code to thwart
easy local DoS attacks.

Other exception codes are made fatal, partly because of insufficient
knowledge, also partly because they are not as easily reproduced. None
of them are encountered in the wild with upstream kernels and userspace
so far.

Some older cores (Loongson-3A1000 and Loongson-3B1500) have ExcCode 16
too, but the semantic is equivalent to GSExcCode 0. Because the
respective manuals did not mention the CP0.Diag1 register or its read
behavior, these cores are not covered in this patch, as MFC0 from
non-existent CP0 registers is UNDEFINED according to the MIPS
architecture spec.

Reviewed-by: Huacai Chen <chenhc@lemote.com>
Signed-off-by: WANG Xuerui <git@xen0n.name>
Cc: Huacai Chen <chenhc@lemote.com>
Cc: Jiaxun Yang <jiaxun.yang@flygoat.com>
Cc: Tiezhu Yang <yangtiezhu@loongson.cn>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
arch/mips/include/asm/cpu-features.h
arch/mips/include/asm/cpu.h
arch/mips/include/asm/mipsregs.h
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/genex.S
arch/mips/kernel/traps.c

index 0b1bc7ed913b20a1d5345d44dc83108d57e3e7b0..78cf7e300f12a5a9a595b2ae0fe6e865aea51733 100644 (file)
 # define cpu_has_ftlbparex     __opt(MIPS_CPU_FTLBPAREX)
 #endif
 
+#ifndef cpu_has_gsexcex
+# define cpu_has_gsexcex       __opt(MIPS_CPU_GSEXCEX)
+#endif
+
 #ifdef CONFIG_SMP
 /*
  * Some systems share FTLB RAMs between threads within a core (siblings in
index 9d08bd33b11f71abfee53d76b46c9f8c656f4ded..388a82f28a874df72438a673ed55b5e7f210f2af 100644 (file)
@@ -428,6 +428,7 @@ enum cpu_type_enum {
 #define MIPS_CPU_MM_FULL       BIT_ULL(59)     /* CPU supports write-through full merge */
 #define MIPS_CPU_MAC_2008_ONLY BIT_ULL(60)     /* CPU Only support MAC2008 Fused multiply-add instruction */
 #define MIPS_CPU_FTLBPAREX     BIT_ULL(61)     /* CPU has FTLB parity exception */
+#define MIPS_CPU_GSEXCEX       BIT_ULL(62)     /* CPU has GSExc exception */
 
 /*
  * CPU ASE encodings
index 5ba268266d16a82eff9039d7f831922aaf7d3c29..4ddc12e4444a4e5ae6999aa6e057a5be6e64bc06 100644 (file)
 /* Implementation specific trap codes used by MIPS cores */
 #define MIPS_EXCCODE_TLBPAR    16      /* TLB parity error exception */
 
+/* Implementation specific trap codes used by Loongson cores */
+#define LOONGSON_EXCCODE_GSEXC 16      /* Loongson-specific exception */
+
 /*
  * Bits in the coprocessor 0 config register.
  */
index 519d101fd00903ca046f1056be87a81bc29ddcbe..e2955f1f6316f0d3762fd4dc23acb92829cd7926 100644 (file)
@@ -2043,6 +2043,9 @@ static inline void cpu_probe_loongson(struct cpuinfo_mips *c, unsigned int cpu)
 {
        decode_configs(c);
 
+       /* All Loongson processors covered here define ExcCode 16 as GSExc. */
+       c->options |= MIPS_CPU_GSEXCEX;
+
        switch (c->processor_id & PRID_IMP_MASK) {
        case PRID_IMP_LOONGSON_64R: /* Loongson-64 Reduced */
                switch (c->processor_id & PRID_REV_MASK) {
index a1b966f3578e869e60cc36cdb7e2f52fc5db9475..bcce32a3de10bc5895ef5923a0d18f968d919602 100644 (file)
@@ -498,6 +498,19 @@ NESTED(nmi_handler, PT_SIZE, sp)
        KMODE
        .endm
 
+       .macro __build_clear_gsexc
+       .set    push
+       /*
+        * We need to specify a selector to access the CP0.Diag1 (GSCause)
+        * register. All GSExc-equipped processors have MIPS32.
+        */
+       .set    mips32
+       mfc0    a1, CP0_DIAGNOSTIC1
+       .set    pop
+       TRACE_IRQS_ON
+       STI
+       .endm
+
        .macro  __BUILD_silent exception
        .endm
 
@@ -556,6 +569,7 @@ NESTED(nmi_handler, PT_SIZE, sp)
        BUILD_HANDLER fpe fpe fpe silent                /* #15 */
 #endif
        BUILD_HANDLER ftlb ftlb none silent             /* #16 */
+       BUILD_HANDLER gsexc gsexc gsexc silent          /* #16 */
        BUILD_HANDLER msa msa sti silent                /* #21 */
        BUILD_HANDLER mdmx mdmx sti silent              /* #22 */
 #ifdef CONFIG_HARDWARE_WATCHPOINTS
index 9c37a69972596ec44caebc52fa7ace3a17a39bc1..b95ef98fc8479332949c96c3a490bb9ee6ac0c11 100644 (file)
@@ -90,6 +90,7 @@ extern asmlinkage void handle_tr(void);
 extern asmlinkage void handle_msa_fpe(void);
 extern asmlinkage void handle_fpe(void);
 extern asmlinkage void handle_ftlb(void);
+extern asmlinkage void handle_gsexc(void);
 extern asmlinkage void handle_msa(void);
 extern asmlinkage void handle_mdmx(void);
 extern asmlinkage void handle_watch(void);
@@ -1900,6 +1901,37 @@ asmlinkage void do_ftlb(void)
        cache_parity_error();
 }
 
+asmlinkage void do_gsexc(struct pt_regs *regs, u32 diag1)
+{
+       u32 exccode = (diag1 & LOONGSON_DIAG1_EXCCODE) >>
+                       LOONGSON_DIAG1_EXCCODE_SHIFT;
+       enum ctx_state prev_state;
+
+       prev_state = exception_enter();
+
+       switch (exccode) {
+       case 0x08:
+               /* Undocumented exception, will trigger on certain
+                * also-undocumented instructions accessible from userspace.
+                * Processor state is not otherwise corrupted, but currently
+                * we don't know how to proceed. Maybe there is some
+                * undocumented control flag to enable the instructions?
+                */
+               force_sig(SIGILL);
+               break;
+
+       default:
+               /* None of the other exceptions, documented or not, have
+                * further details given; none are encountered in the wild
+                * either. Panic in case some of them turn out to be fatal.
+                */
+               show_regs(regs);
+               panic("Unhandled Loongson exception - GSCause = %08x", diag1);
+       }
+
+       exception_exit(prev_state);
+}
+
 /*
  * SDBBP EJTAG debug exception handler.
  * We skip the instruction and return to the next instruction.
@@ -2457,6 +2489,9 @@ void __init trap_init(void)
        if (cpu_has_ftlbparex)
                set_except_vector(MIPS_EXCCODE_TLBPAR, handle_ftlb);
 
+       if (cpu_has_gsexcex)
+               set_except_vector(LOONGSON_EXCCODE_GSEXC, handle_gsexc);
+
        if (cpu_has_rixiex) {
                set_except_vector(EXCCODE_TLBRI, tlb_do_page_fault_0);
                set_except_vector(EXCCODE_TLBXI, tlb_do_page_fault_0);