]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Library/PlatformBootManagerLib/PlatformBm.c
ArmPkg/PlatformBootManagerLib: process pending capsules
[mirror_edk2.git] / ArmPkg / Library / PlatformBootManagerLib / PlatformBm.c
1 /** @file
2 Implementation for PlatformBootManagerLib library class interfaces.
3
4 Copyright (C) 2015-2016, Red Hat, Inc.
5 Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
6 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
7 Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
8
9 This program and the accompanying materials are licensed and made available
10 under the terms and conditions of the BSD License which accompanies this
11 distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
13
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
15 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16
17 **/
18
19 #include <IndustryStandard/Pci22.h>
20 #include <Library/BootLogoLib.h>
21 #include <Library/CapsuleLib.h>
22 #include <Library/DevicePathLib.h>
23 #include <Library/HobLib.h>
24 #include <Library/PcdLib.h>
25 #include <Library/UefiBootManagerLib.h>
26 #include <Library/UefiLib.h>
27 #include <Protocol/DevicePath.h>
28 #include <Protocol/GraphicsOutput.h>
29 #include <Protocol/LoadedImage.h>
30 #include <Protocol/PciIo.h>
31 #include <Protocol/PciRootBridgeIo.h>
32 #include <Guid/EventGroup.h>
33 #include <Guid/TtyTerm.h>
34
35 #include "PlatformBm.h"
36
37 #define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }
38
39 #pragma pack (1)
40 typedef struct {
41 VENDOR_DEVICE_PATH SerialDxe;
42 UART_DEVICE_PATH Uart;
43 VENDOR_DEFINED_DEVICE_PATH TermType;
44 EFI_DEVICE_PATH_PROTOCOL End;
45 } PLATFORM_SERIAL_CONSOLE;
46 #pragma pack ()
47
48 #define SERIAL_DXE_FILE_GUID { \
49 0xD3987D4B, 0x971A, 0x435F, \
50 { 0x8C, 0xAF, 0x49, 0x67, 0xEB, 0x62, 0x72, 0x41 } \
51 }
52
53 STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole = {
54 //
55 // VENDOR_DEVICE_PATH SerialDxe
56 //
57 {
58 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },
59 SERIAL_DXE_FILE_GUID
60 },
61
62 //
63 // UART_DEVICE_PATH Uart
64 //
65 {
66 { MESSAGING_DEVICE_PATH, MSG_UART_DP, DP_NODE_LEN (UART_DEVICE_PATH) },
67 0, // Reserved
68 FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate
69 FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits
70 FixedPcdGet8 (PcdUartDefaultParity), // Parity
71 FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits
72 },
73
74 //
75 // VENDOR_DEFINED_DEVICE_PATH TermType
76 //
77 {
78 {
79 MESSAGING_DEVICE_PATH, MSG_VENDOR_DP,
80 DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH)
81 }
82 //
83 // Guid to be filled in dynamically
84 //
85 },
86
87 //
88 // EFI_DEVICE_PATH_PROTOCOL End
89 //
90 {
91 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
92 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
93 }
94 };
95
96
97 #pragma pack (1)
98 typedef struct {
99 USB_CLASS_DEVICE_PATH Keyboard;
100 EFI_DEVICE_PATH_PROTOCOL End;
101 } PLATFORM_USB_KEYBOARD;
102 #pragma pack ()
103
104 STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard = {
105 //
106 // USB_CLASS_DEVICE_PATH Keyboard
107 //
108 {
109 {
110 MESSAGING_DEVICE_PATH, MSG_USB_CLASS_DP,
111 DP_NODE_LEN (USB_CLASS_DEVICE_PATH)
112 },
113 0xFFFF, // VendorId: any
114 0xFFFF, // ProductId: any
115 3, // DeviceClass: HID
116 1, // DeviceSubClass: boot
117 1 // DeviceProtocol: keyboard
118 },
119
120 //
121 // EFI_DEVICE_PATH_PROTOCOL End
122 //
123 {
124 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
125 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
126 }
127 };
128
129
130 /**
131 Check if the handle satisfies a particular condition.
132
133 @param[in] Handle The handle to check.
134 @param[in] ReportText A caller-allocated string passed in for reporting
135 purposes. It must never be NULL.
136
137 @retval TRUE The condition is satisfied.
138 @retval FALSE Otherwise. This includes the case when the condition could not
139 be fully evaluated due to an error.
140 **/
141 typedef
142 BOOLEAN
143 (EFIAPI *FILTER_FUNCTION) (
144 IN EFI_HANDLE Handle,
145 IN CONST CHAR16 *ReportText
146 );
147
148
149 /**
150 Process a handle.
151
152 @param[in] Handle The handle to process.
153 @param[in] ReportText A caller-allocated string passed in for reporting
154 purposes. It must never be NULL.
155 **/
156 typedef
157 VOID
158 (EFIAPI *CALLBACK_FUNCTION) (
159 IN EFI_HANDLE Handle,
160 IN CONST CHAR16 *ReportText
161 );
162
163 /**
164 Locate all handles that carry the specified protocol, filter them with a
165 callback function, and pass each handle that passes the filter to another
166 callback.
167
168 @param[in] ProtocolGuid The protocol to look for.
169
170 @param[in] Filter The filter function to pass each handle to. If this
171 parameter is NULL, then all handles are processed.
172
173 @param[in] Process The callback function to pass each handle to that
174 clears the filter.
175 **/
176 STATIC
177 VOID
178 FilterAndProcess (
179 IN EFI_GUID *ProtocolGuid,
180 IN FILTER_FUNCTION Filter OPTIONAL,
181 IN CALLBACK_FUNCTION Process
182 )
183 {
184 EFI_STATUS Status;
185 EFI_HANDLE *Handles;
186 UINTN NoHandles;
187 UINTN Idx;
188
189 Status = gBS->LocateHandleBuffer (ByProtocol, ProtocolGuid,
190 NULL /* SearchKey */, &NoHandles, &Handles);
191 if (EFI_ERROR (Status)) {
192 //
193 // This is not an error, just an informative condition.
194 //
195 DEBUG ((EFI_D_VERBOSE, "%a: %g: %r\n", __FUNCTION__, ProtocolGuid,
196 Status));
197 return;
198 }
199
200 ASSERT (NoHandles > 0);
201 for (Idx = 0; Idx < NoHandles; ++Idx) {
202 CHAR16 *DevicePathText;
203 STATIC CHAR16 Fallback[] = L"<device path unavailable>";
204
205 //
206 // The ConvertDevicePathToText() function handles NULL input transparently.
207 //
208 DevicePathText = ConvertDevicePathToText (
209 DevicePathFromHandle (Handles[Idx]),
210 FALSE, // DisplayOnly
211 FALSE // AllowShortcuts
212 );
213 if (DevicePathText == NULL) {
214 DevicePathText = Fallback;
215 }
216
217 if (Filter == NULL || Filter (Handles[Idx], DevicePathText)) {
218 Process (Handles[Idx], DevicePathText);
219 }
220
221 if (DevicePathText != Fallback) {
222 FreePool (DevicePathText);
223 }
224 }
225 gBS->FreePool (Handles);
226 }
227
228
229 /**
230 This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.
231 **/
232 STATIC
233 BOOLEAN
234 EFIAPI
235 IsPciDisplay (
236 IN EFI_HANDLE Handle,
237 IN CONST CHAR16 *ReportText
238 )
239 {
240 EFI_STATUS Status;
241 EFI_PCI_IO_PROTOCOL *PciIo;
242 PCI_TYPE00 Pci;
243
244 Status = gBS->HandleProtocol (Handle, &gEfiPciIoProtocolGuid,
245 (VOID**)&PciIo);
246 if (EFI_ERROR (Status)) {
247 //
248 // This is not an error worth reporting.
249 //
250 return FALSE;
251 }
252
253 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0 /* Offset */,
254 sizeof Pci / sizeof (UINT32), &Pci);
255 if (EFI_ERROR (Status)) {
256 DEBUG ((EFI_D_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));
257 return FALSE;
258 }
259
260 return IS_PCI_DISPLAY (&Pci);
261 }
262
263
264 /**
265 This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking
266 the matching driver to produce all first-level child handles.
267 **/
268 STATIC
269 VOID
270 EFIAPI
271 Connect (
272 IN EFI_HANDLE Handle,
273 IN CONST CHAR16 *ReportText
274 )
275 {
276 EFI_STATUS Status;
277
278 Status = gBS->ConnectController (
279 Handle, // ControllerHandle
280 NULL, // DriverImageHandle
281 NULL, // RemainingDevicePath -- produce all children
282 FALSE // Recursive
283 );
284 DEBUG ((EFI_ERROR (Status) ? EFI_D_ERROR : EFI_D_VERBOSE, "%a: %s: %r\n",
285 __FUNCTION__, ReportText, Status));
286 }
287
288
289 /**
290 This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the
291 handle, and adds it to ConOut and ErrOut.
292 **/
293 STATIC
294 VOID
295 EFIAPI
296 AddOutput (
297 IN EFI_HANDLE Handle,
298 IN CONST CHAR16 *ReportText
299 )
300 {
301 EFI_STATUS Status;
302 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
303
304 DevicePath = DevicePathFromHandle (Handle);
305 if (DevicePath == NULL) {
306 DEBUG ((EFI_D_ERROR, "%a: %s: handle %p: device path not found\n",
307 __FUNCTION__, ReportText, Handle));
308 return;
309 }
310
311 Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
312 if (EFI_ERROR (Status)) {
313 DEBUG ((EFI_D_ERROR, "%a: %s: adding to ConOut: %r\n", __FUNCTION__,
314 ReportText, Status));
315 return;
316 }
317
318 Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
319 if (EFI_ERROR (Status)) {
320 DEBUG ((EFI_D_ERROR, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__,
321 ReportText, Status));
322 return;
323 }
324
325 DEBUG ((EFI_D_VERBOSE, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__,
326 ReportText));
327 }
328
329 STATIC
330 VOID
331 PlatformRegisterFvBootOption (
332 CONST EFI_GUID *FileGuid,
333 CHAR16 *Description,
334 UINT32 Attributes
335 )
336 {
337 EFI_STATUS Status;
338 INTN OptionIndex;
339 EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
340 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
341 UINTN BootOptionCount;
342 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
343 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
344 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
345
346 Status = gBS->HandleProtocol (
347 gImageHandle,
348 &gEfiLoadedImageProtocolGuid,
349 (VOID **) &LoadedImage
350 );
351 ASSERT_EFI_ERROR (Status);
352
353 EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
354 DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
355 ASSERT (DevicePath != NULL);
356 DevicePath = AppendDevicePathNode (
357 DevicePath,
358 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
359 );
360 ASSERT (DevicePath != NULL);
361
362 Status = EfiBootManagerInitializeLoadOption (
363 &NewOption,
364 LoadOptionNumberUnassigned,
365 LoadOptionTypeBoot,
366 Attributes,
367 Description,
368 DevicePath,
369 NULL,
370 0
371 );
372 ASSERT_EFI_ERROR (Status);
373 FreePool (DevicePath);
374
375 BootOptions = EfiBootManagerGetLoadOptions (
376 &BootOptionCount, LoadOptionTypeBoot
377 );
378
379 OptionIndex = EfiBootManagerFindLoadOption (
380 &NewOption, BootOptions, BootOptionCount
381 );
382
383 if (OptionIndex == -1) {
384 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
385 ASSERT_EFI_ERROR (Status);
386 }
387 EfiBootManagerFreeLoadOption (&NewOption);
388 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
389 }
390
391
392 STATIC
393 VOID
394 PlatformRegisterOptionsAndKeys (
395 VOID
396 )
397 {
398 EFI_STATUS Status;
399 EFI_INPUT_KEY Enter;
400 EFI_INPUT_KEY F2;
401 EFI_INPUT_KEY Esc;
402 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
403
404 //
405 // Register ENTER as CONTINUE key
406 //
407 Enter.ScanCode = SCAN_NULL;
408 Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
409 Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
410 ASSERT_EFI_ERROR (Status);
411
412 //
413 // Map F2 and ESC to Boot Manager Menu
414 //
415 F2.ScanCode = SCAN_F2;
416 F2.UnicodeChar = CHAR_NULL;
417 Esc.ScanCode = SCAN_ESC;
418 Esc.UnicodeChar = CHAR_NULL;
419 Status = EfiBootManagerGetBootManagerMenu (&BootOption);
420 ASSERT_EFI_ERROR (Status);
421 Status = EfiBootManagerAddKeyOptionVariable (
422 NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL
423 );
424 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
425 Status = EfiBootManagerAddKeyOptionVariable (
426 NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL
427 );
428 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
429 }
430
431
432 //
433 // BDS Platform Functions
434 //
435 /**
436 Do the platform init, can be customized by OEM/IBV
437 Possible things that can be done in PlatformBootManagerBeforeConsole:
438 > Update console variable: 1. include hot-plug devices;
439 > 2. Clear ConIn and add SOL for AMT
440 > Register new Driver#### or Boot####
441 > Register new Key####: e.g.: F12
442 > Signal ReadyToLock event
443 > Authentication action: 1. connect Auth devices;
444 > 2. Identify auto logon user.
445 **/
446 VOID
447 EFIAPI
448 PlatformBootManagerBeforeConsole (
449 VOID
450 )
451 {
452 EFI_STATUS Status;
453
454 if (GetBootModeHob() == BOOT_ON_FLASH_UPDATE) {
455 DEBUG ((DEBUG_INFO, "ProcessCapsules Before EndOfDxe ......\n"));
456 Status = ProcessCapsules ();
457 DEBUG ((DEBUG_INFO, "ProcessCapsules returned %r\n", Status));
458 }
459
460 //
461 // Signal EndOfDxe PI Event
462 //
463 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
464
465 //
466 // Locate the PCI root bridges and make the PCI bus driver connect each,
467 // non-recursively. This will produce a number of child handles with PciIo on
468 // them.
469 //
470 FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect);
471
472 //
473 // Find all display class PCI devices (using the handles from the previous
474 // step), and connect them non-recursively. This should produce a number of
475 // child handles with GOPs on them.
476 //
477 FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);
478
479 //
480 // Now add the device path of all handles with GOP on them to ConOut and
481 // ErrOut.
482 //
483 FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);
484
485 //
486 // Add the hardcoded short-form USB keyboard device path to ConIn.
487 //
488 EfiBootManagerUpdateConsoleVariable (ConIn,
489 (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard, NULL);
490
491 //
492 // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.
493 //
494 ASSERT (FixedPcdGet8 (PcdDefaultTerminalType) == 4);
495 CopyGuid (&mSerialConsole.TermType.Guid, &gEfiTtyTermGuid);
496
497 EfiBootManagerUpdateConsoleVariable (ConIn,
498 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
499 EfiBootManagerUpdateConsoleVariable (ConOut,
500 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
501 EfiBootManagerUpdateConsoleVariable (ErrOut,
502 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
503
504 //
505 // Register platform-specific boot options and keyboard shortcuts.
506 //
507 PlatformRegisterOptionsAndKeys ();
508 }
509
510 /**
511 Do the platform specific action after the console is ready
512 Possible things that can be done in PlatformBootManagerAfterConsole:
513 > Console post action:
514 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
515 > Signal console ready platform customized event
516 > Run diagnostics like memory testing
517 > Connect certain devices
518 > Dispatch aditional option roms
519 > Special boot: e.g.: USB boot, enter UI
520 **/
521 VOID
522 EFIAPI
523 PlatformBootManagerAfterConsole (
524 VOID
525 )
526 {
527 EFI_STATUS Status;
528
529 //
530 // Show the splash screen.
531 //
532 Status = BootLogoEnableLogo ();
533 if (EFI_ERROR (Status)) {
534 Print (L"Press ESCAPE for boot options ");
535 }
536 //
537 // Connect the rest of the devices.
538 //
539 EfiBootManagerConnectAll ();
540
541 if (GetBootModeHob() == BOOT_ON_FLASH_UPDATE) {
542 DEBUG((DEBUG_INFO, "ProcessCapsules After EndOfDxe ......\n"));
543 Status = ProcessCapsules ();
544 DEBUG((DEBUG_INFO, "ProcessCapsules returned %r\n", Status));
545 }
546
547 //
548 // Enumerate all possible boot options.
549 //
550 EfiBootManagerRefreshAllBootOption ();
551
552 //
553 // Register UEFI Shell
554 //
555 PlatformRegisterFvBootOption (
556 &gUefiShellFileGuid, L"UEFI Shell", LOAD_OPTION_ACTIVE
557 );
558 }
559
560 /**
561 This function is called each second during the boot manager waits the
562 timeout.
563
564 @param TimeoutRemain The remaining timeout.
565 **/
566 VOID
567 EFIAPI
568 PlatformBootManagerWaitCallback (
569 UINT16 TimeoutRemain
570 )
571 {
572 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
573 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
574 UINT16 Timeout;
575 EFI_STATUS Status;
576
577 Timeout = PcdGet16 (PcdPlatformBootTimeOut);
578
579 Black.Raw = 0x00000000;
580 White.Raw = 0x00FFFFFF;
581
582 Status = BootLogoUpdateProgress (
583 White.Pixel,
584 Black.Pixel,
585 L"Press ESCAPE for boot options",
586 White.Pixel,
587 (Timeout - TimeoutRemain) * 100 / Timeout,
588 0
589 );
590 if (EFI_ERROR (Status)) {
591 Print (L".");
592 }
593 }