]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.c
Improve robustness when scanning PCI Option ROM.
[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 Check if the RomImage contains EFI Images.
314
315 @param RomImage The ROM address of Image for check.
316 @param RomSize Size of ROM for check.
317
318 @retval TRUE ROM contain EFI Image.
319 @retval FALSE ROM not contain EFI Image.
320
321 **/
322 BOOLEAN
323 ContainEfiImage (
324 IN VOID *RomImage,
325 IN UINT64 RomSize
326 )
327 {
328 PCI_EXPANSION_ROM_HEADER *RomHeader;
329 PCI_DATA_STRUCTURE *RomPcir;
330
331 RomHeader = RomImage;
332 if (RomHeader == NULL) {
333 return FALSE;
334 }
335 ASSERT (RomHeader->Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE);
336
337 while ((UINT8 *) RomHeader < (UINT8 *) RomImage + RomSize) {
338 if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
339 RomHeader = (PCI_EXPANSION_ROM_HEADER *) ((UINT8 *) RomHeader + 512);
340 continue;
341 }
342
343 RomPcir = (PCI_DATA_STRUCTURE *) ((UINT8 *) RomHeader + RomHeader->PcirOffset);
344 ASSERT (RomPcir->Signature == PCI_DATA_STRUCTURE_SIGNATURE);
345
346 if (RomPcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) {
347 return TRUE;
348 }
349
350 RomHeader = (PCI_EXPANSION_ROM_HEADER *) ((UINT8 *) RomHeader + RomPcir->Length * 512);
351 }
352
353 return FALSE;
354 }
355
356
357 /**
358 Load Option Rom image for specified PCI device.
359
360 @param PciDevice Pci device instance.
361 @param RomBase Base address of Option Rom.
362
363 @retval EFI_OUT_OF_RESOURCES No enough memory to hold image.
364 @retval EFI_SUCESS Successfully loaded Option Rom.
365
366 **/
367 EFI_STATUS
368 LoadOpRomImage (
369 IN PCI_IO_DEVICE *PciDevice,
370 IN UINT64 RomBase
371 )
372 {
373 UINT8 RomBarIndex;
374 UINT8 Indicator;
375 UINT16 OffsetPcir;
376 UINT32 RomBarOffset;
377 UINT32 RomBar;
378 EFI_STATUS RetStatus;
379 BOOLEAN FirstCheck;
380 UINT8 *Image;
381 PCI_EXPANSION_ROM_HEADER *RomHeader;
382 PCI_DATA_STRUCTURE *RomPcir;
383 UINT64 RomSize;
384 UINT64 RomImageSize;
385 UINT32 LegacyImageLength;
386 UINT8 *RomInMemory;
387 UINT8 CodeType;
388
389 RomSize = PciDevice->RomSize;
390
391 Indicator = 0;
392 RomImageSize = 0;
393 RomInMemory = NULL;
394 CodeType = 0xFF;
395
396 //
397 // Get the RomBarIndex
398 //
399
400 //
401 // 0x30
402 //
403 RomBarIndex = PCI_EXPANSION_ROM_BASE;
404 if (IS_PCI_BRIDGE (&(PciDevice->Pci))) {
405 //
406 // if is ppb
407 //
408
409 //
410 // 0x38
411 //
412 RomBarIndex = PCI_BRIDGE_ROMBAR;
413 }
414 //
415 // Allocate memory for Rom header and PCIR
416 //
417 RomHeader = AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER));
418 if (RomHeader == NULL) {
419 return EFI_OUT_OF_RESOURCES;
420 }
421
422 RomPcir = AllocatePool (sizeof (PCI_DATA_STRUCTURE));
423 if (RomPcir == NULL) {
424 FreePool (RomHeader);
425 return EFI_OUT_OF_RESOURCES;
426 }
427
428 RomBar = (UINT32) RomBase;
429
430 //
431 // Enable RomBar
432 //
433 RomDecode (PciDevice, RomBarIndex, RomBar, TRUE);
434
435 RomBarOffset = RomBar;
436 RetStatus = EFI_NOT_FOUND;
437 FirstCheck = TRUE;
438 LegacyImageLength = 0;
439
440 do {
441 PciDevice->PciRootBridgeIo->Mem.Read (
442 PciDevice->PciRootBridgeIo,
443 EfiPciWidthUint8,
444 RomBarOffset,
445 sizeof (PCI_EXPANSION_ROM_HEADER),
446 (UINT8 *) RomHeader
447 );
448
449 if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
450 RomBarOffset = RomBarOffset + 512;
451 if (FirstCheck) {
452 break;
453 } else {
454 RomImageSize = RomImageSize + 512;
455 continue;
456 }
457 }
458
459 FirstCheck = FALSE;
460 OffsetPcir = RomHeader->PcirOffset;
461 //
462 // If the pointer to the PCI Data Structure is invalid, no further images can be located.
463 // The PCI Data Structure must be DWORD aligned.
464 //
465 if (OffsetPcir == 0 ||
466 (OffsetPcir & 3) != 0 ||
467 RomImageSize + OffsetPcir + sizeof (PCI_DATA_STRUCTURE) > RomSize) {
468 break;
469 }
470 PciDevice->PciRootBridgeIo->Mem.Read (
471 PciDevice->PciRootBridgeIo,
472 EfiPciWidthUint8,
473 RomBarOffset + OffsetPcir,
474 sizeof (PCI_DATA_STRUCTURE),
475 (UINT8 *) RomPcir
476 );
477 //
478 // If a valid signature is not present in the PCI Data Structure, no further images can be located.
479 //
480 if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
481 break;
482 }
483 if (RomImageSize + RomPcir->ImageLength * 512 > RomSize) {
484 break;
485 }
486 if (RomPcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
487 CodeType = PCI_CODE_TYPE_PCAT_IMAGE;
488 LegacyImageLength = ((UINT32)((EFI_LEGACY_EXPANSION_ROM_HEADER *)RomHeader)->Size512) * 512;
489 }
490 Indicator = RomPcir->Indicator;
491 RomImageSize = RomImageSize + RomPcir->ImageLength * 512;
492 RomBarOffset = RomBarOffset + RomPcir->ImageLength * 512;
493 } while (((Indicator & 0x80) == 0x00) && ((RomBarOffset - RomBar) < RomSize));
494
495 //
496 // Some Legacy Cards do not report the correct ImageLength so used the maximum
497 // of the legacy length and the PCIR Image Length
498 //
499 if (CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
500 RomImageSize = MAX (RomImageSize, LegacyImageLength);
501 }
502
503 if (RomImageSize > 0) {
504 RetStatus = EFI_SUCCESS;
505 Image = AllocatePool ((UINT32) RomImageSize);
506 if (Image == NULL) {
507 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
508 FreePool (RomHeader);
509 FreePool (RomPcir);
510 return EFI_OUT_OF_RESOURCES;
511 }
512
513 //
514 // Copy Rom image into memory
515 //
516 PciDevice->PciRootBridgeIo->Mem.Read (
517 PciDevice->PciRootBridgeIo,
518 EfiPciWidthUint8,
519 RomBar,
520 (UINT32) RomImageSize,
521 Image
522 );
523 RomInMemory = Image;
524 }
525
526 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
527
528 PciDevice->EmbeddedRom = TRUE;
529 PciDevice->PciIo.RomSize = RomImageSize;
530 PciDevice->PciIo.RomImage = RomInMemory;
531
532 //
533 // For OpROM read from PCI device:
534 // Add the Rom Image to internal database for later PCI light enumeration
535 //
536 PciRomAddImageMapping (
537 NULL,
538 PciDevice->PciRootBridgeIo->SegmentNumber,
539 PciDevice->BusNumber,
540 PciDevice->DeviceNumber,
541 PciDevice->FunctionNumber,
542 (UINT64) (UINTN) PciDevice->PciIo.RomImage,
543 PciDevice->PciIo.RomSize
544 );
545
546 //
547 // Free allocated memory
548 //
549 FreePool (RomHeader);
550 FreePool (RomPcir);
551
552 return RetStatus;
553 }
554
555 /**
556 Enable/Disable Option Rom decode.
557
558 @param PciDevice Pci device instance.
559 @param RomBarIndex The BAR index of the standard PCI Configuration header to use as the
560 base address for resource range. The legal range for this field is 0..5.
561 @param RomBar Base address of Option Rom.
562 @param Enable Flag for enable/disable decode.
563
564 **/
565 VOID
566 RomDecode (
567 IN PCI_IO_DEVICE *PciDevice,
568 IN UINT8 RomBarIndex,
569 IN UINT32 RomBar,
570 IN BOOLEAN Enable
571 )
572 {
573 UINT32 Value32;
574 UINT32 Offset;
575 UINT32 OffsetMax;
576 EFI_PCI_IO_PROTOCOL *PciIo;
577
578 PciIo = &PciDevice->PciIo;
579 if (Enable) {
580 //
581 // Clear all bars
582 //
583 OffsetMax = 0x24;
584 if (IS_PCI_BRIDGE(&PciDevice->Pci)) {
585 OffsetMax = 0x14;
586 }
587
588 for (Offset = 0x10; Offset <= OffsetMax; Offset += sizeof (UINT32)) {
589 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllZero);
590 }
591
592 //
593 // set the Rom base address: now is hardcode
594 // enable its decoder
595 //
596 Value32 = RomBar | 0x1;
597 PciIo->Pci.Write (
598 PciIo,
599 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,
600 RomBarIndex,
601 1,
602 &Value32
603 );
604
605 //
606 // Programe all upstream bridge
607 //
608 ProgrameUpstreamBridgeForRom(PciDevice, RomBar, TRUE);
609
610 //
611 // Setting the memory space bit in the function's command register
612 //
613 PCI_ENABLE_COMMAND_REGISTER(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);
614
615 } else {
616
617 //
618 // disable command register decode to memory
619 //
620 PCI_DISABLE_COMMAND_REGISTER(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);
621
622 //
623 // Destroy the programmed bar in all the upstream bridge.
624 //
625 ProgrameUpstreamBridgeForRom(PciDevice, RomBar, FALSE);
626
627 //
628 // disable rom decode
629 //
630 Value32 = 0xFFFFFFFE;
631 PciIo->Pci.Write (
632 PciIo,
633 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,
634 RomBarIndex,
635 1,
636 &Value32
637 );
638
639 }
640 }
641
642 /**
643 Load and start the Option Rom image.
644
645 @param PciDevice Pci device instance.
646
647 @retval EFI_SUCCESS Successfully loaded and started PCI Option Rom image.
648 @retval EFI_NOT_FOUND Failed to process PCI Option Rom image.
649
650 **/
651 EFI_STATUS
652 ProcessOpRomImage (
653 IN PCI_IO_DEVICE *PciDevice
654 )
655 {
656 UINT8 Indicator;
657 UINT32 ImageSize;
658 VOID *RomBar;
659 UINT8 *RomBarOffset;
660 EFI_HANDLE ImageHandle;
661 EFI_STATUS Status;
662 EFI_STATUS RetStatus;
663 EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader;
664 PCI_DATA_STRUCTURE *Pcir;
665 EFI_DEVICE_PATH_PROTOCOL *PciOptionRomImageDevicePath;
666 MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH EfiOpRomImageNode;
667 VOID *Buffer;
668 UINTN BufferSize;
669
670 Indicator = 0;
671
672 //
673 // Get the Address of the Option Rom image
674 //
675 RomBar = PciDevice->PciIo.RomImage;
676 RomBarOffset = (UINT8 *) RomBar;
677 RetStatus = EFI_NOT_FOUND;
678
679 if (RomBar == NULL) {
680 return RetStatus;
681 }
682 ASSERT (((EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset)->Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE);
683
684 do {
685 EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset;
686 if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
687 RomBarOffset += 512;
688 continue;
689 }
690
691 Pcir = (PCI_DATA_STRUCTURE *) (RomBarOffset + EfiRomHeader->PcirOffset);
692 ASSERT (Pcir->Signature == PCI_DATA_STRUCTURE_SIGNATURE);
693 ImageSize = (UINT32) (Pcir->ImageLength * 512);
694 Indicator = Pcir->Indicator;
695
696 //
697 // Skip the image if it is not an EFI PCI Option ROM image
698 //
699 if (Pcir->CodeType != PCI_CODE_TYPE_EFI_IMAGE) {
700 goto NextImage;
701 }
702
703 //
704 // Skip the EFI PCI Option ROM image if its machine type is not supported
705 //
706 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (EfiRomHeader->EfiMachineType)) {
707 goto NextImage;
708 }
709
710 //
711 // Ignore the EFI PCI Option ROM image if it is an EFI application
712 //
713 if (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
714 goto NextImage;
715 }
716
717 //
718 // Create Pci Option Rom Image device path header
719 //
720 EfiOpRomImageNode.Header.Type = MEDIA_DEVICE_PATH;
721 EfiOpRomImageNode.Header.SubType = MEDIA_RELATIVE_OFFSET_RANGE_DP;
722 SetDevicePathNodeLength (&EfiOpRomImageNode.Header, sizeof (EfiOpRomImageNode));
723 EfiOpRomImageNode.StartingOffset = (UINTN) RomBarOffset - (UINTN) RomBar;
724 EfiOpRomImageNode.EndingOffset = (UINTN) RomBarOffset + ImageSize - 1 - (UINTN) RomBar;
725
726 PciOptionRomImageDevicePath = AppendDevicePathNode (PciDevice->DevicePath, &EfiOpRomImageNode.Header);
727 ASSERT (PciOptionRomImageDevicePath != NULL);
728
729 //
730 // load image and start image
731 //
732 BufferSize = 0;
733 Buffer = NULL;
734 ImageHandle = NULL;
735
736 Status = gBS->LoadImage (
737 FALSE,
738 gPciBusDriverBinding.DriverBindingHandle,
739 PciOptionRomImageDevicePath,
740 Buffer,
741 BufferSize,
742 &ImageHandle
743 );
744
745 FreePool (PciOptionRomImageDevicePath);
746
747 if (!EFI_ERROR (Status)) {
748 Status = gBS->StartImage (ImageHandle, NULL, NULL);
749 if (!EFI_ERROR (Status)) {
750 AddDriver (PciDevice, ImageHandle);
751 PciRomAddImageMapping (
752 ImageHandle,
753 PciDevice->PciRootBridgeIo->SegmentNumber,
754 PciDevice->BusNumber,
755 PciDevice->DeviceNumber,
756 PciDevice->FunctionNumber,
757 (UINT64) (UINTN) PciDevice->PciIo.RomImage,
758 PciDevice->PciIo.RomSize
759 );
760 RetStatus = EFI_SUCCESS;
761 }
762 }
763
764 NextImage:
765 RomBarOffset += ImageSize;
766
767 } while (((Indicator & 0x80) == 0x00) && ((UINTN) (RomBarOffset - (UINT8 *) RomBar) < PciDevice->RomSize));
768
769 return RetStatus;
770 }
771