Corvin Köhne 4092f1d397 OvmfPkg/Bhyve: add support for QemuFwCfg
QemuFwCfg is much more powerful than BhyveFwCtl. Sadly, BhyveFwCtl
decided to use the same IO ports as QemuFwCfg. It's not possible to use
both interfaces simultaneously. So, prefer QemuFwCfg over BhyveFwCtl.

Signed-off-by: Corvin Köhne <c.koehne@beckhoff.com>
Reviewed-by: Rebecca Cran <rebecca@bsdio.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Peter Grehan <grehan@freebsd.org>
Acked-by: Jiewen Yao <jiewen.yao@intel.com>
2022-05-02 16:38:23 +00:00

167 lines
5.2 KiB
C

/*
* Copyright (c) 2020, Rebecca Cran <rebecca@bsdio.com>
* Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>
* Copyright (C) 2012, Red Hat, Inc.
* Copyright (c) 2014, Pluribus Networks, Inc.
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*/
#include "AcpiPlatform.h"
#include <Library/BaseMemoryLib.h>
#include <Library/BhyveFwCtlLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/QemuFwCfgLib.h> // QemuFwCfgFindFile()
STATIC
EFI_STATUS
EFIAPI
BhyveGetCpuCount (
OUT UINT32 *CpuCount
)
{
FIRMWARE_CONFIG_ITEM Item;
UINTN Size;
if (QemuFwCfgIsAvailable ()) {
if (EFI_ERROR (QemuFwCfgFindFile ("opt/bhyve/hw.ncpu", &Item, &Size))) {
return EFI_NOT_FOUND;
} else if (Size != sizeof (*CpuCount)) {
return EFI_BAD_BUFFER_SIZE;
}
QemuFwCfgSelectItem (Item);
QemuFwCfgReadBytes (Size, CpuCount);
return EFI_SUCCESS;
}
//
// QemuFwCfg not available, try BhyveFwCtl.
//
Size = sizeof (*CpuCount);
if (BhyveFwCtlGet ("hw.ncpu", CpuCount, &Size) == RETURN_SUCCESS) {
return EFI_SUCCESS;
}
return EFI_UNSUPPORTED;
}
STATIC
EFI_STATUS
EFIAPI
BhyveInstallAcpiMadtTable (
IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
IN VOID *AcpiTableBuffer,
IN UINTN AcpiTableBufferSize,
OUT UINTN *TableKey
)
{
UINT32 CpuCount;
UINTN NewBufferSize;
EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *Madt;
EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE *LocalApic;
EFI_ACPI_1_0_IO_APIC_STRUCTURE *IoApic;
EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE *Iso;
VOID *Ptr;
UINTN Loop;
EFI_STATUS Status;
ASSERT (AcpiTableBufferSize >= sizeof (EFI_ACPI_DESCRIPTION_HEADER));
// Query the host for the number of vCPUs
Status = BhyveGetCpuCount (&CpuCount);
if (!EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "Retrieved CpuCount %d\n", CpuCount));
ASSERT (CpuCount >= 1);
} else {
DEBUG ((DEBUG_INFO, "CpuCount retrieval error\n"));
CpuCount = 1;
}
NewBufferSize = 1 * sizeof (*Madt) +
CpuCount * sizeof (*LocalApic) +
1 * sizeof (*IoApic) +
1 * sizeof (*Iso);
Madt = AllocatePool (NewBufferSize);
if (Madt == NULL) {
return EFI_OUT_OF_RESOURCES;
}
CopyMem (&(Madt->Header), AcpiTableBuffer, sizeof (EFI_ACPI_DESCRIPTION_HEADER));
Madt->Header.Length = (UINT32)NewBufferSize;
Madt->LocalApicAddress = 0xFEE00000;
Madt->Flags = EFI_ACPI_1_0_PCAT_COMPAT;
Ptr = Madt + 1;
LocalApic = Ptr;
for (Loop = 0; Loop < CpuCount; ++Loop) {
LocalApic->Type = EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC;
LocalApic->Length = sizeof (*LocalApic);
LocalApic->AcpiProcessorId = (UINT8)Loop;
LocalApic->ApicId = (UINT8)Loop;
LocalApic->Flags = 1; // enabled
++LocalApic;
}
Ptr = LocalApic;
IoApic = Ptr;
IoApic->Type = EFI_ACPI_1_0_IO_APIC;
IoApic->Length = sizeof (*IoApic);
IoApic->IoApicId = (UINT8)CpuCount;
IoApic->Reserved = EFI_ACPI_RESERVED_BYTE;
IoApic->IoApicAddress = 0xFEC00000;
IoApic->SystemVectorBase = 0x00000000;
Ptr = IoApic + 1;
//
// IRQ0 (8254 Timer) => IRQ2 (PIC) Interrupt Source Override Structure
//
Iso = Ptr;
Iso->Type = EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE;
Iso->Length = sizeof (*Iso);
Iso->Bus = 0x00; // ISA
Iso->Source = 0x00; // IRQ0
Iso->GlobalSystemInterruptVector = 0x00000002;
Iso->Flags = 0x0000; // Conforms to specs of the bus
Ptr = Iso + 1;
ASSERT ((UINTN)((UINT8 *)Ptr - (UINT8 *)Madt) == NewBufferSize);
Status = InstallAcpiTable (AcpiProtocol, Madt, NewBufferSize, TableKey);
FreePool (Madt);
return Status;
}
EFI_STATUS
EFIAPI
BhyveInstallAcpiTable (
IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
IN VOID *AcpiTableBuffer,
IN UINTN AcpiTableBufferSize,
OUT UINTN *TableKey
)
{
EFI_ACPI_DESCRIPTION_HEADER *Hdr;
EFI_ACPI_TABLE_INSTALL_ACPI_TABLE TableInstallFunction;
Hdr = (EFI_ACPI_DESCRIPTION_HEADER *)AcpiTableBuffer;
switch (Hdr->Signature) {
case EFI_ACPI_1_0_APIC_SIGNATURE:
TableInstallFunction = BhyveInstallAcpiMadtTable;
break;
default:
TableInstallFunction = InstallAcpiTable;
}
return TableInstallFunction (
AcpiProtocol,
AcpiTableBuffer,
AcpiTableBufferSize,
TableKey
);
}