1 /** @file
2 *
3 * Copyright (c) 2017, Linaro, Ltd. 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 <Library/BaseLib.h>
16 #include <Library/DebugLib.h>
17 #include <Library/DevicePathLib.h>
18 #include <Library/DtPlatformDtbLoaderLib.h>
19 #include <Library/HiiLib.h>
20 #include <Library/MemoryAllocationLib.h>
21 #include <Library/UefiBootServicesTableLib.h>
22 #include <Library/UefiDriverEntryPoint.h>
23 #include <Library/UefiRuntimeServicesTableLib.h>
24
25 #include "DtPlatformDxe.h"
26
27 extern UINT8 DtPlatformHiiBin[];
28 extern UINT8 DtPlatformDxeStrings[];
29
30 typedef struct {
31 VENDOR_DEVICE_PATH VendorDevicePath;
32 EFI_DEVICE_PATH_PROTOCOL End;
33 } HII_VENDOR_DEVICE_PATH;
34
35 STATIC HII_VENDOR_DEVICE_PATH mDtPlatformDxeVendorDevicePath = {
36 {
37 {
38 HARDWARE_DEVICE_PATH,
39 HW_VENDOR_DP,
40 {
41 (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
42 (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
43 }
44 },
45 DT_PLATFORM_FORMSET_GUID
46 },
47 {
48 END_DEVICE_PATH_TYPE,
49 END_ENTIRE_DEVICE_PATH_SUBTYPE,
50 {
51 (UINT8) (END_DEVICE_PATH_LENGTH),
52 (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
53 }
54 }
55 };
56
57 STATIC
58 EFI_STATUS
InstallHiiPages(VOID)59 InstallHiiPages (
60 VOID
61 )
62 {
63 EFI_STATUS Status;
64 EFI_HII_HANDLE HiiHandle;
65 EFI_HANDLE DriverHandle;
66
67 DriverHandle = NULL;
68 Status = gBS->InstallMultipleProtocolInterfaces (&DriverHandle,
69 &gEfiDevicePathProtocolGuid,
70 &mDtPlatformDxeVendorDevicePath,
71 NULL);
72 if (EFI_ERROR (Status)) {
73 return Status;
74 }
75
76 HiiHandle = HiiAddPackages (&gDtPlatformFormSetGuid,
77 DriverHandle,
78 DtPlatformDxeStrings,
79 DtPlatformHiiBin,
80 NULL);
81
82 if (HiiHandle == NULL) {
83 gBS->UninstallMultipleProtocolInterfaces (DriverHandle,
84 &gEfiDevicePathProtocolGuid,
85 &mDtPlatformDxeVendorDevicePath,
86 NULL);
87 return EFI_OUT_OF_RESOURCES;
88 }
89 return EFI_SUCCESS;
90 }
91
92 /**
93 The entry point for DtPlatformDxe driver.
94
95 @param[in] ImageHandle The image handle of the driver.
96 @param[in] SystemTable The system table.
97
98 @retval EFI_ALREADY_STARTED The driver already exists in system.
99 @retval EFI_OUT_OF_RESOURCES Fail to execute entry point due to lack of
100 resources.
101 @retval EFI_SUCCES All the related protocols are installed on
102 the driver.
103
104 **/
105 EFI_STATUS
106 EFIAPI
DtPlatformDxeEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)107 DtPlatformDxeEntryPoint (
108 IN EFI_HANDLE ImageHandle,
109 IN EFI_SYSTEM_TABLE *SystemTable
110 )
111 {
112 EFI_STATUS Status;
113 DT_ACPI_VARSTORE_DATA DtAcpiPref;
114 UINTN BufferSize;
115 VOID *Dtb;
116 UINTN DtbSize;
117
118 Dtb = NULL;
119 Status = DtPlatformLoadDtb (&Dtb, &DtbSize);
120 if (EFI_ERROR (Status)) {
121 DEBUG ((DEBUG_WARN,
122 "%a: no DTB blob could be loaded, defaulting to ACPI (Status == %r)\n",
123 __FUNCTION__, Status));
124 DtAcpiPref.Pref = DT_ACPI_SELECT_ACPI;
125 } else {
126 //
127 // Get the current DT/ACPI preference from the DtAcpiPref variable.
128 //
129 BufferSize = sizeof (DtAcpiPref);
130 Status = gRT->GetVariable(DT_ACPI_VARIABLE_NAME, &gDtPlatformFormSetGuid,
131 NULL, &BufferSize, &DtAcpiPref);
132 if (EFI_ERROR (Status)) {
133 DEBUG ((DEBUG_WARN, "%a: no DT/ACPI preference found, defaulting to DT\n",
134 __FUNCTION__));
135 DtAcpiPref.Pref = DT_ACPI_SELECT_DT;
136 }
137 }
138
139 if (!EFI_ERROR (Status) &&
140 DtAcpiPref.Pref != DT_ACPI_SELECT_ACPI &&
141 DtAcpiPref.Pref != DT_ACPI_SELECT_DT) {
142 DEBUG ((DEBUG_WARN, "%a: invalid value for %s, defaulting to DT\n",
143 __FUNCTION__, DT_ACPI_VARIABLE_NAME));
144 DtAcpiPref.Pref = DT_ACPI_SELECT_DT;
145 Status = EFI_INVALID_PARAMETER; // trigger setvar below
146 }
147
148 //
149 // Write the newly selected default value back to the variable store.
150 //
151 if (EFI_ERROR (Status)) {
152 Status = gRT->SetVariable(DT_ACPI_VARIABLE_NAME, &gDtPlatformFormSetGuid,
153 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
154 sizeof (DtAcpiPref), &DtAcpiPref);
155 if (EFI_ERROR (Status)) {
156 goto FreeDtb;
157 }
158 }
159
160 if (DtAcpiPref.Pref == DT_ACPI_SELECT_ACPI) {
161 //
162 // ACPI was selected: install the gEdkiiPlatformHasAcpiGuid GUID as a
163 // NULL protocol to unlock dispatch of ACPI related drivers.
164 //
165 Status = gBS->InstallMultipleProtocolInterfaces (&ImageHandle,
166 &gEdkiiPlatformHasAcpiGuid, NULL, NULL);
167 if (EFI_ERROR (Status)) {
168 DEBUG ((DEBUG_ERROR,
169 "%a: failed to install gEdkiiPlatformHasAcpiGuid as a protocol\n",
170 __FUNCTION__));
171 goto FreeDtb;
172 }
173 } else if (DtAcpiPref.Pref == DT_ACPI_SELECT_DT) {
174 //
175 // DT was selected: copy the blob into newly allocated memory and install
176 // a reference to it as the FDT configuration table.
177 //
178 Status = gBS->InstallConfigurationTable (&gFdtTableGuid, Dtb);
179 if (EFI_ERROR (Status)) {
180 DEBUG ((DEBUG_ERROR, "%a: failed to install FDT configuration table\n",
181 __FUNCTION__));
182 goto FreeDtb;
183 }
184 } else {
185 ASSERT (FALSE);
186 }
187
188 //
189 // No point in installing the HII pages if ACPI is the only description
190 // we have
191 //
192 if (Dtb == NULL) {
193 return EFI_SUCCESS;
194 }
195
196 //
197 // Note that we don't uninstall the gEdkiiPlatformHasAcpiGuid protocol nor
198 // the FDT configuration table if the following call fails. While that will
199 // cause loading of this driver to fail, proceeding with ACPI and DT both
200 // disabled will guarantee a failed boot, and so it is better to leave them
201 // installed in that case.
202 //
203 return InstallHiiPages ();
204
205 FreeDtb:
206 if (Dtb != NULL) {
207 FreePool (Dtb);
208 }
209
210 return Status;
211 }
212