]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.c
Retired PciIncompatibleDeviceSupportLib from IntelFrameworkModulePkg.
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Pci / PciBusDxe / PciOptionRomSupport.c
1 /** @file
2 PCI Rom supporting funtions implementation for PCI Bus module.
3
4 Copyright (c) 2006 - 2009, Intel Corporation
5 All rights reserved. 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->PciIo.RomSize = RomImageSize;
504 PciDevice->PciIo.RomImage = RomInMemory;
505
506 //
507 // For OpROM read from PCI device:
508 // Add the Rom Image to internal database for later PCI light enumeration
509 //
510 PciRomAddImageMapping (
511 NULL,
512 PciDevice->PciRootBridgeIo->SegmentNumber,
513 PciDevice->BusNumber,
514 PciDevice->DeviceNumber,
515 PciDevice->FunctionNumber,
516 (UINT64) (UINTN) PciDevice->PciIo.RomImage,
517 PciDevice->PciIo.RomSize
518 );
519
520 //
521 // Free allocated memory
522 //
523 FreePool (RomHeader);
524 FreePool (RomPcir);
525
526 return RetStatus;
527 }
528
529 /**
530 Enable/Disable Option Rom decode.
531
532 @param PciDevice Pci device instance.
533 @param RomBarIndex The BAR index of the standard PCI Configuration header to use as the
534 base address for resource range. The legal range for this field is 0..5.
535 @param RomBar Base address of Option Rom.
536 @param Enable Flag for enable/disable decode.
537
538 **/
539 VOID
540 RomDecode (
541 IN PCI_IO_DEVICE *PciDevice,
542 IN UINT8 RomBarIndex,
543 IN UINT32 RomBar,
544 IN BOOLEAN Enable
545 )
546 {
547 UINT32 Value32;
548 UINT32 Offset;
549 EFI_PCI_IO_PROTOCOL *PciIo;
550
551 PciIo = &PciDevice->PciIo;
552 if (Enable) {
553 //
554 // Clear all bars
555 //
556 for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {
557 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllZero);
558 }
559
560 //
561 // set the Rom base address: now is hardcode
562 // enable its decoder
563 //
564 Value32 = RomBar | 0x1;
565 PciIo->Pci.Write (
566 PciIo,
567 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,
568 RomBarIndex,
569 1,
570 &Value32
571 );
572
573 //
574 // Programe all upstream bridge
575 //
576 ProgrameUpstreamBridgeForRom(PciDevice, RomBar, TRUE);
577
578 //
579 // Setting the memory space bit in the function's command register
580 //
581 PCI_ENABLE_COMMAND_REGISTER(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);
582
583 } else {
584
585 //
586 // disable command register decode to memory
587 //
588 PCI_DISABLE_COMMAND_REGISTER(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);
589
590 //
591 // Destroy the programmed bar in all the upstream bridge.
592 //
593 ProgrameUpstreamBridgeForRom(PciDevice, RomBar, FALSE);
594
595 //
596 // disable rom decode
597 //
598 Value32 = 0xFFFFFFFE;
599 PciIo->Pci.Write (
600 PciIo,
601 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,
602 RomBarIndex,
603 1,
604 &Value32
605 );
606
607 }
608 }
609
610 /**
611 Load and start the Option Rom image.
612
613 @param PciDevice Pci device instance.
614
615 @retval EFI_SUCCESS Successfully loaded and started PCI Option Rom image.
616 @retval EFI_NOT_FOUND Failed to process PCI Option Rom image.
617
618 **/
619 EFI_STATUS
620 ProcessOpRomImage (
621 IN PCI_IO_DEVICE *PciDevice
622 )
623 {
624 UINT8 Indicator;
625 UINT32 ImageSize;
626 VOID *RomBar;
627 UINT8 *RomBarOffset;
628 EFI_HANDLE ImageHandle;
629 EFI_STATUS Status;
630 EFI_STATUS RetStatus;
631 BOOLEAN FirstCheck;
632 EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader;
633 PCI_DATA_STRUCTURE *Pcir;
634 EFI_DEVICE_PATH_PROTOCOL *PciOptionRomImageDevicePath;
635 MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH EfiOpRomImageNode;
636 VOID *Buffer;
637 UINTN BufferSize;
638
639 Indicator = 0;
640
641 //
642 // Get the Address of the Option Rom image
643 //
644 RomBar = PciDevice->PciIo.RomImage;
645 RomBarOffset = (UINT8 *) RomBar;
646 RetStatus = EFI_NOT_FOUND;
647 FirstCheck = TRUE;
648
649 do {
650 EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset;
651 if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
652 RomBarOffset += 512;
653 if (FirstCheck) {
654 break;
655 } else {
656 continue;
657 }
658 }
659
660 FirstCheck = FALSE;
661 Pcir = (PCI_DATA_STRUCTURE *) (RomBarOffset + EfiRomHeader->PcirOffset);
662 ImageSize = (UINT32) (Pcir->ImageLength * 512);
663 Indicator = Pcir->Indicator;
664
665 //
666 // Create Pci Option Rom Image device path header
667 //
668 EfiOpRomImageNode.Header.Type = MEDIA_DEVICE_PATH;
669 EfiOpRomImageNode.Header.SubType = MEDIA_RELATIVE_OFFSET_RANGE_DP;
670 SetDevicePathNodeLength (&EfiOpRomImageNode.Header, sizeof (EfiOpRomImageNode));
671 EfiOpRomImageNode.StartingOffset = (UINTN) RomBarOffset - (UINTN) RomBar;
672 EfiOpRomImageNode.EndingOffset = (UINTN) RomBarOffset + ImageSize - 1 - (UINTN) RomBar;
673
674 PciOptionRomImageDevicePath = AppendDevicePathNode (PciDevice->DevicePath, &EfiOpRomImageNode.Header);
675 ASSERT (PciOptionRomImageDevicePath != NULL);
676
677 //
678 // load image and start image
679 //
680 BufferSize = 0;
681 Buffer = NULL;
682 Status = EFI_SUCCESS;
683 ImageHandle = NULL;
684
685 if (!EFI_ERROR (Status)) {
686 Status = gBS->LoadImage (
687 FALSE,
688 gPciBusDriverBinding.DriverBindingHandle,
689 PciOptionRomImageDevicePath,
690 Buffer,
691 BufferSize,
692 &ImageHandle
693 );
694 }
695
696 //
697 // load image and start image
698 //
699 if (!EFI_ERROR (Status)) {
700 Status = gBS->LoadImage (
701 FALSE,
702 gPciBusDriverBinding.DriverBindingHandle,
703 PciOptionRomImageDevicePath,
704 Buffer,
705 BufferSize,
706 &ImageHandle
707 );
708 }
709
710 FreePool (PciOptionRomImageDevicePath);
711
712 if (!EFI_ERROR (Status)) {
713 Status = gBS->StartImage (ImageHandle, NULL, NULL);
714 if (!EFI_ERROR (Status)) {
715 AddDriver (PciDevice, ImageHandle);
716 PciRomAddImageMapping (
717 ImageHandle,
718 PciDevice->PciRootBridgeIo->SegmentNumber,
719 PciDevice->BusNumber,
720 PciDevice->DeviceNumber,
721 PciDevice->FunctionNumber,
722 (UINT64) (UINTN) PciDevice->PciIo.RomImage,
723 PciDevice->PciIo.RomSize
724 );
725 RetStatus = EFI_SUCCESS;
726 }
727 }
728
729 RomBarOffset += ImageSize;
730
731 } while (((Indicator & 0x80) == 0x00) && ((UINTN) (RomBarOffset - (UINT8 *) RomBar) < PciDevice->RomSize));
732
733 return RetStatus;
734 }
735