qemu 內存模型(1)---文檔

首先閱讀qemu的memory.txt文檔, 大概有如下信息可知

1 首先AddressSpace是cpu可以看到的地址空間,一般就是cpu地址總線寬度的可尋址範圍

主要包括兩個地址空間

 1 ram 空間 , 通過mov等指令直接訪問

 2 I/O空間, 通過out in等io指令訪問

2 MemoryRegion 用於記錄連續內存/io空間和host 虛擬地址的關係, 和這段連續空間的設備屬性

1 ram 比較簡單的內存空間,讀寫對應直接修改 hva, 初始memory_region_init_ram, memory_region_init_resizeable_ram, memory_region_init_ram_from_file, memory_region_init_ram_ptr 函數用於初始化

2 mmio 這些空間對應於設備的地址空間映射到內存地址空間的空間(也就是mmio), 讀寫這些地址空間都會觸發對應模擬設備的回調操作 memory_region_init_io 初始化

3 ROM 只讀空間, 讀直接訪問hva, 寫則拒絕,使用memory_region_init_rom() 初始化

4 rom device 這類空間讀直接訪問hva, 寫則回調設備註冊的函數(設備可能進行出錯處理)

5 IOMMU 用於iommu建模型,也就是支持iommu的設備模擬 memory_region_init_iommu()

6 container 邏輯單元, 邏輯單元內的地址可以通過overlay覆蓋, memory_region_init() 初始化容器

7 別名: 比較難理解, 比如我的pci是一個MemoryRegion是一個Region, 對應一片連續的hva, 但是我要把它映射到ram的地址空間, 就需要別名機制,把pci的一段地址分裂出一個別名,把這個別名放入Ram MemoryRegion的子region中,這樣這段地址在, 也就是同一個MemoryRegion有相同

的設備屬性(MMIO, RAM , ROM , ROM DEVICES), 但是可能在不連續的AddressSpace, 就是這樣.

addresspace上是在ram所在的區域,但是實際的hva卻指向pci的region, memory_region_init_alias() 初始化

8 保留區域: 主要用於調試,使用 memory_region_init_io() 初始化

3 幾個約束和建議

1 別名MemoryRegion沒有子Region

2 建議使用一個純容器作爲父MemoryRegion, 一個整個空間的MemoryRegion作爲背景MemoryRegion, 其他MemoryRegion 覆蓋到這個MemoryRegion上面, 當讀寫MemoryRegion對應的AddressSpace的時候, 只回調相應MemoryRegion的地址

4 遷移

Where the memory region is backed by host memory (RAM, ROM and
ROM device memory region types), this host memory needs to be
copied to the destination on migration. These APIs which allocate
the host memory for you will also register the memory so it is
migrated:

  • memory_region_init_ram()
  • memory_region_init_rom()
  • memory_region_init_rom_device()

For most devices and boards this is the correct thing. If you
have a special case where you need to manage the migration of
the backing memory yourself, you can call the functions:

  • memory_region_init_ram_nomigrate()
  • memory_region_init_rom_nomigrate()
  • memory_region_init_rom_device_nomigrate()
    which only initialize the MemoryRegion and leave handling
    migration to the caller.

The functions:

  • memory_region_init_resizeable_ram()
  • memory_region_init_ram_from_file()
  • memory_region_init_ram_from_fd()
  • memory_region_init_ram_ptr()
  • memory_region_init_ram_device_ptr()
    are for special cases only, and so they do not automatically
    register the backing memory for migration; the caller must
    manage migration if necessary.
    也就是說對於兩種類型的MemoryRegion, 一種對應hva, 這種系統會直接幫忙遷移(也就是自動保存,複製)
    另外一種不對應hva, 需要設備實現者自己去在相應的回調中實現保存複製

5 MemoryRegion的名稱

名字大部分用於調試,也有部分用於遷移時的複製,所以不要隨便修改名字

6 優先級和覆蓋策略

memory_region_add_subregion_overlap() 函數允許一個MemoryRegion覆蓋容器中的其他區域, 覆蓋是根據優先級來設置的,高優先級覆蓋低優先級地址
如果高優先級的MemoryRegion是別名或者容器, 地址是不連續的,則會留下一些空洞,低優先級的MemoryRegion會在這些空洞的地方漏出來

A是一個純容器,裏面有B和C兩個子MemoryRegion, C的優先級是1 , 相對A偏移爲0, 大小爲6000

B是一個純容器,裏面有兩個MemoryRegion.分別是D和E, D相對B偏移爲0,大小爲1000, E相對B偏移爲2000,大小爲1000,如下圖

    0      1000   2000   3000   4000   5000   6000   7000   8000
    |------|------|------|------|------|------|------|------|

A: [ ]
C: [CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC]
B: [ ]
D: [DDDDD]
E: [EEEEE]

最終映射處的地址如下
[CCCCCCCCCCCC][DDDDD][CCCCC][EEEEE][CCCCC]

如果B不是一個純容器,是一個MMIO區域則如下
[CCCCCCCCCCCC][DDDDD][BBBBB][EEEEE][BBBBB]
另外優先級比較只發生在同一個容器的不同MemoryRegion中, 所以容器只能管理子區域不影響其他區域

7 可見性

當guest os 操作內存地址(gpa)的時候,使用如下規則選擇MemoryRegion

遞歸向下

根區域的子區域按照優先級進行匹配
    - 如果一個區域的地址不匹配,則子區域也不匹配
    - 如果一個區域是葉子區域, 地址匹配則匹配
    - 如果是一個容器,按照相同算法遞歸向下匹配
    - 如果區域是一個別名, 則與別名目標區域進行匹配
    - 如果區域是一個純容器區域,則該區域的子區域不包含該地址,尋找下一個區域(因爲這個純容器可能存在一個洞), 否則直接返回未找到
如果上述沒有找到,則該區域不存在

7 示例

system_memory: container@0-2^48-1
|
±— lomem: alias@0-0xdfffffff —> #ram (0-0xdfffffff)
|
±— himem: alias@0x100000000-0x11fffffff —> #ram (0xe0000000-0xffffffff)
|
±— vga-window: alias@0xa0000-0xbffff —> #pci (0xa0000-0xbffff)
| (prio 1)
|
±— pci-hole: alias@0xe0000000-0xffffffff —> #pci (0xe0000000-0xffffffff)

pci (0-2^32-1)
|
±-- vga-area: container@0xa0000-0xbffff
| |
| ±-- alias@0x00000-0x7fff —> #vram (0x010000-0x017fff)
| |
| ±-- alias@0x08000-0xffff —> #vram (0x020000-0x027fff)
|
±— vram: ram@0xe1000000-0xe1ffffff
|
±— vga-mmio: mmio@0xe2000000-0xe200ffff

ram: ram@0x00000000-0xffffffff

system_memory爲一個純容器,這裏對應cpu看到的AddressSpace , 0-2^48 地址空間. ram的大小是 4g, lomem 1:1映射到 system_memory的AddressSpace的 0-3.5G,

himem映射到4-4.5G AddressSpace. 留下3.5G-4G的空洞, 使用pci-hole別名進行映射(這部分其實是pci MemoryRegion的0xe0000000-0xffffffff區域的一個別名)

vag-window別名映射在memory AddressSpace的 640K-768K, 優先級比較高會覆蓋 lomem, 內存控制器可以移除這個別名暴露下面的ram地址空間

pci MemoryRegion沒有對應的地址空間, 只用於映射到 memory AddressSpace, 包含兩個子區域 .

vga-area區域模擬vga窗口, 由兩個32k的區域組成,模擬vga雙緩衝

varm 和 vga-mmio 作爲pci的子區域, vram在地址e1000000處被映射爲BAR,並且在其之後映射包含MMIO寄存器的附加BAR

8 MMIO 操作

mmio區域提供讀寫回調, 還可以添加額外的限制

1 指定設備訪問的最大和最小地址大小

.valid.min_access_size,
.valid.max_access_size

2 對齊要求
.valid.unaligned 表示該設備支持未對齊的訪問

3 實現的訪問大小

.impl.min_access_size, .impl.max_access_size

4 .impl.unaligned 實現的對齊要求

5 .old_mmio 老式的內存訪問

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章