xref: /illumos-gate/usr/src/cmd/bhyve/common/basl.c (revision 43379a280422204006ceee5a5c5380444cb515d9)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2022 Beckhoff Automation GmbH & Co. KG
5  */
6 
7 #include <sys/param.h>
8 #include <sys/endian.h>
9 #include <sys/errno.h>
10 #include <sys/queue.h>
11 #include <sys/stat.h>
12 
13 #include <machine/vmm.h>
14 
15 #include <assert.h>
16 #include <err.h>
17 #include <libutil.h>
18 #include <stddef.h>
19 #include <stdio.h>
20 #include <vmmapi.h>
21 
22 #ifndef	__FreeBSD__
23 #include <sys/hexdump.h>
24 #endif
25 
26 #include "basl.h"
27 #include "config.h"
28 #include "qemu_loader.h"
29 
30 struct basl_table_checksum {
31 	STAILQ_ENTRY(basl_table_checksum) chain;
32 	uint32_t off;
33 	uint32_t start;
34 	uint32_t len;
35 };
36 
37 struct basl_table_length {
38 	STAILQ_ENTRY(basl_table_length) chain;
39 	uint32_t off;
40 	uint8_t size;
41 };
42 
43 struct basl_table_pointer {
44 	STAILQ_ENTRY(basl_table_pointer) chain;
45 	uint8_t src_signature[ACPI_NAMESEG_SIZE];
46 	uint32_t off;
47 	uint8_t size;
48 };
49 
50 struct basl_table {
51 	STAILQ_ENTRY(basl_table) chain;
52 	struct vmctx *ctx;
53 	uint8_t fwcfg_name[QEMU_FWCFG_MAX_NAME];
54 	void *data;
55 	uint32_t len;
56 	uint32_t off;
57 	uint32_t alignment;
58 	STAILQ_HEAD(basl_table_checksum_list, basl_table_checksum) checksums;
59 	STAILQ_HEAD(basl_table_length_list, basl_table_length) lengths;
60 	STAILQ_HEAD(basl_table_pointer_list, basl_table_pointer) pointers;
61 };
62 static STAILQ_HEAD(basl_table_list, basl_table) basl_tables = STAILQ_HEAD_INITIALIZER(
63     basl_tables);
64 
65 static struct qemu_loader *basl_loader;
66 static struct basl_table *rsdt;
67 static struct basl_table *xsdt;
68 static bool load_into_memory;
69 
70 static __inline uint64_t
basl_le_dec(void * pp,size_t len)71 basl_le_dec(void *pp, size_t len)
72 {
73 	assert(len <= 8);
74 
75 	switch (len) {
76 	case 1:
77 		return ((uint8_t *)pp)[0];
78 	case 2:
79 		return le16dec(pp);
80 	case 4:
81 		return le32dec(pp);
82 	case 8:
83 		return le64dec(pp);
84 	}
85 
86 	return 0;
87 }
88 
89 static __inline void
basl_le_enc(void * pp,uint64_t val,size_t len)90 basl_le_enc(void *pp, uint64_t val, size_t len)
91 {
92 	char buf[8];
93 
94 	assert(len <= 8);
95 
96 	le64enc(buf, val);
97 	memcpy(pp, buf, len);
98 }
99 
100 static int
basl_dump_table(const struct basl_table * const table,const bool mem)101 basl_dump_table(const struct basl_table *const table, const bool mem)
102 {
103 	const ACPI_TABLE_HEADER *const header = table->data;
104 	const uint8_t *data;
105 
106 	if (!mem) {
107 		data = table->data;
108 	} else {
109 		data = vm_map_gpa(table->ctx, BHYVE_ACPI_BASE + table->off,
110 		    table->len);
111 		if (data == NULL) {
112 			return (ENOMEM);
113 		}
114 	}
115 
116 #ifdef	__FreeBSD__
117 	printf("%.4s @ %8x (%s)\n", header->Signature,
118 	    BHYVE_ACPI_BASE + table->off, mem ? "Memory" : "FwCfg");
119 	hexdump(data, table->len, NULL, 0);
120 #else
121 	(void) printf("%.4s @ %8x (%s)\n", header->Signature,
122 	    BHYVE_ACPI_BASE + table->off, mem ? "Memory" : "FwCfg");
123 	hexdump_t h;
124 	hexdump_init(&h);
125 	hexdump_set_addr(&h, BHYVE_ACPI_BASE + table->off);
126 	(void) hexdump_fileh(&h, data, table->len, HDF_DEFAULT, stdout);
127 	hexdump_fini(&h);
128 	(void) printf("\n");
129 #endif
130 
131 	return (0);
132 }
133 
134 static int
basl_dump(const bool mem)135 basl_dump(const bool mem)
136 {
137 	struct basl_table *table;
138 
139 	STAILQ_FOREACH(table, &basl_tables, chain) {
140 		BASL_EXEC(basl_dump_table(table, mem));
141 	}
142 
143 	return (0);
144 }
145 
146 void
basl_fill_gas(ACPI_GENERIC_ADDRESS * const gas,const uint8_t space_id,const uint8_t bit_width,const uint8_t bit_offset,const uint8_t access_width,const uint64_t address)147 basl_fill_gas(ACPI_GENERIC_ADDRESS *const gas, const uint8_t space_id,
148     const uint8_t bit_width, const uint8_t bit_offset,
149     const uint8_t access_width, const uint64_t address)
150 {
151 	assert(gas != NULL);
152 
153 	gas->SpaceId = space_id;
154 	gas->BitWidth = bit_width;
155 	gas->BitOffset = bit_offset;
156 	gas->AccessWidth = access_width;
157 	gas->Address = htole64(address);
158 }
159 
160 static int
basl_finish_install_guest_tables(struct basl_table * const table,uint32_t * const off)161 basl_finish_install_guest_tables(struct basl_table *const table, uint32_t *const off)
162 {
163 	void *gva;
164 
165 	table->off = roundup2(*off, table->alignment);
166 	*off = table->off + table->len;
167 	if (*off <= table->off) {
168 		warnx("%s: invalid table length 0x%8x @ offset 0x%8x", __func__,
169 		    table->len, table->off);
170 		return (EFAULT);
171 	}
172 
173 	/* Cause guest BIOS to copy the ACPI table into guest memory. */
174 #ifdef	__FreeBSD__
175 	BASL_EXEC(
176 	    qemu_fwcfg_add_file(table->fwcfg_name, table->len, table->data));
177 #else
178 	BASL_EXEC(
179 	    qemu_fwcfg_add_file((const char *)table->fwcfg_name,
180 	    table->len, table->data));
181 #endif
182 	BASL_EXEC(qemu_loader_alloc(basl_loader, table->fwcfg_name,
183 	    table->alignment, QEMU_LOADER_ALLOC_HIGH));
184 
185 	if (!load_into_memory) {
186 		return (0);
187 	}
188 
189 	/*
190 	 * Install ACPI tables directly in guest memory for use by guests which
191 	 * do not boot via EFI. EFI ROMs provide a pointer to the firmware
192 	 * generated ACPI tables instead, but it doesn't hurt to install the
193 	 * tables always.
194 	 */
195 	gva = vm_map_gpa(table->ctx, BHYVE_ACPI_BASE + table->off, table->len);
196 	if (gva == NULL) {
197 		warnx("%s: could not map gpa [ 0x%16lx, 0x%16lx ]", __func__,
198 		    (uint64_t)BHYVE_ACPI_BASE + table->off,
199 		    (uint64_t)BHYVE_ACPI_BASE + table->off + table->len);
200 		return (ENOMEM);
201 	}
202 	memcpy(gva, table->data, table->len);
203 
204 	return (0);
205 }
206 
207 static int
basl_finish_patch_checksums(struct basl_table * const table)208 basl_finish_patch_checksums(struct basl_table *const table)
209 {
210 	struct basl_table_checksum *checksum;
211 
212 	STAILQ_FOREACH(checksum, &table->checksums, chain) {
213 		uint8_t *gva, *checksum_gva;
214 		uint64_t gpa;
215 		uint32_t len;
216 		uint8_t sum;
217 
218 		len = checksum->len;
219 		if (len == BASL_TABLE_CHECKSUM_LEN_FULL_TABLE) {
220 			len = table->len;
221 		}
222 
223 		assert(checksum->off < table->len);
224 		assert(checksum->start < table->len);
225 		assert(checksum->start + len <= table->len);
226 
227 		/* Cause guest BIOS to patch the checksum. */
228 		BASL_EXEC(qemu_loader_add_checksum(basl_loader,
229 		    table->fwcfg_name, checksum->off, checksum->start, len));
230 
231 		if (!load_into_memory) {
232 			continue;
233 		}
234 
235 		/*
236 		 * Install ACPI tables directly in guest memory for use by
237 		 * guests which do not boot via EFI. EFI ROMs provide a pointer
238 		 * to the firmware generated ACPI tables instead, but it doesn't
239 		 * hurt to install the tables always.
240 		 */
241 		gpa = BHYVE_ACPI_BASE + table->off + checksum->start;
242 		if ((gpa < BHYVE_ACPI_BASE) ||
243 		    (gpa < BHYVE_ACPI_BASE + table->off)) {
244 			warnx("%s: invalid gpa (off 0x%8x start 0x%8x)",
245 			    __func__, table->off, checksum->start);
246 			return (EFAULT);
247 		}
248 
249 		gva = vm_map_gpa(table->ctx, gpa, len);
250 		if (gva == NULL) {
251 			warnx("%s: could not map gpa [ 0x%16lx, 0x%16lx ]",
252 			    __func__, gpa, gpa + len);
253 			return (ENOMEM);
254 		}
255 
256 		checksum_gva = gva + checksum->off;
257 		if (checksum_gva < gva) {
258 			warnx("%s: invalid checksum offset 0x%8x", __func__,
259 			    checksum->off);
260 			return (EFAULT);
261 		}
262 
263 		sum = 0;
264 		for (uint32_t i = 0; i < len; ++i) {
265 			sum += *(gva + i);
266 		}
267 		*checksum_gva = -sum;
268 	}
269 
270 	return (0);
271 }
272 
273 static struct basl_table *
basl_get_table_by_signature(const uint8_t signature[ACPI_NAMESEG_SIZE])274 basl_get_table_by_signature(const uint8_t signature[ACPI_NAMESEG_SIZE])
275 {
276 	struct basl_table *table;
277 
278 	STAILQ_FOREACH(table, &basl_tables, chain) {
279 		const ACPI_TABLE_HEADER *const header =
280 		    (const ACPI_TABLE_HEADER *)table->data;
281 
282 #ifdef	__FreeBSD__
283 		if (strncmp(header->Signature, signature,
284 			sizeof(header->Signature)) == 0) {
285 			return (table);
286 #else
287 		if (strncmp(header->Signature, (char *)signature,
288 			sizeof(header->Signature)) == 0) {
289 			return (table);
290 #endif
291 		}
292 	}
293 
294 	warnx("%s: %.4s not found", __func__, signature);
295 	return (NULL);
296 }
297 
298 static int
299 basl_finish_patch_pointers(struct basl_table *const table)
300 {
301 	struct basl_table_pointer *pointer;
302 
303 	STAILQ_FOREACH(pointer, &table->pointers, chain) {
304 		const struct basl_table *src_table;
305 		uint8_t *gva;
306 		uint64_t gpa, val;
307 
308 		assert(pointer->off < table->len);
309 		assert(pointer->off + pointer->size <= table->len);
310 
311 		src_table = basl_get_table_by_signature(pointer->src_signature);
312 		if (src_table == NULL) {
313 			warnx("%s: could not find ACPI table %.4s", __func__,
314 			    pointer->src_signature);
315 			return (EFAULT);
316 		}
317 
318 		/* Cause guest BIOS to patch the pointer. */
319 		BASL_EXEC(
320 		    qemu_loader_add_pointer(basl_loader, table->fwcfg_name,
321 			src_table->fwcfg_name, pointer->off, pointer->size));
322 
323 		if (!load_into_memory) {
324 			continue;
325 		}
326 
327 		/*
328 		 * Install ACPI tables directly in guest memory for use by
329 		 * guests which do not boot via EFI. EFI ROMs provide a pointer
330 		 * to the firmware generated ACPI tables instead, but it doesn't
331 		 * hurt to install the tables always.
332 		 */
333 		gpa = BHYVE_ACPI_BASE + table->off;
334 		if (gpa < BHYVE_ACPI_BASE) {
335 			warnx("%s: table offset of 0x%8x is too large",
336 			    __func__, table->off);
337 			return (EFAULT);
338 		}
339 
340 		gva = vm_map_gpa(table->ctx, gpa, table->len);
341 		if (gva == NULL) {
342 			warnx("%s: could not map gpa [ 0x%16lx, 0x%16lx ]",
343 			    __func__, gpa, gpa + table->len);
344 			return (ENOMEM);
345 		}
346 
347 		val = basl_le_dec(gva + pointer->off, pointer->size);
348 		val += BHYVE_ACPI_BASE + src_table->off;
349 		basl_le_enc(gva + pointer->off, val, pointer->size);
350 	}
351 
352 	return (0);
353 }
354 
355 static int
356 basl_finish_set_length(struct basl_table *const table)
357 {
358 	struct basl_table_length *length;
359 
360 	STAILQ_FOREACH(length, &table->lengths, chain) {
361 		assert(length->off < table->len);
362 		assert(length->off + length->size <= table->len);
363 
364 		basl_le_enc((uint8_t *)table->data + length->off, table->len,
365 		    length->size);
366 	}
367 
368 	return (0);
369 }
370 
371 int
372 basl_finish(void)
373 {
374 	struct basl_table *table;
375 	uint32_t off = 0;
376 
377 	if (STAILQ_EMPTY(&basl_tables)) {
378 		warnx("%s: no ACPI tables found", __func__);
379 		return (EINVAL);
380 	}
381 
382 	/*
383 	 * If we install ACPI tables by FwCfg and by memory, Windows will use
384 	 * the tables from memory. This can cause issues when using advanced
385 	 * features like a TPM log because we aren't able to patch the memory
386 	 * tables accordingly.
387 	 */
388 	load_into_memory = get_config_bool_default("acpi_tables_in_memory",
389 	    true);
390 
391 #ifndef __FreeBSD__
392 	if (get_config_bool_default("basl.debug", false))
393 		basl_dump(false);
394 #endif
395 
396 	/*
397 	 * We have to install all tables before we can patch them. Therefore,
398 	 * use two loops. The first one installs all tables and the second one
399 	 * patches them.
400 	 */
401 	STAILQ_FOREACH(table, &basl_tables, chain) {
402 		BASL_EXEC(basl_finish_set_length(table));
403 		BASL_EXEC(basl_finish_install_guest_tables(table, &off));
404 	}
405 	STAILQ_FOREACH(table, &basl_tables, chain) {
406 		BASL_EXEC(basl_finish_patch_pointers(table));
407 
408 		/*
409 		 * Calculate the checksum as last step!
410 		 */
411 		BASL_EXEC(basl_finish_patch_checksums(table));
412 	}
413 	BASL_EXEC(qemu_loader_finish(basl_loader));
414 
415 #ifndef __FreeBSD__
416 	if (get_config_bool_default("basl.debug", false))
417 		basl_dump(true);
418 #endif
419 
420 	return (0);
421 }
422 
423 static int
424 basl_init_rsdt(struct vmctx *const ctx)
425 {
426 	BASL_EXEC(
427 	    basl_table_create(&rsdt, ctx, ACPI_SIG_RSDT, BASL_TABLE_ALIGNMENT));
428 
429 	/* Header */
430 	BASL_EXEC(basl_table_append_header(rsdt, ACPI_SIG_RSDT, 1, 1));
431 	/* Pointers (added by basl_table_register_to_rsdt) */
432 
433 	return (0);
434 }
435 
436 static int
437 basl_init_xsdt(struct vmctx *const ctx)
438 {
439 	BASL_EXEC(
440 	    basl_table_create(&xsdt, ctx, ACPI_SIG_XSDT, BASL_TABLE_ALIGNMENT));
441 
442 	/* Header */
443 	BASL_EXEC(basl_table_append_header(xsdt, ACPI_SIG_XSDT, 1, 1));
444 	/* Pointers (added by basl_table_register_to_rsdt) */
445 
446 	return (0);
447 }
448 
449 int
450 basl_init(struct vmctx *const ctx)
451 {
452 	BASL_EXEC(basl_init_rsdt(ctx));
453 	BASL_EXEC(basl_init_xsdt(ctx));
454 #ifdef	__FreeBSD__
455 	BASL_EXEC(
456 	    qemu_loader_create(&basl_loader, QEMU_FWCFG_FILE_TABLE_LOADER));
457 #else
458 	BASL_EXEC(
459 	    qemu_loader_create(&basl_loader,
460 	    (uint8_t *)QEMU_FWCFG_FILE_TABLE_LOADER));
461 #endif
462 
463 	return (0);
464 }
465 
466 int
467 basl_table_add_checksum(struct basl_table *const table, const uint32_t off,
468     const uint32_t start, const uint32_t len)
469 {
470 	struct basl_table_checksum *checksum;
471 
472 	assert(table != NULL);
473 
474 	checksum = calloc(1, sizeof(struct basl_table_checksum));
475 	if (checksum == NULL) {
476 		warnx("%s: failed to allocate checksum", __func__);
477 		return (ENOMEM);
478 	}
479 
480 	checksum->off = off;
481 	checksum->start = start;
482 	checksum->len = len;
483 
484 	STAILQ_INSERT_TAIL(&table->checksums, checksum, chain);
485 
486 	return (0);
487 }
488 
489 int
490 basl_table_add_length(struct basl_table *const table, const uint32_t off,
491     const uint8_t size)
492 {
493 	struct basl_table_length *length;
494 
495 	assert(table != NULL);
496 	assert(size == 4 || size == 8);
497 
498 	length = calloc(1, sizeof(struct basl_table_length));
499 	if (length == NULL) {
500 		warnx("%s: failed to allocate length", __func__);
501 		return (ENOMEM);
502 	}
503 
504 	length->off = off;
505 	length->size = size;
506 
507 	STAILQ_INSERT_TAIL(&table->lengths, length, chain);
508 
509 	return (0);
510 }
511 
512 int
513 basl_table_add_pointer(struct basl_table *const table,
514     const uint8_t src_signature[ACPI_NAMESEG_SIZE], const uint32_t off,
515     const uint8_t size)
516 {
517 	struct basl_table_pointer *pointer;
518 
519 	assert(table != NULL);
520 	assert(size == 4 || size == 8);
521 
522 	pointer = calloc(1, sizeof(struct basl_table_pointer));
523 	if (pointer == NULL) {
524 		warnx("%s: failed to allocate pointer", __func__);
525 		return (ENOMEM);
526 	}
527 
528 	memcpy(pointer->src_signature, src_signature,
529 	    sizeof(pointer->src_signature));
530 	pointer->off = off;
531 	pointer->size = size;
532 
533 	STAILQ_INSERT_TAIL(&table->pointers, pointer, chain);
534 
535 	return (0);
536 }
537 
538 int
539 basl_table_append_bytes(struct basl_table *const table, const void *const bytes,
540     const uint32_t len)
541 {
542 	void *end;
543 
544 	assert(table != NULL);
545 	assert(bytes != NULL);
546 
547 	if (table->len + len <= table->len) {
548 		warnx("%s: table too large (table->len 0x%8x len 0x%8x)",
549 		    __func__, table->len, len);
550 		return (EFAULT);
551 	}
552 
553 	table->data = reallocf(table->data, table->len + len);
554 	if (table->data == NULL) {
555 		warnx("%s: failed to realloc table to length 0x%8x", __func__,
556 		    table->len + len);
557 		table->len = 0;
558 		return (ENOMEM);
559 	}
560 
561 	end = (uint8_t *)table->data + table->len;
562 	table->len += len;
563 
564 	memcpy(end, bytes, len);
565 
566 	return (0);
567 }
568 
569 int
570 basl_table_append_checksum(struct basl_table *const table, const uint32_t start,
571     const uint32_t len)
572 {
573 	assert(table != NULL);
574 
575 	BASL_EXEC(basl_table_add_checksum(table, table->len, start, len));
576 	BASL_EXEC(basl_table_append_int(table, 0, 1));
577 
578 	return (0);
579 }
580 
581 int
582 basl_table_append_content(struct basl_table *table, void *data, uint32_t len)
583 {
584 	assert(data != NULL);
585 	assert(len >= sizeof(ACPI_TABLE_HEADER));
586 
587 	return (basl_table_append_bytes(table,
588 	    (void *)((uintptr_t)(data) + sizeof(ACPI_TABLE_HEADER)),
589 	    len - sizeof(ACPI_TABLE_HEADER)));
590 }
591 
592 int
593 basl_table_append_fwcfg(struct basl_table *const table,
594     const uint8_t *fwcfg_name, const uint32_t alignment, const uint8_t size)
595 {
596 	assert(table != NULL);
597 	assert(fwcfg_name != NULL);
598 	assert(size <= sizeof(uint64_t));
599 
600 	BASL_EXEC(qemu_loader_alloc(basl_loader, fwcfg_name, alignment,
601 	    QEMU_LOADER_ALLOC_HIGH));
602 	BASL_EXEC(qemu_loader_add_pointer(basl_loader, table->fwcfg_name,
603 	    fwcfg_name, table->len, size));
604 	BASL_EXEC(basl_table_append_int(table, 0, size));
605 
606 	return (0);
607 }
608 
609 int
610 basl_table_append_gas(struct basl_table *const table, const uint8_t space_id,
611     const uint8_t bit_width, const uint8_t bit_offset,
612     const uint8_t access_width, const uint64_t address)
613 {
614 	ACPI_GENERIC_ADDRESS gas_le = {
615 		.SpaceId = space_id,
616 		.BitWidth = bit_width,
617 		.BitOffset = bit_offset,
618 		.AccessWidth = access_width,
619 		.Address = htole64(address),
620 	};
621 
622 	return (basl_table_append_bytes(table, &gas_le, sizeof(gas_le)));
623 }
624 
625 int
626 basl_table_append_header(struct basl_table *const table,
627     const uint8_t signature[ACPI_NAMESEG_SIZE], const uint8_t revision,
628     const uint32_t oem_revision)
629 {
630 	ACPI_TABLE_HEADER header_le;
631 	/* + 1 is required for the null terminator */
632 	char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1];
633 
634 	assert(table != NULL);
635 	assert(table->len == 0);
636 
637 	memcpy(header_le.Signature, signature, ACPI_NAMESEG_SIZE);
638 	header_le.Length = 0; /* patched by basl_finish */
639 	header_le.Revision = revision;
640 	header_le.Checksum = 0; /* patched by basl_finish */
641 	memcpy(header_le.OemId, "BHYVE ", ACPI_OEM_ID_SIZE);
642 	snprintf(oem_table_id, ACPI_OEM_TABLE_ID_SIZE, "BV%.4s  ", signature);
643 	memcpy(header_le.OemTableId, oem_table_id,
644 	    sizeof(header_le.OemTableId));
645 	header_le.OemRevision = htole32(oem_revision);
646 	memcpy(header_le.AslCompilerId, "BASL", ACPI_NAMESEG_SIZE);
647 	header_le.AslCompilerRevision = htole32(0x20220504);
648 
649 	BASL_EXEC(
650 	    basl_table_append_bytes(table, &header_le, sizeof(header_le)));
651 
652 	BASL_EXEC(basl_table_add_length(table,
653 	    offsetof(ACPI_TABLE_HEADER, Length), sizeof(header_le.Length)));
654 	BASL_EXEC(basl_table_add_checksum(table,
655 	    offsetof(ACPI_TABLE_HEADER, Checksum), 0,
656 	    BASL_TABLE_CHECKSUM_LEN_FULL_TABLE));
657 
658 	return (0);
659 }
660 
661 int
662 basl_table_append_int(struct basl_table *const table, const uint64_t val,
663     const uint8_t size)
664 {
665 	char buf[8];
666 
667 	assert(size <= sizeof(val));
668 
669 	basl_le_enc(buf, val, size);
670 	return (basl_table_append_bytes(table, buf, size));
671 }
672 
673 int
674 basl_table_append_length(struct basl_table *const table, const uint8_t size)
675 {
676 	assert(table != NULL);
677 	assert(size <= sizeof(table->len));
678 
679 	BASL_EXEC(basl_table_add_length(table, table->len, size));
680 	BASL_EXEC(basl_table_append_int(table, 0, size));
681 
682 	return (0);
683 }
684 
685 int
686 basl_table_append_pointer(struct basl_table *const table,
687     const uint8_t src_signature[ACPI_NAMESEG_SIZE], const uint8_t size)
688 {
689 	assert(table != NULL);
690 	assert(size == 4 || size == 8);
691 
692 	BASL_EXEC(basl_table_add_pointer(table, src_signature, table->len, size));
693 	BASL_EXEC(basl_table_append_int(table, 0, size));
694 
695 	return (0);
696 }
697 
698 int
699 basl_table_create(struct basl_table **const table, struct vmctx *ctx,
700     const uint8_t *const name, const uint32_t alignment)
701 {
702 	struct basl_table *new_table;
703 
704 	assert(table != NULL);
705 
706 	new_table = calloc(1, sizeof(struct basl_table));
707 	if (new_table == NULL) {
708 		warnx("%s: failed to allocate table", __func__);
709 		return (ENOMEM);
710 	}
711 
712 	new_table->ctx = ctx;
713 
714 #ifdef	__FreeBSD__
715 	snprintf(new_table->fwcfg_name, sizeof(new_table->fwcfg_name),
716 	    "etc/acpi/%s", name);
717 #else
718 	snprintf((char *)new_table->fwcfg_name, sizeof (new_table->fwcfg_name),
719 	    "etc/acpi/%s", name);
720 #endif
721 
722 	new_table->alignment = alignment;
723 
724 	STAILQ_INIT(&new_table->checksums);
725 	STAILQ_INIT(&new_table->lengths);
726 	STAILQ_INIT(&new_table->pointers);
727 
728 	STAILQ_INSERT_TAIL(&basl_tables, new_table, chain);
729 
730 	*table = new_table;
731 
732 	return (0);
733 }
734 
735 int
736 basl_table_register_to_rsdt(struct basl_table *table)
737 {
738 	const ACPI_TABLE_HEADER *header;
739 
740 	assert(table != NULL);
741 
742 	header = (const ACPI_TABLE_HEADER *)table->data;
743 
744 #ifdef	__FreeBSD__
745 	BASL_EXEC(basl_table_append_pointer(rsdt, header->Signature,
746 	    ACPI_RSDT_ENTRY_SIZE));
747 	BASL_EXEC(basl_table_append_pointer(xsdt, header->Signature,
748 	    ACPI_XSDT_ENTRY_SIZE));
749 #else
750 	BASL_EXEC(basl_table_append_pointer(rsdt, (uint8_t *)header->Signature,
751 	    ACPI_RSDT_ENTRY_SIZE));
752 	BASL_EXEC(basl_table_append_pointer(xsdt, (uint8_t *)header->Signature,
753 	    ACPI_XSDT_ENTRY_SIZE));
754 #endif
755 
756 	return (0);
757 }
758