2014-02-10 46 views
9

我試圖使用monitor/mwait指令來監視從設備到內存位置的DMA寫入。在於,在內核線程運行的內核模塊(字符設備)我有以下代碼(非常類似於內核代碼this piece):mwait x86指令不會等待DMA

static int do_monitor(void *arg) 
{ 
    struct page *p = arg; // p is a 'struct page *'; it's also remapped to user space 
    uint32_t *location_p = phys_to_virt(page_to_phys(p)); 
    uint32_t prev = 0; 
    int i = 0; 
    while (i++ < 20) // to avoid infinite loop 
    { 
    if (*location_p == prev) 
    { 
     __monitor(location_p, 0, 0); 
     if (this_cpu_has(X86_FEATURE_CLFLUSH_MONITOR)) 
      clflush(location_p); 
     if (*location_p == prev) 
      __mwait(0, 0); 
    } 
    prev = *location_p; 
    printk(KERN_NOTICE "%d", prev); 
    } 
} 

在用戶空間我有以下測試代碼:

int fd = open("/dev/mon_test_dev", O_RDWR); 
unsigned char *mapped = (unsigned char *)mmap(0, mmap_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 
for (int i = 1; i <= 5; ++i) 
    *mapped = i; 
munmap(mapped, mmap_size); 
close(fd); 

而且內核日誌看起來是這樣的:

1 
2 
3 
4 
5 
5 
5 
5 
5 
5 
5 5 5 5 5 5 5 5 5 5 

即看起來mwait根本不等。 可能是什麼原因?

+0

您是否檢查過「MONITOR' /'MWAIT'可用(即您的BIOS尚未關閉)?其次,你應該在你監視之前執行'clflush' *,否則你只是使緩存無效,迫使它被寫回內存(如果它是髒的),從而觸發等待條件。 – Necrolis

+1

'MWAIT'可以返回「提前」。首先,由於不可屏蔽的事件(NMI,SMI和其他一些'OS以下控制'中斷機制以及異步故障),但其次,更重要的是,由於_ordinary_中斷,除非它們被明確禁用( ''__cli()'和/或'local_irq_disable()'在Linux中...通常不是一個好主意,很多副作用)。在OS'_'idle()'_loop_外面使用它是一個非常相當於在驅動程序代碼中重新實現調度程序部分的任務(您的代碼引用是Linux「idle()」的一部分)。 ..)。你在編寫內核繞過代碼嗎? –

+0

@Necrolis謝謝,當然'clflush'不在正確的地方;然而修復它並沒有幫助。按照CPUID,MONITOR似乎已啓用。 –

回答

5

MONITOR/MWAIT語義的定義沒有明確規定DMA事務是否可以觸發它。假設觸發發生在邏輯處理器的商店中。

英特爾官方軟件開發人員手冊中對MONITOR和MWAIT的描述在這方面非常模糊。但是,有兩個子句中,引起了我的注意MONITOR部分:

  1. EAX的內容是一個有效的地址(在64位模式下,RAX使用)。默認情況下,DS段用於創建受監視的線性地址。

  2. 地址範圍必須使用回寫型的存儲器。只有回寫內存才能正確觸發監視硬件。

第一個條款規定,MONITOR是用於線性地址,而不是物理地址。設備及其DMA只能用於物理地址。所以基本上這意味着依賴於相同MONITOR範圍的所有代理應該在虛擬內存空間的相同域中操作。

第二個子句要求被監視的內存區域可以緩存(寫回,WB)。對於DMA,通常必須將相應的內存範圍標記爲不可緩存,或者最好是寫入組合(UC或WC)。這甚至更強烈地表明,使用MONITOR/MWAIT由DMA觸發的意圖不太可能在當前的硬件上工作。


考慮您的高層次的目標 - 能夠告訴當設備已致函給內存範圍 - 我不記得任何可靠的方法來實現它,除了使用虛擬化設備(VTd的,IOMMU等。 )基本上,外圍設備的經典方法是在寫入內存時發出中斷。在中斷到來之前,CPU無法判斷所有DMA字節是否已成功到達內存中的目的地。

設備虛擬化允許以透明的方式從設備中抽象物理地址,並且在嘗試從內存寫入/讀取時具有相當的頁面錯誤。