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