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