【发布时间】:2014-02-10 08:02:17
【问题描述】:
我正在尝试使用monitor/mwait 指令来监控从设备到内存位置的 DMA 写入。在内核模块(字符设备)中,我有以下代码(非常类似于内核代码的this piece)在内核线程中运行:
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 没有关闭它)?其次,您应该在监控之前执行clflushbefore,否则您只会使缓存无效,强制将其写回内存(如果它是脏的)从而触发等待条件。 -
MWAIT可以“提前”返回。一方面,由于不可屏蔽事件(NMI、SMI 和其他一些“低于操作系统控制”的中断机制,以及异步故障),但第二,更重要的是,由于 普通 中断,除非它们已被明确禁用(Linux 中的__cli()和/或local_irq_disable()...通常不是一个好主意,有很多副作用)。 在操作系统之外使用它idle()loop 是......一项任务几乎等同于在驱动程序代码中重新实现调度程序的那一部分(您的代码引用是 Linux 的一部分idle()...)。你在写内核绕过代码吗? -
@Necrolis 谢谢,当然
clflush不在正确的位置;但是修复它并没有帮助。根据 CPUID,MONITOR 似乎已启用。 -
@FrankH。这不是内核低音。我有一个写入特定内存位置(通过 DMA)的设备,我正在尝试各种方法来尝试找出它何时写入以及写入什么。
-
@Jianchen 不,我最终在用户空间进行了忙碌等待——这对我的目的来说已经足够了。
标签: linux-kernel x86 dma