]> git.proxmox.com Git - mirror_edk2.git/blob - EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c
8d0ffbe88d0a404d000a2160dfb7ad4ffc249f1e
[mirror_edk2.git] / EmbeddedPkg / Drivers / ConsolePrefDxe / ConsolePrefDxe.c
1 /** @file
2 *
3 * Copyright (c) 2017, Linaro, Ltd. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-2-Clause-Patent
6 *
7 **/
8
9 #include <Uefi.h>
10 #include <IndustryStandard/Acpi.h>
11 #include <libfdt.h>
12 #include <Library/BaseLib.h>
13 #include <Library/DebugLib.h>
14 #include <Library/DevicePathLib.h>
15 #include <Library/HiiLib.h>
16 #include <Library/UefiBootServicesTableLib.h>
17 #include <Library/UefiBootServicesTableLib.h>
18 #include <Library/UefiDriverEntryPoint.h>
19 #include <Library/UefiLib.h>
20 #include <Library/UefiRuntimeServicesTableLib.h>
21
22 #include <Protocol/AcpiTable.h>
23 #include <Protocol/AcpiSystemDescriptionTable.h>
24
25 #include "ConsolePrefDxe.h"
26
27 #define SPCR_SIG EFI_ACPI_2_0_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE
28
29 extern UINT8 ConsolePrefHiiBin[];
30 extern UINT8 ConsolePrefDxeStrings[];
31
32 typedef struct {
33 VENDOR_DEVICE_PATH VendorDevicePath;
34 EFI_DEVICE_PATH_PROTOCOL End;
35 } HII_VENDOR_DEVICE_PATH;
36
37 STATIC HII_VENDOR_DEVICE_PATH mConsolePrefDxeVendorDevicePath = {
38 {
39 {
40 HARDWARE_DEVICE_PATH,
41 HW_VENDOR_DP,
42 {
43 (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
44 (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
45 }
46 },
47 CONSOLE_PREF_FORMSET_GUID
48 },
49 {
50 END_DEVICE_PATH_TYPE,
51 END_ENTIRE_DEVICE_PATH_SUBTYPE,
52 {
53 (UINT8) (END_DEVICE_PATH_LENGTH),
54 (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
55 }
56 }
57 };
58
59 STATIC EFI_EVENT mReadyToBootEvent;
60
61 STATIC
62 EFI_STATUS
63 InstallHiiPages (
64 VOID
65 )
66 {
67 EFI_STATUS Status;
68 EFI_HII_HANDLE HiiHandle;
69 EFI_HANDLE DriverHandle;
70
71 DriverHandle = NULL;
72 Status = gBS->InstallMultipleProtocolInterfaces (&DriverHandle,
73 &gEfiDevicePathProtocolGuid,
74 &mConsolePrefDxeVendorDevicePath,
75 NULL);
76 if (EFI_ERROR (Status)) {
77 return Status;
78 }
79
80 HiiHandle = HiiAddPackages (&gConsolePrefFormSetGuid,
81 DriverHandle,
82 ConsolePrefDxeStrings,
83 ConsolePrefHiiBin,
84 NULL);
85
86 if (HiiHandle == NULL) {
87 gBS->UninstallMultipleProtocolInterfaces (DriverHandle,
88 &gEfiDevicePathProtocolGuid,
89 &mConsolePrefDxeVendorDevicePath,
90 NULL);
91 return EFI_OUT_OF_RESOURCES;
92 }
93 return EFI_SUCCESS;
94 }
95
96 STATIC
97 VOID
98 RemoveDtStdoutPath (
99 VOID
100 )
101 {
102 VOID *Dtb;
103 INT32 Node;
104 INT32 Error;
105 EFI_STATUS Status;
106
107 Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, &Dtb);
108 if (EFI_ERROR (Status)) {
109 DEBUG ((DEBUG_INFO, "%a: could not retrieve DT blob - %r\n", __FUNCTION__,
110 Status));
111 return;
112 }
113
114 Node = fdt_path_offset (Dtb, "/chosen");
115 if (Node < 0) {
116 return;
117 }
118
119 Error = fdt_delprop (Dtb, Node, "stdout-path");
120 if (Error) {
121 DEBUG ((DEBUG_INFO, "%a: Failed to delete 'stdout-path' property: %a\n",
122 __FUNCTION__, fdt_strerror (Error)));
123 }
124 }
125
126 STATIC
127 VOID
128 RemoveSpcrTable (
129 VOID
130 )
131 {
132 EFI_ACPI_SDT_PROTOCOL *Sdt;
133 EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
134 EFI_STATUS Status;
135 UINTN TableIndex;
136 EFI_ACPI_SDT_HEADER *TableHeader;
137 EFI_ACPI_TABLE_VERSION TableVersion;
138 UINTN TableKey;
139
140 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL,
141 (VOID **)&AcpiTable);
142 if (EFI_ERROR (Status)) {
143 return;
144 }
145
146 Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (VOID **)&Sdt);
147 if (EFI_ERROR (Status)) {
148 return;
149 }
150
151 TableIndex = 0;
152 TableKey = 0;
153 TableHeader = NULL;
154
155 do {
156 Status = Sdt->GetAcpiTable (TableIndex++, &TableHeader, &TableVersion,
157 &TableKey);
158 if (EFI_ERROR (Status)) {
159 break;
160 }
161
162 if (TableHeader->Signature != SPCR_SIG) {
163 continue;
164 }
165
166 Status = AcpiTable->UninstallAcpiTable (AcpiTable, TableKey);
167 if (EFI_ERROR (Status)) {
168 DEBUG ((DEBUG_WARN, "%a: failed to uninstall SPCR table - %r\n",
169 __FUNCTION__, Status));
170 }
171 break;
172 } while (TRUE);
173 }
174
175 STATIC
176 VOID
177 OnReadyToBoot (
178 IN EFI_EVENT Event,
179 IN VOID *Context
180 )
181 {
182 CONSOLE_PREF_VARSTORE_DATA ConsolePref;
183 UINTN BufferSize;
184 EFI_STATUS Status;
185 VOID *Gop;
186
187 BufferSize = sizeof (ConsolePref);
188 Status = gRT->GetVariable (CONSOLE_PREF_VARIABLE_NAME,
189 &gConsolePrefFormSetGuid, NULL, &BufferSize, &ConsolePref);
190 if (EFI_ERROR (Status)) {
191 DEBUG ((DEBUG_ERROR,
192 "%a: variable '%s' could not be read - bailing!\n", __FUNCTION__,
193 CONSOLE_PREF_VARIABLE_NAME));
194 return;
195 }
196
197 if (ConsolePref.Console == CONSOLE_PREF_SERIAL) {
198 DEBUG ((DEBUG_INFO,
199 "%a: serial console preferred - doing nothing\n", __FUNCTION__));
200 return;
201 }
202
203 //
204 // Check if any GOP instances exist: if so, disable stdout-path and SPCR
205 //
206 Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, NULL, &Gop);
207 if (EFI_ERROR (Status)) {
208 DEBUG ((DEBUG_INFO,
209 "%a: no GOP instances found - doing nothing (%r)\n", __FUNCTION__,
210 Status));
211 return;
212 }
213
214 RemoveDtStdoutPath ();
215 RemoveSpcrTable ();
216 }
217
218 /**
219 The entry point for ConsolePrefDxe driver.
220
221 @param[in] ImageHandle The image handle of the driver.
222 @param[in] SystemTable The system table.
223
224 @retval EFI_ALREADY_STARTED The driver already exists in system.
225 @retval EFI_OUT_OF_RESOURCES Fail to execute entry point due to lack of
226 resources.
227 @retval EFI_SUCCES All the related protocols are installed on
228 the driver.
229
230 **/
231 EFI_STATUS
232 EFIAPI
233 ConsolePrefDxeEntryPoint (
234 IN EFI_HANDLE ImageHandle,
235 IN EFI_SYSTEM_TABLE *SystemTable
236 )
237 {
238 EFI_STATUS Status;
239 CONSOLE_PREF_VARSTORE_DATA ConsolePref;
240 UINTN BufferSize;
241
242 //
243 // Get the current console preference from the ConsolePref variable.
244 //
245 BufferSize = sizeof (ConsolePref);
246 Status = gRT->GetVariable (CONSOLE_PREF_VARIABLE_NAME,
247 &gConsolePrefFormSetGuid, NULL, &BufferSize, &ConsolePref);
248 if (EFI_ERROR (Status)) {
249 DEBUG ((DEBUG_INFO,
250 "%a: no console preference found, defaulting to graphical\n",
251 __FUNCTION__));
252 ConsolePref.Console = CONSOLE_PREF_GRAPHICAL;
253 }
254
255 if (!EFI_ERROR (Status) &&
256 ConsolePref.Console != CONSOLE_PREF_GRAPHICAL &&
257 ConsolePref.Console != CONSOLE_PREF_SERIAL) {
258 DEBUG ((DEBUG_WARN, "%a: invalid value for %s, defaulting to graphical\n",
259 __FUNCTION__, CONSOLE_PREF_VARIABLE_NAME));
260 ConsolePref.Console = CONSOLE_PREF_GRAPHICAL;
261 Status = EFI_INVALID_PARAMETER; // trigger setvar below
262 }
263
264 //
265 // Write the newly selected value back to the variable store.
266 //
267 if (EFI_ERROR (Status)) {
268 ZeroMem (&ConsolePref.Reserved, sizeof (ConsolePref.Reserved));
269 Status = gRT->SetVariable (CONSOLE_PREF_VARIABLE_NAME,
270 &gConsolePrefFormSetGuid,
271 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
272 sizeof (ConsolePref), &ConsolePref);
273
274 if (EFI_ERROR (Status)) {
275 DEBUG ((DEBUG_ERROR, "%a: gRT->SetVariable () failed - %r\n",
276 __FUNCTION__, Status));
277 return Status;
278 }
279 }
280
281 Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
282 OnReadyToBoot, NULL, &gEfiEventReadyToBootGuid,
283 &mReadyToBootEvent);
284 ASSERT_EFI_ERROR (Status);
285
286 return InstallHiiPages ();
287 }