1/** @file
2*
3*  Copyright (c) 2014-2015, ARM Limited. All rights reserved.
4*
5*  This program and the accompanying materials
6*  are licensed and made available under the terms and conditions of the BSD License
7*  which accompanies this distribution.  The full text of the license may be found at
8*  http://opensource.org/licenses/bsd-license.php
9*
10*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12*
13**/
14
15#include <Uefi.h>
16
17#include <Library/AcpiLib.h>
18#include <Library/DebugLib.h>
19#include <Library/UefiBootServicesTableLib.h>
20
21#include <Protocol/AcpiTable.h>
22#include <Protocol/FirmwareVolume2.h>
23
24#include <IndustryStandard/Acpi.h>
25
26/**
27  Locate and Install the ACPI tables from the Firmware Volume if it verifies
28  the function condition.
29
30  @param  AcpiFile                Guid of the ACPI file into the Firmware Volume
31  @param  CheckAcpiTableFunction  Function that checks if the ACPI table should be installed
32
33  @return EFI_SUCCESS             The function completed successfully.
34  @return EFI_NOT_FOUND           The protocol could not be located.
35  @return EFI_OUT_OF_RESOURCES    There are not enough resources to find the protocol.
36
37**/
38EFI_STATUS
39LocateAndInstallAcpiFromFvConditional (
40  IN CONST EFI_GUID*        AcpiFile,
41  IN EFI_LOCATE_ACPI_CHECK  CheckAcpiTableFunction
42  )
43{
44  EFI_STATUS                    Status;
45  EFI_ACPI_TABLE_PROTOCOL       *AcpiProtocol;
46  EFI_HANDLE                    *HandleBuffer;
47  UINTN                         NumberOfHandles;
48  UINT32                        FvStatus;
49  UINTN                         Index;
50  EFI_FIRMWARE_VOLUME2_PROTOCOL *FvInstance;
51  INTN                          SectionInstance;
52  UINTN                         SectionSize;
53  EFI_ACPI_COMMON_HEADER       *AcpiTable;
54  UINTN                         AcpiTableSize;
55  UINTN                         AcpiTableKey;
56  BOOLEAN                       Valid;
57
58  // Ensure the ACPI Table is present
59  Status = gBS->LocateProtocol (
60                  &gEfiAcpiTableProtocolGuid,
61                  NULL,
62                  (VOID**)&AcpiProtocol
63                  );
64  if (EFI_ERROR (Status)) {
65    return Status;
66  }
67
68  FvStatus        = 0;
69  SectionInstance = 0;
70
71  // Locate all the Firmware Volume protocols.
72  Status = gBS->LocateHandleBuffer (
73                   ByProtocol,
74                   &gEfiFirmwareVolume2ProtocolGuid,
75                   NULL,
76                   &NumberOfHandles,
77                   &HandleBuffer
78                   );
79  if (EFI_ERROR (Status)) {
80    return Status;
81  }
82
83  // Looking for FV with ACPI storage file
84  for (Index = 0; Index < NumberOfHandles; Index++) {
85    //
86    // Get the protocol on this handle
87    // This should not fail because of LocateHandleBuffer
88    //
89    Status = gBS->HandleProtocol (
90                     HandleBuffer[Index],
91                     &gEfiFirmwareVolume2ProtocolGuid,
92                     (VOID**) &FvInstance
93                     );
94    if (EFI_ERROR (Status)) {
95      goto FREE_HANDLE_BUFFER;
96    }
97
98    while (Status == EFI_SUCCESS) {
99      // AcpiTable must be allocated by ReadSection (ie: AcpiTable == NULL)
100      AcpiTable = NULL;
101
102      // See if it has the ACPI storage file
103      Status = FvInstance->ReadSection (
104                        FvInstance,
105                        AcpiFile,
106                        EFI_SECTION_RAW,
107                        SectionInstance,
108                        (VOID**) &AcpiTable,
109                        &SectionSize,
110                        &FvStatus
111                        );
112      if (!EFI_ERROR (Status)) {
113        AcpiTableKey = 0;
114        AcpiTableSize = ((EFI_ACPI_DESCRIPTION_HEADER *) AcpiTable)->Length;
115        ASSERT (SectionSize >= AcpiTableSize);
116
117        DEBUG ((EFI_D_ERROR, "- Found '%c%c%c%c' ACPI Table\n",
118            (((EFI_ACPI_DESCRIPTION_HEADER *) AcpiTable)->Signature & 0xFF),
119            ((((EFI_ACPI_DESCRIPTION_HEADER *) AcpiTable)->Signature >> 8) & 0xFF),
120            ((((EFI_ACPI_DESCRIPTION_HEADER *) AcpiTable)->Signature >> 16) & 0xFF),
121            ((((EFI_ACPI_DESCRIPTION_HEADER *) AcpiTable)->Signature >> 24) & 0xFF)));
122
123        // Is the ACPI table valid?
124        if (CheckAcpiTableFunction) {
125          Valid = CheckAcpiTableFunction ((EFI_ACPI_DESCRIPTION_HEADER *)AcpiTable);
126        } else {
127          Valid = TRUE;
128        }
129
130        // Install the ACPI Table
131        if (Valid) {
132          Status = AcpiProtocol->InstallAcpiTable (
133                                 AcpiProtocol,
134                                 AcpiTable,
135                                 AcpiTableSize,
136                                 &AcpiTableKey
137                                 );
138        }
139
140        // Free memory allocated by ReadSection
141        gBS->FreePool (AcpiTable);
142
143        if (EFI_ERROR (Status)) {
144          break;
145        }
146
147        // Increment the section instance
148        SectionInstance++;
149      }
150    }
151  }
152
153FREE_HANDLE_BUFFER:
154  //
155  // Free any allocated buffers
156  //
157  gBS->FreePool (HandleBuffer);
158
159  return EFI_SUCCESS;
160}
161
162/**
163  Locate and Install the ACPI tables from the Firmware Volume
164
165  @param  AcpiFile              Guid of the ACPI file into the Firmware Volume
166
167  @return EFI_SUCCESS           The function completed successfully.
168  @return EFI_NOT_FOUND         The protocol could not be located.
169  @return EFI_OUT_OF_RESOURCES  There are not enough resources to find the protocol.
170
171**/
172EFI_STATUS
173LocateAndInstallAcpiFromFv (
174  IN CONST EFI_GUID* AcpiFile
175  )
176{
177  return LocateAndInstallAcpiFromFvConditional (AcpiFile, NULL);
178}
179