zoukankan      html  css  js  c++  java
  • 16_TLB与流水线

    1 前面做的实验起始有缺陷

    访问内存之后,后面执行两句代码后;并不能保证刚才访问的代码还在TLB中;有可能被刷新出去了;

    实验验证缺陷:

    代码 不连续 TLB 被淘汰:

    1570543935670

    2万次中有1次被淘汰;由于访问代码不连续

    代码:

    // 7_TLB_test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
    //

    #include "pch.h"
    #include<stdio.h>
    #include<stdlib.h>
    #include<Windows.h>

    #define PTE(x) ( (DWORD*)(0xc0000000 + ((x >> 12) << 3)))
    #define PDE(X) ( (DWORD*)(0xc0600000 + ((x >> 21) << 3)))
    DWORD g_out;
    DWORD g_OldPte[2];
    #pragma section("data seg", read, write)
    _declspec(allocate("data seg"))DWORD pagel[1024]; //41d000
    _declspec(allocate("data seg"))DWORD page2[1024]; //41c000
    //0x401000
    void _declspec(naked) IdtEntry()
    {

    // 保存旧的pte ,以用来恢复pte 解决不蓝屏
    g_OldPte[0] = PTE(0x41c000)[0];
    g_OldPte[1] = PTE(0x41c000)[1];

    PTE(0x41c000)[0] = PTE(0x41d000)[0];// 不设置G位
    PTE(0x41c000)[1] = PTE(0x41d000)[1];

    __asm invlpg ds : [0x41c000] // 带有 g 位的刷新;

    // 刷新虚拟地址在TLB中
    __asm
    {
    mov eax, ds: [0x41c000];// 这个时候到快表中了 TLB[0x41c000] 中的值因该是 1;
    }

    // pte 修改回来,但是TLB 中存在所以应该还是 1
    PTE(0x41c000)[0] = g_OldPte[0];
    PTE(0x41c000)[1] = g_OldPte[1];

    __asm
    {
    mov eax,ds:[0x41c000]
    mov g_out,eax
    } // 如果前面访问之后还在快表中,那么这里应该是 [0x41d000] 中的 1;
    // 如果不再快表中了 那么是修改回来的 ,本来的 [0x41c000] 中的 2;

    /*__asm {
    mov eax, cr3
    mov cr3, eax
    }*/
    __asm invlpg ds : [0x41c000] // 带有 g 位的刷新;
    //// 调用调用;确保在 TL B 中
    //__asm mov eax, ds:[0x41c000];

    //// 恢复到原来的pte 
    ////---- 这样
    //// 按道理 后面一旦后面刷新 TLB 将 普通 TLB 刷新出去,
    //// 那么 g_out = page2[0] 的值就 应该是 正常 的原 pte 对应的数据 -- 2。
    //PTE(0x41c000)[0] = g_OldPte[0];
    //PTE(0x41c000)[1] = g_OldPte[1];

    //__asm
    //{
    //mov eax, cr3
    //mov cr3, eax
    //}


    //g_out = page2[0]; // 讲道理 在非G位下 应该是2(原PTE解析出的) -- 但是这里我们设置了PTE 的G位,
    // // so 这里应该是 TLB快表中 对应的 1;


    __asm {
    iretd
    }
    }
    void _declspec(naked) go() {
    {
    pagel[0] = 1; //确保物理页存在
    page2[0] = 2;

    }
    __asm int 0x20
    __asm ret
    }
    //eq 8003f500 0040ee00~ 00081000
    void main()
    {
    if ((DWORD)IdtEntry != 0x401040)
    {
    printf("wrong addr: %p", IdtEntry);
    exit(-1);
    }
    for (int i = 0; i < 200000; i++)
    {
    go();
    if (g_out == 2)
    {
    printf("%d : %d ==== ",i, g_out);
    printf("%d : %d ", i, page2[0]); // 打印出来 还是有小概率 不相同;说明还是在快表中的。
    }
    }

    system("pause");
    }

    G位即使存在 访问代码不连续也可能被淘汰:

    1570543626010

    我这里循环了20000次 ,有1次G位即使在也被TLB淘汰了。

    代码:

    // 7_TLB_test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
    //

    #include "pch.h"
    #include<stdio.h>
    #include<stdlib.h>
    #include<Windows.h>

    #define PTE(x) ( (DWORD*)(0xc0000000 + ((x >> 12) << 3)))
    #define PDE(X) ( (DWORD*)(0xc0600000 + ((x >> 21) << 3)))
    DWORD g_out;
    DWORD g_OldPte[2];
    #pragma section("data seg", read, write)
    _declspec(allocate("data seg"))DWORD pagel[1024]; //41d000
    _declspec(allocate("data seg"))DWORD page2[1024]; //41c000
    //0x401000
    void _declspec(naked) IdtEntry()
    {

    // 保存旧的pte ,以用来恢复pte 解决不蓝屏
    g_OldPte[0] = PTE(0x41c000)[0];
    g_OldPte[1] = PTE(0x41c000)[1];

    PTE(0x41c000)[0] = PTE(0x41d000)[0]| 0x100;// 设置G位
    PTE(0x41c000)[1] = PTE(0x41d000)[1];

    __asm invlpg ds : [0x41c000] // 带有 g 位的刷新;

    // 刷新虚拟地址在TLB中
    __asm
    {
    mov eax, ds: [0x41c000];// 这个时候到快表中了 TLB[0x41c000] 中的值因该是 1;
    }

    // pte 修改回来,但是TLB 中存在所以应该还是 1
    PTE(0x41c000)[0] = g_OldPte[0];
    PTE(0x41c000)[1] = g_OldPte[1];

    __asm
    {
    mov eax,ds:[0x41c000]
    mov g_out,eax
    } // 如果前面访问之后还在快表中,那么这里应该是 [0x41d000] 中的 1;
    // 如果不再快表中了 那么是修改回来的 ,本来的 [0x41c000] 中的 2;

    //__asm invlpg ds : [0x41c000] // 带有 g 位的刷新;即前面如果还在快表中,这里刷新pte再返回3环程序后再次输出。做测试用的没有意义了。
    __asm {
    iretd
    }
    }
    void _declspec(naked) go() {
    {
    pagel[0] = 1; //确保物理页存在
    page2[0] = 2;

    }
    __asm int 0x20
    __asm ret
    }
    //eq 8003f500 0040ee00~ 00081000
    void main()
    {
    if ((DWORD)IdtEntry != 0x401040)
    {
    printf("wrong addr: %p", IdtEntry);
    exit(-1);
    }
    for (int i = 0; i < 20000; i++)
    {
    go();
    if (g_out == 2)
    {
    printf("%d : %d ==== ",i, g_out);
    printf("%d : %d ", i, page2[0]); // 打印出来 还是有小概率 不相同;说明还是在快表中的。
    }
    }

    system("pause");
    }

    总结: 注意啊 ::: 切换 cr3 刷新TLB G位的 无影响; 得 使用

    __asm invlpg ds : [0x41c000] // 无视 g 位的刷新;

    3 流水线指令TLB 和数据TLB 得相互影响

    前置知识 : 如果我们的页面没有可执行属性的话;在没有TLB中时,我们修改pte后,第一次访问 绝对时修改pte之后的对应的物理页数据;但是如果有可执行属性,那么在cpu 流水线 技术( 执行指令的时候,也在取指令,且根据将会执行的可能性提前取指令):

    1570545166831

    现象:

    没有 可执行属性的时候;且没有主动加入快表的时候;坑定 是可预计的数据:

    1570545279564

    但是 一旦加入了可执行属性,流水线的预先取指令,可能执行到这儿,取后面的指令:

    1570545354161

    发现后面的指令有 0x405000 ,而且 0x405000 有可执行属性,可能就预先取了这个指令;继而访问;加入了TLB。 (但是即使这样这里也是指令TLB ,但是这里影响到了 数据TLB,但是概率也不高)

    1570549800314

    代码:

    #include "pch.h"
    #include<stdio.h>
    #include<stdlib.h>
    #include<Windows.h>

    #define PTE(x) ( (DWORD*)(0xc0000000 + ((x >> 12) << 3)))
    #define PDE(X) ( (DWORD*)(0xc0600000 + ((x >> 21) << 3)))
    DWORD g_out;
    DWORD g_OldPte[2];
    #pragma section("data seg", read, write)
    _declspec(allocate("data seg"))DWORD pagel[1024]; //41d000
    _declspec(allocate("data seg"))DWORD page2[1024]; //41c000
    //0x401000
    void _declspec(naked) IdtEntry()
    {
    // 保存旧的pte ,以用来恢复pte 解决不蓝屏
    g_OldPte[0] = PTE(0x41c000)[0];
    g_OldPte[1] = PTE(0x41c000)[1];
    __asm{
    mov eax,cr3
    mov cr3,eax
    }
    //__asm mov eax, ds :[0x41b000]
    PTE(0x41c000)[0] = PTE(0x41d000)[0];
    PTE(0x41c000)[1] = PTE(0x41d000)[1];
    __asm {
    mov eax, ds :[0x41c000]
    mov g_out, eax
    }
    PTE(0x41c000)[0] = g_OldPte[0];
    PTE(0x41c000)[1] = g_OldPte[1];
    _asm {
    mov eax, cr3
    mov cr3, eax
    iretd
    }
    }
    void _declspec(naked) go()
    {

    pagel[0] = 0xc3; //
    page2[0] = 0xc390;
    ((void(*)())(DWORD)pagel)();
    ((void(*)())(DWORD)page2)();
    __asm int 0x20
    __asm ret
    }
    //eq 8003f500 0040ee00 00081000
    void main()
    {
    if ((DWORD)IdtEntry != 0x401040)
    {
    printf("wrong addr: %p", IdtEntry);
    exit(-1);
    }

    for (int i = 0; i < 10000; i++) {
    go();
    if (g_out != 0xc3)
    printf("%d: %p ",i, g_out);

    }
    system("pause");
    }


  • 相关阅读:
    bzoj3505 数三角形 组合计数
    cogs2057 殉国 扩展欧几里得
    cogs333 荒岛野人 扩展欧几里得
    bzoj1123 BLO tarjan求点双连通分量
    poj3352 road construction tarjan求双连通分量
    cogs1804 联合权值 dp
    cogs2478 简单的最近公共祖先 树形dp
    cogs1493 递推关系 矩阵
    cogs2557 天天爱跑步 LCA
    hdu4738 Caocao's Bridge Tarjan求割边
  • 原文地址:https://www.cnblogs.com/leibso-cy/p/11719272.html
Copyright © 2011-2022 走看看