Created
July 3, 2018 22:52
-
-
Save jerrinsg/31582cab3b7e47e63503736a0a6ffe53 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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