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