/* | |
* 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 | |
); | |
} |