How to use /dev/kmem?
c, linux, mmap
Solution
I've tried combinations or offset and bs for dd and found this solution:
On PC, in build directory I've found location of jiffies.
grep -w jiffies System.map c04660c0 D jiffies
On PandaBoard:
In /proc/iomem you can see:
80000000-9c7fffff : System RAM 80008000-80435263 : Kernel code 80464000-804d0d97 : Kernel data a0000000-bfefffff : System RAM
RAM starts from physical 80000000, and Kernel data start on 80464000. Looks similar to address of jiffies.
Then convert from virtual address to phys: virt - 0xC000000 + 0x8000000.
dd if=/dev/mem skip=$((0x804660c)) bs=$((0x10)) count=1 2> /dev/null | hexdump 0000000 02b9 0002 0001 0000 0000 0000 0000 0000 0000010
Try several times and see how the value is incrementing.
Summary: /dev/mem uses phys address, RAM starts at phys address 0x8000000
Problem
Updated my post... I got below program. It operates on `/dev/kmem` and `/dev/mem`. I think I can learn something from the code. But when I run it on my Beagle Board, below result is given: ``` case 1: ( if(1) ) root@omap:/home/ubuntu/tom# ./kmem_mem /boot/System.map-3.0.4-x3 found jiffies at (0xc0870080) c0870080 /dev/kmem read buf = 319317 jiffies=319317 (read from virtual memory) /dev/mem: the offset is 870080 the page size = 4096 mmap: Invalid argument case 2: ( if(0) ) root@omap:/home/ubuntu/tom# ./kmem_mem /boot/System.map-3.0.4-x3 found jiffies at (0xc0870080) c0870080 /dev/kmem read buf = 333631 jiffies=333631 (read from virtual memory) /dev/mem: the offset is 870080 /dev/mem read failed: Bad address jiffies=0 (read from physical memory) ``` And I used below command so that mmap can use NULL as its first parameter. ``` root@omap:/home/ubuntu/tom# echo 0 > /proc/sys/vm/mmap_min_addr root@omap:/home/ubuntu/tom# cat /proc/sys/vm/mmap_min_addr 0 ``` As you can see, `read_kmem()` works fine but `read_mem()` doesn't work, and it seems that the 'offset' transferred to it is wrong. But kernel address - `PAGE_OFFSET(0xC0000000) = physical address`, is it wrong? My questions are: (1) Why "mmap: Invalid argument" in case 1? (2) Why the mmap only maps `PAGE_SIZE` length space? (3) What's wrong with `read_mem`? Can anyone help? Thanks! ``` /* * getjiff.c * * this toolkit shows how to get jiffies value from user space: * 1. find jiffies's address from kernel image. * 2. access virtual address space to get jiffies value. * 3. access physical address sapce to get jiffies value. * * demostrate following techniques: * o get ELF object symbol address by calling nlist() * o access virtual memory space from /dev/kmem * o access virtual memory space from /dev/mem */ #include <stdio.h> #include <stdlib.h> //exit #include <linux/a.out.h> //nlist #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <sys/types.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <memory.h> #define LONG *(volatile unsigned long*) /* read from virtual memory */ int read_kmem(off_t offset, void* buf, size_t count) { int fd; int n; fd = open("/dev/kmem", O_RDONLY); if (fd < 0) { perror("open /dev/kmem failed"); return -1; } lseek(fd, offset, SEEK_SET); n = read(fd, buf, count); if (n != count) perror("/dev/kmem read failed"); else printf("/dev/kmem read buf = %ld\n", *(unsigned long *)buf); close(fd); return n; } /* read from physical memory */ int read_mem(off_t offset, void* buf, size_t count) { int fd; int n; int page_size; void *map_base; unsigned long value; printf("/dev/mem: the offset is %lx\n", offset); fd = open("/dev/mem", O_RDONLY); if (fd < 0) { perror("open /dev/mem failed"); return -1; } if(1){ page_size = getpagesize(); printf("the page size = %d\n", page_size); map_base = mmap(0,page_size,PROT_READ,MAP_SHARED,fd,offset); if (map_base == MAP_FAILED){ perror("mmap"); exit(1); } value = LONG(map_base); printf("/dev/mem: the value is %ld\n", value); buf = (unsigned long *)map_base; } if(0){ lseek(fd, offset, SEEK_SET); n = read(fd, buf, count); if (n != count) perror("/dev/mem read failed"); else printf("/dev/mem read buf = %ld\n", *(unsigned long *)buf); } close(fd); return n; } int main(int argc, char **argv) { FILE *fp; char addr_str[11]="0x"; char var[51]; unsigned long addr; unsigned long jiffies; char ch; int r; if (argc != 2) { fprintf(stderr,"usage: %s System.map\n",argv[0]); exit(-1); } if ((fp = fopen(argv[1],"r")) == NULL) { perror("fopen"); exit(-1); } do { r = fscanf(fp,"%8s %c %50s\n",&addr_str[2],&ch,var); // format of System.map if (strcmp(var,"jiffies")==0) break; } while(r > 0); if (r < 0) { printf("could not find jiffies\n"); exit(-1); } addr = strtoul(addr_str,NULL,16); //Convert string to unsigned long integer printf("found jiffies at (%s) %08lx\n",addr_str,addr); read_kmem(addr, &jiffies, sizeof(jiffies)); printf("jiffies=%ld (read from virtual memory)\n\n", jiffies); jiffies = 0; //reinit for checking read_mem() below read_mem(addr-0xC0000000, &jiffies, sizeof(jiffies)); printf("jiffies=%ld (read from physical memory)\n", jiffies); return 0; } ```