инструкция MWAIT x86 не ждет DMA


Я пытаюсь использовать monitor/mwait Инструкции по мониторингу DMA записываются с устройства в ячейку памяти. В модуле ядра (char device) у меня есть следующий код (очень похожий на этот кусок кода ядра), который выполняется в потоке ядра:

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 вообще не ждет. В чем может быть причина?

1 9

1 ответ:

Определение семантики MONITOR/MWAIT не указывает явно, могут ли транзакции DMA инициировать его или нет. Предполагается, что срабатывание происходит для логических процессорных хранилищ.

Текущие описания MONITOR и MWAIT в официальном руководстве Intel для разработчиков программного обеспечения довольно расплывчаты в этом отношении. Однако в разделе монитора есть два пункта, которые привлекли мое внимание:

  1. Содержимое EAX является эффективным адресом (в 64-битном режиме, Используется РАКС находится). По умолчанию сегмент DS используется для создания линейного адреса, который отслеживается.

  2. Диапазон адресов должен использовать память типа обратной записи. Только память обратной записи правильно вызовет оборудование для мониторинга.

Первое предложение гласит, что монитор предназначен для использования с линейными адресами, а не физическими. Устройства и их DMA предназначены для работы только с физическими адресами. Так что в основном это означает, что все агенты полагаются на одно и то же Диапазон мониторов должен работать в той же области пространства виртуальной памяти.

Второе предложение требует, чтобы контролируемая область памяти была кэшируемой (write-back, WB). Для DMA соответствующий диапазон памяти обычно должен быть помечен как недоступный для записи или в лучшем случае комбинированный (UC или WC). Это еще более сильный показатель того, что ваше намерение использовать MONITOR/MWAIT для запуска DMA вряд ли сработает на текущем оборудовании.


Учитывая вашу цель высокого уровня-уметь скажите, когда устройство записало в заданный диапазон памяти - я не могу вспомнить ни одного надежного метода для его достижения, кроме использования виртуализации для устройств (VTd, IOMMU и т. д.) В принципе, классический подход для периферийного устройства заключается в том, чтобы выдавать прерывание, когда оно выполняется с записью в память. Пока не поступит прерывание, ЦП не сможет определить, все ли байты DMA успешно достигли места назначения в памяти.

Виртуализация устройств позволяет абстрагировать физические адреса от устройство в прозрачном виде, и имеют эквивалент ошибки страницы, когда он пытается записать/прочитать из памяти.