]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.c
Using EFI_RESOUCE status defined in framework Pci Host bridge specification.
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Pci / PciBusDxe / PciOptionRomSupport.c
CommitLineData
eeefcb9d 1/** @file\r
3db51098 2\r
05975035 3Copyright (c) 2006 - 2008, Intel Corporation\r
cfe9de52 4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
3db51098 11\r
12**/\r
ead42efc 13\r
03417d8d 14#include "PciBus.h"\r
ead42efc 15#include "PciResourceSupport.h"\r
16\r
b1ef4015 17#include <IndustryStandard/Pci23.h>\r
ead42efc 18\r
2d9d2abf 19//\r
20// Module global for a template of the PCI option ROM Image Device Path Node\r
21//\r
22MEMMAP_DEVICE_PATH mPciOptionRomImageDevicePathNodeTemplate = {\r
cfe9de52 23 {\r
2d9d2abf 24 HARDWARE_DEVICE_PATH,\r
25 HW_MEMMAP_DP,\r
05975035 26 {\r
27 (UINT8) (sizeof (MEMMAP_DEVICE_PATH)),\r
28 (UINT8) ((sizeof (MEMMAP_DEVICE_PATH)) >> 8)\r
29 }\r
2d9d2abf 30 },\r
31 EfiMemoryMappedIO,\r
32 0,\r
33 0\r
34};\r
35\r
57076f45 36/**\r
37 Get Pci device's oprom infor bits.\r
38 \r
eeefcb9d 39 @param PciIoDevice Pci device instance\r
40\r
57076f45 41 @retval EFI_NOT_FOUND Pci device has not oprom\r
42 @retval EFI_SUCCESS Pci device has oprom\r
43**/\r
ead42efc 44EFI_STATUS\r
45GetOpRomInfo (\r
46 IN PCI_IO_DEVICE *PciIoDevice\r
47 )\r
ead42efc 48{\r
49 UINT8 RomBarIndex;\r
50 UINT32 AllOnes;\r
51 UINT64 Address;\r
52 EFI_STATUS Status;\r
53 UINT8 Bus;\r
54 UINT8 Device;\r
55 UINT8 Function;\r
56 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
57\r
58 Bus = PciIoDevice->BusNumber;\r
59 Device = PciIoDevice->DeviceNumber;\r
60 Function = PciIoDevice->FunctionNumber;\r
61\r
62 PciRootBridgeIo = PciIoDevice->PciRootBridgeIo;\r
63\r
64 //\r
65 // offset is 0x30 if is not ppb\r
66 //\r
67\r
68 //\r
69 // 0x30\r
70 //\r
bc14bdb3 71 RomBarIndex = PCI_EXPANSION_ROM_BASE;\r
ead42efc 72\r
73 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
74 //\r
75 // if is ppb\r
76 //\r
77\r
78 //\r
79 // 0x38\r
80 //\r
81 RomBarIndex = PCI_BRIDGE_ROMBAR;\r
82 }\r
83 //\r
84 // the bit0 is 0 to prevent the enabling of the Rom address decoder\r
85 //\r
86 AllOnes = 0xfffffffe;\r
87 Address = EFI_PCI_ADDRESS (Bus, Device, Function, RomBarIndex);\r
88\r
89 Status = PciRootBridgeIoWrite (\r
90 PciRootBridgeIo,\r
91 &PciIoDevice->Pci,\r
92 EfiPciWidthUint32,\r
93 Address,\r
94 1,\r
95 &AllOnes\r
96 );\r
97 if (EFI_ERROR (Status)) {\r
98 return Status;\r
99 }\r
100\r
101 //\r
102 // read back\r
103 //\r
104 Status = PciRootBridgeIoRead (\r
105 PciRootBridgeIo,\r
106 &PciIoDevice->Pci,\r
107 EfiPciWidthUint32,\r
108 Address,\r
109 1,\r
110 &AllOnes\r
111 );\r
112 if (EFI_ERROR (Status)) {\r
113 return Status;\r
114 }\r
115 //\r
116 // Bits [1, 10] are reserved\r
117 //\r
118 AllOnes &= 0xFFFFF800;\r
119 if ((AllOnes == 0) || (AllOnes == 0xFFFFF800)) {\r
120 return EFI_NOT_FOUND;\r
121 }\r
122\r
123 PciIoDevice->RomSize = (UINT64) ((~AllOnes) + 1);\r
124 return EFI_SUCCESS;\r
125}\r
126\r
57076f45 127/**\r
128 Load option rom image for specified PCI device\r
129 \r
130 @param PciDevice Pci device instance\r
131 @param RomBase Base address of oprom.\r
132 \r
133 @retval EFI_OUT_OF_RESOURCES not enough memory to hold image\r
134 @retval EFI_SUCESS Success\r
135**/\r
ead42efc 136EFI_STATUS\r
137LoadOpRomImage (\r
138 IN PCI_IO_DEVICE *PciDevice,\r
139 IN UINT64 RomBase\r
140 )\r
ead42efc 141{\r
142 UINT8 RomBarIndex;\r
143 UINT8 Indicator;\r
144 UINT16 OffsetPcir;\r
145 UINT32 RomBarOffset;\r
146 UINT32 RomBar;\r
5326528b 147 EFI_STATUS RetStatus;\r
ead42efc 148 BOOLEAN FirstCheck;\r
149 UINT8 *Image;\r
150 PCI_EXPANSION_ROM_HEADER *RomHeader;\r
151 PCI_DATA_STRUCTURE *RomPcir;\r
152 UINT64 RomSize;\r
153 UINT64 RomImageSize;\r
154 UINT8 *RomInMemory;\r
155 UINT8 CodeType;\r
156\r
157 RomSize = PciDevice->RomSize;\r
158\r
159 Indicator = 0;\r
160 RomImageSize = 0;\r
161 RomInMemory = NULL;\r
162 CodeType = 0xFF;\r
163\r
164 //\r
165 // Get the RomBarIndex\r
166 //\r
167\r
168 //\r
169 // 0x30\r
170 //\r
bc14bdb3 171 RomBarIndex = PCI_EXPANSION_ROM_BASE;\r
ead42efc 172 if (IS_PCI_BRIDGE (&(PciDevice->Pci))) {\r
173 //\r
174 // if is ppb\r
175 //\r
176\r
177 //\r
178 // 0x38\r
179 //\r
180 RomBarIndex = PCI_BRIDGE_ROMBAR;\r
181 }\r
182 //\r
183 // Allocate memory for Rom header and PCIR\r
184 //\r
185 RomHeader = AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER));\r
186 if (RomHeader == NULL) {\r
187 return EFI_OUT_OF_RESOURCES;\r
188 }\r
189\r
190 RomPcir = AllocatePool (sizeof (PCI_DATA_STRUCTURE));\r
191 if (RomPcir == NULL) {\r
192 gBS->FreePool (RomHeader);\r
193 return EFI_OUT_OF_RESOURCES;\r
194 }\r
195\r
196 RomBar = (UINT32) RomBase;\r
197\r
198 //\r
199 // Enable RomBar\r
200 //\r
201 RomDecode (PciDevice, RomBarIndex, RomBar, TRUE);\r
202\r
203 RomBarOffset = RomBar;\r
5326528b 204 RetStatus = EFI_NOT_FOUND;\r
ead42efc 205 FirstCheck = TRUE;\r
206\r
207 do {\r
208 PciDevice->PciRootBridgeIo->Mem.Read (\r
209 PciDevice->PciRootBridgeIo,\r
210 EfiPciWidthUint8,\r
211 RomBarOffset,\r
212 sizeof (PCI_EXPANSION_ROM_HEADER),\r
213 (UINT8 *) RomHeader\r
214 );\r
215\r
216 if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
217 RomBarOffset = RomBarOffset + 512;\r
218 if (FirstCheck) {\r
219 break;\r
220 } else {\r
221 RomImageSize = RomImageSize + 512;\r
222 continue;\r
223 }\r
224 }\r
225\r
226 FirstCheck = FALSE;\r
227 OffsetPcir = RomHeader->PcirOffset;\r
228 PciDevice->PciRootBridgeIo->Mem.Read (\r
229 PciDevice->PciRootBridgeIo,\r
230 EfiPciWidthUint8,\r
231 RomBarOffset + OffsetPcir,\r
232 sizeof (PCI_DATA_STRUCTURE),\r
233 (UINT8 *) RomPcir\r
234 );\r
235 if (RomPcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {\r
236 CodeType = PCI_CODE_TYPE_PCAT_IMAGE;\r
237 }\r
238 Indicator = RomPcir->Indicator;\r
239 RomImageSize = RomImageSize + RomPcir->ImageLength * 512;\r
240 RomBarOffset = RomBarOffset + RomPcir->ImageLength * 512;\r
241 } while (((Indicator & 0x80) == 0x00) && ((RomBarOffset - RomBar) < RomSize));\r
242\r
243 //\r
244 // Some Legacy Cards do not report the correct ImageLength so used the maximum\r
245 // of the legacy length and the PCIR Image Length\r
246 //\r
247 if (CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {\r
a1e3528b 248 RomImageSize = MAX(RomImageSize, (((EFI_LEGACY_EXPANSION_ROM_HEADER *)RomHeader)->Size512 * 512));\r
ead42efc 249 }\r
250\r
251 if (RomImageSize > 0) {\r
5326528b 252 RetStatus = EFI_SUCCESS;\r
ead42efc 253 Image = AllocatePool ((UINT32) RomImageSize);\r
254 if (Image == NULL) {\r
255 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);\r
256 gBS->FreePool (RomHeader);\r
257 gBS->FreePool (RomPcir);\r
258 return EFI_OUT_OF_RESOURCES;\r
259 }\r
cfe9de52 260\r
ead42efc 261 //\r
262 // Copy Rom image into memory\r
263 //\r
264 PciDevice->PciRootBridgeIo->Mem.Read (\r
265 PciDevice->PciRootBridgeIo,\r
266 EfiPciWidthUint8,\r
267 RomBar,\r
268 (UINT32) RomImageSize,\r
269 Image\r
270 );\r
271 RomInMemory = Image;\r
272 }\r
273\r
274 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);\r
275\r
276 PciDevice->PciIo.RomSize = RomImageSize;\r
277 PciDevice->PciIo.RomImage = RomInMemory;\r
278\r
96d1b172 279 //\r
280 // For OpROM read from PCI device:\r
281 // Add the Rom Image to internal database for later PCI light enumeration\r
282 //\r
ead42efc 283 PciRomAddImageMapping (\r
284 NULL,\r
285 PciDevice->PciRootBridgeIo->SegmentNumber,\r
286 PciDevice->BusNumber,\r
287 PciDevice->DeviceNumber,\r
288 PciDevice->FunctionNumber,\r
289 (UINT64) (UINTN) PciDevice->PciIo.RomImage,\r
290 PciDevice->PciIo.RomSize\r
291 );\r
292\r
293 //\r
294 // Free allocated memory\r
295 //\r
296 gBS->FreePool (RomHeader);\r
297 gBS->FreePool (RomPcir);\r
298\r
5326528b 299 return RetStatus;\r
ead42efc 300}\r
301\r
57076f45 302/**\r
303 enable/disable oprom decode\r
304 \r
305 @param PciDevice pci device instance\r
306 @param RomBarIndex The BAR index of the standard PCI Configuration header to use as the\r
307 base address for resource range. The legal range for this field is 0..5.\r
308 @param RomBar Base address of rom\r
309 @param Enable Flag for enable/disable decode.\r
310 \r
311 @retval EFI_SUCCESS Success\r
312**/\r
ead42efc 313EFI_STATUS\r
314RomDecode (\r
315 IN PCI_IO_DEVICE *PciDevice,\r
316 IN UINT8 RomBarIndex,\r
317 IN UINT32 RomBar,\r
318 IN BOOLEAN Enable\r
319 )\r
ead42efc 320{\r
321 UINT32 Value32;\r
322 UINT32 Offset;\r
323 EFI_PCI_IO_PROTOCOL *PciIo;\r
324\r
325 PciIo = &PciDevice->PciIo;\r
326 if (Enable) {\r
327 //\r
328 // Clear all bars\r
329 //\r
330 for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {\r
331 PciIoWrite (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllZero);\r
332 }\r
cfe9de52 333\r
ead42efc 334 //\r
335 // set the Rom base address: now is hardcode\r
336 // enable its decoder\r
337 //\r
338 Value32 = RomBar | 0x1;\r
339 PciIoWrite (\r
340 PciIo,\r
341 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,\r
342 RomBarIndex,\r
343 1,\r
344 &Value32\r
345 );\r
346\r
347 //\r
348 // Programe all upstream bridge\r
349 //\r
350 ProgrameUpstreamBridgeForRom(PciDevice, RomBar, TRUE);\r
351\r
352 //\r
353 // Setting the memory space bit in the function's command register\r
354 //\r
355 PciEnableCommandRegister(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);\r
356\r
357 } else {\r
cfe9de52 358\r
ead42efc 359 //\r
360 // disable command register decode to memory\r
361 //\r
362 PciDisableCommandRegister(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);\r
363\r
364 //\r
365 // Destroy the programmed bar in all the upstream bridge.\r
366 //\r
367 ProgrameUpstreamBridgeForRom(PciDevice, RomBar, FALSE);\r
368\r
369 //\r
370 // disable rom decode\r
371 //\r
372 Value32 = 0xFFFFFFFE;\r
373 PciIoWrite (\r
374 PciIo,\r
375 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,\r
376 RomBarIndex,\r
377 1,\r
378 &Value32\r
379 );\r
380\r
381 }\r
382\r
383 return EFI_SUCCESS;\r
384\r
385}\r
386\r
57076f45 387/**\r
388 Process the oprom image.\r
389 \r
390 @param PciDevice Pci device instance\r
391**/\r
ead42efc 392EFI_STATUS\r
393ProcessOpRomImage (\r
394 PCI_IO_DEVICE *PciDevice\r
395 )\r
ead42efc 396{\r
397 UINT8 Indicator;\r
398 UINT32 ImageSize;\r
399 UINT16 ImageOffset;\r
400 VOID *RomBar;\r
401 UINT8 *RomBarOffset;\r
402 EFI_HANDLE ImageHandle;\r
403 EFI_STATUS Status;\r
5326528b 404 EFI_STATUS RetStatus;\r
ead42efc 405 BOOLEAN FirstCheck;\r
406 BOOLEAN SkipImage;\r
407 UINT32 DestinationSize;\r
408 UINT32 ScratchSize;\r
409 UINT8 *Scratch;\r
410 VOID *ImageBuffer;\r
411 VOID *DecompressedImageBuffer;\r
412 UINT32 ImageLength;\r
413 EFI_DECOMPRESS_PROTOCOL *Decompress;\r
414 EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader;\r
415 PCI_DATA_STRUCTURE *Pcir;\r
2d9d2abf 416 EFI_DEVICE_PATH_PROTOCOL *PciOptionRomImageDevicePath;\r
ead42efc 417\r
418 Indicator = 0;\r
419\r
420 //\r
421 // Get the Address of the Rom image\r
422 //\r
423 RomBar = PciDevice->PciIo.RomImage;\r
424 RomBarOffset = (UINT8 *) RomBar;\r
5326528b 425 RetStatus = EFI_NOT_FOUND;\r
ead42efc 426 FirstCheck = TRUE;\r
427\r
428 do {\r
429 EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset;\r
430 if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
431 RomBarOffset = RomBarOffset + 512;\r
432 if (FirstCheck) {\r
433 break;\r
434 } else {\r
435 continue;\r
436 }\r
437 }\r
438\r
439 FirstCheck = FALSE;\r
440 Pcir = (PCI_DATA_STRUCTURE *) (RomBarOffset + EfiRomHeader->PcirOffset);\r
441 ImageSize = (UINT32) (Pcir->ImageLength * 512);\r
442 Indicator = Pcir->Indicator;\r
443\r
cfe9de52 444 if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) &&\r
ead42efc 445 (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE)) {\r
446\r
447 if ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||\r
448 (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)) {\r
449\r
450 ImageOffset = EfiRomHeader->EfiImageHeaderOffset;\r
451 ImageSize = (UINT32) (EfiRomHeader->InitializationSize * 512);\r
452\r
453 ImageBuffer = (VOID *) (RomBarOffset + ImageOffset);\r
454 ImageLength = ImageSize - (UINT32)ImageOffset;\r
455 DecompressedImageBuffer = NULL;\r
456\r
457 //\r
458 // decompress here if needed\r
459 //\r
460 SkipImage = FALSE;\r
461 if (EfiRomHeader->CompressionType > EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {\r
462 SkipImage = TRUE;\r
463 }\r
464\r
465 if (EfiRomHeader->CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {\r
466 Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress);\r
467 if (EFI_ERROR (Status)) {\r
468 SkipImage = TRUE;\r
469 } else {\r
470 SkipImage = TRUE;\r
471 Status = Decompress->GetInfo (\r
472 Decompress,\r
473 ImageBuffer,\r
474 ImageLength,\r
475 &DestinationSize,\r
476 &ScratchSize\r
477 );\r
478 if (!EFI_ERROR (Status)) {\r
479 DecompressedImageBuffer = NULL;\r
480 DecompressedImageBuffer = AllocatePool (DestinationSize);\r
481 if (DecompressedImageBuffer != NULL) {\r
482 Scratch = AllocatePool (ScratchSize);\r
483 if (Scratch != NULL) {\r
484 Status = Decompress->Decompress (\r
485 Decompress,\r
486 ImageBuffer,\r
487 ImageLength,\r
488 DecompressedImageBuffer,\r
489 DestinationSize,\r
490 Scratch,\r
491 ScratchSize\r
492 );\r
493 if (!EFI_ERROR (Status)) {\r
494 ImageBuffer = DecompressedImageBuffer;\r
495 ImageLength = DestinationSize;\r
496 SkipImage = FALSE;\r
497 }\r
498\r
499 gBS->FreePool (Scratch);\r
500 }\r
501 }\r
502 }\r
503 }\r
504 }\r
505\r
506 if (!SkipImage) {\r
2d9d2abf 507 //\r
cfe9de52 508 // Build Memory Mapped device path node to record the image offset into the PCI Option ROM\r
509 //\r
510 mPciOptionRomImageDevicePathNodeTemplate.StartingAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) (RomBarOffset - (UINT8 *) RomBar);\r
511 mPciOptionRomImageDevicePathNodeTemplate.EndingAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) (RomBarOffset + ImageSize - 1 - (UINT8 *) RomBar);\r
2d9d2abf 512 PciOptionRomImageDevicePath = AppendDevicePathNode (PciDevice->DevicePath, (const EFI_DEVICE_PATH_PROTOCOL *)&mPciOptionRomImageDevicePathNodeTemplate);\r
513 ASSERT (PciOptionRomImageDevicePath != NULL);\r
514\r
ead42efc 515 //\r
516 // load image and start image\r
517 //\r
518 Status = gBS->LoadImage (\r
519 FALSE,\r
520 gPciBusDriverBinding.DriverBindingHandle,\r
2d9d2abf 521 PciOptionRomImageDevicePath,\r
ead42efc 522 ImageBuffer,\r
523 ImageLength,\r
524 &ImageHandle\r
525 );\r
2d9d2abf 526\r
527 //\r
528 // Free the device path after it has been used by LoadImage\r
529 //\r
530 gBS->FreePool (PciOptionRomImageDevicePath);\r
531\r
ead42efc 532 if (!EFI_ERROR (Status)) {\r
533 Status = gBS->StartImage (ImageHandle, NULL, NULL);\r
534 if (!EFI_ERROR (Status)) {\r
535 AddDriver (PciDevice, ImageHandle);\r
536 PciRomAddImageMapping (\r
537 ImageHandle,\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
5326528b 545 RetStatus = EFI_SUCCESS;\r
ead42efc 546 }\r
547 }\r
548 }\r
549\r
550 RomBarOffset = RomBarOffset + ImageSize;\r
551 } else {\r
552 RomBarOffset = RomBarOffset + ImageSize;\r
553 }\r
554 } else {\r
555 RomBarOffset = RomBarOffset + ImageSize;\r
556 }\r
557\r
558 } while (((Indicator & 0x80) == 0x00) && ((UINTN) (RomBarOffset - (UINT8 *) RomBar) < PciDevice->RomSize));\r
559\r
5326528b 560 return RetStatus;\r
ead42efc 561\r
562}\r
57076f45 563\r