查看64位多核 MIPS 异常和中断内核代码分析 (1)的源代码
←
64位多核 MIPS 异常和中断内核代码分析 (1)
跳转到:
导航
,
搜索
因为以下原因,你没有权限编辑本页:
您刚才请求的操作只有这个用户组中的用户才能使用:
用户
您可以查看并复制此页面的源代码:
==== Cavium Octeon Cache Error ==== Cavium Octeon 的 Cache 错误处理和 2E 大同小异,只是处理过程多了些鲁棒性 其Cache Error 例外入口初始化,位于: <source lang=c> [arch/mips/mm/c-octeon.c] void __cpuinit octeon_cache_init(void) { extern unsigned long ebase; extern char except_vec2_octeon; memcpy((void *)(ebase + 0x100), &except_vec2_octeon, 0x80); octeon_flush_cache_sigtramp(ebase + 0x100); ...... } </source> 将例外处理函数 except_vec2_octeon 复制到 ebase + 0x100 处,在 Cavium 上 ebase 为: <source lang=c> [arch/mips/cavium-octeon/setup.c] uint32_t ebase = read_c0_ebase() & 0x3ffff000 </source> 实际就是 EBase 寄存器中的值,默认情形下,ebase = 0x8000 0000,ebase + 0x100 就是 0x8000 0180,即物理地址 0x100 处。因为使用 KSEG0 的虚拟地址访问,数据会被缓存,因此为了及时生效到内存,还要 flush 一下 cache。 另外在 64 位的处理器上使用 32 位的地址访问,处理器会自动将其扩展为 64 位,规则就是 32位高位符号扩展。0x8000 0180 最高位为 1,则会被扩展为 0xFFFF FFFF 8000 0180; 0x0000 0180 则会被扩展为 0x0000 0000 0000 0180 其中,Octeon 的 Cache Error 例外处理函数 except_vec2_octeon 定义于: <source lang=c> [arch/mips/mm/cex-oct.S] /* * Handle cache error. Indicate to the second level handler whether * the exception is recoverable. */ LEAF(except_vec2_octeon) /* due to an errata we need to read the COP0 CacheErr (Dcache) * before any cache/DRAM access */ rdhwr k0, $0 /* get core_id */ PTR_LA k1, cache_err_dcache sll k0, k0, 3 PTR_ADDU k1, k0, k1 /* k1 = &cache_err_dcache[core_id] */ dmfc0 k0, CP0_CACHEERR, 1 sd k0, (k1) dmtc0 $0, CP0_CACHEERR, 1 # 把 DCache_Error 寄存器的值存入 cache_err_dcache[core_id] 数组 /* check whether this is a nested exception */ mfc0 k1, CP0_STATUS andi k1, k1, ST0_EXL beqz k1, 1f nop j cache_parity_error_octeon_non_recoverable nop /* exception is recoverable */ 1: j handle_cache_err nop END(except_vec2_octeon) </source> 回顾一下,例外发生时 CPU 会将 STATUS[EXL] 置为 1,但是在 Cache Error 例外出现时,EXL 不会被置为 1,CPU 而是将 STATUS[ERL] 置为 1,这个意味着: I. CPU 自动进入内核模式(忽略 STATUS[KSU] 位),禁止中断(忽略 STATUS[IE] 位) II. eret 指令使用 CP0_ErrorEPC 代替 CP0_EPC 作为例外返回地址 III. Kuseg 和 xkuseg 被改为 unmapped, uncached 的区域,以便在 cache 不能用时,内存空间能正常访问 貌似可恢复 Cache Error 的处理过程如下: 访问地址 VA ---> 第一次发生 Cache Error 例外 ---> 进入 except_vec2_octeon,STATUS[ERL] = 1 ---> CP0_STATUS & ST0_EXL 为 0 ---> 进入 handle_cache_err---> SAVE_ALL 保存上下文后,KMODE 清除 ERL 位 ---> 进入貌似 Cache Error 可恢复的处理函数cache_parity_error_octeon_recoverable ---> 打出CP0_ICache_Error/CP0_DCache_Error 和 CP0_ErrorEPC ---> 执行 eret 指令,例外返回到 ErrorEPC 指向的地址,即刚刚访问出错的地址 VA 再试一下 错误不可恢复的情形: 嵌套异常,即在已有的异常处理过程中,EXL 还没有被清除,却发生了 Cache Error,此时进入except_vec2_octeon,STATUS[ERL] = 1 --->CP0_STATUS & ST0_EXL 为 1 ---> 最终进入cache_parity_error_octeon_non_recoverable,打印CP0_ICache_Error/CP0_DCache_Error 和 CP0_ErrorEPC 后,直接 panic <source lang=c> /* We need to jump to handle_cache_err so that the previous handler * can fit within 0x80 bytes. We also move from 0xFFFFFFFFAXXXXXXX * space (uncached) to the 0xFFFFFFFF8XXXXXXX space (cached). */ LEAF(handle_cache_err) .set push .set noreorder .set noat SAVE_ALL KMODE # clear EXL, ERL, set kernel mode bit jal cache_parity_error_octeon_recoverable nop j ret_from_exception nop .set pop END(handle_cache_err) </source> [arch/mips/mm/c-octeon.c] <source lang=c> asmlinkage void cache_parity_error_octeon_recoverable(void) { cache_parity_error_octeon(0); } asmlinkage void cache_parity_error_octeon_non_recoverable(void) { cache_parity_error_octeon(1); } static void cache_parity_error_octeon(int non_recoverable) { unsigned long coreid = cvmx_get_core_num(); uint64_t icache_err = read_octeon_c0_icacheerr(); pr_err("Cache error exception:\n"); pr_err("cp0_errorepc == %lx\n", read_c0_errorepc()); if (icache_err & 1) { pr_err("CacheErr (Icache) == %llx\n", (unsigned long long)icache_err); write_octeon_c0_icacheerr(0); } if (cache_err_dcache[coreid] & 1) { pr_err("CacheErr (Dcache) == %llx\n", (unsigned long long)cache_err_dcache[coreid]); cache_err_dcache[coreid] = 0; } if (non_recoverable) panic("Can't handle cache error: nested exception"); } </source> <br><br>
返回到
64位多核 MIPS 异常和中断内核代码分析 (1)
。
个人工具
登录
名字空间
页面
讨论
变换
查看
阅读
查看源代码
查看历史
操作
搜索
导航
首页
社区专页
新闻动态
最近更改
随机页面
帮助
工具箱
链入页面
相关更改
特殊页面