我正在尝试从可加载的内核模块读取和写入PCI-device。
因此我遵循post:
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
的值如何复制到设备?该机制如何在iowrite32
和pci_iomap
后面工作?
谢谢和问候
亚历
PS:我成功地测试了来自同一地址的回读。
注册PCI设备的说明:
PCIBAR0
PCI基地址0;用于内存映射配置寄存器PCIBAR1
PCI Base Address 1;用于I / O映射配置寄存器PCIBAR2
PCI Base Address 2;用于本地地址空间0 PCIBAR3
PCI基地址3;用于本地地址空间1 PCIBAR4
未使用的基地址PCIBAR5
未使用的基地址再次问好。
在上一次我尝试了几种与BAR2寄存器通信的方法但没有成功。这是我的实际代码:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
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,®_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: [<ffffffff8137aca8>] 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:[<ffffffff8137aca8>] [<ffffffff8137aca8>] 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] [<ffffffffa02291c4>] ? _pci_probe+0x114/0x215 [expdev]
kernel: [ 493.722481] [<ffffffff813ac8a5>] local_pci_probe+0x45/0xa0
kernel: [ 493.722484] [<ffffffff813adb45>] ? pci_match_device+0xc5/0xd0
kernel: [ 493.722487] [<ffffffff813adc69>] pci_device_probe+0xd9/0x130
kernel: [ 493.722492] [<ffffffff8149a4bd>] driver_probe_device+0x12d/0x3e0
kernel: [ 493.722495] [<ffffffff8149a843>] __driver_attach+0x93/0xa0
kernel: [ 493.722498] [<ffffffff8149a7b0>] ? __device_attach+0x40/0x40
kernel: [ 493.722501] [<ffffffff81498403>] bus_for_each_dev+0x63/0xa0
kernel: [ 493.722504] [<ffffffff81499e6e>] driver_attach+0x1e/0x20
kernel: [ 493.722507] [<ffffffff81499a50>] bus_add_driver+0x180/0x250
kernel: [ 493.722510] [<ffffffffa0005000>] ? 0xffffffffa0004fff
kernel: [ 493.722514] [<ffffffff8149aec4>] driver_register+0x64/0xf0
kernel: [ 493.722517] [<ffffffffa0005000>] ? 0xffffffffa0004fff
kernel: [ 493.722520] [<ffffffff813ac23c>] __pci_register_driver+0x4c/0x50
kernel: [ 493.722523] [<ffffffffa000502c>] _module_init+0x2c/0x1000 [expdev]
kernel: [ 493.722528] [<ffffffff8100214a>] do_one_initcall+0xfa/0x1b0
kernel: [ 493.722532] [<ffffffff810598f3>] ? set_memory_nx+0x43/0x50
kernel: [ 493.722536] [<ffffffff810e2b7d>] load_module+0x12ed/0x1b50
kernel: [ 493.722540] [<ffffffff810de5f0>] ? store_uevent+0x40/0x40
kernel: [ 493.722544] [<ffffffff810e3556>] SyS_finit_module+0x86/0xb0
kernel: [ 493.722548] [<ffffffff817363dd>] 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 <66> 89 3e c3 0f 1f 40 00 48 81 fe ff ff 03 00 48 89 f2 77 2c 48
kernel: [ 493.722583] RIP [<ffffffff8137aca8>] iowrite16+0x38/0x40
kernel: [ 493.722586] RSP <ffff8800555e7b88>
kernel: [ 493.722588] CR2: 00000000eb060000
kernel: [ 493.722591] ---[ end trace 2d3dfa92998d58a7 ]---
根据Ian Abbott的说法,我成功地尝试了这种方法。我真的不了解背后的机制,但它现在有效。因此BAR2是存储器寄存器类型。此方法使用ioremap
而不是内存映射。如何通过内存映射访问BAR2?
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
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,®_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 <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/delay.h>
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: [<ffffffff8137ace8>] 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:[<ffffffff8137ace8>] [<ffffffff8137ace8>] 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] [<ffffffffa01fa0ec>] ? _pci_probe+0xbc/0x110 [expdev]
kernel: [ 1324.605271] [<ffffffff813ac8a5>] local_pci_probe+0x45/0xa0
kernel: [ 1324.605274] [<ffffffff813adb45>] ? pci_match_device+0xc5/0xd0
kernel: [ 1324.605277] [<ffffffff813adc69>] pci_device_probe+0xd9/0x130
kernel: [ 1324.605281] [<ffffffff8149a4bd>] driver_probe_device+0x12d/0x3e0
kernel: [ 1324.605285] [<ffffffff8149a843>] __driver_attach+0x93/0xa0
kernel: [ 1324.605288] [<ffffffff8149a7b0>] ? __device_attach+0x40/0x40
kernel: [ 1324.605290] [<ffffffff81498403>] bus_for_each_dev+0x63/0xa0
kernel: [ 1324.605293] [<ffffffff81499e6e>] driver_attach+0x1e/0x20
kernel: [ 1324.605296] [<ffffffff81499a50>] bus_add_driver+0x180/0x250
kernel: [ 1324.605300] [<ffffffffa0006000>] ? 0xffffffffa0005fff
kernel: [ 1324.605303] [<ffffffff8149aec4>] driver_register+0x64/0xf0
kernel: [ 1324.605306] [<ffffffffa0006000>] ? 0xffffffffa0005fff
kernel: [ 1324.605309] [<ffffffff813ac23c>] __pci_register_driver+0x4c/0x50
kernel: [ 1324.605313] [<ffffffffa000602c>] _module_init+0x2c/0x1000 [expdev]
kernel: [ 1324.605317] [<ffffffff8100214a>] do_one_initcall+0xfa/0x1b0
kernel: [ 1324.605321] [<ffffffff810598f3>] ? set_memory_nx+0x43/0x50
kernel: [ 1324.605326] [<ffffffff810e2b7d>] load_module+0x12ed/0x1b50
kernel: [ 1324.605330] [<ffffffff810de5f0>] ? store_uevent+0x40/0x40
kernel: [ 1324.605334] [<ffffffff810e3556>] SyS_finit_module+0x86/0xb0
kernel: [ 1324.605338] [<ffffffff817363dd>] 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 <89> 3e c3 0f 1f 44 00 00 48 81 ff ff ff 03 00 77 37 48 81 ff 00
kernel: [ 1324.605373] RIP [<ffffffff8137ace8>] iowrite32+0x38/0x40
kernel: [ 1324.605376] RSP <ffff880061123b90>
kernel: [ 1324.605378] CR2: ffffc90008c800a0
kernel: [ 1324.605381] ---[ end trace 9b1029fd3f919791 ]---
RIP - 但为什么呢。偏移量在16 MB的范围内。
答案 0 :(得分:1)
我认为您的代码是正确的,但是应该检查您的资源文件中是否有PCI主机驱动程序。 当您调用功能“ pci_ioremap_bar(pdev,2)”时,该函数需要一些资源数据来重新映射内存空间。
例如,
[2] = {
.name = "ep_mem2",
.start = PCIE_BASE + 0x1000,
.end = PCIE_BASE + 0x2000 - 1,
.flags = IORESOURCE_MEM,
}
答案 1 :(得分:1)
我认为您访问了未映射到PCIe设备的PCIe内存空间的内存空间。 如您所知,BAR由PCIe设备在启动或重新扫描时定义。因此,BAR的大小也由PCIe设备决定。您可以使用启动日志进行检查。 因此,您应该在PCIe设备定义的大小范围内访问内存。
答案 2 :(得分:0)
最初,PCI总线就像一棵树,根部有“ PCI主机控制器”,分支处有网桥,叶子处有设备。当CPU写入与设备MMIO区域相对应的物理地址空间时,内存控制器必须将访问权转发给正确的PCI主机控制器(而不是RAM或其他PCI主机控制器,而不是其他NUMA节点)主机控制器将其转发到第一个PCI总线,然后该PCI总线上的所有网桥决定接受还是忽略访问,其中一个网桥会将访问转发到其“辅助总线”(桥另一侧的总线) ,依此类推,直到它最终终止在设备所在的总线上并且该设备接受访问(该总线上的所有其他设备都将其忽略)。当然,您不能有2个或更多的设备使用相同的物理地址空间来分配不同的MMIO区域,因为这会引起冲突。
对于更现代的系统,还有额外的诡计层(例如IOMMU);并且对于PCI-express,它已从“树”更改为“直接链接”(但这并不意味着您不能也不会看到“ PCI-E到PCI常规”桥与“树”的另一面)。桥)。
这里要了解的重要一点是,固件会配置其中的大部分(以及其他一些内容),以确保访问实际上到达了他们理应访问的设备(内核也可能配置了某些内容,例如IOMMU) ),但设备驱动程序不应随心所欲地决定丢弃所有内容。
设备驱动程序永远不应修改PCI BAR。没有任何借口。
注:理想情况下(对于提供设备枚举和资源自动配置功能的总线-例如EISA,MCA,PCI等),内核将解决所有问题,然后启动驱动程序并告诉驱动程序哪些资源设备使用的(MMIO区域,IRQ等);并且设备驱动程序将不知道或不在乎设备使用哪种总线类型,也不会接触PCI配置空间(一旦发明了“又另一条不同的总线”,并且同一设备被拍打到PCI总线上,配置空间可能就不存在了。不同类型的巴士)。