]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.c
Performance: Refine the format of INF files.
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciBusDxe / PciOptionRomSupport.c
1 /** @file
2 PCI Rom supporting funtions implementation for PCI Bus module.
3
4 Copyright (c) 2006 - 2012, 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 "PciBus.h"
16
17 /**
18 Load the EFI Image from Option ROM
19
20 @param PciIoDevice PCI IO device instance.
21 @param FilePath The file path of the EFI Image
22 @param BufferSize On input the size of Buffer in bytes. On output with a return
23 code of EFI_SUCCESS, the amount of data transferred to Buffer.
24 On output with a return code of EFI_BUFFER_TOO_SMALL,
25 the size of Buffer required to retrieve the requested file.
26 @param Buffer The memory buffer to transfer the file to. If Buffer is NULL,
27 then no the size of the requested file is returned in BufferSize.
28
29 @retval EFI_SUCCESS The file was loaded.
30 @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
31 BufferSize is NULL.
32 @retval EFI_NOT_FOUND Not found PCI Option Rom on PCI device.
33 @retval EFI_DEVICE_ERROR Failed to decompress PCI Option Rom image.
34 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
35 BufferSize has been updated with the size needed to complete the request.
36 **/
37 EFI_STATUS
38 LocalLoadFile2 (
39 IN PCI_IO_DEVICE *PciIoDevice,
40 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
41 IN OUT UINTN *BufferSize,
42 IN VOID *Buffer OPTIONAL
43 )
44 {
45 EFI_STATUS Status;
46 MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH *EfiOpRomImageNode;
47 EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader;
48 PCI_DATA_STRUCTURE *Pcir;
49 UINT32 ImageSize;
50 UINT8 *ImageBuffer;
51 UINT32 ImageLength;
52 UINT32 DestinationSize;
53 UINT32 ScratchSize;
54 VOID *Scratch;
55 EFI_DECOMPRESS_PROTOCOL *Decompress;
56 UINT32 InitializationSize;
57
58 EfiOpRomImageNode = (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH *) FilePath;
59 if ((EfiOpRomImageNode == NULL) ||
60 (DevicePathType (FilePath) != MEDIA_DEVICE_PATH) ||
61 (DevicePathSubType (FilePath) != MEDIA_RELATIVE_OFFSET_RANGE_DP) ||
62 (DevicePathNodeLength (FilePath) != sizeof (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH)) ||
63 (!IsDevicePathEnd (NextDevicePathNode (FilePath))) ||
64 (EfiOpRomImageNode->StartingOffset > EfiOpRomImageNode->EndingOffset) ||
65 (EfiOpRomImageNode->EndingOffset >= PciIoDevice->RomSize) ||
66 (BufferSize == NULL)
67 ) {
68 return EFI_INVALID_PARAMETER;
69 }
70
71 EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) (
72 (UINT8 *) PciIoDevice->PciIo.RomImage + EfiOpRomImageNode->StartingOffset
73 );
74 if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
75 return EFI_NOT_FOUND;
76 }
77
78
79 Pcir = (PCI_DATA_STRUCTURE *) ((UINT8 *) EfiRomHeader + EfiRomHeader->PcirOffset);
80 ASSERT (Pcir->Signature == PCI_DATA_STRUCTURE_SIGNATURE);
81
82 if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) &&
83 (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) &&
84 ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
85 (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)) &&
86 (EfiRomHeader->CompressionType <= EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED)
87 ) {
88
89 ImageSize = Pcir->ImageLength * 512;
90 InitializationSize = (UINT32) EfiRomHeader->InitializationSize * 512;
91 if (InitializationSize > ImageSize || EfiRomHeader->EfiImageHeaderOffset >= InitializationSize) {
92 return EFI_NOT_FOUND;
93 }
94
95 ImageBuffer = (UINT8 *) EfiRomHeader + EfiRomHeader->EfiImageHeaderOffset;
96 ImageLength = InitializationSize - EfiRomHeader->EfiImageHeaderOffset;
97
98 if (EfiRomHeader->CompressionType != EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
99 //
100 // Uncompressed: Copy the EFI Image directly to user's buffer
101 //
102 if (Buffer == NULL || *BufferSize < ImageLength) {
103 *BufferSize = ImageLength;
104 return EFI_BUFFER_TOO_SMALL;
105 }
106
107 *BufferSize = ImageLength;
108 CopyMem (Buffer, ImageBuffer, ImageLength);
109 return EFI_SUCCESS;
110
111 } else {
112 //
113 // Compressed: Uncompress before copying
114 //
115 Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress);
116 if (EFI_ERROR (Status)) {
117 return EFI_DEVICE_ERROR;
118 }
119 Status = Decompress->GetInfo (
120 Decompress,
121 ImageBuffer,
122 ImageLength,
123 &DestinationSize,
124 &ScratchSize
125 );
126 if (EFI_ERROR (Status)) {
127 return EFI_DEVICE_ERROR;
128 }
129
130 if (Buffer == NULL || *BufferSize < DestinationSize) {
131 *BufferSize = DestinationSize;
132 return EFI_BUFFER_TOO_SMALL;
133 }
134
135 *BufferSize = DestinationSize;
136 Scratch = AllocatePool (ScratchSize);
137 if (Scratch == NULL) {
138 return EFI_DEVICE_ERROR;
139 }
140
141 Status = Decompress->Decompress (
142 Decompress,
143 ImageBuffer,
144 ImageLength,
145 Buffer,
146 DestinationSize,
147 Scratch,
148 ScratchSize
149 );
150 FreePool (Scratch);
151
152 if (EFI_ERROR (Status)) {
153 return EFI_DEVICE_ERROR;
154 }
155 return EFI_SUCCESS;
156 }
157 }
158
159 return EFI_NOT_FOUND;
160 }
161
162 /**
163 Initialize a PCI LoadFile2 instance.
164
165 @param PciIoDevice PCI IO Device.
166
167 **/
168 VOID
169 InitializePciLoadFile2 (
170 IN PCI_IO_DEVICE *PciIoDevice
171 )
172 {
173 PciIoDevice->LoadFile2.LoadFile = LoadFile2;
174 }
175
176 /**
177 Causes the driver to load a specified file.
178
179 @param This Indicates a pointer to the calling context.
180 @param FilePath The device specific path of the file to load.
181 @param BootPolicy Should always be FALSE.
182 @param BufferSize On input the size of Buffer in bytes. On output with a return
183 code of EFI_SUCCESS, the amount of data transferred to Buffer.
184 On output with a return code of EFI_BUFFER_TOO_SMALL,
185 the size of Buffer required to retrieve the requested file.
186 @param Buffer The memory buffer to transfer the file to. If Buffer is NULL,
187 then no the size of the requested file is returned in BufferSize.
188
189 @retval EFI_SUCCESS The file was loaded.
190 @retval EFI_UNSUPPORTED BootPolicy is TRUE.
191 @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
192 BufferSize is NULL.
193 @retval EFI_NOT_FOUND Not found PCI Option Rom on PCI device.
194 @retval EFI_DEVICE_ERROR Failed to decompress PCI Option Rom image.
195 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
196 BufferSize has been updated with the size needed to complete the request.
197
198 **/
199 EFI_STATUS
200 EFIAPI
201 LoadFile2 (
202 IN EFI_LOAD_FILE2_PROTOCOL *This,
203 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
204 IN BOOLEAN BootPolicy,
205 IN OUT UINTN *BufferSize,
206 IN VOID *Buffer OPTIONAL
207 )
208 {
209 PCI_IO_DEVICE *PciIoDevice;
210
211 if (BootPolicy) {
212 return EFI_UNSUPPORTED;
213 }
214 PciIoDevice = PCI_IO_DEVICE_FROM_LOAD_FILE2_THIS (This);
215
216 return LocalLoadFile2 (
217 PciIoDevice,
218 FilePath,
219 BufferSize,
220 Buffer
221 );
222 }
223
224 /**
225 Get Pci device's oprom information.
226
227 @param PciIoDevice Input Pci device instance.
228 Output Pci device instance with updated OptionRom size.
229
230 @retval EFI_NOT_FOUND Pci device has not Option Rom.
231 @retval EFI_SUCCESS Pci device has Option Rom.
232
233 **/
234 EFI_STATUS
235 GetOpRomInfo (
236 IN OUT PCI_IO_DEVICE *PciIoDevice
237 )
238 {
239 UINT8 RomBarIndex;
240 UINT32 AllOnes;
241 UINT64 Address;
242 EFI_STATUS Status;
243 UINT8 Bus;
244 UINT8 Device;
245 UINT8 Function;
246 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
247
248 Bus = PciIoDevice->BusNumber;
249 Device = PciIoDevice->DeviceNumber;
250 Function = PciIoDevice->FunctionNumber;
251
252 PciRootBridgeIo = PciIoDevice->PciRootBridgeIo;
253
254 //
255 // Offset is 0x30 if is not ppb
256 //
257
258 //
259 // 0x30
260 //
261 RomBarIndex = PCI_EXPANSION_ROM_BASE;
262
263 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
264 //
265 // If is ppb, 0x38
266 //
267 RomBarIndex = PCI_BRIDGE_ROMBAR;
268 }
269 //
270 // The bit0 is 0 to prevent the enabling of the Rom address decoder
271 //
272 AllOnes = 0xfffffffe;
273 Address = EFI_PCI_ADDRESS (Bus, Device, Function, RomBarIndex);
274
275 Status = PciRootBridgeIo->Pci.Write (
276 PciRootBridgeIo,
277 EfiPciWidthUint32,
278 Address,
279 1,
280 &AllOnes
281 );
282 if (EFI_ERROR (Status)) {
283 return EFI_NOT_FOUND;
284 }
285
286 //
287 // Read back
288 //
289 Status = PciRootBridgeIo->Pci.Read(
290 PciRootBridgeIo,
291 EfiPciWidthUint32,
292 Address,
293 1,
294 &AllOnes
295 );
296 if (EFI_ERROR (Status)) {
297 return EFI_NOT_FOUND;
298 }
299
300 //
301 // Bits [1, 10] are reserved
302 //
303 AllOnes &= 0xFFFFF800;
304 if ((AllOnes == 0) || (AllOnes == 0xFFFFF800)) {
305 return EFI_NOT_FOUND;
306 }
307
308 PciIoDevice->RomSize = (UINT64) ((~AllOnes) + 1);
309 return EFI_SUCCESS;
310 }
311
312 /**
313 Load Option Rom image for specified PCI device.
314
315 @param PciDevice Pci device instance.
316 @param RomBase Base address of Option Rom.
317
318 @retval EFI_OUT_OF_RESOURCES No enough memory to hold image.
319 @retval EFI_SUCESS Successfully loaded Option Rom.
320
321 **/
322 EFI_STATUS
323 LoadOpRomImage (
324 IN PCI_IO_DEVICE *PciDevice,
325 IN UINT64 RomBase
326 )
327 {
328 UINT8 RomBarIndex;
329 UINT8 Indicator;
330 UINT16 OffsetPcir;
331 UINT32 RomBarOffset;
332 UINT32 RomBar;
333 EFI_STATUS RetStatus;
334 BOOLEAN FirstCheck;
335 UINT8 *Image;
336 PCI_EXPANSION_ROM_HEADER *RomHeader;
337 PCI_DATA_STRUCTURE *RomPcir;
338 UINT64 RomSize;
339 UINT64 RomImageSize;
340 UINT32 LegacyImageLength;
341 UINT8 *RomInMemory;
342 UINT8 CodeType;
343 BOOLEAN HasEfiOpRom;
344
345 RomSize = PciDevice->RomSize;
346
347 Indicator = 0;
348 RomImageSize = 0;
349 RomInMemory = NULL;
350 CodeType = 0xFF;
351
352 //
353 // Get the RomBarIndex
354 //
355
356 //
357 // 0x30
358 //
359 RomBarIndex = PCI_EXPANSION_ROM_BASE;
360 if (IS_PCI_BRIDGE (&(PciDevice->Pci))) {
361 //
362 // if is ppb
363 //
364
365 //
366 // 0x38
367 //
368 RomBarIndex = PCI_BRIDGE_ROMBAR;
369 }
370 //
371 // Allocate memory for Rom header and PCIR
372 //
373 RomHeader = AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER));
374 if (RomHeader == NULL) {
375 return EFI_OUT_OF_RESOURCES;
376 }
377
378 RomPcir = AllocatePool (sizeof (PCI_DATA_STRUCTURE));
379 if (RomPcir == NULL) {
380 FreePool (RomHeader);
381 return EFI_OUT_OF_RESOURCES;
382 }
383
384 RomBar = (UINT32) RomBase;
385
386 //
387 // Enable RomBar
388 //
389 RomDecode (PciDevice, RomBarIndex, RomBar, TRUE);
390
391 RomBarOffset = RomBar;
392 RetStatus = EFI_NOT_FOUND;
393 FirstCheck = TRUE;
394 LegacyImageLength = 0;
395 HasEfiOpRom = FALSE;
396
397 do {
398 PciDevice->PciRootBridgeIo->Mem.Read (
399 PciDevice->PciRootBridgeIo,
400 EfiPciWidthUint8,
401 RomBarOffset,
402 sizeof (PCI_EXPANSION_ROM_HEADER),
403 (UINT8 *) RomHeader
404 );
405
406 if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
407 RomBarOffset = RomBarOffset + 512;
408 if (FirstCheck) {
409 break;
410 } else {
411 RomImageSize = RomImageSize + 512;
412 continue;
413 }
414 }
415
416 FirstCheck = FALSE;
417 OffsetPcir = RomHeader->PcirOffset;
418 //
419 // If the pointer to the PCI Data Structure is invalid, no further images can be located.
420 // The PCI Data Structure must be DWORD aligned.
421 //
422 if (OffsetPcir == 0 ||
423 (OffsetPcir & 3) != 0 ||
424 RomImageSize + OffsetPcir + sizeof (PCI_DATA_STRUCTURE) > RomSize) {
425 break;
426 }
427 PciDevice->PciRootBridgeIo->Mem.Read (
428 PciDevice->PciRootBridgeIo,
429 EfiPciWidthUint8,
430 RomBarOffset + OffsetPcir,
431 sizeof (PCI_DATA_STRUCTURE),
432 (UINT8 *) RomPcir
433 );
434 //
435 // If a valid signature is not present in the PCI Data Structure, no further images can be located.
436 //
437 if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
438 break;
439 }
440 if (RomImageSize + RomPcir->ImageLength * 512 > RomSize) {
441 break;
442 }
443 if (RomPcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
444 CodeType = PCI_CODE_TYPE_PCAT_IMAGE;
445 LegacyImageLength = ((UINT32)((EFI_LEGACY_EXPANSION_ROM_HEADER *)RomHeader)->Size512) * 512;
446 } else if (RomPcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) {
447 HasEfiOpRom = TRUE;
448 }
449 Indicator = RomPcir->Indicator;
450 RomImageSize = RomImageSize + RomPcir->ImageLength * 512;
451 RomBarOffset = RomBarOffset + RomPcir->ImageLength * 512;
452 } while (((Indicator & 0x80) == 0x00) && ((RomBarOffset - RomBar) < RomSize));
453
454 //
455 // Some Legacy Cards do not report the correct ImageLength so used the maximum
456 // of the legacy length and the PCIR Image Length
457 //
458 if (CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
459 RomImageSize = MAX (RomImageSize, LegacyImageLength);
460 }
461
462 if (RomImageSize > 0) {
463 RetStatus = EFI_SUCCESS;
464 Image = AllocatePool ((UINT32) RomImageSize);
465 if (Image == NULL) {
466 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
467 FreePool (RomHeader);
468 FreePool (RomPcir);
469 return EFI_OUT_OF_RESOURCES;
470 }
471
472 //
473 // Copy Rom image into memory
474 //
475 PciDevice->PciRootBridgeIo->Mem.Read (
476 PciDevice->PciRootBridgeIo,
477 EfiPciWidthUint8,
478 RomBar,
479 (UINT32) RomImageSize,
480 Image
481 );
482 RomInMemory = Image;
483 }
484
485 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
486
487 PciDevice->HasEfiOpRom = HasEfiOpRom;
488 PciDevice->EmbeddedRom = TRUE;
489 PciDevice->PciIo.RomSize = RomImageSize;
490 PciDevice->PciIo.RomImage = RomInMemory;
491
492 //
493 // For OpROM read from PCI device:
494 // Add the Rom Image to internal database for later PCI light enumeration
495 //
496 PciRomAddImageMapping (
497 NULL,
498 PciDevice->PciRootBridgeIo->SegmentNumber,
499 PciDevice->BusNumber,
500 PciDevice->DeviceNumber,
501 PciDevice->FunctionNumber,
502 (UINT64) (UINTN) PciDevice->PciIo.RomImage,
503 PciDevice->PciIo.RomSize
504 );
505
506 //
507 // Free allocated memory
508 //
509 FreePool (RomHeader);
510 FreePool (RomPcir);
511
512 return RetStatus;
513 }
514
515 /**
516 Enable/Disable Option Rom decode.
517
518 @param PciDevice Pci device instance.
519 @param RomBarIndex The BAR index of the standard PCI Configuration header to use as the
520 base address for resource range. The legal range for this field is 0..5.
521 @param RomBar Base address of Option Rom.
522 @param Enable Flag for enable/disable decode.
523
524 **/
525 VOID
526 RomDecode (
527 IN PCI_IO_DEVICE *PciDevice,
528 IN UINT8 RomBarIndex,
529 IN UINT32 RomBar,
530 IN BOOLEAN Enable
531 )
532 {
533 UINT32 Value32;
534 UINT32 Offset;
535 UINT32 OffsetMax;
536 EFI_PCI_IO_PROTOCOL *PciIo;
537
538 PciIo = &PciDevice->PciIo;
539 if (Enable) {
540 //
541 // Clear all bars
542 //
543 OffsetMax = 0x24;
544 if (IS_PCI_BRIDGE(&PciDevice->Pci)) {
545 OffsetMax = 0x14;
546 }
547
548 for (Offset = 0x10; Offset <= OffsetMax; Offset += sizeof (UINT32)) {
549 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllZero);
550 }
551
552 //
553 // set the Rom base address: now is hardcode
554 // enable its decoder
555 //
556 Value32 = RomBar | 0x1;
557 PciIo->Pci.Write (
558 PciIo,
559 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,
560 RomBarIndex,
561 1,
562 &Value32
563 );
564
565 //
566 // Programe all upstream bridge
567 //
568 ProgrameUpstreamBridgeForRom(PciDevice, RomBar, TRUE);
569
570 //
571 // Setting the memory space bit in the function's command register
572 //
573 PCI_ENABLE_COMMAND_REGISTER(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);
574
575 } else {
576
577 //
578 // disable command register decode to memory
579 //
580 PCI_DISABLE_COMMAND_REGISTER(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);
581
582 //
583 // Destroy the programmed bar in all the upstream bridge.
584 //
585 ProgrameUpstreamBridgeForRom(PciDevice, RomBar, FALSE);
586
587 //
588 // disable rom decode
589 //
590 Value32 = 0xFFFFFFFE;
591 PciIo->Pci.Write (
592 PciIo,
593 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,
594 RomBarIndex,
595 1,
596 &Value32
597 );
598
599 }
600 }
601
602 /**
603 Load and start the Option Rom image.
604
605 @param PciDevice Pci device instance.
606
607 @retval EFI_SUCCESS Successfully loaded and started PCI Option Rom image.
608 @retval EFI_NOT_FOUND Failed to process PCI Option Rom image.
609
610 **/
611 EFI_STATUS
612 ProcessOpRomImage (
613 IN PCI_IO_DEVICE *PciDevice
614 )
615 {
616 UINT8 Indicator;
617 UINT32 ImageSize;
618 VOID *RomBar;
619 UINT8 *RomBarOffset;
620 EFI_HANDLE ImageHandle;
621 EFI_STATUS Status;
622 EFI_STATUS RetStatus;
623 EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader;
624 PCI_DATA_STRUCTURE *Pcir;
625 EFI_DEVICE_PATH_PROTOCOL *PciOptionRomImageDevicePath;
626 MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH EfiOpRomImageNode;
627 VOID *Buffer;
628 UINTN BufferSize;
629
630 Indicator = 0;
631
632 //
633 // Get the Address of the Option Rom image
634 //
635 RomBar = PciDevice->PciIo.RomImage;
636 RomBarOffset = (UINT8 *) RomBar;
637 RetStatus = EFI_NOT_FOUND;
638
639 if (RomBar == NULL) {
640 return RetStatus;
641 }
642 ASSERT (((EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset)->Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE);
643
644 do {
645 EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset;
646 if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
647 RomBarOffset += 512;
648 continue;
649 }
650
651 Pcir = (PCI_DATA_STRUCTURE *) (RomBarOffset + EfiRomHeader->PcirOffset);
652 ASSERT (Pcir->Signature == PCI_DATA_STRUCTURE_SIGNATURE);
653 ImageSize = (UINT32) (Pcir->ImageLength * 512);
654 Indicator = Pcir->Indicator;
655
656 //
657 // Skip the image if it is not an EFI PCI Option ROM image
658 //
659 if (Pcir->CodeType != PCI_CODE_TYPE_EFI_IMAGE) {
660 goto NextImage;
661 }
662
663 //
664 // Skip the EFI PCI Option ROM image if its machine type is not supported
665 //
666 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (EfiRomHeader->EfiMachineType)) {
667 goto NextImage;
668 }
669
670 //
671 // Ignore the EFI PCI Option ROM image if it is an EFI application
672 //
673 if (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
674 goto NextImage;
675 }
676
677 //
678 // Create Pci Option Rom Image device path header
679 //
680 EfiOpRomImageNode.Header.Type = MEDIA_DEVICE_PATH;
681 EfiOpRomImageNode.Header.SubType = MEDIA_RELATIVE_OFFSET_RANGE_DP;
682 SetDevicePathNodeLength (&EfiOpRomImageNode.Header, sizeof (EfiOpRomImageNode));
683 EfiOpRomImageNode.StartingOffset = (UINTN) RomBarOffset - (UINTN) RomBar;
684 EfiOpRomImageNode.EndingOffset = (UINTN) RomBarOffset + ImageSize - 1 - (UINTN) RomBar;
685
686 PciOptionRomImageDevicePath = AppendDevicePathNode (PciDevice->DevicePath, &EfiOpRomImageNode.Header);
687 ASSERT (PciOptionRomImageDevicePath != NULL);
688
689 //
690 // load image and start image
691 //
692 BufferSize = 0;
693 Buffer = NULL;
694 ImageHandle = NULL;
695
696 Status = gBS->LoadImage (
697 FALSE,
698 gPciBusDriverBinding.DriverBindingHandle,
699 PciOptionRomImageDevicePath,
700 Buffer,
701 BufferSize,
702 &ImageHandle
703 );
704
705 FreePool (PciOptionRomImageDevicePath);
706
707 if (!EFI_ERROR (Status)) {
708 Status = gBS->StartImage (ImageHandle, NULL, NULL);
709 if (!EFI_ERROR (Status)) {
710 AddDriver (PciDevice, ImageHandle);
711 PciRomAddImageMapping (
712 ImageHandle,
713 PciDevice->PciRootBridgeIo->SegmentNumber,
714 PciDevice->BusNumber,
715 PciDevice->DeviceNumber,
716 PciDevice->FunctionNumber,
717 (UINT64) (UINTN) PciDevice->PciIo.RomImage,
718 PciDevice->PciIo.RomSize
719 );
720 RetStatus = EFI_SUCCESS;
721 }
722 }
723
724 NextImage:
725 RomBarOffset += ImageSize;
726
727 } while (((Indicator & 0x80) == 0x00) && ((UINTN) (RomBarOffset - (UINT8 *) RomBar) < PciDevice->RomSize));
728
729 return RetStatus;
730 }
731