read PCI memory and config spyce through /dev/mem
Warlich, Christof
christof.warlich at siemens.com
Wed May 8 02:49:45 EDT 2013
Jun Hu <jhu_com at 163.com> wrote:
> strace your application, like as:
> ...
It's the lseek that fails: Obviously, /dev/mem is not seekable.
What really puzzles me is that dd _does_ work on /dev/mem when
looking at ordinary RAM, but I'm reluctant to further debug why.
But anyhow, as I think it may at times be also useful for others
to have a simple tool that allows to read (and write!) PCI memory,
I share the few lines of code that I wrote to fulfill my needs. I
hope that the included "documentation" is verbose enough. And I'm
certainly interested if anyone finds bugs :-):
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#include <sys/mman.h>
void usage(const char *name) {
fprintf(stderr, "Usage: %s address access [size]\033[2m\n", name);
fprintf(stderr, " Either - prints \"size\" bytes \033[1mfrom\033[2m physical memory,\n");
fprintf(stderr, " starting at \"address\" and using \"access\"\n");
fprintf(stderr, " bytes per access \033[1mto\033[2m stdout\n");
fprintf(stderr, " or - writes as many bytes as are available \033\[1mfrom\033[2m\n");
fprintf(stderr, " stdin \033[1mto\033[2m physical memory starting at \"address\"\n");
fprintf(stderr, " using \"access\" bytes per access.\n");
fprintf(stderr, " Note that both \"address\" and either \"size\" or the\n");
fprintf(stderr, " number of available bytes from stdin must be a multiple of\n");
fprintf(stderr, " \"access\", and \"access\" must either be %d, %d, %d or %d.\033[0m\n",
sizeof(uint8_t), sizeof(uint16_t), sizeof(uint32_t), sizeof(uint64_t));
exit(-1);
}
template<typename T> void readOrWrite(uint8_t *src, uint8_t *mem) {
if(src) *(T *) mem = *(T *) src;
else {
T t = *(T *) mem;
assert(write(1, &t, sizeof(T)) == sizeof(T));
}
}
int main( int argc, char *argv[]) {
int fd, pageSize = getpagesize(), size = 0, n;
uint8_t *mem, *b = 0, *buffer = 0;
// Paranoia check to ensure that page size is a power of 2.
assert((pageSize != 0) && !(pageSize & (pageSize - 1)));
if (argc == 3) do {
#define CHUNK_SIZE 1000
assert(b = buffer = (uint8_t *) realloc(buffer, size + CHUNK_SIZE));
assert((n = read(0, buffer + size, CHUNK_SIZE)) >= 0);
size += n;
} while(n);
else if(argc == 4) size = strtoul(argv[3], 0, 0);
else usage(argv[0]);
off_t address = strtoul(argv[1], 0, 0);
size_t access = strtoul(argv[2], 0, 0);
if(address % access || size % access) usage(argv[0]);
assert((fd = open ("/dev/mem", O_RDWR)) >= 0);
size_t s = (((address & (pageSize - 1)) + size - 1) / pageSize + 1) * pageSize;
mem = (uint8_t *) mmap(NULL, s, PROT_READ | PROT_WRITE, MAP_SHARED, fd, address & ~(pageSize - 1));
assert(mem != MAP_FAILED);
for(uint8_t *i = mem; i < mem + size; i += access) {
#define ROW(t) sizeof(t): readOrWrite<t>(b, i); break
switch(access) {
case ROW(uint8_t);
case ROW(uint16_t);
case ROW(uint32_t);
case ROW(uint64_t);
default: usage(argv[0]);
}
if(b) b += access;
}
free(buffer);
munmap(mem, getpagesize());
close(fd);
return 0;
}
More information about the Kernelnewbies
mailing list