Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/acpi.c
Show All 30 Lines | |||||
/* | /* | ||||
* bhyve ACPI table generator. | * bhyve ACPI table generator. | ||||
* | * | ||||
* Create the minimal set of ACPI tables required to boot FreeBSD (and | * Create the minimal set of ACPI tables required to boot FreeBSD (and | ||||
* hopefully other o/s's). | * hopefully other o/s's). | ||||
* | * | ||||
* The tables are placed in the guest's ROM area just below 1MB physical, | * The tables are placed in the guest's ROM area just below 1MB physical, | ||||
* above the MPTable. | * above the MPTable. | ||||
* | |||||
* Layout (No longer correct at FADT and beyond due to properly | |||||
* calculating the size of the MADT to allow for changes to | |||||
* VM_MAXCPU above 21 which overflows this layout.) | |||||
* ------ | |||||
* RSDP -> 0xf2400 (36 bytes fixed) | |||||
* RSDT -> 0xf2440 (36 bytes + 4*7 table addrs, 4 used) | |||||
* XSDT -> 0xf2480 (36 bytes + 8*7 table addrs, 4 used) | |||||
* MADT -> 0xf2500 (depends on #CPUs) | |||||
* FADT -> 0xf2600 (268 bytes) | |||||
* HPET -> 0xf2740 (56 bytes) | |||||
* MCFG -> 0xf2780 (60 bytes) | |||||
* FACS -> 0xf27C0 (64 bytes) | |||||
* DSDT -> 0xf2800 (variable - can go up to 0x100000) | |||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/endian.h> | #include <sys/endian.h> | ||||
#include <sys/errno.h> | #include <sys/errno.h> | ||||
Show All 12 Lines | |||||
#include <vmmapi.h> | #include <vmmapi.h> | ||||
#include "bhyverun.h" | #include "bhyverun.h" | ||||
#include "acpi.h" | #include "acpi.h" | ||||
#include "basl.h" | #include "basl.h" | ||||
#include "pci_emul.h" | #include "pci_emul.h" | ||||
#include "vmgenc.h" | #include "vmgenc.h" | ||||
/* | |||||
* Define the base address of the ACPI tables, the sizes of some tables, | |||||
* and the offsets to the individual tables, | |||||
*/ | |||||
#define RSDT_OFFSET 0x040 | |||||
#define XSDT_OFFSET 0x080 | |||||
#define MADT_OFFSET 0x100 | |||||
/* | |||||
* The MADT consists of: | |||||
* 44 Fixed Header | |||||
* 8 * maxcpu Processor Local APIC entries | |||||
* 12 I/O APIC entry | |||||
* 2 * 10 Interrupt Source Override entries | |||||
* 6 Local APIC NMI entry | |||||
*/ | |||||
#define MADT_SIZE roundup2((44 + basl_ncpu*8 + 12 + 2*10 + 6), 0x100) | |||||
#define FADT_OFFSET (MADT_OFFSET + MADT_SIZE) | |||||
#define FADT_SIZE 0x140 | |||||
#define HPET_OFFSET (FADT_OFFSET + FADT_SIZE) | |||||
#define HPET_SIZE 0x40 | |||||
#define MCFG_OFFSET (HPET_OFFSET + HPET_SIZE) | |||||
#define MCFG_SIZE 0x40 | |||||
#define FACS_OFFSET (MCFG_OFFSET + MCFG_SIZE) | |||||
#define FACS_SIZE 0x40 | |||||
#define DSDT_OFFSET (FACS_OFFSET + FACS_SIZE) | |||||
#define BHYVE_ASL_TEMPLATE "bhyve.XXXXXXX" | #define BHYVE_ASL_TEMPLATE "bhyve.XXXXXXX" | ||||
#define BHYVE_ASL_SUFFIX ".aml" | #define BHYVE_ASL_SUFFIX ".aml" | ||||
#define BHYVE_ASL_COMPILER "/usr/sbin/iasl" | #define BHYVE_ASL_COMPILER "/usr/sbin/iasl" | ||||
#define BHYVE_ADDRESS_IOAPIC 0xFEC00000 | #define BHYVE_ADDRESS_IOAPIC 0xFEC00000 | ||||
#define BHYVE_ADDRESS_HPET 0xFED00000 | #define BHYVE_ADDRESS_HPET 0xFED00000 | ||||
#define BHYVE_ADDRESS_LAPIC 0xFEE00000 | #define BHYVE_ADDRESS_LAPIC 0xFEE00000 | ||||
▲ Show 20 Lines • Show All 214 Lines • ▼ Show 20 Lines | |||||
basl_end(struct basl_fio *in, struct basl_fio *out) | basl_end(struct basl_fio *in, struct basl_fio *out) | ||||
{ | { | ||||
basl_close(in); | basl_close(in); | ||||
basl_close(out); | basl_close(out); | ||||
} | } | ||||
static int | static int | ||||
basl_load(struct vmctx *ctx, int fd, uint64_t off) | basl_load(struct vmctx *ctx, int fd) | ||||
{ | { | ||||
struct stat sb; | struct stat sb; | ||||
void *addr; | void *addr; | ||||
if (fstat(fd, &sb) < 0) | if (fstat(fd, &sb) < 0) | ||||
return (errno); | return (errno); | ||||
addr = calloc(1, sb.st_size); | addr = calloc(1, sb.st_size); | ||||
if (addr == NULL) | if (addr == NULL) | ||||
return (EFAULT); | return (EFAULT); | ||||
if (read(fd, addr, sb.st_size) < 0) | if (read(fd, addr, sb.st_size) < 0) | ||||
return (errno); | return (errno); | ||||
struct basl_table *table; | struct basl_table *table; | ||||
uint8_t name[ACPI_NAMESEG_SIZE + 1] = { 0 }; | uint8_t name[ACPI_NAMESEG_SIZE + 1] = { 0 }; | ||||
memcpy(name, addr, sizeof(name) - 1 /* last char is '\0' */); | memcpy(name, addr, sizeof(name) - 1 /* last char is '\0' */); | ||||
BASL_EXEC( | BASL_EXEC(basl_table_create(&table, ctx, name, BASL_TABLE_ALIGNMENT)); | ||||
basl_table_create(&table, ctx, name, BASL_TABLE_ALIGNMENT, off)); | |||||
BASL_EXEC(basl_table_append_bytes(table, addr, sb.st_size)); | BASL_EXEC(basl_table_append_bytes(table, addr, sb.st_size)); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
basl_compile(struct vmctx *ctx, int (*fwrite_section)(FILE *), uint64_t offset) | basl_compile(struct vmctx *ctx, int (*fwrite_section)(FILE *)) | ||||
{ | { | ||||
struct basl_fio io[2]; | struct basl_fio io[2]; | ||||
static char iaslbuf[3*MAXPATHLEN + 10]; | static char iaslbuf[3*MAXPATHLEN + 10]; | ||||
const char *fmt; | const char *fmt; | ||||
int err; | int err; | ||||
err = basl_start(&io[0], &io[1]); | err = basl_start(&io[0], &io[1]); | ||||
if (!err) { | if (!err) { | ||||
Show All 17 Lines | if (!err) { | ||||
io[1].f_name, io[0].f_name); | io[1].f_name, io[0].f_name); | ||||
err = system(iaslbuf); | err = system(iaslbuf); | ||||
if (!err) { | if (!err) { | ||||
/* | /* | ||||
* Copy the aml output file into guest | * Copy the aml output file into guest | ||||
* memory at the specified location | * memory at the specified location | ||||
*/ | */ | ||||
err = basl_load(ctx, io[1].fd, offset); | err = basl_load(ctx, io[1].fd); | ||||
} | } | ||||
} | } | ||||
basl_end(&io[0], &io[1]); | basl_end(&io[0], &io[1]); | ||||
} | } | ||||
return (err); | return (err); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | basl_make_templates(void) | ||||
} | } | ||||
return (err); | return (err); | ||||
} | } | ||||
static int | static int | ||||
build_dsdt(struct vmctx *const ctx) | build_dsdt(struct vmctx *const ctx) | ||||
{ | { | ||||
BASL_EXEC(basl_compile(ctx, basl_fwrite_dsdt, DSDT_OFFSET)); | BASL_EXEC(basl_compile(ctx, basl_fwrite_dsdt)); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
build_facs(struct vmctx *const ctx) | build_facs(struct vmctx *const ctx) | ||||
{ | { | ||||
ACPI_TABLE_FACS facs; | ACPI_TABLE_FACS facs; | ||||
struct basl_table *table; | struct basl_table *table; | ||||
BASL_EXEC(basl_table_create(&table, ctx, ACPI_SIG_FACS, | BASL_EXEC(basl_table_create(&table, ctx, ACPI_SIG_FACS, | ||||
BASL_TABLE_ALIGNMENT_FACS, FACS_OFFSET)); | BASL_TABLE_ALIGNMENT_FACS)); | ||||
memset(&facs, 0, sizeof(facs)); | memset(&facs, 0, sizeof(facs)); | ||||
memcpy(facs.Signature, ACPI_SIG_FACS, ACPI_NAMESEG_SIZE); | memcpy(facs.Signature, ACPI_SIG_FACS, ACPI_NAMESEG_SIZE); | ||||
facs.Length = sizeof(facs); | facs.Length = sizeof(facs); | ||||
facs.Version = htole32(2); | facs.Version = htole32(2); | ||||
BASL_EXEC(basl_table_append_bytes(table, &facs, sizeof(facs))); | BASL_EXEC(basl_table_append_bytes(table, &facs, sizeof(facs))); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
build_fadt(struct vmctx *const ctx) | build_fadt(struct vmctx *const ctx) | ||||
{ | { | ||||
ACPI_TABLE_FADT fadt; | ACPI_TABLE_FADT fadt; | ||||
struct basl_table *table; | struct basl_table *table; | ||||
BASL_EXEC(basl_table_create(&table, ctx, ACPI_SIG_FADT, | BASL_EXEC(basl_table_create(&table, ctx, ACPI_SIG_FADT, | ||||
BASL_TABLE_ALIGNMENT, FADT_OFFSET)); | BASL_TABLE_ALIGNMENT)); | ||||
memset(&fadt, 0, sizeof(fadt)); | memset(&fadt, 0, sizeof(fadt)); | ||||
BASL_EXEC(basl_table_append_header(table, ACPI_SIG_FADT, 5, 1)); | BASL_EXEC(basl_table_append_header(table, ACPI_SIG_FADT, 5, 1)); | ||||
fadt.Facs = htole32(0); /* patched by basl */ | fadt.Facs = htole32(0); /* patched by basl */ | ||||
fadt.Dsdt = htole32(0); /* patched by basl */ | fadt.Dsdt = htole32(0); /* patched by basl */ | ||||
fadt.SciInterrupt = htole16(SCI_INT); | fadt.SciInterrupt = htole16(SCI_INT); | ||||
fadt.SmiCommand = htole32(SMI_CMD); | fadt.SmiCommand = htole32(SMI_CMD); | ||||
fadt.AcpiEnable = BHYVE_ACPI_ENABLE; | fadt.AcpiEnable = BHYVE_ACPI_ENABLE; | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | |||||
static int | static int | ||||
build_hpet(struct vmctx *const ctx) | build_hpet(struct vmctx *const ctx) | ||||
{ | { | ||||
ACPI_TABLE_HPET hpet; | ACPI_TABLE_HPET hpet; | ||||
struct basl_table *table; | struct basl_table *table; | ||||
BASL_EXEC(basl_table_create(&table, ctx, ACPI_SIG_HPET, | BASL_EXEC(basl_table_create(&table, ctx, ACPI_SIG_HPET, | ||||
BASL_TABLE_ALIGNMENT, HPET_OFFSET)); | BASL_TABLE_ALIGNMENT)); | ||||
memset(&hpet, 0, sizeof(hpet)); | memset(&hpet, 0, sizeof(hpet)); | ||||
BASL_EXEC(basl_table_append_header(table, ACPI_SIG_HPET, 1, 1)); | BASL_EXEC(basl_table_append_header(table, ACPI_SIG_HPET, 1, 1)); | ||||
hpet.Id = htole32(hpet_capabilities); | hpet.Id = htole32(hpet_capabilities); | ||||
basl_fill_gas(&hpet.Address, ACPI_ADR_SPACE_SYSTEM_MEMORY, 0, 0, | basl_fill_gas(&hpet.Address, ACPI_ADR_SPACE_SYSTEM_MEMORY, 0, 0, | ||||
ACPI_GAS_ACCESS_WIDTH_LEGACY, BHYVE_ADDRESS_HPET); | ACPI_GAS_ACCESS_WIDTH_LEGACY, BHYVE_ADDRESS_HPET); | ||||
hpet.Flags = ACPI_HPET_PAGE_PROTECT4; | hpet.Flags = ACPI_HPET_PAGE_PROTECT4; | ||||
BASL_EXEC(basl_table_append_content(table, &hpet, sizeof(hpet))); | BASL_EXEC(basl_table_append_content(table, &hpet, sizeof(hpet))); | ||||
Show All 12 Lines | build_madt(struct vmctx *const ctx) | ||||
ACPI_TABLE_MADT madt; | ACPI_TABLE_MADT madt; | ||||
ACPI_MADT_LOCAL_APIC madt_lapic; | ACPI_MADT_LOCAL_APIC madt_lapic; | ||||
ACPI_MADT_IO_APIC madt_ioapic; | ACPI_MADT_IO_APIC madt_ioapic; | ||||
ACPI_MADT_INTERRUPT_OVERRIDE madt_irq_override; | ACPI_MADT_INTERRUPT_OVERRIDE madt_irq_override; | ||||
ACPI_MADT_LOCAL_APIC_NMI madt_lapic_nmi; | ACPI_MADT_LOCAL_APIC_NMI madt_lapic_nmi; | ||||
struct basl_table *table; | struct basl_table *table; | ||||
BASL_EXEC(basl_table_create(&table, ctx, ACPI_SIG_MADT, | BASL_EXEC(basl_table_create(&table, ctx, ACPI_SIG_MADT, | ||||
BASL_TABLE_ALIGNMENT, MADT_OFFSET)); | BASL_TABLE_ALIGNMENT)); | ||||
memset(&madt, 0, sizeof(madt)); | memset(&madt, 0, sizeof(madt)); | ||||
BASL_EXEC(basl_table_append_header(table, ACPI_SIG_MADT, 1, 1)); | BASL_EXEC(basl_table_append_header(table, ACPI_SIG_MADT, 1, 1)); | ||||
madt.Address = htole32(BHYVE_ADDRESS_LAPIC); | madt.Address = htole32(BHYVE_ADDRESS_LAPIC); | ||||
madt.Flags = htole32(ACPI_MADT_PCAT_COMPAT); | madt.Flags = htole32(ACPI_MADT_PCAT_COMPAT); | ||||
BASL_EXEC(basl_table_append_content(table, &madt, sizeof(madt))); | BASL_EXEC(basl_table_append_content(table, &madt, sizeof(madt))); | ||||
/* Local APIC for each CPU */ | /* Local APIC for each CPU */ | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | |||||
static int | static int | ||||
build_mcfg(struct vmctx *const ctx) | build_mcfg(struct vmctx *const ctx) | ||||
{ | { | ||||
ACPI_TABLE_MCFG mcfg; | ACPI_TABLE_MCFG mcfg; | ||||
ACPI_MCFG_ALLOCATION mcfg_allocation; | ACPI_MCFG_ALLOCATION mcfg_allocation; | ||||
struct basl_table *table; | struct basl_table *table; | ||||
BASL_EXEC(basl_table_create(&table, ctx, ACPI_SIG_MCFG, | BASL_EXEC(basl_table_create(&table, ctx, ACPI_SIG_MCFG, | ||||
BASL_TABLE_ALIGNMENT, MCFG_OFFSET)); | BASL_TABLE_ALIGNMENT)); | ||||
memset(&mcfg, 0, sizeof(mcfg)); | memset(&mcfg, 0, sizeof(mcfg)); | ||||
BASL_EXEC(basl_table_append_header(table, ACPI_SIG_MCFG, 1, 1)); | BASL_EXEC(basl_table_append_header(table, ACPI_SIG_MCFG, 1, 1)); | ||||
BASL_EXEC(basl_table_append_content(table, &mcfg, sizeof(mcfg))); | BASL_EXEC(basl_table_append_content(table, &mcfg, sizeof(mcfg))); | ||||
memset(&mcfg_allocation, 0, sizeof(mcfg_allocation)); | memset(&mcfg_allocation, 0, sizeof(mcfg_allocation)); | ||||
mcfg_allocation.Address = htole64(pci_ecfg_base()); | mcfg_allocation.Address = htole64(pci_ecfg_base()); | ||||
mcfg_allocation.EndBusNumber = 0xFF; | mcfg_allocation.EndBusNumber = 0xFF; | ||||
Show All 10 Lines | |||||
static int | static int | ||||
build_rsdp(struct vmctx *const ctx) | build_rsdp(struct vmctx *const ctx) | ||||
{ | { | ||||
ACPI_TABLE_RSDP rsdp; | ACPI_TABLE_RSDP rsdp; | ||||
struct basl_table *table; | struct basl_table *table; | ||||
BASL_EXEC(basl_table_create(&table, ctx, ACPI_RSDP_NAME, | BASL_EXEC(basl_table_create(&table, ctx, ACPI_RSDP_NAME, | ||||
BASL_TABLE_ALIGNMENT, 0)); | BASL_TABLE_ALIGNMENT)); | ||||
memset(&rsdp, 0, sizeof(rsdp)); | memset(&rsdp, 0, sizeof(rsdp)); | ||||
memcpy(rsdp.Signature, ACPI_SIG_RSDP, 8); | memcpy(rsdp.Signature, ACPI_SIG_RSDP, 8); | ||||
rsdp.Checksum = 0; /* patched by basl */ | rsdp.Checksum = 0; /* patched by basl */ | ||||
memcpy(rsdp.OemId, "BHYVE ", ACPI_OEM_ID_SIZE); | memcpy(rsdp.OemId, "BHYVE ", ACPI_OEM_ID_SIZE); | ||||
rsdp.Revision = 2; | rsdp.Revision = 2; | ||||
rsdp.RsdtPhysicalAddress = htole32(0); /* patched by basl */ | rsdp.RsdtPhysicalAddress = htole32(0); /* patched by basl */ | ||||
rsdp.Length = htole32(0); /* patched by basl */ | rsdp.Length = htole32(0); /* patched by basl */ | ||||
Show All 16 Lines | BASL_EXEC(basl_table_add_checksum(table, | ||||
BASL_TABLE_CHECKSUM_LEN_FULL_TABLE)); | BASL_TABLE_CHECKSUM_LEN_FULL_TABLE)); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
build_rsdt(struct vmctx *const ctx) | build_rsdt(struct vmctx *const ctx) | ||||
{ | { | ||||
BASL_EXEC(basl_table_create(&rsdt, ctx, ACPI_SIG_RSDT, | BASL_EXEC( | ||||
BASL_TABLE_ALIGNMENT, RSDT_OFFSET)); | basl_table_create(&rsdt, ctx, ACPI_SIG_RSDT, BASL_TABLE_ALIGNMENT)); | ||||
/* Header */ | /* Header */ | ||||
BASL_EXEC(basl_table_append_header(rsdt, ACPI_SIG_RSDT, 1, 1)); | BASL_EXEC(basl_table_append_header(rsdt, ACPI_SIG_RSDT, 1, 1)); | ||||
/* Pointers (added by other build_XXX funcs) */ | /* Pointers (added by other build_XXX funcs) */ | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
build_xsdt(struct vmctx *const ctx) | build_xsdt(struct vmctx *const ctx) | ||||
{ | { | ||||
BASL_EXEC(basl_table_create(&xsdt, ctx, ACPI_SIG_XSDT, | BASL_EXEC( | ||||
BASL_TABLE_ALIGNMENT, XSDT_OFFSET)); | basl_table_create(&xsdt, ctx, ACPI_SIG_XSDT, BASL_TABLE_ALIGNMENT)); | ||||
/* Header */ | /* Header */ | ||||
BASL_EXEC(basl_table_append_header(xsdt, ACPI_SIG_XSDT, 1, 1)); | BASL_EXEC(basl_table_append_header(xsdt, ACPI_SIG_XSDT, 1, 1)); | ||||
/* Pointers (added by other build_XXX funcs) */ | /* Pointers (added by other build_XXX funcs) */ | ||||
return (0); | return (0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 50 Lines • Show Last 20 Lines |