170ae9a33SPatrick Mooney /*
270ae9a33SPatrick Mooney  * This file and its contents are supplied under the terms of the
370ae9a33SPatrick Mooney  * Common Development and Distribution License ("CDDL"), version 1.0.
470ae9a33SPatrick Mooney  * You may only use this file in accordance with the terms of version
570ae9a33SPatrick Mooney  * 1.0 of the CDDL.
670ae9a33SPatrick Mooney  *
770ae9a33SPatrick Mooney  * A full copy of the text of the CDDL should have accompanied this
870ae9a33SPatrick Mooney  * source.  A copy of the CDDL is also available via the Internet at
970ae9a33SPatrick Mooney  * http://www.illumos.org/license/CDDL.
1070ae9a33SPatrick Mooney  */
1170ae9a33SPatrick Mooney 
1270ae9a33SPatrick Mooney /*
13*717646f7SJordan Paige Hendricks  * Copyright 2023 Oxide Computer Company
1470ae9a33SPatrick Mooney  */
1570ae9a33SPatrick Mooney 
1670ae9a33SPatrick Mooney #include <stdio.h>
1770ae9a33SPatrick Mooney #include <unistd.h>
1870ae9a33SPatrick Mooney #include <strings.h>
19aa39f6d0SPatrick Mooney #include <fcntl.h>
2042640e49SPatrick Mooney #include <errno.h>
2170ae9a33SPatrick Mooney 
2270ae9a33SPatrick Mooney #include <sys/types.h>
2370ae9a33SPatrick Mooney #include <sys/vmm.h>
2470ae9a33SPatrick Mooney #include <sys/vmm_dev.h>
2570ae9a33SPatrick Mooney #include <vmmapi.h>
2670ae9a33SPatrick Mooney 
27aa39f6d0SPatrick Mooney 
28aa39f6d0SPatrick Mooney /*
29aa39f6d0SPatrick Mooney  * Generate name for test VM based on the name of the test suite (and the pid).
30aa39f6d0SPatrick Mooney  */
31aa39f6d0SPatrick Mooney void
name_test_vm(const char * test_suite_name,char * outp)32aa39f6d0SPatrick Mooney name_test_vm(const char *test_suite_name, char *outp)
33aa39f6d0SPatrick Mooney {
34aa39f6d0SPatrick Mooney 	(void) snprintf(outp, VM_MAX_NAMELEN, "bhyve-test-%s-%d",
35aa39f6d0SPatrick Mooney 	    test_suite_name, getpid());
36aa39f6d0SPatrick Mooney }
37aa39f6d0SPatrick Mooney 
38aa39f6d0SPatrick Mooney /*
39aa39f6d0SPatrick Mooney  * Create a test VM. The name of the test suite will be used to derive the name
40aa39f6d0SPatrick Mooney  * of the instance.
41aa39f6d0SPatrick Mooney  */
4270ae9a33SPatrick Mooney struct vmctx *
create_test_vm(const char * test_suite_name)43957246c9SPatrick Mooney create_test_vm(const char *test_suite_name)
4470ae9a33SPatrick Mooney {
4570ae9a33SPatrick Mooney 	char name[VM_MAX_NAMELEN];
4670ae9a33SPatrick Mooney 	int res;
4770ae9a33SPatrick Mooney 
48aa39f6d0SPatrick Mooney 	name_test_vm(test_suite_name, name);
4970ae9a33SPatrick Mooney 
5070ae9a33SPatrick Mooney 	res = vm_create(name, 0);
5170ae9a33SPatrick Mooney 	if (res != 0) {
5270ae9a33SPatrick Mooney 		return (NULL);
5370ae9a33SPatrick Mooney 	}
5470ae9a33SPatrick Mooney 
5570ae9a33SPatrick Mooney 	return (vm_open(name));
5670ae9a33SPatrick Mooney }
5770ae9a33SPatrick Mooney 
58aa39f6d0SPatrick Mooney /*
59aa39f6d0SPatrick Mooney  * Given a segment ID, length, and name, allocate a memseg in the given VM.
60aa39f6d0SPatrick Mooney  */
6170ae9a33SPatrick Mooney int
alloc_memseg(struct vmctx * ctx,int segid,size_t len,const char * name)6270ae9a33SPatrick Mooney alloc_memseg(struct vmctx *ctx, int segid, size_t len, const char *name)
6370ae9a33SPatrick Mooney {
6470ae9a33SPatrick Mooney 	struct vm_memseg memseg = {
6570ae9a33SPatrick Mooney 		.segid = segid,
6670ae9a33SPatrick Mooney 		.len = len,
6770ae9a33SPatrick Mooney 	};
6870ae9a33SPatrick Mooney 	(void) strlcpy(memseg.name, name, sizeof (memseg.name));
6970ae9a33SPatrick Mooney 
7070ae9a33SPatrick Mooney 	int fd = vm_get_device_fd(ctx);
7170ae9a33SPatrick Mooney 
7270ae9a33SPatrick Mooney 	return (ioctl(fd, VM_ALLOC_MEMSEG, &memseg));
7370ae9a33SPatrick Mooney }
74aa39f6d0SPatrick Mooney 
75aa39f6d0SPatrick Mooney /*
76aa39f6d0SPatrick Mooney  * Open the vmm_drv_test device.
77aa39f6d0SPatrick Mooney  */
78aa39f6d0SPatrick Mooney int
open_drv_test(void)79aa39f6d0SPatrick Mooney open_drv_test(void)
80aa39f6d0SPatrick Mooney {
81aa39f6d0SPatrick Mooney 	return (open("/dev/vmm_drv_test", O_RDWR));
82aa39f6d0SPatrick Mooney }
8342640e49SPatrick Mooney 
8442640e49SPatrick Mooney 
8542640e49SPatrick Mooney /*
8642640e49SPatrick Mooney  * Test if VMM instance exists (and is not being destroyed).
8742640e49SPatrick Mooney  */
8842640e49SPatrick Mooney bool
check_instance_usable(const char * suite_name)8942640e49SPatrick Mooney check_instance_usable(const char *suite_name)
9042640e49SPatrick Mooney {
9142640e49SPatrick Mooney 	char vm_name[VM_MAX_NAMELEN];
9242640e49SPatrick Mooney 	char vm_path[MAXPATHLEN];
9342640e49SPatrick Mooney 
9442640e49SPatrick Mooney 	name_test_vm(suite_name, vm_name);
9542640e49SPatrick Mooney 	(void) snprintf(vm_path, sizeof (vm_path), "/dev/vmm/%s", vm_name);
9642640e49SPatrick Mooney 
9742640e49SPatrick Mooney 	int fd = open(vm_path, O_RDWR, 0);
9842640e49SPatrick Mooney 	if (fd < 0) {
9942640e49SPatrick Mooney 		return (false);
10042640e49SPatrick Mooney 	}
10142640e49SPatrick Mooney 
10242640e49SPatrick Mooney 	const int destroy_pending = ioctl(fd, VM_DESTROY_PENDING, 0);
10342640e49SPatrick Mooney 	(void) close(fd);
10442640e49SPatrick Mooney 
10542640e49SPatrick Mooney 	return (destroy_pending == 0);
10642640e49SPatrick Mooney }
10742640e49SPatrick Mooney 
10842640e49SPatrick Mooney /*
10942640e49SPatrick Mooney  * Does an instance exist in /dev/vmm?  (No check for in-progress destroy)
11042640e49SPatrick Mooney  */
11142640e49SPatrick Mooney bool
check_instance_exists(const char * suite_name)11242640e49SPatrick Mooney check_instance_exists(const char *suite_name)
11342640e49SPatrick Mooney {
11442640e49SPatrick Mooney 	char vm_name[VM_MAX_NAMELEN];
11542640e49SPatrick Mooney 	char vm_path[MAXPATHLEN];
11642640e49SPatrick Mooney 
11742640e49SPatrick Mooney 	name_test_vm(suite_name, vm_name);
11842640e49SPatrick Mooney 	(void) snprintf(vm_path, sizeof (vm_path), "/dev/vmm/%s", vm_name);
11942640e49SPatrick Mooney 
12042640e49SPatrick Mooney 	return (access(vm_path, F_OK) == 0);
12142640e49SPatrick Mooney }
12242640e49SPatrick Mooney 
12342640e49SPatrick Mooney 
12442640e49SPatrick Mooney /*
12542640e49SPatrick Mooney  * Destroy a VMM instance via the vmmctl device.
12642640e49SPatrick Mooney  */
12742640e49SPatrick Mooney int
destroy_instance(const char * suite_name)12842640e49SPatrick Mooney destroy_instance(const char *suite_name)
12942640e49SPatrick Mooney {
13042640e49SPatrick Mooney 	int ctl_fd = open(VMM_CTL_DEV, O_EXCL | O_RDWR);
13142640e49SPatrick Mooney 	if (ctl_fd < 0) {
13242640e49SPatrick Mooney 		return (-1);
13342640e49SPatrick Mooney 	}
13442640e49SPatrick Mooney 
13542640e49SPatrick Mooney 	struct vm_destroy_req req;
13642640e49SPatrick Mooney 	name_test_vm(suite_name, req.name);
13742640e49SPatrick Mooney 
13842640e49SPatrick Mooney 	if (ioctl(ctl_fd, VMM_DESTROY_VM, &req) != 0) {
13942640e49SPatrick Mooney 		/* Preserve the destroy error across the close() */
14042640e49SPatrick Mooney 		int err = errno;
14142640e49SPatrick Mooney 		(void) close(ctl_fd);
14242640e49SPatrick Mooney 		errno = err;
14342640e49SPatrick Mooney 		return (-1);
14442640e49SPatrick Mooney 	} else {
14542640e49SPatrick Mooney 		(void) close(ctl_fd);
14642640e49SPatrick Mooney 		return (0);
14742640e49SPatrick Mooney 	}
14842640e49SPatrick Mooney }
149*717646f7SJordan Paige Hendricks 
150*717646f7SJordan Paige Hendricks /*
151*717646f7SJordan Paige Hendricks  * Returns true if running on AMD
152*717646f7SJordan Paige Hendricks  */
153*717646f7SJordan Paige Hendricks bool
cpu_vendor_amd(void)154*717646f7SJordan Paige Hendricks cpu_vendor_amd(void)
155*717646f7SJordan Paige Hendricks {
156*717646f7SJordan Paige Hendricks 	uint_t regs[4];
157*717646f7SJordan Paige Hendricks 	char cpu_vendor[13];
158*717646f7SJordan Paige Hendricks 
159*717646f7SJordan Paige Hendricks 	do_cpuid(0, regs);
160*717646f7SJordan Paige Hendricks 	((uint_t *)&cpu_vendor)[0] = regs[1];
161*717646f7SJordan Paige Hendricks 	((uint_t *)&cpu_vendor)[1] = regs[3];
162*717646f7SJordan Paige Hendricks 	((uint_t *)&cpu_vendor)[2] = regs[2];
163*717646f7SJordan Paige Hendricks 	cpu_vendor[12] = '\0';
164*717646f7SJordan Paige Hendricks 
165*717646f7SJordan Paige Hendricks 	return (strcmp(cpu_vendor, "AuthenticAMD") == 0 ||
166*717646f7SJordan Paige Hendricks 	    strcmp(cpu_vendor, "HygonGenuine") == 0);
167*717646f7SJordan Paige Hendricks }
168