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