查看64位多核 MIPS 异常和中断内核代码分析 (1)的源代码
←
64位多核 MIPS 异常和中断内核代码分析 (1)
跳转到:
导航
,
搜索
因为以下原因,你没有权限编辑本页:
您刚才请求的操作只有这个用户组中的用户才能使用:
用户
您可以查看并复制此页面的源代码:
==== EXL=0 时 TLB Refill 的处理 ==== ===== Cavium Octeon ===== 这个的处理函数,在 Cavium Octeon 上位于 0xFFFF FFFF 8000 1080 处,但往往这个处理函数都会超过 0x80 字节,所以动态生成过程就使用原来 32 位的入口空间再放一部分代码,在 64 位下,这个 32 位的 TLB Refill 入口空间是不用的: <source lang=c> 0xFFFF FFFF 8000 1000: c: 07410003 bgez k0,1c <0x1c> # badvaddr >= 0,即 badvaddr 低 40 位以上有货,最高位不为 1,即在 0x0 ~ 0x7FFF FFFF FFFF FFFF (xuseg or xsseg) 中时则跳转。一句话就是去处理位于 xuseg or xsseg 的异常地址 10: 3c1b817c lui k1,0x817c # 位于延迟槽,总是被执行。0xFFFF FFFF 817c 0000 #badvaddr低 40 位以上不为 0 且不位于 xuseg 或 xsseg 中,又走 TLB,则其应为位于 xkseg,范围为 0xC000 0000 0000 0000 ~ 0xFFFF FFFF FFFF FFFF。一句话就是去处理位于 xkseg 中的地址 14: 10000024 b a8 <0xa8> ----->@@@ k1 = 0xFFFF FFFF 817B E000, it's swapper_pg_dir, 他是内核使用的除模块以外的 PGD 基地址,内核模块使用 18: 277be000 addiu k1,k1,-8192 # 位于延迟槽,总是被执行。0xFFFF FFFF 817c 0000 - 8192 = 0xFFFF FFFF 817B E000 #badvaddr 低 40 位以上不为 0 且位于 0x0 ~ 0x7FFF FFFF FFFF FFFF ( xuseg or xsseg) 1c: 3c1b8110 lui k1,0x8110 20: 277b4e00 addiu k1,k1,19968 # k1 = 0xFFFF FFFF 8110 4E00, tlb_do_page_fault_0 24: 03600008 jr k1 # call tlb_do_page_fault_0 28: 00000000 nop ... 0xFFFF FFFF 8000 1080: 8c: 403a4000 dmfc0 k0,c0_badvaddr # 取转换失败的虚拟地址 VA,TLB Refill 异常下,cp0_badvaddr (MIPS64 下,64 位长)存放翻译失败的虚拟地址 90: 001ada3e dsrl32 k1,k0,0x8 # VA 逻辑右移 (32+8)位,置入 k1 94: 1760ffdd bnez k1,c <0xc> # k1 不为 0 则跳转到 0xc 处。即 badvaddr[63:41] 不为 0,即高于 40 位不为 0,就跳转。 </source> 对于这种高于 40 位还有有效位的虚拟地址,要不他位于 xkseg,要不就是 xuseg/xsseg 的地址。对于 xkseg 的地址,有有效的地址这是确定的(MIPS32 兼容地址空间内核是用的,高于 40 位的部分都不为 0)。 MIPS64 R2 下,segbit 默认为 40,但具体实现时,MIPS Core 的 segbit 可以超过 40,即实现的真正有效的虚拟地址可以超过 40 位 对只实现 40 位 segbit,出现位于 xuseg/xsseg 的地址且高于 40 位不为 0 的话,这个地址肯定就是用户瞎访问,其就不是一个有效地址,进 do_page_fault() 然后 segment fault 即可 但对实现超过 40 位的 segbit,像 Cavium Octeon CN38xx 实现 49 位,则需要特别对待,因为 4KB 的页大小下,Linux/MIPS 设计时规定整个虚拟地址的有效位是低 40 位,高于 40 的虚拟地址空间,内核没有为之建立页表,即没有映射!虽然你实现了 49 位虚拟地址,但我 Linux 还是用不了,最终也要进入 do_page_fault() 进行处理 <source lang=c> # badvaddr 高于 40 位为 0 98: 403b2000 dmfc0 k1,c0_context # 取 cp0_context 值入 k1 9c: 7c1bb007 dins k1,zero,0x0,0x17 # zero[22:0] 替换 k1[22:0],k1 低 23 位置 0; # 留意:cp0_context[22:4] 是硬件拷贝自 cp0_badvaddr[31:13] # cp0_context[63:23] 是 PGD 的物理地址入口 a0: 377b0540 ori k1,k1,0x540 # 0x540 置入 k1 的低位 a4: 003bdafa dror k1,k1,0xb # drotr k1, k1, 11,即 k1 的低 11 位,和 k1 的高 53 位交换;k1 = k1[10:0] | k1[63:11] 上两条指令实际上是让 0b101 0100 0000 (0x540)或上 k1 的高 11 位,相当于 0xA800 0000 0000 0000 + Phy_PGD_ADDR,其是 PGD 的基地址 @@@ k1 中是 PGD 的基地址 a8: 001ad6fa dsrl k0,k0,0x1b # k0 右移 27 位 ac: 335a1ff8 andi k0,k0,0x1ff8 # 再保留 k0[12:3],实际保留的是 cp0_badvaddr[39:30] 正好是 PGD 的索引值,此时 k0 = cp0_badvaddr[39:30] << 3,64 位下 PGD 的项大小为 2^3 = 8 字节,因此其恰是索引 PGD 的指针 b0: 037ad82d daddu k1,k1,k0 # 获取 VA 对应的 PGD 项,即 VA 对应 PMD 基址的指针 b4: 403a4000 dmfc0 k0,c0_badvaddr # 取转换失败的虚拟地址 VA b8: df7b0000 ld k1,0(k1) # 取对应 PMD 基址 bc: 001ad4ba dsrl k0,k0,0x12 # 右移 18 位 c0: 335a0ff8 andi k0,k0,0xff8 # 保留 k0[12:3],实际是 cp0_badvaddr[29:21] << 3,正好是 PMD 的索引指针,PMD 的项大小也是 2^3 = 8 字节 c4: 037ad82d daddu k1,k1,k0 # 索引 PMD,指向 VA 对应之 PT 基址 c8: 403aa000 dmfc0 k0,c0_xcontext # 取 cp0_xcontext 值,Cavium Octeon 上,BadVPN2 是 xcontext[39:4],置 badvaddr[48:13] cc: df7b0000 ld k1,0(k1) # 取 PT 基址 d0: 335a0ff0 andi k0,k0,0xff0 # 保留 xcontext 的位 11:4,实际为 cp0_badvaddr[20:13] << (3 + 1),这实际为 PT 的索引值,因为 TLB Refill 总是一起填相邻的两项,因此这索引,实际是 VA 对应的偶数项索引 d4: 037ad82d daddu k1,k1,k0 # 索引 PT,指向 VA 对应之偶数项 PTE d8: df7a0000 ld k0,0(k1) # 取 VA 对应偶数项的 PTE dc: df7b0008 ld k1,8(k1) # 取 VA 对应奇数项的 PTE e0: 001ad13a dsrl k0,k0,0x4 # 忽略 PTE 的低 4 位,那是 OS 用的,TLB 的项里没有这些位 e4: 001bd93a dsrl k1,k1,0x4 e8: 003ad0ba dror k0,k0,0x2 # drotr k0, k0, 0x2,k0 低两位和高 62 位交换,这个操作和上面的右移 4 位应该是合起来的忽略 PTE 的低 6 位,因为在 MIPS64 R2 上,写入数据到 entrylo0/1[63:62] 是始终为 0 的。 ec: 40ba1000 dmtc0 k0,c0_entrylo0 # 偶数项 PTE 入 entrylo0 f0: 003bd8ba dror k1,k1,0x2 # 同上面偶数项的分析 f4: 40bb1800 dmtc0 k1,c0_entrylo1 # 奇数项PTE 入 entrylo1 f8: 42000006 tlbwr # 把 entrylo0, entrylo1 随机写入 TLB 的一项 fc: dc1a8078 ld k0,-32648(zero) 100: 42000018 eret ... </source> <br><br> ===== RMI XLR732 ===== <source lang=c> @0xFFFF FFFF 8000 0000 c: 07610005 bgez k1,24 <0x24> /* if vaddr[61] != 1 (0xc000 0000 0000 0000 ~ 0xDFFF FFFF FFFF FFFF), branch */ 10: 3c1bc000 lui k1,0xc000 -----> at delay slot, commit new value to k1 after reading k1 (bgez) # vaddr is at 0xE000000000000000 ~ 0xFFFF FFFF FFFF FFFF,这个地址段里被 64 bit Linux 内核使用且又要经过 TLB 的就是 kseg2 了,内核的模块默认使用这个地址 14: 035bd02f dsubu k0,k0,k1 /* k0 = vaddr - 0xFFFF FFFF C0000000 */ 18: 3c1b8396 lui k1,0x8396 1c: 10000023 b ac <0xac> ----> @@@ 20: 277ba000 addiu k1,k1,-24576 /* 0xFFFF FFFF 8395A000 = module_pg_dir , using the module_pg_dir as the PGD entry */ # vaddr is at 0xC000000000000000 ~ 0xDFFF FFFF FFFF FFFF 24: 001bd83c dsll32 k1,k1,0x0 /* (0xFFFF FFFF C0000000 << 32) */ 28: 035bd02f dsubu k0,k0,k1 /* k0 = vaddr - 0xC000000000000000 */ 2c: 1000001f b ac <0xac> ----> @@@ 30: 3c1b8396 lui k1,0x8396 /* 0xFFFF FFFF 83960000 = swapper_pg_current, using the swapper_pg_current as the PGD entry */ 34: 00000000 38: 00000000 <repeat> ...... @0xFFFF FFFF 8000 0080 (xTLB Refill 入口) 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: 001bddfa dsrl k1,k1,0x17 /* get (smp_processor_id() << 3) (26-23), see asm/mmu_context.h */ 9c: 3c1a8396 lui k0,0x8396 /* swapper_pg_current = 0xFFFF 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 = 0xFFFF FFFF 8396 2000, * 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 above */ 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 0000, so it's in xkphys or xkseg; and 0x8000 0000 0000 0000 ~ 0xBFFF FFFF FFFF 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 </source> <br><br>
返回到
64位多核 MIPS 异常和中断内核代码分析 (1)
。
个人工具
登录
名字空间
页面
讨论
变换
查看
阅读
查看源代码
查看历史
操作
搜索
导航
首页
社区专页
新闻动态
最近更改
随机页面
帮助
工具箱
链入页面
相关更改
特殊页面