diff --git a/lib/libvmmapi/Makefile b/lib/libvmmapi/Makefile --- a/lib/libvmmapi/Makefile +++ b/lib/libvmmapi/Makefile @@ -5,8 +5,15 @@ SRCS= vmmapi.c vmmapi_freebsd.c INCS= vmmapi.h +# acpi.c includes acpixf.h which defines some unused parameters in release +# code. Therefore, the option -Wno-unused-parameter is required for compiling. +# Remove it as far as possible. +CWARNFLAGS.vmmapi.c= -Wno-unused-parameter +CWARNFLAGS.vmmapi_freebsd.c= -Wno-unused-parameter + LIBADD= util CFLAGS+= -I${.CURDIR} +CFLAGS+= -I${SRCTOP}/sys .include diff --git a/lib/libvmmapi/vmmapi.h b/lib/libvmmapi/vmmapi.h --- a/lib/libvmmapi/vmmapi.h +++ b/lib/libvmmapi/vmmapi.h @@ -37,6 +37,8 @@ #include +#include + /* * API version for out-of-tree consumers like grub-bhyve for making compile * time decisions. @@ -190,6 +192,11 @@ int vm_get_intinfo(struct vmctx *ctx, int vcpu, uint64_t *i1, uint64_t *i2); int vm_set_intinfo(struct vmctx *ctx, int vcpu, uint64_t exit_intinfo); +/* + * Return current resources (CRS) used by an ACPI device. + */ +int vm_acpi_device_get_crs(struct vmctx *const ctx, const char *const name, ACPI_BUFFER *const crs); + const cap_ioctl_t *vm_get_ioctls(size_t *len); /* diff --git a/lib/libvmmapi/vmmapi.c b/lib/libvmmapi/vmmapi.c --- a/lib/libvmmapi/vmmapi.c +++ b/lib/libvmmapi/vmmapi.c @@ -1062,6 +1062,46 @@ return ioctl(ctx->fd, VM_PPTDEV_DISABLE_MSIX, &ppt); } +int +vm_acpi_device_get_crs(struct vmctx *const ctx, const char *const name, + ACPI_BUFFER *const crs) +{ + if (crs == NULL) { + return (EINVAL); + } + + char path[NAME_MAX]; + snprintf(path, NAME_MAX, "\\_SB.%s", name); + + /* get required size to hold CRS data */ + struct vm_acpi_device_info acpi_device_info = { + .type = VM_ACPI_DEVICE_INFO_CRS, + .path = path, + }; + int error = ioctl(ctx->fd, VM_GET_ACPI_DEVICE_INFO, &acpi_device_info); + if (error) { + return (error); + } + + /* allocate buffer for CRS */ + crs->Pointer = malloc(acpi_device_info.buffer_length); + if (crs->Pointer == NULL) { + return (ENOMEM); + } + crs->Length = acpi_device_info.buffer_length; + + /* get CRS data */ + acpi_device_info.buffer = crs->Pointer; + acpi_device_info.buffer_length = crs->Length; + error = ioctl(ctx->fd, VM_GET_ACPI_DEVICE_INFO, &acpi_device_info); + if (error) { + free(crs->Pointer); + crs->Length = 0; + } + + return (error); +} + uint64_t * vm_get_stats(struct vmctx *ctx, int vcpu, struct timeval *ret_tv, int *ret_entries) @@ -1694,7 +1734,8 @@ VM_ACTIVATE_CPU, VM_GET_CPUS, VM_SUSPEND_CPU, VM_RESUME_CPU, VM_SET_INTINFO, VM_GET_INTINFO, VM_RTC_WRITE, VM_RTC_READ, VM_RTC_SETTIME, VM_RTC_GETTIME, - VM_RESTART_INSTRUCTION, VM_SET_TOPOLOGY, VM_GET_TOPOLOGY }; + VM_RESTART_INSTRUCTION, VM_SET_TOPOLOGY, VM_GET_TOPOLOGY, + VM_GET_ACPI_DEVICE_INFO }; if (len == NULL) { cmds = malloc(sizeof(vm_ioctl_cmds)); diff --git a/sys/amd64/include/vmm.h b/sys/amd64/include/vmm.h --- a/sys/amd64/include/vmm.h +++ b/sys/amd64/include/vmm.h @@ -741,6 +741,10 @@ } u; }; +enum vm_acpi_device_info_type { + VM_ACPI_DEVICE_INFO_CRS, +}; + /* APIs to inject faults into the guest */ void vm_inject_fault(void *vm, int vcpuid, int vector, int errcode_valid, int errcode); diff --git a/sys/amd64/include/vmm_dev.h b/sys/amd64/include/vmm_dev.h --- a/sys/amd64/include/vmm_dev.h +++ b/sys/amd64/include/vmm_dev.h @@ -256,6 +256,13 @@ }; _Static_assert(sizeof(struct vm_readwrite_kernemu_device) == 24, "ABI"); +struct vm_acpi_device_info { + const char *path; + void *buffer; + size_t buffer_length; + enum vm_acpi_device_info_type type; +}; + enum { /* general routines */ IOCNUM_ABIVERS = 0, @@ -341,6 +348,9 @@ IOCNUM_RTC_SETTIME = 102, IOCNUM_RTC_GETTIME = 103, + /* ACPI */ + IOCNUM_GET_ACPI_DEVICE_INFO = 110, + /* checkpoint */ IOCNUM_SNAPSHOT_REQ = 113, @@ -471,6 +481,8 @@ _IOR('v', IOCNUM_RTC_GETTIME, struct vm_rtc_time) #define VM_RESTART_INSTRUCTION \ _IOW('v', IOCNUM_RESTART_INSTRUCTION, int) +#define VM_GET_ACPI_DEVICE_INFO \ + _IOWR('v', IOCNUM_GET_ACPI_DEVICE_INFO, struct vm_acpi_device_info) #define VM_SNAPSHOT_REQ \ _IOWR('v', IOCNUM_SNAPSHOT_REQ, struct vm_snapshot_meta) #define VM_RESTORE_TIME \ diff --git a/sys/amd64/vmm/io/acpi.h b/sys/amd64/vmm/io/acpi.h new file mode 100644 --- /dev/null +++ b/sys/amd64/vmm/io/acpi.h @@ -0,0 +1,17 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG + * Author: Corvin Köhne + */ + +#pragma once + +#include +#include + +/* + * Executes the CRS (Current Resources) method of an ACPI device. + */ +int vmm_acpi_get_crs(const char *const device_path, void *const buffer, + size_t *const buffer_length); diff --git a/sys/amd64/vmm/io/acpi.c b/sys/amd64/vmm/io/acpi.c new file mode 100644 --- /dev/null +++ b/sys/amd64/vmm/io/acpi.c @@ -0,0 +1,60 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG + * Author: Corvin Köhne + */ + +#include + +#include +#include +#include +#include + +#include +#include + +#include "acpi.h" + +int +vmm_acpi_get_crs(const char *const device_path, void *const buffer, + size_t *const buffer_length) +{ + if (device_path == NULL || buffer_length == NULL) { + return (EINVAL); + } + + /* get device handle */ + ACPI_HANDLE acpi_device; + ACPI_STRING const path = strdup(device_path, M_TEMP); + ACPI_STATUS status = AcpiGetHandle(NULL, path, &acpi_device); + if (!ACPI_SUCCESS(status)) { + printf("%s: failed to get handle for ACPI device \"%s\" (%x)\n", + __func__, device_path, status); + return (ENOENT); + } + + /* get current resources */ + ACPI_BUFFER resources = { ACPI_ALLOCATE_BUFFER }; + status = AcpiGetCurrentResources(acpi_device, &resources); + if (!ACPI_SUCCESS(status)) { + printf( + "%s: failed to get current resources of ACPI device \"%s\" (%x)\n", + __func__, device_path, status); + return (ENODEV); + } + + /* copy data to user space buffer */ + int error = 0; + if (buffer == NULL) { + *buffer_length = resources.Length; + } else { + size_t bytes_to_write = MIN(*buffer_length, resources.Length); + error = copyout(resources.Pointer, buffer, bytes_to_write); + } + + AcpiOsFree(resources.Pointer); + + return (error); +} diff --git a/sys/amd64/vmm/vmm_dev.c b/sys/amd64/vmm/vmm_dev.c --- a/sys/amd64/vmm/vmm_dev.c +++ b/sys/amd64/vmm/vmm_dev.c @@ -63,6 +63,7 @@ #include "vmm_lapic.h" #include "vmm_stat.h" #include "vmm_mem.h" +#include "io/acpi.h" #include "io/ppt.h" #include "io/vatpic.h" #include "io/vioapic.h" @@ -390,6 +391,8 @@ struct vm_memmap *mm; struct vm_munmap *mu; struct vm_cpu_topology *topology; + struct vm_acpi_device_info *acpi_device_info; + char acpi_device_path[NAME_MAX]; struct vm_readwrite_kernemu_device *kernemu; uint64_t *regvals; int *regnums; @@ -870,6 +873,23 @@ &topology->threads, &topology->maxcpus); error = 0; break; + case VM_GET_ACPI_DEVICE_INFO: + acpi_device_info = (struct vm_acpi_device_info *)data; + /* copy device name into kernel space */ + error = copyinstr(acpi_device_info->path, acpi_device_path, + sizeof(acpi_device_path), NULL); + if (error) { + break; + } + /* handle request */ + switch (acpi_device_info->type) { + case VM_ACPI_DEVICE_INFO_CRS: + error = vmm_acpi_get_crs(acpi_device_path, + acpi_device_info->buffer, + &acpi_device_info->buffer_length); + break; + } + break; #ifdef BHYVE_SNAPSHOT case VM_SNAPSHOT_REQ: snapshot_meta = (struct vm_snapshot_meta *)data; diff --git a/sys/modules/vmm/Makefile b/sys/modules/vmm/Makefile --- a/sys/modules/vmm/Makefile +++ b/sys/modules/vmm/Makefile @@ -29,7 +29,8 @@ x86.c .PATH: ${SRCTOP}/sys/amd64/vmm/io -SRCS+= iommu.c \ +SRCS+= acpi.c \ + iommu.c \ ppt.c \ vatpic.c \ vatpit.c \ diff --git a/usr.sbin/bhyvectl/Makefile b/usr.sbin/bhyvectl/Makefile --- a/usr.sbin/bhyvectl/Makefile +++ b/usr.sbin/bhyvectl/Makefile @@ -14,6 +14,7 @@ WARNS?= 3 +CFLAGS+= -I${SRCTOP}/sys CFLAGS+= -I${SRCTOP}/sys/amd64/vmm .if ${MK_BHYVE_SNAPSHOT} != "no" diff --git a/usr.sbin/bhyveload/Makefile b/usr.sbin/bhyveload/Makefile --- a/usr.sbin/bhyveload/Makefile +++ b/usr.sbin/bhyveload/Makefile @@ -10,5 +10,6 @@ WARNS?= 3 CFLAGS+=-I${SRCTOP}/stand/userboot +CFLAGS+= -I${SRCTOP}/sys .include