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;
}
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