最近因爲一個bug涉及到DMAR的問題,網上baidu居然搜到了自己5年前寫的一篇講vt-d的水文,可笑的是因爲百度博客的嗝屁我自己都沒有了,還好這位兄臺轉載了,現在再看好多東西一下就回憶起來了,趕緊接它回家嘍。
-------------------------------------------------------------------------------------------------------------------------------------------------
翻看前文,發現還差一篇風河hypervisor硬件虛擬化的文章,懶得寫了,浪費時間.看過xen的代碼後覺得hypervisor就是隻小麻雀.以後有精力了寫寫xen裏面對x86硬件虛擬化技術的利用,那將是一個大篇幅.今天介紹下linux裏對x86硬件虛擬化技術的利用,算是個引子.xen裏面用到硬件虛擬化那是理所當然,有意思的是linux也用到了裏面的東西,vt-d,sr-iov.它當然不會用vt-x,這裏不講kvm,它本身就把linux變成了虛擬機而不是一個純內核了.同樣我不會寫代碼分析的細節,那是很無聊的事,只寫我認爲有意思的東西.
vt-d裏主要有兩個新技術,int remapping和dma remapping.
int remap在服務器配置中經常見到,如果系統中cpu超過255個或有apic_id>255的時候,intr是必須打開的,因爲ioxapic系統即使在物理目標模式也只支持8bit的cpu_id,沒有辦法把中斷分發給所有的cpu.而打開intr後,雖然ioapic中索引是16bit,但是irte中可以有32bit的物理地址或邏輯地址,最大能有2的32次個cpu.當然也有一些老系統只支持intr的xapic模式,也就是不能和x2apic配合,那和不打開也就沒什麼分別了,只在中斷遷移時能保證不丟中斷.intr關閉時,ioapic或msi/msix中觸發中斷後轉換成內存寫消息向上傳到北橋,被識別爲中斷後自動分發給相應的cpu,中間還會經過cpu的仲裁與選擇,識別是通過特殊地址信息fee來識別的.linux中已經基本有完善的支持了,只是缺msi這塊,msi目前只支持單箇中斷,倒不是無法實現,只是代碼要有大的改動,申請一段連續的vector和irq號都是比較困難的。msix比較不錯,沒有32個vector限制,而且每個vector和irq都不需要連續,缺點是會佔用一些mem空間。另外打開msi中斷後記得關閉legacy int。如果打開intr的話,rte或msix msg中要填的是一個索引,不是關於這個irq的所有信息,比如觸發模式,目標模式,目標地址,vector等。這個index會去索引內存中一個irte的表,找到後取出其中的信息轉發給apic。有意思的是這裏面的信息就是irq的所有信息。當然那個表未必是一個,要看這個系統是不是隻有一個pci段,或者說是不是隻有一個drhd單元。另外irte是有緩存的,修改irte後要有指令清除irte緩存.
所謂dmar就是給設備一個地址空間映射,設備對內存的訪問要通過一個頁表結構轉換成真正的訪存地址.也就是說設備地址就是個設備虛擬地址,真正的訪存地址是設備物理地址。這個頁表結構和cpu的頁表結構還有vmx的ept相似,可以有大頁,還有地址映射的緩存即所謂iotlb,等同於cpu的tlb,但是在北橋裏.有的系統爲了優化,在設備中也提供了device-iotlb,這些對軟件是透明的,只有特殊的刷新指令序列能改變它們.dmar在一些特殊場合有用,比如32bit pci設備要dma數據到4G以上地址,dmar可以提供這種映射,讓高端地址在pci設備中映射爲32bit的範圍之內.關閉dmar的話只能用軟件模擬了,即bounce-buffer.