4 区域的生命周期

一个区域由memory_region_init*()函数中一个创建并与一个object关联,该object被当前它自己或parent。QEMU保证只要该区域对guest可见或只要该区域被vCPU或其他设备使用,owner object仍保持有效。比如owner object在address_space_map()操作和address_space_unmap()操作之间并不会消亡。

在创建后,一个区域通过函数memory_region_add_subregion()被添加到一个地址空间或一个container中,并使用函数memory_region_del_subregion()移除。

各种区域属性(只读,脏标记,合并MMIO,ioeventfd)在区域生命周期可以被修改。只要区域可见,它们就可以生效。这可以立即产生,也可以稍后产生,或永远不会产生。

当owner object消亡时内存区域自动消亡。

但是如果内存区域为动态分配的数据结构的一部分,你应该调用object_unparent()在数据结构被释放之前毁销内存区域。比如看hw/vfio/pci.c中VFIOMSIXInfo和VFIOQuirk。

只要一个内存区域被设备或CPU使用时你不能销毁内存区域。为了使用它,因为在设备的生命周期内通常规则不能动态的创建或销毁内存区域,仅在内存区域owner的instance_finalize回调中调用object_unparent()。动态分配的数据结构包含内存区域,内存区域应该在instance_finalize回调中被销毁。

若你破坏上述规则,下面的情况可能产生:

  1. 内存区域的owner通过memory_region_ref获得引用计数(比如通过address_space_map);
  2. 区域被unparent,不再有owner;
  3. 当address_space_unmap被调用时,对内存区域owner引用计数被释放;

对上述规则有一个例外:在任何时间对alias或container区域调用object_unparent是可以的。因此在设备的生命周期动态的创建或销毁alias或container区域也是可以的。

例外使用也是有效的因为alias或container仅帮助QEMU建立guest的内存映射;它们不能被直接访问。Memory_region_ref和memory_region_unref不需要对alias或container调用,上述情况不会发生。利用这个例外不是很必要,因此不鼓励,但也可以用于有些地方。

对于没有owner的区域(NULL在创建时被传递),机器object被用作owner。因为instance_finalize不会被machine object调用,你不能对没有owner的区域调用object_unparent,如果它们不是alias或container。

5 区域的重叠和优化级

通常区域之间不会相互重叠;一个内存地址被定位到一个目标上。在一些场景下允许区域重叠也是有用的,有时可以来控制哪个重叠区域可以被guest看见。这可以通过memory_region_add_subregion_overlap(),它允许在相同的container中一个区域与其他区域重叠,并指定优先级允许core来决定相同的地址的哪个区域被看到(最高优先级被看到)。

优先级值被赋予,默认值为0。这意味着你可以使用memory_region_add_subregion_overlap()在”above”区域和”below”区域。

如果重叠的最高优先级为一个container或alias,更低优先级区域将出现在更高优先级留下的hole区域(通过没有映射子区域)。(这可以递归的应用。如果子区域自己的container或alias,留下hole,更低优先级区域将出现在Hole)。

比如,假定我们有一个大小为0x8000在container A,它有两个子区域B和C。B为一个映射在0x2000,大小为0x4000的container,优先级为2;C为一个MMIO映射区,它映射到0x0,大小为0x6000,优先级为1。B当前有两个自己的子区域:D偏移为0,大小为0x1000,E偏移为0x2000,大小为0x1000。如下图所示:

可以看到的区域地址范围如下所示:

因为B有比C更高在优先级,它的子区域出现在flat映射,它与C重叠。当B没有映射C的区域。

如果B提供它自己的MMIO操作(如它不是单纯的container),这将用于范围内的任何地址,该范围没有被D和E处理,结果将成为:

优先级值对container是本地的,因为两个区域的优先级仅当它们都是相同container在子区域时才能比较。这意味着负责container的设备可以使用它们来管理它子区域的交互,而没有任何边际效应。在上述例子中,D和E的优先级不重要因为他们相互不重叠。正是B和C的相对优先级导致D和E出现在C的顶部;D和E的优先级不再与C的优先级比较。

6 可见性

当guest访问一个地址时,内存core使用如下规则选择内存区域:

(1)根区域的所有直接子区域都与地址匹配,以降序优先级

- 如果地址在区域offset/size之外,子区域被放弃;

- 如果子区域为叶子结点(RAM或MMIO),查询停止,返回叶子区域;

- 如果子区域为container,在子区域使用相同的算法(在地址被子区域偏移被调整);

- 如果子区域为alias,在alias的目的上继续搜索(在地址被子区域偏移和alias偏移);

- 如果在一个container或alias子区域的递归搜索没有找到匹配(因为它的地址范围的container覆盖中的hole),如果container有自己的MMIO或RAM,返回container。否则我们在优先级顺序中继续下一个子区域

(2)如果没有子区域匹配地址,搜索终止,找不到匹配

7 内存映射的例子

这是一个简化的PC内存映射。4GB RAM块通过两个alias映射到系统地址空间:”lomen”为3.5GB的1:1映射;”himem”在地址4GB至少映射0.5GB。这为PCI hole留下0.5GB,这允许在4GB内存系统中留下32位PCI总线。

内存控制器将地址范围640K-748K转化到PCI地址空间。它使用vga-window alias,映射到一个更高优先级,因此它将RAM抽象到时相同的地址。Vga通过编程内存控制被移除;可通过移除alias和导出RAM建立。

PCI地址空间并不是系统地址空间的直接孩子,因为我们仅希望部分被看到(我们通过使用alias完成上述)。它有两个子区域:vga-area为传统vga窗口并由两个32K内存块指向两个framebuffer的section。

另外vram被映射到地址BAR e1000000,另外BAR包含MMIO寄存器被映射。

注意如果guest映射一个BAR在PCI hole之外,它将不会被看到,因为PCI-HOLE将其放在0.5GB范围。

8 MMIO操作

MMIO区域由->read()和->write()回调提供,这对大多数设备是足够。一些设备基于内存使用的属性而变化行为,或对可能造成总线错误回复而不是成功的完成;这些设备可以使用->read_with_attrs()和->write_with_attrs()回调。

另外各种限制可以被应用来控制这些回调如何被调用:

- .valid.min_access_size,.valid.max_access_size定义了设备接受的访问大小;在这个范围之外进行访问将有设备和总线特定的范围(忽略,或检查);

- .valid.unaligned指定了设备支持的非对齐访问;若失败,非对齐的访问将涉及合适的总线或CPU特定的行为;

- .impl.min_access_size,.impl.max_access_size定义了实现支持的访问大小;其他的访问大小使用有效的被模拟。比如4byte写将使用1byte写来模拟,如果.impl.max_access_size=1;

- .impl.unaligned 指定实现支持不对齐的访问;如果失败,不对齐的访问将由两个访问模拟

内容翻译来自:

memory.rst - docs/devel/memory.rst - Qemu source code (v6.2.0) - Bootlin

QEMU中的内存API(2)相关推荐

  1. 在 CUDA C/C++ kernel中使用内存

    在 CUDA C/C++ kernel中使用内存 如何在主机和设备之间高效地移动数据.本文将讨论如何有效地从内核中访问设备存储器,特别是 全局内存 . 在 CUDA 设备上有几种内存,每种内存的作用域 ...

  2. 如何使用 DBCC MEMORYSTATUS 命令来监视 SQL Server 2005 中的内存使用情况

    https://technet.microsoft.com/en-us/solutionaccelerators/dd537566.aspx 注意:这篇文章是由无人工介入的微软自动的机器翻译软件翻译完 ...

  3. C#中调用Windows API的要点

    在.Net Framework SDK文档中,关于调用Windows API的指示比较零散,并且其中稍全面一点的是针对Visual Basic .net讲述的.本文将C#中调用API的要点汇集如下,希 ...

  4. 内核中的内存申请:kmalloc、vmalloc、kzalloc、kcalloc、get_free_pages【转】

    转自:http://www.cnblogs.com/yfz0/p/5829443.html 在内核模块中申请分配内存需要使用内核中的专用API:kmalloc.vmalloc.kzalloc.kcal ...

  5. C#中调用Windows API的要点【转载】

    在.Net Framework SDK文档中,关于调用Windows API的指示比较零散,并且其中稍全面一点的是针对Visual Basic .net讲述的.本文将C#中调用API的要点汇集如下,希 ...

  6. 在C#中调用windows API函数

    Api函数是构筑Windws应用程序的基石,每一种Windows应用程序开发工具,它提供的底层函数都间接或直接地调用了Windows API函数,同时为了实现功能扩展,一般也都提供了调用Windows ...

  7. [收集]Visual C#中调用Windows API

    在.Net Framework SDK文档中,关于调用Windows API的指示比较零散,并且其中稍全面一点的是针对Visual Basic .net讲述的.本文将C#中调用API的要点汇集如下,希 ...

  8. C++编码中减少内存缺陷的方法和工具

    2019独角兽企业重金招聘Python工程师标准>>> C++编码中减少内存缺陷的方法和工具 程振林,方金云,唐志敏 (中国科学院计算技术研究所,北京 100080) 摘 要:基于C ...

  9. LeakCanary——消除Android中的内存泄露

    2019独角兽企业重金招聘Python工程师标准>>> ##LeakCanary ####简介 LeakCanary是Square公司最近公布的开源项目,旨在消除Android中的内 ...

最新文章

  1. HttpClient连接池设置引发的一次雪崩
  2. 【 FPGA 】UltraFast设计方法学:时序收敛之时序约束基本准则
  3. 数位dp 的简单入门
  4. Java与嵌入式数据库SQLite的结合
  5. Boost:bind绑定的unique_ptr测试程序
  6. python最大公约数计算_使用Python求解最大公约数的实现方法
  7. SAP License:特殊采购类型-寄售及其结算
  8. double精度丢失问题
  9. 大数据人才成了“香饽饽”
  10. java 生产mdb_Java生成mdb文件[MS Access文件]
  11. 忆我在北邮四年中的几位老师(全)
  12. 线性代数 | (4) n维向量
  13. “应用程序无响应”原因汇总
  14. 程序员后来都干啥去了
  15. DEDE织梦常用的调用方法
  16. c语言图片加水印,[求助]C语言 bmp文件加上水印
  17. 使用CSS实现悬停显示二维码
  18. 验证通扫描仪安装使用方法
  19. HiKey970固件烧写
  20. msys2及MinGW工具使用学习笔记

热门文章

  1. 【观察】新华三:云智原生,重塑未来
  2. 光明行动:共同呵护好孩子的眼睛——广西实施光明行动实地考察调研综述
  3. Supplementary Materials for The spread of true and false news online 解读
  4. 在线识别图片文字,分享识别技巧
  5. 多云时代下数据管理技术_建立一个混合的多云数据湖并使用Apache Spark执行数据处理...
  6. 【分享】常用JS(2)
  7. 《Designing Data-Intensive Application》01数据系统的基石-可靠性/可扩展性/可维护性
  8. Typora+smms+picGo(app) 图床使用办法
  9. windows10环境下iceworks(飞冰)安装
  10. php实现报表拖拉拽,看!这款BI工具用拖拉拽的方式做报表