How to validate data read from LBA is correct? - c

I have this program which reads data from LBA (logical block address), but everytime whatever the LBA number i provide, it gives the same output.
How do i validate it?
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <linux/fs.h>
//#include "common.h"
typedef unsigned long long int var64;
int getSectorSize(int handle)
{
int sectorSize = 0;
//get the physical sector size of the disk
if (ioctl(handle, BLKSSZGET, &sectorSize)) {
printf("getSectorSize: Reading physical sector size failed.\n");
sectorSize = 512;
}
return sectorSize;
}
var64 readLBA(int handle, var64 lba, void* buf, var64 bytes)
{
int ret = 0;
int sectorSize = getSectorSize(handle);
var64 offset = lba * sectorSize;
printf("readFromLBA: entered.\n");
lseek64(handle, offset, SEEK_SET);
ret = read(handle, buf, bytes);
if(ret != bytes) {
printf("read LBA: read failed.\n");
return -1;
}
printf("read LBA: retval: %lld.\n", ret);
return ret;
}
int main()
{
int sectorSize, fd;
char buff[100];
printf("Calling getSectorSize\n");
fd = open("/dev/sda1", O_RDONLY);
if(fd == -1)
{
printf("open /dev/sda1 failed");
exit(1);
}
sectorSize = getSectorSize(fd);
printf("Sector size = %u\n", sectorSize);
memset(buff, 0, sizeof(buff));
readLBA(fd, 1, buff, 2); // if i put the 2nd arg as -12378 gives same answer
}
Here is the output:
sles10-sp3:~ # gcc getSectorSizeMain.c
getSectorSizeMain.c: In function ‘main’:
getSectorSizeMain.c:75: warning: incompatible implicit declaration of built-in function ‘memset’
sles10-sp3:~ # ./a.out
Calling getSectorSize
Sector size = 512
read LBA: entered.
read LBA: retval: 8589934594. // This is always constant, how to validate? If i tell to read an invalid LBA number like -123456 the answer remains same. How to validate?

retval doesn't contain the data you are interested in, but the count of bytes read() has stored into your buffer, so it's natural it always contains the same value. But in your test output you try to print it using "%lld" (long long int), even when it's just a plain int, so printf will combine its value with whatever it finds next to it on the stack (notice that 8589934594==0x200000002 - the last digit is your value, the first one propably garbage).
The data you want to check/use/whatever are inside the array buff.

Related

Why can I not mmap /proc/self/maps?

To be specific: why can I do this:
FILE *fp = fopen("/proc/self/maps", "r");
char buf[513]; buf[512] = NULL;
while(fgets(buf, 512, fp) > NULL) printf("%s", buf);
but not this:
int fd = open("/proc/self/maps", O_RDONLY);
struct stat s;
fstat(fd, &s); // st_size = 0 -> why?
char *file = mmap(0, s.st_size /*or any fixed size*/, PROT_READ, MAP_PRIVATE, fd, 0); // gives EINVAL for st_size (because 0) and ENODEV for any fixed block
write(1, file, st_size);
I know that /proc files are not really files, but it seems to have some defined size and content for the FILE* version. Is it secretly generating it on-the-fly for read or something? What am I missing here?
EDIT:
as I can clearly read() from them, is there any way to get the possible available bytes? or am I stuck to read until EOF?
They are created on the fly as you read them. Maybe this would help, it is a tutorial showing how a proc file can be implemented:
https://devarea.com/linux-kernel-development-creating-a-proc-file-and-interfacing-with-user-space/
tl;dr: you give it a name and read and write handlers, that's it. Proc files are meant to be very simple to implement from the kernel dev's point of view. They do not behave like full-featured files though.
As for the bonus question, there doesn't seem to be a way to indicate the size of the file, only EOF on reading.
proc "files" are not really files, they are just streams that can be read/written from, but they contain no pyhsical data in memory you can map to.
https://tldp.org/LDP/Linux-Filesystem-Hierarchy/html/proc.html
As already explained by others, /proc and /sys are pseudo-filesystems, consisting of data provided by the kernel, that does not really exist until it is read – the kernel generates the data then and there. Since the size varies, and really is unknown until the file is opened for reading, it is not provided to userspace at all.
It is not "unfortunate", however. The same situation occurs very often, for example with character devices (under /dev), pipes, FIFOs (named pipes), and sockets.
We can trivially write a helper function to read pseudofiles completely, using dynamic memory management. For example:
// SPDX-License-Identifier: CC0-1.0
//
#define _POSIX_C_SOURCE 200809L
#define _ATFILE_SOURCE
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
/* For example main() */
#include <stdio.h>
/* Return a directory handle for a specific relative directory.
For absolute paths and paths relative to current directory, use dirfd==AT_FDCWD.
*/
int at_dir(const int dirfd, const char *dirpath)
{
if (dirfd == -1 || !dirpath || !*dirpath) {
errno = EINVAL;
return -1;
}
return openat(dirfd, dirpath, O_DIRECTORY | O_PATH | O_CLOEXEC);
}
/* Read the (pseudofile) contents to a dynamically allocated buffer.
For absolute paths and paths relative to current durectory, use dirfd==AT_FDCWD.
You can safely initialize *dataptr=NULL,*sizeptr=0 for dynamic allocation,
or reuse the buffer from a previous call or e.g. getline().
Returns 0 with errno set if an error occurs. If the file is empty, errno==0.
In all cases, remember to free (*dataptr) after it is no longer needed.
*/
size_t read_pseudofile_at(const int dirfd, const char *path, char **dataptr, size_t *sizeptr)
{
char *data;
size_t size, have = 0;
ssize_t n;
int desc;
if (!path || !*path || !dataptr || !sizeptr) {
errno = EINVAL;
return 0;
}
/* Existing dynamic buffer, or a new buffer? */
size = *sizeptr;
if (!size)
*dataptr = NULL;
data = *dataptr;
/* Open pseudofile. */
desc = openat(dirfd, path, O_RDONLY | O_CLOEXEC | O_NOCTTY);
if (desc == -1) {
/* errno set by openat(). */
return 0;
}
while (1) {
/* Need to resize buffer? */
if (have >= size) {
/* For pseudofiles, linear size growth makes most sense. */
size = (have | 4095) + 4097 - 32;
data = realloc(data, size);
if (!data) {
close(desc);
errno = ENOMEM;
return 0;
}
*dataptr = data;
*sizeptr = size;
}
n = read(desc, data + have, size - have);
if (n > 0) {
have += n;
} else
if (n == 0) {
break;
} else
if (n == -1) {
const int saved_errno = errno;
close(desc);
errno = saved_errno;
return 0;
} else {
close(desc);
errno = EIO;
return 0;
}
}
if (close(desc) == -1) {
/* errno set by close(). */
return 0;
}
/* Append zeroes - we know size > have at this point. */
if (have + 32 > size)
memset(data + have, 0, 32);
else
memset(data + have, 0, size - have);
errno = 0;
return have;
}
int main(void)
{
char *data = NULL;
size_t size = 0;
size_t len;
int selfdir;
selfdir = at_dir(AT_FDCWD, "/proc/self/");
if (selfdir == -1) {
fprintf(stderr, "/proc/self/ is not available: %s.\n", strerror(errno));
exit(EXIT_FAILURE);
}
len = read_pseudofile_at(selfdir, "status", &data, &size);
if (errno) {
fprintf(stderr, "/proc/self/status: %s.\n", strerror(errno));
exit(EXIT_FAILURE);
}
printf("/proc/self/status: %zu bytes\n%s\n", len, data);
len = read_pseudofile_at(selfdir, "maps", &data, &size);
if (errno) {
fprintf(stderr, "/proc/self/maps: %s.\n", strerror(errno));
exit(EXIT_FAILURE);
}
printf("/proc/self/maps: %zu bytes\n%s\n", len, data);
close(selfdir);
free(data); data = NULL; size = 0;
return EXIT_SUCCESS;
}
The above example program opens a directory descriptor ("atfile handle") to /proc/self. (This way you do not need to concatenate strings to construct paths.)
It then reads the contents of /proc/self/status. If successful, it displays its size (in bytes) and its contents.
Next, it reads the contents of /proc/self/maps, reusing the previous buffer. If successful, it displays its size and contents as well.
Finally, the directory descriptor is closed as it is no longer needed, and the dynamically allocated buffer released.
Note that it is perfectly safe to do free(NULL), and also to discard the dynamic buffer (free(data); data=NULL; size=0;) between the read_pseudofile_at() calls.
Because pseudofiles are typically small, the read_pseudofile_at() uses a linear dynamic buffer growth policy. If there is no previous buffer, it starts with 8160 bytes, and grows it by 4096 bytes afterwards until sufficiently large. Feel free to replace it with whatever growth policy you prefer, this one is just an example, but works quite well in practice without wasting much memory.

how to properly use posix_memalign

I'am struggling to find out how to proper use the pread and pwrite.
In this case, I am trying to read only 256 bytes using pread.
However, that whenever I try to read less than 512 bytes pread will not return anything.
I believe that this problem has to be with the SECTOR argument that I am assigning to posix_memalign...
Is there some obvious info that I have to be aware of?
#define BUF_SIZE 256
#define SECTOR 512
#define FILE_SIZE 1024 * 1024 * 1024 //1G
int main( int argc, char **argv ){
int fd, nr;
char fl_nm[]={"/dev/nvme0n1p1"};
char* aligned_buf_w = NULL;
char* aligned_buf_r = NULL;
void* ad = NULL;
if (posix_memalign(&ad, SECTOR, BUF_SIZE)) {
perror("posix_memalign failed"); exit (EXIT_FAILURE);
}
aligned_buf_w = (char *)(ad);
ad = NULL;
if (posix_memalign(&ad, SECTOR, BUF_SIZE)) {
perror("posix_memalign failed"); exit (EXIT_FAILURE);
}
aligned_buf_r = (char *)(ad);
memset(aligned_buf_w, '*', BUF_SIZE * sizeof(char));
printf("BEFORE READ BEGIN\n");
printf("\t aligned_buf_w::%ld\n",strlen(aligned_buf_w));
printf("\t aligned_buf_r::%ld\n",strlen(aligned_buf_r));
printf("BEFORE READ END\n");
fd = open(fl_nm, O_RDWR | O_DIRECT);
pwrite(fd, aligned_buf_w, BUF_SIZE, 0);
//write error checking
if(nr == -1){
perror("[error in write 2]\n");
}
nr = pread(fd, aligned_buf_r, BUF_SIZE, 0);
//read error checking
if(nr == -1){
perror("[error in read 2]\n");
}
printf("AFTER READ BEGIN\n");
printf("\taligned_buf_r::%ld \n",strlen(aligned_buf_r));
printf("AFTER READ END\n");
//error checking for close process
if(close(fd) == -1){
perror("[error in close]\n");
}else{
printf("[succeeded in close]\n");
}
return 0;
}
Here is the output when I read and write 512 bytes
BEFORE READ BEGIN
aligned_buf_w::512
aligned_buf_r::0
BEFORE READ END
AFTER READ BEGIN
aligned_buf_r::512
AFTER READ END
[succeeded in close]
and here is the result when I try to read 256 bytes
BEFORE READ BEGIN
aligned_buf_w::256
aligned_buf_r::0
BEFORE READ END
[error in read 2]
: Invalid argument
AFTER READ BEGIN
aligned_buf_r::0
AFTER READ END
[succeeded in close]
While using O_DIRECT "the kernel will do DMA directly from/to the physical memory pointed by the userspace buffer passed as parameter" - https://www.ukuug.org/events/linux2001/papers/html/AArcangeli-o_direct.html - so you have to observe some restrictions - http://man7.org/linux/man-pages/man8/raw.8.html
All I/Os must be correctly aligned in memory and on disk: they must start at a sector
offset on disk, they must be an exact number of sectors long, and the
data buffer in virtual memory must also be aligned to a multiple of
the sector size. The sector size is 512 bytes for most devices.
With buffered IO you do not care of that. The following sample illustrates that while reading a HDD (/dev/sda9) :
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define SECTOR 512
int main( int argc, char **argv ){
int fd, nr, BUF_SIZE;
char fl_nm[]={"/dev/sda9"};
char* buf = NULL;
if (argc>1) {
BUF_SIZE = atoi(argv[1]);
// BUFFERED IO
printf("Buffered IO -------\n");
if ((buf = (char*)malloc(BUF_SIZE)) == NULL) perror("[malloc]");
else {
if ((fd = open(fl_nm, O_RDONLY)) == -1) perror("[open]");
if((nr = pread(fd, buf, BUF_SIZE, 4096)) == -1) perror("[pread]");
else
printf("%i bytes read %.2x %.2x ...\n",nr,buf[0],buf[1]);
free(buf);
if(close(fd) == -1) perror("[close]");
}
// DIRECT IO
printf("Direct IO ---------\n");
if (posix_memalign((void *)&buf, SECTOR, BUF_SIZE)) {
perror("posix_memalign failed");
}
else {
if ((fd = open(fl_nm, O_RDONLY | O_DIRECT)) == -1) perror("[open]");
/* buf size , buf alignment and offset has to observe hardware restrictions */
if((nr = pread(fd, buf, BUF_SIZE, 4096)) == -1) perror("[pread]");
else
printf("%i bytes read %.2x %.2x ...\n",nr,buf[0],buf[1]);
free(buf);
if(close(fd) == -1) perror("[close]");
}
}
return 0;
}
You can verify the following behaviour :
$ sudo ./testodirect 512
Buffered IO -------
512 bytes read 01 04 ...
Direct IO ---------
512 bytes read 01 04 ...
$ sudo ./testodirect 4
Buffered IO -------
4 bytes read 01 04 ...
Direct IO ---------
[pread]: Invalid argument
By the way O_DIRECT is not in flavour of everybody https://yarchive.net/comp/linux/o_direct.html
512B is the smallest unit you can read from a storage device

C program of accessing device file don't work

I have seen device file can be accessed directly in Linux and I want to have a try. I have a free disk partition without any file system. My test code is below.
I expect to get output read data: 199 when I run the program at the second time. But actually, I get output read data: 0 twice. No errors emerge during the program. I have no idea where is wrong.
Thanks for your time.
Test Code:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
int main(){
int num = 0;
int fd = open("/dev/sda6", O_RDWR);
if(fd == -1){
fprintf(stderr, "open device failed, errno : %s(%d) \n",
strerror(errno), errno);
return 1;
}
ssize_t ret = read(fd, &num, sizeof(int));
if(ret != sizeof(int)){
fprintf(stderr, "read fails, errno : %s(%d) \n",
strerror(errno), errno);
return 1;
}
printf("read data: %d\n", num);
num = 199;
ret = write(fd, &num, sizeof(int));
if(ret != sizeof(int)){
fprintf(stderr, "write fails, errno : %s(%d) \n",
strerror(errno), errno);
return 1;
}
close(fd);
return 0;
}
The read and write start reading/writing at the implicit file offset stored in the descriptor, and increment it by the number of bytes read/written. Therefore, you would now read bytes 0 .. 3, and then write bytes 4 .. 7.
Instead of read and write and messing with lseek et al, use the POSIX standard pread and pwrite that do not use the implicit file offset in the descriptor but take explicit file offsets from the beginning of a file in the call.
#include <unistd.h>
ssize_t pread(int fd, void *buf, size_t count, off_t offset);
ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
...
ssize_t ret = pread(fd, &num, sizeof(int), 0);
ssize_t ret = pwrite(fd, &num, sizeof(int), 0);
You do not seek in your program, so what it does:
Read the first 4 bytes of the device, then write the second 4 bytes.
Try
lseek(fd,0,SEEK_SET);
before write if you want to write at the beginning of fole.

segmentation fault in virtual address to physical address

When i run the binary file of this code it throws an segmentation fault core dumped error. And the dmesg is:
segfault at 0 ip b7651747 sp bfb312d0 error 4 in libc-2.21.so[b75e9000+1b4000]
The code is for translation of virtual address to physical address.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
// ORIG_BUFFER will be placed in memory and will then be changed to NEW_BUFFER
// They must be the same length
#define ORIG_BUFFER "Hello, World!"
#define NEW_BUFFER "Hello, Linux!"
// The page frame shifted left by PAGE_SHIFT will give us the physcial address of the frame
// Note that this number is architecture dependent. For me on x86_64 with 4096 page sizes,
// it is defined as 12. If you're running something different, check the kernel source
// for what it is defined as.
#define PAGE_SHIFT 12
#define PAGEMAP_LENGTH 8
void* create_buffer(void);
unsigned long get_page_frame_number_of_address(void *addr);
int open_memory(void);
void seek_memory(int fd, unsigned long offset);
int main(void) {
// Create a buffer with some data in it
void *buffer = create_buffer();
// Get the page frame the buffer is on
unsigned int page_frame_number = get_page_frame_number_of_address(buffer);
printf("Page frame: 0x%x\n", page_frame_number);
// Find the difference from the buffer to the page boundary
unsigned int distance_from_page_boundary = (unsigned long)buffer %
getpagesize();
// Determine how far to seek into memory to find the buffer
uint64_t offset = (page_frame_number << PAGE_SHIFT) + distance_from_page_boundary;
// Open /dev/mem, seek the calculated offset, and
// map it into memory so we can manipulate it
// CONFIG_STRICT_DEVMEM must be disabled for this
int mem_fd = open_memory();
seek_memory(mem_fd, offset);
printf("Buffer: %s\n", buffer);
puts("Changing buffer through /dev/mem...");
// Change the contents of the buffer by writing into /dev/mem
// Note that since the strings are the same length, there's no purpose in
// copying the NUL terminator again
if(write(mem_fd, NEW_BUFFER, strlen(NEW_BUFFER)) == -1) {
fprintf(stderr, "Write failed: %s\n", strerror(errno));
}
printf("Buffer: %s\n", buffer);
// Clean up
free(buffer);
close(mem_fd);
return 0;
}
void* create_buffer(void) {
size_t buf_size = strlen(ORIG_BUFFER) + 1;
// Allocate some memory to manipulate
void *buffer = malloc(buf_size);
if(buffer == NULL) {
fprintf(stderr, "Failed to allocate memory for buffer\n");
exit(1);
}
// Lock the page in memory
// Do this before writing data to the buffer so that any copy-on-write
// mechanisms will give us our own page locked in memory
if(mlock(buffer, buf_size) == -1) {
fprintf(stderr, "Failed to lock page in memory: %s\n", strerror(errno));
exit(1);
}
// Add some data to the memory
strncpy(buffer, ORIG_BUFFER, strlen(ORIG_BUFFER));
return buffer;
}
unsigned long get_page_frame_number_of_address(void *addr) {
// Open the pagemap file for the current process
FILE *pagemap = fopen("/proc/self/pagemap", "rb");
// Seek to the page that the buffer is on
unsigned long offset = (unsigned long)addr / getpagesize() * PAGEMAP_LENGTH;
if(fseek(pagemap, (unsigned long)offset, SEEK_SET) != 0) {
fprintf(stderr, "Failed to seek pagemap to proper location\n");
exit(1);
}
// The page frame number is in bits 0-54 so read the first 7 bytes and clear the 55th bit
unsigned long page_frame_number = 0;
fread(&page_frame_number, 1, PAGEMAP_LENGTH-1, pagemap);
page_frame_number &= 0x7FFFFFFFFFFFFF;
fclose(pagemap);
return page_frame_number;
}
int open_memory(void) {
// Open the memory (must be root for this)
int fd = open("/dev/mem", O_RDWR);
if(fd == -1) {
fprintf(stderr, "Error opening /dev/mem: %s\n", strerror(errno));
exit(1);
}
return fd;
}
void seek_memory(int fd, unsigned long offset) {
unsigned pos = lseek(fd, offset, SEEK_SET);
if(pos == -1) {
fprintf(stderr, "Failed to seek /dev/mem: %s\n", strerror(errno));
exit(1);
}
}
In function get_page_frame_number_of_address.
Please confirm open file success.
FILE *pagemap = fopen("/proc/self/pagemap", "rb");
Check the pagemap is NULL or not.

How to use /dev/kmem?

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.

Resources