Фон
Для моего исследовательского проекта я создаю инструмент, проверяющий правильность алгоритмов и структур данных, предназначенных для постоянной (энергонезависимой) памяти.Чтобы обеспечить краткий обзор проблемы с постоянной памятью, кэш ЦП является энергозависимым, и поэтому ожидающие записи в кэш обратной записи будут потеряны при сбое питания, что приведет к несогласованности.Следовательно, чтобы проверить правильность таких алгоритмов, я планирую периодически проверять содержимое основной памяти без отслеживания из других кэшей ЦП или даже из кэша текущего ЦП и использовать его в качествесредства проверки правильности.
Проблема
После небольшого исследования я обнаружил, что можно выполнять некогерентный 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);