brintos

brintos / linux-shallow public Read only

0
0
Text · 8.1 KiB · 896b3f7 Raw
337 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *4 * Authors: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>5 * Authors: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>6 */7 8#include <stdio.h>9#include <sys/mman.h>10#include <string.h>11 12#include "vm_util.h"13#include "../kselftest.h"14 15/*16 * The hint addr value is used to allocate addresses17 * beyond the high address switch boundary.18 */19 20#define ADDR_MARK_128TB	(1UL << 47)21#define ADDR_MARK_256TB	(1UL << 48)22 23#define HIGH_ADDR_128TB	(1UL << 48)24#define HIGH_ADDR_256TB	(1UL << 49)25 26struct testcase {27	void *addr;28	unsigned long size;29	unsigned long flags;30	const char *msg;31	unsigned int low_addr_required:1;32	unsigned int keep_mapped:1;33};34 35static struct testcase *testcases;36static struct testcase *hugetlb_testcases;37static int sz_testcases, sz_hugetlb_testcases;38static unsigned long switch_hint;39 40/* Initialize testcases inside a function to compute parameters at runtime */41void testcases_init(void)42{43	unsigned long pagesize = getpagesize();44	unsigned long hugepagesize = default_huge_page_size();45	unsigned long low_addr = (1UL << 30);46	unsigned long addr_switch_hint = ADDR_MARK_128TB;47	unsigned long high_addr = HIGH_ADDR_128TB;48 49#ifdef __aarch64__50 51	/* Post LPA2, the lower userspace VA on a 16K pagesize is 47 bits. */52	if (pagesize != (16UL << 10)) {53		addr_switch_hint = ADDR_MARK_256TB;54		high_addr = HIGH_ADDR_256TB;55	}56#endif57 58	struct testcase t[] = {59		{60			/*61			 * If stack is moved, we could possibly allocate62			 * this at the requested address.63			 */64			.addr = ((void *)(addr_switch_hint - pagesize)),65			.size = pagesize,66			.flags = MAP_PRIVATE | MAP_ANONYMOUS,67			.msg = "mmap(addr_switch_hint - pagesize, pagesize)",68			.low_addr_required = 1,69		},70		{71			/*72			 * Unless MAP_FIXED is specified, allocation based on hint73			 * addr is never at requested address or above it, which is74			 * beyond high address switch boundary in this case. Instead,75			 * a suitable allocation is found in lower address space.76			 */77			.addr = ((void *)(addr_switch_hint - pagesize)),78			.size = 2 * pagesize,79			.flags = MAP_PRIVATE | MAP_ANONYMOUS,80			.msg = "mmap(addr_switch_hint - pagesize, (2 * pagesize))",81			.low_addr_required = 1,82		},83		{84			/*85			 * Exact mapping at high address switch boundary, should86			 * be obtained even without MAP_FIXED as area is free.87			 */88			.addr = ((void *)(addr_switch_hint)),89			.size = pagesize,90			.flags = MAP_PRIVATE | MAP_ANONYMOUS,91			.msg = "mmap(addr_switch_hint, pagesize)",92			.keep_mapped = 1,93		},94		{95			.addr = (void *)(addr_switch_hint),96			.size = 2 * pagesize,97			.flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,98			.msg = "mmap(addr_switch_hint, 2 * pagesize, MAP_FIXED)",99		},100		{101			.addr = NULL,102			.size = 2 * pagesize,103			.flags = MAP_PRIVATE | MAP_ANONYMOUS,104			.msg = "mmap(NULL)",105			.low_addr_required = 1,106		},107		{108			.addr = (void *)low_addr,109			.size = 2 * pagesize,110			.flags = MAP_PRIVATE | MAP_ANONYMOUS,111			.msg = "mmap(low_addr)",112			.low_addr_required = 1,113		},114		{115			.addr = (void *)high_addr,116			.size = 2 * pagesize,117			.flags = MAP_PRIVATE | MAP_ANONYMOUS,118			.msg = "mmap(high_addr)",119			.keep_mapped = 1,120		},121		{122			.addr = (void *)high_addr,123			.size = 2 * pagesize,124			.flags = MAP_PRIVATE | MAP_ANONYMOUS,125			.msg = "mmap(high_addr) again",126			.keep_mapped = 1,127		},128		{129			.addr = (void *)high_addr,130			.size = 2 * pagesize,131			.flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,132			.msg = "mmap(high_addr, MAP_FIXED)",133		},134		{135			.addr = (void *) -1,136			.size = 2 * pagesize,137			.flags = MAP_PRIVATE | MAP_ANONYMOUS,138			.msg = "mmap(-1)",139			.keep_mapped = 1,140		},141		{142			.addr = (void *) -1,143			.size = 2 * pagesize,144			.flags = MAP_PRIVATE | MAP_ANONYMOUS,145			.msg = "mmap(-1) again",146		},147		{148			.addr = ((void *)(addr_switch_hint - pagesize)),149			.size = pagesize,150			.flags = MAP_PRIVATE | MAP_ANONYMOUS,151			.msg = "mmap(addr_switch_hint - pagesize, pagesize)",152			.low_addr_required = 1,153		},154		{155			.addr = (void *)(addr_switch_hint - pagesize),156			.size = 2 * pagesize,157			.flags = MAP_PRIVATE | MAP_ANONYMOUS,158			.msg = "mmap(addr_switch_hint - pagesize, 2 * pagesize)",159			.low_addr_required = 1,160			.keep_mapped = 1,161		},162		{163			.addr = (void *)(addr_switch_hint - pagesize / 2),164			.size = 2 * pagesize,165			.flags = MAP_PRIVATE | MAP_ANONYMOUS,166			.msg = "mmap(addr_switch_hint - pagesize/2 , 2 * pagesize)",167			.low_addr_required = 1,168			.keep_mapped = 1,169		},170		{171			.addr = ((void *)(addr_switch_hint)),172			.size = pagesize,173			.flags = MAP_PRIVATE | MAP_ANONYMOUS,174			.msg = "mmap(addr_switch_hint, pagesize)",175		},176		{177			.addr = (void *)(addr_switch_hint),178			.size = 2 * pagesize,179			.flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,180			.msg = "mmap(addr_switch_hint, 2 * pagesize, MAP_FIXED)",181		},182	};183 184	struct testcase ht[] = {185		{186			.addr = NULL,187			.size = hugepagesize,188			.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,189			.msg = "mmap(NULL, MAP_HUGETLB)",190			.low_addr_required = 1,191		},192		{193			.addr = (void *)low_addr,194			.size = hugepagesize,195			.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,196			.msg = "mmap(low_addr, MAP_HUGETLB)",197			.low_addr_required = 1,198		},199		{200			.addr = (void *)high_addr,201			.size = hugepagesize,202			.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,203			.msg = "mmap(high_addr, MAP_HUGETLB)",204			.keep_mapped = 1,205		},206		{207			.addr = (void *)high_addr,208			.size = hugepagesize,209			.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,210			.msg = "mmap(high_addr, MAP_HUGETLB) again",211			.keep_mapped = 1,212		},213		{214			.addr = (void *)high_addr,215			.size = hugepagesize,216			.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,217			.msg = "mmap(high_addr, MAP_FIXED | MAP_HUGETLB)",218		},219		{220			.addr = (void *) -1,221			.size = hugepagesize,222			.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,223			.msg = "mmap(-1, MAP_HUGETLB)",224			.keep_mapped = 1,225		},226		{227			.addr = (void *) -1,228			.size = hugepagesize,229			.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,230			.msg = "mmap(-1, MAP_HUGETLB) again",231		},232		{233			.addr = (void *)(addr_switch_hint - pagesize),234			.size = 2 * hugepagesize,235			.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,236			.msg = "mmap(addr_switch_hint - pagesize, 2*hugepagesize, MAP_HUGETLB)",237			.low_addr_required = 1,238			.keep_mapped = 1,239		},240		{241			.addr = (void *)(addr_switch_hint),242			.size = 2 * hugepagesize,243			.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,244			.msg = "mmap(addr_switch_hint , 2*hugepagesize, MAP_FIXED | MAP_HUGETLB)",245		},246	};247 248	testcases = malloc(sizeof(t));249	hugetlb_testcases = malloc(sizeof(ht));250 251	/* Copy into global arrays */252	memcpy(testcases, t, sizeof(t));253	memcpy(hugetlb_testcases, ht, sizeof(ht));254 255	sz_testcases = ARRAY_SIZE(t);256	sz_hugetlb_testcases = ARRAY_SIZE(ht);257	switch_hint = addr_switch_hint;258}259 260static int run_test(struct testcase *test, int count)261{262	void *p;263	int i, ret = KSFT_PASS;264 265	for (i = 0; i < count; i++) {266		struct testcase *t = test + i;267 268		p = mmap(t->addr, t->size, PROT_READ | PROT_WRITE, t->flags, -1, 0);269 270		printf("%s: %p - ", t->msg, p);271 272		if (p == MAP_FAILED) {273			printf("FAILED\n");274			ret = KSFT_FAIL;275			continue;276		}277 278		if (t->low_addr_required && p >= (void *)(switch_hint)) {279			printf("FAILED\n");280			ret = KSFT_FAIL;281		} else {282			/*283			 * Do a dereference of the address returned so that we catch284			 * bugs in page fault handling285			 */286			memset(p, 0, t->size);287			printf("OK\n");288		}289		if (!t->keep_mapped)290			munmap(p, t->size);291	}292 293	return ret;294}295 296#ifdef __aarch64__297/* Check if userspace VA > 48 bits */298static int high_address_present(void)299{300	void *ptr = mmap((void *)(1UL << 50), 1, PROT_READ | PROT_WRITE,301			 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);302	if (ptr == MAP_FAILED)303		return 0;304 305	munmap(ptr, 1);306	return 1;307}308#endif309 310static int supported_arch(void)311{312#if defined(__powerpc64__)313	return 1;314#elif defined(__x86_64__)315	return 1;316#elif defined(__aarch64__)317	return high_address_present();318#else319	return 0;320#endif321}322 323int main(int argc, char **argv)324{325	int ret;326 327	if (!supported_arch())328		return KSFT_SKIP;329 330	testcases_init();331 332	ret = run_test(testcases, sz_testcases);333	if (argc == 2 && !strcmp(argv[1], "--run-hugetlb"))334		ret = run_test(hugetlb_testcases, sz_hugetlb_testcases);335	return ret;336}337