之前遇到了linux random kernel panic的问题,原因是TLB的entry对应的page其实已经释放。
VIP是独立的ko,create resource是通过VA接口走到我们ko的allocation接口,
unmap gart后,没有invaliate tlb,再create allocation,使用了 同样的va,从tlb 拿PA,结果write到了已经释放的page上。
invaliate gart cache走的是mmio而不是dma,不用等待dma fence back。
现在inv tlb是在submit task里面做的,改成在map gart或者destory allocation时也做。
这里直接invalidate了tlb,降低了性能。
TLB资料:
http://www.wowotech.net/memory_management/tlb-flush.html
TLB flush操作
Linux VM subsystem很多场合要对TLB flush,下面描述了TLB概念,硬件实现,TLB flush的软件接口,内核版本是4.4
1,概念
what's TLB:Translation Lookaside Buffer,
处理器在取址或者执行访问memory指令时需要进行地质翻译,即把虚拟地址翻译成物理地址。
但地址翻译是个漫长的过程,要遍历几个level的translation table,是严重开销。
为提高性能,在MMU增加TLB单元,把地址翻译关系保存在这个高速缓存中,以省略对内存中页表的访问。
why need TLB?
TLB本质是一种cache,cache的存在就是为了更高的performance,
instruction cache,指令缓存,
data cache
translation cache
instruction cache解决cpu获取main memory中的指令数据(地址保存在PC寄存器)的速度慢的问题而设立的。
data cache是为了解决数据访问指令比较慢而设立的。
而这这是事情的一部分,看看程序中数据访问指令的执行过程:
1,将PC的虚拟地址反应成物理地址
2,从memory获取数据访问指令(假设该指令需要访问地址x)
3,将虚拟地址x翻译成物理地址y
4,从location y 的memory获取数据
instruction cache解决了2的性能问题,data cache解决了step 4的性能问题。
复杂的系统会建立各个level的cache来缓存main memory的数据,而他们只加速了2,4步骤,
IC设计师不会放弃1,3的,这也是TLB的由来。
若CPU core发起的地址翻译过程可以在TLB(translation cache)中命中(cahche hit),CPU不需要访问慢速的main memory提高了performance
how TLB work?
图片来自计算机的组成与设计,computer organization and design
当要转换VA到PA时,首先在TLB找是否有匹配的条目,若有,称为TLB hit,则不用再访问页表完成地址翻译。
TLB始终是全部页表的一个子集,所以可能在TLB找不到。
若没有在TLB中找到对应的item,称为TLB miss,就需要访问memory的page table完成地址翻译,同时将翻译结果放入TLB,如果TLB满了,还要设计替换算法决定哪个TLB entry要失效,以加载新的页表项。
TLB entry的内容包括:
1,物理地址,physical page number,这是地址翻译的结果。
2,虚拟地址,virtual page number,用cache的术语描述叫Tag,进程匹配时就是对比Tag。
3,memory attribute,如memory type,cache poliocies, access permissions
4,status bits,如Valid, dirty,reference bits
三,ARM v8的TLB
选择cortex-A72 processor来描述ARMv8的TLB的组成结构和维护TLB的指令。
1,TLB的组成结构,下图是A72的功能block:
A72实现了2个level的TLB, 绿色是L1 TLB,包括L1 instruction TLB(48-entry fully-associative) 和 L1 data TLB(32 entry fully-associative)。黄色block是L2 unified TLB,它要大一些,可荣亚1024个entry,是4-way set-associative的。
当L1 TLB发生TLB miss时,L2 TLB是它坚强的后盾。
2,如何确定TLB match?
地址翻译过程不是VA->PA的映射那么简单,系统中的虚拟地址空间很多,每个地址空间的翻译都是独立的。
1)每个进程有自己独立的VA空间,各进程里,相同的VA翻译成不同的PA。
2)若支持虚拟化,系统中存在一个hostOS和多个guest OS,不同OS间地址翻译不同,
3)
我们可以不考虑复杂的情况,在进程切换、虚拟机切换、secure/normal world切换时,将TLB所有内容全flush(invalidate),这样设计很轻松,但性能下降。
实际设计TLB时,会让TLB entry包含和虚拟地址空间context相关的信息,A72里,满足下面条件,才算匹配了一个TLB entry:
1)请求进程地址翻译的VA page number等于TLB entry中的VA page number
2)请求进程地址翻译的memory space identifier等于TLB entry的memory sppace identifier。
所谓memory space identifier就是区分请求是来自EL3 Exception level,nonsecure EL2 exception level,Sucure and nonsucrue EL0.。。。。
3)若entry标记为non-Global.,请求进行地址翻译的ASID等于TLB entry的ASID
4) ....
3,进程切换和ASID(address space identifier)
进程有自己独立的VA,若TLB不标识VA,进程切换是,VA变化,TLB的entry也应该无效了要invalidate all,
但这么做从功能上没问题,性能却下降。
好的方案是区分global pages(内核地址空间)和process-specific pages,
Global pages,所有进程一样,进程切换后仍然需要这些entry,不用flush TLB,
Process-specific pages的TLB entry,一旦切换,TLB不能识别,就要flush掉上一个进程VA的TLB entry。
若支持ASID就不通了,TLB 的entry,保存多个相同的VA到不同的PA的映射也是可以的,只要他们有不同的ASID。
4,TLB的一致性问题,
TLB也是一种cache,有cache就意味着数据有多个copy,所以存在一致性coherence问题。
与数据,指令cahce或者unified cahche不同的是,硬件不维护TLB的coherence,一旦软件修改了page table,软件也要进程TLB invalidate操作,以维护TLB coherence。
5,TLB操作过程
四,TLB flush API
invalidate使无效
https://blog.csdn.net/qingfengjuechen/article/details/83749946
clean:对于回写类型的数据cache,若包含尚未写到主存的数据,则将数据写到主存
invalidate:将cache的某个块(或者所有)标识成无效,使所有访问这个块的操作一定是不命中。对于写回类型的数据cache来说,使无效,并不使数据写到主存中。(invalidate=flush)