]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c
b5af58367e32197821f6d75e9cc376a13ce6ddc9
[mirror_edk2.git] / OvmfPkg / Library / PlatformBootManagerLib / BdsPlatform.c
1 /** @file
2 Platform BDS customizations.
3
4 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
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 "BdsPlatform.h"
16 #include <Guid/RootBridgesConnectedEventGroup.h>
17
18
19 //
20 // Global data
21 //
22
23 VOID *mEfiDevPathNotifyReg;
24 EFI_EVENT mEfiDevPathEvent;
25 VOID *mEmuVariableEventReg;
26 EFI_EVENT mEmuVariableEvent;
27 BOOLEAN mDetectVgaOnly;
28 UINT16 mHostBridgeDevId;
29
30 //
31 // Table of host IRQs matching PCI IRQs A-D
32 // (for configuring PCI Interrupt Line register)
33 //
34 CONST UINT8 PciHostIrqs[] = {
35 0x0a, 0x0a, 0x0b, 0x0b
36 };
37
38 //
39 // Array Size macro
40 //
41 #define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))
42
43 //
44 // Type definitions
45 //
46
47 typedef
48 EFI_STATUS
49 (EFIAPI *PROTOCOL_INSTANCE_CALLBACK)(
50 IN EFI_HANDLE Handle,
51 IN VOID *Instance,
52 IN VOID *Context
53 );
54
55 /**
56 @param[in] Handle - Handle of PCI device instance
57 @param[in] PciIo - PCI IO protocol instance
58 @param[in] Pci - PCI Header register block
59 **/
60 typedef
61 EFI_STATUS
62 (EFIAPI *VISIT_PCI_INSTANCE_CALLBACK)(
63 IN EFI_HANDLE Handle,
64 IN EFI_PCI_IO_PROTOCOL *PciIo,
65 IN PCI_TYPE00 *Pci
66 );
67
68
69 //
70 // Function prototypes
71 //
72
73 EFI_STATUS
74 VisitAllInstancesOfProtocol (
75 IN EFI_GUID *Id,
76 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,
77 IN VOID *Context
78 );
79
80 EFI_STATUS
81 VisitAllPciInstancesOfProtocol (
82 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
83 );
84
85 VOID
86 InstallDevicePathCallback (
87 VOID
88 );
89
90 VOID
91 PlatformRegisterFvBootOption (
92 EFI_GUID *FileGuid,
93 CHAR16 *Description,
94 UINT32 Attributes
95 )
96 {
97 EFI_STATUS Status;
98 INTN OptionIndex;
99 EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
100 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
101 UINTN BootOptionCount;
102 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
103 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
104 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
105
106 Status = gBS->HandleProtocol (
107 gImageHandle,
108 &gEfiLoadedImageProtocolGuid,
109 (VOID **) &LoadedImage
110 );
111 ASSERT_EFI_ERROR (Status);
112
113 EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
114 DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
115 ASSERT (DevicePath != NULL);
116 DevicePath = AppendDevicePathNode (
117 DevicePath,
118 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
119 );
120 ASSERT (DevicePath != NULL);
121
122 Status = EfiBootManagerInitializeLoadOption (
123 &NewOption,
124 LoadOptionNumberUnassigned,
125 LoadOptionTypeBoot,
126 Attributes,
127 Description,
128 DevicePath,
129 NULL,
130 0
131 );
132 ASSERT_EFI_ERROR (Status);
133 FreePool (DevicePath);
134
135 BootOptions = EfiBootManagerGetLoadOptions (
136 &BootOptionCount, LoadOptionTypeBoot
137 );
138
139 OptionIndex = EfiBootManagerFindLoadOption (
140 &NewOption, BootOptions, BootOptionCount
141 );
142
143 if (OptionIndex == -1) {
144 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
145 ASSERT_EFI_ERROR (Status);
146 }
147 EfiBootManagerFreeLoadOption (&NewOption);
148 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
149 }
150
151 VOID
152 PlatformRegisterOptionsAndKeys (
153 VOID
154 )
155 {
156 EFI_STATUS Status;
157 EFI_INPUT_KEY Enter;
158 EFI_INPUT_KEY F2;
159 EFI_INPUT_KEY Esc;
160 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
161
162 //
163 // Register ENTER as CONTINUE key
164 //
165 Enter.ScanCode = SCAN_NULL;
166 Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
167 Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
168 ASSERT_EFI_ERROR (Status);
169
170 //
171 // Map F2 to Boot Manager Menu
172 //
173 F2.ScanCode = SCAN_F2;
174 F2.UnicodeChar = CHAR_NULL;
175 Esc.ScanCode = SCAN_ESC;
176 Esc.UnicodeChar = CHAR_NULL;
177 Status = EfiBootManagerGetBootManagerMenu (&BootOption);
178 ASSERT_EFI_ERROR (Status);
179 Status = EfiBootManagerAddKeyOptionVariable (
180 NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL
181 );
182 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
183 Status = EfiBootManagerAddKeyOptionVariable (
184 NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL
185 );
186 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
187 }
188
189 EFI_STATUS
190 EFIAPI
191 ConnectRootBridge (
192 IN EFI_HANDLE RootBridgeHandle,
193 IN VOID *Instance,
194 IN VOID *Context
195 );
196
197 STATIC
198 VOID
199 SaveS3BootScript (
200 VOID
201 );
202
203 //
204 // BDS Platform Functions
205 //
206 VOID
207 EFIAPI
208 PlatformBootManagerBeforeConsole (
209 VOID
210 )
211 /*++
212
213 Routine Description:
214
215 Platform Bds init. Incude the platform firmware vendor, revision
216 and so crc check.
217
218 Arguments:
219
220 Returns:
221
222 None.
223
224 --*/
225 {
226 EFI_HANDLE Handle;
227 EFI_STATUS Status;
228
229 DEBUG ((EFI_D_INFO, "PlatformBootManagerBeforeConsole\n"));
230 InstallDevicePathCallback ();
231
232 VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid,
233 ConnectRootBridge, NULL);
234
235 //
236 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
237 //
238 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);
239
240 //
241 // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
242 // the preparation of S3 system information. That logic has a hard dependency
243 // on the presence of the FACS ACPI table. Since our ACPI tables are only
244 // installed after PCI enumeration completes, we must not trigger the S3 save
245 // earlier, hence we can't signal End-of-Dxe earlier.
246 //
247 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
248
249 if (QemuFwCfgS3Enabled ()) {
250 //
251 // Save the boot script too. Note that this will require us to emit the
252 // DxeSmmReadyToLock event just below, which in turn locks down SMM.
253 //
254 SaveS3BootScript ();
255 }
256
257 //
258 // Prevent further changes to LockBoxes or SMRAM.
259 //
260 Handle = NULL;
261 Status = gBS->InstallProtocolInterface (&Handle,
262 &gEfiDxeSmmReadyToLockProtocolGuid, EFI_NATIVE_INTERFACE,
263 NULL);
264 ASSERT_EFI_ERROR (Status);
265
266 PlatformInitializeConsole (gPlatformConsole);
267 PcdSet16 (PcdPlatformBootTimeOut, GetFrontPageTimeoutFromQemu ());
268
269 PlatformRegisterOptionsAndKeys ();
270 }
271
272
273 EFI_STATUS
274 EFIAPI
275 ConnectRootBridge (
276 IN EFI_HANDLE RootBridgeHandle,
277 IN VOID *Instance,
278 IN VOID *Context
279 )
280 {
281 EFI_STATUS Status;
282
283 //
284 // Make the PCI bus driver connect the root bridge, non-recursively. This
285 // will produce a number of child handles with PciIo on them.
286 //
287 Status = gBS->ConnectController (
288 RootBridgeHandle, // ControllerHandle
289 NULL, // DriverImageHandle
290 NULL, // RemainingDevicePath -- produce all
291 // children
292 FALSE // Recursive
293 );
294 return Status;
295 }
296
297
298 EFI_STATUS
299 PrepareLpcBridgeDevicePath (
300 IN EFI_HANDLE DeviceHandle
301 )
302 /*++
303
304 Routine Description:
305
306 Add IsaKeyboard to ConIn,
307 add IsaSerial to ConOut, ConIn, ErrOut.
308 LPC Bridge: 06 01 00
309
310 Arguments:
311
312 DeviceHandle - Handle of PCIIO protocol.
313
314 Returns:
315
316 EFI_SUCCESS - LPC bridge is added to ConOut, ConIn, and ErrOut.
317 EFI_STATUS - No LPC bridge is added.
318
319 --*/
320 {
321 EFI_STATUS Status;
322 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
323 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
324 CHAR16 *DevPathStr;
325
326 DevicePath = NULL;
327 Status = gBS->HandleProtocol (
328 DeviceHandle,
329 &gEfiDevicePathProtocolGuid,
330 (VOID*)&DevicePath
331 );
332 if (EFI_ERROR (Status)) {
333 return Status;
334 }
335 TempDevicePath = DevicePath;
336
337 //
338 // Register Keyboard
339 //
340 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode);
341
342 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
343
344 //
345 // Register COM1
346 //
347 DevicePath = TempDevicePath;
348 gPnp16550ComPortDeviceNode.UID = 0;
349
350 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);
351 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
352 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
353
354 //
355 // Print Device Path
356 //
357 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
358 if (DevPathStr != NULL) {
359 DEBUG((
360 EFI_D_INFO,
361 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
362 __LINE__,
363 gPnp16550ComPortDeviceNode.UID + 1,
364 DevPathStr
365 ));
366 FreePool(DevPathStr);
367 }
368
369 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
370 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
371 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
372
373 //
374 // Register COM2
375 //
376 DevicePath = TempDevicePath;
377 gPnp16550ComPortDeviceNode.UID = 1;
378
379 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);
380 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
381 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
382
383 //
384 // Print Device Path
385 //
386 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
387 if (DevPathStr != NULL) {
388 DEBUG((
389 EFI_D_INFO,
390 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
391 __LINE__,
392 gPnp16550ComPortDeviceNode.UID + 1,
393 DevPathStr
394 ));
395 FreePool(DevPathStr);
396 }
397
398 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
399 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
400 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
401
402 return EFI_SUCCESS;
403 }
404
405 EFI_STATUS
406 GetGopDevicePath (
407 IN EFI_DEVICE_PATH_PROTOCOL *PciDevicePath,
408 OUT EFI_DEVICE_PATH_PROTOCOL **GopDevicePath
409 )
410 {
411 UINTN Index;
412 EFI_STATUS Status;
413 EFI_HANDLE PciDeviceHandle;
414 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
415 EFI_DEVICE_PATH_PROTOCOL *TempPciDevicePath;
416 UINTN GopHandleCount;
417 EFI_HANDLE *GopHandleBuffer;
418
419 if (PciDevicePath == NULL || GopDevicePath == NULL) {
420 return EFI_INVALID_PARAMETER;
421 }
422
423 //
424 // Initialize the GopDevicePath to be PciDevicePath
425 //
426 *GopDevicePath = PciDevicePath;
427 TempPciDevicePath = PciDevicePath;
428
429 Status = gBS->LocateDevicePath (
430 &gEfiDevicePathProtocolGuid,
431 &TempPciDevicePath,
432 &PciDeviceHandle
433 );
434 if (EFI_ERROR (Status)) {
435 return Status;
436 }
437
438 //
439 // Try to connect this handle, so that GOP dirver could start on this
440 // device and create child handles with GraphicsOutput Protocol installed
441 // on them, then we get device paths of these child handles and select
442 // them as possible console device.
443 //
444 gBS->ConnectController (PciDeviceHandle, NULL, NULL, FALSE);
445
446 Status = gBS->LocateHandleBuffer (
447 ByProtocol,
448 &gEfiGraphicsOutputProtocolGuid,
449 NULL,
450 &GopHandleCount,
451 &GopHandleBuffer
452 );
453 if (!EFI_ERROR (Status)) {
454 //
455 // Add all the child handles as possible Console Device
456 //
457 for (Index = 0; Index < GopHandleCount; Index++) {
458 Status = gBS->HandleProtocol (GopHandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID*)&TempDevicePath);
459 if (EFI_ERROR (Status)) {
460 continue;
461 }
462 if (CompareMem (
463 PciDevicePath,
464 TempDevicePath,
465 GetDevicePathSize (PciDevicePath) - END_DEVICE_PATH_LENGTH
466 ) == 0) {
467 //
468 // In current implementation, we only enable one of the child handles
469 // as console device, i.e. sotre one of the child handle's device
470 // path to variable "ConOut"
471 // In futhure, we could select all child handles to be console device
472 //
473
474 *GopDevicePath = TempDevicePath;
475
476 //
477 // Delete the PCI device's path that added by GetPlugInPciVgaDevicePath()
478 // Add the integrity GOP device path.
479 //
480 EfiBootManagerUpdateConsoleVariable (ConOutDev, NULL, PciDevicePath);
481 EfiBootManagerUpdateConsoleVariable (ConOutDev, TempDevicePath, NULL);
482 }
483 }
484 gBS->FreePool (GopHandleBuffer);
485 }
486
487 return EFI_SUCCESS;
488 }
489
490 EFI_STATUS
491 PreparePciVgaDevicePath (
492 IN EFI_HANDLE DeviceHandle
493 )
494 /*++
495
496 Routine Description:
497
498 Add PCI VGA to ConOut.
499 PCI VGA: 03 00 00
500
501 Arguments:
502
503 DeviceHandle - Handle of PCIIO protocol.
504
505 Returns:
506
507 EFI_SUCCESS - PCI VGA is added to ConOut.
508 EFI_STATUS - No PCI VGA device is added.
509
510 --*/
511 {
512 EFI_STATUS Status;
513 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
514 EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;
515
516 DevicePath = NULL;
517 GopDevicePath = NULL;
518 Status = gBS->HandleProtocol (
519 DeviceHandle,
520 &gEfiDevicePathProtocolGuid,
521 (VOID*)&DevicePath
522 );
523 if (EFI_ERROR (Status)) {
524 return Status;
525 }
526
527 GetGopDevicePath (DevicePath, &GopDevicePath);
528 DevicePath = GopDevicePath;
529
530 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
531
532 return EFI_SUCCESS;
533 }
534
535 EFI_STATUS
536 PreparePciSerialDevicePath (
537 IN EFI_HANDLE DeviceHandle
538 )
539 /*++
540
541 Routine Description:
542
543 Add PCI Serial to ConOut, ConIn, ErrOut.
544 PCI Serial: 07 00 02
545
546 Arguments:
547
548 DeviceHandle - Handle of PCIIO protocol.
549
550 Returns:
551
552 EFI_SUCCESS - PCI Serial is added to ConOut, ConIn, and ErrOut.
553 EFI_STATUS - No PCI Serial device is added.
554
555 --*/
556 {
557 EFI_STATUS Status;
558 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
559
560 DevicePath = NULL;
561 Status = gBS->HandleProtocol (
562 DeviceHandle,
563 &gEfiDevicePathProtocolGuid,
564 (VOID*)&DevicePath
565 );
566 if (EFI_ERROR (Status)) {
567 return Status;
568 }
569
570 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
571 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
572
573 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
574 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
575 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
576
577 return EFI_SUCCESS;
578 }
579
580 EFI_STATUS
581 VisitAllInstancesOfProtocol (
582 IN EFI_GUID *Id,
583 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,
584 IN VOID *Context
585 )
586 {
587 EFI_STATUS Status;
588 UINTN HandleCount;
589 EFI_HANDLE *HandleBuffer;
590 UINTN Index;
591 VOID *Instance;
592
593 //
594 // Start to check all the PciIo to find all possible device
595 //
596 HandleCount = 0;
597 HandleBuffer = NULL;
598 Status = gBS->LocateHandleBuffer (
599 ByProtocol,
600 Id,
601 NULL,
602 &HandleCount,
603 &HandleBuffer
604 );
605 if (EFI_ERROR (Status)) {
606 return Status;
607 }
608
609 for (Index = 0; Index < HandleCount; Index++) {
610 Status = gBS->HandleProtocol (HandleBuffer[Index], Id, &Instance);
611 if (EFI_ERROR (Status)) {
612 continue;
613 }
614
615 Status = (*CallBackFunction) (
616 HandleBuffer[Index],
617 Instance,
618 Context
619 );
620 }
621
622 gBS->FreePool (HandleBuffer);
623
624 return EFI_SUCCESS;
625 }
626
627
628 EFI_STATUS
629 EFIAPI
630 VisitingAPciInstance (
631 IN EFI_HANDLE Handle,
632 IN VOID *Instance,
633 IN VOID *Context
634 )
635 {
636 EFI_STATUS Status;
637 EFI_PCI_IO_PROTOCOL *PciIo;
638 PCI_TYPE00 Pci;
639
640 PciIo = (EFI_PCI_IO_PROTOCOL*) Instance;
641
642 //
643 // Check for all PCI device
644 //
645 Status = PciIo->Pci.Read (
646 PciIo,
647 EfiPciIoWidthUint32,
648 0,
649 sizeof (Pci) / sizeof (UINT32),
650 &Pci
651 );
652 if (EFI_ERROR (Status)) {
653 return Status;
654 }
655
656 return (*(VISIT_PCI_INSTANCE_CALLBACK)(UINTN) Context) (
657 Handle,
658 PciIo,
659 &Pci
660 );
661
662 }
663
664
665
666 EFI_STATUS
667 VisitAllPciInstances (
668 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
669 )
670 {
671 return VisitAllInstancesOfProtocol (
672 &gEfiPciIoProtocolGuid,
673 VisitingAPciInstance,
674 (VOID*)(UINTN) CallBackFunction
675 );
676 }
677
678
679 /**
680 Do platform specific PCI Device check and add them to
681 ConOut, ConIn, ErrOut.
682
683 @param[in] Handle - Handle of PCI device instance
684 @param[in] PciIo - PCI IO protocol instance
685 @param[in] Pci - PCI Header register block
686
687 @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
688 @retval EFI_STATUS - PCI Device check or Console variable update fail.
689
690 **/
691 EFI_STATUS
692 EFIAPI
693 DetectAndPreparePlatformPciDevicePath (
694 IN EFI_HANDLE Handle,
695 IN EFI_PCI_IO_PROTOCOL *PciIo,
696 IN PCI_TYPE00 *Pci
697 )
698 {
699 EFI_STATUS Status;
700
701 Status = PciIo->Attributes (
702 PciIo,
703 EfiPciIoAttributeOperationEnable,
704 EFI_PCI_DEVICE_ENABLE,
705 NULL
706 );
707 ASSERT_EFI_ERROR (Status);
708
709 if (!mDetectVgaOnly) {
710 //
711 // Here we decide whether it is LPC Bridge
712 //
713 if ((IS_PCI_LPC (Pci)) ||
714 ((IS_PCI_ISA_PDECODE (Pci)) &&
715 (Pci->Hdr.VendorId == 0x8086) &&
716 (Pci->Hdr.DeviceId == 0x7000)
717 )
718 ) {
719 //
720 // Add IsaKeyboard to ConIn,
721 // add IsaSerial to ConOut, ConIn, ErrOut
722 //
723 DEBUG ((EFI_D_INFO, "Found LPC Bridge device\n"));
724 PrepareLpcBridgeDevicePath (Handle);
725 return EFI_SUCCESS;
726 }
727 //
728 // Here we decide which Serial device to enable in PCI bus
729 //
730 if (IS_PCI_16550SERIAL (Pci)) {
731 //
732 // Add them to ConOut, ConIn, ErrOut.
733 //
734 DEBUG ((EFI_D_INFO, "Found PCI 16550 SERIAL device\n"));
735 PreparePciSerialDevicePath (Handle);
736 return EFI_SUCCESS;
737 }
738 }
739
740 //
741 // Here we decide which VGA device to enable in PCI bus
742 //
743 if (IS_PCI_VGA (Pci)) {
744 //
745 // Add them to ConOut.
746 //
747 DEBUG ((EFI_D_INFO, "Found PCI VGA device\n"));
748 PreparePciVgaDevicePath (Handle);
749 return EFI_SUCCESS;
750 }
751
752 return Status;
753 }
754
755
756 /**
757 Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
758
759 @param[in] DetectVgaOnly - Only detect VGA device if it's TRUE.
760
761 @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
762 @retval EFI_STATUS - PCI Device check or Console variable update fail.
763
764 **/
765 EFI_STATUS
766 DetectAndPreparePlatformPciDevicePaths (
767 BOOLEAN DetectVgaOnly
768 )
769 {
770 mDetectVgaOnly = DetectVgaOnly;
771 return VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath);
772 }
773
774
775 VOID
776 PlatformInitializeConsole (
777 IN PLATFORM_CONSOLE_CONNECT_ENTRY *PlatformConsole
778 )
779 /*++
780
781 Routine Description:
782
783 Connect the predefined platform default console device. Always try to find
784 and enable the vga device if have.
785
786 Arguments:
787
788 PlatformConsole - Predfined platform default console device array.
789 --*/
790 {
791 UINTN Index;
792 EFI_DEVICE_PATH_PROTOCOL *VarConout;
793 EFI_DEVICE_PATH_PROTOCOL *VarConin;
794
795 //
796 // Connect RootBridge
797 //
798 GetEfiGlobalVariable2 (EFI_CON_OUT_VARIABLE_NAME, (VOID **) &VarConout, NULL);
799 GetEfiGlobalVariable2 (EFI_CON_IN_VARIABLE_NAME, (VOID **) &VarConin, NULL);
800
801 if (VarConout == NULL || VarConin == NULL) {
802 //
803 // Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
804 //
805 DetectAndPreparePlatformPciDevicePaths (FALSE);
806
807 //
808 // Have chance to connect the platform default console,
809 // the platform default console is the minimue device group
810 // the platform should support
811 //
812 for (Index = 0; PlatformConsole[Index].DevicePath != NULL; ++Index) {
813 //
814 // Update the console variable with the connect type
815 //
816 if ((PlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {
817 EfiBootManagerUpdateConsoleVariable (ConIn, PlatformConsole[Index].DevicePath, NULL);
818 }
819 if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {
820 EfiBootManagerUpdateConsoleVariable (ConOut, PlatformConsole[Index].DevicePath, NULL);
821 }
822 if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {
823 EfiBootManagerUpdateConsoleVariable (ErrOut, PlatformConsole[Index].DevicePath, NULL);
824 }
825 }
826 } else {
827 //
828 // Only detect VGA device and add them to ConOut
829 //
830 DetectAndPreparePlatformPciDevicePaths (TRUE);
831 }
832 }
833
834
835 /**
836 Configure PCI Interrupt Line register for applicable devices
837 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
838
839 @param[in] Handle - Handle of PCI device instance
840 @param[in] PciIo - PCI IO protocol instance
841 @param[in] PciHdr - PCI Header register block
842
843 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
844
845 **/
846 EFI_STATUS
847 EFIAPI
848 SetPciIntLine (
849 IN EFI_HANDLE Handle,
850 IN EFI_PCI_IO_PROTOCOL *PciIo,
851 IN PCI_TYPE00 *PciHdr
852 )
853 {
854 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
855 EFI_DEVICE_PATH_PROTOCOL *DevPath;
856 UINTN RootSlot;
857 UINTN Idx;
858 UINT8 IrqLine;
859 EFI_STATUS Status;
860 UINT32 RootBusNumber;
861
862 Status = EFI_SUCCESS;
863
864 if (PciHdr->Device.InterruptPin != 0) {
865
866 DevPathNode = DevicePathFromHandle (Handle);
867 ASSERT (DevPathNode != NULL);
868 DevPath = DevPathNode;
869
870 RootBusNumber = 0;
871 if (DevicePathType (DevPathNode) == ACPI_DEVICE_PATH &&
872 DevicePathSubType (DevPathNode) == ACPI_DP &&
873 ((ACPI_HID_DEVICE_PATH *)DevPathNode)->HID == EISA_PNP_ID(0x0A03)) {
874 RootBusNumber = ((ACPI_HID_DEVICE_PATH *)DevPathNode)->UID;
875 }
876
877 //
878 // Compute index into PciHostIrqs[] table by walking
879 // the device path and adding up all device numbers
880 //
881 Status = EFI_NOT_FOUND;
882 RootSlot = 0;
883 Idx = PciHdr->Device.InterruptPin - 1;
884 while (!IsDevicePathEnd (DevPathNode)) {
885 if (DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH &&
886 DevicePathSubType (DevPathNode) == HW_PCI_DP) {
887
888 Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;
889
890 //
891 // Unlike SeaBIOS, which starts climbing from the leaf device
892 // up toward the root, we traverse the device path starting at
893 // the root moving toward the leaf node.
894 // The slot number of the top-level parent bridge is needed for
895 // Q35 cases with more than 24 slots on the root bus.
896 //
897 if (Status != EFI_SUCCESS) {
898 Status = EFI_SUCCESS;
899 RootSlot = ((PCI_DEVICE_PATH *)DevPathNode)->Device;
900 }
901 }
902
903 DevPathNode = NextDevicePathNode (DevPathNode);
904 }
905 if (EFI_ERROR (Status)) {
906 return Status;
907 }
908 if (RootBusNumber == 0 && RootSlot == 0) {
909 DEBUG((
910 EFI_D_ERROR,
911 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
912 __FUNCTION__
913 ));
914 ASSERT (FALSE);
915 }
916
917 //
918 // Final PciHostIrqs[] index calculation depends on the platform
919 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
920 //
921 switch (mHostBridgeDevId) {
922 case INTEL_82441_DEVICE_ID:
923 Idx -= 1;
924 break;
925 case INTEL_Q35_MCH_DEVICE_ID:
926 //
927 // SeaBIOS contains the following comment:
928 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
929 // with a different starting index - see q35-acpi-dsdt.dsl.
930 //
931 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
932 //
933 if (RootSlot > 24) {
934 //
935 // in this case, subtract back out RootSlot from Idx
936 // (SeaBIOS never adds it to begin with, but that would make our
937 // device path traversal loop above too awkward)
938 //
939 Idx -= RootSlot;
940 }
941 break;
942 default:
943 ASSERT (FALSE); // should never get here
944 }
945 Idx %= ARRAY_SIZE (PciHostIrqs);
946 IrqLine = PciHostIrqs[Idx];
947
948 DEBUG_CODE_BEGIN ();
949 {
950 CHAR16 *DevPathString;
951 STATIC CHAR16 Fallback[] = L"<failed to convert>";
952 UINTN Segment, Bus, Device, Function;
953
954 DevPathString = ConvertDevicePathToText (DevPath, FALSE, FALSE);
955 if (DevPathString == NULL) {
956 DevPathString = Fallback;
957 }
958 Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);
959 ASSERT_EFI_ERROR (Status);
960
961 DEBUG ((EFI_D_VERBOSE, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__,
962 (UINT32)Bus, (UINT32)Device, (UINT32)Function, DevPathString,
963 IrqLine));
964
965 if (DevPathString != Fallback) {
966 FreePool (DevPathString);
967 }
968 }
969 DEBUG_CODE_END ();
970
971 //
972 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
973 //
974 Status = PciIo->Pci.Write (
975 PciIo,
976 EfiPciIoWidthUint8,
977 PCI_INT_LINE_OFFSET,
978 1,
979 &IrqLine
980 );
981 }
982
983 return Status;
984 }
985
986
987 VOID
988 PciAcpiInitialization (
989 )
990 {
991 UINTN Pmba;
992
993 //
994 // Query Host Bridge DID to determine platform type
995 //
996 mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);
997 switch (mHostBridgeDevId) {
998 case INTEL_82441_DEVICE_ID:
999 Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
1000 //
1001 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
1002 //
1003 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
1004 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
1005 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
1006 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
1007 break;
1008 case INTEL_Q35_MCH_DEVICE_ID:
1009 Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);
1010 //
1011 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
1012 //
1013 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
1014 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
1015 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
1016 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
1017 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
1018 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
1019 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
1020 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
1021 break;
1022 default:
1023 DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
1024 __FUNCTION__, mHostBridgeDevId));
1025 ASSERT (FALSE);
1026 return;
1027 }
1028
1029 //
1030 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
1031 //
1032 VisitAllPciInstances (SetPciIntLine);
1033
1034 //
1035 // Set ACPI SCI_EN bit in PMCNTRL
1036 //
1037 IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);
1038 }
1039
1040
1041 EFI_STATUS
1042 EFIAPI
1043 ConnectRecursivelyIfPciMassStorage (
1044 IN EFI_HANDLE Handle,
1045 IN EFI_PCI_IO_PROTOCOL *Instance,
1046 IN PCI_TYPE00 *PciHeader
1047 )
1048 {
1049 EFI_STATUS Status;
1050 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1051 CHAR16 *DevPathStr;
1052
1053 if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE)) {
1054 DevicePath = NULL;
1055 Status = gBS->HandleProtocol (
1056 Handle,
1057 &gEfiDevicePathProtocolGuid,
1058 (VOID*)&DevicePath
1059 );
1060 if (EFI_ERROR (Status)) {
1061 return Status;
1062 }
1063
1064 //
1065 // Print Device Path
1066 //
1067 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
1068 if (DevPathStr != NULL) {
1069 DEBUG((
1070 EFI_D_INFO,
1071 "Found Mass Storage device: %s\n",
1072 DevPathStr
1073 ));
1074 FreePool(DevPathStr);
1075 }
1076
1077 Status = gBS->ConnectController (Handle, NULL, NULL, TRUE);
1078 if (EFI_ERROR (Status)) {
1079 return Status;
1080 }
1081
1082 }
1083
1084 return EFI_SUCCESS;
1085 }
1086
1087
1088 /**
1089 This notification function is invoked when the
1090 EMU Variable FVB has been changed.
1091
1092 @param Event The event that occured
1093 @param Context For EFI compatiblity. Not used.
1094
1095 **/
1096 VOID
1097 EFIAPI
1098 EmuVariablesUpdatedCallback (
1099 IN EFI_EVENT Event,
1100 IN VOID *Context
1101 )
1102 {
1103 DEBUG ((EFI_D_INFO, "EmuVariablesUpdatedCallback\n"));
1104 UpdateNvVarsOnFileSystem ();
1105 }
1106
1107
1108 EFI_STATUS
1109 EFIAPI
1110 VisitingFileSystemInstance (
1111 IN EFI_HANDLE Handle,
1112 IN VOID *Instance,
1113 IN VOID *Context
1114 )
1115 {
1116 EFI_STATUS Status;
1117 STATIC BOOLEAN ConnectedToFileSystem = FALSE;
1118
1119 if (ConnectedToFileSystem) {
1120 return EFI_ALREADY_STARTED;
1121 }
1122
1123 Status = ConnectNvVarsToFileSystem (Handle);
1124 if (EFI_ERROR (Status)) {
1125 return Status;
1126 }
1127
1128 ConnectedToFileSystem = TRUE;
1129 mEmuVariableEvent =
1130 EfiCreateProtocolNotifyEvent (
1131 &gEfiDevicePathProtocolGuid,
1132 TPL_CALLBACK,
1133 EmuVariablesUpdatedCallback,
1134 NULL,
1135 &mEmuVariableEventReg
1136 );
1137 PcdSet64 (PcdEmuVariableEvent, (UINT64)(UINTN) mEmuVariableEvent);
1138
1139 return EFI_SUCCESS;
1140 }
1141
1142
1143 VOID
1144 PlatformBdsRestoreNvVarsFromHardDisk (
1145 )
1146 {
1147 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage);
1148 VisitAllInstancesOfProtocol (
1149 &gEfiSimpleFileSystemProtocolGuid,
1150 VisitingFileSystemInstance,
1151 NULL
1152 );
1153
1154 }
1155
1156 VOID
1157 PlatformBdsConnectSequence (
1158 VOID
1159 )
1160 /*++
1161
1162 Routine Description:
1163
1164 Connect with predeined platform connect sequence,
1165 the OEM/IBV can customize with their own connect sequence.
1166
1167 Arguments:
1168
1169 None.
1170
1171 Returns:
1172
1173 None.
1174
1175 --*/
1176 {
1177 UINTN Index;
1178
1179 DEBUG ((EFI_D_INFO, "PlatformBdsConnectSequence\n"));
1180
1181 Index = 0;
1182
1183 //
1184 // Here we can get the customized platform connect sequence
1185 // Notes: we can connect with new variable which record the
1186 // last time boots connect device path sequence
1187 //
1188 while (gPlatformConnectSequence[Index] != NULL) {
1189 //
1190 // Build the platform boot option
1191 //
1192 EfiBootManagerConnectDevicePath (gPlatformConnectSequence[Index], NULL);
1193 Index++;
1194 }
1195
1196 //
1197 // Just use the simple policy to connect all devices
1198 //
1199 DEBUG ((EFI_D_INFO, "EfiBootManagerConnectAll\n"));
1200 EfiBootManagerConnectAll ();
1201
1202 PciAcpiInitialization ();
1203
1204 //
1205 // Clear the logo after all devices are connected.
1206 //
1207 gST->ConOut->ClearScreen (gST->ConOut);
1208 }
1209
1210 /**
1211 Save the S3 boot script.
1212
1213 Note that DxeSmmReadyToLock must be signaled after this function returns;
1214 otherwise the script wouldn't be saved actually.
1215 **/
1216 STATIC
1217 VOID
1218 SaveS3BootScript (
1219 VOID
1220 )
1221 {
1222 EFI_STATUS Status;
1223 EFI_S3_SAVE_STATE_PROTOCOL *BootScript;
1224 STATIC CONST UINT8 Info[] = { 0xDE, 0xAD, 0xBE, 0xEF };
1225
1226 Status = gBS->LocateProtocol (&gEfiS3SaveStateProtocolGuid, NULL,
1227 (VOID **) &BootScript);
1228 ASSERT_EFI_ERROR (Status);
1229
1230 //
1231 // Despite the opcode documentation in the PI spec, the protocol
1232 // implementation embeds a deep copy of the info in the boot script, rather
1233 // than storing just a pointer to runtime or NVS storage.
1234 //
1235 Status = BootScript->Write(BootScript, EFI_BOOT_SCRIPT_INFORMATION_OPCODE,
1236 (UINT32) sizeof Info,
1237 (EFI_PHYSICAL_ADDRESS)(UINTN) &Info);
1238 ASSERT_EFI_ERROR (Status);
1239 }
1240
1241
1242 VOID
1243 EFIAPI
1244 PlatformBootManagerAfterConsole (
1245 VOID
1246 )
1247 /*++
1248
1249 Routine Description:
1250
1251 The function will excute with as the platform policy, current policy
1252 is driven by boot mode. IBV/OEM can customize this code for their specific
1253 policy action.
1254
1255 --*/
1256 {
1257 EFI_BOOT_MODE BootMode;
1258
1259 DEBUG ((EFI_D_INFO, "PlatformBootManagerAfterConsole\n"));
1260
1261 if (PcdGetBool (PcdOvmfFlashVariablesEnable)) {
1262 DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior: not restoring NvVars "
1263 "from disk since flash variables appear to be supported.\n"));
1264 } else {
1265 //
1266 // Try to restore variables from the hard disk early so
1267 // they can be used for the other BDS connect operations.
1268 //
1269 PlatformBdsRestoreNvVarsFromHardDisk ();
1270 }
1271
1272 //
1273 // Get current Boot Mode
1274 //
1275 BootMode = GetBootModeHob ();
1276 DEBUG ((EFI_D_ERROR, "Boot Mode:%x\n", BootMode));
1277
1278 //
1279 // Go the different platform policy with different boot mode
1280 // Notes: this part code can be change with the table policy
1281 //
1282 ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);
1283
1284 //
1285 // Logo show
1286 //
1287 BootLogoEnableLogo (
1288 ImageFormatBmp, // ImageFormat
1289 PcdGetPtr (PcdLogoFile), // Logo
1290 EdkiiPlatformLogoDisplayAttributeCenter, // Attribute
1291 0, // OffsetX
1292 0 // OffsetY
1293 );
1294
1295 //
1296 // Perform some platform specific connect sequence
1297 //
1298 PlatformBdsConnectSequence ();
1299
1300 //
1301 // Process QEMU's -kernel command line option
1302 //
1303 TryRunningQemuKernel ();
1304
1305 EfiBootManagerRefreshAllBootOption ();
1306
1307 //
1308 // Register UEFI Shell
1309 //
1310 PlatformRegisterFvBootOption (
1311 PcdGetPtr (PcdShellFile), L"EFI Internal Shell", LOAD_OPTION_ACTIVE
1312 );
1313
1314 SetBootOrderFromQemu ();
1315 }
1316
1317 /**
1318 This notification function is invoked when an instance of the
1319 EFI_DEVICE_PATH_PROTOCOL is produced.
1320
1321 @param Event The event that occured
1322 @param Context For EFI compatiblity. Not used.
1323
1324 **/
1325 VOID
1326 EFIAPI
1327 NotifyDevPath (
1328 IN EFI_EVENT Event,
1329 IN VOID *Context
1330 )
1331 {
1332 EFI_HANDLE Handle;
1333 EFI_STATUS Status;
1334 UINTN BufferSize;
1335 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
1336 ATAPI_DEVICE_PATH *Atapi;
1337
1338 //
1339 // Examine all new handles
1340 //
1341 for (;;) {
1342 //
1343 // Get the next handle
1344 //
1345 BufferSize = sizeof (Handle);
1346 Status = gBS->LocateHandle (
1347 ByRegisterNotify,
1348 NULL,
1349 mEfiDevPathNotifyReg,
1350 &BufferSize,
1351 &Handle
1352 );
1353
1354 //
1355 // If not found, we're done
1356 //
1357 if (EFI_NOT_FOUND == Status) {
1358 break;
1359 }
1360
1361 if (EFI_ERROR (Status)) {
1362 continue;
1363 }
1364
1365 //
1366 // Get the DevicePath protocol on that handle
1367 //
1368 Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevPathNode);
1369 ASSERT_EFI_ERROR (Status);
1370
1371 while (!IsDevicePathEnd (DevPathNode)) {
1372 //
1373 // Find the handler to dump this device path node
1374 //
1375 if (
1376 (DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH) &&
1377 (DevicePathSubType(DevPathNode) == MSG_ATAPI_DP)
1378 ) {
1379 Atapi = (ATAPI_DEVICE_PATH*) DevPathNode;
1380 PciOr16 (
1381 PCI_LIB_ADDRESS (
1382 0,
1383 1,
1384 1,
1385 (Atapi->PrimarySecondary == 1) ? 0x42: 0x40
1386 ),
1387 BIT15
1388 );
1389 }
1390
1391 //
1392 // Next device path node
1393 //
1394 DevPathNode = NextDevicePathNode (DevPathNode);
1395 }
1396 }
1397
1398 return;
1399 }
1400
1401
1402 VOID
1403 InstallDevicePathCallback (
1404 VOID
1405 )
1406 {
1407 DEBUG ((EFI_D_INFO, "Registered NotifyDevPath Event\n"));
1408 mEfiDevPathEvent = EfiCreateProtocolNotifyEvent (
1409 &gEfiDevicePathProtocolGuid,
1410 TPL_CALLBACK,
1411 NotifyDevPath,
1412 NULL,
1413 &mEfiDevPathNotifyReg
1414 );
1415 }
1416
1417 /**
1418 This function is called each second during the boot manager waits the timeout.
1419
1420 @param TimeoutRemain The remaining timeout.
1421 **/
1422 VOID
1423 EFIAPI
1424 PlatformBootManagerWaitCallback (
1425 UINT16 TimeoutRemain
1426 )
1427 {
1428 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
1429 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
1430 UINT16 Timeout;
1431
1432 Timeout = PcdGet16 (PcdPlatformBootTimeOut);
1433
1434 Black.Raw = 0x00000000;
1435 White.Raw = 0x00FFFFFF;
1436
1437 BootLogoUpdateProgress (
1438 White.Pixel,
1439 Black.Pixel,
1440 L"Start boot option",
1441 White.Pixel,
1442 (Timeout - TimeoutRemain) * 100 / Timeout,
1443 0
1444 );
1445 }
1446