read PCI memory and config spyce through /dev/mem
Hi, I'd like to look at some of my PCI devices through /dev/mem. My kernel config has "Filter access to /dev/mem" (STRICT_DEVMEM) switched off, so as root, I should have unrestricted access. I get my PCI device's BAR address through /proc/iomem, e.g.: $ cat /proc/iomem ... f7600000-f7603fff : r8169 ... Ok, so there should be 16K of PCI memory from my ethernet card starting at f7600000, which is 4150263808 in decimal to be used With dd. But: $ dd if=/dev/mem bs=1 count=1024 skip=4150263808 dd: reading `/dev/mem': Bad address 0+0 records in 0+0 records out 0 bytes (0 B) copied, 6.6658e-05 s, 0.0 kB/s The kernel config help says that _PCI_ memory access is even possible with STRICT_DEVMEM enabled. Can anyone give me a hint what I may do wrong? Thanks a lot, Chris
On Mon, 06 May 2013 14:44:03 -0000, "Warlich, Christof" said:
$ dd if=/dev/mem bs=1 count=1024 skip=4150263808 dd: reading `/dev/mem': Bad address 0+0 records in 0+0 records out 0 bytes (0 B) copied, 6.6658e-05 s, 0.0 kB/s
The kernel config help says that _PCI_ memory access is even possible with STRICT_DEVMEM enabled. Can anyone give me a hint what I may do wrong?
You *do* realize that doing a byte access on a 64-bit PCI register will probably fail, right? And changing it to bs=8 won't fix it either, because some registers are 32-bit, and some are write-only. Bottom line - what you're doing wrong is not accessing the PCI address space in the exact manner that the PCI spec requires. You're lucky it just threw "bad address" - it *is* possible to end up wiping your entire system this way if you screw up the PCI config for your disk controller or similar. Be glad you didn't have to recover from your backups this time. You *do* have backups, right?
$ dd if=/dev/mem bs=1 count=1024 skip=4150263808 dd: reading `/dev/mem': Bad address 0+0 records in 0+0 records out 0 bytes (0 B) copied, 6.6658e-05 s, 0.0 kB/s
The kernel config help says that _PCI_ memory access is even possible with STRICT_DEVMEM enabled. Can anyone give me a hint what I may do wrong?
You *do* realize that doing a byte access on a 64-bit PCI register will probably fail, right? And changing it to bs=8 won't fix it either, because some registers are 32-bit, and some are write-only.
The real target that I need to explore is a custom FPGA device on an embedded (i386) system. One of its BARs (at 0x81423000) point to memory that _does_ allow unrestricted byte access and has a size of two pages. But anyhow, all of the following commands show the same error: $ dd if=/dev/mem bs=1 count=1 skip=2168598528 | hexdump $ dd if=/dev/mem bs=2 count=1 skip=1084299264 | hexdump $ dd if=/dev/mem bs=4 count=1 skip=542149632 | hexdump $ dd if=/dev/mem bs=8 count=1 skip=271074816 | hexdump $ dd if=/dev/mem bs=4096 count=1 skip=529443 | hexdump # 4096 being the system's page size Furthermore, read / write access through a simple program using /dev/mem _does_ work as expected: #include <unistd.h> #include <stdio.h> #include <fcntl.h> #include <assert.h> #include <sys/mman.h> int main( int argc, char *argv[]) { char *mem; int fd; fd = open ("/dev/mem", O_RDWR); assert(fd >= 0); mem = mmap(NULL, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, (off_t) 0x81423000); assert(mem != MAP_FAILED); printf("Memory pointer: %p\n", mem); printf("The PCI memory is : %#x\n", *mem); *mem = *argv[1]; printf("The PCI memory is : %#x\n", *mem); munmap(mem, getpagesize()); close(fd); return 0; } Calling it, yields: $ led 4 Memory pointer: 0xb7678000 The PCI memory is : 0x33 The PCI memory is : 0x34 And the LED matrix display being behind that address switches from 3 to 4 as expected. Thus, I still cannot see why the access through /dev/mem using dd doesn't work.
Bottom line - what you're doing wrong is not accessing the PCI address space in the exact manner that the PCI spec requires. You're lucky it just threw "bad address" - it *is* possible to end up wiping your entire system this way if you screw up the PCI config for your disk controller or similar. Be glad you didn't have to recover from your backups this time.
You *do* have backups, right?
Don't worry about that, I've restored the system in less than a minute.
On Tue, May 07, 2013 at 06:35:43AM +0000, Warlich, Christof wrote: [...]
Furthermore, read / write access through a simple program using /dev/mem _does_ work as expected:
#include <unistd.h> #include <stdio.h> #include <fcntl.h> #include <assert.h> #include <sys/mman.h> int main( int argc, char *argv[]) { char *mem; int fd; fd = open ("/dev/mem", O_RDWR); assert(fd >= 0); mem = mmap(NULL, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, (off_t) 0x81423000); assert(mem != MAP_FAILED); printf("Memory pointer: %p\n", mem); printf("The PCI memory is : %#x\n", *mem); *mem = *argv[1]; printf("The PCI memory is : %#x\n", *mem); munmap(mem, getpagesize()); close(fd); return 0; }
Calling it, yields:
$ led 4 Memory pointer: 0xb7678000 The PCI memory is : 0x33 The PCI memory is : 0x34
And the LED matrix display being behind that address switches from 3 to 4 as expected.
Thus, I still cannot see why the access through /dev/mem using dd doesn't work.
I suspect dd uses read instead of mmap. Thanks, Jonathan Neuschäfer
participants (3)
-
Jonathan Neuschäfer -
Valdis.Kletnieks@vt.edu -
Warlich, Christof