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