]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c
Update OVMF BDS Library to call GenericBdsLib function to save gEfiMemoryTypeInformation
[mirror_edk2.git] / OvmfPkg / Library / PlatformBdsLib / BdsPlatform.c
1 /** @file
2 Platform BDS customizations.
3
4 Copyright (c) 2004 - 2009, 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
17
18 //
19 // Global data
20 //
21
22 VOID *mEfiDevPathNotifyReg;
23 EFI_EVENT mEfiDevPathEvent;
24 VOID *mEmuVariableEventReg;
25 EFI_EVENT mEmuVariableEvent;
26 BOOLEAN mDetectVgaOnly;
27
28
29 //
30 // Type definitions
31 //
32
33 typedef
34 EFI_STATUS
35 (EFIAPI *PROTOCOL_INSTANCE_CALLBACK)(
36 IN EFI_HANDLE Handle,
37 IN VOID *Instance,
38 IN VOID *Context
39 );
40
41 /**
42 @param[in] Handle - Handle of PCI device instance
43 @param[in] PciIo - PCI IO protocol instance
44 @param[in] Pci - PCI Header register block
45 **/
46 typedef
47 EFI_STATUS
48 (EFIAPI *VISIT_PCI_INSTANCE_CALLBACK)(
49 IN EFI_HANDLE Handle,
50 IN EFI_PCI_IO_PROTOCOL *PciIo,
51 IN PCI_TYPE00 *Pci
52 );
53
54
55 //
56 // Function prototypes
57 //
58
59 EFI_STATUS
60 VisitAllInstancesOfProtocol (
61 IN EFI_GUID *Id,
62 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,
63 IN VOID *Context
64 );
65
66 EFI_STATUS
67 VisitAllPciInstancesOfProtocol (
68 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
69 );
70
71 VOID
72 InstallDevicePathCallback (
73 VOID
74 );
75
76 STATIC
77 VOID
78 LoadVideoRom (
79 VOID
80 );
81
82 STATIC
83 EFI_STATUS
84 PciRomLoadEfiDriversFromRomImage (
85 IN EFI_PHYSICAL_ADDRESS Rom,
86 IN UINTN RomSize
87 );
88
89 //
90 // BDS Platform Functions
91 //
92 VOID
93 EFIAPI
94 PlatformBdsInit (
95 VOID
96 )
97 /*++
98
99 Routine Description:
100
101 Platform Bds init. Incude the platform firmware vendor, revision
102 and so crc check.
103
104 Arguments:
105
106 Returns:
107
108 None.
109
110 --*/
111 {
112 DEBUG ((EFI_D_INFO, "PlatformBdsInit\n"));
113 BdsLibSaveMemoryTypeInformation ();
114 InstallDevicePathCallback ();
115 LoadVideoRom ();
116 }
117
118
119 EFI_STATUS
120 ConnectRootBridge (
121 VOID
122 )
123 /*++
124
125 Routine Description:
126
127 Connect RootBridge
128
129 Arguments:
130
131 None.
132
133 Returns:
134
135 EFI_SUCCESS - Connect RootBridge successfully.
136 EFI_STATUS - Connect RootBridge fail.
137
138 --*/
139 {
140 EFI_STATUS Status;
141 EFI_HANDLE RootHandle;
142
143 //
144 // Make all the PCI_IO protocols on PCI Seg 0 show up
145 //
146 BdsLibConnectDevicePath (gPlatformRootBridges[0]);
147
148 Status = gBS->LocateDevicePath (
149 &gEfiDevicePathProtocolGuid,
150 &gPlatformRootBridges[0],
151 &RootHandle
152 );
153 if (EFI_ERROR (Status)) {
154 return Status;
155 }
156
157 Status = gBS->ConnectController (RootHandle, NULL, NULL, FALSE);
158 if (EFI_ERROR (Status)) {
159 return Status;
160 }
161
162 return EFI_SUCCESS;
163 }
164
165
166 EFI_STATUS
167 PrepareLpcBridgeDevicePath (
168 IN EFI_HANDLE DeviceHandle
169 )
170 /*++
171
172 Routine Description:
173
174 Add IsaKeyboard to ConIn,
175 add IsaSerial to ConOut, ConIn, ErrOut.
176 LPC Bridge: 06 01 00
177
178 Arguments:
179
180 DeviceHandle - Handle of PCIIO protocol.
181
182 Returns:
183
184 EFI_SUCCESS - LPC bridge is added to ConOut, ConIn, and ErrOut.
185 EFI_STATUS - No LPC bridge is added.
186
187 --*/
188 {
189 EFI_STATUS Status;
190 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
191 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
192 CHAR16 *DevPathStr;
193
194 DevicePath = NULL;
195 Status = gBS->HandleProtocol (
196 DeviceHandle,
197 &gEfiDevicePathProtocolGuid,
198 (VOID*)&DevicePath
199 );
200 if (EFI_ERROR (Status)) {
201 return Status;
202 }
203 TempDevicePath = DevicePath;
204
205 //
206 // Register Keyboard
207 //
208 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode);
209
210 BdsLibUpdateConsoleVariable (VarConsoleInp, DevicePath, NULL);
211
212 //
213 // Register COM1
214 //
215 DevicePath = TempDevicePath;
216 gPnp16550ComPortDeviceNode.UID = 0;
217
218 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);
219 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
220 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
221
222 //
223 // Print Device Path
224 //
225 DevPathStr = DevicePathToStr(DevicePath);
226 DEBUG((
227 EFI_D_INFO,
228 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
229 __LINE__,
230 gPnp16550ComPortDeviceNode.UID + 1,
231 DevPathStr
232 ));
233 FreePool(DevPathStr);
234
235 BdsLibUpdateConsoleVariable (VarConsoleOut, DevicePath, NULL);
236 BdsLibUpdateConsoleVariable (VarConsoleInp, DevicePath, NULL);
237 BdsLibUpdateConsoleVariable (VarErrorOut, DevicePath, NULL);
238
239 //
240 // Register COM2
241 //
242 DevicePath = TempDevicePath;
243 gPnp16550ComPortDeviceNode.UID = 1;
244
245 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);
246 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
247 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
248
249 //
250 // Print Device Path
251 //
252 DevPathStr = DevicePathToStr(DevicePath);
253 DEBUG((
254 EFI_D_INFO,
255 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
256 __LINE__,
257 gPnp16550ComPortDeviceNode.UID + 1,
258 DevPathStr
259 ));
260 FreePool(DevPathStr);
261
262 BdsLibUpdateConsoleVariable (VarConsoleOut, DevicePath, NULL);
263 BdsLibUpdateConsoleVariable (VarConsoleInp, DevicePath, NULL);
264 BdsLibUpdateConsoleVariable (VarErrorOut, DevicePath, NULL);
265
266 return EFI_SUCCESS;
267 }
268
269 EFI_STATUS
270 GetGopDevicePath (
271 IN EFI_DEVICE_PATH_PROTOCOL *PciDevicePath,
272 OUT EFI_DEVICE_PATH_PROTOCOL **GopDevicePath
273 )
274 {
275 UINTN Index;
276 EFI_STATUS Status;
277 EFI_HANDLE PciDeviceHandle;
278 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
279 EFI_DEVICE_PATH_PROTOCOL *TempPciDevicePath;
280 UINTN GopHandleCount;
281 EFI_HANDLE *GopHandleBuffer;
282
283 if (PciDevicePath == NULL || GopDevicePath == NULL) {
284 return EFI_INVALID_PARAMETER;
285 }
286
287 //
288 // Initialize the GopDevicePath to be PciDevicePath
289 //
290 *GopDevicePath = PciDevicePath;
291 TempPciDevicePath = PciDevicePath;
292
293 Status = gBS->LocateDevicePath (
294 &gEfiDevicePathProtocolGuid,
295 &TempPciDevicePath,
296 &PciDeviceHandle
297 );
298 if (EFI_ERROR (Status)) {
299 return Status;
300 }
301
302 //
303 // Try to connect this handle, so that GOP dirver could start on this
304 // device and create child handles with GraphicsOutput Protocol installed
305 // on them, then we get device paths of these child handles and select
306 // them as possible console device.
307 //
308 gBS->ConnectController (PciDeviceHandle, NULL, NULL, FALSE);
309
310 Status = gBS->LocateHandleBuffer (
311 ByProtocol,
312 &gEfiGraphicsOutputProtocolGuid,
313 NULL,
314 &GopHandleCount,
315 &GopHandleBuffer
316 );
317 if (!EFI_ERROR (Status)) {
318 //
319 // Add all the child handles as possible Console Device
320 //
321 for (Index = 0; Index < GopHandleCount; Index++) {
322 Status = gBS->HandleProtocol (GopHandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID*)&TempDevicePath);
323 if (EFI_ERROR (Status)) {
324 continue;
325 }
326 if (CompareMem (
327 PciDevicePath,
328 TempDevicePath,
329 GetDevicePathSize (PciDevicePath) - END_DEVICE_PATH_LENGTH
330 ) == 0) {
331 //
332 // In current implementation, we only enable one of the child handles
333 // as console device, i.e. sotre one of the child handle's device
334 // path to variable "ConOut"
335 // In futhure, we could select all child handles to be console device
336 //
337
338 *GopDevicePath = TempDevicePath;
339
340 //
341 // Delete the PCI device's path that added by GetPlugInPciVgaDevicePath()
342 // Add the integrity GOP device path.
343 //
344 BdsLibUpdateConsoleVariable (VarConsoleOutDev, NULL, PciDevicePath);
345 BdsLibUpdateConsoleVariable (VarConsoleOutDev, TempDevicePath, NULL);
346 }
347 }
348 gBS->FreePool (GopHandleBuffer);
349 }
350
351 return EFI_SUCCESS;
352 }
353
354 EFI_STATUS
355 PreparePciVgaDevicePath (
356 IN EFI_HANDLE DeviceHandle
357 )
358 /*++
359
360 Routine Description:
361
362 Add PCI VGA to ConOut.
363 PCI VGA: 03 00 00
364
365 Arguments:
366
367 DeviceHandle - Handle of PCIIO protocol.
368
369 Returns:
370
371 EFI_SUCCESS - PCI VGA is added to ConOut.
372 EFI_STATUS - No PCI VGA device is added.
373
374 --*/
375 {
376 EFI_STATUS Status;
377 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
378 EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;
379
380 DevicePath = NULL;
381 Status = gBS->HandleProtocol (
382 DeviceHandle,
383 &gEfiDevicePathProtocolGuid,
384 (VOID*)&DevicePath
385 );
386 if (EFI_ERROR (Status)) {
387 return Status;
388 }
389
390 GetGopDevicePath (DevicePath, &GopDevicePath);
391 DevicePath = GopDevicePath;
392
393 BdsLibUpdateConsoleVariable (VarConsoleOut, DevicePath, NULL);
394
395 return EFI_SUCCESS;
396 }
397
398 EFI_STATUS
399 PreparePciSerialDevicePath (
400 IN EFI_HANDLE DeviceHandle
401 )
402 /*++
403
404 Routine Description:
405
406 Add PCI Serial to ConOut, ConIn, ErrOut.
407 PCI Serial: 07 00 02
408
409 Arguments:
410
411 DeviceHandle - Handle of PCIIO protocol.
412
413 Returns:
414
415 EFI_SUCCESS - PCI Serial is added to ConOut, ConIn, and ErrOut.
416 EFI_STATUS - No PCI Serial device is added.
417
418 --*/
419 {
420 EFI_STATUS Status;
421 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
422
423 DevicePath = NULL;
424 Status = gBS->HandleProtocol (
425 DeviceHandle,
426 &gEfiDevicePathProtocolGuid,
427 (VOID*)&DevicePath
428 );
429 if (EFI_ERROR (Status)) {
430 return Status;
431 }
432
433 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
434 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
435
436 BdsLibUpdateConsoleVariable (VarConsoleOut, DevicePath, NULL);
437 BdsLibUpdateConsoleVariable (VarConsoleInp, DevicePath, NULL);
438 BdsLibUpdateConsoleVariable (VarErrorOut, DevicePath, NULL);
439
440 return EFI_SUCCESS;
441 }
442
443 EFI_STATUS
444 VisitAllInstancesOfProtocol (
445 IN EFI_GUID *Id,
446 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,
447 IN VOID *Context
448 )
449 {
450 EFI_STATUS Status;
451 UINTN HandleCount;
452 EFI_HANDLE *HandleBuffer;
453 UINTN Index;
454 VOID *Instance;
455
456 //
457 // Start to check all the PciIo to find all possible device
458 //
459 HandleCount = 0;
460 HandleBuffer = NULL;
461 Status = gBS->LocateHandleBuffer (
462 ByProtocol,
463 Id,
464 NULL,
465 &HandleCount,
466 &HandleBuffer
467 );
468 if (EFI_ERROR (Status)) {
469 return Status;
470 }
471
472 for (Index = 0; Index < HandleCount; Index++) {
473 Status = gBS->HandleProtocol (HandleBuffer[Index], Id, &Instance);
474 if (EFI_ERROR (Status)) {
475 continue;
476 }
477
478 Status = (*CallBackFunction) (
479 HandleBuffer[Index],
480 Instance,
481 Context
482 );
483 }
484
485 gBS->FreePool (HandleBuffer);
486
487 return EFI_SUCCESS;
488 }
489
490
491 EFI_STATUS
492 EFIAPI
493 VisitingAPciInstance (
494 IN EFI_HANDLE Handle,
495 IN VOID *Instance,
496 IN VOID *Context
497 )
498 {
499 EFI_STATUS Status;
500 EFI_PCI_IO_PROTOCOL *PciIo;
501 PCI_TYPE00 Pci;
502
503 PciIo = (EFI_PCI_IO_PROTOCOL*) Instance;
504
505 //
506 // Check for all PCI device
507 //
508 Status = PciIo->Pci.Read (
509 PciIo,
510 EfiPciIoWidthUint32,
511 0,
512 sizeof (Pci) / sizeof (UINT32),
513 &Pci
514 );
515 if (EFI_ERROR (Status)) {
516 return Status;
517 }
518
519 return (*(VISIT_PCI_INSTANCE_CALLBACK)(UINTN) Context) (
520 Handle,
521 PciIo,
522 &Pci
523 );
524
525 }
526
527
528
529 EFI_STATUS
530 VisitAllPciInstances (
531 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
532 )
533 {
534 return VisitAllInstancesOfProtocol (
535 &gEfiPciIoProtocolGuid,
536 VisitingAPciInstance,
537 (VOID*)(UINTN) CallBackFunction
538 );
539 }
540
541
542 /**
543 Do platform specific PCI Device check and add them to
544 ConOut, ConIn, ErrOut.
545
546 @param[in] Handle - Handle of PCI device instance
547 @param[in] PciIo - PCI IO protocol instance
548 @param[in] Pci - PCI Header register block
549
550 @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
551 @retval EFI_STATUS - PCI Device check or Console variable update fail.
552
553 **/
554 EFI_STATUS
555 EFIAPI
556 DetectAndPreparePlatformPciDevicePath (
557 IN EFI_HANDLE Handle,
558 IN EFI_PCI_IO_PROTOCOL *PciIo,
559 IN PCI_TYPE00 *Pci
560 )
561 {
562 EFI_STATUS Status;
563
564 Status = PciIo->Attributes (
565 PciIo,
566 EfiPciIoAttributeOperationEnable,
567 EFI_PCI_DEVICE_ENABLE,
568 NULL
569 );
570 ASSERT_EFI_ERROR (Status);
571
572 if (!mDetectVgaOnly) {
573 //
574 // Here we decide whether it is LPC Bridge
575 //
576 if ((IS_PCI_LPC (Pci)) ||
577 ((IS_PCI_ISA_PDECODE (Pci)) &&
578 (Pci->Hdr.VendorId == 0x8086) &&
579 (Pci->Hdr.DeviceId == 0x7000)
580 )
581 ) {
582 //
583 // Add IsaKeyboard to ConIn,
584 // add IsaSerial to ConOut, ConIn, ErrOut
585 //
586 DEBUG ((EFI_D_INFO, "Found LPC Bridge device\n"));
587 PrepareLpcBridgeDevicePath (Handle);
588 return EFI_SUCCESS;
589 }
590 //
591 // Here we decide which Serial device to enable in PCI bus
592 //
593 if (IS_PCI_16550SERIAL (Pci)) {
594 //
595 // Add them to ConOut, ConIn, ErrOut.
596 //
597 DEBUG ((EFI_D_INFO, "Found PCI 16550 SERIAL device\n"));
598 PreparePciSerialDevicePath (Handle);
599 return EFI_SUCCESS;
600 }
601 }
602
603 //
604 // Here we decide which VGA device to enable in PCI bus
605 //
606 if (IS_PCI_VGA (Pci)) {
607 //
608 // Add them to ConOut.
609 //
610 DEBUG ((EFI_D_INFO, "Found PCI VGA device\n"));
611 PreparePciVgaDevicePath (Handle);
612 return EFI_SUCCESS;
613 }
614
615 return Status;
616 }
617
618
619 /**
620 Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
621
622 @param[in] DetectVgaOnly - Only detect VGA device if it's TRUE.
623
624 @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
625 @retval EFI_STATUS - PCI Device check or Console variable update fail.
626
627 **/
628 EFI_STATUS
629 DetectAndPreparePlatformPciDevicePaths (
630 BOOLEAN DetectVgaOnly
631 )
632 {
633 mDetectVgaOnly = DetectVgaOnly;
634 return VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath);
635 }
636
637
638 EFI_STATUS
639 PlatformBdsConnectConsole (
640 IN BDS_CONSOLE_CONNECT_ENTRY *PlatformConsole
641 )
642 /*++
643
644 Routine Description:
645
646 Connect the predefined platform default console device. Always try to find
647 and enable the vga device if have.
648
649 Arguments:
650
651 PlatformConsole - Predfined platform default console device array.
652
653 Returns:
654
655 EFI_SUCCESS - Success connect at least one ConIn and ConOut
656 device, there must have one ConOut device is
657 active vga device.
658
659 EFI_STATUS - Return the status of
660 BdsLibConnectAllDefaultConsoles ()
661
662 --*/
663 {
664 EFI_STATUS Status;
665 UINTN Index;
666 EFI_DEVICE_PATH_PROTOCOL *VarConout;
667 EFI_DEVICE_PATH_PROTOCOL *VarConin;
668 UINTN DevicePathSize;
669
670 //
671 // Connect RootBridge
672 //
673 VarConout = BdsLibGetVariableAndSize (
674 VarConsoleOut,
675 &gEfiGlobalVariableGuid,
676 &DevicePathSize
677 );
678 VarConin = BdsLibGetVariableAndSize (
679 VarConsoleInp,
680 &gEfiGlobalVariableGuid,
681 &DevicePathSize
682 );
683
684 if (VarConout == NULL || VarConin == NULL) {
685 //
686 // Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
687 //
688 DetectAndPreparePlatformPciDevicePaths (FALSE);
689
690 //
691 // Have chance to connect the platform default console,
692 // the platform default console is the minimue device group
693 // the platform should support
694 //
695 for (Index = 0; PlatformConsole[Index].DevicePath != NULL; ++Index) {
696 //
697 // Update the console variable with the connect type
698 //
699 if ((PlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {
700 BdsLibUpdateConsoleVariable (VarConsoleInp, PlatformConsole[Index].DevicePath, NULL);
701 }
702 if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {
703 BdsLibUpdateConsoleVariable (VarConsoleOut, PlatformConsole[Index].DevicePath, NULL);
704 }
705 if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {
706 BdsLibUpdateConsoleVariable (VarErrorOut, PlatformConsole[Index].DevicePath, NULL);
707 }
708 }
709 } else {
710 //
711 // Only detect VGA device and add them to ConOut
712 //
713 DetectAndPreparePlatformPciDevicePaths (TRUE);
714 }
715
716 //
717 // Connect the all the default console with current cosole variable
718 //
719 Status = BdsLibConnectAllDefaultConsoles ();
720 if (EFI_ERROR (Status)) {
721 return Status;
722 }
723
724 return EFI_SUCCESS;
725 }
726
727
728 VOID
729 PciInitialization (
730 )
731 {
732 //
733 // Bus 0, Device 0, Function 0 - Host to PCI Bridge
734 //
735 PciWrite8 (PCI_LIB_ADDRESS (0, 0, 0, 0x3c), 0x00);
736
737 //
738 // Bus 0, Device 1, Function 0 - PCI to ISA Bridge
739 //
740 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x3c), 0x00);
741 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b);
742 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x09);
743 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0b);
744 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x09);
745
746 //
747 // Bus 0, Device 1, Function 1 - IDE Controller
748 //
749 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 1, 0x3c), 0x00);
750 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 1, 0x0d), 0x40);
751
752 //
753 // Bus 0, Device 1, Function 3 - Power Managment Controller
754 //
755 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 3, 0x3c), 0x0b);
756 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 3, 0x3d), 0x01);
757
758 //
759 // Bus 0, Device 2, Function 0 - Video Controller
760 //
761 PciWrite8 (PCI_LIB_ADDRESS (0, 2, 0, 0x3c), 0x00);
762
763 //
764 // Bus 0, Device 3, Function 0 - Network Controller
765 //
766 PciWrite8 (PCI_LIB_ADDRESS (0, 3, 0, 0x3c), 0x0b);
767 PciWrite8 (PCI_LIB_ADDRESS (0, 3, 0, 0x3d), 0x01);
768
769 //
770 // Bus 0, Device 4, Function 0 - RAM Memory
771 //
772 PciWrite8 (PCI_LIB_ADDRESS (0, 4, 0, 0x3c), 0x09);
773 PciWrite8 (PCI_LIB_ADDRESS (0, 4, 0, 0x3d), 0x01);
774 }
775
776
777 EFI_STATUS
778 EFIAPI
779 ConnectRecursivelyIfPciMassStorage (
780 IN EFI_HANDLE Handle,
781 IN EFI_PCI_IO_PROTOCOL *Instance,
782 IN PCI_TYPE00 *PciHeader
783 )
784 {
785 EFI_STATUS Status;
786 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
787 CHAR16 *DevPathStr;
788
789 if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE)) {
790 DevicePath = NULL;
791 Status = gBS->HandleProtocol (
792 Handle,
793 &gEfiDevicePathProtocolGuid,
794 (VOID*)&DevicePath
795 );
796 if (EFI_ERROR (Status)) {
797 return Status;
798 }
799
800 //
801 // Print Device Path
802 //
803 DevPathStr = DevicePathToStr (DevicePath);
804 DEBUG((
805 EFI_D_INFO,
806 "Found Mass Storage device: %s\n",
807 DevPathStr
808 ));
809 FreePool(DevPathStr);
810
811 Status = gBS->ConnectController (Handle, NULL, NULL, TRUE);
812 if (EFI_ERROR (Status)) {
813 return Status;
814 }
815
816 }
817
818 return EFI_SUCCESS;
819 }
820
821
822 /**
823 This notification function is invoked when the
824 EMU Variable FVB has been changed.
825
826 @param Event The event that occured
827 @param Context For EFI compatiblity. Not used.
828
829 **/
830 VOID
831 EFIAPI
832 EmuVariablesUpdatedCallback (
833 IN EFI_EVENT Event,
834 IN VOID *Context
835 )
836 {
837 DEBUG ((EFI_D_INFO, "EmuVariablesUpdatedCallback\n"));
838 UpdateNvVarsOnFileSystem ();
839 }
840
841
842 EFI_STATUS
843 EFIAPI
844 VisitingFileSystemInstance (
845 IN EFI_HANDLE Handle,
846 IN VOID *Instance,
847 IN VOID *Context
848 )
849 {
850 EFI_STATUS Status;
851 STATIC BOOLEAN ConnectedToFileSystem = FALSE;
852
853 if (ConnectedToFileSystem) {
854 return EFI_ALREADY_STARTED;
855 }
856
857 Status = ConnectNvVarsToFileSystem (Handle);
858 if (EFI_ERROR (Status)) {
859 return Status;
860 }
861
862 ConnectedToFileSystem = TRUE;
863 mEmuVariableEvent =
864 EfiCreateProtocolNotifyEvent (
865 &gEfiDevicePathProtocolGuid,
866 TPL_CALLBACK,
867 EmuVariablesUpdatedCallback,
868 NULL,
869 &mEmuVariableEventReg
870 );
871 PcdSet64 (PcdEmuVariableEvent, (UINT64)(UINTN) mEmuVariableEvent);
872
873 return EFI_SUCCESS;
874 }
875
876
877 VOID
878 PlatformBdsRestoreNvVarsFromHardDisk (
879 )
880 {
881 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage);
882 VisitAllInstancesOfProtocol (
883 &gEfiSimpleFileSystemProtocolGuid,
884 VisitingFileSystemInstance,
885 NULL
886 );
887
888 }
889
890
891 VOID
892 PlatformBdsConnectSequence (
893 VOID
894 )
895 /*++
896
897 Routine Description:
898
899 Connect with predeined platform connect sequence,
900 the OEM/IBV can customize with their own connect sequence.
901
902 Arguments:
903
904 None.
905
906 Returns:
907
908 None.
909
910 --*/
911 {
912 UINTN Index;
913
914 DEBUG ((EFI_D_INFO, "PlatformBdsConnectSequence\n"));
915
916 Index = 0;
917
918 //
919 // Here we can get the customized platform connect sequence
920 // Notes: we can connect with new variable which record the
921 // last time boots connect device path sequence
922 //
923 while (gPlatformConnectSequence[Index] != NULL) {
924 //
925 // Build the platform boot option
926 //
927 BdsLibConnectDevicePath (gPlatformConnectSequence[Index]);
928 Index++;
929 }
930
931 //
932 // Just use the simple policy to connect all devices
933 //
934 BdsLibConnectAll ();
935
936 PciInitialization ();
937
938 //
939 // Clear the logo after all devices are connected.
940 //
941 gST->ConOut->ClearScreen (gST->ConOut);
942 }
943
944 VOID
945 PlatformBdsGetDriverOption (
946 IN OUT LIST_ENTRY *BdsDriverLists
947 )
948 /*++
949
950 Routine Description:
951
952 Load the predefined driver option, OEM/IBV can customize this
953 to load their own drivers
954
955 Arguments:
956
957 BdsDriverLists - The header of the driver option link list.
958
959 Returns:
960
961 None.
962
963 --*/
964 {
965 DEBUG ((EFI_D_INFO, "PlatformBdsGetDriverOption\n"));
966 return;
967 }
968
969 VOID
970 PlatformBdsDiagnostics (
971 IN EXTENDMEM_COVERAGE_LEVEL MemoryTestLevel,
972 IN BOOLEAN QuietBoot,
973 IN BASEM_MEMORY_TEST BaseMemoryTest
974 )
975 /*++
976
977 Routine Description:
978
979 Perform the platform diagnostic, such like test memory. OEM/IBV also
980 can customize this fuction to support specific platform diagnostic.
981
982 Arguments:
983
984 MemoryTestLevel - The memory test intensive level
985
986 QuietBoot - Indicate if need to enable the quiet boot
987
988 BaseMemoryTest - A pointer to BaseMemoryTest()
989
990 Returns:
991
992 None.
993
994 --*/
995 {
996 EFI_STATUS Status;
997
998 DEBUG ((EFI_D_INFO, "PlatformBdsDiagnostics\n"));
999
1000 //
1001 // Here we can decide if we need to show
1002 // the diagnostics screen
1003 // Notes: this quiet boot code should be remove
1004 // from the graphic lib
1005 //
1006 if (QuietBoot) {
1007 EnableQuietBoot (PcdGetPtr(PcdLogoFile));
1008 //
1009 // Perform system diagnostic
1010 //
1011 Status = BaseMemoryTest (MemoryTestLevel);
1012 if (EFI_ERROR (Status)) {
1013 DisableQuietBoot ();
1014 }
1015
1016 return ;
1017 }
1018 //
1019 // Perform system diagnostic
1020 //
1021 Status = BaseMemoryTest (MemoryTestLevel);
1022 }
1023
1024
1025 VOID
1026 EFIAPI
1027 PlatformBdsPolicyBehavior (
1028 IN OUT LIST_ENTRY *DriverOptionList,
1029 IN OUT LIST_ENTRY *BootOptionList,
1030 IN PROCESS_CAPSULES ProcessCapsules,
1031 IN BASEM_MEMORY_TEST BaseMemoryTest
1032 )
1033 /*++
1034
1035 Routine Description:
1036
1037 The function will excute with as the platform policy, current policy
1038 is driven by boot mode. IBV/OEM can customize this code for their specific
1039 policy action.
1040
1041 Arguments:
1042
1043 DriverOptionList - The header of the driver option link list
1044
1045 BootOptionList - The header of the boot option link list
1046
1047 ProcessCapsules - A pointer to ProcessCapsules()
1048
1049 BaseMemoryTest - A pointer to BaseMemoryTest()
1050
1051 Returns:
1052
1053 None.
1054
1055 --*/
1056 {
1057 EFI_STATUS Status;
1058 UINT16 Timeout;
1059 EFI_EVENT UserInputDurationTime;
1060 LIST_ENTRY *Link;
1061 BDS_COMMON_OPTION *BootOption;
1062 UINTN Index;
1063 EFI_INPUT_KEY Key;
1064 EFI_TPL OldTpl;
1065 EFI_BOOT_MODE BootMode;
1066
1067 DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior\n"));
1068
1069 ConnectRootBridge ();
1070
1071 //
1072 // Try to restore variables from the hard disk early so
1073 // they can be used for the other BDS connect operations.
1074 //
1075 PlatformBdsRestoreNvVarsFromHardDisk ();
1076
1077 //
1078 // Init the time out value
1079 //
1080 Timeout = PcdGet16 (PcdPlatformBootTimeOut);
1081
1082 //
1083 // Load the driver option as the driver option list
1084 //
1085 PlatformBdsGetDriverOption (DriverOptionList);
1086
1087 //
1088 // Get current Boot Mode
1089 //
1090 Status = BdsLibGetBootMode (&BootMode);
1091 DEBUG ((EFI_D_ERROR, "Boot Mode:%x\n", BootMode));
1092
1093 //
1094 // Go the different platform policy with different boot mode
1095 // Notes: this part code can be change with the table policy
1096 //
1097 ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);
1098 //
1099 // Connect platform console
1100 //
1101 Status = PlatformBdsConnectConsole (gPlatformConsole);
1102 if (EFI_ERROR (Status)) {
1103 //
1104 // Here OEM/IBV can customize with defined action
1105 //
1106 PlatformBdsNoConsoleAction ();
1107 }
1108 //
1109 // Create a 300ms duration event to ensure user has enough input time to enter Setup
1110 //
1111 Status = gBS->CreateEvent (
1112 EVT_TIMER,
1113 0,
1114 NULL,
1115 NULL,
1116 &UserInputDurationTime
1117 );
1118 ASSERT (Status == EFI_SUCCESS);
1119 Status = gBS->SetTimer (UserInputDurationTime, TimerRelative, 3000000);
1120 ASSERT (Status == EFI_SUCCESS);
1121 //
1122 // Memory test and Logo show
1123 //
1124 PlatformBdsDiagnostics (IGNORE, TRUE, BaseMemoryTest);
1125
1126 //
1127 // Perform some platform specific connect sequence
1128 //
1129 PlatformBdsConnectSequence ();
1130
1131 //
1132 // Give one chance to enter the setup if we
1133 // have the time out
1134 //
1135 if (Timeout != 0) {
1136 //PlatformBdsEnterFrontPage (Timeout, FALSE);
1137 }
1138
1139 DEBUG ((EFI_D_INFO, "BdsLibConnectAll\n"));
1140 BdsLibConnectAll ();
1141 BdsLibEnumerateAllBootOption (BootOptionList);
1142
1143 //
1144 // Please uncomment above ConnectAll and EnumerateAll code and remove following first boot
1145 // checking code in real production tip.
1146 //
1147 // In BOOT_WITH_FULL_CONFIGURATION boot mode, should always connect every device
1148 // and do enumerate all the default boot options. But in development system board, the boot mode
1149 // cannot be BOOT_ASSUMING_NO_CONFIGURATION_CHANGES because the machine box
1150 // is always open. So the following code only do the ConnectAll and EnumerateAll at first boot.
1151 //
1152 Status = BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder");
1153 if (EFI_ERROR(Status)) {
1154 //
1155 // If cannot find "BootOrder" variable, it may be first boot.
1156 // Try to connect all devices and enumerate all boot options here.
1157 //
1158 BdsLibConnectAll ();
1159 BdsLibEnumerateAllBootOption (BootOptionList);
1160 }
1161
1162 //
1163 // To give the User a chance to enter Setup here, if user set TimeOut is 0.
1164 // BDS should still give user a chance to enter Setup
1165 //
1166 // Connect first boot option, and then check user input before exit
1167 //
1168 for (Link = BootOptionList->ForwardLink; Link != BootOptionList;Link = Link->ForwardLink) {
1169 BootOption = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
1170 if (!IS_LOAD_OPTION_TYPE (BootOption->Attribute, LOAD_OPTION_ACTIVE)) {
1171 //
1172 // skip the header of the link list, becuase it has no boot option
1173 //
1174 continue;
1175 } else {
1176 //
1177 // Make sure the boot option device path connected, but ignore the BBS device path
1178 //
1179 if (DevicePathType (BootOption->DevicePath) != BBS_DEVICE_PATH) {
1180 BdsLibConnectDevicePath (BootOption->DevicePath);
1181 }
1182 break;
1183 }
1184 }
1185
1186 //
1187 // Check whether the user input after the duration time has expired
1188 //
1189 OldTpl = EfiGetCurrentTpl();
1190 gBS->RestoreTPL (TPL_APPLICATION);
1191 gBS->WaitForEvent (1, &UserInputDurationTime, &Index);
1192 gBS->CloseEvent (UserInputDurationTime);
1193 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
1194 gBS->RaiseTPL (OldTpl);
1195
1196 if (!EFI_ERROR (Status)) {
1197 //
1198 // Enter Setup if user input
1199 //
1200 Timeout = 0xffff;
1201 PlatformBdsEnterFrontPage (Timeout, FALSE);
1202 }
1203
1204 return ;
1205 }
1206
1207 VOID
1208 EFIAPI
1209 PlatformBdsBootSuccess (
1210 IN BDS_COMMON_OPTION *Option
1211 )
1212 /*++
1213
1214 Routine Description:
1215
1216 Hook point after a boot attempt succeeds. We don't expect a boot option to
1217 return, so the EFI 1.0 specification defines that you will default to an
1218 interactive mode and stop processing the BootOrder list in this case. This
1219 is alos a platform implementation and can be customized by IBV/OEM.
1220
1221 Arguments:
1222
1223 Option - Pointer to Boot Option that succeeded to boot.
1224
1225 Returns:
1226
1227 None.
1228
1229 --*/
1230 {
1231 CHAR16 *TmpStr;
1232
1233 DEBUG ((EFI_D_INFO, "PlatformBdsBootSuccess\n"));
1234 //
1235 // If Boot returned with EFI_SUCCESS and there is not in the boot device
1236 // select loop then we need to pop up a UI and wait for user input.
1237 //
1238 TmpStr = Option->StatusString;
1239 if (TmpStr != NULL) {
1240 BdsLibOutputStrings (gST->ConOut, TmpStr, Option->Description, L"\n\r", NULL);
1241 FreePool (TmpStr);
1242 }
1243 }
1244
1245 VOID
1246 EFIAPI
1247 PlatformBdsBootFail (
1248 IN BDS_COMMON_OPTION *Option,
1249 IN EFI_STATUS Status,
1250 IN CHAR16 *ExitData,
1251 IN UINTN ExitDataSize
1252 )
1253 /*++
1254
1255 Routine Description:
1256
1257 Hook point after a boot attempt fails.
1258
1259 Arguments:
1260
1261 Option - Pointer to Boot Option that failed to boot.
1262
1263 Status - Status returned from failed boot.
1264
1265 ExitData - Exit data returned from failed boot.
1266
1267 ExitDataSize - Exit data size returned from failed boot.
1268
1269 Returns:
1270
1271 None.
1272
1273 --*/
1274 {
1275 CHAR16 *TmpStr;
1276
1277 DEBUG ((EFI_D_INFO, "PlatformBdsBootFail\n"));
1278
1279 //
1280 // If Boot returned with failed status then we need to pop up a UI and wait
1281 // for user input.
1282 //
1283 TmpStr = Option->StatusString;
1284 if (TmpStr != NULL) {
1285 BdsLibOutputStrings (gST->ConOut, TmpStr, Option->Description, L"\n\r", NULL);
1286 FreePool (TmpStr);
1287 }
1288 }
1289
1290 EFI_STATUS
1291 PlatformBdsNoConsoleAction (
1292 VOID
1293 )
1294 /*++
1295
1296 Routine Description:
1297
1298 This function is remained for IBV/OEM to do some platform action,
1299 if there no console device can be connected.
1300
1301 Arguments:
1302
1303 None.
1304
1305 Returns:
1306
1307 EFI_SUCCESS - Direct return success now.
1308
1309 --*/
1310 {
1311 DEBUG ((EFI_D_INFO, "PlatformBdsNoConsoleAction\n"));
1312 return EFI_SUCCESS;
1313 }
1314
1315 VOID
1316 EFIAPI
1317 PlatformBdsLockNonUpdatableFlash (
1318 VOID
1319 )
1320 {
1321 DEBUG ((EFI_D_INFO, "PlatformBdsLockNonUpdatableFlash\n"));
1322 return;
1323 }
1324
1325
1326 /**
1327 This notification function is invoked when an instance of the
1328 EFI_DEVICE_PATH_PROTOCOL is produced.
1329
1330 @param Event The event that occured
1331 @param Context For EFI compatiblity. Not used.
1332
1333 **/
1334 VOID
1335 EFIAPI
1336 NotifyDevPath (
1337 IN EFI_EVENT Event,
1338 IN VOID *Context
1339 )
1340 {
1341 EFI_HANDLE Handle;
1342 EFI_STATUS Status;
1343 UINTN BufferSize;
1344 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
1345 ATAPI_DEVICE_PATH *Atapi;
1346
1347 //
1348 // Examine all new handles
1349 //
1350 for (;;) {
1351 //
1352 // Get the next handle
1353 //
1354 BufferSize = sizeof (Handle);
1355 Status = gBS->LocateHandle (
1356 ByRegisterNotify,
1357 NULL,
1358 mEfiDevPathNotifyReg,
1359 &BufferSize,
1360 &Handle
1361 );
1362
1363 //
1364 // If not found, we're done
1365 //
1366 if (EFI_NOT_FOUND == Status) {
1367 break;
1368 }
1369
1370 if (EFI_ERROR (Status)) {
1371 continue;
1372 }
1373
1374 //
1375 // Get the DevicePath protocol on that handle
1376 //
1377 Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevPathNode);
1378 ASSERT_EFI_ERROR (Status);
1379
1380 while (!IsDevicePathEnd (DevPathNode)) {
1381 //
1382 // Find the handler to dump this device path node
1383 //
1384 if (
1385 (DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH) &&
1386 (DevicePathSubType(DevPathNode) == MSG_ATAPI_DP)
1387 ) {
1388 Atapi = (ATAPI_DEVICE_PATH*) DevPathNode;
1389 PciOr16 (
1390 PCI_LIB_ADDRESS (
1391 0,
1392 1,
1393 1,
1394 (Atapi->PrimarySecondary == 1) ? 0x42: 0x40
1395 ),
1396 BIT15
1397 );
1398 }
1399
1400 //
1401 // Next device path node
1402 //
1403 DevPathNode = NextDevicePathNode (DevPathNode);
1404 }
1405 }
1406
1407 return;
1408 }
1409
1410
1411 VOID
1412 InstallDevicePathCallback (
1413 VOID
1414 )
1415 {
1416 DEBUG ((EFI_D_INFO, "Registered NotifyDevPath Event\n"));
1417 mEfiDevPathEvent = EfiCreateProtocolNotifyEvent (
1418 &gEfiDevicePathProtocolGuid,
1419 TPL_CALLBACK,
1420 NotifyDevPath,
1421 NULL,
1422 &mEfiDevPathNotifyReg
1423 );
1424 }
1425
1426 /**
1427 Lock the ConsoleIn device in system table. All key
1428 presses will be ignored until the Password is typed in. The only way to
1429 disable the password is to type it in to a ConIn device.
1430
1431 @param Password Password used to lock ConIn device.
1432
1433 @retval EFI_SUCCESS lock the Console In Spliter virtual handle successfully.
1434 @retval EFI_UNSUPPORTED Password not found
1435
1436 **/
1437 EFI_STATUS
1438 EFIAPI
1439 LockKeyboards (
1440 IN CHAR16 *Password
1441 )
1442 {
1443 return EFI_UNSUPPORTED;
1444 }
1445
1446
1447 STATIC
1448 VOID
1449 LoadVideoRom (
1450 VOID
1451 )
1452 {
1453 PCI_DATA_STRUCTURE *Pcir;
1454 UINTN RomSize;
1455
1456 //
1457 // The virtual machines sometimes load the video rom image
1458 // directly at the legacy video BIOS location of C000:0000,
1459 // and do not implement the PCI expansion ROM feature.
1460 //
1461 Pcir = (PCI_DATA_STRUCTURE *) (UINTN) 0xc0000;
1462 RomSize = Pcir->ImageLength * 512;
1463 PciRomLoadEfiDriversFromRomImage (0xc0000, RomSize);
1464 }
1465
1466
1467 STATIC
1468 EFI_STATUS
1469 PciRomLoadEfiDriversFromRomImage (
1470 IN EFI_PHYSICAL_ADDRESS Rom,
1471 IN UINTN RomSize
1472 )
1473 {
1474 CHAR16 *FileName;
1475 EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader;
1476 PCI_DATA_STRUCTURE *Pcir;
1477 UINTN ImageIndex;
1478 UINTN RomOffset;
1479 UINT32 ImageSize;
1480 UINT16 ImageOffset;
1481 EFI_HANDLE ImageHandle;
1482 EFI_STATUS Status;
1483 EFI_STATUS retStatus;
1484 EFI_DEVICE_PATH_PROTOCOL *FilePath;
1485 BOOLEAN SkipImage;
1486 UINT32 DestinationSize;
1487 UINT32 ScratchSize;
1488 UINT8 *Scratch;
1489 VOID *ImageBuffer;
1490 VOID *DecompressedImageBuffer;
1491 UINT32 ImageLength;
1492 EFI_DECOMPRESS_PROTOCOL *Decompress;
1493
1494 FileName = L"PciRomInMemory";
1495
1496 //FileName = L"PciRom Addr=0000000000000000";
1497 //HexToString (&FileName[12], Rom, 16);
1498
1499 ImageIndex = 0;
1500 retStatus = EFI_NOT_FOUND;
1501 RomOffset = (UINTN) Rom;
1502
1503 do {
1504
1505 EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) (UINTN) RomOffset;
1506
1507 if (EfiRomHeader->Signature != 0xaa55) {
1508 return retStatus;
1509 }
1510
1511 Pcir = (PCI_DATA_STRUCTURE *) (UINTN) (RomOffset + EfiRomHeader->PcirOffset);
1512 ImageSize = Pcir->ImageLength * 512;
1513
1514 if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) &&
1515 (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) ) {
1516
1517 if ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
1518 (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) ) {
1519
1520 ImageOffset = EfiRomHeader->EfiImageHeaderOffset;
1521 ImageSize = EfiRomHeader->InitializationSize * 512;
1522
1523 ImageBuffer = (VOID *) (UINTN) (RomOffset + ImageOffset);
1524 ImageLength = ImageSize - ImageOffset;
1525 DecompressedImageBuffer = NULL;
1526
1527 //
1528 // decompress here if needed
1529 //
1530 SkipImage = FALSE;
1531 if (EfiRomHeader->CompressionType > EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
1532 SkipImage = TRUE;
1533 }
1534
1535 if (EfiRomHeader->CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
1536 Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress);
1537 if (EFI_ERROR (Status)) {
1538 SkipImage = TRUE;
1539 } else {
1540 SkipImage = TRUE;
1541 Status = Decompress->GetInfo (
1542 Decompress,
1543 ImageBuffer,
1544 ImageLength,
1545 &DestinationSize,
1546 &ScratchSize
1547 );
1548 if (!EFI_ERROR (Status)) {
1549 DecompressedImageBuffer = NULL;
1550 DecompressedImageBuffer = AllocatePool (DestinationSize);
1551 if (DecompressedImageBuffer != NULL) {
1552 Scratch = AllocatePool (ScratchSize);
1553 if (Scratch != NULL) {
1554 Status = Decompress->Decompress (
1555 Decompress,
1556 ImageBuffer,
1557 ImageLength,
1558 DecompressedImageBuffer,
1559 DestinationSize,
1560 Scratch,
1561 ScratchSize
1562 );
1563 if (!EFI_ERROR (Status)) {
1564 ImageBuffer = DecompressedImageBuffer;
1565 ImageLength = DestinationSize;
1566 SkipImage = FALSE;
1567 }
1568
1569 gBS->FreePool (Scratch);
1570 }
1571 }
1572 }
1573 }
1574 }
1575
1576 if (!SkipImage) {
1577
1578 //
1579 // load image and start image
1580 //
1581
1582 FilePath = FileDevicePath (NULL, FileName);
1583
1584 Status = gBS->LoadImage (
1585 FALSE,
1586 gImageHandle,
1587 FilePath,
1588 ImageBuffer,
1589 ImageLength,
1590 &ImageHandle
1591 );
1592 if (!EFI_ERROR (Status)) {
1593 Status = gBS->StartImage (ImageHandle, NULL, NULL);
1594 if (!EFI_ERROR (Status)) {
1595 retStatus = Status;
1596 }
1597 }
1598 if (FilePath != NULL) {
1599 gBS->FreePool (FilePath);
1600 }
1601 }
1602
1603 if (DecompressedImageBuffer != NULL) {
1604 gBS->FreePool (DecompressedImageBuffer);
1605 }
1606
1607 }
1608 }
1609
1610 RomOffset = RomOffset + ImageSize;
1611 ImageIndex++;
1612 } while (((Pcir->Indicator & 0x80) == 0x00) && ((RomOffset - (UINTN) Rom) < RomSize));
1613
1614 return retStatus;
1615 }
1616
1617