欢迎来到三一文库! | 帮助中心 三一文库31doc.com 一个上传文档投稿赚钱的网站
三一文库
全部分类
  • 研究报告>
  • 工作总结>
  • 合同范本>
  • 心得体会>
  • 工作报告>
  • 党团相关>
  • 幼儿/小学教育>
  • 高等教育>
  • 经济/贸易/财会>
  • 建筑/环境>
  • 金融/证券>
  • 医学/心理学>
  • ImageVerifierCode 换一换
    首页 三一文库 > 资源分类 > DOC文档下载
     

    KPTI实现机制及性能与开销.doc

    • 资源ID:3253472       资源大小:29KB        全文页数:6页
    • 资源格式: DOC        下载积分:4
    快捷下载 游客一键下载
    会员登录下载
    微信登录下载
    三方登录下载: 微信开放平台登录 QQ登录   微博登录  
    二维码
    微信扫一扫登录
    下载资源需要4
    邮箱/手机:
    温馨提示:
    用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)
    支付方式: 支付宝    微信支付   
    验证码:   换一换

    加入VIP免费专享
     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    KPTI实现机制及性能与开销.doc

    KPTI实现机制及性能与开销1 KPTI概述KPTI(Kernel PageTable Isolation)全称内核页表隔离。KPTI是由KAISER补丁修改而来。之前,进程地址空间被分成了内核地址空间和用户地址空间。其中内核地址空间映射到了整个物理地址空间,而用户地址空间只能映射到指定的物理地址空间。内核地址空间和用户地址空间共用一个页全局目录表(PGD表示进程的整个地址空间),meltdown漏洞就恰恰利用了这一点。攻击者在非法访问内核地址和CPU处理异常的时间窗口,通过访存微指令获取内核数据。为了彻底防止用户程序获取内核数据,可以令内核地址空间和用户地址空间使用两组页表集(也就是使用两个PGD)。图1 修改后的进程地址空间2 问题当然事情并没有那么简单,有两个问题:问题1: X86架构中,在上下文切换的间隙(注意是间隙)内存中的一部分需要对内核空间和用户空间都是有效的,也就是说在切换CR3之前内核就要开始工作了。问题2:修改CR3时,CPU会冲刷TLB,从而带来很大的性能问题3 KPTI实现机制在KAISER的论文中针对这两个问题,提出了以下解决方案3.1 影子地址空间(Shadow Address Spaces)KPTI中每个进程有两个地址空间,第一个地址空间只能在内核态下访问,可以创建到内核和用户的映射(不过用户空间受SMAP和SMEP保护,具体可查询Intel手册)。第二个地址空间被称为影子地址空间,只包含用户空间。不过由于涉及到上下文切换,所以在影子地址空间中必须包含部分内核地址,用来建立到中断入口和出口的映射。当中断在用户态发生时,就涉及到切换CR3寄存器,从影子地址空间切换到用户态的地址空间。中断上半部的要求是尽可能的快,从而切换CR3这个操作也要求尽可能的快。为了达到这个目的,KAISER中将内核空间的PGD和用户空间的PGD连续的放置在一个8KB的内存空间中。这段空间必须是8K对齐的,这样将CR3的切换操作转换为将CR3值的第13位(由低到高)的置位或清零操作,提高了CR3切换的速度。用户空间和内核空间的PGD分布示意图3.2 内核空间的最小映射上文提到,在从影子地址空间切换到内核地址空间的过程中,为了使得内核在CR3切换之前就能够开始工作,影子地址空间必须包含部分内核地址空间。如下图所示,阴影处就是在陷入内核态过程中,需要映射的内核数据和代码。图a 是常规OS的进程的地址空间。图b和图c是页表隔离后的进程地址空间,两者的区别再与是否使用了SMAP和SMEP机制。那么如何确定影子地址空间应该映射那些内核数据呢?由于中断可能发生在用户态,所以应该包含中断向量表(IDT),中断栈,中断向量。另外内核栈,GDT和TSS也应该映射到影子地址空间。4 性能与开销(performance and overhead)4.1 TLB在intel手册中提到,线性地址的高位被称为页号(page number),低位被称为页偏移(page offset, 如果页大小是4K则是低12位)。物理地址的高位被称为页框(page frame)。TLB用于加速从线性地址到物理地址的转换,本质上还是一种缓存。TLB使用页号来获取线性地址所对应的页的基地址。TLB中的每一项包含以下内容:页号对应页的物理地址页的访问权限(R/W,U/S )页属性(dirty flag,memory type)图4-1  基于TLB的访存过程一个处理器可能包含不同类型的TLB,比如专用于取指令的TLB和用于数据访问的TLB切换CR3时,CPU会隐式的冲刷TLB。TLB的miss penalty可以达到10 100 个 时钟周期(clock cycles)。内存中的一些页(比如共享库)的一些页是由所有的进程共享的。这些页由页表项的全局位(G)来标示。共享页并不会参与TLB的隐式冲刷。有两种方法防止数据的泄露,第一种需要冲刷整个TLB,而第二种则是禁用页表项的全局位。通过PCID的使用可以缓解由于冲刷TLB带来的性能问题。4.2 Process-Context Identifiers(PCID)PCID全称进程上下文标示符,CR4寄存器的PCIDE位表示是否启用CPU的PCID功能。PCIDE=1表示启用PCID。启用之后,CR3(页目基址寄存器)的低12位用来存储PCID。每个进程都有一个PCID,当未启用PCID时,CR3的低12位为全0(000H)。Intel手册对于TLB失效的行为作出了很详细的解释,在使用mov指令修改CR3时会使TLB失效(mov to CR3),具体行为如下:如果CR4.PCIDE = 0(表示未启用PCID),CPU会使所有与PCID 000H关联的TLB缓存项(TLB entry)失效,除了全局页。如果CR4.PCIDE = 1(启用PCID),并且源操作数的第63位=0,源操作数的0-11位为指定的PCID。那么CPU会使所有与指定PCID关联的TLB缓存项失效。TLB中与其他PCID关联的TLB缓存项并不会失效。如果CR4.PCIDE=1,并且源操作数的第63位=1,CPU不会对TLB做任何的失效操作。5 代码分析我们选取linux4.15版本作为演示,说明KPTI补丁的内核中的分布这是4.15版本和PTI(pagetable isolation)有关的diff stat. 可以看到共涉及到45个文件的修改,插入了1636行代码,删除202行代码。增加代码行数的前三名是mm/pti.carch/x86/include/asm/tlbflush.harch/x86/entry/calling.h5.1 arch/x86/mm/pti.cpti.c是补丁新增的文件. 其中的入口函数是pti_init(), 该函数在init/main.c中的mm_init()函数中调用。这个文件中的函数总共分为两种,第一种类似pti_clone_user_shared(),将内核的页表项复制到用户空间。第二种类似pti_user_pagetable_walk_p4d(unsigned long address),根据参数中的虚拟地址,得到该地址相应的页表项指针。void _init pti_init(void)if(!static_cpu_has(X86_FEATURE_PTI)return;pr_info("enabledn");pti_clone_user_shared();pti_clone_entry_text();pti_setup_espfix64();pti_setup_vsyscall();5.2 arch/x86/include/asm/tlbflush.h该文件包含一系列的有关TLB flush的函数在KPTI中并不仅仅使用PCID,由于内核中的进程地址空间标示符必须从0开始。所以ASID是地址空间真正的标示符。又因为补丁中进程的地址空间有两个部分,所以我们需要两个PCID。kPCID内核空间使用的标示符。uPCID用户空间使用的标示符。* ASID  -0, TLB_NR_DYN_ASIDS-1*         the canonical identifier for an mm* kPCID -1, TLB_NR_DYN_ASIDS*         the value we write into the PCID part of CR3; corresponds to the*         ASID+1, because PCID 0 is special.* uPCID -2048+1,2048+ TLB_NR_DYN_ASIDS*         for KPTI each mm has two address spaces and thus needs two*         PCID values, but we can still do with a single ASID denomination*         for each mm.Corresponds to kPCID +2048.#define CR3_HW_ASID_BITS        12# define PTI_CONSUMED_PCID_BITS 1/* 6 because 6 should be plenty and struct tlb_state will fit in two cache* lines.*/#define TLB_NR_DYN_ASIDS    65.3 /arch/x86/entry/calling.hcalling.h 是系统调用的入口函数,用于处理系统调用时的寄存器保存操作。系统调用涉及到由用户态到内核态的切换。所以calling.h需要修改。以下一系列的汇编宏指令涉及到用户PGD和内核PGD的切换. 下面我们挑选几个宏进行说明:1. SWITCH_TO_KERNEL_CR3该宏的任务是清楚CR3存储的PCID,并将CR3的第13置1,从而使其指向内核PGD.macro SWITCH_TO_KERNEL_CR3 scratch_reg:reqALTERNATIVE "jmp .Lend_","", X86_FEATURE_PTImov %cr3, scratch_regADJUST_KERNEL_CR3 scratch_regmov scratch_reg,%cr3.Lend_:.endm2. SWITCH_TO_USER_CR3_NOSTACK该宏的任务是根据进程的ASID判断其TLB是否需要flush, 如果不需要就在CR3中标记为no_flush。随后将kPCID转换为uPCID,并使CR3指向用户PGD。这一切都在很短的时间内发生,因为它们只是对CR3寄存器的置位操作。.macro SWITCH_TO_USER_CR3_NOSTACK scratch_reg:req scratch_reg2:reqALTERNATIVE "jmp .Lend_","", X86_FEATURE_PTImov %cr3, scratch_regALTERNATIVE "jmp .Lwrcr3_","", X86_FEATURE_PCID/* Test if the ASID needs a flush.*/movq    scratch_reg, scratch_reg2andq    $(0x7FF), scratch_reg     /* mask ASID */bt  scratch_reg, THIS_CPU_user_pcid_flush_maskjnc .Lnoflush_/* Flush needed, clear the bit */btr scratch_reg, THIS_CPU_user_pcid_flush_maskmovq    scratch_reg2, scratch_regjmp .Lwrcr3_pcid_.Lnoflush_:movq    scratch_reg2, scratch_regSET_NOFLUSH_BIT scratch_reg.Lwrcr3_pcid_:/* Flip the ASID to the user version */orq $(PTI_USER_PCID_MASK), scratch_reg.Lwrcr3_:/* Flip the PGD to the user version */orq     $(PTI_USER_PGTABLE_MASK), scratch_regmov scratch_reg,%cr3.Lend_:.endm

    注意事项

    本文(KPTI实现机制及性能与开销.doc)为本站会员(白大夫)主动上传,三一文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知三一文库(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    经营许可证编号:宁ICP备18001539号-1

    三一文库
    收起
    展开