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