diff --git a/usr.sbin/bhyve/Makefile b/usr.sbin/bhyve/Makefile --- a/usr.sbin/bhyve/Makefile +++ b/usr.sbin/bhyve/Makefile @@ -18,6 +18,7 @@ atkbdc.c \ acpi.c \ audio.c \ + basl.c \ bhyvegc.c \ bhyverun.c \ block_if.c \ diff --git a/usr.sbin/bhyve/acpi.c b/usr.sbin/bhyve/acpi.c --- a/usr.sbin/bhyve/acpi.c +++ b/usr.sbin/bhyve/acpi.c @@ -73,6 +73,7 @@ #include "bhyverun.h" #include "acpi.h" +#include "basl.h" #include "pci_emul.h" #include "vmgenc.h" @@ -80,7 +81,6 @@ * Define the base address of the ACPI tables, the sizes of some tables, * and the offsets to the individual tables, */ -#define BHYVE_ACPI_BASE 0xf2400 #define RSDT_OFFSET 0x040 #define XSDT_OFFSET 0x080 #define MADT_OFFSET 0x100 diff --git a/usr.sbin/bhyve/basl.h b/usr.sbin/bhyve/basl.h new file mode 100644 --- /dev/null +++ b/usr.sbin/bhyve/basl.h @@ -0,0 +1,37 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2022 Beckhoff Automation GmbH & Co. KG + * Author: Corvin Köhne + */ + +#pragma once + +#include + +#define BHYVE_ACPI_BASE 0xf2400 + +#define BASL_TABLE_ALIGNMENT 0x10 +#define BASL_TABLE_ALIGNMENT_FACS 0x40 + +#define BASL_EXEC(x) \ + do { \ + const int error = (x); \ + if (error) { \ + warnc(error, \ + "BASL failed @ %s:%d\n Failed to execute %s", \ + __func__, __LINE__, #x); \ + return (error); \ + } \ + } while (0) + +#define QEMU_FWCFG_MAX_NAME 56 + +struct basl_table; + +int basl_finish(void); +int basl_init(void); +int basl_table_append_bytes(struct basl_table *table, const void *bytes, + uint32_t len); +int basl_table_create(struct basl_table **table, struct vmctx *ctx, + const uint8_t *name, uint32_t alignment, uint32_t off); diff --git a/usr.sbin/bhyve/basl.c b/usr.sbin/bhyve/basl.c new file mode 100644 --- /dev/null +++ b/usr.sbin/bhyve/basl.c @@ -0,0 +1,140 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2022 Beckhoff Automation GmbH & Co. KG + * Author: Corvin Köhne + */ + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "basl.h" + +struct basl_table { + STAILQ_ENTRY(basl_table) chain; + struct vmctx *ctx; + uint8_t fwcfg_name[QEMU_FWCFG_MAX_NAME]; + void *data; + uint32_t len; + uint32_t off; + uint32_t alignment; +}; +static STAILQ_HEAD(basl_table_list, basl_table) basl_tables = STAILQ_HEAD_INITIALIZER( + basl_tables); + +static int +basl_finish_install_guest_tables(void) +{ + struct basl_table *table; + STAILQ_FOREACH(table, &basl_tables, chain) { + /* + * Guest bios versions without qemu fwcfg support search for + * ACPI tables in the guest memory and install them as is. + * Therefore, copy the tables into the guest memory. + */ + void *gva = vm_map_gpa(table->ctx, BHYVE_ACPI_BASE + table->off, + table->len); + if (gva == NULL) { + warnx("%s: could not map gpa [ 0x%16lx, 0x%16lx ]", + __func__, (uint64_t)BHYVE_ACPI_BASE + table->off, + (uint64_t)BHYVE_ACPI_BASE + table->off + + table->len); + return (ENOMEM); + } + memcpy(gva, table->data, table->len); + } + + return (0); +} + +int +basl_finish(void) +{ + if (STAILQ_EMPTY(&basl_tables)) { + warnx("%s: no ACPI tables found", __func__); + return (EINVAL); + } + + BASL_EXEC(basl_finish_install_guest_tables()); + + return (0); +} + +int +basl_init(void) +{ + return (0); +} + +int +basl_table_append_bytes(struct basl_table *const table, const void *const bytes, + const uint32_t len) +{ + if (table == NULL || bytes == NULL) { + return (EINVAL); + } + if (table->len + len <= table->len) { + warnx("%s: table too large (table->len 0x%8x len 0x%8x)", + __func__, table->len, len); + return (EFAULT); + } + + table->data = reallocf(table->data, table->len + len); + if (table->data == NULL) { + warnx("%s: failed to realloc table to length 0x%8x", __func__, + table->len + len); + table->len = 0; + return (ENOMEM); + } + void *const end = (uint8_t *)table->data + table->len; + table->len += len; + + memcpy(end, bytes, len); + + return (0); +} + +int +basl_table_create(struct basl_table **const table, struct vmctx *ctx, + const uint8_t *const name, const uint32_t alignment, + const uint32_t off) +{ + if (table == NULL) { + return (EINVAL); + } + + struct basl_table *const new_table = calloc(1, + sizeof(struct basl_table)); + if (new_table == NULL) { + warnx("%s: failed to allocate table", __func__); + return (ENOMEM); + } + + new_table->ctx = ctx; + + const int name_length = snprintf(new_table->fwcfg_name, + sizeof(new_table->fwcfg_name), "etc/acpi/%s", name); + assert(name_length > 0 && name_length < sizeof(new_table->fwcfg_name)); + + new_table->alignment = alignment; + new_table->off = off; + + STAILQ_INSERT_TAIL(&basl_tables, new_table, chain); + + *table = new_table; + + return (0); +}