xref: /illumos-gate/usr/src/cmd/bhyve/acpi.c (revision 32640292339b07090f10ce34d455f98711077343)
14c87aefeSPatrick Mooney /*-
2*32640292SAndy Fiddaman  * SPDX-License-Identifier: BSD-2-Clause
34c87aefeSPatrick Mooney  *
44c87aefeSPatrick Mooney  * Copyright (c) 2012 NetApp, Inc.
54c87aefeSPatrick Mooney  * All rights reserved.
64c87aefeSPatrick Mooney  *
74c87aefeSPatrick Mooney  * Redistribution and use in source and binary forms, with or without
84c87aefeSPatrick Mooney  * modification, are permitted provided that the following conditions
94c87aefeSPatrick Mooney  * are met:
104c87aefeSPatrick Mooney  * 1. Redistributions of source code must retain the above copyright
114c87aefeSPatrick Mooney  *    notice, this list of conditions and the following disclaimer.
124c87aefeSPatrick Mooney  * 2. Redistributions in binary form must reproduce the above copyright
134c87aefeSPatrick Mooney  *    notice, this list of conditions and the following disclaimer in the
144c87aefeSPatrick Mooney  *    documentation and/or other materials provided with the distribution.
154c87aefeSPatrick Mooney  *
164c87aefeSPatrick Mooney  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
174c87aefeSPatrick Mooney  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
184c87aefeSPatrick Mooney  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
194c87aefeSPatrick Mooney  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
204c87aefeSPatrick Mooney  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
214c87aefeSPatrick Mooney  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
224c87aefeSPatrick Mooney  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
234c87aefeSPatrick Mooney  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
244c87aefeSPatrick Mooney  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
254c87aefeSPatrick Mooney  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
264c87aefeSPatrick Mooney  * SUCH DAMAGE.
274c87aefeSPatrick Mooney  */
284c87aefeSPatrick Mooney 
294c87aefeSPatrick Mooney /*
304c87aefeSPatrick Mooney  * bhyve ACPI table generator.
314c87aefeSPatrick Mooney  *
324c87aefeSPatrick Mooney  * Create the minimal set of ACPI tables required to boot FreeBSD (and
3359d65d31SAndy Fiddaman  * hopefully other o/s's).
344c87aefeSPatrick Mooney  *
354c87aefeSPatrick Mooney  * The tables are placed in the guest's ROM area just below 1MB physical,
364c87aefeSPatrick Mooney  * above the MPTable.
374c87aefeSPatrick Mooney  */
384c87aefeSPatrick Mooney 
394c87aefeSPatrick Mooney #include <sys/cdefs.h>
404c87aefeSPatrick Mooney 
414c87aefeSPatrick Mooney #include <sys/param.h>
4259d65d31SAndy Fiddaman #include <sys/endian.h>
434c87aefeSPatrick Mooney #include <sys/errno.h>
444c87aefeSPatrick Mooney #include <sys/stat.h>
454c87aefeSPatrick Mooney 
4659d65d31SAndy Fiddaman #include <err.h>
474c87aefeSPatrick Mooney #include <paths.h>
484c87aefeSPatrick Mooney #include <stdarg.h>
4959d65d31SAndy Fiddaman #include <stddef.h>
504c87aefeSPatrick Mooney #include <stdio.h>
514c87aefeSPatrick Mooney #include <stdlib.h>
524c87aefeSPatrick Mooney #include <string.h>
534c87aefeSPatrick Mooney #include <unistd.h>
544c87aefeSPatrick Mooney 
554c87aefeSPatrick Mooney #include <machine/vmm.h>
564c87aefeSPatrick Mooney #include <vmmapi.h>
574c87aefeSPatrick Mooney 
584c87aefeSPatrick Mooney #include "bhyverun.h"
594c87aefeSPatrick Mooney #include "acpi.h"
6059d65d31SAndy Fiddaman #include "basl.h"
614c87aefeSPatrick Mooney #include "pci_emul.h"
62154972afSPatrick Mooney #include "vmgenc.h"
634c87aefeSPatrick Mooney 
644c87aefeSPatrick Mooney #define	BHYVE_ASL_TEMPLATE	"bhyve.XXXXXXX"
654c87aefeSPatrick Mooney #define BHYVE_ASL_SUFFIX	".aml"
664c87aefeSPatrick Mooney #define BHYVE_ASL_COMPILER	"/usr/sbin/iasl"
674c87aefeSPatrick Mooney 
6859d65d31SAndy Fiddaman #define BHYVE_ADDRESS_IOAPIC 	0xFEC00000
6959d65d31SAndy Fiddaman #define BHYVE_ADDRESS_HPET 	0xFED00000
7059d65d31SAndy Fiddaman #define BHYVE_ADDRESS_LAPIC 	0xFEE00000
7159d65d31SAndy Fiddaman 
724c87aefeSPatrick Mooney static int basl_keep_temps;
734c87aefeSPatrick Mooney static int basl_verbose_iasl;
744c87aefeSPatrick Mooney static int basl_ncpu;
754c87aefeSPatrick Mooney static uint32_t hpet_capabilities;
764c87aefeSPatrick Mooney 
774c87aefeSPatrick Mooney /*
784c87aefeSPatrick Mooney  * Contains the full pathname of the template to be passed
794c87aefeSPatrick Mooney  * to mkstemp/mktemps(3)
804c87aefeSPatrick Mooney  */
814c87aefeSPatrick Mooney static char basl_template[MAXPATHLEN];
824c87aefeSPatrick Mooney static char basl_stemplate[MAXPATHLEN];
834c87aefeSPatrick Mooney 
844c87aefeSPatrick Mooney /*
854c87aefeSPatrick Mooney  * State for dsdt_line(), dsdt_indent(), and dsdt_unindent().
864c87aefeSPatrick Mooney  */
874c87aefeSPatrick Mooney static FILE *dsdt_fp;
884c87aefeSPatrick Mooney static int dsdt_indent_level;
894c87aefeSPatrick Mooney static int dsdt_error;
904c87aefeSPatrick Mooney 
914c87aefeSPatrick Mooney struct basl_fio {
924c87aefeSPatrick Mooney 	int	fd;
934c87aefeSPatrick Mooney 	FILE	*fp;
944c87aefeSPatrick Mooney 	char	f_name[MAXPATHLEN];
954c87aefeSPatrick Mooney };
964c87aefeSPatrick Mooney 
974c87aefeSPatrick Mooney #define EFPRINTF(...) \
98*32640292SAndy Fiddaman 	if (fprintf(__VA_ARGS__) < 0) goto err_exit
994c87aefeSPatrick Mooney 
1004c87aefeSPatrick Mooney #define EFFLUSH(x) \
101*32640292SAndy Fiddaman 	if (fflush(x) != 0) goto err_exit
102*32640292SAndy Fiddaman 
103*32640292SAndy Fiddaman /*
104*32640292SAndy Fiddaman  * A list for additional ACPI devices like a TPM.
105*32640292SAndy Fiddaman  */
106*32640292SAndy Fiddaman struct acpi_device_list_entry {
107*32640292SAndy Fiddaman 	SLIST_ENTRY(acpi_device_list_entry) chain;
108*32640292SAndy Fiddaman 	const struct acpi_device *dev;
109*32640292SAndy Fiddaman };
110*32640292SAndy Fiddaman static SLIST_HEAD(acpi_device_list,
111*32640292SAndy Fiddaman     acpi_device_list_entry) acpi_devices = SLIST_HEAD_INITIALIZER(acpi_devices);
112*32640292SAndy Fiddaman 
113*32640292SAndy Fiddaman int
acpi_tables_add_device(const struct acpi_device * const dev)114*32640292SAndy Fiddaman acpi_tables_add_device(const struct acpi_device *const dev)
115*32640292SAndy Fiddaman {
116*32640292SAndy Fiddaman 	struct acpi_device_list_entry *const entry = calloc(1, sizeof(*entry));
117*32640292SAndy Fiddaman 	if (entry == NULL) {
118*32640292SAndy Fiddaman 		return (ENOMEM);
119*32640292SAndy Fiddaman 	}
120*32640292SAndy Fiddaman 
121*32640292SAndy Fiddaman 	entry->dev = dev;
122*32640292SAndy Fiddaman 	SLIST_INSERT_HEAD(&acpi_devices, entry, chain);
123*32640292SAndy Fiddaman 
124*32640292SAndy Fiddaman 	return (0);
125*32640292SAndy Fiddaman }
1264c87aefeSPatrick Mooney 
1274c87aefeSPatrick Mooney /*
1284c87aefeSPatrick Mooney  * Helper routines for writing to the DSDT from other modules.
1294c87aefeSPatrick Mooney  */
1304c87aefeSPatrick Mooney void
dsdt_line(const char * fmt,...)1314c87aefeSPatrick Mooney dsdt_line(const char *fmt, ...)
1324c87aefeSPatrick Mooney {
1334c87aefeSPatrick Mooney 	va_list ap;
1344c87aefeSPatrick Mooney 
1354c87aefeSPatrick Mooney 	if (dsdt_error != 0)
1364c87aefeSPatrick Mooney 		return;
1374c87aefeSPatrick Mooney 
1384c87aefeSPatrick Mooney 	if (strcmp(fmt, "") != 0) {
1394c87aefeSPatrick Mooney 		if (dsdt_indent_level != 0)
1404c87aefeSPatrick Mooney 			EFPRINTF(dsdt_fp, "%*c", dsdt_indent_level * 2, ' ');
1414c87aefeSPatrick Mooney 		va_start(ap, fmt);
1424c87aefeSPatrick Mooney 		if (vfprintf(dsdt_fp, fmt, ap) < 0) {
1434c87aefeSPatrick Mooney 			va_end(ap);
1444c87aefeSPatrick Mooney 			goto err_exit;
1454c87aefeSPatrick Mooney 		}
1464c87aefeSPatrick Mooney 		va_end(ap);
1474c87aefeSPatrick Mooney 	}
1484c87aefeSPatrick Mooney 	EFPRINTF(dsdt_fp, "\n");
1494c87aefeSPatrick Mooney 	return;
1504c87aefeSPatrick Mooney 
1514c87aefeSPatrick Mooney err_exit:
1524c87aefeSPatrick Mooney 	dsdt_error = errno;
1534c87aefeSPatrick Mooney }
1544c87aefeSPatrick Mooney 
1554c87aefeSPatrick Mooney void
dsdt_indent(int levels)1564c87aefeSPatrick Mooney dsdt_indent(int levels)
1574c87aefeSPatrick Mooney {
1584c87aefeSPatrick Mooney 
1594c87aefeSPatrick Mooney 	dsdt_indent_level += levels;
1604c87aefeSPatrick Mooney 	assert(dsdt_indent_level >= 0);
1614c87aefeSPatrick Mooney }
1624c87aefeSPatrick Mooney 
1634c87aefeSPatrick Mooney void
dsdt_unindent(int levels)1644c87aefeSPatrick Mooney dsdt_unindent(int levels)
1654c87aefeSPatrick Mooney {
1664c87aefeSPatrick Mooney 
1674c87aefeSPatrick Mooney 	assert(dsdt_indent_level >= levels);
1684c87aefeSPatrick Mooney 	dsdt_indent_level -= levels;
1694c87aefeSPatrick Mooney }
1704c87aefeSPatrick Mooney 
1714c87aefeSPatrick Mooney void
dsdt_fixed_ioport(uint16_t iobase,uint16_t length)1724c87aefeSPatrick Mooney dsdt_fixed_ioport(uint16_t iobase, uint16_t length)
1734c87aefeSPatrick Mooney {
1744c87aefeSPatrick Mooney 
1754c87aefeSPatrick Mooney 	dsdt_line("IO (Decode16,");
1764c87aefeSPatrick Mooney 	dsdt_line("  0x%04X,             // Range Minimum", iobase);
1774c87aefeSPatrick Mooney 	dsdt_line("  0x%04X,             // Range Maximum", iobase);
1784c87aefeSPatrick Mooney 	dsdt_line("  0x01,               // Alignment");
1794c87aefeSPatrick Mooney 	dsdt_line("  0x%02X,               // Length", length);
1804c87aefeSPatrick Mooney 	dsdt_line("  )");
1814c87aefeSPatrick Mooney }
1824c87aefeSPatrick Mooney 
1834c87aefeSPatrick Mooney void
dsdt_fixed_irq(uint8_t irq)1844c87aefeSPatrick Mooney dsdt_fixed_irq(uint8_t irq)
1854c87aefeSPatrick Mooney {
1864c87aefeSPatrick Mooney 
1874c87aefeSPatrick Mooney 	dsdt_line("IRQNoFlags ()");
1884c87aefeSPatrick Mooney 	dsdt_line("  {%d}", irq);
1894c87aefeSPatrick Mooney }
1904c87aefeSPatrick Mooney 
1914c87aefeSPatrick Mooney void
dsdt_fixed_mem32(uint32_t base,uint32_t length)1924c87aefeSPatrick Mooney dsdt_fixed_mem32(uint32_t base, uint32_t length)
1934c87aefeSPatrick Mooney {
1944c87aefeSPatrick Mooney 
1954c87aefeSPatrick Mooney 	dsdt_line("Memory32Fixed (ReadWrite,");
1964c87aefeSPatrick Mooney 	dsdt_line("  0x%08X,         // Address Base", base);
1974c87aefeSPatrick Mooney 	dsdt_line("  0x%08X,         // Address Length", length);
1984c87aefeSPatrick Mooney 	dsdt_line("  )");
1994c87aefeSPatrick Mooney }
2004c87aefeSPatrick Mooney 
2014c87aefeSPatrick Mooney static int
basl_fwrite_dsdt(FILE * fp)2024c87aefeSPatrick Mooney basl_fwrite_dsdt(FILE *fp)
2034c87aefeSPatrick Mooney {
2044c87aefeSPatrick Mooney 	dsdt_fp = fp;
2054c87aefeSPatrick Mooney 	dsdt_error = 0;
2064c87aefeSPatrick Mooney 	dsdt_indent_level = 0;
2074c87aefeSPatrick Mooney 
2084c87aefeSPatrick Mooney 	dsdt_line("/*");
2094c87aefeSPatrick Mooney 	dsdt_line(" * bhyve DSDT template");
2104c87aefeSPatrick Mooney 	dsdt_line(" */");
2114c87aefeSPatrick Mooney 	dsdt_line("DefinitionBlock (\"bhyve_dsdt.aml\", \"DSDT\", 2,"
2124c87aefeSPatrick Mooney 		 "\"BHYVE \", \"BVDSDT  \", 0x00000001)");
2134c87aefeSPatrick Mooney 	dsdt_line("{");
2144c87aefeSPatrick Mooney 	dsdt_line("  Name (_S5, Package ()");
2154c87aefeSPatrick Mooney 	dsdt_line("  {");
2164c87aefeSPatrick Mooney 	dsdt_line("      0x05,");
2174c87aefeSPatrick Mooney 	dsdt_line("      Zero,");
2184c87aefeSPatrick Mooney 	dsdt_line("  })");
2194c87aefeSPatrick Mooney 
2204c87aefeSPatrick Mooney 	pci_write_dsdt();
2214c87aefeSPatrick Mooney 
2224c87aefeSPatrick Mooney 	dsdt_line("");
2234c87aefeSPatrick Mooney 	dsdt_line("  Scope (_SB.PC00)");
2244c87aefeSPatrick Mooney 	dsdt_line("  {");
2254c87aefeSPatrick Mooney 	dsdt_line("    Device (HPET)");
2264c87aefeSPatrick Mooney 	dsdt_line("    {");
2274c87aefeSPatrick Mooney 	dsdt_line("      Name (_HID, EISAID(\"PNP0103\"))");
2284c87aefeSPatrick Mooney 	dsdt_line("      Name (_UID, 0)");
2294c87aefeSPatrick Mooney 	dsdt_line("      Name (_CRS, ResourceTemplate ()");
2304c87aefeSPatrick Mooney 	dsdt_line("      {");
2314c87aefeSPatrick Mooney 	dsdt_indent(4);
2324c87aefeSPatrick Mooney 	dsdt_fixed_mem32(0xFED00000, 0x400);
2334c87aefeSPatrick Mooney 	dsdt_unindent(4);
2344c87aefeSPatrick Mooney 	dsdt_line("      })");
2354c87aefeSPatrick Mooney 	dsdt_line("    }");
2364c87aefeSPatrick Mooney 	dsdt_line("  }");
237154972afSPatrick Mooney 
238154972afSPatrick Mooney 	vmgenc_write_dsdt();
239154972afSPatrick Mooney 
240*32640292SAndy Fiddaman 	const struct acpi_device_list_entry *entry;
241*32640292SAndy Fiddaman 	SLIST_FOREACH(entry, &acpi_devices, chain) {
242*32640292SAndy Fiddaman 		BASL_EXEC(acpi_device_write_dsdt(entry->dev));
243*32640292SAndy Fiddaman 	}
244*32640292SAndy Fiddaman 
2454c87aefeSPatrick Mooney 	dsdt_line("}");
2464c87aefeSPatrick Mooney 
2474c87aefeSPatrick Mooney 	if (dsdt_error != 0)
2484c87aefeSPatrick Mooney 		return (dsdt_error);
2494c87aefeSPatrick Mooney 
2504c87aefeSPatrick Mooney 	EFFLUSH(fp);
2514c87aefeSPatrick Mooney 
2524c87aefeSPatrick Mooney 	return (0);
2534c87aefeSPatrick Mooney 
2544c87aefeSPatrick Mooney err_exit:
2554c87aefeSPatrick Mooney 	return (errno);
2564c87aefeSPatrick Mooney }
2574c87aefeSPatrick Mooney 
2584c87aefeSPatrick Mooney static int
basl_open(struct basl_fio * bf,int suffix)2594c87aefeSPatrick Mooney basl_open(struct basl_fio *bf, int suffix)
2604c87aefeSPatrick Mooney {
2614c87aefeSPatrick Mooney 	int err;
2624c87aefeSPatrick Mooney 
2634c87aefeSPatrick Mooney 	err = 0;
2644c87aefeSPatrick Mooney 
2654c87aefeSPatrick Mooney 	if (suffix) {
2664c87aefeSPatrick Mooney 		strlcpy(bf->f_name, basl_stemplate, MAXPATHLEN);
2674c87aefeSPatrick Mooney 		bf->fd = mkstemps(bf->f_name, strlen(BHYVE_ASL_SUFFIX));
2684c87aefeSPatrick Mooney 	} else {
2694c87aefeSPatrick Mooney 		strlcpy(bf->f_name, basl_template, MAXPATHLEN);
2704c87aefeSPatrick Mooney 		bf->fd = mkstemp(bf->f_name);
2714c87aefeSPatrick Mooney 	}
2724c87aefeSPatrick Mooney 
2734c87aefeSPatrick Mooney 	if (bf->fd > 0) {
2744c87aefeSPatrick Mooney 		bf->fp = fdopen(bf->fd, "w+");
2754c87aefeSPatrick Mooney 		if (bf->fp == NULL) {
2764c87aefeSPatrick Mooney 			unlink(bf->f_name);
2774c87aefeSPatrick Mooney 			close(bf->fd);
2784c87aefeSPatrick Mooney 		}
2794c87aefeSPatrick Mooney 	} else {
2804c87aefeSPatrick Mooney 		err = 1;
2814c87aefeSPatrick Mooney 	}
2824c87aefeSPatrick Mooney 
2834c87aefeSPatrick Mooney 	return (err);
2844c87aefeSPatrick Mooney }
2854c87aefeSPatrick Mooney 
2864c87aefeSPatrick Mooney static void
basl_close(struct basl_fio * bf)2874c87aefeSPatrick Mooney basl_close(struct basl_fio *bf)
2884c87aefeSPatrick Mooney {
2894c87aefeSPatrick Mooney 
2904c87aefeSPatrick Mooney 	if (!basl_keep_temps)
2914c87aefeSPatrick Mooney 		unlink(bf->f_name);
2924c87aefeSPatrick Mooney 	fclose(bf->fp);
2934c87aefeSPatrick Mooney }
2944c87aefeSPatrick Mooney 
2954c87aefeSPatrick Mooney static int
basl_start(struct basl_fio * in,struct basl_fio * out)2964c87aefeSPatrick Mooney basl_start(struct basl_fio *in, struct basl_fio *out)
2974c87aefeSPatrick Mooney {
2984c87aefeSPatrick Mooney 	int err;
2994c87aefeSPatrick Mooney 
3004c87aefeSPatrick Mooney 	err = basl_open(in, 0);
3014c87aefeSPatrick Mooney 	if (!err) {
3024c87aefeSPatrick Mooney 		err = basl_open(out, 1);
3034c87aefeSPatrick Mooney 		if (err) {
3044c87aefeSPatrick Mooney 			basl_close(in);
3054c87aefeSPatrick Mooney 		}
3064c87aefeSPatrick Mooney 	}
3074c87aefeSPatrick Mooney 
3084c87aefeSPatrick Mooney 	return (err);
3094c87aefeSPatrick Mooney }
3104c87aefeSPatrick Mooney 
3114c87aefeSPatrick Mooney static void
basl_end(struct basl_fio * in,struct basl_fio * out)3124c87aefeSPatrick Mooney basl_end(struct basl_fio *in, struct basl_fio *out)
3134c87aefeSPatrick Mooney {
3144c87aefeSPatrick Mooney 
3154c87aefeSPatrick Mooney 	basl_close(in);
3164c87aefeSPatrick Mooney 	basl_close(out);
3174c87aefeSPatrick Mooney }
3184c87aefeSPatrick Mooney 
3194c87aefeSPatrick Mooney static int
basl_load(struct vmctx * ctx,int fd)32059d65d31SAndy Fiddaman basl_load(struct vmctx *ctx, int fd)
3214c87aefeSPatrick Mooney {
3224c87aefeSPatrick Mooney 	struct stat sb;
32359d65d31SAndy Fiddaman 	void *addr;
3244c87aefeSPatrick Mooney 
3254c87aefeSPatrick Mooney 	if (fstat(fd, &sb) < 0)
3264c87aefeSPatrick Mooney 		return (errno);
3274c87aefeSPatrick Mooney 
32859d65d31SAndy Fiddaman 	addr = calloc(1, sb.st_size);
32959d65d31SAndy Fiddaman 	if (addr == NULL)
3304c87aefeSPatrick Mooney 		return (EFAULT);
3314c87aefeSPatrick Mooney 
33259d65d31SAndy Fiddaman 	if (read(fd, addr, sb.st_size) < 0)
3334c87aefeSPatrick Mooney 		return (errno);
3344c87aefeSPatrick Mooney 
33559d65d31SAndy Fiddaman 	struct basl_table *table;
33659d65d31SAndy Fiddaman 
33759d65d31SAndy Fiddaman 	uint8_t name[ACPI_NAMESEG_SIZE + 1] = { 0 };
33859d65d31SAndy Fiddaman 	memcpy(name, addr, sizeof(name) - 1 /* last char is '\0' */);
33959d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_create(&table, ctx, name, BASL_TABLE_ALIGNMENT));
34059d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_append_bytes(table, addr, sb.st_size));
34159d65d31SAndy Fiddaman 
3424c87aefeSPatrick Mooney 	return (0);
3434c87aefeSPatrick Mooney }
3444c87aefeSPatrick Mooney 
3454c87aefeSPatrick Mooney static int
basl_compile(struct vmctx * ctx,int (* fwrite_section)(FILE *))34659d65d31SAndy Fiddaman basl_compile(struct vmctx *ctx, int (*fwrite_section)(FILE *))
3474c87aefeSPatrick Mooney {
3484c87aefeSPatrick Mooney 	struct basl_fio io[2];
3494c87aefeSPatrick Mooney 	static char iaslbuf[3*MAXPATHLEN + 10];
3504f3f3e9aSAndy Fiddaman 	const char *fmt;
3514c87aefeSPatrick Mooney 	int err;
3524c87aefeSPatrick Mooney 
3534c87aefeSPatrick Mooney 	err = basl_start(&io[0], &io[1]);
3544c87aefeSPatrick Mooney 	if (!err) {
3554c87aefeSPatrick Mooney 		err = (*fwrite_section)(io[0].fp);
3564c87aefeSPatrick Mooney 
3574c87aefeSPatrick Mooney 		if (!err) {
3584c87aefeSPatrick Mooney 			/*
3594c87aefeSPatrick Mooney 			 * iasl sends the results of the compilation to
3604c87aefeSPatrick Mooney 			 * stdout. Shut this down by using the shell to
3614c87aefeSPatrick Mooney 			 * redirect stdout to /dev/null, unless the user
3624c87aefeSPatrick Mooney 			 * has requested verbose output for debugging
3634c87aefeSPatrick Mooney 			 * purposes
3644c87aefeSPatrick Mooney 			 */
3654c87aefeSPatrick Mooney 			fmt = basl_verbose_iasl ?
3664c87aefeSPatrick Mooney 				"%s -p %s %s" :
3674c87aefeSPatrick Mooney 				"/bin/sh -c \"%s -p %s %s\" 1> /dev/null";
3684c87aefeSPatrick Mooney 
3694c87aefeSPatrick Mooney 			snprintf(iaslbuf, sizeof(iaslbuf),
3704c87aefeSPatrick Mooney 				 fmt,
3714c87aefeSPatrick Mooney 				 BHYVE_ASL_COMPILER,
3724c87aefeSPatrick Mooney 				 io[1].f_name, io[0].f_name);
3734c87aefeSPatrick Mooney 			err = system(iaslbuf);
3744c87aefeSPatrick Mooney 
3754c87aefeSPatrick Mooney 			if (!err) {
3764c87aefeSPatrick Mooney 				/*
3774c87aefeSPatrick Mooney 				 * Copy the aml output file into guest
3784c87aefeSPatrick Mooney 				 * memory at the specified location
3794c87aefeSPatrick Mooney 				 */
38059d65d31SAndy Fiddaman 				err = basl_load(ctx, io[1].fd);
3814c87aefeSPatrick Mooney 			}
3824c87aefeSPatrick Mooney 		}
3834c87aefeSPatrick Mooney 		basl_end(&io[0], &io[1]);
3844c87aefeSPatrick Mooney 	}
3854c87aefeSPatrick Mooney 
3864c87aefeSPatrick Mooney 	return (err);
3874c87aefeSPatrick Mooney }
3884c87aefeSPatrick Mooney 
3894c87aefeSPatrick Mooney static int
basl_make_templates(void)3904c87aefeSPatrick Mooney basl_make_templates(void)
3914c87aefeSPatrick Mooney {
3924c87aefeSPatrick Mooney 	const char *tmpdir;
3934c87aefeSPatrick Mooney 	int err;
3944c87aefeSPatrick Mooney 	int len;
3954c87aefeSPatrick Mooney 
3964c87aefeSPatrick Mooney 	err = 0;
3974c87aefeSPatrick Mooney 
3984c87aefeSPatrick Mooney 	/*
3994c87aefeSPatrick Mooney 	 *
4004c87aefeSPatrick Mooney 	 */
4014c87aefeSPatrick Mooney 	if ((tmpdir = getenv("BHYVE_TMPDIR")) == NULL || *tmpdir == '\0' ||
4024c87aefeSPatrick Mooney 	    (tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0') {
4034c87aefeSPatrick Mooney 		tmpdir = _PATH_TMP;
4044c87aefeSPatrick Mooney 	}
4054c87aefeSPatrick Mooney 
4064c87aefeSPatrick Mooney 	len = strlen(tmpdir);
4074c87aefeSPatrick Mooney 
4084c87aefeSPatrick Mooney 	if ((len + sizeof(BHYVE_ASL_TEMPLATE) + 1) < MAXPATHLEN) {
4094c87aefeSPatrick Mooney 		strcpy(basl_template, tmpdir);
4104c87aefeSPatrick Mooney 		while (len > 0 && basl_template[len - 1] == '/')
4114c87aefeSPatrick Mooney 			len--;
4124c87aefeSPatrick Mooney 		basl_template[len] = '/';
4134c87aefeSPatrick Mooney 		strcpy(&basl_template[len + 1], BHYVE_ASL_TEMPLATE);
4144c87aefeSPatrick Mooney 	} else
4154c87aefeSPatrick Mooney 		err = E2BIG;
4164c87aefeSPatrick Mooney 
4174c87aefeSPatrick Mooney 	if (!err) {
4184c87aefeSPatrick Mooney 		/*
419*32640292SAndy Fiddaman 		 * len has been initialized (and maybe adjusted) above
4204c87aefeSPatrick Mooney 		 */
4214c87aefeSPatrick Mooney 		if ((len + sizeof(BHYVE_ASL_TEMPLATE) + 1 +
4224c87aefeSPatrick Mooney 		     sizeof(BHYVE_ASL_SUFFIX)) < MAXPATHLEN) {
4234c87aefeSPatrick Mooney 			strcpy(basl_stemplate, tmpdir);
4244c87aefeSPatrick Mooney 			basl_stemplate[len] = '/';
4254c87aefeSPatrick Mooney 			strcpy(&basl_stemplate[len + 1], BHYVE_ASL_TEMPLATE);
4264c87aefeSPatrick Mooney 			len = strlen(basl_stemplate);
4274c87aefeSPatrick Mooney 			strcpy(&basl_stemplate[len], BHYVE_ASL_SUFFIX);
4284c87aefeSPatrick Mooney 		} else
4294c87aefeSPatrick Mooney 			err = E2BIG;
4304c87aefeSPatrick Mooney 	}
4314c87aefeSPatrick Mooney 
4324c87aefeSPatrick Mooney 	return (err);
4334c87aefeSPatrick Mooney }
4344c87aefeSPatrick Mooney 
43559d65d31SAndy Fiddaman static int
build_dsdt(struct vmctx * const ctx)43659d65d31SAndy Fiddaman build_dsdt(struct vmctx *const ctx)
43759d65d31SAndy Fiddaman {
43859d65d31SAndy Fiddaman 	BASL_EXEC(basl_compile(ctx, basl_fwrite_dsdt));
43959d65d31SAndy Fiddaman 
44059d65d31SAndy Fiddaman 	return (0);
44159d65d31SAndy Fiddaman }
44259d65d31SAndy Fiddaman 
44359d65d31SAndy Fiddaman static int
build_facs(struct vmctx * const ctx)44459d65d31SAndy Fiddaman build_facs(struct vmctx *const ctx)
44559d65d31SAndy Fiddaman {
44659d65d31SAndy Fiddaman 	ACPI_TABLE_FACS facs;
44759d65d31SAndy Fiddaman 	struct basl_table *table;
44859d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_create(&table, ctx, ACPI_SIG_FACS,
44959d65d31SAndy Fiddaman 	    BASL_TABLE_ALIGNMENT_FACS));
45059d65d31SAndy Fiddaman 
45159d65d31SAndy Fiddaman 	memset(&facs, 0, sizeof(facs));
45259d65d31SAndy Fiddaman 	memcpy(facs.Signature, ACPI_SIG_FACS, ACPI_NAMESEG_SIZE);
45359d65d31SAndy Fiddaman 	facs.Length = sizeof(facs);
45459d65d31SAndy Fiddaman 	facs.Version = htole32(2);
45559d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_append_bytes(table, &facs, sizeof(facs)));
45659d65d31SAndy Fiddaman 
45759d65d31SAndy Fiddaman 	return (0);
45859d65d31SAndy Fiddaman }
45959d65d31SAndy Fiddaman 
46059d65d31SAndy Fiddaman static int
build_fadt(struct vmctx * const ctx)46159d65d31SAndy Fiddaman build_fadt(struct vmctx *const ctx)
46259d65d31SAndy Fiddaman {
46359d65d31SAndy Fiddaman 	ACPI_TABLE_FADT fadt;
46459d65d31SAndy Fiddaman 	struct basl_table *table;
46559d65d31SAndy Fiddaman 
46659d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_create(&table, ctx, ACPI_SIG_FADT,
46759d65d31SAndy Fiddaman 	    BASL_TABLE_ALIGNMENT));
46859d65d31SAndy Fiddaman 
46959d65d31SAndy Fiddaman 	memset(&fadt, 0, sizeof(fadt));
47059d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_append_header(table, ACPI_SIG_FADT, 5, 1));
47159d65d31SAndy Fiddaman 	fadt.Facs = htole32(0); /* patched by basl */
47259d65d31SAndy Fiddaman 	fadt.Dsdt = htole32(0); /* patched by basl */
47359d65d31SAndy Fiddaman 	fadt.SciInterrupt = htole16(SCI_INT);
47459d65d31SAndy Fiddaman 	fadt.SmiCommand = htole32(SMI_CMD);
47559d65d31SAndy Fiddaman 	fadt.AcpiEnable = BHYVE_ACPI_ENABLE;
47659d65d31SAndy Fiddaman 	fadt.AcpiDisable = BHYVE_ACPI_DISABLE;
47759d65d31SAndy Fiddaman 	fadt.Pm1aEventBlock = htole32(PM1A_EVT_ADDR);
47859d65d31SAndy Fiddaman 	fadt.Pm1aControlBlock = htole32(PM1A_CNT_ADDR);
47959d65d31SAndy Fiddaman 	fadt.PmTimerBlock = htole32(IO_PMTMR);
48059d65d31SAndy Fiddaman 	fadt.Gpe0Block = htole32(IO_GPE0_BLK);
48159d65d31SAndy Fiddaman 	fadt.Pm1EventLength = 4;
48259d65d31SAndy Fiddaman 	fadt.Pm1ControlLength = 2;
48359d65d31SAndy Fiddaman 	fadt.PmTimerLength = 4;
48459d65d31SAndy Fiddaman 	fadt.Gpe0BlockLength = IO_GPE0_LEN;
48559d65d31SAndy Fiddaman 	fadt.Century = 0x32;
48659d65d31SAndy Fiddaman 	fadt.BootFlags = htole16(ACPI_FADT_NO_VGA | ACPI_FADT_NO_ASPM);
48759d65d31SAndy Fiddaman 	fadt.Flags = htole32(ACPI_FADT_WBINVD | ACPI_FADT_C1_SUPPORTED |
48859d65d31SAndy Fiddaman 	    ACPI_FADT_SLEEP_BUTTON | ACPI_FADT_32BIT_TIMER |
48959d65d31SAndy Fiddaman 	    ACPI_FADT_RESET_REGISTER | ACPI_FADT_HEADLESS |
49059d65d31SAndy Fiddaman 	    ACPI_FADT_APIC_PHYSICAL);
49159d65d31SAndy Fiddaman 	basl_fill_gas(&fadt.ResetRegister, ACPI_ADR_SPACE_SYSTEM_IO, 8, 0,
49259d65d31SAndy Fiddaman 	    ACPI_GAS_ACCESS_WIDTH_BYTE, 0xCF9);
49359d65d31SAndy Fiddaman 	fadt.ResetValue = 6;
49459d65d31SAndy Fiddaman 	fadt.MinorRevision = 1;
49559d65d31SAndy Fiddaman 	fadt.XFacs = htole64(0); /* patched by basl */
49659d65d31SAndy Fiddaman 	fadt.XDsdt = htole64(0); /* patched by basl */
49759d65d31SAndy Fiddaman 	basl_fill_gas(&fadt.XPm1aEventBlock, ACPI_ADR_SPACE_SYSTEM_IO, 0x20, 0,
49859d65d31SAndy Fiddaman 	    ACPI_GAS_ACCESS_WIDTH_WORD, PM1A_EVT_ADDR);
49959d65d31SAndy Fiddaman 	basl_fill_gas(&fadt.XPm1bEventBlock, ACPI_ADR_SPACE_SYSTEM_IO, 0, 0,
50059d65d31SAndy Fiddaman 	    ACPI_GAS_ACCESS_WIDTH_UNDEFINED, 0);
50159d65d31SAndy Fiddaman 	basl_fill_gas(&fadt.XPm1aControlBlock, ACPI_ADR_SPACE_SYSTEM_IO, 0x10,
50259d65d31SAndy Fiddaman 	    0, ACPI_GAS_ACCESS_WIDTH_WORD, PM1A_CNT_ADDR);
50359d65d31SAndy Fiddaman 	basl_fill_gas(&fadt.XPm1bControlBlock, ACPI_ADR_SPACE_SYSTEM_IO, 0, 0,
50459d65d31SAndy Fiddaman 	    ACPI_GAS_ACCESS_WIDTH_UNDEFINED, 0);
50559d65d31SAndy Fiddaman 	basl_fill_gas(&fadt.XPm2ControlBlock, ACPI_ADR_SPACE_SYSTEM_IO, 8, 0,
50659d65d31SAndy Fiddaman 	    ACPI_GAS_ACCESS_WIDTH_UNDEFINED, 0);
50759d65d31SAndy Fiddaman 	basl_fill_gas(&fadt.XPmTimerBlock, ACPI_ADR_SPACE_SYSTEM_IO, 0x20, 0,
50859d65d31SAndy Fiddaman 	    ACPI_GAS_ACCESS_WIDTH_DWORD, IO_PMTMR);
50959d65d31SAndy Fiddaman 	basl_fill_gas(&fadt.XGpe0Block, ACPI_ADR_SPACE_SYSTEM_IO,
51059d65d31SAndy Fiddaman 	    IO_GPE0_LEN * 8, 0, ACPI_GAS_ACCESS_WIDTH_BYTE, IO_GPE0_BLK);
51159d65d31SAndy Fiddaman 	basl_fill_gas(&fadt.XGpe1Block, ACPI_ADR_SPACE_SYSTEM_IO, 0, 0,
51259d65d31SAndy Fiddaman 	    ACPI_GAS_ACCESS_WIDTH_UNDEFINED, 0);
51359d65d31SAndy Fiddaman 	basl_fill_gas(&fadt.SleepControl, ACPI_ADR_SPACE_SYSTEM_IO, 8, 0,
51459d65d31SAndy Fiddaman 	    ACPI_GAS_ACCESS_WIDTH_BYTE, 0);
51559d65d31SAndy Fiddaman 	basl_fill_gas(&fadt.SleepStatus, ACPI_ADR_SPACE_SYSTEM_IO, 8, 0,
51659d65d31SAndy Fiddaman 	    ACPI_GAS_ACCESS_WIDTH_BYTE, 0);
51759d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_append_content(table, &fadt, sizeof(fadt)));
51859d65d31SAndy Fiddaman 
51959d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_add_pointer(table, ACPI_SIG_FACS,
52059d65d31SAndy Fiddaman 	    offsetof(ACPI_TABLE_FADT, Facs), sizeof(fadt.Facs)));
52159d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_add_pointer(table, ACPI_SIG_DSDT,
52259d65d31SAndy Fiddaman 	    offsetof(ACPI_TABLE_FADT, Dsdt), sizeof(fadt.Dsdt)));
52359d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_add_pointer(table, ACPI_SIG_FACS,
52459d65d31SAndy Fiddaman 	    offsetof(ACPI_TABLE_FADT, XFacs), sizeof(fadt.XFacs)));
52559d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_add_pointer(table, ACPI_SIG_DSDT,
52659d65d31SAndy Fiddaman 	    offsetof(ACPI_TABLE_FADT, XDsdt), sizeof(fadt.XDsdt)));
52759d65d31SAndy Fiddaman 
528*32640292SAndy Fiddaman 	BASL_EXEC(basl_table_register_to_rsdt(table));
52959d65d31SAndy Fiddaman 
53059d65d31SAndy Fiddaman 	return (0);
53159d65d31SAndy Fiddaman }
53259d65d31SAndy Fiddaman 
53359d65d31SAndy Fiddaman static int
build_hpet(struct vmctx * const ctx)53459d65d31SAndy Fiddaman build_hpet(struct vmctx *const ctx)
53559d65d31SAndy Fiddaman {
53659d65d31SAndy Fiddaman 	ACPI_TABLE_HPET hpet;
53759d65d31SAndy Fiddaman 	struct basl_table *table;
53859d65d31SAndy Fiddaman 
53959d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_create(&table, ctx, ACPI_SIG_HPET,
54059d65d31SAndy Fiddaman 	    BASL_TABLE_ALIGNMENT));
54159d65d31SAndy Fiddaman 
54259d65d31SAndy Fiddaman 	memset(&hpet, 0, sizeof(hpet));
54359d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_append_header(table, ACPI_SIG_HPET, 1, 1));
54459d65d31SAndy Fiddaman 	hpet.Id = htole32(hpet_capabilities);
54559d65d31SAndy Fiddaman 	basl_fill_gas(&hpet.Address, ACPI_ADR_SPACE_SYSTEM_MEMORY, 0, 0,
54659d65d31SAndy Fiddaman 	    ACPI_GAS_ACCESS_WIDTH_LEGACY, BHYVE_ADDRESS_HPET);
54759d65d31SAndy Fiddaman 	hpet.Flags = ACPI_HPET_PAGE_PROTECT4;
54859d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_append_content(table, &hpet, sizeof(hpet)));
54959d65d31SAndy Fiddaman 
550*32640292SAndy Fiddaman 	BASL_EXEC(basl_table_register_to_rsdt(table));
55159d65d31SAndy Fiddaman 
55259d65d31SAndy Fiddaman 	return (0);
55359d65d31SAndy Fiddaman }
55459d65d31SAndy Fiddaman 
55559d65d31SAndy Fiddaman static int
build_madt(struct vmctx * const ctx)55659d65d31SAndy Fiddaman build_madt(struct vmctx *const ctx)
55759d65d31SAndy Fiddaman {
55859d65d31SAndy Fiddaman 	ACPI_TABLE_MADT madt;
55959d65d31SAndy Fiddaman 	ACPI_MADT_LOCAL_APIC madt_lapic;
56059d65d31SAndy Fiddaman 	ACPI_MADT_IO_APIC madt_ioapic;
56159d65d31SAndy Fiddaman 	ACPI_MADT_INTERRUPT_OVERRIDE madt_irq_override;
56259d65d31SAndy Fiddaman 	ACPI_MADT_LOCAL_APIC_NMI madt_lapic_nmi;
56359d65d31SAndy Fiddaman 	struct basl_table *table;
56459d65d31SAndy Fiddaman 
56559d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_create(&table, ctx, ACPI_SIG_MADT,
56659d65d31SAndy Fiddaman 	    BASL_TABLE_ALIGNMENT));
56759d65d31SAndy Fiddaman 
56859d65d31SAndy Fiddaman 	memset(&madt, 0, sizeof(madt));
56959d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_append_header(table, ACPI_SIG_MADT, 1, 1));
57059d65d31SAndy Fiddaman 	madt.Address = htole32(BHYVE_ADDRESS_LAPIC);
57159d65d31SAndy Fiddaman 	madt.Flags = htole32(ACPI_MADT_PCAT_COMPAT);
57259d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_append_content(table, &madt, sizeof(madt)));
57359d65d31SAndy Fiddaman 
57459d65d31SAndy Fiddaman 	/* Local APIC for each CPU */
57559d65d31SAndy Fiddaman 	for (int i = 0; i < basl_ncpu; ++i) {
57659d65d31SAndy Fiddaman 		memset(&madt_lapic, 0, sizeof(madt_lapic));
57759d65d31SAndy Fiddaman 		madt_lapic.Header.Type = ACPI_MADT_TYPE_LOCAL_APIC;
57859d65d31SAndy Fiddaman 		madt_lapic.Header.Length = sizeof(madt_lapic);
57959d65d31SAndy Fiddaman 		madt_lapic.ProcessorId = i;
58059d65d31SAndy Fiddaman 		madt_lapic.Id = i;
58159d65d31SAndy Fiddaman 		madt_lapic.LapicFlags = htole32(ACPI_MADT_ENABLED);
58259d65d31SAndy Fiddaman 		BASL_EXEC(basl_table_append_bytes(table, &madt_lapic,
58359d65d31SAndy Fiddaman 		    sizeof(madt_lapic)));
58459d65d31SAndy Fiddaman 	}
58559d65d31SAndy Fiddaman 
58659d65d31SAndy Fiddaman 	/* I/O APIC */
58759d65d31SAndy Fiddaman 	memset(&madt_ioapic, 0, sizeof(madt_ioapic));
58859d65d31SAndy Fiddaman 	madt_ioapic.Header.Type = ACPI_MADT_TYPE_IO_APIC;
58959d65d31SAndy Fiddaman 	madt_ioapic.Header.Length = sizeof(madt_ioapic);
59059d65d31SAndy Fiddaman 	madt_ioapic.Address = htole32(BHYVE_ADDRESS_IOAPIC);
59159d65d31SAndy Fiddaman 	BASL_EXEC(
59259d65d31SAndy Fiddaman 	    basl_table_append_bytes(table, &madt_ioapic, sizeof(madt_ioapic)));
59359d65d31SAndy Fiddaman 
59459d65d31SAndy Fiddaman 	/* Legacy IRQ0 is connected to pin 2 of the I/O APIC */
59559d65d31SAndy Fiddaman 	memset(&madt_irq_override, 0, sizeof(madt_irq_override));
59659d65d31SAndy Fiddaman 	madt_irq_override.Header.Type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE;
59759d65d31SAndy Fiddaman 	madt_irq_override.Header.Length = sizeof(madt_irq_override);
59859d65d31SAndy Fiddaman 	madt_irq_override.GlobalIrq = htole32(2);
59959d65d31SAndy Fiddaman 	madt_irq_override.IntiFlags = htole16(
60059d65d31SAndy Fiddaman 	    ACPI_MADT_POLARITY_ACTIVE_HIGH | ACPI_MADT_TRIGGER_EDGE);
60159d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_append_bytes(table, &madt_irq_override,
60259d65d31SAndy Fiddaman 	    sizeof(madt_irq_override)));
60359d65d31SAndy Fiddaman 
60459d65d31SAndy Fiddaman 	memset(&madt_irq_override, 0, sizeof(madt_irq_override));
60559d65d31SAndy Fiddaman 	madt_irq_override.Header.Type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE;
60659d65d31SAndy Fiddaman 	madt_irq_override.Header.Length = sizeof(madt_irq_override);
60759d65d31SAndy Fiddaman 	madt_irq_override.SourceIrq = SCI_INT;
60859d65d31SAndy Fiddaman 	madt_irq_override.GlobalIrq = htole32(SCI_INT);
60959d65d31SAndy Fiddaman 	madt_irq_override.IntiFlags = htole16(
61059d65d31SAndy Fiddaman 	    ACPI_MADT_POLARITY_ACTIVE_LOW | ACPI_MADT_TRIGGER_LEVEL);
61159d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_append_bytes(table, &madt_irq_override,
61259d65d31SAndy Fiddaman 	    sizeof(madt_irq_override)));
61359d65d31SAndy Fiddaman 
61459d65d31SAndy Fiddaman 	/* Local APIC NMI is conntected to LINT 1 on all CPUs */
61559d65d31SAndy Fiddaman 	memset(&madt_lapic_nmi, 0, sizeof(madt_lapic_nmi));
61659d65d31SAndy Fiddaman 	madt_lapic_nmi.Header.Type = ACPI_MADT_TYPE_LOCAL_APIC_NMI;
61759d65d31SAndy Fiddaman 	madt_lapic_nmi.Header.Length = sizeof(madt_lapic_nmi);
61859d65d31SAndy Fiddaman 	madt_lapic_nmi.ProcessorId = 0xFF;
61959d65d31SAndy Fiddaman 	madt_lapic_nmi.IntiFlags = htole16(
62059d65d31SAndy Fiddaman 	    ACPI_MADT_POLARITY_ACTIVE_HIGH | ACPI_MADT_TRIGGER_EDGE);
62159d65d31SAndy Fiddaman 	madt_lapic_nmi.Lint = 1;
62259d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_append_bytes(table, &madt_lapic_nmi,
62359d65d31SAndy Fiddaman 	    sizeof(madt_lapic_nmi)));
62459d65d31SAndy Fiddaman 
625*32640292SAndy Fiddaman 	BASL_EXEC(basl_table_register_to_rsdt(table));
62659d65d31SAndy Fiddaman 
62759d65d31SAndy Fiddaman 	return (0);
62859d65d31SAndy Fiddaman }
62959d65d31SAndy Fiddaman 
63059d65d31SAndy Fiddaman static int
build_mcfg(struct vmctx * const ctx)63159d65d31SAndy Fiddaman build_mcfg(struct vmctx *const ctx)
63259d65d31SAndy Fiddaman {
63359d65d31SAndy Fiddaman 	ACPI_TABLE_MCFG mcfg;
63459d65d31SAndy Fiddaman 	ACPI_MCFG_ALLOCATION mcfg_allocation;
63559d65d31SAndy Fiddaman 	struct basl_table *table;
63659d65d31SAndy Fiddaman 
63759d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_create(&table, ctx, ACPI_SIG_MCFG,
63859d65d31SAndy Fiddaman 	    BASL_TABLE_ALIGNMENT));
63959d65d31SAndy Fiddaman 
64059d65d31SAndy Fiddaman 	memset(&mcfg, 0, sizeof(mcfg));
64159d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_append_header(table, ACPI_SIG_MCFG, 1, 1));
64259d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_append_content(table, &mcfg, sizeof(mcfg)));
64359d65d31SAndy Fiddaman 
64459d65d31SAndy Fiddaman 	memset(&mcfg_allocation, 0, sizeof(mcfg_allocation));
64559d65d31SAndy Fiddaman 	mcfg_allocation.Address = htole64(pci_ecfg_base());
64659d65d31SAndy Fiddaman 	mcfg_allocation.EndBusNumber = 0xFF;
64759d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_append_bytes(table, &mcfg_allocation,
64859d65d31SAndy Fiddaman 	    sizeof(mcfg_allocation)));
64959d65d31SAndy Fiddaman 
650*32640292SAndy Fiddaman 	BASL_EXEC(basl_table_register_to_rsdt(table));
65159d65d31SAndy Fiddaman 
65259d65d31SAndy Fiddaman 	return (0);
65359d65d31SAndy Fiddaman }
65459d65d31SAndy Fiddaman 
65559d65d31SAndy Fiddaman static int
build_rsdp(struct vmctx * const ctx)65659d65d31SAndy Fiddaman build_rsdp(struct vmctx *const ctx)
65759d65d31SAndy Fiddaman {
65859d65d31SAndy Fiddaman 	ACPI_TABLE_RSDP rsdp;
65959d65d31SAndy Fiddaman 	struct basl_table *table;
66059d65d31SAndy Fiddaman 
66159d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_create(&table, ctx, ACPI_RSDP_NAME,
66259d65d31SAndy Fiddaman 	    BASL_TABLE_ALIGNMENT));
66359d65d31SAndy Fiddaman 
66459d65d31SAndy Fiddaman 	memset(&rsdp, 0, sizeof(rsdp));
66559d65d31SAndy Fiddaman 	memcpy(rsdp.Signature, ACPI_SIG_RSDP, 8);
66659d65d31SAndy Fiddaman 	rsdp.Checksum = 0; /* patched by basl */
66759d65d31SAndy Fiddaman 	memcpy(rsdp.OemId, "BHYVE ", ACPI_OEM_ID_SIZE);
66859d65d31SAndy Fiddaman 	rsdp.Revision = 2;
66959d65d31SAndy Fiddaman 	rsdp.RsdtPhysicalAddress = htole32(0); /* patched by basl */
67059d65d31SAndy Fiddaman 	rsdp.Length = htole32(0);	       /* patched by basl */
67159d65d31SAndy Fiddaman 	rsdp.XsdtPhysicalAddress = htole64(0); /* patched by basl */
67259d65d31SAndy Fiddaman 	rsdp.ExtendedChecksum = 0;	       /* patched by basl */
67359d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_append_bytes(table, &rsdp, sizeof(rsdp)));
67459d65d31SAndy Fiddaman 
67559d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_add_checksum(table,
67659d65d31SAndy Fiddaman 	    offsetof(ACPI_TABLE_RSDP, Checksum), 0, 20));
67759d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_add_pointer(table, ACPI_SIG_RSDT,
67859d65d31SAndy Fiddaman 	    offsetof(ACPI_TABLE_RSDP, RsdtPhysicalAddress),
67959d65d31SAndy Fiddaman 	    sizeof(rsdp.RsdtPhysicalAddress)));
68059d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_add_length(table,
68159d65d31SAndy Fiddaman 	    offsetof(ACPI_TABLE_RSDP, Length), sizeof(rsdp.Length)));
68259d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_add_pointer(table, ACPI_SIG_XSDT,
68359d65d31SAndy Fiddaman 	    offsetof(ACPI_TABLE_RSDP, XsdtPhysicalAddress),
68459d65d31SAndy Fiddaman 	    sizeof(rsdp.XsdtPhysicalAddress)));
68559d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_add_checksum(table,
68659d65d31SAndy Fiddaman 	    offsetof(ACPI_TABLE_RSDP, ExtendedChecksum), 0,
68759d65d31SAndy Fiddaman 	    BASL_TABLE_CHECKSUM_LEN_FULL_TABLE));
68859d65d31SAndy Fiddaman 
68959d65d31SAndy Fiddaman 	return (0);
69059d65d31SAndy Fiddaman }
69159d65d31SAndy Fiddaman 
69259d65d31SAndy Fiddaman static int
build_spcr(struct vmctx * const ctx)69359d65d31SAndy Fiddaman build_spcr(struct vmctx *const ctx)
69459d65d31SAndy Fiddaman {
69559d65d31SAndy Fiddaman 	ACPI_TABLE_SPCR spcr;
69659d65d31SAndy Fiddaman 	struct basl_table *table;
69759d65d31SAndy Fiddaman 
69859d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_create(&table, ctx, ACPI_SIG_SPCR,
69959d65d31SAndy Fiddaman 	    BASL_TABLE_ALIGNMENT));
70059d65d31SAndy Fiddaman 
70159d65d31SAndy Fiddaman 	memset(&spcr, 0, sizeof(spcr));
70259d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_append_header(table, ACPI_SIG_SPCR, 1, 1));
70359d65d31SAndy Fiddaman 	spcr.InterfaceType = ACPI_DBG2_16550_COMPATIBLE;
70459d65d31SAndy Fiddaman 	basl_fill_gas(&spcr.SerialPort, ACPI_ADR_SPACE_SYSTEM_IO, 8, 0,
70559d65d31SAndy Fiddaman 	    ACPI_GAS_ACCESS_WIDTH_LEGACY, 0x3F8);
70659d65d31SAndy Fiddaman 	spcr.InterruptType = ACPI_SPCR_INTERRUPT_TYPE_8259;
70759d65d31SAndy Fiddaman 	spcr.PcInterrupt = 4;
70859d65d31SAndy Fiddaman 	spcr.BaudRate = ACPI_SPCR_BAUD_RATE_115200;
70959d65d31SAndy Fiddaman 	spcr.Parity = ACPI_SPCR_PARITY_NO_PARITY;
71059d65d31SAndy Fiddaman 	spcr.StopBits = ACPI_SPCR_STOP_BITS_1;
71159d65d31SAndy Fiddaman 	spcr.FlowControl = 3; /* RTS/CTS | DCD */
71259d65d31SAndy Fiddaman 	spcr.TerminalType = ACPI_SPCR_TERMINAL_TYPE_VT_UTF8;
71359d65d31SAndy Fiddaman 	BASL_EXEC(basl_table_append_content(table, &spcr, sizeof(spcr)));
71459d65d31SAndy Fiddaman 
715*32640292SAndy Fiddaman 	BASL_EXEC(basl_table_register_to_rsdt(table));
71659d65d31SAndy Fiddaman 
71759d65d31SAndy Fiddaman 	return (0);
71859d65d31SAndy Fiddaman }
71959d65d31SAndy Fiddaman 
7204c87aefeSPatrick Mooney int
acpi_build(struct vmctx * ctx,int ncpu)7214c87aefeSPatrick Mooney acpi_build(struct vmctx *ctx, int ncpu)
7224c87aefeSPatrick Mooney {
7234c87aefeSPatrick Mooney 	int err;
7244c87aefeSPatrick Mooney 
7254c87aefeSPatrick Mooney 	basl_ncpu = ncpu;
7264c87aefeSPatrick Mooney 
7274c87aefeSPatrick Mooney 	err = vm_get_hpet_capabilities(ctx, &hpet_capabilities);
7284c87aefeSPatrick Mooney 	if (err != 0)
7294c87aefeSPatrick Mooney 		return (err);
7304c87aefeSPatrick Mooney 
7314c87aefeSPatrick Mooney 	/*
7324c87aefeSPatrick Mooney 	 * For debug, allow the user to have iasl compiler output sent
7334c87aefeSPatrick Mooney 	 * to stdout rather than /dev/null
7344c87aefeSPatrick Mooney 	 */
7354c87aefeSPatrick Mooney 	if (getenv("BHYVE_ACPI_VERBOSE_IASL"))
7364c87aefeSPatrick Mooney 		basl_verbose_iasl = 1;
7374c87aefeSPatrick Mooney 
7384c87aefeSPatrick Mooney 	/*
7394c87aefeSPatrick Mooney 	 * Allow the user to keep the generated ASL files for debugging
7404c87aefeSPatrick Mooney 	 * instead of deleting them following use
7414c87aefeSPatrick Mooney 	 */
7424c87aefeSPatrick Mooney 	if (getenv("BHYVE_ACPI_KEEPTMPS"))
7434c87aefeSPatrick Mooney 		basl_keep_temps = 1;
7444c87aefeSPatrick Mooney 
745*32640292SAndy Fiddaman 	BASL_EXEC(basl_init(ctx));
74659d65d31SAndy Fiddaman 
74759d65d31SAndy Fiddaman 	BASL_EXEC(basl_make_templates());
7484c87aefeSPatrick Mooney 
7494c87aefeSPatrick Mooney 	/*
75059d65d31SAndy Fiddaman 	 * Generate ACPI tables and copy them into guest memory.
75159d65d31SAndy Fiddaman 	 *
75259d65d31SAndy Fiddaman 	 * According to UEFI Specification v6.3 chapter 5.1 the FADT should be
75359d65d31SAndy Fiddaman 	 * the first table pointed to by XSDT. For that reason, build it as the
75459d65d31SAndy Fiddaman 	 * first table after XSDT.
7554c87aefeSPatrick Mooney 	 */
75659d65d31SAndy Fiddaman 	BASL_EXEC(build_rsdp(ctx));
75759d65d31SAndy Fiddaman 	BASL_EXEC(build_fadt(ctx));
75859d65d31SAndy Fiddaman 	BASL_EXEC(build_madt(ctx));
75959d65d31SAndy Fiddaman 	BASL_EXEC(build_hpet(ctx));
76059d65d31SAndy Fiddaman 	BASL_EXEC(build_mcfg(ctx));
76159d65d31SAndy Fiddaman 	BASL_EXEC(build_facs(ctx));
76259d65d31SAndy Fiddaman 	BASL_EXEC(build_spcr(ctx));
763*32640292SAndy Fiddaman 
764*32640292SAndy Fiddaman 	/* Build ACPI device-specific tables such as a TPM2 table. */
765*32640292SAndy Fiddaman 	const struct acpi_device_list_entry *entry;
766*32640292SAndy Fiddaman 	SLIST_FOREACH(entry, &acpi_devices, chain) {
767*32640292SAndy Fiddaman 		BASL_EXEC(acpi_device_build_table(entry->dev));
768*32640292SAndy Fiddaman 	}
769*32640292SAndy Fiddaman 
77059d65d31SAndy Fiddaman 	BASL_EXEC(build_dsdt(ctx));
7714c87aefeSPatrick Mooney 
77259d65d31SAndy Fiddaman 	BASL_EXEC(basl_finish());
77359d65d31SAndy Fiddaman 
77459d65d31SAndy Fiddaman 	return (0);
7754c87aefeSPatrick Mooney }
776