1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2022 Oxide Computer Company
14  */
15 
16 
17 #include <stdio.h>
18 #include <unistd.h>
19 #include <stropts.h>
20 #include <strings.h>
21 #include <signal.h>
22 #include <setjmp.h>
23 #include <libgen.h>
24 
25 #include <sys/vmm.h>
26 #include <sys/vmm_dev.h>
27 #include <sys/mman.h>
28 #include <vmmapi.h>
29 
30 #include "common.h"
31 
32 #define	TEST_SEGID	0
33 #define	PAGE_CNT	1024
34 #define	PAGE_SZ		4096
35 #define	SEG_SZ	(PAGE_CNT * PAGE_SZ)
36 
37 int
main(int argc,char * argv[])38 main(int argc, char *argv[])
39 {
40 	struct vmctx *ctx;
41 	int res, fd;
42 	void *seg_obj, *guest_mem;
43 	const char *suite_name = basename(argv[0]);
44 
45 	ctx = create_test_vm(suite_name);
46 	if (ctx == NULL) {
47 		perror("could open test VM");
48 		return (1);
49 	}
50 	fd = vm_get_device_fd(ctx);
51 
52 	res = alloc_memseg(ctx, TEST_SEGID, SEG_SZ, "test_seg");
53 	if (res != 0) {
54 		perror("could not alloc memseg");
55 		goto bail;
56 	}
57 	off_t seg_obj_off;
58 	res = vm_get_devmem_offset(ctx, TEST_SEGID, &seg_obj_off);
59 	if (res != 0) {
60 		perror("could not find mapping offset for seg object");
61 		goto bail;
62 	}
63 
64 	seg_obj = mmap(NULL, SEG_SZ, PROT_READ | PROT_WRITE, MAP_SHARED,
65 	    fd, seg_obj_off);
66 	if (seg_obj == MAP_FAILED) {
67 		perror("could not mmap seg object");
68 		goto bail;
69 	}
70 
71 	/* populate with initial data */
72 	for (uint_t i = 0; i < PAGE_CNT; i++) {
73 		uint64_t *p = (uint64_t *)((uintptr_t)seg_obj + i * PAGE_SZ);
74 
75 		*p = i;
76 	}
77 
78 	res = vm_mmap_memseg(ctx, 0, TEST_SEGID, 0, SEG_SZ, PROT_ALL);
79 	if (res != 0) {
80 		perror("could not map memseg into vmspace");
81 		goto bail;
82 	}
83 	guest_mem = mmap(NULL, SEG_SZ, PROT_READ | PROT_WRITE, MAP_SHARED,
84 	    fd, 0);
85 	if (seg_obj == MAP_FAILED) {
86 		perror("could not mmap vmspace");
87 		goto bail;
88 	}
89 
90 	/* check data and access though vmspace */
91 	for (uint_t i = 0; i < PAGE_CNT; i++) {
92 		const uint64_t off = i * PAGE_SZ;
93 		uint64_t *p = (uint64_t *)((uintptr_t)guest_mem + off);
94 
95 		const uint64_t val = *p;
96 		if (val != i) {
97 			(void) printf("%lu != %u at gpa:%lx\n", val, i, off);
98 			goto bail;
99 		}
100 
101 		/* leave a change behind */
102 		*p = val * 2;
103 	}
104 
105 	/* check changes made through vmspace */
106 	for (uint_t i = 0; i < PAGE_CNT; i++) {
107 		const uint64_t off = i * PAGE_SZ;
108 		uint64_t *p = (uint64_t *)((uintptr_t)seg_obj + off);
109 
110 		const uint_t expected = i * 2;
111 		const uint64_t val = *p;
112 		if (val != expected) {
113 			(void) printf("%lu != %u at gpa:%lx\n", val, expected,
114 			    off);
115 			goto bail;
116 		}
117 	}
118 
119 	/* unmap access mappings */
120 	res = munmap(guest_mem, SEG_SZ);
121 	if (res != 0) {
122 		perror("could not munmap vmspace");
123 		goto bail;
124 	}
125 	res = munmap(seg_obj, SEG_SZ);
126 	if (res != 0) {
127 		perror("could not munmap seg object");
128 		goto bail;
129 	}
130 
131 	/* mission accomplished */
132 	vm_destroy(ctx);
133 	(void) printf("%s\tPASS\n", suite_name);
134 	return (0);
135 
136 bail:
137 	vm_destroy(ctx);
138 	return (1);
139 }
140