ОШИБКА: невозможно обработать запрос пейджинга ядра на

Я пишу драйвер PCI для простого тестового устройства.

Оборудование корректно распознается с помощью lspci (как видите, мой драйвер vabs зарегистрирован):

04:02.0 Non-VGA unclassified device: Device bace:55aa
    Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
    Status: Cap- 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
    Latency: 0
    Region 0: Memory at f0000000 (32-bit, prefetchable) [size=16M]
    Kernel driver in use: vabs

Инициализация и деинициализация драйвера и подсистемы PCI работают нормально. Я получаю номер устройства, и udev создает файл устройства.

При чтении из файла устройства я получаю следующее сообщение об ошибке:

BUG: unable to handle kernel paging request at 00000000f0000000

Я успешно запрашиваю ресурсы PCI при инициализации. Это возвращает 00000000f0000000 для memstart0, что является моим базовым адресом 0 для PCI.

memstart0 = pci_resource_start( pdev, 0 );
memlen = pci_resource_len( pdev, 0 );
if( request_mem_region(memstart0,memlen,pdev->dev.kobj.name)==NULL ) {
    dev_err(&pdev->dev,"Memory address conflict for device\n");
    goto cleanup_mem;
}

Попытка чтения с этого мемо-адреса с помощью следующего кода дает указанную ошибку:

ssize_t driver_read(struct file *instance, char __user *buffer, size_t max_bytes_to_read, loff_t *offset) {
    u32 test;

    dev_dbg(vabs_dev,"copying from %p\n", (void *) memstart0);
    test = readl((void *) memstart0);

    return max_bytes_to_read;
}

Я также пробовал другие функции доступа, такие как memcpy_fromio, ioread32 и прямой доступ по указателю с тем же результатом.

Аппаратное обеспечение работает на машине Windows. Единственное заметное отличие состоит в том, что Windows резервирует базовый адрес 0 как 00000000fd000000, а Linux резервирует его как 00000000f0000000.

Это для некоммерческих образовательных целей в государственной школе. Спасибо за вашу помощь!


person kohpe    schedule 10.12.2012    source источник


Ответы (1)


Прочтите Documentation/IO-mapping.txt (найдите "iomap ") и/или Глава 15 LDD3.

request_mem_region просто гарантирует, что никакой другой драйвер уже не захватил эту область памяти. Вам все еще нужно сопоставить его с пространством виртуальных машин ядра, используя iomap, прежде чем вы сможете читать/записывать его.

Обратите внимание, что весь танец pci_resource_start и т. д. несколько устарел. Я считаю, что рекомендуемый подход в наши дни:

pci_request_regions(pdev, "myname");  /* to request regions for all BARs */

Затем:

void __iomem *base = pci_iomap(pdev, 0, pci_resources_len(pdev,0)); /* to map BAR 0 */

Затем:

ioread32(base + offset);  /* Or readl(base + offset), but this is more generic */

И, наконец, в конце:

pci_iounmap(pdev, base);  /* Release kernel VM mapping (undoes pci_iomap) */
pci_release_regions(pdev); /* Release all regions (undoes pci_request_regions) */

Вы можете сделать первые два вручную, комбинируя pci_resource_start, pci_resource_len, request_mem_region и iomap. Но приведенное выше (а) короче и (б) является общим для устройств с отображением памяти и тех, которые используют старое пространство ввода-вывода x86. (Не то, чтобы их было много вокруг.)

person Nemo    schedule 10.12.2012
comment
Большое тебе спасибо. Теперь это работает. Я использую книгу по программированию драйверов, в которой полностью игнорируется тема пейджинга! - person kohpe; 11.12.2012
comment
Рад, что смог помочь. Вы можете принять мой ответ :-) - person Nemo; 11.12.2012