]> git.proxmox.com Git - mirror_edk2.git/blob - ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c
OvmfPkg, ArmVirtPkg: clean up SetBootOrderFromQemu() parameter list
[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 EfiBootManagerConnectAll ();
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 //
550 // Enumerate all possible boot options, then filter and reorder them based on
551 // the QEMU configuration.
552 //
553 EfiBootManagerRefreshAllBootOption ();
554 SetBootOrderFromQemu ();
555 }
556
557 /**
558 This function is called each second during the boot manager waits the
559 timeout.
560
561 @param TimeoutRemain The remaining timeout.
562 **/
563 VOID
564 EFIAPI
565 PlatformBootManagerWaitCallback (
566 UINT16 TimeoutRemain
567 )
568 {
569 }