1 /* SPDX-License-Identifier: GPL-2.0 */
2 
3 #ifndef __KSELFTEST_VM_UTIL_H
4 #define __KSELFTEST_VM_UTIL_H
5 
6 #include <stdint.h>
7 #include <sys/mman.h>
8 #include <err.h>
9 #include <string.h> /* ffsl() */
10 #include <unistd.h> /* _SC_PAGESIZE */
11 
12 static unsigned int __page_size;
13 static unsigned int __page_shift;
14 
page_size(void)15 static inline unsigned int page_size(void)
16 {
17 	if (!__page_size)
18 		__page_size = sysconf(_SC_PAGESIZE);
19 	return __page_size;
20 }
21 
page_shift(void)22 static inline unsigned int page_shift(void)
23 {
24 	if (!__page_shift)
25 		__page_shift = (ffsl(page_size()) - 1);
26 	return __page_shift;
27 }
28 
29 #define PAGE_SHIFT	(page_shift())
30 #define PAGE_SIZE	(page_size())
31 /*
32  * On ppc64 this will only work with radix 2M hugepage size
33  */
34 #define HPAGE_SHIFT 21
35 #define HPAGE_SIZE (1 << HPAGE_SHIFT)
36 
37 #define PAGEMAP_PRESENT(ent)	(((ent) & (1ull << 63)) != 0)
38 #define PAGEMAP_PFN(ent)	((ent) & ((1ull << 55) - 1))
39 
40 
allocate_transhuge(void * ptr,int pagemap_fd)41 static inline int64_t allocate_transhuge(void *ptr, int pagemap_fd)
42 {
43 	uint64_t ent[2];
44 
45 	/* drop pmd */
46 	if (mmap(ptr, HPAGE_SIZE, PROT_READ | PROT_WRITE,
47 		 MAP_FIXED | MAP_ANONYMOUS |
48 		 MAP_NORESERVE | MAP_PRIVATE, -1, 0) != ptr)
49 		errx(2, "mmap transhuge");
50 
51 	if (madvise(ptr, HPAGE_SIZE, MADV_HUGEPAGE))
52 		err(2, "MADV_HUGEPAGE");
53 
54 	/* allocate transparent huge page */
55 	*(volatile void **)ptr = ptr;
56 
57 	if (pread(pagemap_fd, ent, sizeof(ent),
58 		  (uintptr_t)ptr >> (PAGE_SHIFT - 3)) != sizeof(ent))
59 		err(2, "read pagemap");
60 
61 	if (PAGEMAP_PRESENT(ent[0]) && PAGEMAP_PRESENT(ent[1]) &&
62 	    PAGEMAP_PFN(ent[0]) + 1 == PAGEMAP_PFN(ent[1]) &&
63 	    !(PAGEMAP_PFN(ent[0]) & ((1 << (HPAGE_SHIFT - PAGE_SHIFT)) - 1)))
64 		return PAGEMAP_PFN(ent[0]);
65 
66 	return -1;
67 }
68 
69 #endif
70