From fb7e2b527e12870117975f5eb686488d0130a8a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timur=20=C3=87elik?= Date: Mon, 28 Apr 2025 12:37:12 +0200 Subject: [PATCH 1/7] mips64: Fix initial memclr memclrNoHeapPointers will check the MIPS64X struct whether to use an SIMD instruction set, which isn't initialized at this point. As a safe fallback disable all optional instruction sets (currently only MSA) until proper initialization. --- src/runtime/rt0_noos_mips64.s | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/runtime/rt0_noos_mips64.s b/src/runtime/rt0_noos_mips64.s index f3f3aa665b032d..d9b875220116e7 100644 --- a/src/runtime/rt0_noos_mips64.s +++ b/src/runtime/rt0_noos_mips64.s @@ -16,6 +16,10 @@ TEXT runtime·_rt0_mips64_noos1(SB),NOSPLIT|NOFRAME,$0 // Store RAM size in a register not used by memclrNoHeapPointers MOVV R4, R16 + // Make sure the MIPS64X struct is initialized before calling + // memclrNoHeapPointers. + MOVBU R0, internal∕cpu·MIPS64X+const_offsetMIPS64XHasMSA(SB) + // Clear .bss, .noptrbss and unallocated memory. SUBU $16, R29 From 4e00d7c895108555b974b790ff9bc518061cb853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timur=20=C3=87elik?= Date: Mon, 28 Apr 2025 12:42:43 +0200 Subject: [PATCH 2/7] mips64: Fix calling of meminit() to new signature --- src/runtime/rt0_noos_mips64.s | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/runtime/rt0_noos_mips64.s b/src/runtime/rt0_noos_mips64.s index d9b875220116e7..de04346d703ed3 100644 --- a/src/runtime/rt0_noos_mips64.s +++ b/src/runtime/rt0_noos_mips64.s @@ -105,13 +105,14 @@ TEXT runtime·rt0_go(SB),NOSPLIT|NOFRAME|TOPFRAME,$0 MOVV $runtime·nodmaend(SB), R11 SUB $SIGNAL_STACK_SIZE, R9 - SUB $32, R29 + SUB $48, R29 MOVV R8, 8(R29) MOVV R9, 16(R29) MOVV R10, 24(R29) MOVV R11, 32(R29) + MOVV R0, 40(R29) JAL runtime·meminit(SB) - ADD $32, R29 + ADD $48, R29 // initialize noos tasker and Go scheduler JAL runtime·taskerinit(SB) From 05324b3bb853e038100e5cd816741904cfdcaa60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timur=20=C3=87elik?= Date: Mon, 28 Apr 2025 12:58:50 +0200 Subject: [PATCH 3/7] mips64: Avoid CACHE warnings by ares ares will report unusual cache accesses if a CACHE OP is performed on non-cacheable addresses. It's not a bug, but to make ares happy do the cache ops in the uncached segment. --- src/runtime/rt0_noos_mips64.s | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/runtime/rt0_noos_mips64.s b/src/runtime/rt0_noos_mips64.s index de04346d703ed3..5d2871db5acc93 100644 --- a/src/runtime/rt0_noos_mips64.s +++ b/src/runtime/rt0_noos_mips64.s @@ -49,6 +49,7 @@ TEXT runtime·_rt0_mips64_noos1(SB),NOSPLIT|NOFRAME,$0 // Load interrupt vector MOVW $runtime·intvector(SB), R8 MOVW $0xa0000000, R9 + MOVW $0x80000000, R12 MOVW $4, R10 loop: MOVW (R8), R11 @@ -56,12 +57,13 @@ loop: MOVW R11, 0x80(R9) MOVW R11, 0x100(R9) MOVW R11, 0x180(R9) - CACHE HIT_INVALIDATE_I, 0(R9) - CACHE HIT_INVALIDATE_I, 0x80(R9) - CACHE HIT_INVALIDATE_I, 0x100(R9) - CACHE HIT_INVALIDATE_I, 0x180(R9) + CACHE HIT_INVALIDATE_I, 0(R12) + CACHE HIT_INVALIDATE_I, 0x80(R12) + CACHE HIT_INVALIDATE_I, 0x100(R12) + CACHE HIT_INVALIDATE_I, 0x180(R12) ADD $4, R8 ADD $4, R9 + ADD $4, R12 ADDU $-1, R10 BGTZ R10,loop From 9aa6f2dcccef09c13e7b399c44c21ea12ea22a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timur=20=C3=87elik?= Date: Fri, 9 May 2025 14:33:05 +0200 Subject: [PATCH 4/7] mips64: Fix handling of interrupts >= IRQ5 --- src/cmd/link/internal/mips64/asm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/link/internal/mips64/asm.go b/src/cmd/link/internal/mips64/asm.go index d690a626dba6a0..d91fc6f98b0265 100644 --- a/src/cmd/link/internal/mips64/asm.go +++ b/src/cmd/link/internal/mips64/asm.go @@ -85,7 +85,7 @@ func gentext_noos(ctxt *ld.Link, ldr *loader.Loader) { // search for user defined ISRs: //go:linkname functionName IRQ%d_Handler // This code tries to keep runtime.vectors small, by cutting off all irq // at the end that point to runtime.unhandledExternalInterrupt. - var irqHandlers [5]loader.Sym + var irqHandlers [8]loader.Sym irqNum := 1 for i := 1; i < len(irqHandlers); i++ { s := lookupFuncSym(ldr, ld.InterruptHandler(i)) From e78cfa2d7922ab591f78138589e2c8beae689c12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timur=20=C3=87elik?= Date: Fri, 9 May 2025 14:39:31 +0200 Subject: [PATCH 5/7] mips64: Fix disabling of interrupts Disabling of interrupts was broken since after the call to sysirqctl(), the STATUS register would be restored from exception context saved on the stack. The globalIRQMask is now stored separately and always used to restore the mask for external interrupts. As a side-effect, the system will now boot with all external interrupts disabled and waits for the user application to enable them. --- src/runtime/rt0_noos_mips64.s | 3 +-- src/runtime/tasker_noos_mips64.go | 11 +++++++---- src/runtime/tasker_noos_mips64.s | 22 ++++++++++++++++++++-- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/runtime/rt0_noos_mips64.s b/src/runtime/rt0_noos_mips64.s index 5d2871db5acc93..facd3026b897eb 100644 --- a/src/runtime/rt0_noos_mips64.s +++ b/src/runtime/rt0_noos_mips64.s @@ -160,10 +160,9 @@ TEXT runtime·rt0_go(SB),NOSPLIT|NOFRAME|TOPFRAME,$0 ADD $16, R29 // enable interrupts - // TODO where to enable interupts correctly? MOVW R0, M(C0_COMPARE) MOVW M(C0_SR), R8 - OR $(SR_IE|INTR_SW|INTR_EXT), R8 + OR $(SR_IE|INTR_SW), R8 MOVW R8, M(C0_SR) // start this M diff --git a/src/runtime/tasker_noos_mips64.go b/src/runtime/tasker_noos_mips64.go index cebc3539e52df8..5cfec28e6c0826 100644 --- a/src/runtime/tasker_noos_mips64.go +++ b/src/runtime/tasker_noos_mips64.go @@ -112,7 +112,10 @@ func syscachemaint(op int, p unsafe.Pointer, size int) { } } -var highPrioIRQMask uint32 +var ( + globalIRQMask uint32 + highPrioIRQMask uint32 +) func sysirqctl(irq, ctl, ctxid int) (enabled, prio, errno int) { if uint(irq) > 8 { // TODO PIC dependent @@ -132,14 +135,14 @@ func sysirqctl(irq, ctl, ctxid int) (enabled, prio, errno int) { } else if ctl > 0 { atomic.Or32(&highPrioIRQMask, irqMask) // set prio to high } - creg.STATUS.SetBits(irqMask) + atomic.Or32(&globalIRQMask, irqMask) case ctl == -2: // disable IRQ - creg.STATUS.ClearBits(irqMask) + atomic.And32(&globalIRQMask, ^irqMask) default: // -3, IRQ status if irqMask&atomic.Load(&highPrioIRQMask) != 0 { prio = 1 } - if creg.STATUS.LoadBits(irqMask) != 0 { + if atomic.Load(&globalIRQMask)&irqMask != 0 { enabled = 1 } } diff --git a/src/runtime/tasker_noos_mips64.s b/src/runtime/tasker_noos_mips64.s index a7c33db906cfc8..6dc55913257950 100644 --- a/src/runtime/tasker_noos_mips64.s +++ b/src/runtime/tasker_noos_mips64.s @@ -184,7 +184,7 @@ TEXT runtime·syscallHandler(SB),NOSPLIT|NOFRAME,$0 currentStack: BGTZ R4, badSyscall // slow syscall from handler - ADD $excCtxSize, R29, R1 // duffcopy src handler + ADD $excCtxSize, R29, R1 // duffcopy src duffcopy: // 3 extra registers to preserve src, dst and size of result @@ -287,6 +287,10 @@ TEXT runtime·enterScheduler(SB),NOSPLIT|NOFRAME,$0 // Restore mstatus from exception context MOVV _mstatus(R29), R1 + AND $~INTR_EXT, R1 + MOVW ·globalIRQMask(SB), R2 + AND $INTR_EXT, R2 + OR R2, R1 MOVV R1, M(C0_SR) ADD $excCtxSize, R29 @@ -406,6 +410,10 @@ fatal: TEXT runtime·exceptionReturn(SB),NOSPLIT|NOFRAME,$0 MOVV _mstatus(R29), R26 + AND $~INTR_EXT, R26 + MOVW ·globalIRQMask(SB), R27 + AND $INTR_EXT, R27 + OR R27, R26 MOVV R26, M(C0_SR) MOVV _lr(R29), R26 MOVV $~1, R27 @@ -420,9 +428,19 @@ TEXT runtime·exceptionReturn(SB),NOSPLIT|NOFRAME,$0 ADD $excCtxSize, R29 - // Don't switch stacks yet if we were called from handler + // Don't restore interrupt mask or switch stacks yet if we were called + // from handler BNE R27, R0, return + MOVW M(C0_SR), R26 + MOVW $~INTR_EXT, R27 + AND R27, R26 + MOVW $·globalIRQMask(SB), R27 + MOVW (R27), R27 + AND $INTR_EXT, R27 + OR R27, R26 + MOVW R26, M(C0_SR) + MOVV $·cpu0(SB), R26 MOVV (g_sched+gobuf_sp)(R26), R29 MOVV (g_sched+gobuf_g)(R26), g From e02c09b33d873f9f0aa4dd0931799bc91b43fc6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timur=20=C3=87elik?= Date: Sat, 10 May 2025 22:19:06 +0200 Subject: [PATCH 6/7] mips64: Don't store REGTMP with GPRS REGTMP is the scratch register used by the assembler. Saving it with GPRS is bad because one needs to be extra careful writing assembly that won't clobber REGTMP as long as it's not saved or after it's restored. Instead try to save it as early and restore it as late as possible to prevent bugs, that will only be visible in the disassembly. --- src/runtime/tasker_noos_mips64.go | 8 ++--- src/runtime/tasker_noos_mips64.s | 56 ++++++++++++++++++------------- 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/src/runtime/tasker_noos_mips64.go b/src/runtime/tasker_noos_mips64.go index 5cfec28e6c0826..e583a3a3f32740 100644 --- a/src/runtime/tasker_noos_mips64.go +++ b/src/runtime/tasker_noos_mips64.go @@ -24,15 +24,15 @@ import ( // See saveGPRS and saveFPRS const ( - numGPRS = 28 + numGPRS = 27 numFPRS = 33 ) type mOS struct { // thread context - gprs [numGPRS]uintptr - fprs [numFPRS]float64 - sp, fp, ra, epc uintptr + gprs [numGPRS]uintptr + fprs [numFPRS]float64 + sp, fp, ra, epc, tmp uintptr } var ( diff --git a/src/runtime/tasker_noos_mips64.s b/src/runtime/tasker_noos_mips64.s index 6dc55913257950..0de120e5905aaa 100644 --- a/src/runtime/tasker_noos_mips64.s +++ b/src/runtime/tasker_noos_mips64.s @@ -46,7 +46,8 @@ #define _lr (0*8) #define _mstatus (1*8) #define _mepc (2*8) -#define excCtxSize (3*8) +#define _mregtmp (3*8) +#define excCtxSize (4*8) // This will be copied into the processor's general exception vector. Since the @@ -69,6 +70,9 @@ TEXT runtime·intvector(SB),NOSPLIT|NOFRAME,$0 // Only syscalls and interrupts are handled at the moment, all other exceptions // are fatal. TEXT runtime·exceptionHandler(SB),NOSPLIT|NOFRAME,$0 + // Be especially careful to not clobber REGTMP with multi-instruction + // statements until it's saved on the stack. + // Determine caller stack MOVV $·cpu0(SB), R26 BNE R26, g, fromThread @@ -89,6 +93,7 @@ fromThread: fromHandler: // Save exception context on ISR stack SUB $excCtxSize, R29 + MOVV R23, _mregtmp(R29) // R23 (REGTMP) is now free for use OR $1, R31, R26 // Encode smallCtx flag in lr MOVV R26, _lr(R29) // R29 is now free for use MOVV M(C0_SR), R26 @@ -170,7 +175,8 @@ TEXT runtime·syscallHandler(SB),NOSPLIT|NOFRAME,$0 MOVV _lr(R29), R3 MOVV R3, (m_mOS+mOS_ra)(R2) - + MOVV _mregtmp(R29), R3 + MOVV R3, (m_mOS+mOS_tmp)(R2) MOVV _mepc(R29), R3 AND $~1, R3 // Remove fromHandler flag from epc MOVV R3, (m_mOS+mOS_epc)(R2) @@ -249,6 +255,9 @@ TEXT runtime·softwareInterruptHandler(SB),NOSPLIT|NOFRAME,$0 // Save thread context in mOS MOVV (cpuctx_exe)(g), R27 + MOVV _mregtmp(R29), R26 + MOVV R26, (m_mOS+mOS_tmp)(R27) + MOVV _lr(R29), R26 AND $~1, R26 // Remove smallCtx flag from lr MOVV R26, (m_mOS+mOS_ra)(R27) @@ -315,8 +324,8 @@ smallCtx: MOVV (m_mOS+mOS_ra)(R27), R31 MOVV (m_mOS+mOS_epc)(R27), R26 MOVV R26, M(C0_EPC) - MOVV $~1, R27 - AND R27, R31 // Remove smallCtx flag + AND $~1, R31 // Remove smallCtx flag + MOVV (m_mOS+mOS_tmp)(R27), R23 ERET @@ -426,11 +435,9 @@ TEXT runtime·exceptionReturn(SB),NOSPLIT|NOFRAME,$0 MOVV $1, R27 AND R26, R27 - ADD $excCtxSize, R29 - // Don't restore interrupt mask or switch stacks yet if we were called // from handler - BNE R27, R0, return + BNE R27, R0, fromHandler MOVW M(C0_SR), R26 MOVW $~INTR_EXT, R27 @@ -441,11 +448,18 @@ TEXT runtime·exceptionReturn(SB),NOSPLIT|NOFRAME,$0 OR R27, R26 MOVW R26, M(C0_SR) + MOVV _mregtmp(R29), R23 + ADD $excCtxSize, R29 MOVV $·cpu0(SB), R26 MOVV (g_sched+gobuf_sp)(R26), R29 MOVV (g_sched+gobuf_g)(R26), g -return: + ERET + +fromHandler: + MOVV _mregtmp(R29), R23 + ADD $excCtxSize, R29 + ERET @@ -478,29 +492,25 @@ TEXT ·saveGPRs(SB),NOSPLIT|NOFRAME,$0 MOVV R20, 152(R26) MOVV R21, 160(R26) MOVV R22, 168(R26) - MOVV R23, 176(R26) - MOVV R24, 184(R26) - MOVV R25, 192(R26) - MOVV RSB, 200(R26) + MOVV R24, 176(R26) + MOVV R25, 184(R26) + MOVV RSB, 192(R26) MOVV HI, R1 - MOVV R1, 208(R26) + MOVV R1, 200(R26) MOVV LO, R1 - MOVV R1, 216(R26) + MOVV R1, 208(R26) RET -// R26 must point to stored gprs. Only use R26, R27 after restoring. Be -// especially careful and look at the disassembly; The assembler might decide -// to use R16-R23 for you. +// R26 must point to stored gprs. Only use R26, R27 after restoring. TEXT ·restoreGPRs(SB),NOSPLIT|NOFRAME,$0 - MOVV 216(R26), R1 - MOVV R1, LO MOVV 208(R26), R1 + MOVV R1, LO + MOVV 200(R26), R1 MOVV R1, HI - MOVV 200(R26), RSB - MOVV 192(R26), R25 - MOVV 184(R26), R24 - MOVV 176(R26), R23 + MOVV 192(R26), RSB + MOVV 184(R26), R25 + MOVV 176(R26), R24 MOVV 168(R26), R22 MOVV 160(R26), R21 MOVV 152(R26), R20 From 83523f269073bd2536d0c37dd2a668abcffab05d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timur=20=C3=87elik?= Date: Sat, 10 May 2025 22:42:32 +0200 Subject: [PATCH 7/7] mips64: Simplify a bit now that we can use REGTMP --- src/runtime/tasker_noos_mips64.s | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/runtime/tasker_noos_mips64.s b/src/runtime/tasker_noos_mips64.s index 0de120e5905aaa..672b0865ba6303 100644 --- a/src/runtime/tasker_noos_mips64.s +++ b/src/runtime/tasker_noos_mips64.s @@ -424,26 +424,21 @@ TEXT runtime·exceptionReturn(SB),NOSPLIT|NOFRAME,$0 AND $INTR_EXT, R27 OR R27, R26 MOVV R26, M(C0_SR) - MOVV _lr(R29), R26 - MOVV $~1, R27 - AND R27, R26, R31 // Remove smallCtx flag from lr + MOVV _lr(R29), R31 + AND $~1, R31 // Remove smallCtx flag from lr MOVV _mepc(R29), R26 - MOVV $~1, R27 - AND R26, R27 // Remove fromHandler flag from EPC + AND $~1, R26, R27 // Remove fromHandler flag from EPC MOVV R27, M(C0_EPC) - MOVV $1, R27 - AND R26, R27 + AND $1, R26, R27 // Don't restore interrupt mask or switch stacks yet if we were called // from handler BNE R27, R0, fromHandler MOVW M(C0_SR), R26 - MOVW $~INTR_EXT, R27 - AND R27, R26 - MOVW $·globalIRQMask(SB), R27 - MOVW (R27), R27 + AND $~INTR_EXT, R26 + MOVW ·globalIRQMask(SB), R27 AND $INTR_EXT, R27 OR R27, R26 MOVW R26, M(C0_SR)