Skip to content

Bug 7: Flush Trampoline Timeout

Category: Cache coherency Related docs: mips-memory-model, address-map

Symptom

The FLUSH_TRAMPOLINE—a small MIPS program using CACHE instructions to writeback-invalidate D-cache and I-cache lines—was loaded to the trampoline region and the CPU was resumed. The script waited for an SDBBP (debug breakpoint) at the end of the trampoline to signal completion. After 3 seconds, the wait timed out. The SDBBP was never hit.

Root Cause

The CACHE instruction is a coprocessor 0 (CP0) operation that requires specific privilege and exception vector configuration. The trampoline was loaded to KSEG1 (0xA0800000, uncached) and the CPU was resumed at that address.

The likely failure mode: executing a CACHE instruction while running from KSEG1, with exception vectors pointing to the Nandloader's handlers (not ours), causes a cache error exception or other CP0 exception. The Nandloader's exception handler either hangs or jumps to an unexpected location. Either way, execution never reaches the SDBBP at the end of the trampoline.

The exact failure mode is difficult to diagnose because the exception vectors are in NAND-loaded Cisco code that we do not control, and JTAG access to the CPU is limited while the exception handler is running.

Fix

Eliminated the need for CACHE instructions entirely by loading the binary to KSEG1 instead of KSEG0. Since KSEG1 is uncached, there are no D-cache lines to flush for the loaded data. The D_CACHE_FLUSH_TRAMPOLINE (which uses plain lw loads to evict stale lines via LRU replacement) replaced the FLUSH_TRAMPOLINE for the pre-load cache cleanup.

The FLUSH_TRAMPOLINE with CACHE instructions is still present in the code for belt-and-suspenders post-load use, but the critical path no longer depends on it.

Lesson

When a workaround (flushing the cache with CACHE instructions) fails due to environmental constraints (wrong exception vectors, privilege issues), question whether the root problem can be eliminated rather than worked around differently. Loading to KSEG1 removes the D-cache involvement entirely, making the flush unnecessary for the loaded data.