mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
289 lines
6.7 KiB
289 lines
6.7 KiB
// SPDX-License-Identifier: GPL-2.0-only |
|
/* |
|
* |
|
* Authors: Kirill A. Shutemov <[email protected]> |
|
* Authors: Aneesh Kumar K.V <[email protected]> |
|
*/ |
|
|
|
#include <stdio.h> |
|
#include <sys/mman.h> |
|
#include <string.h> |
|
|
|
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) |
|
|
|
#ifdef __powerpc64__ |
|
#define PAGE_SIZE (64 << 10) |
|
/* |
|
* This will work with 16M and 2M hugepage size |
|
*/ |
|
#define HUGETLB_SIZE (16 << 20) |
|
#else |
|
#define PAGE_SIZE (4 << 10) |
|
#define HUGETLB_SIZE (2 << 20) |
|
#endif |
|
|
|
/* |
|
* >= 128TB is the hint addr value we used to select |
|
* large address space. |
|
*/ |
|
#define ADDR_SWITCH_HINT (1UL << 47) |
|
#define LOW_ADDR ((void *) (1UL << 30)) |
|
#define HIGH_ADDR ((void *) (1UL << 48)) |
|
|
|
struct testcase { |
|
void *addr; |
|
unsigned long size; |
|
unsigned long flags; |
|
const char *msg; |
|
unsigned int low_addr_required:1; |
|
unsigned int keep_mapped:1; |
|
}; |
|
|
|
static struct testcase testcases[] = { |
|
{ |
|
/* |
|
* If stack is moved, we could possibly allocate |
|
* this at the requested address. |
|
*/ |
|
.addr = ((void *)(ADDR_SWITCH_HINT - PAGE_SIZE)), |
|
.size = PAGE_SIZE, |
|
.flags = MAP_PRIVATE | MAP_ANONYMOUS, |
|
.msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, PAGE_SIZE)", |
|
.low_addr_required = 1, |
|
}, |
|
{ |
|
/* |
|
* We should never allocate at the requested address or above it |
|
* The len cross the 128TB boundary. Without MAP_FIXED |
|
* we will always search in the lower address space. |
|
*/ |
|
.addr = ((void *)(ADDR_SWITCH_HINT - PAGE_SIZE)), |
|
.size = 2 * PAGE_SIZE, |
|
.flags = MAP_PRIVATE | MAP_ANONYMOUS, |
|
.msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, (2 * PAGE_SIZE))", |
|
.low_addr_required = 1, |
|
}, |
|
{ |
|
/* |
|
* Exact mapping at 128TB, the area is free we should get that |
|
* even without MAP_FIXED. |
|
*/ |
|
.addr = ((void *)(ADDR_SWITCH_HINT)), |
|
.size = PAGE_SIZE, |
|
.flags = MAP_PRIVATE | MAP_ANONYMOUS, |
|
.msg = "mmap(ADDR_SWITCH_HINT, PAGE_SIZE)", |
|
.keep_mapped = 1, |
|
}, |
|
{ |
|
.addr = (void *)(ADDR_SWITCH_HINT), |
|
.size = 2 * PAGE_SIZE, |
|
.flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, |
|
.msg = "mmap(ADDR_SWITCH_HINT, 2 * PAGE_SIZE, MAP_FIXED)", |
|
}, |
|
{ |
|
.addr = NULL, |
|
.size = 2 * PAGE_SIZE, |
|
.flags = MAP_PRIVATE | MAP_ANONYMOUS, |
|
.msg = "mmap(NULL)", |
|
.low_addr_required = 1, |
|
}, |
|
{ |
|
.addr = LOW_ADDR, |
|
.size = 2 * PAGE_SIZE, |
|
.flags = MAP_PRIVATE | MAP_ANONYMOUS, |
|
.msg = "mmap(LOW_ADDR)", |
|
.low_addr_required = 1, |
|
}, |
|
{ |
|
.addr = HIGH_ADDR, |
|
.size = 2 * PAGE_SIZE, |
|
.flags = MAP_PRIVATE | MAP_ANONYMOUS, |
|
.msg = "mmap(HIGH_ADDR)", |
|
.keep_mapped = 1, |
|
}, |
|
{ |
|
.addr = HIGH_ADDR, |
|
.size = 2 * PAGE_SIZE, |
|
.flags = MAP_PRIVATE | MAP_ANONYMOUS, |
|
.msg = "mmap(HIGH_ADDR) again", |
|
.keep_mapped = 1, |
|
}, |
|
{ |
|
.addr = HIGH_ADDR, |
|
.size = 2 * PAGE_SIZE, |
|
.flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, |
|
.msg = "mmap(HIGH_ADDR, MAP_FIXED)", |
|
}, |
|
{ |
|
.addr = (void *) -1, |
|
.size = 2 * PAGE_SIZE, |
|
.flags = MAP_PRIVATE | MAP_ANONYMOUS, |
|
.msg = "mmap(-1)", |
|
.keep_mapped = 1, |
|
}, |
|
{ |
|
.addr = (void *) -1, |
|
.size = 2 * PAGE_SIZE, |
|
.flags = MAP_PRIVATE | MAP_ANONYMOUS, |
|
.msg = "mmap(-1) again", |
|
}, |
|
{ |
|
.addr = ((void *)(ADDR_SWITCH_HINT - PAGE_SIZE)), |
|
.size = PAGE_SIZE, |
|
.flags = MAP_PRIVATE | MAP_ANONYMOUS, |
|
.msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, PAGE_SIZE)", |
|
.low_addr_required = 1, |
|
}, |
|
{ |
|
.addr = (void *)(ADDR_SWITCH_HINT - PAGE_SIZE), |
|
.size = 2 * PAGE_SIZE, |
|
.flags = MAP_PRIVATE | MAP_ANONYMOUS, |
|
.msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, 2 * PAGE_SIZE)", |
|
.low_addr_required = 1, |
|
.keep_mapped = 1, |
|
}, |
|
{ |
|
.addr = (void *)(ADDR_SWITCH_HINT - PAGE_SIZE / 2), |
|
.size = 2 * PAGE_SIZE, |
|
.flags = MAP_PRIVATE | MAP_ANONYMOUS, |
|
.msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE/2 , 2 * PAGE_SIZE)", |
|
.low_addr_required = 1, |
|
.keep_mapped = 1, |
|
}, |
|
{ |
|
.addr = ((void *)(ADDR_SWITCH_HINT)), |
|
.size = PAGE_SIZE, |
|
.flags = MAP_PRIVATE | MAP_ANONYMOUS, |
|
.msg = "mmap(ADDR_SWITCH_HINT, PAGE_SIZE)", |
|
}, |
|
{ |
|
.addr = (void *)(ADDR_SWITCH_HINT), |
|
.size = 2 * PAGE_SIZE, |
|
.flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, |
|
.msg = "mmap(ADDR_SWITCH_HINT, 2 * PAGE_SIZE, MAP_FIXED)", |
|
}, |
|
}; |
|
|
|
static struct testcase hugetlb_testcases[] = { |
|
{ |
|
.addr = NULL, |
|
.size = HUGETLB_SIZE, |
|
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS, |
|
.msg = "mmap(NULL, MAP_HUGETLB)", |
|
.low_addr_required = 1, |
|
}, |
|
{ |
|
.addr = LOW_ADDR, |
|
.size = HUGETLB_SIZE, |
|
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS, |
|
.msg = "mmap(LOW_ADDR, MAP_HUGETLB)", |
|
.low_addr_required = 1, |
|
}, |
|
{ |
|
.addr = HIGH_ADDR, |
|
.size = HUGETLB_SIZE, |
|
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS, |
|
.msg = "mmap(HIGH_ADDR, MAP_HUGETLB)", |
|
.keep_mapped = 1, |
|
}, |
|
{ |
|
.addr = HIGH_ADDR, |
|
.size = HUGETLB_SIZE, |
|
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS, |
|
.msg = "mmap(HIGH_ADDR, MAP_HUGETLB) again", |
|
.keep_mapped = 1, |
|
}, |
|
{ |
|
.addr = HIGH_ADDR, |
|
.size = HUGETLB_SIZE, |
|
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, |
|
.msg = "mmap(HIGH_ADDR, MAP_FIXED | MAP_HUGETLB)", |
|
}, |
|
{ |
|
.addr = (void *) -1, |
|
.size = HUGETLB_SIZE, |
|
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS, |
|
.msg = "mmap(-1, MAP_HUGETLB)", |
|
.keep_mapped = 1, |
|
}, |
|
{ |
|
.addr = (void *) -1, |
|
.size = HUGETLB_SIZE, |
|
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS, |
|
.msg = "mmap(-1, MAP_HUGETLB) again", |
|
}, |
|
{ |
|
.addr = (void *)(ADDR_SWITCH_HINT - PAGE_SIZE), |
|
.size = 2 * HUGETLB_SIZE, |
|
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS, |
|
.msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, 2*HUGETLB_SIZE, MAP_HUGETLB)", |
|
.low_addr_required = 1, |
|
.keep_mapped = 1, |
|
}, |
|
{ |
|
.addr = (void *)(ADDR_SWITCH_HINT), |
|
.size = 2 * HUGETLB_SIZE, |
|
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, |
|
.msg = "mmap(ADDR_SWITCH_HINT , 2*HUGETLB_SIZE, MAP_FIXED | MAP_HUGETLB)", |
|
}, |
|
}; |
|
|
|
static int run_test(struct testcase *test, int count) |
|
{ |
|
void *p; |
|
int i, ret = 0; |
|
|
|
for (i = 0; i < count; i++) { |
|
struct testcase *t = test + i; |
|
|
|
p = mmap(t->addr, t->size, PROT_READ | PROT_WRITE, t->flags, -1, 0); |
|
|
|
printf("%s: %p - ", t->msg, p); |
|
|
|
if (p == MAP_FAILED) { |
|
printf("FAILED\n"); |
|
ret = 1; |
|
continue; |
|
} |
|
|
|
if (t->low_addr_required && p >= (void *)(ADDR_SWITCH_HINT)) { |
|
printf("FAILED\n"); |
|
ret = 1; |
|
} else { |
|
/* |
|
* Do a dereference of the address returned so that we catch |
|
* bugs in page fault handling |
|
*/ |
|
memset(p, 0, t->size); |
|
printf("OK\n"); |
|
} |
|
if (!t->keep_mapped) |
|
munmap(p, t->size); |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
static int supported_arch(void) |
|
{ |
|
#if defined(__powerpc64__) |
|
return 1; |
|
#elif defined(__x86_64__) |
|
return 1; |
|
#else |
|
return 0; |
|
#endif |
|
} |
|
|
|
int main(int argc, char **argv) |
|
{ |
|
int ret; |
|
|
|
if (!supported_arch()) |
|
return 0; |
|
|
|
ret = run_test(testcases, ARRAY_SIZE(testcases)); |
|
if (argc == 2 && !strcmp(argv[1], "--run-hugetlb")) |
|
ret = run_test(hugetlb_testcases, ARRAY_SIZE(hugetlb_testcases)); |
|
return ret; |
|
}
|
|
|