tlb kern_pcid
kern_pcid是 x86 架构中用于将内核内部的逻辑 ASID 转换为写入 CR3 寄存器、用于内核态的内核 PCIDkPCID的辅助函数。核心作用逻辑 ASID → 硬件 kPCIDLinux 内部使用一个很小的逻辑 ASID 空间0到TLB_NR_DYN_ASIDS - 1即0到5而硬件 PCID 是 12 位。kern_pcid负责完成这个转换核心操作就一行return asid 1;为什么要1注释中给出了两个关键原因保护 ASID 0如果 PCID 0 被用于动态 ASID那么当“不感知 PCID”的代码保存 CR3、加载一个 PCID0 的值、再恢复 CR3 时会破坏 ASID 0 的 TLB。通过把动态 ASID 映射到1~6PCID 0 被保留给swapper_pg_dir等特殊用途避免了这种冲突。让 bug 确定性触发如果有人在CR4.PCIDE关闭的情况下加载了 PCID 启用的 CR31的偏移会使其行为异常从而确定性地暴露 bug而不是产生难以追踪的静默错误。代码逻辑解析1. 边界检查VM_WARN_ON_ONCE(asid MAX_ASID_AVAILABLE);确保传入的 ASID 不超过可用范围MAX_ASID_AVAILABLE等于TLB_NR_DYN_ASIDS - 1即 5。2. KPTI 下的冲突检查#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION BUILD_BUG_ON(TLB_NR_DYN_ASIDS (1 X86_CR3_PTI_PCID_USER_BIT)); VM_WARN_ON_ONCE(asid (1 X86_CR3_PTI_PCID_USER_BIT)); #endif在 KPTI页表隔离启用时BUILD_BUG_ON编译时断言确保TLB_NR_DYN_ASIDS6不会与用于区分用户/内核 PCID 的切换位冲突。X86_CR3_PTI_PCID_USER_BIT通常是 bit 111 11 20486 远小于 2048所以这个断言通过。VM_WARN_ON_ONCE运行时检查传入的 ASID 是否误设了切换位。正常情况下动态 ASID 都是小值0~5不会触及 bit 11。3. 转换return asid 1;将逻辑 ASID 加 1得到 kPCID范围1~6。与user_pcid的关系kern_pcid只处理内核态 PCID。对于 KPTI 场景下的用户态 PCID还有另一个函数user_pcidstatic inline u16 user_pcid(u16 asid) { u16 ret kern_pcid(asid); ret | 1 X86_CR3_PTI_PCID_USER_BIT; // 设置切换位 return ret; }user_pcid先调用kern_pcid得到基础值然后设置 bit 11X86_CR3_PTI_PCID_USER_BIT得到用户态 PCID范围2049~2054。这样同一个进程的内核态和用户态 PCID 就通过这个切换位区分开来CR3 切换时只需翻转这一位即可。设计意图kern_pcid的1偏移和位检查体现了 Linux 对 PCID 这个硬件资源的“非正统”但务实的利用方式用极小的 ASID 空间6 个槽位配合位标志在有限的 12 位 PCID 中为每个 CPU 缓存最近使用的少量地址空间同时与 KPTI 的页表切换需求完美协同。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →