/* * Copyright (c) 2020, Rebecca Cran * Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.
* Copyright (C) 2012, Red Hat, Inc. * Copyright (c) 2014, Pluribus Networks, Inc. * * SPDX-License-Identifier: BSD-2-Clause-Patent */ #include "AcpiPlatform.h" #include #include #include #include // 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 ); }