1 /*
2  * Copyright (c) 2020, Rebecca Cran <rebecca@bsdio.com>
3  * Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>
4  * Copyright (C) 2012, Red Hat, Inc.
5  * Copyright (c) 2014, Pluribus Networks, Inc.
6  *
7  * SPDX-License-Identifier: BSD-2-Clause-Patent
8  */
9 #include "AcpiPlatform.h"
10 
11 #include <Library/BaseMemoryLib.h>
12 #include <Library/BhyveFwCtlLib.h>
13 #include <Library/MemoryAllocationLib.h>
14 
15 STATIC
16 EFI_STATUS
17 EFIAPI
18 BhyveInstallAcpiMadtTable (
19   IN   EFI_ACPI_TABLE_PROTOCOL       *AcpiProtocol,
20   IN   VOID                          *AcpiTableBuffer,
21   IN   UINTN                         AcpiTableBufferSize,
22   OUT  UINTN                         *TableKey
23   )
24 {
25   UINT32                                              CpuCount;
26   UINTN                                               cSize;
27   UINTN                                               NewBufferSize;
28   EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *Madt;
29   EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE         *LocalApic;
30   EFI_ACPI_1_0_IO_APIC_STRUCTURE                      *IoApic;
31   EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE    *Iso;
32   VOID                                                *Ptr;
33   UINTN                                               Loop;
34   EFI_STATUS                                          Status;
35 
36   ASSERT (AcpiTableBufferSize >= sizeof (EFI_ACPI_DESCRIPTION_HEADER));
37 
38   // Query the host for the number of vCPUs
39   CpuCount = 0;
40   cSize = sizeof(CpuCount);
41   if (BhyveFwCtlGet ("hw.ncpu", &CpuCount, &cSize) == RETURN_SUCCESS) {
42     DEBUG ((DEBUG_INFO, "Retrieved CpuCount %d\n", CpuCount));
43     ASSERT (CpuCount >= 1);
44   } else {
45     DEBUG ((DEBUG_INFO, "CpuCount retrieval error\n"));
46     CpuCount = 1;
47   }
48 
49   NewBufferSize = 1                     * sizeof (*Madt) +
50                   CpuCount              * sizeof (*LocalApic) +
51                   1                     * sizeof (*IoApic) +
52                   1                     * sizeof (*Iso);
53 
54   Madt = AllocatePool (NewBufferSize);
55   if (Madt == NULL) {
56     return EFI_OUT_OF_RESOURCES;
57   }
58 
59   CopyMem (&(Madt->Header), AcpiTableBuffer, sizeof (EFI_ACPI_DESCRIPTION_HEADER));
60   Madt->Header.Length    = (UINT32) NewBufferSize;
61   Madt->LocalApicAddress = 0xFEE00000;
62   Madt->Flags            = EFI_ACPI_1_0_PCAT_COMPAT;
63   Ptr = Madt + 1;
64 
65   LocalApic = Ptr;
66   for (Loop = 0; Loop < CpuCount; ++Loop) {
67     LocalApic->Type            = EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC;
68     LocalApic->Length          = sizeof (*LocalApic);
69     LocalApic->AcpiProcessorId = (UINT8) Loop;
70     LocalApic->ApicId          = (UINT8) Loop;
71     LocalApic->Flags           = 1; // enabled
72     ++LocalApic;
73   }
74   Ptr = LocalApic;
75 
76   IoApic = Ptr;
77   IoApic->Type             = EFI_ACPI_1_0_IO_APIC;
78   IoApic->Length           = sizeof (*IoApic);
79   IoApic->IoApicId         = (UINT8) CpuCount;
80   IoApic->Reserved         = EFI_ACPI_RESERVED_BYTE;
81   IoApic->IoApicAddress    = 0xFEC00000;
82   IoApic->SystemVectorBase = 0x00000000;
83   Ptr = IoApic + 1;
84 
85   //
86   // IRQ0 (8254 Timer) => IRQ2 (PIC) Interrupt Source Override Structure
87   //
88   Iso = Ptr;
89   Iso->Type                        = EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE;
90   Iso->Length                      = sizeof (*Iso);
91   Iso->Bus                         = 0x00; // ISA
92   Iso->Source                      = 0x00; // IRQ0
93   Iso->GlobalSystemInterruptVector = 0x00000002;
94   Iso->Flags                       = 0x0000; // Conforms to specs of the bus
95   Ptr = Iso + 1;
96 
97   ASSERT ((UINTN) ((UINT8 *)Ptr - (UINT8 *)Madt) == NewBufferSize);
98   Status = InstallAcpiTable (AcpiProtocol, Madt, NewBufferSize, TableKey);
99 
100   FreePool (Madt);
101 
102   return Status;
103 }
104 
105 EFI_STATUS
106 EFIAPI
107 BhyveInstallAcpiTable (
108   IN   EFI_ACPI_TABLE_PROTOCOL       *AcpiProtocol,
109   IN   VOID                          *AcpiTableBuffer,
110   IN   UINTN                         AcpiTableBufferSize,
111   OUT  UINTN                         *TableKey
112   )
113 {
114   EFI_ACPI_DESCRIPTION_HEADER        *Hdr;
115   EFI_ACPI_TABLE_INSTALL_ACPI_TABLE  TableInstallFunction;
116 
117   Hdr = (EFI_ACPI_DESCRIPTION_HEADER*) AcpiTableBuffer;
118   switch (Hdr->Signature) {
119   case EFI_ACPI_1_0_APIC_SIGNATURE:
120     TableInstallFunction = BhyveInstallAcpiMadtTable;
121     break;
122   default:
123     TableInstallFunction = InstallAcpiTable;
124   }
125 
126   return TableInstallFunction (
127            AcpiProtocol,
128            AcpiTableBuffer,
129            AcpiTableBufferSize,
130            TableKey
131            );
132 }
133