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