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