内核空间中PCI内存的地址映射

我正在尝试从可加载的内核模块读取和写入PCI设备。

因此我按照这篇文章 :

pci_enable_device(dev); pci_request_regions(dev, "expdev"); bar1 = pci_iomap(dev, 1, 0); // void iowrite32(u32 val, void __iomem *addr) iowrite32( 0xaaaaaaaa, bar1 + 0x060000); /* offset from device spec */ 

但最终设备没有按预期完成他的工作。 然后我查看bar1后面的地址,发现了一个非常大的值ffffbaaaaa004500

在这一点上,我真的不明白那里发生了什么,什么是正确的。 我可以将bar1解释为内核地址空间内的地址,该地址直接指向基本地址,该地址是PCI芯片选择地址的0x60000偏移量吗?

如何将写入bar1 + offset的值复制到设备中? 该机制如何在iowrite32pci_iomap后面工作?

感谢致敬

亚历克斯

PS:我成功测试了同一地址的回读。


注册PCI设备的说明:

  • PCIBAR0 PCI基地址0; 用于存储器映射配置寄存器
  • PCIBAR1 PCI基地址1; 用于I / O映射配置寄存器
  • PCIBAR2 PCI基地址2; 用于本地地址空间0
  • PCIBAR3 PCI基地址3; 用于本地地址空间1
  • PCIBAR4未使用的基址
  • PCIBAR5未使用的基地址

再次问好。

在上一次我尝试了几种方法与BAR2寄存器进行通信但没有成功。 这是我的实际代码:

 #include  #include  #include  #include  #include  #include  MODULE_LICENSE("GPL"); MODULE_AUTHOR("Alex"); MODULE_DESCRIPTION("test module."); MODULE_VERSION("0.1"); #define DEV_PCI_VENDORID 0x10B5 #define DEV_PCI_DEVICEID 0x1860 static struct pci_device_id pci_drvIdTable[] = { { .vendor = DEV_PCI_VENDORID, // vendor ID .device = DEV_PCI_DEVICEID, // device ID .subvendor = PCI_ANY_ID, // no subsystem available .subdevice = PCI_ANY_ID, // no subsystem available .class = PCI_CLASS_NOT_DEFINED, // no device class .class_mask = 0, // no device class .driver_data = 0 // no private data to the driver }, { 0, } // end of table }; struct pci_data { /// the IO mapping for the PCI config space uint32_t *pciConfigAddr; uint32_t *pciB2Addr; // void __iomem *pciConfigAddr; wait_queue_head_t waitq; uint8_t flag; } *data; static irqreturn_t _expdev_irq (int irq, void *pdata) { struct pci_data *data = pdata; printk(KERN_INFO "Interrupt talks...\n"); data->flag = 1; wake_up_interruptible( &data->waitq ); return IRQ_HANDLED; } static int _pci_probe ( struct pci_dev *pdev, const struct pci_device_id *ent ) { int ret = 0; int i; u16 reg_16; unsigned long bas2addr; data = kzalloc( sizeof(*data) , GFP_KERNEL ); if( !data ) { printk(KERN_ERR "Failed to allocate memory.\n"); return -ENOMEM; } pci_set_drvdata(pdev, data); // enabling the device ret = pci_enable_device(pdev); if( ret ) { printk(KERN_ERR "Failed to enable PCI device.\n"); goto no_enable; } pci_read_config_word(pdev,0,&reg_16); printk(KERN_INFO "VendorID. %x\n",reg_16); // checking if PCI-device reachable by checking that BAR0 is defined and // memory mapped if( !(pci_resource_flags(pdev,0) & IORESOURCE_MEM) ) { printk(KERN_ERR "Incorrect BAR configuration.\n"); ret = -ENODEV; goto bad_bar; } // taking ownership of a memory region ret = pcim_iomap_regions(pdev, 0b0100, "expdev"); // ret = pci_request_regions(pdev,"expdev"); if( ret ) { printk(KERN_ERR "Failed to request regions.\n"); goto failed_request_regions; } bas2addr = pci_resource_start(pdev, 2); reg_16 = 0xAA; i = 0x060000; iowrite16( reg_16 , (unsigned long *)(bas2addr+i) ); printk( KERN_INFO "BAR2 Register[0x%x] = 0x%x\n", i, ioread32( (unsigned long *)(bas2addr+i) ) ); printk(KERN_INFO "Module successfully initialised.\n"); return 0; // Error handling - backward disabling the device failed_request_regions: bad_bar: pci_disable_device(pdev); no_enable: pci_set_drvdata(pdev, data); return ret; } static void _pci_remove( struct pci_dev *pdev ) { free_irq(pdev->irq, data); pci_disable_msi(pdev); pci_clear_master(pdev); pci_iounmap(pdev,data->pciConfigAddr); pci_release_regions(pdev); pci_disable_device(pdev); printk(KERN_INFO "PCI-device removed.\n"); } static struct pci_driver pci_drv = { .name = "expdev", .id_table = pci_drvIdTable, .probe = _pci_probe, .remove = _pci_remove, }; // module related functions /////////////////////////////////////////////////// static int __init _module_init(void){ printk(KERN_INFO "Hello!\n"); pci_register_driver(&pci_drv); return 0; } static void __exit _module_exit(void){ pci_unregister_driver(&pci_drv); printk(KERN_INFO "Goodbye!\n"); } module_init(_module_init); module_exit(_module_exit); 

这是tail -f /var/log/kern.log的响应输出

 kernel: [ 493.719999] Hello! kernel: [ 493.720071] expdev 0000:05:02.0: enabling device (0000 -> 0003) kernel: [ 493.720845] VendorID. 10b5 kernel: [ 493.722375] BUG: unable to handle kernel paging request at 00000000eb060000 kernel: [ 493.722381] IP: [] iowrite16+0x38/0x40 kernel: [ 493.722388] PGD 0 kernel: [ 493.722390] Oops: 0002 [#1] SMP kernel: [ 493.722394] Modules linked in: expdev(OX+) rfcomm bnep bluetooth nvidia(POX) snd_hda_codec_hdmi joydev snd_hda_codec_idt snd_hda_intel snd_hda_codec snd_hwdep snd_pcm coretemp snd_page_alloc snd_seq_midi snd_seq_midi_event snd_rawmidi gpio_ich kvm snd_seq snd_seq_device drm dcdbas snd_timer lpc_ich snd soundcore shpchp serio_raw ppdev i82975x_edac lp parport_pc edac_core parport mac_hid hid_generic usbhid hid psmouse ahci tg3 libahci ptp pps_core pata_acpi kernel: [ 493.722429] CPU: 0 PID: 3542 Comm: insmod Tainted: P OX 3.13.0-79-generic #123-Ubuntu kernel: [ 493.722431] Hardware name: Dell Inc. Precision WorkStation 390 /0DN075, BIOS 2.3.0 05/01/2007 kernel: [ 493.722434] task: ffff8800549c3000 ti: ffff8800555e6000 task.ti: ffff8800555e6000 kernel: [ 493.722436] RIP: 0010:[] [] iowrite16+0x38/0x40 kernel: [ 493.722440] RSP: 0018:ffff8800555e7b88 EFLAGS: 00010212 kernel: [ 493.722442] RAX: 00000000eb000000 RBX: ffff88007c2b4000 RCX: 0000000000000000 kernel: [ 493.722444] RDX: 00000000eb060000 RSI: 00000000eb060000 RDI: 00000000000000aa kernel: [ 493.722446] RBP: ffff8800555e7bb0 R08: 00000000ebffffff R09: 00000000ffffffec kernel: [ 493.722448] R10: 0000000000003692 R11: 0000000000000000 R12: 00000000eb060000 kernel: [ 493.722450] R13: ffff88007c2b4098 R14: ffff88007c2b4098 R15: ffffffffa022b140 kernel: [ 493.722452] FS: 00007fa8053ef740(0000) GS:ffff88007f800000(0000) knlGS:0000000000000000 kernel: [ 493.722454] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b kernel: [ 493.722456] CR2: 00000000eb060000 CR3: 000000005a74b000 CR4: 00000000000007f0 kernel: [ 493.722458] Stack: kernel: [ 493.722460] ffffffffa02291c4 00aa88007c2b4000 ffff88007c2b4000 0000000000000000 kernel: [ 493.722464] ffffffffa022b000 ffff8800555e7be8 ffffffff813ac8a5 ffffffff813adb45 kernel: [ 493.722467] ffff88007c2b4098 ffffffffffffffff ffff88007c2b4000 0000000000000017 kernel: [ 493.722471] Call Trace: kernel: [ 493.722477] [] ? _pci_probe+0x114/0x215 [expdev] kernel: [ 493.722481] [] local_pci_probe+0x45/0xa0 kernel: [ 493.722484] [] ? pci_match_device+0xc5/0xd0 kernel: [ 493.722487] [] pci_device_probe+0xd9/0x130 kernel: [ 493.722492] [] driver_probe_device+0x12d/0x3e0 kernel: [ 493.722495] [] __driver_attach+0x93/0xa0 kernel: [ 493.722498] [] ? __device_attach+0x40/0x40 kernel: [ 493.722501] [] bus_for_each_dev+0x63/0xa0 kernel: [ 493.722504] [] driver_attach+0x1e/0x20 kernel: [ 493.722507] [] bus_add_driver+0x180/0x250 kernel: [ 493.722510] [] ? 0xffffffffa0004fff kernel: [ 493.722514] [] driver_register+0x64/0xf0 kernel: [ 493.722517] [] ? 0xffffffffa0004fff kernel: [ 493.722520] [] __pci_register_driver+0x4c/0x50 kernel: [ 493.722523] [] _module_init+0x2c/0x1000 [expdev] kernel: [ 493.722528] [] do_one_initcall+0xfa/0x1b0 kernel: [ 493.722532] [] ? set_memory_nx+0x43/0x50 kernel: [ 493.722536] [] load_module+0x12ed/0x1b50 kernel: [ 493.722540] [] ? store_uevent+0x40/0x40 kernel: [ 493.722544] [] SyS_finit_module+0x86/0xb0 kernel: [ 493.722548] [] system_call_fastpath+0x1a/0x1f kernel: [ 493.722550] Code: 81 fe 00 00 01 00 76 0b 0f b7 d6 89 f8 66 ef c3 0f 1f 00 55 48 c7 c6 b0 10 a9 81 48 89 d7 48 89 e5 e8 5d fe ff ff 5d c3 0f 1f 00  89 3e c3 0f 1f 40 00 48 81 fe ff ff 03 00 48 89 f2 77 2c 48 kernel: [ 493.722583] RIP [] iowrite16+0x38/0x40 kernel: [ 493.722586] RSP  kernel: [ 493.722588] CR2: 00000000eb060000 kernel: [ 493.722591] ---[ end trace 2d3dfa92998d58a7 ]--- 

根据Ian Abbott的说法,我现在成功地尝试了这种方法。 我真的不了解背后的机制,但它现在有效。 因此BAR2是存储器寄存器类型。 此方法使用ioremap而不是内存映射。 如何通过内存映射访问BAR2?

 #include  #include  #include  #include  MODULE_LICENSE("GPL"); MODULE_AUTHOR("Alex"); MODULE_DESCRIPTION("test module."); MODULE_VERSION("0.1"); #define DEV_PCI_VENDORID 0x10B5 #define DEV_PCI_DEVICEID 0x1860 static struct pci_device_id pci_drvIdTable[] = { { .vendor = DEV_PCI_VENDORID, // vendor ID .device = DEV_PCI_DEVICEID, // device ID .subvendor = PCI_ANY_ID, // no subsystem available .subdevice = PCI_ANY_ID, // no subsystem available .class = PCI_CLASS_NOT_DEFINED, // no device class .class_mask = 0, // no device class .driver_data = 0 // no private data to the driver }, { 0, } // end of table }; struct pci_data { // struct pci_dev *pci_dev; /// the IO mapping for the PCI config space uint32_t *pciConfigAddr; uint32_t *pciB2Addr; wait_queue_head_t waitq; uint8_t flag; } *data; static int _pci_probe ( struct pci_dev *pdev, const struct pci_device_id *ent ) { int ret = 0; int i; u16 reg_16; unsigned long *pbas2addr; data = kzalloc( sizeof(*data) , GFP_KERNEL ); if( !data ) { printk(KERN_ERR "Failed to allocate memory.\n"); return -ENOMEM; } pci_set_drvdata(pdev, data); // enabling the device ret = pci_enable_device(pdev); if( ret ) { printk(KERN_ERR "Failed to enable PCI device.\n"); goto no_enable; } pci_read_config_word(pdev,0,&reg_16); printk(KERN_INFO "VendorID. %x\n",reg_16); // checking if PCI-device reachable by checking that BAR0 is defined and // memory mapped if( !(pci_resource_flags(pdev,0) & IORESOURCE_MEM) ) { printk(KERN_ERR "Incorrect BAR configuration.\n"); ret = -ENODEV; goto bad_bar; } // taking ownership of a memory region pbas2addr = pci_ioremap_bar(pdev, 2); // void iowrite8(u8 val, void __iomem *addr) for ( i = 0x060000; i<0x070000; i++ ) { iowrite8( 0x11 , pbas2addr+i ); } // further read/write function in the kernel: // inp, readl, readw, readb, ioread8, ioread16, ioread32 // outp, writel, writew, writeb, iowrite8, iowrite16, iowrite32 bad_bar: pci_disable_device(pdev); no_enable: pci_set_drvdata(pdev, data); return ret; } static void _pci_remove( struct pci_dev *pdev ) { pci_disable_device(pdev); printk(KERN_INFO "PCI-device removed.\n"); } static struct pci_driver pci_drv = { .name = "expdev", .id_table = pci_drvIdTable, .probe = _pci_probe, .remove = _pci_remove, }; // module related functions /////////////////////////////////////////////////// static int __init _module_init(void){ printk(KERN_INFO "Hello!\n"); pci_register_driver(&pci_drv); return 0; } static void __exit _module_exit(void){ pci_unregister_driver(&pci_drv); printk(KERN_INFO "Goodbye!\n"); } module_init(_module_init); module_exit(_module_exit); 

我真的到底了。 我认为我完全按照文档进行操作,但它没有按预期工作。

这里的代码:

 #include  #include  #include  #include  #include  #include  #include  MODULE_LICENSE("GPL"); MODULE_AUTHOR("Alex"); MODULE_DESCRIPTION("test module."); MODULE_VERSION("0.1"); #define DEV_PCI_VENDORID 0x10B5 #define DEV_PCI_DEVICEID 0x1860 static struct pci_device_id pci_drvIdTable[] = { { .vendor = DEV_PCI_VENDORID, // vendor ID .device = DEV_PCI_DEVICEID, // device ID .subvendor = PCI_ANY_ID, // no subsystem available .subdevice = PCI_ANY_ID, // no subsystem available .class = PCI_CLASS_NOT_DEFINED, // no device class .class_mask = 0, // no device class .driver_data = 0 // no private data to the driver }, { 0, } }; static int _pci_probe ( struct pci_dev *pdev, const struct pci_device_id *ent ) { int ret = 0; int i; unsigned long *pbas2addr; // enabling the device ret = pci_enable_device(pdev); if( ret ) { printk(KERN_ERR "Failed to enable PCI device.\n"); goto no_enable; } pci_request_regions(pdev, "expdev"); // checking if PCI-device reachable by checking that BAR0 is defined and // memory mapped if( !(pci_resource_flags(pdev,0) & IORESOURCE_MEM) ) { printk(KERN_ERR "Incorrect BAR configuration.\n"); ret = -ENODEV; goto bad_bar; } // taking ownership of a memory region pbas2addr = pci_ioremap_bar(pdev, 2); printk(KERN_INFO "BAR2: %p\n",pbas2addr); for ( i = 0x060000; i<0x070000; i++ ) { iowrite8( 0x00 , pbas2addr+i ); } // the next write operations cause crashing the the module // load control word to set ICD in set-up-mode iowrite32(0b01111000000101, pbas2addr+0x200014); // load the bit-stuffed set up word iowrite32(0b10110001001001101110000, pbas2addr+0x200018); // 39.5 MHz // load control word to set ICD in set-up-mode iowrite32(0b01111000000100, pbas2addr+0x200014); msleep(10); // load control word to set ICD in set-up-mode iowrite32(0b01111000000000, pbas2addr+0x200014); return 0; bad_bar: pci_disable_device(pdev); return ret; } static void _pci_remove( struct pci_dev *pdev ) { pci_release_regions(pdev); pci_disable_device(pdev); printk(KERN_INFO "PCI-device removed.\n"); } static struct pci_driver pci_drv = { .name = "expdev", .id_table = pci_drvIdTable, .probe = _pci_probe, .remove = _pci_remove, }; // module related functions static int __init _module_init(void){ printk(KERN_INFO "Hello!\n"); pci_register_driver(&pci_drv); return 0; } static void __exit _module_exit(void){ pci_unregister_driver(&pci_drv); printk(KERN_INFO "Goodbye!\n"); } module_init(_module_init); module_exit(_module_exit); 

只有for循环:

 kernel: [ 467.545079] Hello! kernel: [ 467.545136] expdev 0000:05:02.0: enabling device (0000 -> 0003) kernel: [ 467.546807] BAR2: ffffc90006c00000 kernel: [ 467.562146] PCI-device removed. kernel: [ 467.562489] Goodbye! 

我可以在设备GPIO上看到一些输出。

如果我根据需要写入更高的地址有关设备手册,LKM崩溃:

 kernel: [ 1324.591578] Hello! kernel: [ 1324.593300] BAR2: ffffc90007c80000 kernel: [ 1324.605162] BUG: unable to handle kernel paging request at ffffc90008c800a0 kernel: [ 1324.605168] IP: [] iowrite32+0x38/0x40 kernel: [ 1324.605175] PGD 7d00d067 PUD 7d00e067 PMD 611e7067 PTE 0 kernel: [ 1324.605179] Oops: 0002 [#1] SMP kernel: [ 1324.605183] Modules linked in: expdev(OX+) rfcomm bnep bluetooth nvidia(POX) snd_hda_codec_hdmi joydev snd_hda_codec_idt snd_hda_intel snd_hda_codec gpio_ich coretemp drm snd_seq_midi kvm snd_seq_midi_event dcdbas snd_rawmidi snd_hwdep lpc_ich snd_seq snd_pcm snd_seq_device snd_page_alloc shpchp ppdev serio_raw snd_timer lp snd soundcore mac_hid i82975x_edac edac_core parport_pc parport hid_generic usbhid hid psmouse ahci libahci pata_acpi tg3 ptp pps_core [last unloaded: expdev] kernel: [ 1324.605219] CPU: 0 PID: 3155 Comm: insmod Tainted: P OX 3.13.0-79-generic #123-Ubuntu kernel: [ 1324.605221] Hardware name: Dell Inc. Precision WorkStation 390 /0DN075, BIOS 2.3.0 05/01/2007 kernel: [ 1324.605224] task: ffff88007c048000 ti: ffff880061122000 task.ti: ffff880061122000 kernel: [ 1324.605226] RIP: 0010:[] [] iowrite32+0x38/0x40 kernel: [ 1324.605229] RSP: 0018:ffff880061123b90 EFLAGS: 00010292 kernel: [ 1324.605231] RAX: 0000000000000016 RBX: ffffc90008c800a0 RCX: 0000000000000000 kernel: [ 1324.605233] RDX: ffffc90008c800a0 RSI: ffffc90008c800a0 RDI: 0000000000001e05 kernel: [ 1324.605235] RBP: ffff880061123bb0 R08: 0000000000000096 R09: 0000000000000306 kernel: [ 1324.605237] R10: 0000000000000000 R11: ffff8800611238c6 R12: ffffc90007f80000 kernel: [ 1324.605239] R13: ffffc90007c80000 R14: ffff88007c2b4098 R15: ffffffffa01fc140 kernel: [ 1324.605242] FS: 00007fc6802cb740(0000) GS:ffff88007f800000(0000) knlGS:0000000000000000 kernel: [ 1324.605244] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 kernel: [ 1324.605246] CR2: ffffc90008c800a0 CR3: 0000000062f96000 CR4: 00000000000007f0 kernel: [ 1324.605248] Stack: kernel: [ 1324.605249] ffffffffa01fa0ec ffff88007c2b4000 0000000000000000 ffffffffa01fc000 kernel: [ 1324.605253] ffff880061123be8 ffffffff813ac8a5 ffffffff813adb45 ffff88007c2b4098 kernel: [ 1324.605257] ffffffffffffffff ffff88007c2b4000 0000000000000018 ffff880061123c30 kernel: [ 1324.605260] Call Trace: kernel: [ 1324.605267] [] ? _pci_probe+0xbc/0x110 [expdev] kernel: [ 1324.605271] [] local_pci_probe+0x45/0xa0 kernel: [ 1324.605274] [] ? pci_match_device+0xc5/0xd0 kernel: [ 1324.605277] [] pci_device_probe+0xd9/0x130 kernel: [ 1324.605281] [] driver_probe_device+0x12d/0x3e0 kernel: [ 1324.605285] [] __driver_attach+0x93/0xa0 kernel: [ 1324.605288] [] ? __device_attach+0x40/0x40 kernel: [ 1324.605290] [] bus_for_each_dev+0x63/0xa0 kernel: [ 1324.605293] [] driver_attach+0x1e/0x20 kernel: [ 1324.605296] [] bus_add_driver+0x180/0x250 kernel: [ 1324.605300] [] ? 0xffffffffa0005fff kernel: [ 1324.605303] [] driver_register+0x64/0xf0 kernel: [ 1324.605306] [] ? 0xffffffffa0005fff kernel: [ 1324.605309] [] __pci_register_driver+0x4c/0x50 kernel: [ 1324.605313] [] _module_init+0x2c/0x1000 [expdev] kernel: [ 1324.605317] [] do_one_initcall+0xfa/0x1b0 kernel: [ 1324.605321] [] ? set_memory_nx+0x43/0x50 kernel: [ 1324.605326] [] load_module+0x12ed/0x1b50 kernel: [ 1324.605330] [] ? store_uevent+0x40/0x40 kernel: [ 1324.605334] [] SyS_finit_module+0x86/0xb0 kernel: [ 1324.605338] [] system_call_fastpath+0x1a/0x1f kernel: [ 1324.605340] Code: 81 fe 00 00 01 00 76 0b 0f b7 d6 89 f8 ef c3 0f 1f 40 00 55 48 c7 c6 bf 10 a9 81 48 89 d7 48 89 e5 e8 1d fe ff ff 5d c3 0f 1f 00  3e c3 0f 1f 44 00 00 48 81 ff ff ff 03 00 77 37 48 81 ff 00 kernel: [ 1324.605373] RIP [] iowrite32+0x38/0x40 kernel: [ 1324.605376] RSP  kernel: [ 1324.605378] CR2: ffffc90008c800a0 kernel: [ 1324.605381] ---[ end trace 9b1029fd3f919791 ]--- 

RIP – 但为什么。 偏移量在16 MB的范围内。