Page MenuHomeFreeBSD

D36991.id112766.diff
No OneTemporary

D36991.id112766.diff

diff --git a/usr.sbin/bhyve/basl.h b/usr.sbin/bhyve/basl.h
--- a/usr.sbin/bhyve/basl.h
+++ b/usr.sbin/bhyve/basl.h
@@ -49,5 +49,7 @@
uint64_t address);
int basl_table_append_int(struct basl_table *table, uint64_t val, uint8_t size);
int basl_table_append_length(struct basl_table *table, uint8_t size);
+int basl_table_append_pointer(struct basl_table *table,
+ const uint8_t src_sign[ACPI_NAMESEG_SIZE], uint8_t size);
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
--- a/usr.sbin/bhyve/basl.c
+++ b/usr.sbin/bhyve/basl.c
@@ -36,6 +36,13 @@
uint8_t size;
};
+struct basl_table_pointer {
+ STAILQ_ENTRY(basl_table_pointer) chain;
+ uint8_t src_sign[ACPI_NAMESEG_SIZE];
+ uint32_t off;
+ uint8_t size;
+};
+
struct basl_table {
STAILQ_ENTRY(basl_table) chain;
struct vmctx *ctx;
@@ -47,6 +54,7 @@
STAILQ_HEAD(basl_table_checksum_list,
basl_table_checksum) checksums;
STAILQ_HEAD(basl_table_length_list, basl_table_length) lengths;
+ STAILQ_HEAD(basl_table_pointer_list, basl_table_pointer) pointers;
};
static STAILQ_HEAD(basl_table_list, basl_table) basl_tables = STAILQ_HEAD_INITIALIZER(
basl_tables);
@@ -183,6 +191,102 @@
return (0);
}
+static struct basl_table *
+basl_get_table_by_sign(const uint8_t sign[ACPI_NAMESEG_SIZE])
+{
+ struct basl_table *table;
+ STAILQ_FOREACH (table, &basl_tables, chain) {
+ const ACPI_TABLE_HEADER *const header =
+ (const ACPI_TABLE_HEADER *)table->data;
+ if (strncmp(header->Signature, sign,
+ sizeof(header->Signature)) == 0) {
+ return (table);
+ }
+ }
+
+ warnx("%s: %c%c%c%c not found", __func__, sign[0], sign[1], sign[2],
+ sign[3]);
+ return (NULL);
+}
+
+static int
+basl_finish_patch_pointers(struct basl_table *const table)
+{
+ struct basl_table_pointer *pointer;
+ STAILQ_FOREACH(pointer, &table->pointers, chain) {
+ assert(pointer->off < table->len);
+ assert(pointer->off + pointer->size <= table->len);
+
+ const struct basl_table *const src_table =
+ basl_get_table_by_sign(pointer->src_sign);
+ if (src_table == NULL) {
+ warnx("%s: could not find ACPI table %c%c%c%c",
+ __func__, pointer->src_sign[0],
+ pointer->src_sign[1], pointer->src_sign[2],
+ pointer->src_sign[3]);
+ return (EFAULT);
+ }
+
+ /*
+ * Guest bios versions without qemu fwcfg support search for
+ * ACPI tables in the guest memory and install them as is.
+ * Therefore, patch the pointers in the guest memory copies
+ * manually.
+ */
+ const uint64_t gpa = BHYVE_ACPI_BASE + table->off;
+ if (gpa < BHYVE_ACPI_BASE) {
+ warnx("%s: table offset of 0x%8x is too large",
+ __func__, table->off);
+ return (EFAULT);
+ }
+
+ uint8_t *const gva = (uint8_t *)vm_map_gpa(table->ctx, gpa,
+ table->len);
+ if (gva == NULL) {
+ warnx("%s: could not map gpa [ 0x%16lx, 0x%16lx ]",
+ __func__, gpa, gpa + table->len);
+ return (ENOMEM);
+ }
+
+ /*
+ * ACPI tables are always little endian. So, memcpy works here
+ * for fetching the current value.
+ */
+ uint64_t val_le = 0;
+ memcpy(&val_le, gva + pointer->off, pointer->size);
+
+ uint64_t val;
+ switch (pointer->size) {
+ case 1:
+ val = val_le;
+ break;
+ case 2:
+ val = le16toh(val_le);
+ break;
+ case 4:
+ val = le32toh(val_le);
+ break;
+ case 8:
+ val = le64toh(val_le);
+ break;
+ default:
+ warnx("%s: invalid pointer size %x", __func__,
+ pointer->size);
+ return (EINVAL);
+ }
+ val += BHYVE_ACPI_BASE + src_table->off;
+
+ /*
+ * ACPI tables are always little endian. So, memcpy works here
+ * for writing the new value.
+ */
+ val_le = htole64(val);
+ memcpy(gva + pointer->off, &val_le, pointer->size);
+ }
+
+ return (0);
+}
+
static int
basl_finish_set_length(struct basl_table *const table)
{
@@ -217,6 +321,7 @@
BASL_EXEC(basl_finish_install_guest_tables(table));
}
STAILQ_FOREACH(table, &basl_tables, chain) {
+ BASL_EXEC(basl_finish_patch_pointers(table));
/*
* Calculate the checksum as last step!
*/
@@ -271,6 +376,27 @@
return (0);
}
+static int
+basl_table_add_pointer(struct basl_table *const table,
+ const uint8_t src_sign[ACPI_NAMESEG_SIZE], const uint32_t off,
+ const uint8_t size)
+{
+ struct basl_table_pointer *const pointer = calloc(1,
+ sizeof(struct basl_table_pointer));
+ if (pointer == NULL) {
+ warnx("%s: failed to allocate pointer", __func__);
+ return (ENOMEM);
+ }
+
+ memcpy(pointer->src_sign, src_sign, sizeof(pointer->src_sign));
+ pointer->off = off;
+ pointer->size = size;
+
+ STAILQ_INSERT_TAIL(&table->pointers, pointer, chain);
+
+ return (0);
+}
+
int
basl_table_append_bytes(struct basl_table *const table, const void *const bytes,
const uint32_t len)
@@ -349,6 +475,19 @@
return (0);
}
+int
+basl_table_append_pointer(struct basl_table *const table,
+ const uint8_t src_sign[ACPI_NAMESEG_SIZE], const uint8_t size)
+{
+ assert(table != NULL);
+ assert(size <= sizeof(UINT64));
+
+ BASL_EXEC(basl_table_add_pointer(table, src_sign, table->len, size));
+ BASL_EXEC(basl_table_append_int(table, 0, size));
+
+ return (0);
+}
+
int
basl_table_create(struct basl_table **const table, struct vmctx *ctx,
const uint8_t *const name, const uint32_t alignment,
@@ -374,6 +513,7 @@
STAILQ_INIT(&new_table->checksums);
STAILQ_INIT(&new_table->lengths);
+ STAILQ_INIT(&new_table->pointers);
STAILQ_INSERT_TAIL(&basl_tables, new_table, chain);

File Metadata

Mime Type
text/plain
Expires
Tue, Feb 17, 8:33 AM (15 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28808476
Default Alt Text
D36991.id112766.diff (5 KB)

Event Timeline