Ошибка: не удается обработать запрос подкачки ядра на
Я пишу драйвер PCI для простого тестового устройства.
оборудование распознается правильно с помощью lspci (как вы можете видеть мой драйвер вабс зарегистрированной):
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
Инициализация и deinitalisation драйвера и PCI subystem работает отлично. Я получаю номер устройства, и 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 devicen");
goto cleanup_mem;
}
попытка прочитать из этого адреса memio со следующим кодом дает указанную ошибку:
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 %pn", (void *) memstart0);
test = readl((void *) memstart0);
return max_bytes_to_read;
}
Я также попробовал другие функции доступа, такие как memcpy_fromio, ioread32 и прямой доступ указателя с тем же результатом.
оборудование работает на машине Windows. Единственное заметное различие заключается в том, что Windows резервирует базовый адрес 0 как 00000000fd000000 в то время как Linux резервирует его как 00000000f0000000.
это для некоммерческой образовательной цели в государственной школе. Спасибо за помощь!
1 ответов
читать документация / IO-отображение.txt (поиск "iomap") и/или Глава 15 LDD3.
request_mem_region
просто гарантирует, что никакой другой драйвер не захватил эту область памяти. Вам все равно нужно сопоставить его с пространством виртуальной машины ядра, используя iomap
прежде чем вы можете читать/писать.
обратите внимание, что вся pci_resource_start
etc. танец несколько устарел. Я считаю, что рекомендуемый подход в эти дни есть:
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
. Но вышеизложенное (a) короче и (b) универсально между устройствами, сопоставленными с памятью, и теми, которые используют старое пространство ввода-вывода x86. (Не то, чтобы их было много вокруг.)