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