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

时间:2016-01-28 10:05:15

标签: c linux-kernel kernel kernel-module pci

我正在尝试从可加载的内核模块读取和写入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的值如何复制到设备?该机制如何在iowrite32pci_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,&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: [<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,&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 <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的范围内。

3 个答案:

答案 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总线上,配置空间可能就不存在了。不同类型的巴士)。