我試圖使用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
根本不等。 可能是什麼原因?
您是否檢查過「MONITOR' /'MWAIT'可用(即您的BIOS尚未關閉)?其次,你應該在你監視之前執行'clflush' *,否則你只是使緩存無效,迫使它被寫回內存(如果它是髒的),從而觸發等待條件。 – Necrolis
'MWAIT'可以返回「提前」。首先,由於不可屏蔽的事件(NMI,SMI和其他一些'OS以下控制'中斷機制以及異步故障),但其次,更重要的是,由於_ordinary_中斷,除非它們被明確禁用( ''__cli()'和/或'local_irq_disable()'在Linux中...通常不是一個好主意,很多副作用)。在OS'_'idle()'_loop_外面使用它是一個非常相當於在驅動程序代碼中重新實現調度程序部分的任務(您的代碼引用是Linux「idle()」的一部分)。 ..)。你在編寫內核繞過代碼嗎? –
@Necrolis謝謝,當然'clflush'不在正確的地方;然而修復它並沒有幫助。按照CPUID,MONITOR似乎已啓用。 –