From 9cf2f9fe9714d0e52a74beb1ef264145b953d534 Mon Sep 17 00:00:00 2001 From: Lephe Date: Sat, 20 Jun 2020 09:32:48 +0200 Subject: [PATCH] core tmu: improve reliability of interrupt handlers This change includes three reliability improvements in handlers: 1. TMU handlers now actively check for the UNF flag to go low rather than expecting it to do so right away. 2. CPUOPM.INTMU is now set so that IMASK it updated at every interrupt (which is absolutely required for nested interrupts!). 3. gint_inth_callback() no longer performs transfers between user bank and kernel bank while in user bank, because this is when interrupts are enabled and thus likely to corrupt the kernel bank; rather, it now does it while in kernel bank with interrupts disabled. --- include/core/setup.h | 3 +++ src/core/inth.S | 25 ++++++++++++++++--------- src/core/setup.c | 7 +++++++ src/core/vbr.s | 35 +++++++++++++++++++++++++++++++++++ src/tmu/inth.s | 28 +++++++++++++++++----------- 5 files changed, 78 insertions(+), 20 deletions(-) diff --git a/include/core/setup.h b/include/core/setup.h index 7e13026..803b1ea 100644 --- a/include/core/setup.h +++ b/include/core/setup.h @@ -20,6 +20,9 @@ Returns the previous VBR address. */ uint32_t gint_setvbr(uint32_t vbr, void (*configure)(void)); +void gint_setcpuopm(uint32_t CPUOPM); +uint32_t gint_getcpuopm(void); + /* gint_exch(): Exception handler */ void gint_exch(void); /* gint_tlbh(): TLB miss handler */ diff --git a/src/core/inth.S b/src/core/inth.S index 25f7f07..ba20123 100644 --- a/src/core/inth.S +++ b/src/core/inth.S @@ -184,28 +184,35 @@ _gint_inth_callback: stc.l ssr, @-r15 stc.l sr, @-r15 + /* Save some values to user bank; once we enable interrupts, the kernel + bank might be overwritten at any moment. */ + ldc r4, r0_bank + ldc r5, r4_bank + /* Enable interrupts and go back to user bank. SR.IMASK is already set to the level of the current interrupt, which makes sure we can only be re-interrupted by something with a higher priority. */ - mov.l .SR_clear_RB_BL, r1 stc sr, r0 + mov.l .SR_clear_RB_BL, r1 and r1, r0 ldc r0, sr - /* We are now in the user bank, but we can still use r0..r7 as the - important values have been saved on the stack. Call back. */ - stc r4_bank, r0 + /* We are now in the user bank with r0 and r4 set. Call back. We want + to forward the return value to kernel bank, but this bank can be + changed at any moment since interrupts are enabled. */ sts.l pr, @-r15 jsr @r0 - stc r5_bank, r4 + nop lds.l @r15+, pr - /* We want to forward the return value to the system bank */ - ldc r0, r0_bank - /* Restore the previous status register and the registers of the - interrupted procedure. */ + interrupted procedure. Restoring sr gets us back to system bank with + interrupts disabled. */ ldc.l @r15+, sr + + /* We can now pull the return value since interrupts are disabled */ + stc r0_bank, r0 + ldc.l @r15+, ssr ldc.l @r15+, spc ldc.l @r15+, r7_bank diff --git a/src/core/setup.c b/src/core/setup.c index de4cc91..a123dff 100644 --- a/src/core/setup.c +++ b/src/core/setup.c @@ -37,6 +37,7 @@ typedef struct { uint16_t iprs[12]; uint8_t masks[13]; + uint32_t CPUOPM; } GPACKED(2) gint_core_ctx; @@ -57,6 +58,8 @@ GMAPPED static void gint_ctx_save(gint_core_ctx *ctx) uint8_t *IMR = (void *)SH7305_INTC.MSK; for(int i = 0; i < 13; i++, IMR += 4) ctx->masks[i] = *IMR; + + ctx->CPUOPM = gint_getcpuopm(); } } @@ -82,6 +85,8 @@ GMAPPED static void gint_ctx_restore(gint_core_ctx *ctx) *IMCR = 0xff; *IMR = ctx->masks[i]; } + + gint_setcpuopm(ctx->CPUOPM); } } @@ -100,6 +105,8 @@ GMAPPED static void lock(void) *(SH7705_INTC.IPRS[i]) = 0x0000; else for(int i = 0; i < 12; i++) SH7305_INTC.IPRS[2 * i] = 0x0000; + + gint_setcpuopm(gint_getcpuopm() | 0x00000008); } /* gint_install() - install and start gint */ diff --git a/src/core/vbr.s b/src/core/vbr.s index 5e33666..69bbe41 100644 --- a/src/core/vbr.s +++ b/src/core/vbr.s @@ -3,6 +3,9 @@ */ .global _gint_setvbr +.global _gint_setcpuopm +.global _gint_getcpuopm + .section .gint.mapped /* gint_setvbr() @@ -47,3 +50,35 @@ _gint_setvbr: mov r9, r0 rts mov.l @r15+, r9 + +.text + +/* gint_setcpuopm() + Changes the CPUOPM value and executes an ICBI to register the change. + + @r4 New value of CPUOPM (uint32_t) */ +_gint_setcpuopm: + /* Set CPUOPM as requested */ + mov.l 1f, r0 + mov.l r4, @r0 + + /* Read CPUOPM again */ + mov.l @r0, r5 + + /* Invalidate a cache address */ + mov #-96, r0 + shll16 r0 + shll8 r0 + icbi @r0 + + rts + nop + +_gint_getcpuopm: + mov.l 1f, r0 + rts + mov.l @r0, r0 + +.align 4 + +1: .long 0xff2f0000 diff --git a/src/tmu/inth.s b/src/tmu/inth.s index 9867495..d6a028d 100644 --- a/src/tmu/inth.s +++ b/src/tmu/inth.s @@ -45,23 +45,23 @@ _inth_tmu_0: sts.l pr, @-r15 mov.l r1, @-r15 - /* Load the TCR address and clear the interrupt flag */ + /* Load the TCR address */ mov.l .mask, r3 + not r3, r4 mov.l @(8, r0), r1 - mov.w @r1, r2 + + /* Clear the interrupt flag */ +1: mov.w @r1, r2 + tst r4, r2 and r3, r2 mov.w r2, @r1 + bf 1b - /* Invoke the callback function and pass the argument */ + /* Prepare callback and jump to second section */ mov.l .gint_inth_callback_1, r1 mov.l @r0, r4 - jsr @r1 - mov.l @(4, r0), r5 - - /* Jump to second section */ - mov.l .timer_stop_1, r1 bra .shared2 - mov.l @r15+, r4 + mov.l @(4, r0), r5 /* SECOND GATE - TMU1 entry and stop timer */ _inth_tmu_1: @@ -71,9 +71,15 @@ _inth_tmu_1: /*** This is the second shared section ***/ .shared2: + /* Invoke callback */ + jsr @r1 + nop + /* Stop the timer if the return value is not zero */ + mov.l @r15+, r4 tst r0, r0 bt .shared3 + mov.l .timer_stop_1, r1 jsr @r1 nop @@ -82,7 +88,7 @@ _inth_tmu_1: rts nop - .zero 12 + .zero 4 /* THIRD GATE - TMU2 entry and storage for TMU0 */ _inth_tmu_2: @@ -104,7 +110,7 @@ _inth_tmu_2: _inth_tmu_storage: .mask: - .long 0x0000feff + .long 0xfffffeff .timer_stop_1: .long _timer_stop