-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
x86/selftests: Add test for mapping placement for 5-level paging
5-level paging provides a 56-bit virtual address space for user space application. But the kernel defaults to mappings below the 47-bit address space boundary, which is the upper bound for 4-level paging, unless an application explicitely request it by using a mmap(2) address hint above the 47-bit boundary. The kernel prevents mappings which spawn across the 47-bit boundary unless mmap(2) was invoked with MAP_FIXED. Add a self-test that covers the corner cases of the interface and validates the correctness of the implementation. [ tglx: Massaged changelog once more ] Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Nicholas Piggin <npiggin@gmail.com> Cc: Andy Lutomirski <luto@amacapital.net> Cc: linux-mm@kvack.org Cc: Linus Torvalds <torvalds@linux-foundation.org> Link: https://lkml.kernel.org/r/20171115143607.81541-2-kirill.shutemov@linux.intel.com
- Loading branch information
Kirill A. Shutemov
authored and
Thomas Gleixner
committed
Nov 16, 2017
1 parent
1e0f25d
commit 97f404a
Showing
2 changed files
with
178 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
#include <stdio.h> | ||
#include <sys/mman.h> | ||
|
||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) | ||
|
||
#define PAGE_SIZE 4096 | ||
#define LOW_ADDR ((void *) (1UL << 30)) | ||
#define HIGH_ADDR ((void *) (1UL << 50)) | ||
|
||
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[] = { | ||
{ | ||
.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 *)((1UL << 47) - PAGE_SIZE), | ||
.size = 2 * PAGE_SIZE, | ||
.flags = MAP_PRIVATE | MAP_ANONYMOUS, | ||
.msg = "mmap((1UL << 47), 2 * PAGE_SIZE)", | ||
.low_addr_required = 1, | ||
.keep_mapped = 1, | ||
}, | ||
{ | ||
.addr = (void *)((1UL << 47) - PAGE_SIZE / 2), | ||
.size = 2 * PAGE_SIZE, | ||
.flags = MAP_PRIVATE | MAP_ANONYMOUS, | ||
.msg = "mmap((1UL << 47), 2 * PAGE_SIZE / 2)", | ||
.low_addr_required = 1, | ||
.keep_mapped = 1, | ||
}, | ||
{ | ||
.addr = (void *)((1UL << 47) - PAGE_SIZE), | ||
.size = 2 * PAGE_SIZE, | ||
.flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, | ||
.msg = "mmap((1UL << 47) - PAGE_SIZE, 2 * PAGE_SIZE, MAP_FIXED)", | ||
}, | ||
{ | ||
.addr = NULL, | ||
.size = 2UL << 20, | ||
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS, | ||
.msg = "mmap(NULL, MAP_HUGETLB)", | ||
.low_addr_required = 1, | ||
}, | ||
{ | ||
.addr = LOW_ADDR, | ||
.size = 2UL << 20, | ||
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS, | ||
.msg = "mmap(LOW_ADDR, MAP_HUGETLB)", | ||
.low_addr_required = 1, | ||
}, | ||
{ | ||
.addr = HIGH_ADDR, | ||
.size = 2UL << 20, | ||
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS, | ||
.msg = "mmap(HIGH_ADDR, MAP_HUGETLB)", | ||
.keep_mapped = 1, | ||
}, | ||
{ | ||
.addr = HIGH_ADDR, | ||
.size = 2UL << 20, | ||
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS, | ||
.msg = "mmap(HIGH_ADDR, MAP_HUGETLB) again", | ||
.keep_mapped = 1, | ||
}, | ||
{ | ||
.addr = HIGH_ADDR, | ||
.size = 2UL << 20, | ||
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, | ||
.msg = "mmap(HIGH_ADDR, MAP_FIXED | MAP_HUGETLB)", | ||
}, | ||
{ | ||
.addr = (void*) -1, | ||
.size = 2UL << 20, | ||
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS, | ||
.msg = "mmap(-1, MAP_HUGETLB)", | ||
.keep_mapped = 1, | ||
}, | ||
{ | ||
.addr = (void*) -1, | ||
.size = 2UL << 20, | ||
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS, | ||
.msg = "mmap(-1, MAP_HUGETLB) again", | ||
}, | ||
{ | ||
.addr = (void *)((1UL << 47) - PAGE_SIZE), | ||
.size = 4UL << 20, | ||
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS, | ||
.msg = "mmap((1UL << 47), 4UL << 20, MAP_HUGETLB)", | ||
.low_addr_required = 1, | ||
.keep_mapped = 1, | ||
}, | ||
{ | ||
.addr = (void *)((1UL << 47) - (2UL << 20)), | ||
.size = 4UL << 20, | ||
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, | ||
.msg = "mmap((1UL << 47) - (2UL << 20), 4UL << 20, MAP_FIXED | MAP_HUGETLB)", | ||
}, | ||
}; | ||
|
||
int main(int argc, char **argv) | ||
{ | ||
int i; | ||
void *p; | ||
|
||
for (i = 0; i < ARRAY_SIZE(testcases); i++) { | ||
struct testcase *t = testcases + i; | ||
|
||
p = mmap(t->addr, t->size, PROT_NONE, t->flags, -1, 0); | ||
|
||
printf("%s: %p - ", t->msg, p); | ||
|
||
if (p == MAP_FAILED) { | ||
printf("FAILED\n"); | ||
continue; | ||
} | ||
|
||
if (t->low_addr_required && p >= (void *)(1UL << 47)) | ||
printf("FAILED\n"); | ||
else | ||
printf("OK\n"); | ||
if (!t->keep_mapped) | ||
munmap(p, t->size); | ||
} | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters