zoukankan      html  css  js  c++  java
  • PCI Access Without a Driver

    t work recently, I had a new PCI device that I needed to experiment with. I was dreading writing a Linux kernel driver to talk to it. It turns out, Linux makes it possible to read and write to a PCI device's memory space without a driver! Woohoo!

    Linux provides a sysfs interface to PCI devices. From that interface, the memory space can be mmaped and then read and written. No driver involved.

    As a quick example, we can use lspci to get information about a particular device.

    $ vendor="10ee" # Use your device ID
    $ device="7014" # Use your vendor ID
    $ lspci -d $vendor:$device -nvv
    04:00.0 1180: 10ee:7014
        ...
        Region 0: Memory at f7300000 (32-bit, non-prefetchable) [size=128K]
    

    Then we can look at the sysfs interface, at /sys/bus/pci/devices/. The first bit of data in the output of lspci gives the location of the device on the bus, that we can use when traversing the sysfs interface.

    $ ls -alF /sys/bus/pci/devices/0000:04:00.0/
    total 0
    drwxr-xr-x 3 root root      0 Jul  1 12:42 ./
    drwxr-xr-x 8 root root      0 Jul  1 12:42 ../
    -rw-r--r-- 1 root root   4096 Jul  9 12:48 broken_parity_status
    -r--r--r-- 1 root root   4096 Jul  1 12:42 class
    -rw-r--r-- 1 root root   4096 Jul  9 12:44 config
    -r--r--r-- 1 root root   4096 Jul  1 12:42 device
    ...
    -r--r--r-- 1 root root   4096 Jul  1 12:43 resource
    -rw------- 1 root root 131072 Jul  1 12:43 resource0
    ...
    -r--r--r-- 1 root root   4096 Jul  1 12:42 vendor
    

    This interface has some useful files like vendor and device that confirm that we have the right device. These are also useful for programatically finding the correct device, rather than using lspci.

    $ cat /sys/bus/pci/devices/0000:04:00.0/vendor
    0x10ee
    $ cat /sys/bus/pci/devices/0000:04:00.0/device
    0x7014
    

    Looking back at the lspci output, we can also find memory resources and addresses. These are represented as resource0...resourceN in the sysfs interface. That's what we use to get access to the PCI memory space.

    Open the resource0 file (which can be some number other than 0 depending on the device).

    int fd = open("/sys/bus/pci/devices/0000:04:00.0/resource0", O_RDWR | O_SYNC);
    

    Then use the memory address and size from the lspci output to mmap the file.

    void* base_address = (void*)0xf7300000;
    size_t size = 128 * 1024; // 128K
    void* void_memory = mmap(base_address,
                             size,
                             PROT_READ | PROT_WRITE,
                             MAP_SHARED,
                             fd,
                             0);
    uint16_t* memory = (uint16_t*)void_memory;
    

    Now memory provides direct access to read and write the PCI memory space. We can hack away!

    // Read the value of the first register
    uint16_t first_register = memory[0];
    
    // Write a value to the third register
    memory[2] = 0x0007;
    

    Now, this isn't the perfect scenario. For one, we need to be root to access this memory space. For two, there's no sign of interrupt handling anywhere.

    But for basic poking around on a new device, it works pretty slick. No kernel module development required.

  • 相关阅读:
    开发新技术展望系列课程(视频课程讲师:徐晓卓)
    VSTS风暴系列课程(视频课程讲师:王京京/王兴明/王然)
    Mysql索引的数据结构及索引优化
    CAP原则,分布式场景下为何只能取其二
    为什么使用Redission解决高并发场景分布式锁问题
    Java面试题(6)Redis
    外企英语面试常见问题及核心话术
    Nacos&Eureka&Zookeeper
    j2ee中DAO设计模式
    第一个随笔
  • 原文地址:https://www.cnblogs.com/dream397/p/13553824.html
Copyright © 2011-2022 走看看