xref: /illumos-gate/usr/src/test/bhyve-tests/tests/vmm/maxcpu.c (revision e00bdde3c6d406f40f53f3025defadc22f7ec31a)
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 2024 Oxide Computer Company
14  */
15 
16 #include <stdio.h>
17 #include <unistd.h>
18 #include <stdlib.h>
19 #include <fcntl.h>
20 #include <libgen.h>
21 #include <sys/stat.h>
22 #include <errno.h>
23 #include <err.h>
24 #include <assert.h>
25 #include <sys/sysmacros.h>
26 #include <stdbool.h>
27 
28 #include <sys/vmm.h>
29 #include <sys/vmm_dev.h>
30 #include <sys/vmm_data.h>
31 #include <vmmapi.h>
32 
33 #include "common.h"
34 
35 int
36 main(int argc, char *argv[])
37 {
38 	const char *suite_name = basename(argv[0]);
39 	struct vmctx *ctx;
40 
41 	ctx = create_test_vm(suite_name);
42 	if (ctx == NULL) {
43 		errx(EXIT_FAILURE, "could not open test VM");
44 	}
45 
46 	/* Query VM_MAXCPU equivalent via VM topology */
47 	uint16_t sockets, cores, threads, maxcpus;
48 	if (vm_get_topology(ctx, &sockets, &cores, &threads, &maxcpus) != 0) {
49 		err(EXIT_FAILURE,
50 		    "could not query maxcpu via vm_get_topology()");
51 	}
52 
53 	for (int i = 0; i < maxcpus; i++) {
54 		struct vcpu *vcpu;
55 		uint64_t val = 0;
56 
57 		if ((vcpu = vm_vcpu_open(ctx, i)) == NULL) {
58 			err(EXIT_FAILURE, "could not open vcpu %d", i);
59 		}
60 
61 		/* Check that all valid vCPUs can be activated... */
62 		if (vm_activate_cpu(vcpu) != 0) {
63 			err(EXIT_FAILURE, "could not activate vcpu %d", i);
64 		}
65 
66 		/* and that we can do something basic (like read a register) */
67 		if (vm_get_register(vcpu, VM_REG_GUEST_RAX, &val) != 0) {
68 			err(EXIT_FAILURE, "could not read %%rax on vcpu %d", i);
69 		}
70 
71 		vm_vcpu_close(vcpu);
72 	}
73 
74 	/* Check some bogus inputs as well */
75 	const int bad_inputs[] = {-1, maxcpus, maxcpus + 1};
76 	for (uint_t i = 0; i < ARRAY_SIZE(bad_inputs); i++) {
77 		const int vcpuid = bad_inputs[i];
78 
79 		/*
80 		 * There is no logic (currently) in vm_vcpu_open() checking
81 		 * vcpuid for validity, so we must use a further operation to
82 		 * perform a useful test.
83 		 */
84 		struct vcpu *vcpu = vm_vcpu_open(ctx, vcpuid);
85 		if (vcpu == NULL) {
86 			errx(EXIT_FAILURE,
87 			    "unexpected failure from vm_vcpu_open()");
88 		}
89 
90 		if (vm_activate_cpu(vcpu) == 0) {
91 			err(EXIT_FAILURE,
92 			    "unexpected VM_ACTIVATE success for bad vcpuid %d",
93 			    vcpuid);
94 		}
95 		vm_vcpu_close(vcpu);
96 	}
97 
98 	vm_destroy(ctx);
99 	(void) printf("%s\tPASS\n", suite_name);
100 	return (EXIT_SUCCESS);
101 }
102