]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - 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
1/**@file\r
2\r
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
11\r
12**/\r
13\r
14#include "PciBus.h"\r
15#include "PciResourceSupport.h"\r
16\r
17#include <IndustryStandard/Pci23.h>\r
18\r
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
23 {\r
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
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
39EFI_STATUS\r
40GetOpRomInfo (\r
41 IN PCI_IO_DEVICE *PciIoDevice\r
42 )\r
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
66 RomBarIndex = PCI_EXPANSION_ROM_BASE;\r
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
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
131EFI_STATUS\r
132LoadOpRomImage (\r
133 IN PCI_IO_DEVICE *PciDevice,\r
134 IN UINT64 RomBase\r
135 )\r
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
166 RomBarIndex = PCI_EXPANSION_ROM_BASE;\r
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
243 RomImageSize = MAX(RomImageSize, (((EFI_LEGACY_EXPANSION_ROM_HEADER *)RomHeader)->Size512 * 512));\r
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
255\r
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
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
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
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
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
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
328\r
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
353\r
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
382/**\r
383 Process the oprom image.\r
384 \r
385 @param PciDevice Pci device instance\r
386**/\r
387EFI_STATUS\r
388ProcessOpRomImage (\r
389 PCI_IO_DEVICE *PciDevice\r
390 )\r
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
411 EFI_DEVICE_PATH_PROTOCOL *PciOptionRomImageDevicePath;\r
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
439 if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) &&\r
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
502 //\r
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
507 PciOptionRomImageDevicePath = AppendDevicePathNode (PciDevice->DevicePath, (const EFI_DEVICE_PATH_PROTOCOL *)&mPciOptionRomImageDevicePathNodeTemplate);\r
508 ASSERT (PciOptionRomImageDevicePath != NULL);\r
509\r
510 //\r
511 // load image and start image\r
512 //\r
513 Status = gBS->LoadImage (\r
514 FALSE,\r
515 gPciBusDriverBinding.DriverBindingHandle,\r
516 PciOptionRomImageDevicePath,\r
517 ImageBuffer,\r
518 ImageLength,\r
519 &ImageHandle\r
520 );\r
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
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
558\r