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