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 enum test_segs {
33 	SEG_LOWMEM = 0,
34 	SEG_BOOTROM = 1,
35 };
36 #define	PAGE_CNT	2
37 #define	PAGE_SZ		4096
38 #define	SEG_SZ		(PAGE_CNT * PAGE_SZ)
39 #define	WHOLE_SZ	(SEG_SZ * 2)
40 
41 #define	TESTVAL_LOWMEM	0x1000ffff
42 #define	TESTVAL_BOOTROM	0x2000eeee
43 
44 int
main(int argc,char * argv[])45 main(int argc, char *argv[])
46 {
47 	struct vmctx *ctx;
48 	int res, fd;
49 	const char *suite_name = basename(argv[0]);
50 
51 	ctx = create_test_vm(suite_name);
52 	if (ctx == NULL) {
53 		perror("could open test VM");
54 		return (1);
55 	}
56 	fd = vm_get_device_fd(ctx);
57 
58 	res = alloc_memseg(ctx, SEG_LOWMEM, SEG_SZ, "");
59 	if (res != 0) {
60 		perror("could not alloc lowmem seg");
61 		goto bail;
62 	}
63 	res = alloc_memseg(ctx, SEG_BOOTROM, SEG_SZ, "bootrom");
64 	if (res != 0) {
65 		perror("could not alloc bootrom seg");
66 		goto bail;
67 	}
68 
69 	res = vm_mmap_memseg(ctx, 0, SEG_LOWMEM, 0, SEG_SZ, PROT_ALL);
70 	if (res != 0) {
71 		perror("could not map lowmem into vmspace");
72 		goto bail;
73 	}
74 	res = vm_mmap_memseg(ctx, SEG_SZ, SEG_BOOTROM, 0, SEG_SZ, PROT_READ);
75 	if (res != 0) {
76 		perror("could not map bootrom into vmspace");
77 		goto bail;
78 	}
79 
80 	void *guest_mem;
81 	guest_mem = mmap(NULL, WHOLE_SZ, PROT_READ, MAP_SHARED, fd, 0);
82 	if (guest_mem == MAP_FAILED) {
83 		perror("could not mmap guest-physical memory");
84 		goto bail;
85 	}
86 
87 	void *direct_lowmem, *direct_bootrom;
88 	off_t seg_obj_off;
89 
90 	res = vm_get_devmem_offset(ctx, SEG_LOWMEM, &seg_obj_off);
91 	if (res != 0) {
92 		perror("could not find mapping offset for lowmem seg");
93 		goto bail;
94 	}
95 	direct_lowmem = mmap(NULL, SEG_SZ, PROT_READ | PROT_WRITE, MAP_SHARED,
96 	    fd, seg_obj_off);
97 	if (direct_lowmem == MAP_FAILED) {
98 		perror("could not mmap lowmem directly");
99 		goto bail;
100 	}
101 
102 	res = vm_get_devmem_offset(ctx, SEG_BOOTROM, &seg_obj_off);
103 	if (res != 0) {
104 		perror("could not find mapping offset for lowmem seg");
105 		goto bail;
106 	}
107 	direct_bootrom = mmap(NULL, SEG_SZ, PROT_READ | PROT_WRITE, MAP_SHARED,
108 	    fd, seg_obj_off);
109 	if (direct_bootrom == MAP_FAILED) {
110 		perror("could not mmap bootrom directly");
111 		goto bail;
112 	}
113 
114 	uint32_t *datap;
115 
116 	datap = direct_lowmem;
117 	*datap = TESTVAL_LOWMEM;
118 	datap = direct_bootrom;
119 	*datap = TESTVAL_BOOTROM;
120 
121 	/* check that data written though direct access is as expected */
122 	datap = guest_mem;
123 	if (*datap != TESTVAL_LOWMEM) {
124 		(void) fprintf(stderr, "unexpected data in lowmem %x != %x\n",
125 		    *datap, TESTVAL_LOWMEM);
126 		goto bail;
127 	}
128 	datap = (guest_mem + SEG_SZ);
129 	if (*datap != TESTVAL_BOOTROM) {
130 		(void) fprintf(stderr, "unexpected data in bootrom %x != %x\n",
131 		    *datap, TESTVAL_BOOTROM);
132 		goto bail;
133 	}
134 
135 	/* unmap access mappings */
136 	res = munmap(guest_mem, WHOLE_SZ);
137 	if (res != 0) {
138 		perror("could not munmap vmspace");
139 		goto bail;
140 	}
141 	res = munmap(direct_lowmem, SEG_SZ);
142 	if (res != 0) {
143 		perror("could not munmap lowmem object");
144 		goto bail;
145 	}
146 	res = munmap(direct_bootrom, SEG_SZ);
147 	if (res != 0) {
148 		perror("could not munmap bootrom object");
149 		goto bail;
150 	}
151 
152 	/* mission accomplished */
153 	vm_destroy(ctx);
154 	(void) printf("%s\tPASS\n", suite_name);
155 	return (0);
156 
157 bail:
158 	vm_destroy(ctx);
159 	return (1);
160 }
161