Некогерентный доступ к основной памяти через потоковые отображения DMA - PullRequest
0 голосов
/ 14 октября 2018

Фон

Для моего исследовательского проекта я создаю инструмент, проверяющий правильность алгоритмов и структур данных, предназначенных для постоянной (энергонезависимой) памяти.Чтобы обеспечить краткий обзор проблемы с постоянной памятью, кэш ЦП является энергозависимым, и поэтому ожидающие записи в кэш обратной записи будут потеряны при сбое питания, что приведет к несогласованности.Следовательно, чтобы проверить правильность таких алгоритмов, я планирую периодически проверять содержимое основной памяти без отслеживания из других кэшей ЦП или даже из кэша текущего ЦП и использовать его в качествесредства проверки правильности.

Проблема

После небольшого исследования я обнаружил, что можно выполнять некогерентный DMA, но только с помощью потоковых отображений DMA.У меня проблема в том, что DMA требует struct device, который представляет реальное устройство, но я хочу просто прочитать в буфер .

Что я пробовал

Я выделил буфер B и попытался использовать API platform_device (linux / platform_device.h) для создания псевдо-устройства.Я использую platform_device_alloc для выделения struct platform_device (без проверки NULL), я настраиваю struct resource для установки .start = virt_to_phys(B), .end = dirt_to_phys(B) + sizeof(B) и .flag = IORESOURCE_MEM, а также .name.У меня в полях num_resources и resources установлены соответствующие значения выше struct resource.

В результате получается сообщение ядра BUG ...

BUG: unable to handle kernel NULL pointer dereference at 0000000000000000

Я что-то здесь упускаю.Существует ли более простой способ чтения непосредственно из памяти без потоковой передачи DMA, а если нет, то есть ли способ создать struct device, который просто записывает в буфер?

Минимальный рабочий пример

Нижеэто минимальный рабочий пример того, что я пытаюсь сделать.В этом тесте я хочу записать значение в testMemory, которое предположительно будет храниться в кэше обратной записи, а затем выполнить некогерентную потоковую передачу памяти DMA в readMemory, и, следовательно,readMemory должно быть любым другим значением, кроме того, которое мы только что написали testMemory.

#include <linux/init.h>             
#include <linux/module.h>         
#include <linux/kernel.h>           
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>

MODULE_LICENSE("GPL");             
MODULE_AUTHOR("Louis Jenkins");      
MODULE_DESCRIPTION("Persistent Memory Analysis Tool - Kernel Module");
MODULE_VERSION("0.1");

static uint64_t *testMemory;
static uint64_t *readMemory;
static struct resource res[] = {{0}};
static struct platform_device *pdev;

static int __init dummymodule_init(void){
   void *addr;
   int i;
   int ret;
   size_t size;
   dma_addr_t dma_handle;

   // Allocate memory...
   testMemory = kvzalloc(sizeof(*testMemory), GFP_KERNEL);
   readMemory = kvzalloc(sizeof(*readMemory), GFP_KERNEL);

   // Give testMemory a deterministic value
   *testMemory = 1;

   // Initialize resource to point to the readMemory (so that it will do a DMA memory-to-memory
   // transfer from testMemory into readMemory...
   res[0] = (struct resource) {
       .start = virt_to_phys(readMemory),
       .end = virt_to_phys(readMemory) + sizeof(*readMemory),
       .flags = IORESOURCE_MEM,
       .name = "readMemory"
   };

   // Some debug information...
   printk(KERN_INFO ".start = %u, .end = %u\n", res[0].start, res[0].end);

   // Allocate platform device
   pdev = platform_device_alloc("Non-Coherent DMA Memory Prodding Tool", 0);

   // Ensure that it did not return NULL
   printk(KERN_INFO "Allocated pdev: %x", pdev);
   BUG_ON(pdev == NULL);

   // Configure resources
   pdev->num_resources = 1;
   pdev->resource = res;

   // Add device
   ret = platform_device_add(pdev);
   if (ret != 0) {
    printk(KERN_ERR "Could not add device! error=%d", ret);
    BUG();
   }

   // Perform DMA memory-to-memory of testMemory into (hopefully) readMemory
   dma_handle = dma_map_single(&pdev->dev, testMemory, sizeof(*testMemory), DMA_TO_DEVICE);
   BUG_ON(dma_mapping_error(&pdev->dev, dma_handle));

   for(i = 0; i < 1000000; i++) {
       // I don't know if DMA will be performed immediately, so I poll on it a bit...
       if (readMemory == 0) {
           __asm__ __volatile__ ("NOP");
       } else {
           break;
       }
   }

   // Debug information... Prints out whether we read the value from CPU Cache or not 
   printk(KERN_INFO "testMemory = %d, readMemory = %d", *testMemory, *readMemory);
   dma_unmap_single(&pdev->dev, dma_handle, size, DMA_TO_DEVICE);

   return 0;
}

static void __exit dummymodule_exit(void){
   kvfree(testMemory);
   kvfree(readMemory);
   platform_device_unregister(pdev);
}

module_init(dummymodule_init);
module_exit(dummymodule_exit); 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...