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