1a93cbee5SMike Rapoport (Microsoft) // SPDX-License-Identifier: GPL-2.0 2a93cbee5SMike Rapoport (Microsoft) /* 3a93cbee5SMike Rapoport (Microsoft) * A test case of using hugepage memory in a user application using the 4a93cbee5SMike Rapoport (Microsoft) * mmap system call with MAP_HUGETLB flag. Before running this program 5a93cbee5SMike Rapoport (Microsoft) * make sure the administrator has allocated enough default sized huge 6a93cbee5SMike Rapoport (Microsoft) * pages to cover the 2 MB allocation. 7a93cbee5SMike Rapoport (Microsoft) */ 8a93cbee5SMike Rapoport (Microsoft) #include <stdlib.h> 9a93cbee5SMike Rapoport (Microsoft) #include <stdio.h> 10a93cbee5SMike Rapoport (Microsoft) #include <unistd.h> 11a93cbee5SMike Rapoport (Microsoft) #include <sys/mman.h> 12a93cbee5SMike Rapoport (Microsoft) #include <fcntl.h> 13a93cbee5SMike Rapoport (Microsoft) #include "vm_util.h" 141bdc1698SMike Rapoport (Microsoft) #include "hugepage_settings.h" 15a93cbee5SMike Rapoport (Microsoft) 16a93cbee5SMike Rapoport (Microsoft) #define PAGE_COMPOUND_HEAD (1UL << 15) 17a93cbee5SMike Rapoport (Microsoft) #define PAGE_COMPOUND_TAIL (1UL << 16) 18a93cbee5SMike Rapoport (Microsoft) #define PAGE_HUGE (1UL << 17) 19a93cbee5SMike Rapoport (Microsoft) 20a93cbee5SMike Rapoport (Microsoft) #define HEAD_PAGE_FLAGS (PAGE_COMPOUND_HEAD | PAGE_HUGE) 21a93cbee5SMike Rapoport (Microsoft) #define TAIL_PAGE_FLAGS (PAGE_COMPOUND_TAIL | PAGE_HUGE) 22a93cbee5SMike Rapoport (Microsoft) 23a93cbee5SMike Rapoport (Microsoft) #define PM_PFRAME_BITS 55 24a93cbee5SMike Rapoport (Microsoft) #define PM_PFRAME_MASK ~((1UL << PM_PFRAME_BITS) - 1) 25a93cbee5SMike Rapoport (Microsoft) 26a93cbee5SMike Rapoport (Microsoft) static size_t pagesize; 27a93cbee5SMike Rapoport (Microsoft) static size_t maplength; 28a93cbee5SMike Rapoport (Microsoft) 29a93cbee5SMike Rapoport (Microsoft) static void write_bytes(char *addr, size_t length) 30a93cbee5SMike Rapoport (Microsoft) { 31a93cbee5SMike Rapoport (Microsoft) unsigned long i; 32a93cbee5SMike Rapoport (Microsoft) 33a93cbee5SMike Rapoport (Microsoft) for (i = 0; i < length; i++) 34a93cbee5SMike Rapoport (Microsoft) *(addr + i) = (char)i; 35a93cbee5SMike Rapoport (Microsoft) } 36a93cbee5SMike Rapoport (Microsoft) 37a93cbee5SMike Rapoport (Microsoft) static unsigned long virt_to_pfn(void *addr) 38a93cbee5SMike Rapoport (Microsoft) { 39a93cbee5SMike Rapoport (Microsoft) int fd; 40a93cbee5SMike Rapoport (Microsoft) unsigned long pagemap; 41a93cbee5SMike Rapoport (Microsoft) 42a93cbee5SMike Rapoport (Microsoft) fd = open("/proc/self/pagemap", O_RDONLY); 43a93cbee5SMike Rapoport (Microsoft) if (fd < 0) 44a93cbee5SMike Rapoport (Microsoft) return -1UL; 45a93cbee5SMike Rapoport (Microsoft) 46a93cbee5SMike Rapoport (Microsoft) lseek(fd, (unsigned long)addr / pagesize * sizeof(pagemap), SEEK_SET); 47a93cbee5SMike Rapoport (Microsoft) read(fd, &pagemap, sizeof(pagemap)); 48a93cbee5SMike Rapoport (Microsoft) close(fd); 49a93cbee5SMike Rapoport (Microsoft) 50a93cbee5SMike Rapoport (Microsoft) return pagemap & ~PM_PFRAME_MASK; 51a93cbee5SMike Rapoport (Microsoft) } 52a93cbee5SMike Rapoport (Microsoft) 53a93cbee5SMike Rapoport (Microsoft) static int check_page_flags(unsigned long pfn) 54a93cbee5SMike Rapoport (Microsoft) { 55a93cbee5SMike Rapoport (Microsoft) int fd, i; 56a93cbee5SMike Rapoport (Microsoft) unsigned long pageflags; 57a93cbee5SMike Rapoport (Microsoft) 58a93cbee5SMike Rapoport (Microsoft) fd = open("/proc/kpageflags", O_RDONLY); 59a93cbee5SMike Rapoport (Microsoft) if (fd < 0) 60a93cbee5SMike Rapoport (Microsoft) return -1; 61a93cbee5SMike Rapoport (Microsoft) 62a93cbee5SMike Rapoport (Microsoft) lseek(fd, pfn * sizeof(pageflags), SEEK_SET); 63a93cbee5SMike Rapoport (Microsoft) 64a93cbee5SMike Rapoport (Microsoft) read(fd, &pageflags, sizeof(pageflags)); 65a93cbee5SMike Rapoport (Microsoft) if ((pageflags & HEAD_PAGE_FLAGS) != HEAD_PAGE_FLAGS) { 66a93cbee5SMike Rapoport (Microsoft) close(fd); 6740e9e3d7SMike Rapoport (Microsoft) ksft_print_msg("Head page flags (%lx) is invalid\n", pageflags); 68a93cbee5SMike Rapoport (Microsoft) return -1; 69a93cbee5SMike Rapoport (Microsoft) } 70a93cbee5SMike Rapoport (Microsoft) 71a93cbee5SMike Rapoport (Microsoft) /* 72a93cbee5SMike Rapoport (Microsoft) * pages other than the first page must be tail and shouldn't be head; 73a93cbee5SMike Rapoport (Microsoft) * this also verifies kernel has correctly set the fake page_head to tail 74a93cbee5SMike Rapoport (Microsoft) * while hugetlb_free_vmemmap is enabled. 75a93cbee5SMike Rapoport (Microsoft) */ 76a93cbee5SMike Rapoport (Microsoft) for (i = 1; i < maplength / pagesize; i++) { 77a93cbee5SMike Rapoport (Microsoft) read(fd, &pageflags, sizeof(pageflags)); 78a93cbee5SMike Rapoport (Microsoft) if ((pageflags & TAIL_PAGE_FLAGS) != TAIL_PAGE_FLAGS || 79a93cbee5SMike Rapoport (Microsoft) (pageflags & HEAD_PAGE_FLAGS) == HEAD_PAGE_FLAGS) { 80a93cbee5SMike Rapoport (Microsoft) close(fd); 8140e9e3d7SMike Rapoport (Microsoft) ksft_print_msg("Tail page flags (%lx) is invalid\n", pageflags); 82a93cbee5SMike Rapoport (Microsoft) return -1; 83a93cbee5SMike Rapoport (Microsoft) } 84a93cbee5SMike Rapoport (Microsoft) } 85a93cbee5SMike Rapoport (Microsoft) 86a93cbee5SMike Rapoport (Microsoft) close(fd); 87a93cbee5SMike Rapoport (Microsoft) 88a93cbee5SMike Rapoport (Microsoft) return 0; 89a93cbee5SMike Rapoport (Microsoft) } 90a93cbee5SMike Rapoport (Microsoft) 91a93cbee5SMike Rapoport (Microsoft) int main(int argc, char **argv) 92a93cbee5SMike Rapoport (Microsoft) { 93a93cbee5SMike Rapoport (Microsoft) void *addr; 94a93cbee5SMike Rapoport (Microsoft) unsigned long pfn; 9540e9e3d7SMike Rapoport (Microsoft) int ret; 9640e9e3d7SMike Rapoport (Microsoft) 9740e9e3d7SMike Rapoport (Microsoft) ksft_print_header(); 9840e9e3d7SMike Rapoport (Microsoft) ksft_set_plan(1); 99a93cbee5SMike Rapoport (Microsoft) 100*496a662fSMike Rapoport (Microsoft) if (!hugetlb_setup_default(1)) 101*496a662fSMike Rapoport (Microsoft) ksft_exit_skip("Not enough free huge pages\n"); 102*496a662fSMike Rapoport (Microsoft) 103a93cbee5SMike Rapoport (Microsoft) pagesize = psize(); 104a93cbee5SMike Rapoport (Microsoft) maplength = default_huge_page_size(); 10540e9e3d7SMike Rapoport (Microsoft) if (!maplength) 10640e9e3d7SMike Rapoport (Microsoft) ksft_exit_skip("Unable to determine huge page size\n"); 107a93cbee5SMike Rapoport (Microsoft) 108a93cbee5SMike Rapoport (Microsoft) addr = mmap(NULL, maplength, PROT_READ | PROT_WRITE, 109a93cbee5SMike Rapoport (Microsoft) MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0); 11040e9e3d7SMike Rapoport (Microsoft) if (addr == MAP_FAILED) 11140e9e3d7SMike Rapoport (Microsoft) ksft_exit_fail_perror("mmap"); 112a93cbee5SMike Rapoport (Microsoft) 113a93cbee5SMike Rapoport (Microsoft) /* Trigger allocation of HugeTLB page. */ 114a93cbee5SMike Rapoport (Microsoft) write_bytes(addr, maplength); 115a93cbee5SMike Rapoport (Microsoft) 116a93cbee5SMike Rapoport (Microsoft) pfn = virt_to_pfn(addr); 117a93cbee5SMike Rapoport (Microsoft) if (pfn == -1UL) { 11840e9e3d7SMike Rapoport (Microsoft) ksft_perror("virt_to_pfn"); 119a93cbee5SMike Rapoport (Microsoft) munmap(addr, maplength); 12040e9e3d7SMike Rapoport (Microsoft) ksft_exit_fail(); 121a93cbee5SMike Rapoport (Microsoft) } 122a93cbee5SMike Rapoport (Microsoft) 12340e9e3d7SMike Rapoport (Microsoft) ksft_print_msg("Returned address is %p whose pfn is %lx\n", addr, pfn); 124a93cbee5SMike Rapoport (Microsoft) 12540e9e3d7SMike Rapoport (Microsoft) ret = check_page_flags(pfn); 126a93cbee5SMike Rapoport (Microsoft) 12740e9e3d7SMike Rapoport (Microsoft) if (munmap(addr, maplength)) 12840e9e3d7SMike Rapoport (Microsoft) ksft_exit_fail_perror("munmap"); 129a93cbee5SMike Rapoport (Microsoft) 13040e9e3d7SMike Rapoport (Microsoft) ksft_test_result(!ret, "HugeTLB vmemmap page flags\n"); 13140e9e3d7SMike Rapoport (Microsoft) ksft_finished(); 132a93cbee5SMike Rapoport (Microsoft) } 133