捉虫日记 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.