xref: /illumos-gate/usr/src/test/bhyve-tests/tests/vmm/datarw_vcpu.c (revision 32640292339b07090f10ce34d455f98711077343)
1ad4335f7SPatrick Mooney /*
2ad4335f7SPatrick Mooney  * This file and its contents are supplied under the terms of the
3ad4335f7SPatrick Mooney  * Common Development and Distribution License ("CDDL"), version 1.0.
4ad4335f7SPatrick Mooney  * You may only use this file in accordance with the terms of version
5ad4335f7SPatrick Mooney  * 1.0 of the CDDL.
6ad4335f7SPatrick Mooney  *
7ad4335f7SPatrick Mooney  * A full copy of the text of the CDDL should have accompanied this
8ad4335f7SPatrick Mooney  * source.  A copy of the CDDL is also available via the Internet at
9ad4335f7SPatrick Mooney  * http://www.illumos.org/license/CDDL.
10ad4335f7SPatrick Mooney  */
11ad4335f7SPatrick Mooney 
12ad4335f7SPatrick Mooney /*
13ad4335f7SPatrick Mooney  * Copyright 2023 Oxide Computer Company
14ad4335f7SPatrick Mooney  */
15ad4335f7SPatrick Mooney 
16ad4335f7SPatrick Mooney #include <stdio.h>
17ad4335f7SPatrick Mooney #include <unistd.h>
18ad4335f7SPatrick Mooney #include <stdlib.h>
19ad4335f7SPatrick Mooney #include <fcntl.h>
20ad4335f7SPatrick Mooney #include <libgen.h>
21ad4335f7SPatrick Mooney #include <sys/stat.h>
22ad4335f7SPatrick Mooney #include <errno.h>
23ad4335f7SPatrick Mooney #include <err.h>
24ad4335f7SPatrick Mooney #include <assert.h>
25ad4335f7SPatrick Mooney #include <sys/sysmacros.h>
26ad4335f7SPatrick Mooney #include <stdbool.h>
27ad4335f7SPatrick Mooney 
28ad4335f7SPatrick Mooney #include <sys/vmm.h>
29ad4335f7SPatrick Mooney #include <sys/vmm_dev.h>
30ad4335f7SPatrick Mooney #include <sys/vmm_data.h>
31ad4335f7SPatrick Mooney #include <vmmapi.h>
32ad4335f7SPatrick Mooney 
33ad4335f7SPatrick Mooney #include "common.h"
34ad4335f7SPatrick Mooney 
35ad4335f7SPatrick Mooney static void
should_eq_u64(const char * field_name,uint64_t a,uint64_t b)36ad4335f7SPatrick Mooney should_eq_u64(const char *field_name, uint64_t a, uint64_t b)
37ad4335f7SPatrick Mooney {
38ad4335f7SPatrick Mooney 	if (a != b) {
396fa29843SRobert Mustacchi 		errx(EXIT_FAILURE, "unexpected %s %" PRIu64 " != %" PRIu64,
40ad4335f7SPatrick Mooney 		    field_name, a, b);
41ad4335f7SPatrick Mooney 	}
42ad4335f7SPatrick Mooney }
43ad4335f7SPatrick Mooney 
44ad4335f7SPatrick Mooney static void
check_inval_field(int vmfd,uint32_t ident,uint64_t val)45ad4335f7SPatrick Mooney check_inval_field(int vmfd, uint32_t ident, uint64_t val)
46ad4335f7SPatrick Mooney {
47ad4335f7SPatrick Mooney 	struct vdi_field_entry_v1 field = {
48ad4335f7SPatrick Mooney 		.vfe_ident = ident,
49ad4335f7SPatrick Mooney 		.vfe_value = val,
50ad4335f7SPatrick Mooney 	};
51ad4335f7SPatrick Mooney 	struct vm_data_xfer vdx = {
52ad4335f7SPatrick Mooney 		.vdx_class = VDC_VMM_ARCH,
53ad4335f7SPatrick Mooney 		.vdx_version = 1,
54ad4335f7SPatrick Mooney 		.vdx_len = sizeof (field),
55ad4335f7SPatrick Mooney 		.vdx_data = &field,
56ad4335f7SPatrick Mooney 	};
57ad4335f7SPatrick Mooney 
58ad4335f7SPatrick Mooney 	if (ioctl(vmfd, VM_DATA_WRITE, &vdx) == 0) {
59ad4335f7SPatrick Mooney 		err(EXIT_FAILURE, "vmm_data_write should have failed");
60ad4335f7SPatrick Mooney 	}
61ad4335f7SPatrick Mooney 	int err = errno;
62ad4335f7SPatrick Mooney 	if (err != EINVAL) {
63ad4335f7SPatrick Mooney 		errx(EXIT_FAILURE, "expected EINVAL errno, got %d", err);
64ad4335f7SPatrick Mooney 	}
65ad4335f7SPatrick Mooney }
66ad4335f7SPatrick Mooney 
67ad4335f7SPatrick Mooney static void
do_data_write(int vmfd,struct vm_data_xfer * vdx)68ad4335f7SPatrick Mooney do_data_write(int vmfd, struct vm_data_xfer *vdx)
69ad4335f7SPatrick Mooney {
70ad4335f7SPatrick Mooney 	if (ioctl(vmfd, VM_DATA_WRITE, vdx) != 0) {
71ad4335f7SPatrick Mooney 		err(EXIT_FAILURE, "valid vmm_data_write failed");
72ad4335f7SPatrick Mooney 	}
73ad4335f7SPatrick Mooney 	if (vdx->vdx_result_len != vdx->vdx_len) {
74ad4335f7SPatrick Mooney 		errx(EXIT_FAILURE, "unexpected vdx_result_len %u != %u",
75ad4335f7SPatrick Mooney 		    vdx->vdx_len, vdx->vdx_result_len);
76ad4335f7SPatrick Mooney 	}
77ad4335f7SPatrick Mooney }
78ad4335f7SPatrick Mooney 
79ad4335f7SPatrick Mooney static void
do_data_read(int vmfd,struct vm_data_xfer * vdx)80ad4335f7SPatrick Mooney do_data_read(int vmfd, struct vm_data_xfer *vdx)
81ad4335f7SPatrick Mooney {
82ad4335f7SPatrick Mooney 	if (ioctl(vmfd, VM_DATA_READ, vdx) != 0) {
83ad4335f7SPatrick Mooney 		err(EXIT_FAILURE, "valid vmm_data_read failed");
84ad4335f7SPatrick Mooney 	}
85ad4335f7SPatrick Mooney 	if (vdx->vdx_result_len != vdx->vdx_len) {
86ad4335f7SPatrick Mooney 		errx(EXIT_FAILURE, "unexpected vdx_result_len %u != %u",
87ad4335f7SPatrick Mooney 		    vdx->vdx_len, vdx->vdx_result_len);
88ad4335f7SPatrick Mooney 	}
89ad4335f7SPatrick Mooney }
90ad4335f7SPatrick Mooney 
91ad4335f7SPatrick Mooney int
main(int argc,char * argv[])92ad4335f7SPatrick Mooney main(int argc, char *argv[])
93ad4335f7SPatrick Mooney {
94ad4335f7SPatrick Mooney 	const char *suite_name = basename(argv[0]);
95ad4335f7SPatrick Mooney 	struct vmctx *ctx;
96*32640292SAndy Fiddaman 	struct vcpu *vcpu;
97ad4335f7SPatrick Mooney 
98ad4335f7SPatrick Mooney 	ctx = create_test_vm(suite_name);
99ad4335f7SPatrick Mooney 	if (ctx == NULL) {
100ad4335f7SPatrick Mooney 		errx(EXIT_FAILURE, "could not open test VM");
101ad4335f7SPatrick Mooney 	}
102ad4335f7SPatrick Mooney 
103*32640292SAndy Fiddaman 	if ((vcpu = vm_vcpu_open(ctx, 0)) == NULL) {
104*32640292SAndy Fiddaman 		err(EXIT_FAILURE, "Could not open vcpu0");
105*32640292SAndy Fiddaman 	}
106*32640292SAndy Fiddaman 
107*32640292SAndy Fiddaman 	if (vm_activate_cpu(vcpu) != 0) {
108ad4335f7SPatrick Mooney 		err(EXIT_FAILURE, "could not activate vcpu0");
109ad4335f7SPatrick Mooney 	}
110ad4335f7SPatrick Mooney 
111ad4335f7SPatrick Mooney 	const int vmfd = vm_get_device_fd(ctx);
112ad4335f7SPatrick Mooney 
113ad4335f7SPatrick Mooney 	/* Pause the instance before attempting to manipulate vcpu data */
114ad4335f7SPatrick Mooney 	if (ioctl(vmfd, VM_PAUSE, 0) != 0) {
115ad4335f7SPatrick Mooney 		err(EXIT_FAILURE, "VM_PAUSE failed");
116ad4335f7SPatrick Mooney 	}
117ad4335f7SPatrick Mooney 
118ad4335f7SPatrick Mooney 	struct vdi_field_entry_v1 fields[4] = {
119ad4335f7SPatrick Mooney 		{ .vfe_ident = VAI_PEND_NMI },
120ad4335f7SPatrick Mooney 		{ .vfe_ident = VAI_PEND_EXTINT },
121ad4335f7SPatrick Mooney 		{ .vfe_ident = VAI_PEND_EXCP },
122ad4335f7SPatrick Mooney 		{ .vfe_ident = VAI_PEND_INTINFO },
123ad4335f7SPatrick Mooney 	};
124ad4335f7SPatrick Mooney 
125ad4335f7SPatrick Mooney 	struct vm_data_xfer vdx = {
126ad4335f7SPatrick Mooney 		.vdx_class = VDC_VMM_ARCH,
127ad4335f7SPatrick Mooney 		.vdx_version = 1,
128ad4335f7SPatrick Mooney 		.vdx_flags = VDX_FLAG_READ_COPYIN,
129ad4335f7SPatrick Mooney 		.vdx_len = sizeof (fields),
130ad4335f7SPatrick Mooney 		.vdx_data = &fields,
131ad4335f7SPatrick Mooney 	};
132ad4335f7SPatrick Mooney 
133ad4335f7SPatrick Mooney 	/* Fetch arch state first */
134ad4335f7SPatrick Mooney 	do_data_read(vmfd, &vdx);
135ad4335f7SPatrick Mooney 
136ad4335f7SPatrick Mooney 	/* All of these should be zeroed on a fresh vcpu */
137ad4335f7SPatrick Mooney 	should_eq_u64("VAI_PEND_NMI", fields[0].vfe_value, 0);
138ad4335f7SPatrick Mooney 	should_eq_u64("VAI_PEND_EXTINT", fields[1].vfe_value, 0);
139ad4335f7SPatrick Mooney 	should_eq_u64("VAI_PEND_EXCP", fields[2].vfe_value, 0);
140ad4335f7SPatrick Mooney 	should_eq_u64("VAI_PEND_INTINFO", fields[3].vfe_value, 0);
141ad4335f7SPatrick Mooney 
142ad4335f7SPatrick Mooney 	/* Light up those fields */
143ad4335f7SPatrick Mooney 	fields[0].vfe_value = 1;
144ad4335f7SPatrick Mooney 	fields[1].vfe_value = 1;
145ad4335f7SPatrick Mooney 	fields[2].vfe_value = VM_INTINFO_VALID | VM_INTINFO_HWEXCP | IDT_GP;
146ad4335f7SPatrick Mooney 	fields[3].vfe_value = VM_INTINFO_VALID | VM_INTINFO_SWINTR | 0x80;
147ad4335f7SPatrick Mooney 	do_data_write(vmfd, &vdx);
148ad4335f7SPatrick Mooney 
149ad4335f7SPatrick Mooney 	/*
150ad4335f7SPatrick Mooney 	 * Flip the order (just for funsies) and re-query to check that we still
151ad4335f7SPatrick Mooney 	 * get the expected state.
152ad4335f7SPatrick Mooney 	 */
153ad4335f7SPatrick Mooney 	fields[0].vfe_ident = VAI_PEND_INTINFO;
154ad4335f7SPatrick Mooney 	fields[1].vfe_ident = VAI_PEND_EXCP;
155ad4335f7SPatrick Mooney 	fields[2].vfe_ident = VAI_PEND_EXTINT;
156ad4335f7SPatrick Mooney 	fields[3].vfe_ident = VAI_PEND_NMI;
157ad4335f7SPatrick Mooney 	do_data_read(vmfd, &vdx);
158ad4335f7SPatrick Mooney 
159ad4335f7SPatrick Mooney 	should_eq_u64("VAI_PEND_INTINFO", fields[0].vfe_value,
160ad4335f7SPatrick Mooney 	    VM_INTINFO_VALID | VM_INTINFO_SWINTR | 0x80);
161ad4335f7SPatrick Mooney 	should_eq_u64("VAI_PEND_EXCP", fields[1].vfe_value,
162ad4335f7SPatrick Mooney 	    VM_INTINFO_VALID | VM_INTINFO_HWEXCP | IDT_GP);
163ad4335f7SPatrick Mooney 	should_eq_u64("VAI_PEND_EXTINT", fields[2].vfe_value, 1);
164ad4335f7SPatrick Mooney 	should_eq_u64("VAI_PEND_NMI", fields[3].vfe_value, 1);
165ad4335f7SPatrick Mooney 
166ad4335f7SPatrick Mooney 
167ad4335f7SPatrick Mooney 	/* NMI-typed exception with the wrong vector */
168ad4335f7SPatrick Mooney 	check_inval_field(vmfd, VAI_PEND_INTINFO,
169ad4335f7SPatrick Mooney 	    VM_INTINFO_VALID | VM_INTINFO_NMI | 0xd);
170ad4335f7SPatrick Mooney 
171ad4335f7SPatrick Mooney 	/* Hardware exception with a bad vector (>= 32) */
172ad4335f7SPatrick Mooney 	check_inval_field(vmfd, VAI_PEND_INTINFO,
173ad4335f7SPatrick Mooney 	    VM_INTINFO_VALID | VM_INTINFO_HWEXCP | 0x40);
174ad4335f7SPatrick Mooney 
175ad4335f7SPatrick Mooney 	/* Non-HW event injected into HW exception field */
176ad4335f7SPatrick Mooney 	check_inval_field(vmfd, VAI_PEND_EXCP,
177ad4335f7SPatrick Mooney 	    VM_INTINFO_VALID | VM_INTINFO_SWINTR | 0xd);
178ad4335f7SPatrick Mooney 
179ad4335f7SPatrick Mooney 	/* Zero out the values again */
180ad4335f7SPatrick Mooney 	fields[0].vfe_value = 0;
181ad4335f7SPatrick Mooney 	fields[1].vfe_value = 0;
182ad4335f7SPatrick Mooney 	fields[2].vfe_value = 0;
183ad4335f7SPatrick Mooney 	fields[3].vfe_value = 0;
184ad4335f7SPatrick Mooney 	do_data_write(vmfd, &vdx);
185ad4335f7SPatrick Mooney 
186ad4335f7SPatrick Mooney 	/* And confirm that it took */
187ad4335f7SPatrick Mooney 	do_data_read(vmfd, &vdx);
188ad4335f7SPatrick Mooney 	should_eq_u64("VAI_PEND_INTINFO", fields[0].vfe_value, 0);
189ad4335f7SPatrick Mooney 	should_eq_u64("VAI_PEND_EXCP", fields[1].vfe_value, 0);
190ad4335f7SPatrick Mooney 	should_eq_u64("VAI_PEND_EXTINT", fields[2].vfe_value, 0);
191ad4335f7SPatrick Mooney 	should_eq_u64("VAI_PEND_NMI", fields[3].vfe_value, 0);
192ad4335f7SPatrick Mooney 
193*32640292SAndy Fiddaman 	vm_vcpu_close(vcpu);
194ad4335f7SPatrick Mooney 	vm_destroy(ctx);
195ad4335f7SPatrick Mooney 	(void) printf("%s\tPASS\n", suite_name);
196ad4335f7SPatrick Mooney 	return (EXIT_SUCCESS);
197ad4335f7SPatrick Mooney }
198