1

I wrote a program which calculates the physical address of a given virtual address. This program always return 0. Which means that particular page is not found. Why is that page not available?

What this code does is: This code creates a memory of a file and that memory mapped virtual address is converted to physical address using a function that I took from https://stackoverflow.com/a/28987409/6941772.

#include <sys/mman.h> 
#include <sys/stat.h>
#include <fcntl.h> // O_RDONLY
//#include <stddef.h> // to get NULL definition. NULL not a built in const. 
#include <string.h> // NULL is also defined in string.h, stdlib.h
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include "inttypes.h"

uint64_t vtop(uint64_t vaddr) {
    FILE *pagemap;
    uint64_t paddr = 0;

    unsigned long long int offset = (vaddr / sysconf(_SC_PAGESIZE)) * sizeof(uint64_t);
    uint64_t e;

    // https://www.kernel.org/doc/Documentation/vm/pagemap.txt
    if ((pagemap = fopen("/proc/self/pagemap", "r"))) {
        if (lseek(fileno(pagemap), offset, SEEK_SET) == offset) {
            if (fread(&e, sizeof(uint64_t), 1, pagemap)) {
                if (e & (1ULL << 63)) { // page present ?
                    paddr = e & ((1ULL << 54) - 1); // pfn mask
                    paddr = paddr * sysconf(_SC_PAGESIZE);
                    // add offset within page

                    paddr = paddr | (vaddr & (sysconf(_SC_PAGESIZE) - 1));
                                        printf(" paddr %lu \n", paddr);
                }
                                else {
                                    printf("page not found\n");
                                    }
            }
        }
        fclose(pagemap);
    }

    return paddr;
}

int main() {

    int oflag = O_RDONLY;
    const char *path = "file.json";
    const int fd = open(path, oflag);

    // use stat to find the file size
    struct stat stat;
    int ret = fstat(fd, &stat);

    int mflags = MAP_PRIVATE; // information about handling the mapped data
    int mprot = PROT_READ|PROT_WRITE; // access permissions to the data being mapped 
    size_t size = stat.st_size;
    void *addr = mmap(NULL, size, mprot, mflags, fd, 0);
    printf("virtual addres is %p\n", addr);
    printf("physical addres is %ld\n", vtop((uint64_t)addr));

    return 0;
}

When I use malloc, instead of mmap, I get the physical address as 0x670what is the speciality of this number?

Hadi Brais
  • 22,259
  • 3
  • 54
  • 95

1 Answers1

0

I wrote a program which calculates the physical address of a given virtual address. This program always return 0.

Accessing the physical address from /proc/self/pagemap requires running the program with root privileges (sudo). Otherwise, you'd still be able to open /proc/self/pagemap and read from it. It's just that the physical addresses would all appear to be zero. Since you're passing NULL to the first parameter of mmap, it will return a page-aligned virtual address. So the page offset is also zero. Therefore, vtop will return zero.

When I use malloc, instead of mmap, I get the physical address as 0x670what is the speciality of this number?

When allocating memory using malloc, the returned virtual address may not be page-aligned. Therefore, the page offset may not be zero. The value being printed 0x670 is just the page offset added to a physical address of zero.

Here is what you need to do:

  • Ensure that the length parameter (file size) passed to mmap is larger than zero (file must not empty). Otherwise, mmap returns -1 with errno set to EINVAL.
  • Irrespective of whether the program has root privileges, if none of the mapped pages were touched, by default, no physical pages would be allocated for them. The program would print page not found. To avoid this issue, you can read one byte (char c = *((char*)addr);) before the call to vtop.
  • Now if you touch the first page of the mapped region, but ran the program without root privileges, the physical address would be zero but the page offset may or not be zero. So you'd just get the page offset. Run the program with sudo to resolve the issue.
Hadi Brais
  • 22,259
  • 3
  • 54
  • 95
  • Used sudo command: when using mmap, I am still getting paddr as 0. But when I use malloc, I am getting an 8 digit hexa addr something like `0x52508670` why only 8 digit hexa? I am expecting 12 digits hexa – BODDU MANOHAR REDDY May 24 '18 at 04:03
  • @BODDUMANOHARREDDY is it printing `page not found` when mapping the file? – Hadi Brais May 24 '18 at 04:05
  • `page not found` is not printed – BODDU MANOHAR REDDY May 24 '18 at 04:07
  • @BODDUMANOHARREDDY This shows that it's working when using malloc. But when using mmap on the opened file, what does it print? Did you carefully read the second half of my answer? – Hadi Brais May 24 '18 at 04:08
  • @BODDUMANOHARREDDY Why are expecting 12 hex digits? Any most significant zero bits of the physical address will not be printed using the `%ld` format. – Hadi Brais May 24 '18 at 04:13
  • when using sudo and mmap: It prints that `page not found` `physical addres is 0` – BODDU MANOHAR REDDY May 24 '18 at 04:22
  • @BODDUMANOHARREDDY Is there any part of the answer you didn't understand? I've already specified in the answer what you need to do to avoid the `page not found` error. Evey sentence in the answer matters, so make sure you carefully read and understand every sentence. – Hadi Brais May 24 '18 at 19:36