捉虫日记 0001: Cache initialize issue on 4KEc (MIPS32r2)
1 Phenomenon
Initialize the 4KEc's cache like following code in head.S:
li a0, 0x2000 # icache size is 8KB lui a2, 0x8000 addu a3, a2, a0 21: cache Index_Store_Tag_I, 0(a2) addiu a2, 16 ble a2, a3, 21b nop /* setup dcache */ lui a2, 0x8000 li a0, 0x2000 # dcache size is also 8KB addu a3, a2, a0 22: cache Index_Store_Tag_D, 0(a2) addiu a2, 16 ble a2, a3, 22b nop
Above code defined in kernel_entry_setup (include/asm/mach-emma3p/kernel-entry-init.h)
The kernel can not boot up properly (No printk out, serial console can not be used).
2 Analysis
- Removed the setup_cache code the kernel can boot up properly.
- Add Led support(asm) for indicating where the executing point is. By this way I found that the head.S executed properly but when executing stream enter the start_kernel the kernel would enter an unknown path.
- Think about the cache initializing code issue
Modify the icache initializing like this:
Index_Store_Tag_I ---> Fill ---> Index_Store_Tag_I
li a0, 0x2000 lui a2, 0x8000 addu a3, a2, a0 move k0, a2 21: cache Index_Store_Tag_I, 0(a2) addiu a2, 16 ble a2, a3, 21b nop 20: cache Fill, 0(k0) addiu k0, 16 ble k0, a3, 20b nop li a2, KSEG0 25: cache Index_Store_Tag_I, 0(a2) addiu a2, 16 ble a2, a3, 25b nop
Modify the dcache initializing code like this:
Index_Store_Tag_D ---> load ---> Index_Store_Tag_D
lui a2, 0x8000 li a0, 0x2000 addu a3, a2, a0 move k0, a2 22: cache Index_Store_Tag_D, 0(a2) addiu a2, 16 ble a2, a3, 22b nop 23: lw t3, 0(k0) addiu k0, 16 ble k0, a3, 23b nop lui a2, 0x8000 24: cache Index_Store_Tag_D, 0(a2) addiu a2, 16 ble a2, a3, 24b nop
The issue is also exist.
- Doubt the Index_* cache ops function
Add the following initializing code:
/* initialize way select array */ li k0, 0x0400 # TagLo[15:10] is LRU bit mtc0 k0, CP0_TAGLO /* enable ws */ lui k0, 0x2000 mtc0 k0, $26 # CP0_ErrCtl ssnop ssnop ssnop sll zero, 3 li a0, 0x1000 li a2, KSEG0 addu a3, a2, a0 /* set way select value is 1 */ 28: cache Index_Store_Tag_I, 0(a2) cache Index_Store_Tag_D, 0(a2) addu a2, 16 bne a2, a3, 28b nop mtc0 zero, CP0_TAGLO /* clear way 1 tag */ li a0, 0x1000 li a2, KSEG0 addu a3, a2, a0 28: cache Index_Store_Tag_I, 0(a2) cache Index_Store_Tag_D, 0(k0) addu a2, 16 bne a2, a3, 28b nop /* disable ws */ mtc0 zero, $26 ssnop ssnop ssnop sll zero, 3
The issue is also exist.
- By Chance
When I enable_cached in the end of setup_cache macro and disable_cached before the j start_kernel the kernel can boot up properly.
I moved the enable_cached/disable_cached pair and found that the issue is disappear so long as the pair braket following code block:
enable_cached LONG_S a0, fw_arg0 # firmware arguments LONG_S a1, fw_arg1 LONG_S a2, fw_arg2 LONG_S a3, fw_arg3 disable_cached
I reviewed the setup_cp0 and setup_cache macro defined in include/asm-mips/mach-emma3p/subcore-init.h and found that they use the a0, a2 and a3 register and these vaules is also up 0x8000_0000. So the kernel get the incorrect value and make the kernel enter an unknown path.
3 Solution
Don't use these register before they are saved in fw_argx.