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