MIPS: Allow vectored interrupt handler to reside everywhere for 64bit
authorThomas Bogendoerfer <tsbogend@alpha.franken.de>
Thu, 21 Dec 2023 12:54:03 +0000 (13:54 +0100)
committerThomas Bogendoerfer <tsbogend@alpha.franken.de>
Sat, 30 Dec 2023 14:36:01 +0000 (15:36 +0100)
Setting up vector interrupts worked only with handlers, which resided
in CKSEG0 space. This limits the kernel placement for 64bit platforms.
By patching in the offset into vi_handlers[] instead of the full
handler address, the vectored exception handler can load the
address by itself and jump to it.

Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Reviewed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
arch/mips/kernel/genex.S
arch/mips/kernel/traps.c

index b6de8e88c1bd428f1f1b7eee6b1118c9304e3601..a572ce36a24f21d25bf99943deac10545f7c3de5 100644 (file)
@@ -272,18 +272,17 @@ NESTED(except_vec_vi, 0, sp)
        .set    push
        .set    noreorder
        PTR_LA  v1, except_vec_vi_handler
-FEXPORT(except_vec_vi_lui)
-       lui     v0, 0           /* Patched */
        jr      v1
 FEXPORT(except_vec_vi_ori)
-        ori    v0, 0           /* Patched */
+        ori    v0, zero, 0             /* Offset in vi_handlers[] */
        .set    pop
        END(except_vec_vi)
 EXPORT(except_vec_vi_end)
 
 /*
  * Common Vectored Interrupt code
- * Complete the register saves and invoke the handler which is passed in $v0
+ * Complete the register saves and invoke the handler, $v0 holds
+ * offset into vi_handlers[]
  */
 NESTED(except_vec_vi_handler, 0, sp)
        SAVE_TEMP
@@ -331,6 +330,7 @@ NESTED(except_vec_vi_handler, 0, sp)
        /* Save task's sp on IRQ stack so that unwinding can follow it */
        LONG_S  s1, 0(sp)
 2:
+       PTR_L   v0, vi_handlers(v0)
        jalr    v0
 
        /* Restore sp */
index 246c6a6b02614cdc396749ce1d21da3ee5763b74..d90b189086926f11d5680db8eb65d4e373d606c4 100644 (file)
@@ -2091,16 +2091,14 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs)
                 * If no shadow set is selected then use the default handler
                 * that does normal register saving and standard interrupt exit
                 */
-               extern const u8 except_vec_vi[], except_vec_vi_lui[];
+               extern const u8 except_vec_vi[];
                extern const u8 except_vec_vi_ori[], except_vec_vi_end[];
                extern const u8 rollback_except_vec_vi[];
                const u8 *vec_start = using_rollback_handler() ?
                                      rollback_except_vec_vi : except_vec_vi;
 #if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_BIG_ENDIAN)
-               const int lui_offset = except_vec_vi_lui - vec_start + 2;
                const int ori_offset = except_vec_vi_ori - vec_start + 2;
 #else
-               const int lui_offset = except_vec_vi_lui - vec_start;
                const int ori_offset = except_vec_vi_ori - vec_start;
 #endif
                const int handler_len = except_vec_vi_end - vec_start;
@@ -2119,10 +2117,9 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs)
 #else
                                handler_len);
 #endif
-               h = (u16 *)(b + lui_offset);
-               *h = (handler >> 16) & 0xffff;
+               /* insert offset into vi_handlers[] */
                h = (u16 *)(b + ori_offset);
-               *h = (handler & 0xffff);
+               *h = n * sizeof(handler);
                local_flush_icache_range((unsigned long)b,
                                         (unsigned long)(b+handler_len));
        }