qemu内存模型(5)  GPA到MemoryRegionSection

gpa 是指qemu虚拟机的guest端的cpu看到的内存地址空间。
qemu的模型可以参考前边的四篇文章
qemu 内存模型(1)—文档
qemu内存模型(2) 实现说明
qemu内存模型(3) 内存布局初始化
qemu内存模型(4) 内存渲染过程(MemoryRegion到FlatView)

前边分析qemu会将MemoryRegion转化为FlatRange, 在gpa的读写过程中,其实就是要找到对应的MemoryRegion,由于MemoryRegion渲染过程中,优先级的问题, 一个MemoryRegion被分割成多个FlatRange,为了维护这个关系,就有了本篇文章要分析的内容,
GPA->MemeoryRegionSection, MemoryRegionSection维护了FlatRange到MemoryRegion的关系。

qemu的模型是采用六级页表对gpa线性地址对MemoryRegionSection进行映射。这非常类似cpu的mmu页映射过程,qemu也是将页面按照4k进行分页,建立6级页表。
在这里插入图片描述

映射过程和上边映射过程类似,只不过是6级也表,上边是三级也表。

和linux内核的映射方式基本类似,不过这里每个页目录有512项,也就是通过虚拟地址中的9位定位在页目录中的偏移。

struct PhysPageEntry {
    /* How many bits skip to next level (in units of L2_SIZE). 0 for a leaf. */
    uint32_t skip : 6;
     /* index into phys_sections (!skip) or phys_map_nodes (skip) */
    uint32_t ptr : 26;
};

页目录项用PhysPageEntry表示, 其中skip用于定位虚拟地址中该级页目录中的偏移, skip为0的时候标示为页表项,页表项指向MemoryRegionSection,

ptr则用于定位下一级页目录/页表项, 当PhysPageEntry为一个页目录项的时候该值指向下一级(其实为下一级页表/页目录在nodes数组中的下标), 当PhysPageEntry

为一个页表项的时候指向一个MemoryRegionSection(其实为sections数组下标)
在这里插入图片描述
AddressSpaceDispatch中的phyMap相当于cr3 寄存器,用于定位最高级别页目录

gpa注册到页表的过程

1415 void flatview_add_to_dispatch(FlatView *fv, MemoryRegionSection *section)
1416 {
1417     MemoryRegionSection now = *section, remain = *section;
1418     Int128 page_size = int128_make64(TARGET_PAGE_SIZE);
1419
1420     if (now.offset_within_address_space & ~TARGET_PAGE_MASK) {
1421         uint64_t left = TARGET_PAGE_ALIGN(now.offset_within_address_space)
1422                        - now.offset_within_address_space;
1423
1424         now.size = int128_min(int128_make64(left), now.size);
1425         register_subpage(fv, &now);
1426     } else {
1427         now.size = int128_zero();
1428     }
1429     while (int128_ne(remain.size, now.size)) {
1430         remain.size = int128_sub(remain.size, now.size);
1431         remain.offset_within_address_space += int128_get64(now.size);
1432         remain.offset_within_region += int128_get64(now.size);
1433         now = remain;
1434         if (int128_lt(remain.size, page_size)) { 
1435             register_subpage(fv, &now);
1436         } else if (remain.offset_within_address_space & ~TARGET_PAGE_MASK) {
1437             now.size = page_size;
1438             register_subpage(fv, &now);
1439         } else {
1440             now.size = int128_and(now.size, int128_neg(page_size));
1441             register_multipage(fv, &now);
1442         }
1443     }
1444 }

这段代码主要是把MemoryRegionSection(根据FlatRange生成)的内存地址空间按照注册到页表

首先

1420-1427 把开始不页面对齐的地址裁剪出来,使用register_subpage(fv, &now) 进行注册,因为这部分肯定不足一个页面,所以使用register_subpage注册

1429-1443 行把剩余地址对齐的页面进行注册, 分为3中情况

1434行的情况标示地址对齐的剩余地址不足一页, 使用register_subpage 注册
1436 的情况永远不会发生
1439行的情况标示该地址空间包含多个页面,(注意这种情况要求结尾也是页面对对齐的,其余部分会裁剪用register_subpage注册,在下次循环)

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值