• 客户机页表遍历


    转载:http://blog.chinaunix.net/uid-26000137-id-3768752.html

    MMU的功能:虚拟机地址转换为物理地址,下面函数模拟此过程。

    1.数据结构

     struct guest_walker {
            int level;
            gfn_t table_gfn[PT_MAX_FULL_LEVELS];
            pt_element_t ptes[PT_MAX_FULL_LEVELS];
            gpa_t pte_gpa[PT_MAX_FULL_LEVELS];
            unsigned pt_access;
            unsigned pte_access;
            gfn_t gfn;
            u32 error_code;
    };
               +-------+
               |       |
               +-------+
               |   c   |
               |-------|<-----b          
               |       |
               +-------+
               |-------|      
               |-------|       
               +-------+<-----a
                某级页表
    a:页表项基地址
    b:index的地址
    c:index的地址内容

    遍历完成后,数据结构内容为
    gfn:客户机页表转换后物理地址页框号
    假设PT_MAX_FULL_LEVELS=4
    table_gfn【0-3】存放 4级页表项基地址
    pte_gpa【0-3】  存放4级页表项中index基地址
    ptes【0-3】     存放4级页表项中index基地址内容
    pt_access:     gfn的访问权限
    pte_access:    gfn的访问权限

    2:客户机页表的遍历,也是虚拟MMU
    static int FNAME(walk_addr)(struct guest_walker *walker,
                                struct kvm_vcpu *vcpu, gva_t addr,
                                int write_fault, int user_fault, int fetch_fault)
       walker->level = vcpu->arch.mmu.root_level;//64位客户机系统,页表级数为4.
       pte = vcpu->arch.cr3; //页目录基地址
       for (;;) { //从64位客户机页目录开始遍历,最后到页表
                    index = PT_INDEX(addr, walker->level);

                    table_gfn = gpte_to_gfn(pte);
                    pte_gpa = gfn_to_gpa(table_gfn);
                    pte_gpa += index * sizeof(pt_element_t);

                    walker->table_gfn[walker->level - 1] = table_gfn; //存放页表基地址 
                    walker->pte_gpa[walker->level - 1] = pte_gpa;     //存放页表index基地址

                    if (kvm_read_guest(vcpu->kvm, pte_gpa, &pte, sizeof(pte)))//获取存放页表index基地址页表项
                            goto not_present;
                     pte_access = pt_access & FNAME(gpte_access)(vcpu, pte);//获取存放页表index基地址页表项权限

                    walker->ptes[walker->level - 1] = pte;//存放存放页表index基地址页表项

                    if ((walker->level == PT_PAGE_TABLE_LEVEL)//页表的最后一级存放客户机物理页地址
                    {
                            int lvl = walker->level;

                            walker->gfn = gpte_to_gfn_lvl(pte, lvl);//转换客户机物理页地址为客户机物理页框号
                            walker->gfn += (addr & PT_LVL_OFFSET_MASK(lvl))
                                            >> PAGE_SHIFT;
                            break;
                    }

                   pt_access = pte_access;
                    --walker->level; //遍历下一级页表
                 }
            //页表遍历完成后,获取页表的访问权限,存放到数据结构中
            walker->pt_access = pt_access;
            walker->pte_access = pte_access;
            pgprintk("%s: pte %llx pte_access %x pt_access %x ",
                     __func__, (u64)pte, pt_access, pte_access);
            return 1;
    }

  • 相关阅读:
    @value传值到static字段
    [Err] 1701
    eclipse search只能打开一个文件
    FTPClient登录慢的问题
    nginx克隆之后问题
    centos-ftp搭建
    addEventListener和attachEvent的区别 分类: JavaScript 2015-05-12 19:03 702人阅读 评论(0) 收藏
    python中使用eval() 和 ast.literal_eval()的区别 分类: Python 2015-05-11 15:21 1216人阅读 评论(0) 收藏
    初学者必知的Python中优雅的用法 分类: Python 2015-05-11 15:02 782人阅读 评论(0) 收藏
    javascript中函数声明和函数表达式的区别 分类: JavaScript 2015-05-07 21:41 897人阅读 评论(0) 收藏
  • 原文地址:https://www.cnblogs.com/scu-cjx/p/6878579.html
Copyright © 2020-2023  润新知