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