Skip to content

Instantly share code, notes, and snippets.

@jerrinsg
Created July 3, 2018 22:52
Show Gist options
  • Save jerrinsg/31582cab3b7e47e63503736a0a6ffe53 to your computer and use it in GitHub Desktop.
Save jerrinsg/31582cab3b7e47e63503736a0a6ffe53 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <stdint.h>
#define PAGE_SHIFT 12
#define PAGEMAP_LENGTH 8
typedef unsigned long ul;
// Function that returns page frame number of the virtual address that is passed
// in as 'addr'.
ul get_pfn(ul addr) {
// https://shanetully.com/2014/12/translating-virtual-addresses-to-physcial-addresses-in-user-space/
// https://www.kernel.org/doc/Documentation/vm/pagemap.txt
FILE *pfd = fopen("/proc/self/pagemap", "rb");
if (pfd == NULL) {
printf("Error opening pagemanp = %s\n", strerror(errno));
}
ul pfn = 0, i = 1;
ul offset = (addr / getpagesize()) * PAGEMAP_LENGTH;
if(fseek(pfd, offset, SEEK_SET) != 0) {
fprintf(stderr, "Failed to seek pagemap to proper location\n");
exit(1);
}
fread(&pfn, PAGEMAP_LENGTH, 1, pfd);
fclose(pfd);
/*
* Bits 0-54 page frame number (PFN) if present
* Bits 0-4 swap type if swapped
* Bits 5-54 swap offset if swapped
* Bit 55 pte is soft-dirty (see Documentation/vm/soft-dirty.txt)
* Bit 56 page exclusively mapped (since 4.2)
* Bits 57-60 zero
* Bit 61 page is file-page or shared-anon (since 3.5)
* Bit 62 page swapped
* Bit 63 page present
*/
printf("page present:%lu page swapped:%lu page exclusively mapped:%lu"\
" file page or shared-anon:%lu pfn:%lu\n", (pfn>>63)&i, (pfn>>62)&i,\
(pfn>>56)&i, (pfn>>61)&i,(pfn&((i<<55) - i)));
// return page frame number (bits 0 to 54)
return (pfn&((i<<55) - i));
}
int open_memory(void) {
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);
}
}
int main() {
//int pmem_fd = open("/mnt/ext4-pmem0/testflush", O_RDWR|O_SYNC);
int pmem_fd = open("/dev/dax0.0", O_RDWR|O_SYNC);
if (pmem_fd < 0) {
printf("unable to open file, err=%s\n", strerror(errno));
return -1;
}
char* pmemaddr = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, pmem_fd, 0);
if (pmemaddr == MAP_FAILED) {
printf("mmap failed with error=%s\n", strerror(errno));
return -1;
}
close(pmem_fd);
printf("pmemaddr is %p\n", pmemaddr);
// write 0x88 0x77 0x66 .. into first 8 bytes of mapped memory
for(int i=0;i<8;i++) {
*(pmemaddr+i) = (0x11*(i+1));
}
// get page frame number of mapped virtual address
ul pfn = get_pfn((ul)(pmemaddr));
// shift pfn by PAGE_SHIFT to get offset in /dev/mem where the data we wrote
// should be.
uint64_t offset = (pfn << PAGE_SHIFT);
int mem_fd = open_memory();
seek_memory(mem_fd, offset);
ul tmp;
if(read(mem_fd, &tmp, 8) == -1) {
fprintf(stderr, "Read failed: %s\n", strerror(errno));
} else {
printf("read from device: %lx\n", tmp);
}
if (munmap(pmemaddr, 4096) != 0) {
printf("munmap failed %s\n", strerror(errno));
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment