Page MenuHomeFreeBSD

D36990.id112915.diff
No OneTemporary

D36990.id112915.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
@@ -20,6 +20,8 @@
#define BASL_TABLE_ALIGNMENT 0x10
#define BASL_TABLE_ALIGNMENT_FACS 0x40
+#define BASL_TABLE_CHECKSUM_LEN_FULL_TABLE (-1)
+
#define BASL_EXEC(x) \
do { \
const int error = (x); \
@@ -39,6 +41,8 @@
int basl_init(void);
int basl_table_append_bytes(struct basl_table *table, const void *bytes,
uint32_t len);
+int basl_table_append_checksum(struct basl_table *table, uint32_t start,
+ uint32_t len);
int basl_table_append_gas(struct basl_table *table, uint8_t space_id,
uint8_t bit_width, uint8_t bit_offset, uint8_t access_width,
uint64_t address);
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
@@ -21,6 +21,13 @@
#include "basl.h"
+struct basl_table_checksum {
+ STAILQ_ENTRY(basl_table_checksum) chain;
+ uint32_t off;
+ uint32_t start;
+ uint32_t len;
+};
+
struct basl_table_length {
STAILQ_ENTRY(basl_table_length) chain;
uint32_t off;
@@ -35,6 +42,8 @@
uint32_t len;
uint32_t off;
uint32_t alignment;
+ STAILQ_HEAD(basl_table_checksum_list,
+ basl_table_checksum) checksums;
STAILQ_HEAD(basl_table_length_list, basl_table_length) lengths;
};
static STAILQ_HEAD(basl_table_list, basl_table) basl_tables = STAILQ_HEAD_INITIALIZER(
@@ -109,6 +118,63 @@
return (0);
}
+static int
+basl_finish_patch_checksums(struct basl_table *const table)
+{
+ struct basl_table_checksum *checksum;
+
+ STAILQ_FOREACH(checksum, &table->checksums, chain) {
+ uint8_t *gva, *checksum_gva;
+ uint64_t gpa;
+ uint32_t len;
+ uint8_t sum;
+
+ len = checksum->len;
+ if (len == BASL_TABLE_CHECKSUM_LEN_FULL_TABLE) {
+ len = table->len;
+ }
+
+ assert(checksum->off < table->len);
+ assert(checksum->start < table->len);
+ assert(checksum->start + len <= table->len);
+
+ /*
+ * Some guests are searching for ACPI tables in the guest memory
+ * and install them as they are. Therefore, patch the checksum
+ * in the guest memory copies to a correct value.
+ */
+ gpa = BHYVE_ACPI_BASE + table->off + checksum->start;
+ if ((gpa < BHYVE_ACPI_BASE) ||
+ (gpa < BHYVE_ACPI_BASE + table->off)) {
+ warnx("%s: invalid gpa (off 0x%8x start 0x%8x)",
+ __func__, table->off, checksum->start);
+ return (EFAULT);
+ }
+
+ gva = vm_map_gpa(table->ctx, gpa, len);
+ if (gva == NULL) {
+ warnx("%s: could not map gpa [ 0x%16lx, 0x%16lx ]",
+ __func__, gpa, gpa + len);
+ return (ENOMEM);
+ }
+
+ checksum_gva = gva + checksum->off;
+ if (checksum_gva < gva) {
+ warnx("%s: invalid checksum offset 0x%8x", __func__,
+ checksum->off);
+ return (EFAULT);
+ }
+
+ sum = 0;
+ for (uint32_t i = 0; i < len; ++i) {
+ sum += *(gva + i);
+ }
+ *checksum_gva = -sum;
+ }
+
+ return (0);
+}
+
static int
basl_finish_set_length(struct basl_table *const table)
{
@@ -135,10 +201,21 @@
return (EINVAL);
}
+ /*
+ * We have to install all tables before we can patch them. Therefore,
+ * use two loops. The first one installs all tables and the second one
+ * patches them.
+ */
STAILQ_FOREACH(table, &basl_tables, chain) {
BASL_EXEC(basl_finish_set_length(table));
BASL_EXEC(basl_finish_install_guest_tables(table));
}
+ STAILQ_FOREACH(table, &basl_tables, chain) {
+ /*
+ * Calculate the checksum as last step!
+ */
+ BASL_EXEC(basl_finish_patch_checksums(table));
+ }
return (0);
}
@@ -149,6 +226,27 @@
return (0);
}
+static int
+basl_table_add_checksum(struct basl_table *const table, const uint32_t off,
+ const uint32_t start, const uint32_t len)
+{
+ struct basl_table_checksum *checksum;
+
+ checksum = calloc(1, sizeof(struct basl_table_checksum));
+ if (checksum == NULL) {
+ warnx("%s: failed to allocate checksum", __func__);
+ return (ENOMEM);
+ }
+
+ checksum->off = off;
+ checksum->start = start;
+ checksum->len = len;
+
+ STAILQ_INSERT_TAIL(&table->checksums, checksum, chain);
+
+ return (0);
+}
+
static int
basl_table_add_length(struct basl_table *const table, const uint32_t off,
const uint8_t size)
@@ -200,6 +298,18 @@
return (0);
}
+int
+basl_table_append_checksum(struct basl_table *const table, const uint32_t start,
+ const uint32_t len)
+{
+ assert(table != NULL);
+
+ BASL_EXEC(basl_table_add_checksum(table, table->len, start, len));
+ BASL_EXEC(basl_table_append_int(table, 0, 1));
+
+ return (0);
+}
+
int
basl_table_append_gas(struct basl_table *const table, const uint8_t space_id,
const uint8_t bit_width, const uint8_t bit_offset,
@@ -263,6 +373,7 @@
new_table->alignment = alignment;
new_table->off = off;
+ STAILQ_INIT(&new_table->checksums);
STAILQ_INIT(&new_table->lengths);
STAILQ_INSERT_TAIL(&basl_tables, new_table, chain);

File Metadata

Mime Type
text/plain
Expires
Mon, Jan 27, 6:03 PM (2 h, 31 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16202758
Default Alt Text
D36990.id112915.diff (4 KB)

Event Timeline