The background is based on Intel EDS document (example_doc)
see Section 5 ~ 5.2
I was trying to access PCI configuration space to get the CPU vendor ID,
and then accessing the MCH Bar to read out some information under OS base, not developing the driver.
I had search for few days, but most of information are driver related, or using linux kernel library such as pci.h, which is not I prefer.
My Process:
get mcfg base address from /sys/firmware/acpi/tables/MCFG
calculate actual address with bus0, dev0, func0, reg0 (ie. lspci 0000:00:00.0)
read data from the address
Code in C:
BOOLEAN IoConfigRead(uint32_t bus, uint32_t dev, uint32_t func, uint32_t reg, void* Buffer, unsigned long length){
static uint32_t pcieBar = 0;
int fd,fd1;
int sz;
uint32_t buffer[12];
uint32_t addr;
uint32_t *p;
uint32_t value;
if(pcieBar == 0){
fd = open("/sys/firmware/acpi/tables/MCFG",0);
if(fd == -1){
printf("Error opening /sys/firmware/acpi/tables/MCFG");
exit(EXIT_FAILURE);
}
sz = read(fd, buffer, 48);
if (sz != 48) {
printf("couldn't read 48 bytes from MCFG, sz=%d\n", sz);
exit(EXIT_FAILURE);
}
if (close(fd)) {
perror("Error closing /sys/firmware/acpi/tables/MCFG");
exit(EXIT_FAILURE);
}
if (buffer[0] != 0x4746434d) {
printf("MCFG signature not found\n");
exit(EXIT_FAILURE);
}
pcieBar = buffer[11];
}
addr = pcieBar;
addr |= (((DWORD)(func & 0x7)) << 12);
addr |= (((DWORD)(dev & 0x1f)) << 15);
addr |= ((bus & 0xff) << 20);
fd1 = open("/dev/mem", O_RDWR|O_DSYNC);
if (fd1 == -1) {
perror("Error opening /dev/mem");
return EXIT_FAILURE;
}
p = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, addr);
if(p == MAP_FAILED){
printf("Failed to mmap address,0x%x\n",addr);
}
else{
int i = 0;
while (i < length/4){
((uint32_t*)Buffer)[i] = p[(reg/4)+i];
i++;
}
munmap(p,4096);
close(fd1);
}
return 0;
}
Error Msg:
Failed to mmap address,0xe0000000
Base on the acpi table the base address is
at byte 0xc(12) which is 0xe0000000 but I'm not able to use mmap to allocate it correctly.
This code seems to be workable in the past, but I'm not able to make it work.
I'm not sure what I had missed. It's already run under sudo, maybe it need some special permission?
I had tried it on kernel: 5.3.18 / 4.12.14-23 neither of them worked.
gcc version : 7.5 / 7.3
I am trying to read memory of another process and print whatever is in the memory (Heap and/or stack). I have got the range of memory addresses using /proc
I have extracted address range like this. Now I want to read the memory range of the other process like as defined.
5569032d2000-5569032f3000 rw-p 00000000 00:00 0 [heap]
I am stuck on how to access those memory addresses. I tried something like shown below , but doesn't help much.
int main(int argc, char *argv[]) {
off_t offset = strtoul(argv[1], NULL, 0);
size_t len = strtoul(argv[2], NULL, 0);
// Truncate offset to a multiple of the page size, or mmap will fail.
size_t pagesize = sysconf(_SC_PAGE_SIZE);
off_t page_base = (offset / pagesize) * pagesize;
off_t page_offset = offset - page_base;
int fd = open("/dev/mem", O_SYNC);
unsigned char *mem = mmap(NULL, page_offset + len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, page_base);
if (mem == MAP_FAILED) {
perror("Can't map memory");
return -1;
}
size_t i;
for (i = 0; i < len; ++i)
printf("%x ", (int)mem[page_offset + i]);
//size_t i;
return 0;}
Thanks.
I am making like a debug tool for my embedded system. I can't use ptrace() as it halts the running process while trying to peek into the device memory.
I figured out to read the process of another process, I can use process_vm_readv() function as follow:
pid_t pid; // Put value of pid in this
void *remotePtr; // Put starting address
size_t bufferLength; // Put size of buffer in this, aka size to read
// Build iovec structs
struct iovec local[1];
local[0].iov_base = calloc(bufferLength, sizeof(char));
local[0].iov_len = bufferLength;
struct iovec remote[1];
remote[0].iov_base = remotePtr;
remote[0].iov_len = bufferLength;
/*Nread will contain amount of bytes of data read*/
nread = process_vm_readv(pid, local, 2, remote, 1, 0);
if (nread < 0) {
switch (errno) {
case EINVAL:
printf("ERROR: INVALID ARGUMENTS.\n");
break;
case EFAULT:
printf
("ERROR: UNABLE TO ACCESS TARGET MEMORY ADDRESS.\n");
break;
case ENOMEM:
printf("ERROR: UNABLE TO ALLOCATE MEMORY.\n");
break;
case EPERM:
printf
("ERROR: INSUFFICIENT PRIVILEGES TO TARGET PROCESS.\n");
break;
case ESRCH:
printf("ERROR: PROCESS DOES NOT EXIST.\n");
break;
default:
printf("ERROR: AN UNKNOWN ERROR HAS OCCURRED.\n");
}
return -1;
}
/* To print the read data */
printf("The read text is \n %s\n", local[0].iov_base);
I created a process which calls mmap with MAP_SHARED flag set,when i attempt to copy a string to that address i receive Bus error core dumped,could some one please explain the reason behind it and how to fix it. Following is my code
int main()
{
int fd=0;
char* ret = NULL;
void *map_addr = NULL;
fd = open("./shared_file.txt", O_RDWR, S_IRUSR | S_IWUSR);
if(fd == -1) {
printf("errno = %d\n",errno);
printf("Aborting process1###########\n");
abort();
}
map_addr = mmap(NULL, 5*sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if(map_addr == MAP_FAILED) {
printf("mmap failed error no =%d\n",errno);
close(fd);
return -1;
}
printf("map_addr = %p#################\n",(int*)map_addr);
printf("processid = %d#################\n",(int)getpid());
ret = strcpy((char*)map_addr,"Stack Overflow");
if(ret == (char*)map_addr)
printf("strcpy success\n");
/*if(msync(map_addr, sizeof(int), MS_SYNC))
printf("msync failed errno = %d\n",errno);*/
close(fd);
sleep(120);
return (0);
}
The cause of a bus error is usually an attempt to dereference a pointer that has not been initialized properly and contains junk data that are not accessible in a multiple of 4 or 1 or as related to datatype sizes.
First you should check if the shared_file.txt file size is >= 20 bytes(assuming sizeof int is 4 bytes) as specified in the mmap() length argument(where you put 5*(sizeof(int))) in the line below:
map_addr = mmap(NULL, 5*sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
If file size is less than 20 bytes, you could use fallocate call to pre allocate the memory.
If shared_file.txt file size is <= 20 bytes and then you ask mmap to map 20 bytes, it could cause a bus error when you write beyond the actual no. of bytes available in file, because that would be access to an undefined portion of a memory. MMAP_FAILED will not be returned in this case, during memory initialization.
A quick check is to see if you can write a single character in the mmap char* pointer. If you can't( you will get a SIGBUS), that means file size is zero.
The idea is relatively simple, but I see some complications for implementations, so I'm wondering if it's even possible right now.
An example of what I'd like to do is to generate some data in a
buffer, then map the contents of this buffer to a file. Instead of
having the memory space virtually populated with the contents of the
file, I'd like the contents of the original buffer to be transferred
to the system cache (which should be a zero-copy operation) and
dirtied immediately (which would flush the data out to disk
eventually).
Of course the complication I mentioned is that the buffer should be deallocated and unmapped (since the data is now under the responsibility of the system cache), and I don't know how to do that either.
The important aspects are that:
The program can control when the file is created linked.
The program isn't required to anticipate the size of the file nor does it have to remap it as the dataset grows. Instead it can realloc the initial buffer (using an efficient memory allocator for this) until it is satisfied (it knows for sure that the dataset won't grow anymore) before finally mapping it to the file.
The data remains accessible through the same virtual memory address even after being mapped to the file, still without a single intra-memory copy.
One assumption is that:
We can use an arbitrary memory allocator (or memory management scheme in general) that can manage dynamic buffers more efficiently than mmap/mremap can for the memory space it manages, because the latter must deal with the filesystem to grow/shrink the file, which would always be slower.
So, (1) are these requirements too constrained? (2) Is this assumption correct?
PS: I had to arbitrarily pick the tags for this question, but I'm also interested in hearing how BSDs and Windows would do this. Of course if the POSIX API allows to do this already, that would be great.
Update: I call a buffer a space of private memory (private to the process/task in any OS with normal VMM) allocated in primary memory. The high-level goal involves generating a dataset of an arbitrary size using another input (in my case the network), then once it's generated, make it accessible for long periods of time (to the network and to the process itself), saving it to disk in the process.
If I keep the datasets in private memory and write them out normally, they'll just be swapped when the OS needs the space, which is a bit stupid since they're already on disk.
If I map another region then I have to copy the contents of the buffer to that region (which resides in the system cache), which, again, is a tad stupid since I won't use that buffer after that.
The alternative that I see is to write or use a full-blown userland cache reading and writing to the disk itself to ensure that (a) pages don't get uselessly swapped out and (b) the process doesn't hold too much memory for itself, which is never possible to do optimally anyway (better let the kernel do its job), and which is simply not a road I think is worth going down (too complex for less gains).
Update: Requirements 2 and 3 are non-issues considering Nominal Animal's answer. Of course this implies that the assumption is incorrect, as he proved is almost the case (overhead is minimal). I also relaxed requirement 1, O_TMPFILE is indeed perfect for this.
Update: A recent article on LWN mentions, somewhere in the middle: "That could possibly be done with a special write operation that would not actually cause I/O, or with a system call that would transfer a physical page into the page cache". That suggests that indeed, there is currently (April 2014) no way to do this at least with Linux (and likely other operating systems), much less with a standard API. The article is about PostgreSQL, but the issue in question is identical, except perhaps for the specific requirements to this question, which aren't defined in the article.
This is not a satisfactory answer to the question; is is more of a continuation of the comment chain.
Here is a test program one can use to measure the overhead of using a file-backed memory map, instead of an anonymous memory map.
Note that the work() function listed just fills in the memory map with random data. To be more realistic, it should simulate at least the access patterns expected from real-world usage.
#define _POSIX_C_SOURCE 200809L
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <time.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
/* Xorshift random number generator.
*/
static uint32_t xorshift_state[4] = {
123456789U,
362436069U,
521288629U,
88675123U
};
static int xorshift_setseed(const void *const data, const size_t len)
{
uint32_t state[4] = { 0 };
if (len < 1)
return ENOENT;
else
if (len < sizeof state)
memcpy(state, data, len);
else
memcpy(state, data, sizeof state);
if (state[0] || state[1] || state[2] || state[3]) {
xorshift_state[0] = state[0];
xorshift_state[1] = state[1];
xorshift_state[2] = state[2];
xorshift_state[3] = state[3];
return 0;
}
return EINVAL;
}
static uint32_t xorshift_u32(void)
{
const uint32_t temp = xorshift_state[0] ^ (xorshift_state[0] << 11U);
xorshift_state[0] = xorshift_state[1];
xorshift_state[1] = xorshift_state[2];
xorshift_state[2] = xorshift_state[3];
return xorshift_state[3] ^= (temp >> 8U) ^ temp ^ (xorshift_state[3] >> 19U);
}
/* Wallclock timing functions.
*/
static struct timespec wallclock_started;
static void wallclock_start(void)
{
clock_gettime(CLOCK_REALTIME, &wallclock_started);
}
static double wallclock_stop(void)
{
struct timespec wallclock_stopped;
clock_gettime(CLOCK_REALTIME, &wallclock_stopped);
return difftime(wallclock_stopped.tv_sec, wallclock_started.tv_sec)
+ (double)(wallclock_stopped.tv_nsec - wallclock_started.tv_nsec) / 1000000000.0;
}
/* Accessor function. This needs to read/modify/write the mapping,
* simulating the actual work done onto the mapping.
*/
static void work(void *const area, size_t const length)
{
uint32_t *const data = (uint32_t *)area;
size_t size = length / sizeof data[0];
size_t i;
/* Add xorshift data. */
for (i = 0; i < size; i++)
data[i] += xorshift_u32();
}
int main(int argc, char *argv[])
{
long page, size, delta, maxsize, steps;
int fd, result;
void *map, *old;
char dummy;
double seconds;
page = sysconf(_SC_PAGESIZE);
if (argc < 5 || argc > 6 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s MAPFILE SIZE DELTA MAXSIZE [ SEEDSTRING ]\n", argv[0]);
fprintf(stderr, "Where:\n");
fprintf(stderr, " MAPFILE backing file, '-' for none\n");
fprintf(stderr, " SIZE initial map size\n");
fprintf(stderr, " DELTA map size change\n");
fprintf(stderr, " MAXSIZE final size of the map\n");
fprintf(stderr, " SEEDSTRING seeds the Xorshift PRNG\n");
fprintf(stderr, "Note: sizes must be page aligned, each page being %ld bytes.\n", (long)page);
fprintf(stderr, "\n");
return 1;
}
if (argc >= 6) {
if (xorshift_setseed(argv[5], strlen(argv[5]))) {
fprintf(stderr, "%s: Invalid seed string for the Xorshift generator.\n", argv[5]);
return 1;
} else {
fprintf(stderr, "Xorshift initialized with { %lu, %lu, %lu, %lu }.\n",
(unsigned long)xorshift_state[0],
(unsigned long)xorshift_state[1],
(unsigned long)xorshift_state[2],
(unsigned long)xorshift_state[3]);
fflush(stderr);
}
}
if (sscanf(argv[2], " %ld %c", &size, &dummy) != 1) {
fprintf(stderr, "%s: Invalid map size.\n", argv[2]);
return 1;
} else
if (size < page || size % page) {
fprintf(stderr, "%s: Map size must be a multiple of page size (%ld).\n", argv[2], page);
return 1;
}
if (sscanf(argv[3], " %ld %c", &delta, &dummy) != 1) {
fprintf(stderr, "%s: Invalid map size change.\n", argv[2]);
return 1;
} else
if (delta % page) {
fprintf(stderr, "%s: Map size change must be a multiple of page size (%ld).\n", argv[3], page);
return 1;
}
if (delta) {
if (sscanf(argv[4], " %ld %c", &maxsize, &dummy) != 1) {
fprintf(stderr, "%s: Invalid final map size.\n", argv[3]);
return 1;
} else
if (maxsize < page || maxsize % page) {
fprintf(stderr, "%s: Final map size must be a multiple of page size (%ld).\n", argv[4], page);
return 1;
}
steps = (maxsize - size) / delta;
if (steps < 0L)
steps = -steps;
} else {
maxsize = size;
steps = 0L;
}
/* Time measurement includes the file open etc. overheads.
*/
wallclock_start();
if (strlen(argv[1]) < 1 || !strcmp(argv[1], "-"))
fd = -1;
else {
do {
fd = open(argv[1], O_RDWR | O_CREAT | O_EXCL, 0600);
} while (fd == -1 && errno == EINTR);
if (fd == -1) {
fprintf(stderr, "%s: %s.\n", argv[1], strerror(errno));
return 1;
}
do {
result = ftruncate(fd, (off_t)size);
} while (result == -1 && errno == EINTR);
if (result == -1) {
fprintf(stderr, "%s: %s.\n", argv[1], strerror(errno));
unlink(argv[1]);
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
return 1;
}
result = posix_fadvise(fd, 0, size, POSIX_FADV_RANDOM);
}
/* Initial mapping. */
if (fd == -1)
map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, fd, 0);
else
map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE, fd, 0);
if (map == MAP_FAILED) {
fprintf(stderr, "Memory map failed: %s.\n", strerror(errno));
if (fd != -1) {
unlink(argv[1]);
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
}
return 1;
}
result = posix_madvise(map, size, POSIX_MADV_RANDOM);
work(map, size);
while (steps-->0L) {
if (fd != -1) {
do {
result = ftruncate(fd, (off_t)(size + delta));
} while (result == -1 && errno == EINTR);
if (result == -1) {
fprintf(stderr, "%s: Cannot grow file: %s.\n", argv[1], strerror(errno));
unlink(argv[1]);
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
return 1;
}
result = posix_fadvise(fd, 0, size, POSIX_FADV_RANDOM);
}
old = map;
map = mremap(map, size, size + delta, MREMAP_MAYMOVE);
if (map == MAP_FAILED) {
fprintf(stderr, "Cannot remap memory map: %s.\n", strerror(errno));
munmap(old, size);
if (fd != -1) {
unlink(argv[1]);
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
}
return 1;
}
size += delta;
result = posix_madvise(map, size, POSIX_MADV_RANDOM);
work(map, size);
}
/* Timing does not include file renaming.
*/
seconds = wallclock_stop();
munmap(map, size);
if (fd != -1) {
unlink(argv[1]);
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
}
printf("%.9f seconds elapsed.\n", seconds);
return 0;
}
If you save the above as bench.c, you can compile it using
gcc -W -Wall -O3 bench.c -lrt -o bench
Run it without parameters to see the usage.
On my machine, on ext4 filesystem, running tests
./bench - 4096 4096 4096000
./bench testfile 4096 4096 4096000
yields 1.307 seconds wall clock time for the anonymous memory map, and 1.343 seconds for the file-backed memory map, meaning the file backed mapping is about 2.75% slower.
This test starts with one page memory map, then enlarges it by one page a thousand times. For tests like 4096000 4096 8192000 the difference is even smaller. The time measured does include constructing the initial file (and using posix_fallocate() to allocate the blocks on disk for the file).
Running the test on tmpfs, on ext4 over swRAID0, and on ext4 over swRAID1, on the same machine, does not seem to affect the results; all differences are lost in the noise.
While I would prefer to test this on multiple machines and kernel versions before making any sweeping statements, I do know something about how the kernel manages these memory maps. Therefore, I shall make the following claim, based on above and my own experience:
Using a file-backed memory map will not cause a significant slowdown compared to an anonymous memory map, or even compared to malloc()/realloc()/free(). I expect the difference to be under 5% in all real-world use cases, and at most 1% for typical real-world use cases; less, if the resizes are rare compared to how often the map is accessed.
To user2266481 the above means it should be acceptable to just create a temporary file on the target filesystem, to hold the memory map. (Note that it is possible to create the temporary file without allowing anyone access to it, mode 0, as access mode is only checked when opening the file.) When the contents are in final form, ftruncate() and msync() the contents, then hard-link the final file to the temporary file using link(). Finally, unlink the temporary file and close the temporary file descriptor, and the task should be completed with near-optimal efficiency.
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
For the invalid argument in case 1, the problem is offset being non-page aligned. mmap(2) works by manipulating page tables, and such works only on multiplies of page-size for both size and offset
As for the second case, I'm not sure if you're guaranteed to have kernel space begin at 3G boundary. Also, I'm pretty sure that's the boundary of kernel's virtual space, not location in physical memory - so on beagle board, quite possibly you ended up with a wrapped-around offset pointing who-knows-where.
I think what you might need is PHYS_OFFSET, not PAGE_OFFSET.