]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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
1436aea4
MK
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
9060e3ec 37 )\r
38{\r
1436aea4
MK
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
50 UINT32 InitializationSize;\r
51\r
52 EfiOpRomImageNode = (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH *)FilePath;\r
9060e3ec 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
1436aea4
MK
61 )\r
62 {\r
9060e3ec 63 return EFI_INVALID_PARAMETER;\r
64 }\r
65\r
1436aea4
MK
66 EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *)(\r
67 (UINT8 *)PciIoDevice->PciIo.RomImage + EfiOpRomImageNode->StartingOffset\r
68 );\r
9060e3ec 69 if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
70 return EFI_NOT_FOUND;\r
71 }\r
72\r
1436aea4 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
1436aea4
MK
81 )\r
82 {\r
83 ImageSize = Pcir->ImageLength * 512;\r
84 InitializationSize = (UINT32)EfiRomHeader->InitializationSize * 512;\r
85 if ((InitializationSize > ImageSize) || (EfiRomHeader->EfiImageHeaderOffset >= InitializationSize)) {\r
94020bb4 86 return EFI_NOT_FOUND;\r
87 }\r
88\r
1436aea4
MK
89 ImageBuffer = (UINT8 *)EfiRomHeader + EfiRomHeader->EfiImageHeaderOffset;\r
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
1436aea4 96 if ((Buffer == NULL) || (*BufferSize < ImageLength)) {\r
9060e3ec 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
9060e3ec 104 } else {\r
105 //\r
106 // Compressed: Uncompress before copying\r
107 //\r
1436aea4 108 Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **)&Decompress);\r
9060e3ec 109 if (EFI_ERROR (Status)) {\r
110 return EFI_DEVICE_ERROR;\r
111 }\r
1436aea4 112\r
9060e3ec 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
1436aea4 124 if ((Buffer == NULL) || (*BufferSize < DestinationSize)) {\r
9060e3ec 125 *BufferSize = DestinationSize;\r
126 return EFI_BUFFER_TOO_SMALL;\r
127 }\r
128\r
129 *BufferSize = DestinationSize;\r
1436aea4 130 Scratch = AllocatePool (ScratchSize);\r
9060e3ec 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
1436aea4 149\r
9060e3ec 150 return EFI_SUCCESS;\r
151 }\r
152 }\r
153\r
154 return EFI_NOT_FOUND;\r
155}\r
156\r
157/**\r
158 Initialize a PCI LoadFile2 instance.\r
159\r
160 @param PciIoDevice PCI IO Device.\r
161\r
162**/\r
163VOID\r
164InitializePciLoadFile2 (\r
1436aea4 165 IN PCI_IO_DEVICE *PciIoDevice\r
9060e3ec 166 )\r
167{\r
168 PciIoDevice->LoadFile2.LoadFile = LoadFile2;\r
169}\r
170\r
171/**\r
172 Causes the driver to load a specified file.\r
173\r
174 @param This Indicates a pointer to the calling context.\r
175 @param FilePath The device specific path of the file to load.\r
176 @param BootPolicy Should always be FALSE.\r
177 @param BufferSize On input the size of Buffer in bytes. On output with a return\r
178 code of EFI_SUCCESS, the amount of data transferred to Buffer.\r
179 On output with a return code of EFI_BUFFER_TOO_SMALL,\r
180 the size of Buffer required to retrieve the requested file.\r
181 @param Buffer The memory buffer to transfer the file to. If Buffer is NULL,\r
182 then no the size of the requested file is returned in BufferSize.\r
183\r
184 @retval EFI_SUCCESS The file was loaded.\r
185 @retval EFI_UNSUPPORTED BootPolicy is TRUE.\r
186 @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or\r
187 BufferSize is NULL.\r
188 @retval EFI_NOT_FOUND Not found PCI Option Rom on PCI device.\r
189 @retval EFI_DEVICE_ERROR Failed to decompress PCI Option Rom image.\r
190 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.\r
191 BufferSize has been updated with the size needed to complete the request.\r
192\r
193**/\r
194EFI_STATUS\r
195EFIAPI\r
196LoadFile2 (\r
1436aea4
MK
197 IN EFI_LOAD_FILE2_PROTOCOL *This,\r
198 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
199 IN BOOLEAN BootPolicy,\r
200 IN OUT UINTN *BufferSize,\r
201 IN VOID *Buffer OPTIONAL\r
9060e3ec 202 )\r
203{\r
1436aea4 204 PCI_IO_DEVICE *PciIoDevice;\r
9060e3ec 205\r
206 if (BootPolicy) {\r
207 return EFI_UNSUPPORTED;\r
208 }\r
1436aea4 209\r
9060e3ec 210 PciIoDevice = PCI_IO_DEVICE_FROM_LOAD_FILE2_THIS (This);\r
211\r
212 return LocalLoadFile2 (\r
213 PciIoDevice,\r
214 FilePath,\r
215 BufferSize,\r
216 Buffer\r
217 );\r
218}\r
219\r
220/**\r
221 Get Pci device's oprom information.\r
222\r
223 @param PciIoDevice Input Pci device instance.\r
224 Output Pci device instance with updated OptionRom size.\r
225\r
226 @retval EFI_NOT_FOUND Pci device has not Option Rom.\r
227 @retval EFI_SUCCESS Pci device has Option Rom.\r
228\r
229**/\r
230EFI_STATUS\r
231GetOpRomInfo (\r
1436aea4 232 IN OUT PCI_IO_DEVICE *PciIoDevice\r
9060e3ec 233 )\r
234{\r
1436aea4
MK
235 UINT8 RomBarIndex;\r
236 UINT32 AllOnes;\r
237 UINT64 Address;\r
238 EFI_STATUS Status;\r
239 UINT8 Bus;\r
240 UINT8 Device;\r
241 UINT8 Function;\r
242 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
243\r
244 Bus = PciIoDevice->BusNumber;\r
245 Device = PciIoDevice->DeviceNumber;\r
246 Function = PciIoDevice->FunctionNumber;\r
9060e3ec 247\r
248 PciRootBridgeIo = PciIoDevice->PciRootBridgeIo;\r
249\r
250 //\r
251 // Offset is 0x30 if is not ppb\r
252 //\r
253\r
254 //\r
255 // 0x30\r
256 //\r
257 RomBarIndex = PCI_EXPANSION_ROM_BASE;\r
258\r
259 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
260 //\r
261 // If is ppb, 0x38\r
262 //\r
263 RomBarIndex = PCI_BRIDGE_ROMBAR;\r
264 }\r
1436aea4 265\r
9060e3ec 266 //\r
267 // The bit0 is 0 to prevent the enabling of the Rom address decoder\r
268 //\r
269 AllOnes = 0xfffffffe;\r
270 Address = EFI_PCI_ADDRESS (Bus, Device, Function, RomBarIndex);\r
271\r
272 Status = PciRootBridgeIo->Pci.Write (\r
273 PciRootBridgeIo,\r
274 EfiPciWidthUint32,\r
275 Address,\r
276 1,\r
277 &AllOnes\r
278 );\r
279 if (EFI_ERROR (Status)) {\r
280 return EFI_NOT_FOUND;\r
281 }\r
282\r
283 //\r
284 // Read back\r
285 //\r
1436aea4 286 Status = PciRootBridgeIo->Pci.Read (\r
9060e3ec 287 PciRootBridgeIo,\r
288 EfiPciWidthUint32,\r
289 Address,\r
290 1,\r
291 &AllOnes\r
292 );\r
293 if (EFI_ERROR (Status)) {\r
294 return EFI_NOT_FOUND;\r
295 }\r
296\r
297 //\r
298 // Bits [1, 10] are reserved\r
299 //\r
300 AllOnes &= 0xFFFFF800;\r
301 if ((AllOnes == 0) || (AllOnes == 0xFFFFF800)) {\r
302 return EFI_NOT_FOUND;\r
303 }\r
304\r
16f69227 305 PciIoDevice->RomSize = (~AllOnes) + 1;\r
9060e3ec 306 return EFI_SUCCESS;\r
307}\r
308\r
483d0d85
RN
309/**\r
310 Check if the RomImage contains EFI Images.\r
311\r
312 @param RomImage The ROM address of Image for check.\r
313 @param RomSize Size of ROM for check.\r
314\r
315 @retval TRUE ROM contain EFI Image.\r
316 @retval FALSE ROM not contain EFI Image.\r
317\r
318**/\r
319BOOLEAN\r
320ContainEfiImage (\r
1436aea4
MK
321 IN VOID *RomImage,\r
322 IN UINT64 RomSize\r
483d0d85
RN
323 )\r
324{\r
325 PCI_EXPANSION_ROM_HEADER *RomHeader;\r
326 PCI_DATA_STRUCTURE *RomPcir;\r
327 UINT8 Indicator;\r
328\r
329 Indicator = 0;\r
330 RomHeader = RomImage;\r
331 if (RomHeader == NULL) {\r
332 return FALSE;\r
333 }\r
334\r
335 do {\r
336 if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
1436aea4 337 RomHeader = (PCI_EXPANSION_ROM_HEADER *)((UINT8 *)RomHeader + 512);\r
483d0d85
RN
338 continue;\r
339 }\r
340\r
341 //\r
d1102dba 342 // The PCI Data Structure must be DWORD aligned.\r
483d0d85 343 //\r
1436aea4
MK
344 if ((RomHeader->PcirOffset == 0) ||\r
345 ((RomHeader->PcirOffset & 3) != 0) ||\r
346 ((UINT8 *)RomHeader + RomHeader->PcirOffset + sizeof (PCI_DATA_STRUCTURE) > (UINT8 *)RomImage + RomSize))\r
347 {\r
483d0d85
RN
348 break;\r
349 }\r
350\r
1436aea4 351 RomPcir = (PCI_DATA_STRUCTURE *)((UINT8 *)RomHeader + RomHeader->PcirOffset);\r
483d0d85
RN
352 if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {\r
353 break;\r
354 }\r
355\r
356 if (RomPcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) {\r
357 return TRUE;\r
358 }\r
359\r
360 Indicator = RomPcir->Indicator;\r
1436aea4
MK
361 RomHeader = (PCI_EXPANSION_ROM_HEADER *)((UINT8 *)RomHeader + RomPcir->ImageLength * 512);\r
362 } while (((UINT8 *)RomHeader < (UINT8 *)RomImage + RomSize) && ((Indicator & 0x80) == 0x00));\r
483d0d85
RN
363\r
364 return FALSE;\r
365}\r
366\r
9060e3ec 367/**\r
368 Load Option Rom image for specified PCI device.\r
369\r
370 @param PciDevice Pci device instance.\r
371 @param RomBase Base address of Option Rom.\r
372\r
373 @retval EFI_OUT_OF_RESOURCES No enough memory to hold image.\r
374 @retval EFI_SUCESS Successfully loaded Option Rom.\r
375\r
376**/\r
377EFI_STATUS\r
378LoadOpRomImage (\r
1436aea4
MK
379 IN PCI_IO_DEVICE *PciDevice,\r
380 IN UINT64 RomBase\r
9060e3ec 381 )\r
382{\r
383 UINT8 RomBarIndex;\r
384 UINT8 Indicator;\r
385 UINT16 OffsetPcir;\r
386 UINT32 RomBarOffset;\r
387 UINT32 RomBar;\r
388 EFI_STATUS RetStatus;\r
389 BOOLEAN FirstCheck;\r
390 UINT8 *Image;\r
391 PCI_EXPANSION_ROM_HEADER *RomHeader;\r
392 PCI_DATA_STRUCTURE *RomPcir;\r
393 UINT64 RomSize;\r
394 UINT64 RomImageSize;\r
94020bb4 395 UINT32 LegacyImageLength;\r
9060e3ec 396 UINT8 *RomInMemory;\r
397 UINT8 CodeType;\r
398\r
1436aea4 399 RomSize = PciDevice->RomSize;\r
9060e3ec 400\r
1436aea4
MK
401 Indicator = 0;\r
402 RomImageSize = 0;\r
403 RomInMemory = NULL;\r
404 CodeType = 0xFF;\r
9060e3ec 405\r
406 //\r
407 // Get the RomBarIndex\r
408 //\r
409\r
410 //\r
411 // 0x30\r
412 //\r
413 RomBarIndex = PCI_EXPANSION_ROM_BASE;\r
414 if (IS_PCI_BRIDGE (&(PciDevice->Pci))) {\r
415 //\r
416 // if is ppb\r
417 //\r
418\r
419 //\r
420 // 0x38\r
421 //\r
422 RomBarIndex = PCI_BRIDGE_ROMBAR;\r
423 }\r
1436aea4 424\r
9060e3ec 425 //\r
426 // Allocate memory for Rom header and PCIR\r
427 //\r
428 RomHeader = AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER));\r
429 if (RomHeader == NULL) {\r
430 return EFI_OUT_OF_RESOURCES;\r
431 }\r
432\r
433 RomPcir = AllocatePool (sizeof (PCI_DATA_STRUCTURE));\r
434 if (RomPcir == NULL) {\r
435 FreePool (RomHeader);\r
436 return EFI_OUT_OF_RESOURCES;\r
437 }\r
438\r
1436aea4 439 RomBar = (UINT32)RomBase;\r
9060e3ec 440\r
441 //\r
442 // Enable RomBar\r
443 //\r
444 RomDecode (PciDevice, RomBarIndex, RomBar, TRUE);\r
445\r
1436aea4
MK
446 RomBarOffset = RomBar;\r
447 RetStatus = EFI_NOT_FOUND;\r
448 FirstCheck = TRUE;\r
94020bb4 449 LegacyImageLength = 0;\r
9060e3ec 450\r
451 do {\r
452 PciDevice->PciRootBridgeIo->Mem.Read (\r
453 PciDevice->PciRootBridgeIo,\r
454 EfiPciWidthUint8,\r
455 RomBarOffset,\r
456 sizeof (PCI_EXPANSION_ROM_HEADER),\r
1436aea4 457 (UINT8 *)RomHeader\r
9060e3ec 458 );\r
459\r
460 if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
461 RomBarOffset = RomBarOffset + 512;\r
462 if (FirstCheck) {\r
463 break;\r
464 } else {\r
465 RomImageSize = RomImageSize + 512;\r
466 continue;\r
467 }\r
468 }\r
469\r
1436aea4
MK
470 FirstCheck = FALSE;\r
471 OffsetPcir = RomHeader->PcirOffset;\r
94020bb4 472 //\r
d1102dba
LG
473 // If the pointer to the PCI Data Structure is invalid, no further images can be located.\r
474 // The PCI Data Structure must be DWORD aligned.\r
94020bb4 475 //\r
1436aea4
MK
476 if ((OffsetPcir == 0) ||\r
477 ((OffsetPcir & 3) != 0) ||\r
478 (RomImageSize + OffsetPcir + sizeof (PCI_DATA_STRUCTURE) > RomSize))\r
479 {\r
94020bb4 480 break;\r
481 }\r
1436aea4 482\r
9060e3ec 483 PciDevice->PciRootBridgeIo->Mem.Read (\r
484 PciDevice->PciRootBridgeIo,\r
485 EfiPciWidthUint8,\r
486 RomBarOffset + OffsetPcir,\r
487 sizeof (PCI_DATA_STRUCTURE),\r
1436aea4 488 (UINT8 *)RomPcir\r
9060e3ec 489 );\r
94020bb4 490 //\r
491 // If a valid signature is not present in the PCI Data Structure, no further images can be located.\r
492 //\r
493 if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {\r
494 break;\r
495 }\r
1436aea4 496\r
94020bb4 497 if (RomImageSize + RomPcir->ImageLength * 512 > RomSize) {\r
498 break;\r
499 }\r
1436aea4 500\r
9060e3ec 501 if (RomPcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {\r
1436aea4 502 CodeType = PCI_CODE_TYPE_PCAT_IMAGE;\r
94020bb4 503 LegacyImageLength = ((UINT32)((EFI_LEGACY_EXPANSION_ROM_HEADER *)RomHeader)->Size512) * 512;\r
9060e3ec 504 }\r
1436aea4
MK
505\r
506 Indicator = RomPcir->Indicator;\r
507 RomImageSize = RomImageSize + RomPcir->ImageLength * 512;\r
508 RomBarOffset = RomBarOffset + RomPcir->ImageLength * 512;\r
9060e3ec 509 } while (((Indicator & 0x80) == 0x00) && ((RomBarOffset - RomBar) < RomSize));\r
510\r
511 //\r
512 // Some Legacy Cards do not report the correct ImageLength so used the maximum\r
513 // of the legacy length and the PCIR Image Length\r
514 //\r
515 if (CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {\r
94020bb4 516 RomImageSize = MAX (RomImageSize, LegacyImageLength);\r
9060e3ec 517 }\r
518\r
519 if (RomImageSize > 0) {\r
520 RetStatus = EFI_SUCCESS;\r
1436aea4 521 Image = AllocatePool ((UINT32)RomImageSize);\r
9060e3ec 522 if (Image == NULL) {\r
523 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);\r
524 FreePool (RomHeader);\r
525 FreePool (RomPcir);\r
526 return EFI_OUT_OF_RESOURCES;\r
527 }\r
528\r
529 //\r
530 // Copy Rom image into memory\r
531 //\r
532 PciDevice->PciRootBridgeIo->Mem.Read (\r
533 PciDevice->PciRootBridgeIo,\r
cdf75447 534 EfiPciWidthUint32,\r
9060e3ec 535 RomBar,\r
1436aea4 536 (UINT32)RomImageSize/sizeof (UINT32),\r
9060e3ec 537 Image\r
538 );\r
539 RomInMemory = Image;\r
540 }\r
541\r
542 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);\r
543\r
4ed4e19c 544 PciDevice->EmbeddedRom = TRUE;\r
9060e3ec 545 PciDevice->PciIo.RomSize = RomImageSize;\r
546 PciDevice->PciIo.RomImage = RomInMemory;\r
547\r
548 //\r
549 // For OpROM read from PCI device:\r
550 // Add the Rom Image to internal database for later PCI light enumeration\r
551 //\r
552 PciRomAddImageMapping (\r
553 NULL,\r
554 PciDevice->PciRootBridgeIo->SegmentNumber,\r
555 PciDevice->BusNumber,\r
556 PciDevice->DeviceNumber,\r
557 PciDevice->FunctionNumber,\r
221c8fd5 558 PciDevice->PciIo.RomImage,\r
9060e3ec 559 PciDevice->PciIo.RomSize\r
560 );\r
561\r
562 //\r
563 // Free allocated memory\r
564 //\r
565 FreePool (RomHeader);\r
566 FreePool (RomPcir);\r
567\r
568 return RetStatus;\r
569}\r
570\r
571/**\r
572 Enable/Disable Option Rom decode.\r
573\r
574 @param PciDevice Pci device instance.\r
575 @param RomBarIndex The BAR index of the standard PCI Configuration header to use as the\r
576 base address for resource range. The legal range for this field is 0..5.\r
577 @param RomBar Base address of Option Rom.\r
578 @param Enable Flag for enable/disable decode.\r
579\r
580**/\r
581VOID\r
582RomDecode (\r
1436aea4
MK
583 IN PCI_IO_DEVICE *PciDevice,\r
584 IN UINT8 RomBarIndex,\r
585 IN UINT32 RomBar,\r
586 IN BOOLEAN Enable\r
9060e3ec 587 )\r
588{\r
1436aea4
MK
589 UINT32 Value32;\r
590 EFI_PCI_IO_PROTOCOL *PciIo;\r
9060e3ec 591\r
592 PciIo = &PciDevice->PciIo;\r
593 if (Enable) {\r
9060e3ec 594 //\r
595 // set the Rom base address: now is hardcode\r
596 // enable its decoder\r
597 //\r
598 Value32 = RomBar | 0x1;\r
599 PciIo->Pci.Write (\r
600 PciIo,\r
1436aea4 601 (EFI_PCI_IO_PROTOCOL_WIDTH)EfiPciWidthUint32,\r
9060e3ec 602 RomBarIndex,\r
603 1,\r
604 &Value32\r
605 );\r
606\r
607 //\r
608 // Programe all upstream bridge\r
609 //\r
fcdfcdbf 610 ProgramUpstreamBridgeForRom (PciDevice, RomBar, TRUE);\r
9060e3ec 611\r
612 //\r
613 // Setting the memory space bit in the function's command register\r
614 //\r
1436aea4 615 PCI_ENABLE_COMMAND_REGISTER (PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);\r
9060e3ec 616 } else {\r
9060e3ec 617 //\r
618 // disable command register decode to memory\r
619 //\r
1436aea4 620 PCI_DISABLE_COMMAND_REGISTER (PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);\r
9060e3ec 621\r
622 //\r
623 // Destroy the programmed bar in all the upstream bridge.\r
624 //\r
fcdfcdbf 625 ProgramUpstreamBridgeForRom (PciDevice, RomBar, FALSE);\r
9060e3ec 626\r
627 //\r
628 // disable rom decode\r
629 //\r
630 Value32 = 0xFFFFFFFE;\r
631 PciIo->Pci.Write (\r
632 PciIo,\r
1436aea4 633 (EFI_PCI_IO_PROTOCOL_WIDTH)EfiPciWidthUint32,\r
9060e3ec 634 RomBarIndex,\r
635 1,\r
636 &Value32\r
637 );\r
9060e3ec 638 }\r
639}\r
640\r
641/**\r
642 Load and start the Option Rom image.\r
643\r
644 @param PciDevice Pci device instance.\r
645\r
646 @retval EFI_SUCCESS Successfully loaded and started PCI Option Rom image.\r
647 @retval EFI_NOT_FOUND Failed to process PCI Option Rom image.\r
648\r
649**/\r
650EFI_STATUS\r
651ProcessOpRomImage (\r
1436aea4 652 IN PCI_IO_DEVICE *PciDevice\r
9060e3ec 653 )\r
654{\r
655 UINT8 Indicator;\r
656 UINT32 ImageSize;\r
657 VOID *RomBar;\r
658 UINT8 *RomBarOffset;\r
659 EFI_HANDLE ImageHandle;\r
660 EFI_STATUS Status;\r
661 EFI_STATUS RetStatus;\r
9060e3ec 662 EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader;\r
663 PCI_DATA_STRUCTURE *Pcir;\r
664 EFI_DEVICE_PATH_PROTOCOL *PciOptionRomImageDevicePath;\r
665 MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH EfiOpRomImageNode;\r
666 VOID *Buffer;\r
667 UINTN BufferSize;\r
668\r
669 Indicator = 0;\r
670\r
671 //\r
672 // Get the Address of the Option Rom image\r
673 //\r
1436aea4
MK
674 RomBar = PciDevice->PciIo.RomImage;\r
675 RomBarOffset = (UINT8 *)RomBar;\r
676 RetStatus = EFI_NOT_FOUND;\r
94020bb4 677\r
678 if (RomBar == NULL) {\r
679 return RetStatus;\r
680 }\r
1436aea4
MK
681\r
682 ASSERT (((EFI_PCI_EXPANSION_ROM_HEADER *)RomBarOffset)->Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE);\r
9060e3ec 683\r
684 do {\r
1436aea4 685 EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *)RomBarOffset;\r
9060e3ec 686 if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
687 RomBarOffset += 512;\r
94020bb4 688 continue;\r
9060e3ec 689 }\r
690\r
1436aea4 691 Pcir = (PCI_DATA_STRUCTURE *)(RomBarOffset + EfiRomHeader->PcirOffset);\r
94020bb4 692 ASSERT (Pcir->Signature == PCI_DATA_STRUCTURE_SIGNATURE);\r
1436aea4
MK
693 ImageSize = (UINT32)(Pcir->ImageLength * 512);\r
694 Indicator = Pcir->Indicator;\r
9060e3ec 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
a93e23f9 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
1436aea4
MK
713 EfiOpRomImageNode.Header.Type = MEDIA_DEVICE_PATH;\r
714 EfiOpRomImageNode.Header.SubType = MEDIA_RELATIVE_OFFSET_RANGE_DP;\r
9060e3ec 715 SetDevicePathNodeLength (&EfiOpRomImageNode.Header, sizeof (EfiOpRomImageNode));\r
1436aea4
MK
716 EfiOpRomImageNode.StartingOffset = (UINTN)RomBarOffset - (UINTN)RomBar;\r
717 EfiOpRomImageNode.EndingOffset = (UINTN)RomBarOffset + ImageSize - 1 - (UINTN)RomBar;\r
9060e3ec 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
1436aea4 762\r
b5cbef4e 763 FreePool (PciOptionRomImageDevicePath);\r
9060e3ec 764\r
a93e23f9 765NextImage:\r
9060e3ec 766 RomBarOffset += ImageSize;\r
1436aea4 767 } while (((Indicator & 0x80) == 0x00) && (((UINTN)RomBarOffset - (UINTN)RomBar) < PciDevice->RomSize));\r
9060e3ec 768\r
769 return RetStatus;\r
770}\r