]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Bus/Pci/PciBus/Dxe/PciOptionRomSupport.c
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@1459 6f19259b...
[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
27EFI_STATUS\r
28GetOpRomInfo (\r
29 IN PCI_IO_DEVICE *PciIoDevice\r
30 )\r
31/*++\r
32\r
33Routine Description:\r
34\r
35Arguments:\r
36\r
37Returns:\r
38\r
39--*/\r
40// TODO: PciIoDevice - add argument and description to function comment\r
41// TODO: EFI_NOT_FOUND - add return value to function comment\r
42// TODO: EFI_SUCCESS - add return value to function comment\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 48 if is not ppb\r
61 //\r
62\r
63 //\r
64 // 0x30\r
65 //\r
66 RomBarIndex = PCI_DEVICE_ROMBAR;\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 = PciRootBridgeIo->Pci.Write (\r
85 PciRootBridgeIo,\r
86 EfiPciWidthUint32,\r
87 Address,\r
88 1,\r
89 &AllOnes\r
90 );\r
91 if (EFI_ERROR (Status)) {\r
92 return Status;\r
93 }\r
94 \r
95 //\r
96 // read back\r
97 //\r
98 Status = PciRootBridgeIo->Pci.Read (\r
99 PciRootBridgeIo,\r
100 EfiPciWidthUint32,\r
101 Address,\r
102 1,\r
103 &AllOnes\r
104 );\r
105 if (EFI_ERROR (Status)) {\r
106 return Status;\r
107 }\r
108\r
109 AllOnes &= 0xFFFFFFFC;\r
110 if ((AllOnes == 0) || (AllOnes == 0xFFFFFFFC)) {\r
111 return EFI_NOT_FOUND;\r
112 }\r
113\r
114 PciIoDevice->RomSize = (UINT64) ((~AllOnes) + 1);\r
115 return EFI_SUCCESS;\r
116\r
117}\r
118\r
119EFI_STATUS\r
120LoadOpRomImage (\r
121 IN PCI_IO_DEVICE *PciDevice,\r
122 IN UINT64 RomBase\r
123 )\r
124/*++\r
125\r
126Routine Description:\r
127 \r
128 Load option rom image for specified PCI device\r
129\r
130Arguments:\r
131\r
132Returns:\r
133\r
134--*/\r
135// TODO: PciDevice - add argument and description to function comment\r
136// TODO: RomBase - add argument and description to function comment\r
137// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment\r
138// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment\r
139// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment\r
140{\r
141 UINT8 RomBarIndex;\r
142 UINT8 Indicator;\r
143 UINT16 OffsetPcir;\r
144 UINT32 RomBarOffset;\r
145 UINT32 RomBar;\r
146 UINT64 Temp;\r
147 EFI_STATUS retStatus;\r
148 BOOLEAN FirstCheck;\r
149 UINT8 *Image;\r
150 PCI_EXPANSION_ROM_HEADER *RomHeader;\r
151 PCI_DATA_STRUCTURE *RomPcir;\r
152 UINT64 RomSize;\r
153 UINT64 RomImageSize;\r
154 UINT8 *RomInMemory;\r
155\r
156 RomSize = PciDevice->RomSize;\r
157\r
158 Indicator = 0;\r
159 RomImageSize = 0;\r
160 RomInMemory = NULL;\r
161 Temp = 0;\r
162\r
163 //\r
164 // Get the RomBarIndex\r
165 //\r
166\r
167 //\r
168 // 0x30\r
169 //\r
170 RomBarIndex = PCI_DEVICE_ROMBAR;\r
171 if (IS_PCI_BRIDGE (&(PciDevice->Pci))) {\r
172 //\r
173 // if is ppb\r
174 //\r
175\r
176 //\r
177 // 0x38\r
178 //\r
179 RomBarIndex = PCI_BRIDGE_ROMBAR;\r
180 }\r
181 //\r
182 // Allocate memory for Rom header and PCIR\r
183 //\r
184 RomHeader = AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER));\r
185 if (RomHeader == NULL) {\r
186 return EFI_OUT_OF_RESOURCES;\r
187 }\r
188\r
189 RomPcir = AllocatePool (sizeof (PCI_DATA_STRUCTURE));\r
190 if (RomPcir == NULL) {\r
191 gBS->FreePool (RomHeader);\r
192 return EFI_OUT_OF_RESOURCES;\r
193 }\r
194\r
195 RomBar = (UINT32) RomBase;\r
196\r
197 //\r
198 // Enable RomBar\r
199 //\r
200 RomDecode (PciDevice, RomBarIndex, RomBar, TRUE);\r
201\r
202 RomBarOffset = RomBar;\r
203 retStatus = EFI_NOT_FOUND;\r
204 FirstCheck = TRUE;\r
205\r
206 do {\r
207 PciDevice->PciRootBridgeIo->Mem.Read (\r
208 PciDevice->PciRootBridgeIo,\r
209 EfiPciWidthUint8,\r
210 RomBarOffset,\r
211 sizeof (PCI_EXPANSION_ROM_HEADER),\r
212 (UINT8 *) RomHeader\r
213 );\r
214\r
215 if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
216 RomBarOffset = RomBarOffset + 512;\r
217 if (FirstCheck) {\r
218 break;\r
219 } else {\r
220 RomImageSize = RomImageSize + 512;\r
221 continue;\r
222 }\r
223 }\r
224\r
225 FirstCheck = FALSE;\r
226 OffsetPcir = RomHeader->PcirOffset;\r
227 PciDevice->PciRootBridgeIo->Mem.Read (\r
228 PciDevice->PciRootBridgeIo,\r
229 EfiPciWidthUint8,\r
230 RomBarOffset + OffsetPcir,\r
231 sizeof (PCI_DATA_STRUCTURE),\r
232 (UINT8 *) RomPcir\r
233 );\r
234 Indicator = RomPcir->Indicator;\r
235 RomImageSize = RomImageSize + RomPcir->ImageLength * 512;\r
236 RomBarOffset = RomBarOffset + RomPcir->ImageLength * 512;\r
237 } while (((Indicator & 0x80) == 0x00) && ((RomBarOffset - RomBar) < RomSize));\r
238\r
239 if (RomImageSize > 0) {\r
240 retStatus = EFI_SUCCESS;\r
241 Image = AllocatePool ((UINT32) RomImageSize);\r
242 if (Image == NULL) {\r
243 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);\r
244 gBS->FreePool (RomHeader);\r
245 gBS->FreePool (RomPcir);\r
246 return EFI_OUT_OF_RESOURCES;\r
247 }\r
248 \r
249 //\r
250 // Copy Rom image into memory\r
251 //\r
252 PciDevice->PciRootBridgeIo->Mem.Read (\r
253 PciDevice->PciRootBridgeIo,\r
254 EfiPciWidthUint8,\r
255 RomBar,\r
256 (UINT32) RomImageSize,\r
257 Image\r
258 );\r
259 RomInMemory = Image;\r
260 }\r
261\r
262 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);\r
263\r
264 PciDevice->PciIo.RomSize = RomImageSize;\r
265 PciDevice->PciIo.RomImage = RomInMemory;\r
266\r
267 PciRomAddImageMapping (\r
268 NULL,\r
269 PciDevice->PciRootBridgeIo->SegmentNumber,\r
270 PciDevice->BusNumber,\r
271 PciDevice->DeviceNumber,\r
272 PciDevice->FunctionNumber,\r
273 (UINT64) (UINTN) PciDevice->PciIo.RomImage,\r
274 PciDevice->PciIo.RomSize\r
275 );\r
276\r
277 //\r
278 // Free allocated memory\r
279 //\r
280 gBS->FreePool (RomHeader);\r
281 gBS->FreePool (RomPcir);\r
282\r
283 return retStatus;\r
284}\r
285\r
286EFI_STATUS\r
287RomDecode (\r
288 IN PCI_IO_DEVICE *PciDevice,\r
289 IN UINT8 RomBarIndex,\r
290 IN UINT32 RomBar,\r
291 IN BOOLEAN Enable\r
292 )\r
293/*++\r
294\r
295Routine Description:\r
296\r
297Arguments:\r
298\r
299Returns:\r
300\r
301--*/\r
302// TODO: PciDevice - add argument and description to function comment\r
303// TODO: RomBarIndex - add argument and description to function comment\r
304// TODO: RomBar - add argument and description to function comment\r
305// TODO: Enable - add argument and description to function comment\r
306// TODO: EFI_SUCCESS - add return value to function comment\r
307{\r
308 UINT32 Value32;\r
309 UINT32 Offset;\r
310 EFI_PCI_IO_PROTOCOL *PciIo;\r
311\r
312 PciIo = &PciDevice->PciIo;\r
313 if (Enable) {\r
314 //\r
315 // Clear all bars\r
316 //\r
317 for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {\r
318 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllZero);\r
319 }\r
320 \r
321 //\r
322 // set the Rom base address: now is hardcode\r
323 // enable its decoder\r
324 //\r
325 Value32 = RomBar | 0x1;\r
326 PciIo->Pci.Write (\r
327 PciIo,\r
328 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,\r
329 RomBarIndex,\r
330 1,\r
331 &Value32\r
332 );\r
333\r
334 //\r
335 // Programe all upstream bridge\r
336 //\r
337 ProgrameUpstreamBridgeForRom(PciDevice, RomBar, TRUE);\r
338\r
339 //\r
340 // Setting the memory space bit in the function's command register\r
341 //\r
342 PciEnableCommandRegister(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);\r
343\r
344 } else {\r
345 \r
346 //\r
347 // disable command register decode to memory\r
348 //\r
349 PciDisableCommandRegister(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);\r
350\r
351 //\r
352 // Destroy the programmed bar in all the upstream bridge.\r
353 //\r
354 ProgrameUpstreamBridgeForRom(PciDevice, RomBar, FALSE);\r
355\r
356 //\r
357 // disable rom decode\r
358 //\r
359 Value32 = 0xFFFFFFFE;\r
360 PciIo->Pci.Write (\r
361 PciIo,\r
362 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,\r
363 RomBarIndex,\r
364 1,\r
365 &Value32\r
366 );\r
367\r
368 }\r
369\r
370 return EFI_SUCCESS;\r
371\r
372}\r
373\r
374EFI_STATUS\r
375ProcessOpRomImage (\r
376 PCI_IO_DEVICE *PciDevice\r
377 )\r
378/*++\r
379\r
380Routine Description:\r
381\r
382 Process the oprom image.\r
383 \r
384Arguments:\r
385 PciDevice A pointer to a pci device.\r
386\r
387Returns:\r
388\r
389 EFI Status.\r
390 \r
391--*/\r
392{\r
393 UINT8 Indicator;\r
394 UINT32 ImageSize;\r
395 UINT16 ImageOffset;\r
396 VOID *RomBar;\r
397 UINT8 *RomBarOffset;\r
398 EFI_HANDLE ImageHandle;\r
399 EFI_STATUS Status;\r
400 EFI_STATUS retStatus;\r
401 BOOLEAN FirstCheck;\r
402 BOOLEAN SkipImage;\r
403 UINT32 DestinationSize;\r
404 UINT32 ScratchSize;\r
405 UINT8 *Scratch;\r
406 VOID *ImageBuffer;\r
407 VOID *DecompressedImageBuffer;\r
408 UINT32 ImageLength;\r
409 EFI_DECOMPRESS_PROTOCOL *Decompress;\r
410 EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader;\r
411 PCI_DATA_STRUCTURE *Pcir;\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 // load image and start image\r
504 //\r
505 Status = gBS->LoadImage (\r
506 FALSE,\r
507 gPciBusDriverBinding.DriverBindingHandle,\r
508 PciDevice->Handle,\r
509 ImageBuffer,\r
510 ImageLength,\r
511 &ImageHandle\r
512 );\r
513 if (!EFI_ERROR (Status)) {\r
514 Status = gBS->StartImage (ImageHandle, NULL, NULL);\r
515 if (!EFI_ERROR (Status)) {\r
516 AddDriver (PciDevice, ImageHandle);\r
517 PciRomAddImageMapping (\r
518 ImageHandle,\r
519 PciDevice->PciRootBridgeIo->SegmentNumber,\r
520 PciDevice->BusNumber,\r
521 PciDevice->DeviceNumber,\r
522 PciDevice->FunctionNumber,\r
523 (UINT64) (UINTN) PciDevice->PciIo.RomImage,\r
524 PciDevice->PciIo.RomSize\r
525 );\r
526 retStatus = EFI_SUCCESS;\r
527 }\r
528 }\r
529 }\r
530\r
531 RomBarOffset = RomBarOffset + ImageSize;\r
532 } else {\r
533 RomBarOffset = RomBarOffset + ImageSize;\r
534 }\r
535 } else {\r
536 RomBarOffset = RomBarOffset + ImageSize;\r
537 }\r
538\r
539 } while (((Indicator & 0x80) == 0x00) && ((UINTN) (RomBarOffset - (UINT8 *) RomBar) < PciDevice->RomSize));\r
540\r
541 return retStatus;\r
542\r
543}\r