64-bit multi-core MIPS exception and interrupt kernel code analysis (3)
Analysis of RMI xlr732tlb related processing functions
0. Background
The virtual address space in mips64 is divided:
The kernel space is xkphys and xkseg, and xkphys are fixed mappings without TLB (unmapped)
The user space is xuseg.
1. Rmi xlr732 TLB refill handler Analysis
@ 0 xFFFF FFFF 8000 0000
C: 07610005 bgez K1, 24 <0x24>/* If vaddr [61]! = 1 (0xc000 0000 0000 0000 ~ 0 xdfff FFFF), Branch */
10: 3c1bc000 lui K1, 0xc000 -----> at delay slot, commit new value to K1 after reading K1 (bgez)
# Vaddr is at 0xe000000000000000 ~ 0 xFFFF FFFF. kseg2 is used by 64-bit Linux kernel and must pass through TLB. This address is used by kernel modules by default.
14: 035bd02f dsubu K0, K0, K1/* K0 = vaddr-0 xFFFF FFFF c0000000 */
18: 3c1b8396 lui K1, 0x8396
1c: 10000023 B AC <0xac> ----> @@@
20: 277ba000 addiu K1, K1,-24576/* 0 xFFFF FFFF 8395a000 = module_pg_dir, using the module_pg_dir as the PGD entry */
# Vaddr is at 0xc00000000000 ~ 0 xdfff FFFF
24: 001bd83c dsll32 K1, K1, 0x0/* (0 xFFFF FFFF c0000000 <32 )*/
28: 035bd02f dsubu K0, K0, K1/* K0 = vaddr-0xc00000000000 */
2c: 1000001f B AC <0xac> ----> @@@
30: 3c1b8396 lui K1, 0x8396/* 0 xFFFF FFFF 83960000 = swapper_pg_current, using the swapper_pg_current as the PGD entry */
34: 00000000
38: 00000000 <repeat>
......
@ 0 xFFFF FFFF 8000 0080 (xtlb refill entry)
8c: 403a4000 dmfc0 K0, c0_badvaddr
90: 0740001a BLTZ K0, FC <0xfc>/* If badvaddr> = 0x80000000 00000000 Branch */
# Vaddr is <0x8000 0000 0000 000, So it's at kuseg
94: 403b2000 dmfc0 K1, c0_context
98: 001 bddfa dsrl K1, K1, 0x17/* Get (smp_processor_id () <3) (26-23), see ASM/mmu_context.h */
9C: 3c1a8396 lui K0, 0x8396/* swapper_pg_current = 0 xFFFF FFFF 83960000 */
A0: 037ad82d daddu K1, K1, K0/* k1 = swapper_pg_current [smp_processor_id ()] */
A4: 403a4000 dmfc0 K0, c0_badvaddr
A8: df7b2000 LD K1, 8192 (K1 )/*
* PGD = * (void *) (K1 + 8192), 8 bytes per PGD entry, pgd_current = 0 xFFFF FFFF 8396 2000,
X 0x2000 = 8192
* Actually it's PGD = pgd_current [smp_processor_id ()]
*/
@@@
AC: 001ad6fa dsrl K0, K0, 0x1b #> 27
B0: 335a1ff8 Andi K0, K0, 0x1ff8/* Get (vaddr [39: 30] <3), for indexing PGD */
B4: 037ad82d daddu K1, K1, K0/* index PGD */
B8: 403a4000 dmfc0 K0, c0_badvaddr
BC: df7b0000 LD K1, 0 (K1)/* Get p_pmd */
C0: 001ad4ba dsrl K0, K0, 0x12
C4: 335a0ff8 Andi K0, K0, 0xff8/* Get (vaddr [29:21] <3), for indexing PMD */
C8: 037ad82d daddu K1, K1, K0/* index PMD */
Cc: 403aa000 dmfc0 K0, c0_xcontext
D0: df7b0000 LD K1, 0 (K1)/* Get p_pt */
D4: 335a0ff0 Andi K0, K0, 0xff0/* Get (va [20: 13] <4), actually use va [20: 12] index the PT, VA [12] = 0, for indexing Pt */
D8: 037ad82d daddu K1, K1, K0/* index Pt */
DC: df7a0000 LD K0, 0 (K1)/* Get Even page ADDR */<-------------
E0: df7b0008 LD K1, 8 (K1)/* get odd page ADDR */
E4: 001ad1ba dsrl K0, K0, 0x6/* ignore the low 6 bits, it's for OS */
E8: 409a1000 mtc0 K0, c0_entrylo0/* TLB even page entry */
EC: 001bd9ba dsrl K1, K1, 0x6/* same as abve */
F0: 409b1800 mtc0 K1, c0_entrylo1/* TLB odd page entry */
F4: 42000006 tlbwr/* random write TLB */
F8: 42000018 eret
# Go here, vaddr is> = 0x8000 0000 0000, so it's in xkphys or xkseg; and 0x0000 8000 0000 0000 ~ 0 xbfff FFFF is xkphys, unmapped, do not index TLB, so vaddr is at 0xc000 0000 0000 0000
FC: 001ad8b8 dsll K1, K0, 0x2 # vaddr <2, will be test the vaddr [61]
100: 1000ffc2 B C <0xc>
104: 00000000 NOP
108: 00000000 NOP
2. Rmi xlr732 handle_tlbl Analysis
Handle_tlbl:
C: 403a4000 dmfc0 K0, c0_badvaddr <---- handle_tlbl start
10: 07400027 BLTZ K0, B0 <0xb0> # If badvaddr> = 0x80000000 00000000 Branch
14: 403b2000 dmfc0 K1, c0_context
18: 001 bddfa dsrl K1, K1, 0x17/* Get (smp_processor_id () <3) (26-23 )*/
1c: 3c1a8396 lui K0, 0x8396/* 0xffffffff83960000 + 0x2000 = pgd_current */
20: 037ad82d daddu K1, K1, K0
24: 403a4000 dmfc0 K0, c0_badvaddr
28: df7b2000 LD K1, 8192 (K1)/* PGD = pgd_current [smp_processor_id ()] */
@@
2c: 001ad6fa dsrl K0, K0, 0x1b #> 27
30: 335a1ff8 Andi K0, K0, 0x1ff8/* Get (vaddr [39: 30] <3), for indexing PGD */
34: 037ad82d daddu K1, K1, K0/* index PGD */
38: 403a4000 dmfc0 K0, c0_badvaddr
3c: df7b0000 LD K1, 0 (K1)/* Get PMD */
40: 001ad4ba dsrl K0, K0, 0x12 #> 18
44: 335a0ff8 Andi K0, K0, 0xff8 # Get (vaddr [29:21] <3)
48: 037ad82d daddu K1, K1, K0 # index PMD
4c: 403a4000 dmfc0 K0, c0_badvaddr
50: df7b0000 LD K1, 0 (K1) # Get p_pt
54: 001ad27a dsrl K0, K0, 0x9
58: 335a0ff8 Andi K0, K0, 0xff8 # Get (vaddr [20:12])
5C: 037ad82d daddu K1, K1, K0 # index PT
60: d37a0000 LLD K0, 0 (K1) # Get PT entry
64: 42000008 tlbp # To distinguish TLB invalid or TLB refill exception
68: 335a0003 Andi K0, K0, 0x3
6c: 3b5a0003 xori K0, K0, 0x3 # _ present and _ read
70: 1740001a bnez K0, DC <0xdc> # Low two bits is not 011, Branch --> out
74: d37a0000 LLD K0, 0 (K1) # Get PT entry again
78: 375a0088 Ori K0, K0, 0x88
7c: f37a0000 SCD K0, 0 (K1) # Set PT entry's PTE [7] = 1, PTE [3] = 1
80: 1340fff7 beqz K0, 60 <0x60>
84: 00000000 NOP
88: 377b0008 Ori K1, K1, 0x8
8c: 3b7b0008 xori K1, K1, 0x8 # For getting even page
90: df7a0000 LD K0, 0 (K1) # Get Even page ADDR
94: df7b0008 LD K1, 8 (K1) # Get odd page ADDR
98: 001ad1ba dsrl K0, K0, 0x6
9C: 409a1000 mtc0 K0, c0_entrylo0
A0: 001bd9ba dsrl K1, K1, 0x6
A4: 409b1800 mtc0 K1, c0_entrylo1
A8: 42000002 tlbwi
AC: 42000018 eret
@@
B0: 001ad8b8 dsll K1, K0, 0x2 # Go here, vaddr is in xkphys or xkseg (> 0x8000.. 0000)
#0x8000... 0000 ~ 0xc000 .. 0000 is xkphys, unmapped,
# So vaddr> 0xc000 .. 0000; vaddr <2
B4: 07610005 bgez K1, CC <0xcc>
# Vaddr [61]! = 1 (0xc000... 0000 ~ 0xdfff .. FFFF), Branch
B8: 3c1bc000 lui K1, 0xc000
# Vaddr, 0xe000... 0000 ~ 0xffff .. FFFF
BC: 035bd02f dsubu K0, K0, K1 # K0 = vaddr-0xffffffffc0000000
C0: 3c1b8396 lui K1, 0x8396
C4: 1000ffd9 B 2C <0x2c>
C8: 277ba000 addiu K1, K1,-24576 # k1 = 0xffffffff8395a000, module_pg_dir
# Module_pg_dir & swapper_pg_dir don't need the SMP
@@
# Vaddr, 0xc000... 0000 ~ 0xdfff .. FFFF
Cc: 001bd83c dsll32 K1, K1, 0x0 #0xc0000000 00000000
D0: 035bd02f dsubu K0, K0, K1 # K0 = vaddr-0xc0000000 00000000
D4: 1000ffd5 B 2C <0x2c>
D8: 3c1b8396 lui K1, 0x8396 # Only swapper_pg_current
@ --> Do_page_fault
DC: 08d01150 J 3404540 <0 x3404540>
E0: 00000000 NOP
...