在内核空间PCI-内存地址映射

问题描述 投票:4回答:3

我试图读取并从一个可加载的内核模块写入和PCI设备。

因此,我按照这个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我的内核地址空间内的地址直接指向这是0x60000偏移到PCI片选地址的基址?

它怎么能是我写的值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 <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 ]---

据伊恩·雅培,现在我成功尝试这种方法。我真的不明白背后的机制,但它适用于现在。所以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的限制范围内。

c linux-kernel kernel kernel-module pci
3个回答
1
投票

我觉得你的代码是corrent,但你应该检查你的资源文件PCI主机驱动程序。当调用funtion“pci_ioremap_bar(PDEV,2)”,该功能需要一定的资源数据重新映射内存空间。

例如,

[2] = {
    .name   = "ep_mem2",
    .start  = PCIE_BASE + 0x1000,
    .end    = PCIE_BASE + 0x2000 - 1,
    .flags  = IORESOURCE_MEM,
}

1
投票

我认为你访问它没有映射到PCIe存储空间为PCIe设备的内存空间。如你所知,BAR由PCIe设备在启动时间或重新扫描时间定义。所以BAR的大小也通过PCIe设备决定。您可以通过启动日志检查。其结果是,应该由所述PCIe设备所定义的大小范围内访问所述存储器。


0
投票

原来PCI总线像树干一样,用“PCI主机控制器”的根,在分支机构的桥梁和设备的叶子。当CPU写入到对应于一个设备的MMIO区域中的物理地址空间,存储器控制器具有转发访问正确的PCI主机控制器(而不是RAM或不同的PCI主控制器,而不是一个不同NUMA节点)时,PCI主机控制器将其转发到第一PCI总线,那么所有的PCI总线上的桥梁决定接受或忽略的访问,其中一人将转发访问其“二次总线”(总线上的桥的另一侧) ,等,直到它,该装置是在总线上的结束和设备接受存取(和总线上的任何其它设备忽略)。当然,你可以使用不同的MMIO区域的物理地址空间的同一区域不具有2级或更多的设备,因为这会是导致冲突。

欲了解更多现代系统有恶作剧(例如IOMMUs)的额外层;和PCI-EXPRESS从“树”改为“直接联系”(但是,这并不意味着你不能,也不会看到“PCI-E转PCI传统”上的另一边与“树”的桥梁桥)。

了解这里最重要的是该固件配置大多数这(和其他一些东西),以确保实际上访问得到的是他们应该的设备(和内核还可以配置一些 - 例如IOMMUs),但设备驱动程序不应该随机决定垃圾一时兴起的一切。

设备驱动程序不应该修改PCI试条,在所有的,直到永远。没有理由。

注意:理想情况下(对提供设备枚举和资源的自动配置功能,公交车 - 如EISA,MCA,PCI,..)内核将事情做好,然后启动驱动程序并告诉司机哪些资源(MMIO区域的IRQ, ...)其设备使用;和设备驱动程序不知道或总线型设备使用护理和将不触及PCI配置空间(这可能不是只要是“另一个不同的总线”存在被发明并在同一台设备被掴到不同类型的总线)。

© www.soinside.com 2019 - 2024. All rights reserved.