summaryrefslogtreecommitdiffstats
path: root/ArmVirtPkg/CloudHvAcpiPlatformDxe/CloudHvAcpi.c
blob: 0e86e7a036e50bf1f5b41a562f9e54d2de7ffb24 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/** @file
  Install Acpi tables for Cloud Hypervisor

  Copyright (c) 2021, Arm Limited. All rights reserved.<BR>

  SPDX-License-Identifier: BSD-2-Clause-Patent
**/

#include <Library/BaseLib.h>
#include <Library/MemoryAllocationLib.h>
#include <IndustryStandard/Acpi63.h>
#include <Protocol/AcpiTable.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/DebugLib.h>

/**
   Find Acpi table Protocol and return it

   @return AcpiTable  Protocol, which is used to handle Acpi Table, on SUCCESS or NULL on FAILURE.

**/
STATIC
EFI_ACPI_TABLE_PROTOCOL *
FindAcpiTableProtocol (
  VOID
  )
{
  EFI_STATUS              Status;
  EFI_ACPI_TABLE_PROTOCOL *AcpiTable;

  Status = gBS->LocateProtocol (
                  &gEfiAcpiTableProtocolGuid,
                  NULL,
                  (VOID**)&AcpiTable
                  );
  ASSERT_EFI_ERROR (Status);
  return AcpiTable;
}

/** Install Acpi tables for Cloud Hypervisor

  @param [in]  AcpiProtocol  Acpi Protocol which is used to install Acpi tables

  @return EFI_SUCCESS            The table was successfully inserted.
  @return EFI_INVALID_PARAMETER  Either AcpiProtocol, AcpiTablePtr or DsdtPtr is NULL
                                 and the size field embedded in the ACPI table pointed
                                 by AcpiTablePtr or DsdtPtr are not in sync.
  @return EFI_OUT_OF_RESOURCES   Insufficient resources exist to complete the request.
  @return EFI_NOT_FOUND          DSDT table not found.
**/
EFI_STATUS
EFIAPI
InstallCloudHvAcpiTables (
  IN     EFI_ACPI_TABLE_PROTOCOL       *AcpiProtocol
  )
{
  UINTN          InstalledKey;
  UINTN          TableSize;
  UINTN          AcpiTableLength;
  UINT64         RsdpPtr;
  UINT64         XsdtPtr;
  UINT64         TableOffset;
  UINT64         AcpiTablePtr;
  UINT64         *DsdtPtr;
  EFI_STATUS     Status;

  if (AcpiProtocol == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  RsdpPtr = PcdGet64 (PcdCloudHvAcpiRsdpBaseAddress);
  XsdtPtr = ((EFI_ACPI_6_3_ROOT_SYSTEM_DESCRIPTION_POINTER *)RsdpPtr)->XsdtAddress;
  AcpiTableLength = ((EFI_ACPI_COMMON_HEADER *)XsdtPtr)->Length;
  TableOffset = sizeof (EFI_ACPI_DESCRIPTION_HEADER);
  DsdtPtr = NULL;

  while (TableOffset < AcpiTableLength) {
    AcpiTablePtr = *(UINT64 *)(XsdtPtr + TableOffset);
    TableSize = ((EFI_ACPI_COMMON_HEADER *)AcpiTablePtr)->Length;

    //
    // Install ACPI tables from XSDT
    //
    Status = AcpiProtocol->InstallAcpiTable (
                             AcpiProtocol,
                             (VOID *)AcpiTablePtr,
                             TableSize,
                             &InstalledKey
                             );
    if (EFI_ERROR (Status)) {
        return Status;
    }

    //
    // Get DSDT from FADT
    //
    if ((DsdtPtr == NULL) &&
        (EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE ==
         ((EFI_ACPI_COMMON_HEADER *)AcpiTablePtr)->Signature)) {
      DsdtPtr = (UINT64 *)((EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE *)AcpiTablePtr)->XDsdt;
    }

    TableOffset += sizeof (UINT64);
  } // while

  if (DsdtPtr == NULL) {
    DEBUG ((DEBUG_ERROR, "%a: no DSDT found\n", __FUNCTION__));
    return EFI_NOT_FOUND;
  }

  //
  // Install DSDT table
  //
  TableSize = ((EFI_ACPI_COMMON_HEADER *)DsdtPtr)->Length;
  Status = AcpiProtocol->InstallAcpiTable (
                           AcpiProtocol,
                           DsdtPtr,
                           TableSize,
                           &InstalledKey
                           );

  return Status;
}

/** Entry point for Cloud Hypervisor Platform Dxe

  @param [in]  ImageHandle  Handle for this image.
  @param [in]  SystemTable  Pointer to the EFI system table.

  @return EFI_SUCCESS            The table was successfully inserted.
  @return EFI_INVALID_PARAMETER  Either AcpiProtocol, AcpiTablePtr or DsdtPtr is NULL
                                 and the size field embedded in the ACPI table pointed to
                                 by AcpiTablePtr or DsdtPtr are not in sync.
  @return EFI_OUT_OF_RESOURCES   Insufficient resources exist to complete the request.
  @return EFI_NOT_FOUND          DSDT table not found
**/
EFI_STATUS
EFIAPI
CloudHvAcpiPlatformEntryPoint (
  IN EFI_HANDLE         ImageHandle,
  IN EFI_SYSTEM_TABLE   *SystemTable
  )
{
  EFI_STATUS                         Status;

  Status = InstallCloudHvAcpiTables (FindAcpiTableProtocol ());

  if (EFI_ERROR (Status)) {
     DEBUG ((
       DEBUG_ERROR,
       "%a: Fail to install Acpi table: %r\n",
       __FUNCTION__,
       Status
       ));
     CpuDeadLoop ();
  }

  return EFI_SUCCESS;
}