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