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