一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

VFIO將DMA映射暴露給用戶態(tài)?

Linux閱碼場 ? 來源:Linuxer ? 作者:Linuxer ? 2020-12-26 09:39 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

在開始之前我們先要說一個東西就是 DMA,直接讓設(shè)備訪問內(nèi)存,可以不通過 CPU 搬運(yùn)數(shù)據(jù)。

48963e3a-4422-11eb-8b86-12bb97331649.jpg

這是一個比較簡單的體系結(jié)構(gòu)圖,設(shè)備 和 CPU 通過存儲控制器訪問存儲器。一個簡單的 case 是 CPU 向存儲器寫數(shù)據(jù),然后設(shè)備從存儲器讀數(shù)據(jù)。這么快來一切都很正常。但是實際上 CPU 是有一層緩存的,例如下面這樣的。

48b96504-4422-11eb-8b86-12bb97331649.jpg

CPU 想內(nèi)存寫數(shù)據(jù),但是先要清空到不一致的緩存,然后設(shè)備再去讀數(shù)據(jù),不然設(shè)備讀到的數(shù)據(jù)和 CPU 實際的數(shù)據(jù)會不一致(因為緩存里的數(shù)據(jù)可能和存儲器的不一致),而且實際上緩存也不只是一層,所以需要一個中間層來保證 從 CPU 的角度和從設(shè)備的角度內(nèi)存都是一致的,所以就有了下面這個結(jié)構(gòu)。

48db9c32-4422-11eb-8b86-12bb97331649.jpg

CPU 和 設(shè)備都會走緩存驗證一遍以后,再落到存儲器上,這樣帶上緩存以后大家的一致性都是一樣的了。所以從設(shè)備的角度,設(shè)備也擁有了緩存,實際上這個和 IOMMU 關(guān)系不是很大,接下來設(shè)備其實也可以和 CPU 一樣有一層 MMU,也就是地址到存儲器物理地址的轉(zhuǎn)換。注意,這里我用了地址,因為對 CPU 來說是虛擬地址,但是對設(shè)備來說是一個總線域的地址。這里要明確區(qū)分一下,一個是總線地址,是從設(shè)備的角度來看的,一個是 CPU 的虛擬地址,這是從 CPU 角度來看的,兩個是不同的東西。將總線域地址轉(zhuǎn)換成存儲器物理地址的設(shè)備就叫 IOMMU。

495b4f04-4422-11eb-8b86-12bb97331649.jpg

如果沒有 IOMMU,DMA 也能照常工作,IOMMU 的主要作用就是保護(hù)功能,防止使用 DMA 的設(shè)備訪問任意存儲器的物理地址。

IOMMU 在不同架構(gòu)上名字不太一樣,AMD 叫 AMD-Vi,最開始針對的設(shè)備只是顯卡,Intel 叫 VT-d,arm 叫 SMMU,具體對應(yīng)的手冊也不太一樣,但是主要解決的問題是一致的。在 VTd 中,dmar (DMA remapping) 就是那個 IOMMU 設(shè)備,通過中斷的方式實現(xiàn)類似 page fault 一樣的內(nèi)存分配行為。DMA 傳輸是由 CPU 發(fā)起的:CPU 會告訴 DMA 控制器,幫忙將 xxx 地方的數(shù)據(jù)搬到 xxx 地方。CPU 發(fā)完指令之后,就當(dāng)甩手掌柜了。IOMMU 有點像 MMU 是一個將設(shè)備地址翻譯到內(nèi)存地址的頁表體系,也會有對應(yīng)的頁表,這個東西在虛擬化中也非常有用,可以將原本有軟件模擬的設(shè)備,用直接的硬件替代,而原本的隔離通過 IOMMU 來完成。如下圖所示,原本需要通過軟件模擬的驅(qū)動設(shè)備可以通過 IOMMU 以安全的方式來直接把硬件設(shè)備分配個用戶態(tài)的 Guest OS。

49842d16-4422-11eb-8b86-12bb97331649.jpg

理論上講沒有 IOMMU 實際上是可以工作的,但是硬件的角度,設(shè)備就擁有了整個存儲器的全局視圖,這是無論如何都非常不合理的事情,不應(yīng)該讓設(shè)備擁有訪問任意物理內(nèi)存的能力。

這里要提的另外一個功能就是對中斷的隔離,類似于下面的通過在中斷請求中添加標(biāo)識來重定向中斷到對應(yīng)的中斷回調(diào)上。

49faa900-4422-11eb-8b86-12bb97331649.jpg

VFIO 的作用就是通過 IOMMU 以安全的方式來將設(shè)備的訪問直接暴露到用戶空間,而不用專門完成某個驅(qū)動等待合并到上游或者使用之前的對 IOMMU 沒有感知的 UIO 的框架。通過 VFIO 向用戶態(tài)開放 IOMMU 的功能,編寫用戶態(tài)的驅(qū)動。

對于 IOMMU 來說,隔離的級別不一定是單個設(shè)備,比如一個后面有幾個設(shè)備的 PCI 橋,從 PCI 橋角度來說,都是來自 PCI 橋的總線事務(wù)。所以 IOMMU 有一個iommu_group的概念,代表一組與其他設(shè)備隔離的設(shè)備的集合。

IOMMU 根據(jù)手冊上講還有一個域的概念,可以簡單理解為一段物理地址的抽象。

在iommu_group的層級上,VFIO 封裝了一層container class,這個的作用對應(yīng)于希望能夠在不同的iommu_group之間共享TLB和page tables,這個就是一個集合的概念,跟容器的那個概念沒啥關(guān)系,一個集合總歸要有個名字。通過把 host 的 device 和 driver 解綁,然后綁定到 VFIO 的 driver 上,就會有個/dev/vfio/$GROUP/出現(xiàn),然后這個$GROUP代表的就是這個 device 的iommu_group號,如果要使用 VFIO 就要把這個 group 下的所有 device 都解綁才可以。

通過打開/dev/vfio/vfio就能創(chuàng)建一個 VFIO 的 container,然后再打開/dev/vfio/$GROUP用VFIO_GROUP_SET_CONTAINERioctl 把文件描述傳進(jìn)去,就把 group 加進(jìn)去了,如果支持多個 group 共享頁表等結(jié)構(gòu),還可以把相應(yīng)的 group 也加進(jìn)去。(再強(qiáng)調(diào)一遍這個頁表是總線地址到存儲器物理地址,IOMMU 管理的那個頁表)。

下面舉個官方的栗子,獲取 PCI 設(shè)備 00000d.0 的group_id(PCI 命名的規(guī)則是domainslot.func)

$ readlink /sys/bus/pci/devices/00000d.0/iommu_group../../../../kernel/iommu_groups/26

使用之前需要你已經(jīng)加載了 VFIO 模塊

modprobevfio-pci

解綁 PCI 設(shè)備,然后創(chuàng)建一個 container id

$ lspci -n -s 00000d.006:0d.0 0401: 1102:0002 (rev 08)# echo 00000d.0 > /sys/bus/pci/devices/00000d.0/driver/unbind# echo 1102 0002 > /sys/bus/pci/drivers/vfio-pci/new_id

然后尋找其他同屬于一個 group 的設(shè)備

$ ls -l /sys/bus/pci/devices/0000:06:0d.0/iommu_group/devicestotal 0lrwxrwxrwx. 1 root root 0 Apr 23 16:13 0000:00:1e.0 -> ../../../../devices/pci0000:00/0000:00:1e.0lrwxrwxrwx. 1 root root 0 Apr 23 16:13 0000:06:0d.0 -> ../../../../devices/pci0000:00/0000:00:1e.0/0000:06:0d.0lrwxrwxrwx. 1 root root 0 Apr 23 16:13 0000:06:0d.1 ->../../../../devices/pci0000:00/0000:00:1e.0/0000:06:0d.1PCI 橋00001e.0后面掛了兩個設(shè)備,一個是剛才加進(jìn)去的00000d.0,還有一個是00000d.1,通過上面的步奏加進(jìn)去就可以。

最后一步是讓用戶有權(quán)限使用這個 group。

#chownuser:user/dev/vfio/26

下面就是一個樣例,從用戶態(tài)使用 VFIO,整個的使用方式是通過ioctl來獲取中斷相關(guān)信息,以及注冊中斷處理函數(shù),然后也是通過ioctl來獲取region信息,然后調(diào)用相應(yīng)的mmap函數(shù),讓 CPU 可以訪問內(nèi)存。

int container, group, device, i;struct vfio_group_status group_status ={ .argsz = sizeof(group_status) };struct vfio_iommu_type1_info iommu_info = { .argsz = sizeof(iommu_info) };struct vfio_iommu_type1_dma_map dma_map = { .argsz = sizeof(dma_map) };struct vfio_device_info device_info = { .argsz = sizeof(device_info) }; /* Create a new container */container = open("/dev/vfio/vfio", O_RDWR); if (ioctl(container, VFIO_GET_API_VERSION) != VFIO_API_VERSION) /* Unknown API version */ if (!ioctl(container, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU)) /* Doesn't support the IOMMU driver we want. */ /* Open the group */group = open("/dev/vfio/26", O_RDWR); /* Test the group is viable and available */ioctl(group, VFIO_GROUP_GET_STATUS, &group_status); if (!(group_status.flags & VFIO_GROUP_FLAGS_VIABLE)) /* Group is not viable (ie, not all devices bound for vfio) */ /* Add the group to the container */ioctl(group, VFIO_GROUP_SET_CONTAINER, &container); /* Enable the IOMMU model we want */ioctl(container, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU); /* Get addition IOMMU info */ioctl(container, VFIO_IOMMU_GET_INFO, &iommu_info); /* Allocate some space and setup a DMA mapping */dma_map.vaddr = mmap(0, 1024 * 1024, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);dma_map.size = 1024 * 1024;dma_map.iova = 0; /* 1MB starting at 0x0 from device view */dma_map.flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE; ioctl(container, VFIO_IOMMU_MAP_DMA, &dma_map); /* Get a file descriptor for the device */device = ioctl(group, VFIO_GROUP_GET_DEVICE_FD, "00000d.0"); /* Test and setup the device */ioctl(device, VFIO_DEVICE_GET_INFO, &device_info); for (i = 0; i < device_info.num_regions; i++) { struct vfio_region_info reg = { .argsz = sizeof(reg) }; reg.index = i; ioctl(device, VFIO_DEVICE_GET_REGION_INFO, ®); /* Setup mappings... read/write offsets, mmaps * For PCI devices, config space is a region */} for (i = 0; i < device_info.num_irqs; i++) { struct vfio_irq_info irq = { .argsz = sizeof(irq) }; irq.index = i; ioctl(device, VFIO_DEVICE_GET_IRQ_INFO, &irq); /* Setup IRQs... eventfds, VFIO_DEVICE_SET_IRQS */} /* Gratuitous device reset and go... */ioctl(device, VFIO_DEVICE_RESET);

在include/linux/vfio.h里面有完整的 API,這里就簡單略過。

在理解了一些基本原理和使用方式之后再來看 VFIO 的代碼應(yīng)該叫就比較容易理解了。

首先是作為 PCI 設(shè)備的probe。主要是通過vfio_iommu_group_get分配iommu_group,然后調(diào)用vfio_add_group_dev初始化設(shè)備回調(diào)接口vfio_pci_ops,而remove就是反過來把對應(yīng)的結(jié)構(gòu)釋放掉就可以。然后再看注冊的回調(diào)函數(shù)結(jié)構(gòu)體。

static const struct vfio_device_ops vfio_pci_ops = { .name = "vfio-pci", .open = vfio_pci_open, .release = vfio_pci_release, .ioctl = vfio_pci_ioctl, .read = vfio_pci_read, .write = vfio_pci_write, .mmap = vfio_pci_mmap, .request = vfio_pci_request,};

這里分析幾個關(guān)鍵的函數(shù),他們會通過file_operations vfio_fops被間接的調(diào)用。

首先是 mmap,就是在調(diào)用vfio_pci_mmap的時候最終調(diào)用remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, req_len, vma->vm_page_prot);來將物理內(nèi)存映射到用戶態(tài)空間,這就是上面的栗子中 mmap 系統(tǒng)調(diào)用的入口,而具體要映射的物理內(nèi)存是通過一系列pci_resource_xxx宏從 PCI bar 空間讀出來的配置。

然后是 ioctl 接口,這個接口比較豐富,也簡單的看一下。比如VFIO_DEVICE_SET_IRQS會通過使用用戶態(tài)傳進(jìn)來的結(jié)構(gòu)體,調(diào)用vfio_pci_set_irqs_ioctl注冊中斷處理函數(shù)。而通過vfio_ioctl_set_iommu會設(shè)置 container 的 iommu_group 以及對應(yīng)的 driver。read/write接口都是用于修改 PCI 配置信息的。

簡單的來說,VFIO 的主要工作是把設(shè)備通過 IOMMU 映射的 DMA 物理內(nèi)存地址映射到用戶態(tài)中,讓用戶態(tài)程序可以自行操縱設(shè)備的傳輸,并且可以保證一定程度的安全,另外可以自行注冊中斷處理函數(shù),從而在用戶態(tài)實現(xiàn)設(shè)備的驅(qū)動程序,通過這樣的框架,可以在 DPDK 中充分發(fā)揮用戶態(tài)協(xié)議棧的威力。

原文標(biāo)題:VFIO —將 DMA 映射暴露給用戶態(tài)

文章出處:【微信公眾號:Linuxer】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

責(zé)任編輯:haq

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴

原文標(biāo)題:VFIO —將 DMA 映射暴露給用戶態(tài)

文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    NVMe IP高速傳輸卻不依賴XDMA設(shè)計之五:DMA 控制單元設(shè)計

    DMA 控制單元負(fù)責(zé)控制 DMA 傳輸事務(wù), 該單元承擔(dān)了 DMA 事務(wù)到 NVMe 事務(wù)的轉(zhuǎn)換任務(wù), 使用戶對數(shù)據(jù)傳輸事務(wù)的控制更加簡單快捷。 D
    的頭像 發(fā)表于 07-02 19:47 ?1122次閱讀
    NVMe IP高速傳輸卻不依賴XDMA設(shè)計之五:<b class='flag-5'>DMA</b> 控制單元設(shè)計

    一文詳解AXI DMA技術(shù)

    AXI直接數(shù)值存?。―rect Memory Access,DMA)IP核在AXI4內(nèi)存映射和AXI4流IP接口之間提供高帶寬的直接內(nèi)存訪問。DMA可以選擇分散收集(Scatter Gather
    的頭像 發(fā)表于 04-03 09:32 ?1010次閱讀
    一文詳解AXI <b class='flag-5'>DMA</b>技術(shù)

    如何使用DMA進(jìn)行USART不定長度接收

    在上一講中,我們對USART進(jìn)行了簡單介紹,并講解了如何在不使用DMA的情況下進(jìn)行不定長度數(shù)據(jù)接收,本講著重講解如何使用DMA進(jìn)行USART不定長度接收。
    的頭像 發(fā)表于 02-18 17:01 ?935次閱讀
    如何使用<b class='flag-5'>DMA</b>進(jìn)行USART不定長度接收

    無法通過DMA讀取輸入捕獲寄存器的值

    想法:使用HC-SR04超聲波模塊檢測距離,利用輸入捕獲計算模塊高電平的時間與DMA傳輸輸入捕獲寄存器的數(shù)值。 配置描述: DMA設(shè)置為如下圖: 故障描述: 如果使用DMA,則數(shù)據(jù)顯
    發(fā)表于 02-10 14:31

    ZYNQ基礎(chǔ)---AXI DMA使用

    前言 在ZYNQ中進(jìn)行PL-PS數(shù)據(jù)交互的時候,經(jīng)常會使用到DMA,其實在前面的ZYNQ學(xué)習(xí)當(dāng)中,也有學(xué)習(xí)過DMA的使用,那就是通過使用自定義的IP,完成HP接口向內(nèi)存寫入和讀取數(shù)據(jù)的方式。同樣
    的頭像 發(fā)表于 01-06 11:13 ?2358次閱讀
    ZYNQ基礎(chǔ)---AXI <b class='flag-5'>DMA</b>使用

    TMS320DM643x DMP增強(qiáng)型DMA(EDMA)控制器用戶指南

    電子發(fā)燒友網(wǎng)站提供《TMS320DM643x DMP增強(qiáng)型DMA(EDMA)控制器用戶指南.pdf》資料免費下載
    發(fā)表于 12-16 10:25 ?0次下載
    TMS320DM643x DMP增強(qiáng)型<b class='flag-5'>DMA</b>(EDMA)控制器<b class='flag-5'>用戶</b>指南

    雅特力AT32F402/F405 DMA使用指南

    通道都支持外設(shè)的DMA請求映射到任意通道上。圖1.DMA控制器架構(gòu)DMAMUX簡介對于如何外設(shè)的DMA請求
    的頭像 發(fā)表于 11-20 01:03 ?1014次閱讀
    雅特力AT32F402/F405 <b class='flag-5'>DMA</b>使用指南

    如何設(shè)置內(nèi)網(wǎng)IP的端口映射到公網(wǎng)

    在現(xiàn)代網(wǎng)絡(luò)環(huán)境中,端口映射(Port Mapping)是一項非常實用的技術(shù),它允許用戶內(nèi)網(wǎng)設(shè)備的服務(wù)端口映射到公網(wǎng),使外網(wǎng)用戶可以訪問內(nèi)網(wǎng)
    的頭像 發(fā)表于 11-14 14:23 ?1985次閱讀

    DMA是什么?詳細(xì)介紹

    DMA(Direct Memory Access)是一種允許某些硬件子系統(tǒng)直接訪問系統(tǒng)內(nèi)存的技術(shù),而無需中央處理單元(CPU)的介入。這種技術(shù)可以顯著提高數(shù)據(jù)傳輸速率,減輕CPU的負(fù)擔(dān),并提高整體
    的頭像 發(fā)表于 11-11 10:49 ?1.9w次閱讀

    為什么gv7601在spi用戶態(tài)訪問寄存器時,讀取音頻寄存器讀不到信息,是要設(shè)置什么嗎?

    為什么gv7601在spi用戶態(tài)訪問寄存器時。讀取視頻寄存器正常。讀取音頻寄存器讀不到信息。是要設(shè)置什么嗎?
    發(fā)表于 11-04 08:21

    Juniper防火墻配置NAT映射的問題分析

    的情況下,啟用VIP的Server Auto Enable 功能引起的NAT映射失效問題,希望可以碰到相同問題的人一些參考。
    的頭像 發(fā)表于 10-29 09:55 ?994次閱讀
    Juniper防火墻配置NAT<b class='flag-5'>映射</b>的問題分析

    DMA與C64x的框架組件結(jié)合使用

    電子發(fā)燒友網(wǎng)站提供《DMA與C64x的框架組件結(jié)合使用.pdf》資料免費下載
    發(fā)表于 10-16 10:29 ?0次下載
    <b class='flag-5'>將</b><b class='flag-5'>DMA</b>與C64x的框架組件結(jié)合使用

    用于ADC的DMA乒乓

    電子發(fā)燒友網(wǎng)站提供《用于ADC的DMA乒乓.pdf》資料免費下載
    發(fā)表于 09-07 11:27 ?1次下載
    用于ADC的<b class='flag-5'>DMA</b>乒乓

    2k1000LA星云板上的SATA的DMA訪存異常

    地址的CLB(但是這里依舊有疑問:使用uboot提供的高32位中的高4位明明是0x9,但是為什么沒有被窗口過濾呢?)。 假設(shè)是窗口映射有問題,我IO DMA的win0的mask配置為 0xFFFF
    發(fā)表于 08-17 00:30

    揭秘車載VCU項目之外掛界的“大哥”DMA

    引腳配置此實例選擇CAN0進(jìn)行配置。三、外設(shè)配置對于DMA,其采用的固定映射,對于通道0至通道15,其映射一部分外設(shè),通道16至通道31映射一部分外設(shè),所以對于外設(shè)要使用
    的頭像 發(fā)表于 07-30 08:11 ?1381次閱讀
    揭秘車載VCU項目之外掛界的“大哥”<b class='flag-5'>DMA</b>