Monday, July 19, 2010

tlb_flush needs patch, what the reason?

Without following #ifdef CPU_OCTEON, TLBWI throw MCHECK Exception.
According simulator trace log, in 2nd time of TLBWI va is zero.
Probably that means we need rewrite TLB_HI after TLBWI, but dmtc0 v0, COP_0_TLB_HI is not enough, addu v0, v0, 8 * 1024 is required.
Maybe same address on more than 2 entries is not allowed on OCTEON(or MIPS64R2)?
I just borrowed these codes from FreeBSD/mips, not quite sure the meaning...


LEAF(tlb_flush, 0)
mfc0 v1, COP_0_STATUS_REG # Save the status register.
ori v0, v1, SR_INT_ENAB
xori v0, v0, SR_INT_ENAB
mtc0 v0, COP_0_STATUS_REG # Disable interrupts
ITLBNOPFIX
mfc0 ta1, COP_0_TLB_WIRED


LA v0, CKSEG0_BASE # invalid address
dmfc0 ta0, COP_0_TLB_HI # Save the PID

dmtc0 v0, COP_0_TLB_HI # Mark entry high as invalid
dmtc0 zero, COP_0_TLB_LO0 # Zero out low entry0.
dmtc0 zero, COP_0_TLB_LO1 # Zero out low entry1.
mtc0 zero, COP_0_TLB_PG_MASK # Zero out mask entry.
/*
 * Align the starting value (ta1) and the upper bound (a0).
 */
1:
mtc0 ta1, COP_0_TLB_INDEX # Set the index register.
#ifdef CPU_OCTEON
ITLBNOPFIX
dmtc0 v0, COP_0_TLB_HI # Mark entry high as invalid
#endif
addu ta1, ta1, 1 # Increment index.
#ifdef CPU_OCTEON
addu v0, v0, 8 * 1024
#endif
nop
nop
nop
tlbwi # Write the TLB entry.
nop
nop
bne ta1, a0, 1b
nop

#ifdef CPU_LOONGSON2
li v0, COP_0_DIAG_ITLB_CLEAR | COP_0_DIAG_BTB_CLEAR | COP_0_DIAG_RAS_DISABLE
dmtc0 v0, COP_0_DIAG
#endif

dmtc0 ta0, COP_0_TLB_HI # Restore the PID
li a0, TLB_PAGE_MASK
mtc0 a0, COP_0_TLB_PG_MASK # Restore default mask value.
mtc0 v1, COP_0_STATUS_REG # Restore the status register
ITLBNOPFIX
j ra
nop
END(tlb_flush)

No comments:

Post a Comment