Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *
0004  * Authors: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
0005  * Authors: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
0006  */
0007 
0008 #include <stdio.h>
0009 #include <sys/mman.h>
0010 #include <string.h>
0011 
0012 #include "../kselftest.h"
0013 
0014 #ifdef __powerpc64__
0015 #define PAGE_SIZE   (64 << 10)
0016 /*
0017  * This will work with 16M and 2M hugepage size
0018  */
0019 #define HUGETLB_SIZE    (16 << 20)
0020 #else
0021 #define PAGE_SIZE   (4 << 10)
0022 #define HUGETLB_SIZE    (2 << 20)
0023 #endif
0024 
0025 /*
0026  * >= 128TB is the hint addr value we used to select
0027  * large address space.
0028  */
0029 #define ADDR_SWITCH_HINT (1UL << 47)
0030 #define LOW_ADDR    ((void *) (1UL << 30))
0031 #define HIGH_ADDR   ((void *) (1UL << 48))
0032 
0033 struct testcase {
0034     void *addr;
0035     unsigned long size;
0036     unsigned long flags;
0037     const char *msg;
0038     unsigned int low_addr_required:1;
0039     unsigned int keep_mapped:1;
0040 };
0041 
0042 static struct testcase testcases[] = {
0043     {
0044         /*
0045          * If stack is moved, we could possibly allocate
0046          * this at the requested address.
0047          */
0048         .addr = ((void *)(ADDR_SWITCH_HINT - PAGE_SIZE)),
0049         .size = PAGE_SIZE,
0050         .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0051         .msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, PAGE_SIZE)",
0052         .low_addr_required = 1,
0053     },
0054     {
0055         /*
0056          * We should never allocate at the requested address or above it
0057          * The len cross the 128TB boundary. Without MAP_FIXED
0058          * we will always search in the lower address space.
0059          */
0060         .addr = ((void *)(ADDR_SWITCH_HINT - PAGE_SIZE)),
0061         .size = 2 * PAGE_SIZE,
0062         .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0063         .msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, (2 * PAGE_SIZE))",
0064         .low_addr_required = 1,
0065     },
0066     {
0067         /*
0068          * Exact mapping at 128TB, the area is free we should get that
0069          * even without MAP_FIXED.
0070          */
0071         .addr = ((void *)(ADDR_SWITCH_HINT)),
0072         .size = PAGE_SIZE,
0073         .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0074         .msg = "mmap(ADDR_SWITCH_HINT, PAGE_SIZE)",
0075         .keep_mapped = 1,
0076     },
0077     {
0078         .addr = (void *)(ADDR_SWITCH_HINT),
0079         .size = 2 * PAGE_SIZE,
0080         .flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
0081         .msg = "mmap(ADDR_SWITCH_HINT, 2 * PAGE_SIZE, MAP_FIXED)",
0082     },
0083     {
0084         .addr = NULL,
0085         .size = 2 * PAGE_SIZE,
0086         .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0087         .msg = "mmap(NULL)",
0088         .low_addr_required = 1,
0089     },
0090     {
0091         .addr = LOW_ADDR,
0092         .size = 2 * PAGE_SIZE,
0093         .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0094         .msg = "mmap(LOW_ADDR)",
0095         .low_addr_required = 1,
0096     },
0097     {
0098         .addr = HIGH_ADDR,
0099         .size = 2 * PAGE_SIZE,
0100         .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0101         .msg = "mmap(HIGH_ADDR)",
0102         .keep_mapped = 1,
0103     },
0104     {
0105         .addr = HIGH_ADDR,
0106         .size = 2 * PAGE_SIZE,
0107         .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0108         .msg = "mmap(HIGH_ADDR) again",
0109         .keep_mapped = 1,
0110     },
0111     {
0112         .addr = HIGH_ADDR,
0113         .size = 2 * PAGE_SIZE,
0114         .flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
0115         .msg = "mmap(HIGH_ADDR, MAP_FIXED)",
0116     },
0117     {
0118         .addr = (void *) -1,
0119         .size = 2 * PAGE_SIZE,
0120         .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0121         .msg = "mmap(-1)",
0122         .keep_mapped = 1,
0123     },
0124     {
0125         .addr = (void *) -1,
0126         .size = 2 * PAGE_SIZE,
0127         .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0128         .msg = "mmap(-1) again",
0129     },
0130     {
0131         .addr = ((void *)(ADDR_SWITCH_HINT - PAGE_SIZE)),
0132         .size = PAGE_SIZE,
0133         .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0134         .msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, PAGE_SIZE)",
0135         .low_addr_required = 1,
0136     },
0137     {
0138         .addr = (void *)(ADDR_SWITCH_HINT - PAGE_SIZE),
0139         .size = 2 * PAGE_SIZE,
0140         .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0141         .msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, 2 * PAGE_SIZE)",
0142         .low_addr_required = 1,
0143         .keep_mapped = 1,
0144     },
0145     {
0146         .addr = (void *)(ADDR_SWITCH_HINT - PAGE_SIZE / 2),
0147         .size = 2 * PAGE_SIZE,
0148         .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0149         .msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE/2 , 2 * PAGE_SIZE)",
0150         .low_addr_required = 1,
0151         .keep_mapped = 1,
0152     },
0153     {
0154         .addr = ((void *)(ADDR_SWITCH_HINT)),
0155         .size = PAGE_SIZE,
0156         .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0157         .msg = "mmap(ADDR_SWITCH_HINT, PAGE_SIZE)",
0158     },
0159     {
0160         .addr = (void *)(ADDR_SWITCH_HINT),
0161         .size = 2 * PAGE_SIZE,
0162         .flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
0163         .msg = "mmap(ADDR_SWITCH_HINT, 2 * PAGE_SIZE, MAP_FIXED)",
0164     },
0165 };
0166 
0167 static struct testcase hugetlb_testcases[] = {
0168     {
0169         .addr = NULL,
0170         .size = HUGETLB_SIZE,
0171         .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
0172         .msg = "mmap(NULL, MAP_HUGETLB)",
0173         .low_addr_required = 1,
0174     },
0175     {
0176         .addr = LOW_ADDR,
0177         .size = HUGETLB_SIZE,
0178         .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
0179         .msg = "mmap(LOW_ADDR, MAP_HUGETLB)",
0180         .low_addr_required = 1,
0181     },
0182     {
0183         .addr = HIGH_ADDR,
0184         .size = HUGETLB_SIZE,
0185         .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
0186         .msg = "mmap(HIGH_ADDR, MAP_HUGETLB)",
0187         .keep_mapped = 1,
0188     },
0189     {
0190         .addr = HIGH_ADDR,
0191         .size = HUGETLB_SIZE,
0192         .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
0193         .msg = "mmap(HIGH_ADDR, MAP_HUGETLB) again",
0194         .keep_mapped = 1,
0195     },
0196     {
0197         .addr = HIGH_ADDR,
0198         .size = HUGETLB_SIZE,
0199         .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
0200         .msg = "mmap(HIGH_ADDR, MAP_FIXED | MAP_HUGETLB)",
0201     },
0202     {
0203         .addr = (void *) -1,
0204         .size = HUGETLB_SIZE,
0205         .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
0206         .msg = "mmap(-1, MAP_HUGETLB)",
0207         .keep_mapped = 1,
0208     },
0209     {
0210         .addr = (void *) -1,
0211         .size = HUGETLB_SIZE,
0212         .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
0213         .msg = "mmap(-1, MAP_HUGETLB) again",
0214     },
0215     {
0216         .addr = (void *)(ADDR_SWITCH_HINT - PAGE_SIZE),
0217         .size = 2 * HUGETLB_SIZE,
0218         .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
0219         .msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, 2*HUGETLB_SIZE, MAP_HUGETLB)",
0220         .low_addr_required = 1,
0221         .keep_mapped = 1,
0222     },
0223     {
0224         .addr = (void *)(ADDR_SWITCH_HINT),
0225         .size = 2 * HUGETLB_SIZE,
0226         .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
0227         .msg = "mmap(ADDR_SWITCH_HINT , 2*HUGETLB_SIZE, MAP_FIXED | MAP_HUGETLB)",
0228     },
0229 };
0230 
0231 static int run_test(struct testcase *test, int count)
0232 {
0233     void *p;
0234     int i, ret = KSFT_PASS;
0235 
0236     for (i = 0; i < count; i++) {
0237         struct testcase *t = test + i;
0238 
0239         p = mmap(t->addr, t->size, PROT_READ | PROT_WRITE, t->flags, -1, 0);
0240 
0241         printf("%s: %p - ", t->msg, p);
0242 
0243         if (p == MAP_FAILED) {
0244             printf("FAILED\n");
0245             ret = KSFT_FAIL;
0246             continue;
0247         }
0248 
0249         if (t->low_addr_required && p >= (void *)(ADDR_SWITCH_HINT)) {
0250             printf("FAILED\n");
0251             ret = KSFT_FAIL;
0252         } else {
0253             /*
0254              * Do a dereference of the address returned so that we catch
0255              * bugs in page fault handling
0256              */
0257             memset(p, 0, t->size);
0258             printf("OK\n");
0259         }
0260         if (!t->keep_mapped)
0261             munmap(p, t->size);
0262     }
0263 
0264     return ret;
0265 }
0266 
0267 static int supported_arch(void)
0268 {
0269 #if defined(__powerpc64__)
0270     return 1;
0271 #elif defined(__x86_64__)
0272     return 1;
0273 #else
0274     return 0;
0275 #endif
0276 }
0277 
0278 int main(int argc, char **argv)
0279 {
0280     int ret;
0281 
0282     if (!supported_arch())
0283         return KSFT_SKIP;
0284 
0285     ret = run_test(testcases, ARRAY_SIZE(testcases));
0286     if (argc == 2 && !strcmp(argv[1], "--run-hugetlb"))
0287         ret = run_test(hugetlb_testcases, ARRAY_SIZE(hugetlb_testcases));
0288     return ret;
0289 }