]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.c
MdeModulePkg/PciBus: Refine EFI_PCI_ROM_IMAGE_MAPPING
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciBusDxe / PciOptionRomSupport.c
CommitLineData
9060e3ec 1/** @file\r
2 PCI Rom supporting funtions implementation for PCI Bus module.\r
3\r
809e2bbf 4Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>\r
cd5ebaa0 5This program and the accompanying materials\r
9060e3ec 6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "PciBus.h"\r
16\r
17/**\r
18 Load the EFI Image from Option ROM\r
19\r
20 @param PciIoDevice PCI IO device instance.\r
21 @param FilePath The file path of the EFI Image\r
22 @param BufferSize On input the size of Buffer in bytes. On output with a return\r
23 code of EFI_SUCCESS, the amount of data transferred to Buffer.\r
24 On output with a return code of EFI_BUFFER_TOO_SMALL,\r
25 the size of Buffer required to retrieve the requested file.\r
26 @param Buffer The memory buffer to transfer the file to. If Buffer is NULL,\r
27 then no the size of the requested file is returned in BufferSize.\r
28\r
29 @retval EFI_SUCCESS The file was loaded.\r
30 @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or\r
31 BufferSize is NULL.\r
32 @retval EFI_NOT_FOUND Not found PCI Option Rom on PCI device.\r
33 @retval EFI_DEVICE_ERROR Failed to decompress PCI Option Rom image.\r
34 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.\r
35 BufferSize has been updated with the size needed to complete the request.\r
36**/\r
37EFI_STATUS\r
38LocalLoadFile2 (\r
39 IN PCI_IO_DEVICE *PciIoDevice,\r
40 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
41 IN OUT UINTN *BufferSize,\r
42 IN VOID *Buffer OPTIONAL\r
43 )\r
44{\r
45 EFI_STATUS Status;\r
46 MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH *EfiOpRomImageNode;\r
47 EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader;\r
48 PCI_DATA_STRUCTURE *Pcir;\r
49 UINT32 ImageSize;\r
50 UINT8 *ImageBuffer;\r
51 UINT32 ImageLength;\r
52 UINT32 DestinationSize;\r
53 UINT32 ScratchSize;\r
54 VOID *Scratch;\r
55 EFI_DECOMPRESS_PROTOCOL *Decompress;\r
94020bb4 56 UINT32 InitializationSize;\r
9060e3ec 57\r
58 EfiOpRomImageNode = (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH *) FilePath;\r
59 if ((EfiOpRomImageNode == NULL) ||\r
60 (DevicePathType (FilePath) != MEDIA_DEVICE_PATH) ||\r
61 (DevicePathSubType (FilePath) != MEDIA_RELATIVE_OFFSET_RANGE_DP) ||\r
62 (DevicePathNodeLength (FilePath) != sizeof (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH)) ||\r
63 (!IsDevicePathEnd (NextDevicePathNode (FilePath))) ||\r
64 (EfiOpRomImageNode->StartingOffset > EfiOpRomImageNode->EndingOffset) ||\r
65 (EfiOpRomImageNode->EndingOffset >= PciIoDevice->RomSize) ||\r
66 (BufferSize == NULL)\r
67 ) {\r
68 return EFI_INVALID_PARAMETER;\r
69 }\r
70\r
71 EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) (\r
72 (UINT8 *) PciIoDevice->PciIo.RomImage + EfiOpRomImageNode->StartingOffset\r
73 );\r
74 if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
75 return EFI_NOT_FOUND;\r
76 }\r
77\r
78\r
79 Pcir = (PCI_DATA_STRUCTURE *) ((UINT8 *) EfiRomHeader + EfiRomHeader->PcirOffset);\r
94020bb4 80 ASSERT (Pcir->Signature == PCI_DATA_STRUCTURE_SIGNATURE);\r
9060e3ec 81\r
82 if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) &&\r
83 (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) &&\r
84 ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||\r
85 (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)) &&\r
86 (EfiRomHeader->CompressionType <= EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED)\r
87 ) {\r
88\r
94020bb4 89 ImageSize = Pcir->ImageLength * 512;\r
90 InitializationSize = (UINT32) EfiRomHeader->InitializationSize * 512;\r
91 if (InitializationSize > ImageSize || EfiRomHeader->EfiImageHeaderOffset >= InitializationSize) {\r
92 return EFI_NOT_FOUND;\r
93 }\r
94\r
9060e3ec 95 ImageBuffer = (UINT8 *) EfiRomHeader + EfiRomHeader->EfiImageHeaderOffset;\r
94020bb4 96 ImageLength = InitializationSize - EfiRomHeader->EfiImageHeaderOffset;\r
9060e3ec 97\r
98 if (EfiRomHeader->CompressionType != EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {\r
99 //\r
100 // Uncompressed: Copy the EFI Image directly to user's buffer\r
101 //\r
102 if (Buffer == NULL || *BufferSize < ImageLength) {\r
103 *BufferSize = ImageLength;\r
104 return EFI_BUFFER_TOO_SMALL;\r
105 }\r
106\r
107 *BufferSize = ImageLength;\r
108 CopyMem (Buffer, ImageBuffer, ImageLength);\r
109 return EFI_SUCCESS;\r
110\r
111 } else {\r
112 //\r
113 // Compressed: Uncompress before copying\r
114 //\r
115 Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress);\r
116 if (EFI_ERROR (Status)) {\r
117 return EFI_DEVICE_ERROR;\r
118 }\r
119 Status = Decompress->GetInfo (\r
120 Decompress,\r
121 ImageBuffer,\r
122 ImageLength,\r
123 &DestinationSize,\r
124 &ScratchSize\r
125 );\r
126 if (EFI_ERROR (Status)) {\r
127 return EFI_DEVICE_ERROR;\r
128 }\r
129\r
130 if (Buffer == NULL || *BufferSize < DestinationSize) {\r
131 *BufferSize = DestinationSize;\r
132 return EFI_BUFFER_TOO_SMALL;\r
133 }\r
134\r
135 *BufferSize = DestinationSize;\r
136 Scratch = AllocatePool (ScratchSize);\r
137 if (Scratch == NULL) {\r
138 return EFI_DEVICE_ERROR;\r
139 }\r
140\r
141 Status = Decompress->Decompress (\r
142 Decompress,\r
143 ImageBuffer,\r
144 ImageLength,\r
145 Buffer,\r
146 DestinationSize,\r
147 Scratch,\r
148 ScratchSize\r
149 );\r
150 FreePool (Scratch);\r
151\r
152 if (EFI_ERROR (Status)) {\r
153 return EFI_DEVICE_ERROR;\r
154 }\r
155 return EFI_SUCCESS;\r
156 }\r
157 }\r
158\r
159 return EFI_NOT_FOUND;\r
160}\r
161\r
162/**\r
163 Initialize a PCI LoadFile2 instance.\r
164\r
165 @param PciIoDevice PCI IO Device.\r
166\r
167**/\r
168VOID\r
169InitializePciLoadFile2 (\r
170 IN PCI_IO_DEVICE *PciIoDevice\r
171 )\r
172{\r
173 PciIoDevice->LoadFile2.LoadFile = LoadFile2;\r
174}\r
175\r
176/**\r
177 Causes the driver to load a specified file.\r
178\r
179 @param This Indicates a pointer to the calling context.\r
180 @param FilePath The device specific path of the file to load.\r
181 @param BootPolicy Should always be FALSE.\r
182 @param BufferSize On input the size of Buffer in bytes. On output with a return\r
183 code of EFI_SUCCESS, the amount of data transferred to Buffer.\r
184 On output with a return code of EFI_BUFFER_TOO_SMALL,\r
185 the size of Buffer required to retrieve the requested file.\r
186 @param Buffer The memory buffer to transfer the file to. If Buffer is NULL,\r
187 then no the size of the requested file is returned in BufferSize.\r
188\r
189 @retval EFI_SUCCESS The file was loaded.\r
190 @retval EFI_UNSUPPORTED BootPolicy is TRUE.\r
191 @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or\r
192 BufferSize is NULL.\r
193 @retval EFI_NOT_FOUND Not found PCI Option Rom on PCI device.\r
194 @retval EFI_DEVICE_ERROR Failed to decompress PCI Option Rom image.\r
195 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.\r
196 BufferSize has been updated with the size needed to complete the request.\r
197\r
198**/\r
199EFI_STATUS\r
200EFIAPI\r
201LoadFile2 (\r
202 IN EFI_LOAD_FILE2_PROTOCOL *This,\r
203 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
204 IN BOOLEAN BootPolicy,\r
205 IN OUT UINTN *BufferSize,\r
206 IN VOID *Buffer OPTIONAL\r
207 )\r
208{\r
209 PCI_IO_DEVICE *PciIoDevice;\r
210\r
211 if (BootPolicy) {\r
212 return EFI_UNSUPPORTED;\r
213 }\r
214 PciIoDevice = PCI_IO_DEVICE_FROM_LOAD_FILE2_THIS (This);\r
215\r
216 return LocalLoadFile2 (\r
217 PciIoDevice,\r
218 FilePath,\r
219 BufferSize,\r
220 Buffer\r
221 );\r
222}\r
223\r
224/**\r
225 Get Pci device's oprom information.\r
226\r
227 @param PciIoDevice Input Pci device instance.\r
228 Output Pci device instance with updated OptionRom size.\r
229\r
230 @retval EFI_NOT_FOUND Pci device has not Option Rom.\r
231 @retval EFI_SUCCESS Pci device has Option Rom.\r
232\r
233**/\r
234EFI_STATUS\r
235GetOpRomInfo (\r
236 IN OUT PCI_IO_DEVICE *PciIoDevice\r
237 )\r
238{\r
239 UINT8 RomBarIndex;\r
240 UINT32 AllOnes;\r
241 UINT64 Address;\r
242 EFI_STATUS Status;\r
243 UINT8 Bus;\r
244 UINT8 Device;\r
245 UINT8 Function;\r
246 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
247\r
248 Bus = PciIoDevice->BusNumber;\r
249 Device = PciIoDevice->DeviceNumber;\r
250 Function = PciIoDevice->FunctionNumber;\r
251\r
252 PciRootBridgeIo = PciIoDevice->PciRootBridgeIo;\r
253\r
254 //\r
255 // Offset is 0x30 if is not ppb\r
256 //\r
257\r
258 //\r
259 // 0x30\r
260 //\r
261 RomBarIndex = PCI_EXPANSION_ROM_BASE;\r
262\r
263 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
264 //\r
265 // If is ppb, 0x38\r
266 //\r
267 RomBarIndex = PCI_BRIDGE_ROMBAR;\r
268 }\r
269 //\r
270 // The bit0 is 0 to prevent the enabling of the Rom address decoder\r
271 //\r
272 AllOnes = 0xfffffffe;\r
273 Address = EFI_PCI_ADDRESS (Bus, Device, Function, RomBarIndex);\r
274\r
275 Status = PciRootBridgeIo->Pci.Write (\r
276 PciRootBridgeIo,\r
277 EfiPciWidthUint32,\r
278 Address,\r
279 1,\r
280 &AllOnes\r
281 );\r
282 if (EFI_ERROR (Status)) {\r
283 return EFI_NOT_FOUND;\r
284 }\r
285\r
286 //\r
287 // Read back\r
288 //\r
289 Status = PciRootBridgeIo->Pci.Read(\r
290 PciRootBridgeIo,\r
291 EfiPciWidthUint32,\r
292 Address,\r
293 1,\r
294 &AllOnes\r
295 );\r
296 if (EFI_ERROR (Status)) {\r
297 return EFI_NOT_FOUND;\r
298 }\r
299\r
300 //\r
301 // Bits [1, 10] are reserved\r
302 //\r
303 AllOnes &= 0xFFFFF800;\r
304 if ((AllOnes == 0) || (AllOnes == 0xFFFFF800)) {\r
305 return EFI_NOT_FOUND;\r
306 }\r
307\r
16f69227 308 PciIoDevice->RomSize = (~AllOnes) + 1;\r
9060e3ec 309 return EFI_SUCCESS;\r
310}\r
311\r
483d0d85
RN
312/**\r
313 Check if the RomImage contains EFI Images.\r
314\r
315 @param RomImage The ROM address of Image for check.\r
316 @param RomSize Size of ROM for check.\r
317\r
318 @retval TRUE ROM contain EFI Image.\r
319 @retval FALSE ROM not contain EFI Image.\r
320\r
321**/\r
322BOOLEAN\r
323ContainEfiImage (\r
324 IN VOID *RomImage,\r
325 IN UINT64 RomSize\r
326 )\r
327{\r
328 PCI_EXPANSION_ROM_HEADER *RomHeader;\r
329 PCI_DATA_STRUCTURE *RomPcir;\r
330 UINT8 Indicator;\r
331\r
332 Indicator = 0;\r
333 RomHeader = RomImage;\r
334 if (RomHeader == NULL) {\r
335 return FALSE;\r
336 }\r
337\r
338 do {\r
339 if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
340 RomHeader = (PCI_EXPANSION_ROM_HEADER *) ((UINT8 *) RomHeader + 512);\r
341 continue;\r
342 }\r
343\r
344 //\r
345 // The PCI Data Structure must be DWORD aligned. \r
346 //\r
347 if (RomHeader->PcirOffset == 0 ||\r
348 (RomHeader->PcirOffset & 3) != 0 ||\r
349 (UINT8 *) RomHeader + RomHeader->PcirOffset + sizeof (PCI_DATA_STRUCTURE) > (UINT8 *) RomImage + RomSize) {\r
350 break;\r
351 }\r
352\r
353 RomPcir = (PCI_DATA_STRUCTURE *) ((UINT8 *) RomHeader + RomHeader->PcirOffset);\r
354 if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {\r
355 break;\r
356 }\r
357\r
358 if (RomPcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) {\r
359 return TRUE;\r
360 }\r
361\r
362 Indicator = RomPcir->Indicator;\r
363 RomHeader = (PCI_EXPANSION_ROM_HEADER *) ((UINT8 *) RomHeader + RomPcir->ImageLength * 512);\r
364 } while (((UINT8 *) RomHeader < (UINT8 *) RomImage + RomSize) && ((Indicator & 0x80) == 0x00));\r
365\r
366 return FALSE;\r
367}\r
368\r
9060e3ec 369/**\r
370 Load Option Rom image for specified PCI device.\r
371\r
372 @param PciDevice Pci device instance.\r
373 @param RomBase Base address of Option Rom.\r
374\r
375 @retval EFI_OUT_OF_RESOURCES No enough memory to hold image.\r
376 @retval EFI_SUCESS Successfully loaded Option Rom.\r
377\r
378**/\r
379EFI_STATUS\r
380LoadOpRomImage (\r
381 IN PCI_IO_DEVICE *PciDevice,\r
382 IN UINT64 RomBase\r
383 )\r
384{\r
385 UINT8 RomBarIndex;\r
386 UINT8 Indicator;\r
387 UINT16 OffsetPcir;\r
388 UINT32 RomBarOffset;\r
389 UINT32 RomBar;\r
390 EFI_STATUS RetStatus;\r
391 BOOLEAN FirstCheck;\r
392 UINT8 *Image;\r
393 PCI_EXPANSION_ROM_HEADER *RomHeader;\r
394 PCI_DATA_STRUCTURE *RomPcir;\r
395 UINT64 RomSize;\r
396 UINT64 RomImageSize;\r
94020bb4 397 UINT32 LegacyImageLength;\r
9060e3ec 398 UINT8 *RomInMemory;\r
399 UINT8 CodeType;\r
400\r
401 RomSize = PciDevice->RomSize;\r
402\r
403 Indicator = 0;\r
404 RomImageSize = 0;\r
405 RomInMemory = NULL;\r
406 CodeType = 0xFF;\r
407\r
408 //\r
409 // Get the RomBarIndex\r
410 //\r
411\r
412 //\r
413 // 0x30\r
414 //\r
415 RomBarIndex = PCI_EXPANSION_ROM_BASE;\r
416 if (IS_PCI_BRIDGE (&(PciDevice->Pci))) {\r
417 //\r
418 // if is ppb\r
419 //\r
420\r
421 //\r
422 // 0x38\r
423 //\r
424 RomBarIndex = PCI_BRIDGE_ROMBAR;\r
425 }\r
426 //\r
427 // Allocate memory for Rom header and PCIR\r
428 //\r
429 RomHeader = AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER));\r
430 if (RomHeader == NULL) {\r
431 return EFI_OUT_OF_RESOURCES;\r
432 }\r
433\r
434 RomPcir = AllocatePool (sizeof (PCI_DATA_STRUCTURE));\r
435 if (RomPcir == NULL) {\r
436 FreePool (RomHeader);\r
437 return EFI_OUT_OF_RESOURCES;\r
438 }\r
439\r
440 RomBar = (UINT32) RomBase;\r
441\r
442 //\r
443 // Enable RomBar\r
444 //\r
445 RomDecode (PciDevice, RomBarIndex, RomBar, TRUE);\r
446\r
447 RomBarOffset = RomBar;\r
448 RetStatus = EFI_NOT_FOUND;\r
449 FirstCheck = TRUE;\r
94020bb4 450 LegacyImageLength = 0;\r
9060e3ec 451\r
452 do {\r
453 PciDevice->PciRootBridgeIo->Mem.Read (\r
454 PciDevice->PciRootBridgeIo,\r
455 EfiPciWidthUint8,\r
456 RomBarOffset,\r
457 sizeof (PCI_EXPANSION_ROM_HEADER),\r
458 (UINT8 *) RomHeader\r
459 );\r
460\r
461 if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
462 RomBarOffset = RomBarOffset + 512;\r
463 if (FirstCheck) {\r
464 break;\r
465 } else {\r
466 RomImageSize = RomImageSize + 512;\r
467 continue;\r
468 }\r
469 }\r
470\r
471 FirstCheck = FALSE;\r
472 OffsetPcir = RomHeader->PcirOffset;\r
94020bb4 473 //\r
474 // If the pointer to the PCI Data Structure is invalid, no further images can be located. \r
475 // The PCI Data Structure must be DWORD aligned. \r
476 //\r
477 if (OffsetPcir == 0 ||\r
478 (OffsetPcir & 3) != 0 ||\r
479 RomImageSize + OffsetPcir + sizeof (PCI_DATA_STRUCTURE) > RomSize) {\r
480 break;\r
481 }\r
9060e3ec 482 PciDevice->PciRootBridgeIo->Mem.Read (\r
483 PciDevice->PciRootBridgeIo,\r
484 EfiPciWidthUint8,\r
485 RomBarOffset + OffsetPcir,\r
486 sizeof (PCI_DATA_STRUCTURE),\r
487 (UINT8 *) RomPcir\r
488 );\r
94020bb4 489 //\r
490 // If a valid signature is not present in the PCI Data Structure, no further images can be located.\r
491 //\r
492 if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {\r
493 break;\r
494 }\r
495 if (RomImageSize + RomPcir->ImageLength * 512 > RomSize) {\r
496 break;\r
497 }\r
9060e3ec 498 if (RomPcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {\r
499 CodeType = PCI_CODE_TYPE_PCAT_IMAGE;\r
94020bb4 500 LegacyImageLength = ((UINT32)((EFI_LEGACY_EXPANSION_ROM_HEADER *)RomHeader)->Size512) * 512;\r
9060e3ec 501 }\r
502 Indicator = RomPcir->Indicator;\r
503 RomImageSize = RomImageSize + RomPcir->ImageLength * 512;\r
504 RomBarOffset = RomBarOffset + RomPcir->ImageLength * 512;\r
505 } while (((Indicator & 0x80) == 0x00) && ((RomBarOffset - RomBar) < RomSize));\r
506\r
507 //\r
508 // Some Legacy Cards do not report the correct ImageLength so used the maximum\r
509 // of the legacy length and the PCIR Image Length\r
510 //\r
511 if (CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {\r
94020bb4 512 RomImageSize = MAX (RomImageSize, LegacyImageLength);\r
9060e3ec 513 }\r
514\r
515 if (RomImageSize > 0) {\r
516 RetStatus = EFI_SUCCESS;\r
517 Image = AllocatePool ((UINT32) RomImageSize);\r
518 if (Image == NULL) {\r
519 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);\r
520 FreePool (RomHeader);\r
521 FreePool (RomPcir);\r
522 return EFI_OUT_OF_RESOURCES;\r
523 }\r
524\r
525 //\r
526 // Copy Rom image into memory\r
527 //\r
528 PciDevice->PciRootBridgeIo->Mem.Read (\r
529 PciDevice->PciRootBridgeIo,\r
530 EfiPciWidthUint8,\r
531 RomBar,\r
532 (UINT32) RomImageSize,\r
533 Image\r
534 );\r
535 RomInMemory = Image;\r
536 }\r
537\r
538 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);\r
539\r
4ed4e19c 540 PciDevice->EmbeddedRom = TRUE;\r
9060e3ec 541 PciDevice->PciIo.RomSize = RomImageSize;\r
542 PciDevice->PciIo.RomImage = RomInMemory;\r
543\r
544 //\r
545 // For OpROM read from PCI device:\r
546 // Add the Rom Image to internal database for later PCI light enumeration\r
547 //\r
548 PciRomAddImageMapping (\r
549 NULL,\r
550 PciDevice->PciRootBridgeIo->SegmentNumber,\r
551 PciDevice->BusNumber,\r
552 PciDevice->DeviceNumber,\r
553 PciDevice->FunctionNumber,\r
221c8fd5 554 PciDevice->PciIo.RomImage,\r
9060e3ec 555 PciDevice->PciIo.RomSize\r
556 );\r
557\r
558 //\r
559 // Free allocated memory\r
560 //\r
561 FreePool (RomHeader);\r
562 FreePool (RomPcir);\r
563\r
564 return RetStatus;\r
565}\r
566\r
567/**\r
568 Enable/Disable Option Rom decode.\r
569\r
570 @param PciDevice Pci device instance.\r
571 @param RomBarIndex The BAR index of the standard PCI Configuration header to use as the\r
572 base address for resource range. The legal range for this field is 0..5.\r
573 @param RomBar Base address of Option Rom.\r
574 @param Enable Flag for enable/disable decode.\r
575\r
576**/\r
577VOID\r
578RomDecode (\r
579 IN PCI_IO_DEVICE *PciDevice,\r
580 IN UINT8 RomBarIndex,\r
581 IN UINT32 RomBar,\r
582 IN BOOLEAN Enable\r
583 )\r
584{\r
585 UINT32 Value32;\r
586 UINT32 Offset;\r
6989af71 587 UINT32 OffsetMax;\r
9060e3ec 588 EFI_PCI_IO_PROTOCOL *PciIo;\r
589\r
590 PciIo = &PciDevice->PciIo;\r
591 if (Enable) {\r
592 //\r
593 // Clear all bars\r
594 //\r
6989af71
RN
595 OffsetMax = 0x24;\r
596 if (IS_PCI_BRIDGE(&PciDevice->Pci)) {\r
597 OffsetMax = 0x14;\r
598 }\r
599\r
600 for (Offset = 0x10; Offset <= OffsetMax; Offset += sizeof (UINT32)) {\r
9060e3ec 601 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllZero);\r
602 }\r
603\r
604 //\r
605 // set the Rom base address: now is hardcode\r
606 // enable its decoder\r
607 //\r
608 Value32 = RomBar | 0x1;\r
609 PciIo->Pci.Write (\r
610 PciIo,\r
611 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,\r
612 RomBarIndex,\r
613 1,\r
614 &Value32\r
615 );\r
616\r
617 //\r
618 // Programe all upstream bridge\r
619 //\r
620 ProgrameUpstreamBridgeForRom(PciDevice, RomBar, TRUE);\r
621\r
622 //\r
623 // Setting the memory space bit in the function's command register\r
624 //\r
625 PCI_ENABLE_COMMAND_REGISTER(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);\r
626\r
627 } else {\r
628\r
629 //\r
630 // disable command register decode to memory\r
631 //\r
632 PCI_DISABLE_COMMAND_REGISTER(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);\r
633\r
634 //\r
635 // Destroy the programmed bar in all the upstream bridge.\r
636 //\r
637 ProgrameUpstreamBridgeForRom(PciDevice, RomBar, FALSE);\r
638\r
639 //\r
640 // disable rom decode\r
641 //\r
642 Value32 = 0xFFFFFFFE;\r
643 PciIo->Pci.Write (\r
644 PciIo,\r
645 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,\r
646 RomBarIndex,\r
647 1,\r
648 &Value32\r
649 );\r
650\r
651 }\r
652}\r
653\r
654/**\r
655 Load and start the Option Rom image.\r
656\r
657 @param PciDevice Pci device instance.\r
658\r
659 @retval EFI_SUCCESS Successfully loaded and started PCI Option Rom image.\r
660 @retval EFI_NOT_FOUND Failed to process PCI Option Rom image.\r
661\r
662**/\r
663EFI_STATUS\r
664ProcessOpRomImage (\r
665 IN PCI_IO_DEVICE *PciDevice\r
666 )\r
667{\r
668 UINT8 Indicator;\r
669 UINT32 ImageSize;\r
670 VOID *RomBar;\r
671 UINT8 *RomBarOffset;\r
672 EFI_HANDLE ImageHandle;\r
673 EFI_STATUS Status;\r
674 EFI_STATUS RetStatus;\r
9060e3ec 675 EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader;\r
676 PCI_DATA_STRUCTURE *Pcir;\r
677 EFI_DEVICE_PATH_PROTOCOL *PciOptionRomImageDevicePath;\r
678 MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH EfiOpRomImageNode;\r
679 VOID *Buffer;\r
680 UINTN BufferSize;\r
681\r
682 Indicator = 0;\r
683\r
684 //\r
685 // Get the Address of the Option Rom image\r
686 //\r
687 RomBar = PciDevice->PciIo.RomImage;\r
688 RomBarOffset = (UINT8 *) RomBar;\r
689 RetStatus = EFI_NOT_FOUND;\r
94020bb4 690\r
691 if (RomBar == NULL) {\r
692 return RetStatus;\r
693 }\r
694 ASSERT (((EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset)->Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE);\r
9060e3ec 695\r
696 do {\r
697 EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset;\r
698 if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
699 RomBarOffset += 512;\r
94020bb4 700 continue;\r
9060e3ec 701 }\r
702\r
9060e3ec 703 Pcir = (PCI_DATA_STRUCTURE *) (RomBarOffset + EfiRomHeader->PcirOffset);\r
94020bb4 704 ASSERT (Pcir->Signature == PCI_DATA_STRUCTURE_SIGNATURE);\r
9060e3ec 705 ImageSize = (UINT32) (Pcir->ImageLength * 512);\r
706 Indicator = Pcir->Indicator;\r
707\r
a93e23f9 708 //\r
709 // Skip the image if it is not an EFI PCI Option ROM image\r
710 //\r
711 if (Pcir->CodeType != PCI_CODE_TYPE_EFI_IMAGE) {\r
712 goto NextImage;\r
713 }\r
714\r
715 //\r
716 // Skip the EFI PCI Option ROM image if its machine type is not supported\r
717 //\r
718 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (EfiRomHeader->EfiMachineType)) {\r
719 goto NextImage;\r
720 }\r
721\r
722 //\r
723 // Ignore the EFI PCI Option ROM image if it is an EFI application\r
724 //\r
725 if (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {\r
726 goto NextImage;\r
727 }\r
728\r
9060e3ec 729 //\r
730 // Create Pci Option Rom Image device path header\r
731 //\r
732 EfiOpRomImageNode.Header.Type = MEDIA_DEVICE_PATH;\r
733 EfiOpRomImageNode.Header.SubType = MEDIA_RELATIVE_OFFSET_RANGE_DP;\r
734 SetDevicePathNodeLength (&EfiOpRomImageNode.Header, sizeof (EfiOpRomImageNode));\r
735 EfiOpRomImageNode.StartingOffset = (UINTN) RomBarOffset - (UINTN) RomBar;\r
736 EfiOpRomImageNode.EndingOffset = (UINTN) RomBarOffset + ImageSize - 1 - (UINTN) RomBar;\r
737\r
738 PciOptionRomImageDevicePath = AppendDevicePathNode (PciDevice->DevicePath, &EfiOpRomImageNode.Header);\r
739 ASSERT (PciOptionRomImageDevicePath != NULL);\r
740\r
741 //\r
742 // load image and start image\r
743 //\r
744 BufferSize = 0;\r
745 Buffer = NULL;\r
9060e3ec 746 ImageHandle = NULL;\r
747\r
a93e23f9 748 Status = gBS->LoadImage (\r
749 FALSE,\r
750 gPciBusDriverBinding.DriverBindingHandle,\r
751 PciOptionRomImageDevicePath,\r
752 Buffer,\r
753 BufferSize,\r
754 &ImageHandle\r
755 );\r
9060e3ec 756\r
757 FreePool (PciOptionRomImageDevicePath);\r
758\r
759 if (!EFI_ERROR (Status)) {\r
760 Status = gBS->StartImage (ImageHandle, NULL, NULL);\r
761 if (!EFI_ERROR (Status)) {\r
762 AddDriver (PciDevice, ImageHandle);\r
763 PciRomAddImageMapping (\r
764 ImageHandle,\r
765 PciDevice->PciRootBridgeIo->SegmentNumber,\r
766 PciDevice->BusNumber,\r
767 PciDevice->DeviceNumber,\r
768 PciDevice->FunctionNumber,\r
221c8fd5 769 PciDevice->PciIo.RomImage,\r
9060e3ec 770 PciDevice->PciIo.RomSize\r
771 );\r
772 RetStatus = EFI_SUCCESS;\r
773 }\r
774 }\r
775\r
a93e23f9 776NextImage:\r
9060e3ec 777 RomBarOffset += ImageSize;\r
778\r
809e2bbf 779 } while (((Indicator & 0x80) == 0x00) && (((UINTN) RomBarOffset - (UINTN) RomBar) < PciDevice->RomSize));\r
9060e3ec 780\r
781 return RetStatus;\r
782}\r
783\r