]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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 {
63 return EFI_INVALID_PARAMETER;
64 }
65
66 EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *)(
67 (UINT8 *)PciIoDevice->PciIo.RomImage + EfiOpRomImageNode->StartingOffset
68 );
69 if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
70 return EFI_NOT_FOUND;
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 } else {
105 //
106 // Compressed: Uncompress before copying
107 //
108 Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **)&Decompress);
109 if (EFI_ERROR (Status)) {
110 return EFI_DEVICE_ERROR;
111 }
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
150 return EFI_SUCCESS;
151 }
152 }
153
154 return EFI_NOT_FOUND;
155 }
156
157 /**
158 Initialize a PCI LoadFile2 instance.
159
160 @param PciIoDevice PCI IO Device.
161
162 **/
163 VOID
164 InitializePciLoadFile2 (
165 IN PCI_IO_DEVICE *PciIoDevice
166 )
167 {
168 PciIoDevice->LoadFile2.LoadFile = LoadFile2;
169 }
170
171 /**
172 Causes the driver to load a specified file.
173
174 @param This Indicates a pointer to the calling context.
175 @param FilePath The device specific path of the file to load.
176 @param BootPolicy Should always be FALSE.
177 @param BufferSize On input the size of Buffer in bytes. On output with a return
178 code of EFI_SUCCESS, the amount of data transferred to Buffer.
179 On output with a return code of EFI_BUFFER_TOO_SMALL,
180 the size of Buffer required to retrieve the requested file.
181 @param Buffer The memory buffer to transfer the file to. If Buffer is NULL,
182 then no the size of the requested file is returned in BufferSize.
183
184 @retval EFI_SUCCESS The file was loaded.
185 @retval EFI_UNSUPPORTED BootPolicy is TRUE.
186 @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
187 BufferSize is NULL.
188 @retval EFI_NOT_FOUND Not found PCI Option Rom on PCI device.
189 @retval EFI_DEVICE_ERROR Failed to decompress PCI Option Rom image.
190 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
191 BufferSize has been updated with the size needed to complete the request.
192
193 **/
194 EFI_STATUS
195 EFIAPI
196 LoadFile2 (
197 IN EFI_LOAD_FILE2_PROTOCOL *This,
198 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
199 IN BOOLEAN BootPolicy,
200 IN OUT UINTN *BufferSize,
201 IN VOID *Buffer OPTIONAL
202 )
203 {
204 PCI_IO_DEVICE *PciIoDevice;
205
206 if (BootPolicy) {
207 return EFI_UNSUPPORTED;
208 }
209
210 PciIoDevice = PCI_IO_DEVICE_FROM_LOAD_FILE2_THIS (This);
211
212 return LocalLoadFile2 (
213 PciIoDevice,
214 FilePath,
215 BufferSize,
216 Buffer
217 );
218 }
219
220 /**
221 Get Pci device's oprom information.
222
223 @param PciIoDevice Input Pci device instance.
224 Output Pci device instance with updated OptionRom size.
225
226 @retval EFI_NOT_FOUND Pci device has not Option Rom.
227 @retval EFI_SUCCESS Pci device has Option Rom.
228
229 **/
230 EFI_STATUS
231 GetOpRomInfo (
232 IN OUT PCI_IO_DEVICE *PciIoDevice
233 )
234 {
235 UINT8 RomBarIndex;
236 UINT32 AllOnes;
237 UINT64 Address;
238 EFI_STATUS Status;
239 UINT8 Bus;
240 UINT8 Device;
241 UINT8 Function;
242 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
243
244 Bus = PciIoDevice->BusNumber;
245 Device = PciIoDevice->DeviceNumber;
246 Function = PciIoDevice->FunctionNumber;
247
248 PciRootBridgeIo = PciIoDevice->PciRootBridgeIo;
249
250 //
251 // Offset is 0x30 if is not ppb
252 //
253
254 //
255 // 0x30
256 //
257 RomBarIndex = PCI_EXPANSION_ROM_BASE;
258
259 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
260 //
261 // If is ppb, 0x38
262 //
263 RomBarIndex = PCI_BRIDGE_ROMBAR;
264 }
265
266 //
267 // The bit0 is 0 to prevent the enabling of the Rom address decoder
268 //
269 AllOnes = 0xfffffffe;
270 Address = EFI_PCI_ADDRESS (Bus, Device, Function, RomBarIndex);
271
272 Status = PciRootBridgeIo->Pci.Write (
273 PciRootBridgeIo,
274 EfiPciWidthUint32,
275 Address,
276 1,
277 &AllOnes
278 );
279 if (EFI_ERROR (Status)) {
280 return EFI_NOT_FOUND;
281 }
282
283 //
284 // Read back
285 //
286 Status = PciRootBridgeIo->Pci.Read (
287 PciRootBridgeIo,
288 EfiPciWidthUint32,
289 Address,
290 1,
291 &AllOnes
292 );
293 if (EFI_ERROR (Status)) {
294 return EFI_NOT_FOUND;
295 }
296
297 //
298 // Bits [1, 10] are reserved
299 //
300 AllOnes &= 0xFFFFF800;
301 if ((AllOnes == 0) || (AllOnes == 0xFFFFF800)) {
302 return EFI_NOT_FOUND;
303 }
304
305 PciIoDevice->RomSize = (~AllOnes) + 1;
306 return EFI_SUCCESS;
307 }
308
309 /**
310 Check if the RomImage contains EFI Images.
311
312 @param RomImage The ROM address of Image for check.
313 @param RomSize Size of ROM for check.
314
315 @retval TRUE ROM contain EFI Image.
316 @retval FALSE ROM not contain EFI Image.
317
318 **/
319 BOOLEAN
320 ContainEfiImage (
321 IN VOID *RomImage,
322 IN UINT64 RomSize
323 )
324 {
325 PCI_EXPANSION_ROM_HEADER *RomHeader;
326 PCI_DATA_STRUCTURE *RomPcir;
327 UINT8 Indicator;
328
329 Indicator = 0;
330 RomHeader = RomImage;
331 if (RomHeader == NULL) {
332 return FALSE;
333 }
334
335 do {
336 if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
337 RomHeader = (PCI_EXPANSION_ROM_HEADER *)((UINT8 *)RomHeader + 512);
338 continue;
339 }
340
341 //
342 // The PCI Data Structure must be DWORD aligned.
343 //
344 if ((RomHeader->PcirOffset == 0) ||
345 ((RomHeader->PcirOffset & 3) != 0) ||
346 ((UINT8 *)RomHeader + RomHeader->PcirOffset + sizeof (PCI_DATA_STRUCTURE) > (UINT8 *)RomImage + RomSize))
347 {
348 break;
349 }
350
351 RomPcir = (PCI_DATA_STRUCTURE *)((UINT8 *)RomHeader + RomHeader->PcirOffset);
352 if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
353 break;
354 }
355
356 if (RomPcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) {
357 return TRUE;
358 }
359
360 Indicator = RomPcir->Indicator;
361 RomHeader = (PCI_EXPANSION_ROM_HEADER *)((UINT8 *)RomHeader + RomPcir->ImageLength * 512);
362 } while (((UINT8 *)RomHeader < (UINT8 *)RomImage + RomSize) && ((Indicator & 0x80) == 0x00));
363
364 return FALSE;
365 }
366
367 /**
368 Load Option Rom image for specified PCI device.
369
370 @param PciDevice Pci device instance.
371 @param RomBase Base address of Option Rom.
372
373 @retval EFI_OUT_OF_RESOURCES No enough memory to hold image.
374 @retval EFI_SUCESS Successfully loaded Option Rom.
375
376 **/
377 EFI_STATUS
378 LoadOpRomImage (
379 IN PCI_IO_DEVICE *PciDevice,
380 IN UINT64 RomBase
381 )
382 {
383 UINT8 RomBarIndex;
384 UINT8 Indicator;
385 UINT16 OffsetPcir;
386 UINT32 RomBarOffset;
387 UINT32 RomBar;
388 EFI_STATUS RetStatus;
389 BOOLEAN FirstCheck;
390 UINT8 *Image;
391 PCI_EXPANSION_ROM_HEADER *RomHeader;
392 PCI_DATA_STRUCTURE *RomPcir;
393 UINT64 RomSize;
394 UINT64 RomImageSize;
395 UINT32 LegacyImageLength;
396 UINT8 *RomInMemory;
397 UINT8 CodeType;
398
399 RomSize = PciDevice->RomSize;
400
401 Indicator = 0;
402 RomImageSize = 0;
403 RomInMemory = NULL;
404 CodeType = 0xFF;
405
406 //
407 // Get the RomBarIndex
408 //
409
410 //
411 // 0x30
412 //
413 RomBarIndex = PCI_EXPANSION_ROM_BASE;
414 if (IS_PCI_BRIDGE (&(PciDevice->Pci))) {
415 //
416 // if is ppb
417 //
418
419 //
420 // 0x38
421 //
422 RomBarIndex = PCI_BRIDGE_ROMBAR;
423 }
424
425 //
426 // Allocate memory for Rom header and PCIR
427 //
428 RomHeader = AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER));
429 if (RomHeader == NULL) {
430 return EFI_OUT_OF_RESOURCES;
431 }
432
433 RomPcir = AllocatePool (sizeof (PCI_DATA_STRUCTURE));
434 if (RomPcir == NULL) {
435 FreePool (RomHeader);
436 return EFI_OUT_OF_RESOURCES;
437 }
438
439 RomBar = (UINT32)RomBase;
440
441 //
442 // Enable RomBar
443 //
444 RomDecode (PciDevice, RomBarIndex, RomBar, TRUE);
445
446 RomBarOffset = RomBar;
447 RetStatus = EFI_NOT_FOUND;
448 FirstCheck = TRUE;
449 LegacyImageLength = 0;
450
451 do {
452 PciDevice->PciRootBridgeIo->Mem.Read (
453 PciDevice->PciRootBridgeIo,
454 EfiPciWidthUint8,
455 RomBarOffset,
456 sizeof (PCI_EXPANSION_ROM_HEADER),
457 (UINT8 *)RomHeader
458 );
459
460 if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
461 RomBarOffset = RomBarOffset + 512;
462 if (FirstCheck) {
463 break;
464 } else {
465 RomImageSize = RomImageSize + 512;
466 continue;
467 }
468 }
469
470 FirstCheck = FALSE;
471 OffsetPcir = RomHeader->PcirOffset;
472 //
473 // If the pointer to the PCI Data Structure is invalid, no further images can be located.
474 // The PCI Data Structure must be DWORD aligned.
475 //
476 if ((OffsetPcir == 0) ||
477 ((OffsetPcir & 3) != 0) ||
478 (RomImageSize + OffsetPcir + sizeof (PCI_DATA_STRUCTURE) > RomSize))
479 {
480 break;
481 }
482
483 PciDevice->PciRootBridgeIo->Mem.Read (
484 PciDevice->PciRootBridgeIo,
485 EfiPciWidthUint8,
486 RomBarOffset + OffsetPcir,
487 sizeof (PCI_DATA_STRUCTURE),
488 (UINT8 *)RomPcir
489 );
490 //
491 // If a valid signature is not present in the PCI Data Structure, no further images can be located.
492 //
493 if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
494 break;
495 }
496
497 if (RomImageSize + RomPcir->ImageLength * 512 > RomSize) {
498 break;
499 }
500
501 if (RomPcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
502 CodeType = PCI_CODE_TYPE_PCAT_IMAGE;
503 LegacyImageLength = ((UINT32)((EFI_LEGACY_EXPANSION_ROM_HEADER *)RomHeader)->Size512) * 512;
504 }
505
506 Indicator = RomPcir->Indicator;
507 RomImageSize = RomImageSize + RomPcir->ImageLength * 512;
508 RomBarOffset = RomBarOffset + RomPcir->ImageLength * 512;
509 } while (((Indicator & 0x80) == 0x00) && ((RomBarOffset - RomBar) < RomSize));
510
511 //
512 // Some Legacy Cards do not report the correct ImageLength so used the maximum
513 // of the legacy length and the PCIR Image Length
514 //
515 if (CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
516 RomImageSize = MAX (RomImageSize, LegacyImageLength);
517 }
518
519 if (RomImageSize > 0) {
520 RetStatus = EFI_SUCCESS;
521 Image = AllocatePool ((UINT32)RomImageSize);
522 if (Image == NULL) {
523 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
524 FreePool (RomHeader);
525 FreePool (RomPcir);
526 return EFI_OUT_OF_RESOURCES;
527 }
528
529 //
530 // Copy Rom image into memory
531 //
532 PciDevice->PciRootBridgeIo->Mem.Read (
533 PciDevice->PciRootBridgeIo,
534 EfiPciWidthUint32,
535 RomBar,
536 (UINT32)RomImageSize/sizeof (UINT32),
537 Image
538 );
539 RomInMemory = Image;
540 }
541
542 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
543
544 PciDevice->EmbeddedRom = TRUE;
545 PciDevice->PciIo.RomSize = RomImageSize;
546 PciDevice->PciIo.RomImage = RomInMemory;
547
548 //
549 // For OpROM read from PCI device:
550 // Add the Rom Image to internal database for later PCI light enumeration
551 //
552 PciRomAddImageMapping (
553 NULL,
554 PciDevice->PciRootBridgeIo->SegmentNumber,
555 PciDevice->BusNumber,
556 PciDevice->DeviceNumber,
557 PciDevice->FunctionNumber,
558 PciDevice->PciIo.RomImage,
559 PciDevice->PciIo.RomSize
560 );
561
562 //
563 // Free allocated memory
564 //
565 FreePool (RomHeader);
566 FreePool (RomPcir);
567
568 return RetStatus;
569 }
570
571 /**
572 Enable/Disable Option Rom decode.
573
574 @param PciDevice Pci device instance.
575 @param RomBarIndex The BAR index of the standard PCI Configuration header to use as the
576 base address for resource range. The legal range for this field is 0..5.
577 @param RomBar Base address of Option Rom.
578 @param Enable Flag for enable/disable decode.
579
580 **/
581 VOID
582 RomDecode (
583 IN PCI_IO_DEVICE *PciDevice,
584 IN UINT8 RomBarIndex,
585 IN UINT32 RomBar,
586 IN BOOLEAN Enable
587 )
588 {
589 UINT32 Value32;
590 EFI_PCI_IO_PROTOCOL *PciIo;
591
592 PciIo = &PciDevice->PciIo;
593 if (Enable) {
594 //
595 // set the Rom base address: now is hardcode
596 // enable its decoder
597 //
598 Value32 = RomBar | 0x1;
599 PciIo->Pci.Write (
600 PciIo,
601 (EFI_PCI_IO_PROTOCOL_WIDTH)EfiPciWidthUint32,
602 RomBarIndex,
603 1,
604 &Value32
605 );
606
607 //
608 // Programe all upstream bridge
609 //
610 ProgramUpstreamBridgeForRom (PciDevice, RomBar, TRUE);
611
612 //
613 // Setting the memory space bit in the function's command register
614 //
615 PCI_ENABLE_COMMAND_REGISTER (PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);
616 } else {
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 ProgramUpstreamBridgeForRom (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 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
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 // 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
763 FreePool (PciOptionRomImageDevicePath);
764
765 NextImage:
766 RomBarOffset += ImageSize;
767 } while (((Indicator & 0x80) == 0x00) && (((UINTN)RomBarOffset - (UINTN)RomBar) < PciDevice->RomSize));
768
769 return RetStatus;
770 }