freebsd-dev/usr.sbin/bhyve/acpi_device.c
Warner Losh 4d846d260e spdx: The BSD-2-Clause-FreeBSD identifier is obsolete, drop -FreeBSD
The SPDX folks have obsoleted the BSD-2-Clause-FreeBSD identifier. Catch
up to that fact and revert to their recommended match of BSD-2-Clause.

Discussed with:		pfg
MFC After:		3 days
Sponsored by:		Netflix
2023-05-12 10:44:03 -06:00

214 lines
4.6 KiB
C

/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
* Author: Corvin Köhne <c.koehne@beckhoff.com>
*/
#include <sys/param.h>
#include <sys/queue.h>
#include <machine/vmm.h>
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <vmmapi.h>
#include "acpi.h"
#include "acpi_device.h"
#include "basl.h"
/**
* List entry to enumerate all resources used by an ACPI device.
*
* @param chain Used to chain multiple elements together.
* @param type Type of the ACPI resource.
* @param data Data of the ACPI resource.
*/
struct acpi_resource_list_entry {
SLIST_ENTRY(acpi_resource_list_entry) chain;
UINT32 type;
ACPI_RESOURCE_DATA data;
};
/**
* Holds information about an ACPI device.
*
* @param vm_ctx VM context the ACPI device was created in.
* @param softc A pointer to the software context of the ACPI device.
* @param emul Device emulation struct. It contains some information like the
name of the ACPI device and some device specific functions.
* @param crs Current resources used by the ACPI device.
*/
struct acpi_device {
struct vmctx *vm_ctx;
void *softc;
const struct acpi_device_emul *emul;
SLIST_HEAD(acpi_resource_list, acpi_resource_list_entry) crs;
};
int
acpi_device_create(struct acpi_device **const new_dev, void *const softc,
struct vmctx *const vm_ctx, const struct acpi_device_emul *const emul)
{
assert(new_dev != NULL);
assert(vm_ctx != NULL);
assert(emul != NULL);
struct acpi_device *const dev = calloc(1, sizeof(*dev));
if (dev == NULL) {
return (ENOMEM);
}
dev->vm_ctx = vm_ctx;
dev->softc = softc;
dev->emul = emul;
SLIST_INIT(&dev->crs);
const int error = acpi_tables_add_device(dev);
if (error) {
acpi_device_destroy(dev);
return (error);
}
*new_dev = dev;
return (0);
}
void
acpi_device_destroy(struct acpi_device *const dev)
{
if (dev == NULL) {
return;
}
struct acpi_resource_list_entry *res;
while (!SLIST_EMPTY(&dev->crs)) {
res = SLIST_FIRST(&dev->crs);
SLIST_REMOVE_HEAD(&dev->crs, chain);
free(res);
}
free(dev);
}
int
acpi_device_add_res_fixed_ioport(struct acpi_device *const dev,
const UINT16 port, const UINT8 length)
{
if (dev == NULL) {
return (EINVAL);
}
struct acpi_resource_list_entry *const res = calloc(1, sizeof(*res));
if (res == NULL) {
return (ENOMEM);
}
res->type = ACPI_RESOURCE_TYPE_FIXED_IO;
res->data.FixedIo.Address = port;
res->data.FixedIo.AddressLength = length;
SLIST_INSERT_HEAD(&dev->crs, res, chain);
return (0);
}
int
acpi_device_add_res_fixed_memory32(struct acpi_device *const dev,
const UINT8 write_protected, const UINT32 address, const UINT32 length)
{
if (dev == NULL) {
return (EINVAL);
}
struct acpi_resource_list_entry *const res = calloc(1, sizeof(*res));
if (res == NULL) {
return (ENOMEM);
}
res->type = ACPI_RESOURCE_TYPE_FIXED_MEMORY32;
res->data.FixedMemory32.WriteProtect = write_protected;
res->data.FixedMemory32.Address = address;
res->data.FixedMemory32.AddressLength = length;
SLIST_INSERT_HEAD(&dev->crs, res, chain);
return (0);
}
void *
acpi_device_get_softc(const struct acpi_device *const dev)
{
assert(dev != NULL);
return (dev->softc);
}
int
acpi_device_build_table(const struct acpi_device *const dev)
{
assert(dev != NULL);
assert(dev->emul != NULL);
if (dev->emul->build_table != NULL) {
return (dev->emul->build_table(dev));
}
return (0);
}
static int
acpi_device_write_dsdt_crs(const struct acpi_device *const dev)
{
const struct acpi_resource_list_entry *res;
SLIST_FOREACH(res, &dev->crs, chain) {
switch (res->type) {
case ACPI_RESOURCE_TYPE_FIXED_IO:
dsdt_fixed_ioport(res->data.FixedIo.Address,
res->data.FixedIo.AddressLength);
break;
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
dsdt_fixed_mem32(res->data.FixedMemory32.Address,
res->data.FixedMemory32.AddressLength);
break;
default:
assert(0);
break;
}
}
return (0);
}
int
acpi_device_write_dsdt(const struct acpi_device *const dev)
{
assert(dev != NULL);
dsdt_line("");
dsdt_line(" Scope (\\_SB)");
dsdt_line(" {");
dsdt_line(" Device (%s)", dev->emul->name);
dsdt_line(" {");
dsdt_line(" Name (_HID, \"%s\")", dev->emul->hid);
dsdt_line(" Name (_STA, 0x0F)");
dsdt_line(" Name (_CRS, ResourceTemplate ()");
dsdt_line(" {");
dsdt_indent(4);
BASL_EXEC(acpi_device_write_dsdt_crs(dev));
dsdt_unindent(4);
dsdt_line(" })");
if (dev->emul->write_dsdt != NULL) {
dsdt_indent(3);
BASL_EXEC(dev->emul->write_dsdt(dev));
dsdt_unindent(3);
}
dsdt_line(" }");
dsdt_line(" }");
return (0);
}