0001
0002
0003
0004
0005
0006
0007
0008 #include <stdlib.h>
0009 #include <stdio.h>
0010 #include <unistd.h>
0011 #include <sys/mman.h>
0012 #include <fcntl.h>
0013
0014 #define MAP_LENGTH (2UL * 1024 * 1024)
0015
0016 #ifndef MAP_HUGETLB
0017 #define MAP_HUGETLB 0x40000
0018 #endif
0019
0020 #define PAGE_SIZE 4096
0021
0022 #define PAGE_COMPOUND_HEAD (1UL << 15)
0023 #define PAGE_COMPOUND_TAIL (1UL << 16)
0024 #define PAGE_HUGE (1UL << 17)
0025
0026 #define HEAD_PAGE_FLAGS (PAGE_COMPOUND_HEAD | PAGE_HUGE)
0027 #define TAIL_PAGE_FLAGS (PAGE_COMPOUND_TAIL | PAGE_HUGE)
0028
0029 #define PM_PFRAME_BITS 55
0030 #define PM_PFRAME_MASK ~((1UL << PM_PFRAME_BITS) - 1)
0031
0032
0033
0034
0035
0036
0037
0038 #ifdef __ia64__
0039 #define MAP_ADDR (void *)(0x8000000000000000UL)
0040 #define MAP_FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_FIXED)
0041 #else
0042 #define MAP_ADDR NULL
0043 #define MAP_FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB)
0044 #endif
0045
0046 static void write_bytes(char *addr, size_t length)
0047 {
0048 unsigned long i;
0049
0050 for (i = 0; i < length; i++)
0051 *(addr + i) = (char)i;
0052 }
0053
0054 static unsigned long virt_to_pfn(void *addr)
0055 {
0056 int fd;
0057 unsigned long pagemap;
0058
0059 fd = open("/proc/self/pagemap", O_RDONLY);
0060 if (fd < 0)
0061 return -1UL;
0062
0063 lseek(fd, (unsigned long)addr / PAGE_SIZE * sizeof(pagemap), SEEK_SET);
0064 read(fd, &pagemap, sizeof(pagemap));
0065 close(fd);
0066
0067 return pagemap & ~PM_PFRAME_MASK;
0068 }
0069
0070 static int check_page_flags(unsigned long pfn)
0071 {
0072 int fd, i;
0073 unsigned long pageflags;
0074
0075 fd = open("/proc/kpageflags", O_RDONLY);
0076 if (fd < 0)
0077 return -1;
0078
0079 lseek(fd, pfn * sizeof(pageflags), SEEK_SET);
0080
0081 read(fd, &pageflags, sizeof(pageflags));
0082 if ((pageflags & HEAD_PAGE_FLAGS) != HEAD_PAGE_FLAGS) {
0083 close(fd);
0084 printf("Head page flags (%lx) is invalid\n", pageflags);
0085 return -1;
0086 }
0087
0088
0089
0090
0091
0092
0093 for (i = 1; i < MAP_LENGTH / PAGE_SIZE; i++) {
0094 read(fd, &pageflags, sizeof(pageflags));
0095 if ((pageflags & TAIL_PAGE_FLAGS) != TAIL_PAGE_FLAGS ||
0096 (pageflags & HEAD_PAGE_FLAGS) == HEAD_PAGE_FLAGS) {
0097 close(fd);
0098 printf("Tail page flags (%lx) is invalid\n", pageflags);
0099 return -1;
0100 }
0101 }
0102
0103 close(fd);
0104
0105 return 0;
0106 }
0107
0108 int main(int argc, char **argv)
0109 {
0110 void *addr;
0111 unsigned long pfn;
0112
0113 addr = mmap(MAP_ADDR, MAP_LENGTH, PROT_READ | PROT_WRITE, MAP_FLAGS, -1, 0);
0114 if (addr == MAP_FAILED) {
0115 perror("mmap");
0116 exit(1);
0117 }
0118
0119
0120 write_bytes(addr, MAP_LENGTH);
0121
0122 pfn = virt_to_pfn(addr);
0123 if (pfn == -1UL) {
0124 munmap(addr, MAP_LENGTH);
0125 perror("virt_to_pfn");
0126 exit(1);
0127 }
0128
0129 printf("Returned address is %p whose pfn is %lx\n", addr, pfn);
0130
0131 if (check_page_flags(pfn) < 0) {
0132 munmap(addr, MAP_LENGTH);
0133 perror("check_page_flags");
0134 exit(1);
0135 }
0136
0137
0138 if (munmap(addr, MAP_LENGTH)) {
0139 perror("munmap");
0140 exit(1);
0141 }
0142
0143 return 0;
0144 }