xref: /illumos-gate/usr/src/test/bhyve-tests/tests/vmm/mem_partial.c (revision 957246c9e6c47389c40079995d73eebcc659fb29)
170ae9a33SPatrick Mooney /*
270ae9a33SPatrick Mooney  * This file and its contents are supplied under the terms of the
370ae9a33SPatrick Mooney  * Common Development and Distribution License ("CDDL"), version 1.0.
470ae9a33SPatrick Mooney  * You may only use this file in accordance with the terms of version
570ae9a33SPatrick Mooney  * 1.0 of the CDDL.
670ae9a33SPatrick Mooney  *
770ae9a33SPatrick Mooney  * A full copy of the text of the CDDL should have accompanied this
870ae9a33SPatrick Mooney  * source.  A copy of the CDDL is also available via the Internet at
970ae9a33SPatrick Mooney  * http://www.illumos.org/license/CDDL.
1070ae9a33SPatrick Mooney  */
1170ae9a33SPatrick Mooney 
1270ae9a33SPatrick Mooney /*
1370ae9a33SPatrick Mooney  * Copyright 2022 Oxide Computer Company
1470ae9a33SPatrick Mooney  */
1570ae9a33SPatrick Mooney 
1670ae9a33SPatrick Mooney 
1770ae9a33SPatrick Mooney #include <stdio.h>
1870ae9a33SPatrick Mooney #include <unistd.h>
1970ae9a33SPatrick Mooney #include <stropts.h>
2070ae9a33SPatrick Mooney #include <strings.h>
2170ae9a33SPatrick Mooney #include <signal.h>
2270ae9a33SPatrick Mooney #include <setjmp.h>
2370ae9a33SPatrick Mooney #include <libgen.h>
2470ae9a33SPatrick Mooney 
2570ae9a33SPatrick Mooney #include <sys/vmm.h>
2670ae9a33SPatrick Mooney #include <sys/vmm_dev.h>
2770ae9a33SPatrick Mooney #include <sys/mman.h>
2870ae9a33SPatrick Mooney #include <vmmapi.h>
2970ae9a33SPatrick Mooney 
3070ae9a33SPatrick Mooney #include "common.h"
3170ae9a33SPatrick Mooney 
3270ae9a33SPatrick Mooney /* Half of a leaf page table is 256 pages */
3370ae9a33SPatrick Mooney #define	LOWER_SZ	(256 * 4096)
3470ae9a33SPatrick Mooney #define	UPPER_SZ	LOWER_SZ
3570ae9a33SPatrick Mooney #define	TOTAL_SZ	(LOWER_SZ + UPPER_SZ)
3670ae9a33SPatrick Mooney 
3770ae9a33SPatrick Mooney #define	LOWER_OFF	0
3870ae9a33SPatrick Mooney #define	UPPER_OFF	LOWER_SZ
3970ae9a33SPatrick Mooney 
4070ae9a33SPatrick Mooney enum test_memsegs {
4170ae9a33SPatrick Mooney 	MSEG_LOW = 0,
4270ae9a33SPatrick Mooney 	MSEG_HIGH = 1,
4370ae9a33SPatrick Mooney };
4470ae9a33SPatrick Mooney 
4570ae9a33SPatrick Mooney static sigjmp_buf segv_env;
4670ae9a33SPatrick Mooney 
4770ae9a33SPatrick Mooney void
sigsegv_handler(int sig)4870ae9a33SPatrick Mooney sigsegv_handler(int sig)
4970ae9a33SPatrick Mooney {
5070ae9a33SPatrick Mooney 	siglongjmp(segv_env, 1);
5170ae9a33SPatrick Mooney }
5270ae9a33SPatrick Mooney 
5370ae9a33SPatrick Mooney 
5470ae9a33SPatrick Mooney int
main(int argc,char * argv[])5570ae9a33SPatrick Mooney main(int argc, char *argv[])
5670ae9a33SPatrick Mooney {
5770ae9a33SPatrick Mooney 	struct vmctx *ctx;
5870ae9a33SPatrick Mooney 	int res, fd;
5970ae9a33SPatrick Mooney 	void *guest_mem;
60*957246c9SPatrick Mooney 	const char *suite_name = basename(argv[0]);
6170ae9a33SPatrick Mooney 
62*957246c9SPatrick Mooney 	ctx = create_test_vm(suite_name);
6370ae9a33SPatrick Mooney 	if (ctx == NULL) {
6470ae9a33SPatrick Mooney 		perror("could open test VM");
6570ae9a33SPatrick Mooney 		return (1);
6670ae9a33SPatrick Mooney 	}
6770ae9a33SPatrick Mooney 	fd = vm_get_device_fd(ctx);
6870ae9a33SPatrick Mooney 
6970ae9a33SPatrick Mooney 	res = alloc_memseg(ctx, MSEG_LOW, LOWER_SZ, "mseg_low");
7070ae9a33SPatrick Mooney 	if (res != 0) {
7170ae9a33SPatrick Mooney 		perror("could not alloc low memseg");
7270ae9a33SPatrick Mooney 		goto bail;
7370ae9a33SPatrick Mooney 	}
7470ae9a33SPatrick Mooney 	res = alloc_memseg(ctx, MSEG_HIGH, UPPER_SZ, "mseg_high");
7570ae9a33SPatrick Mooney 	if (res != 0) {
7670ae9a33SPatrick Mooney 		perror("could not alloc high memseg");
7770ae9a33SPatrick Mooney 		goto bail;
7870ae9a33SPatrick Mooney 	}
7970ae9a33SPatrick Mooney 
8070ae9a33SPatrick Mooney 
8170ae9a33SPatrick Mooney 	res = vm_mmap_memseg(ctx, LOWER_OFF, MSEG_LOW, 0, LOWER_SZ, PROT_ALL);
8270ae9a33SPatrick Mooney 	if (res != 0) {
8370ae9a33SPatrick Mooney 		perror("could not map low memseg");
8470ae9a33SPatrick Mooney 		goto bail;
8570ae9a33SPatrick Mooney 	}
8670ae9a33SPatrick Mooney 	res = vm_mmap_memseg(ctx, UPPER_OFF, MSEG_HIGH, 0, UPPER_SZ, PROT_ALL);
8770ae9a33SPatrick Mooney 	if (res != 0) {
8870ae9a33SPatrick Mooney 		perror("could not map high memseg");
8970ae9a33SPatrick Mooney 		goto bail;
9070ae9a33SPatrick Mooney 	}
9170ae9a33SPatrick Mooney 
9270ae9a33SPatrick Mooney 	guest_mem = mmap(NULL, TOTAL_SZ, PROT_READ | PROT_WRITE, MAP_SHARED,
9370ae9a33SPatrick Mooney 	    fd, 0);
9470ae9a33SPatrick Mooney 	if (guest_mem == MAP_FAILED) {
9570ae9a33SPatrick Mooney 		perror("could not mmap guest memory");
9670ae9a33SPatrick Mooney 		goto bail;
9770ae9a33SPatrick Mooney 	}
9870ae9a33SPatrick Mooney 
9970ae9a33SPatrick Mooney 	/* Fill memory with 0xff */
10070ae9a33SPatrick Mooney 	for (uintptr_t gpa = 0; gpa < TOTAL_SZ; gpa++) {
10170ae9a33SPatrick Mooney 		uint8_t *ptr = guest_mem + gpa;
10270ae9a33SPatrick Mooney 		*ptr = 0xff;
10370ae9a33SPatrick Mooney 	}
10470ae9a33SPatrick Mooney 
10570ae9a33SPatrick Mooney 	/* Unmap the lower memseg */
10670ae9a33SPatrick Mooney 	res = vm_munmap_memseg(ctx, LOWER_OFF, LOWER_SZ);
10770ae9a33SPatrick Mooney 	if (guest_mem == NULL) {
10870ae9a33SPatrick Mooney 		perror("could not unmap lower memseg");
10970ae9a33SPatrick Mooney 		goto bail;
11070ae9a33SPatrick Mooney 	}
11170ae9a33SPatrick Mooney 
11270ae9a33SPatrick Mooney 	/* Confirm upper contents are still correct/accessible */
11370ae9a33SPatrick Mooney 	for (uintptr_t gpa = UPPER_OFF; gpa < UPPER_OFF + UPPER_SZ; gpa++) {
11470ae9a33SPatrick Mooney 		uint8_t *ptr = guest_mem + gpa;
11570ae9a33SPatrick Mooney 		if (*ptr != 0xff) {
11670ae9a33SPatrick Mooney 			(void) printf("invalid mem contents at GPA %lx: %x\n",
11770ae9a33SPatrick Mooney 			    gpa, *ptr);
11870ae9a33SPatrick Mooney 			goto bail;
11970ae9a33SPatrick Mooney 		}
12070ae9a33SPatrick Mooney 		*ptr = 0xee;
12170ae9a33SPatrick Mooney 	}
12270ae9a33SPatrick Mooney 
12370ae9a33SPatrick Mooney 	/*
12470ae9a33SPatrick Mooney 	 * Attempt to access the lower contents, which should result in an
12570ae9a33SPatrick Mooney 	 * expected (and thus handled) SIGSEGV.
12670ae9a33SPatrick Mooney 	 */
12770ae9a33SPatrick Mooney 	struct sigaction sa = {
12870ae9a33SPatrick Mooney 		.sa_handler = sigsegv_handler,
12970ae9a33SPatrick Mooney 	};
13070ae9a33SPatrick Mooney 	struct sigaction old_sa;
13170ae9a33SPatrick Mooney 	res = sigaction(SIGSEGV, &sa, &old_sa);
13270ae9a33SPatrick Mooney 	if (res != 0) {
13370ae9a33SPatrick Mooney 		perror("could not prep signal handling for bad access");
13470ae9a33SPatrick Mooney 		goto bail;
13570ae9a33SPatrick Mooney 	}
13670ae9a33SPatrick Mooney 
13770ae9a33SPatrick Mooney 	if (sigsetjmp(segv_env, 1) == 0) {
13870ae9a33SPatrick Mooney 		volatile uint8_t *ptr = guest_mem;
13970ae9a33SPatrick Mooney 
14070ae9a33SPatrick Mooney 		/*
14170ae9a33SPatrick Mooney 		 * This access to the guest space should fail, since the memseg
14270ae9a33SPatrick Mooney 		 * covering the lower part of the VM space has been unmapped.
14370ae9a33SPatrick Mooney 		 */
14470ae9a33SPatrick Mooney 		uint8_t tmp = *ptr;
14570ae9a33SPatrick Mooney 
14670ae9a33SPatrick Mooney 		(void) printf("access to %p (%x) should have failed\n", tmp);
14770ae9a33SPatrick Mooney 		goto bail;
14870ae9a33SPatrick Mooney 	}
14970ae9a33SPatrick Mooney 
15070ae9a33SPatrick Mooney 	/*
15170ae9a33SPatrick Mooney 	 * Unmap and remap the space so any cached entries are dropped for the
15270ae9a33SPatrick Mooney 	 * portion we expect is still accessible.
15370ae9a33SPatrick Mooney 	 */
15470ae9a33SPatrick Mooney 	res = munmap(guest_mem, TOTAL_SZ);
15570ae9a33SPatrick Mooney 	if (res != 0) {
15670ae9a33SPatrick Mooney 		perror("could not unmap lower memseg");
15770ae9a33SPatrick Mooney 		goto bail;
15870ae9a33SPatrick Mooney 	}
15970ae9a33SPatrick Mooney 	guest_mem = mmap(NULL, TOTAL_SZ, PROT_READ | PROT_WRITE, MAP_SHARED,
16070ae9a33SPatrick Mooney 	    fd, 0);
16170ae9a33SPatrick Mooney 	if (guest_mem == MAP_FAILED) {
16270ae9a33SPatrick Mooney 		perror("could not re-mmap guest memory");
16370ae9a33SPatrick Mooney 		goto bail;
16470ae9a33SPatrick Mooney 	}
16570ae9a33SPatrick Mooney 
16670ae9a33SPatrick Mooney 	/* Check the upper portion for accessibility. */
16770ae9a33SPatrick Mooney 	if (sigsetjmp(segv_env, 1) == 0) {
16870ae9a33SPatrick Mooney 		volatile uint8_t *ptr = guest_mem + UPPER_OFF;
16970ae9a33SPatrick Mooney 
17070ae9a33SPatrick Mooney 		uint8_t tmp = *ptr;
17170ae9a33SPatrick Mooney 		if (tmp != 0xee) {
17270ae9a33SPatrick Mooney 			(void) printf("unexpected value at %p (%x)\n", ptr,
17370ae9a33SPatrick Mooney 			    tmp);
17470ae9a33SPatrick Mooney 			goto bail;
17570ae9a33SPatrick Mooney 		}
17670ae9a33SPatrick Mooney 
17770ae9a33SPatrick Mooney 		res = sigaction(SIGSEGV, &old_sa, NULL);
17870ae9a33SPatrick Mooney 		if (res != 0) {
17970ae9a33SPatrick Mooney 			perror("could not restore SIGSEGV handler");
18070ae9a33SPatrick Mooney 			goto bail;
18170ae9a33SPatrick Mooney 		}
18270ae9a33SPatrick Mooney 	} else {
18370ae9a33SPatrick Mooney 		(void) printf("unexpected fault in upper mapping\n");
18470ae9a33SPatrick Mooney 		goto bail;
18570ae9a33SPatrick Mooney 	}
18670ae9a33SPatrick Mooney 
18770ae9a33SPatrick Mooney 
18870ae9a33SPatrick Mooney 	/* Unmap the upper memseg */
18970ae9a33SPatrick Mooney 	res = vm_munmap_memseg(ctx, UPPER_OFF, UPPER_SZ);
19070ae9a33SPatrick Mooney 	if (guest_mem == NULL) {
19170ae9a33SPatrick Mooney 		perror("could not unmap upper memseg");
19270ae9a33SPatrick Mooney 		goto bail;
19370ae9a33SPatrick Mooney 	}
19470ae9a33SPatrick Mooney 
19570ae9a33SPatrick Mooney 	/* mission accomplished */
196*957246c9SPatrick Mooney 	(void) printf("%s\tPASS\n", suite_name);
19770ae9a33SPatrick Mooney 	vm_destroy(ctx);
19870ae9a33SPatrick Mooney 	return (0);
19970ae9a33SPatrick Mooney 
20070ae9a33SPatrick Mooney bail:
20170ae9a33SPatrick Mooney 	vm_destroy(ctx);
20270ae9a33SPatrick Mooney 	return (1);
20370ae9a33SPatrick Mooney }
204