diff --git a/usr.sbin/bhyve/basl.c b/usr.sbin/bhyve/basl.c
index b03c936bd517..77f26a930b94 100644
--- a/usr.sbin/bhyve/basl.c
+++ b/usr.sbin/bhyve/basl.c
@@ -1,273 +1,385 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2022 Beckhoff Automation GmbH & Co. KG
  */
 
 #include <sys/param.h>
 #include <sys/endian.h>
 #include <sys/errno.h>
 #include <sys/queue.h>
 #include <sys/stat.h>
 
 #include <machine/vmm.h>
 
 #include <assert.h>
 #include <err.h>
 #include <libutil.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <vmmapi.h>
 
 #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;
 	uint8_t size;
 };
 
 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;
+	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(
     basl_tables);
 
 static __inline void
 basl_le_enc(void *pp, uint64_t val, size_t len)
 {
 	char buf[8];
 
 	assert(len <= 8);
 
 	le64enc(buf, val);
 	memcpy(pp, buf, len);
 }
 
 static int
 basl_dump_table(const struct basl_table *const table, const bool mem)
 {
 	const ACPI_TABLE_HEADER *const header = table->data;
 	const uint8_t *data;
 
 	if (!mem) {
 		data = table->data;
 	} else {
 		data = vm_map_gpa(table->ctx, BHYVE_ACPI_BASE + table->off,
 		    table->len);
 		if (data == NULL) {
 			return (ENOMEM);
 		}
 	}
 
 	printf("%.4s @ %8x (%s)\n", header->Signature,
 	    BHYVE_ACPI_BASE + table->off, mem ? "Memory" : "FwCfg");
 	hexdump(data, table->len, NULL, 0);
 
 	return (0);
 }
 
 static int
 basl_dump(const bool mem)
 {
 	struct basl_table *table;
 
 	STAILQ_FOREACH(table, &basl_tables, chain) {
 		BASL_EXEC(basl_dump_table(table, mem));
 	}
 
 	return (0);
 }
 
 static int
 basl_finish_install_guest_tables(struct basl_table *const table)
 {
 	void *gva;
 
 	/*
 	 * Install ACPI tables directly in guest memory for use by guests which
 	 * do not boot via EFI. EFI ROMs provide a pointer to the firmware
 	 * generated ACPI tables instead, but it doesn't hurt to install the
 	 * tables always.
 	 */
 	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);
 }
 
+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);
+
+		/*
+		 * Install ACPI tables directly in guest memory for use by
+		 * guests which do not boot via EFI. EFI ROMs provide a pointer
+		 * to the firmware generated ACPI tables instead, but it doesn't
+		 * hurt to install the tables always.
+		 */
+		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)
 {
 	struct basl_table_length *length;
 
 	STAILQ_FOREACH(length, &table->lengths, chain) {
 		assert(length->off < table->len);
 		assert(length->off + length->size <= table->len);
 
 		basl_le_enc(table->data + length->off, table->len,
 		    length->size);
 	}
 
 	return (0);
 }
 
 int
 basl_finish(void)
 {
 	struct basl_table *table;
 
 	if (STAILQ_EMPTY(&basl_tables)) {
 		warnx("%s: no ACPI tables found", __func__);
 		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);
 }
 
 int
 basl_init(void)
 {
 	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)
 {
 	struct basl_table_length *length;
 
 	length = calloc(1, sizeof(struct basl_table_length));
 	if (length == NULL) {
 		warnx("%s: failed to allocate length", __func__);
 		return (ENOMEM);
 	}
 
 	length->off = off;
 	length->size = size;
 
 	STAILQ_INSERT_TAIL(&table->lengths, length, chain);
 
 	return (0);
 }
 
 int
 basl_table_append_bytes(struct basl_table *const table, const void *const bytes,
     const uint32_t len)
 {
 	void *end;
 
 	assert(table != NULL);
 	assert(bytes != NULL);
 
 	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);
 	}
 
 	end = (uint8_t *)table->data + table->len;
 	table->len += len;
 
 	memcpy(end, bytes, len);
 
 	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,
     const uint8_t access_width, const uint64_t address)
 {
 	ACPI_GENERIC_ADDRESS gas_le = {
 		.SpaceId = space_id,
 		.BitWidth = bit_width,
 		.BitOffset = bit_offset,
 		.AccessWidth = access_width,
 		.Address = htole64(address),
 	};
 
 	return (basl_table_append_bytes(table, &gas_le, sizeof(gas_le)));
 }
 
 int
 basl_table_append_int(struct basl_table *const table, const uint64_t val,
     const uint8_t size)
 {
 	char buf[8];
 
 	assert(size <= sizeof(val));
 
 	basl_le_enc(buf, val, size);
 	return (basl_table_append_bytes(table, buf, size));
 }
 
 int
 basl_table_append_length(struct basl_table *const table, const uint8_t size)
 {
 	assert(table != NULL);
 	assert(size <= sizeof(table->len));
 
 	BASL_EXEC(basl_table_add_length(table, 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,
     const uint32_t off)
 {
 	struct basl_table *new_table;
 
 	assert(table != NULL);
 
 	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;
 
 	snprintf(new_table->fwcfg_name, sizeof(new_table->fwcfg_name),
 	    "etc/acpi/%s", name);
 
 	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);
 
 	*table = new_table;
 
 	return (0);
 }
diff --git a/usr.sbin/bhyve/basl.h b/usr.sbin/bhyve/basl.h
index 95c5fd916761..b478780cb74d 100644
--- a/usr.sbin/bhyve/basl.h
+++ b/usr.sbin/bhyve/basl.h
@@ -1,48 +1,52 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (c) 2022 Beckhoff Automation GmbH & Co. KG
  */
 
 #pragma once
 
 #include <contrib/dev/acpica/include/acpi.h>
 
 #define ACPI_GAS_ACCESS_WIDTH_LEGACY 0
 #define ACPI_GAS_ACCESS_WIDTH_UNDEFINED 0
 #define ACPI_GAS_ACCESS_WIDTH_BYTE 1
 #define ACPI_GAS_ACCESS_WIDTH_WORD 2
 #define ACPI_GAS_ACCESS_WIDTH_DWORD 3
 #define ACPI_GAS_ACCESS_WIDTH_QWORD 4
 
 #define BHYVE_ACPI_BASE 0xf2400
 
 #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);                                       \
 		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_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);
 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_create(struct basl_table **table, struct vmctx *ctx,
     const uint8_t *name, uint32_t alignment, uint32_t off);