TLB是什么
简单来说TLB (translation lookaside buffer) 是一个类似cache (快表) 的东西,不知道什么是cache那只需要知道——快表,快就完了
CPU读取两个相邻的地址的时候都要拆分一次PDE,PTE,非常的麻烦,能不能把线性地址、物理页和属性对应起来,这样每次CPU只需要查看这个对应关系表就行了。所以TLB就是这么一个对应关系表(TLB一核一个,TLB不会太大,所以当TLB满了以后,不常用的会被删掉)
那么CPU怎么知道什么是常用的什么是不常用的呢?
- G位表示全局位,G = 1不会被换出。全局位一般使用在高2G的内核上,内核程序是所有应用程序共享的,所以很常用,不应该换出
- 猜测有一个或多个位用于统计是否是常用到的地址,不常用的换出
- 进程切换,线程切换时,CR3变化,代表这一块地址暂时不会被访问了,所以直接全部刷新
x86中一般有四组TLB
4. 缓存一般页表(4K字节页面)的指令页表缓存(Instruction-TLB)
5. 缓存一般页表(4K字节页面)的数据页表缓存(Data-TLB)
6. 缓存大尺寸页表(2M/4M字节页面)的指令页表缓存(Instruction-TLB)
7. 缓存大尺寸页表(2M/4M字节页面)的数据页表缓存(Data-TLB)
验证TLB存在
这里是把之前的代码稍作修改后,直接使用
#include <windows.h>
#include <stdio.h>
PDWORD pde, pte, pde0, pte0;
DWORD get0value;
void __declspec(naked) func(){
_asm{
pushad
pushf
// 挂物理页, 注意G == 1
mov dword ptr ds:[0xC0000000], 0x11111867
// 给 (void*)0 赋值,这将写入TLB
mov dword ptr ds:[0x0], 0x87654321
// 物理页切换
mov dword ptr ds:[0xC0000000], 0x22222867
// 读取 (void*0) 的值
mov eax, dword ptr ds:[0x0]
mov get0value, eax
popf
popad
retf
}
}
int main(){
BYTE addrs[6] = {0x00, 0x00, 0x00, 0x00, 0x48, 0x00 };
int selector = 0x0008;
printf("windbg input:\t eq 8003f048 %04xEC00`%04x%04x\n",
(((DWORD)&func)>>16), selector, (DWORD)&func & 0xFFFF);
_asm{
push fs
call fword ptr[addrs]
pop fs
}
printf("%x\n", get0value); //打印 指针0 的值
return 0;
}
当CR3刷新时,TLB换出
TLB在CR3刷新时换出,但G == 0时,TLB不会换出
修改上面的代码(G==0)
#include <windows.h>
#include <stdio.h>
PDWORD pde, pte, pde0, pte0;
DWORD get0value;
void __declspec(naked) func(){
_asm{
pushad
pushf
// 挂物理页, 注意G == 0
mov dword ptr ds:[0xC0000000], 0x11111067
// 给 (void*)0 赋值,这将写入TLB
mov dword ptr ds:[0x0], 0x87654321
// 物理页切换
mov dword ptr ds:[0xC0000000], 0x22222067
//加入刷新CR3的代码
mov eax,cr3
mov cr3,eax
// 读取 (void*0) 的值
mov eax, dword ptr ds:[0x0]
mov get0value, eax
popf
popad
retf
}
}
int main(){
// 不变...
}
G == 1
#include <windows.h>
#include <stdio.h>
PDWORD pde, pte, pde0, pte0;
DWORD get0value;
void __declspec(naked) func(){
_asm{
pushad
pushf
// 挂物理页, 注意G == 1
mov dword ptr ds:[0xC0000000], 0x11111167
mov dword ptr ds:[0x0], 0x87654321
mov dword ptr ds:[0xC0000000], 0x22222167
mov eax,cr3
mov cr3,eax
mov eax, dword ptr ds:[0x0]
mov get0value, eax
popf
popad
retf
}
}
int main(){
// 不变...
}
INVLPG指令
可以使用INVLPG
指令刷新指定地址的TLB项
#include <windows.h>
#include <stdio.h>
PDWORD pde, pte, pde0, pte0;
DWORD get0value;
void __declspec(naked) func(){
_asm{
pushad
pushf
// 挂物理页, 注意G == 1
mov dword ptr ds:[0xC0000000], 0x11111167
mov dword ptr ds:[0x0], 0x87654321
mov dword ptr ds:[0xC0000000], 0x22222167
INVLPG dword ptr ds:[0x0]
mov eax, dword ptr ds:[0x0]
mov get0value, eax
popf
popad
retf
}
}
int main(){
// 不变...
}