]> git.proxmox.com Git - mirror_edk2.git/blame - DuetPkg/PciBusNoEnumerationDxe/PciOptionRomSupport.c
Enhance the error handling.
[mirror_edk2.git] / DuetPkg / PciBusNoEnumerationDxe / PciOptionRomSupport.c
CommitLineData
10590588 1/*++\r
2\r
b1f700a8
HT
3Copyright (c) 2005 - 2006, Intel Corporation. All rights reserved.<BR>\r
4This program and the accompanying materials \r
10590588 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\r
26\r
27EFI_STATUS\r
28RomDecode (\r
29 IN PCI_IO_DEVICE *PciDevice,\r
30 IN UINT8 RomBarIndex,\r
31 IN UINT32 RomBar,\r
32 IN BOOLEAN Enable\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{\r
49 UINT8 RomBarIndex;\r
50 UINT32 AllOnes;\r
51 UINT64 Address;\r
52 EFI_STATUS Status;\r
53 UINT8 Bus;\r
54 UINT8 Device;\r
55 UINT8 Function;\r
56 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
57\r
58 Bus = PciIoDevice->BusNumber;\r
59 Device = PciIoDevice->DeviceNumber;\r
60 Function = PciIoDevice->FunctionNumber;\r
61\r
62 PciRootBridgeIo = PciIoDevice->PciRootBridgeIo;\r
63\r
64 //\r
65 // offset is 0x30 if is not ppb\r
66 //\r
67\r
68 //\r
69 // 0x30\r
70 //\r
bc14bdb3 71 RomBarIndex = PCI_EXPANSION_ROM_BASE;\r
10590588 72\r
73 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
74 //\r
75 // if is ppb\r
76 //\r
77\r
78 //\r
79 // 0x38\r
80 //\r
81 RomBarIndex = PCI_BRIDGE_ROMBAR;\r
82 }\r
83 //\r
84 // the bit0 is 0 to prevent the enabling of the Rom address decoder\r
85 //\r
86 AllOnes = 0xfffffffe;\r
87 Address = EFI_PCI_ADDRESS (Bus, Device, Function, RomBarIndex);\r
88\r
89 Status = PciRootBridgeIo->Pci.Write (\r
90 PciRootBridgeIo,\r
91 EfiPciWidthUint32,\r
92 Address,\r
93 1,\r
94 &AllOnes\r
95 );\r
96 if (EFI_ERROR (Status)) {\r
97 return Status;\r
98 }\r
99 \r
100 //\r
101 // read back\r
102 //\r
103 Status = PciRootBridgeIo->Pci.Read (\r
104 PciRootBridgeIo,\r
105 EfiPciWidthUint32,\r
106 Address,\r
107 1,\r
108 &AllOnes\r
109 );\r
110 if (EFI_ERROR (Status)) {\r
111 return Status;\r
112 }\r
113\r
114 //\r
115 // Bits [1, 10] are reserved\r
116 //\r
117 AllOnes &= 0xFFFFF800;\r
118 if ((AllOnes == 0) || (AllOnes == 0xFFFFF800)) {\r
119 return EFI_NOT_FOUND;\r
120 }\r
121 \r
122 DEBUG ((EFI_D_ERROR, "PCIBUS: GetOpRomInfo: OPROM detected!\n"));\r
123 DEBUG ((EFI_D_ERROR, "PCIBUS: GetOpRomInfo: B-%x, D-%x, F-%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Function));\r
124\r
125 PciIoDevice->RomSize = (UINT64) ((~AllOnes) + 1);\r
126 return EFI_SUCCESS;\r
127}\r
128\r
129EFI_STATUS\r
130LoadOpRomImage (\r
131 IN PCI_IO_DEVICE *PciDevice,\r
132 IN UINT64 ReservedMemoryBase\r
133 )\r
134/*++\r
135\r
136Routine Description:\r
137 \r
138 Load option rom image for specified PCI device\r
139\r
140Arguments:\r
141\r
142Returns:\r
143\r
144--*/\r
145{\r
146 UINT8 RomBarIndex;\r
147 UINT8 Indicator;\r
148 UINT16 OffsetPcir;\r
149 UINT32 RomBarOffset;\r
150 UINT32 RomBar;\r
10590588 151 EFI_STATUS retStatus;\r
152 BOOLEAN FirstCheck;\r
153 UINT8 *Image;\r
154 PCI_EXPANSION_ROM_HEADER *RomHeader;\r
155 PCI_DATA_STRUCTURE *RomPcir;\r
156 UINT64 RomSize;\r
157 UINT64 RomImageSize;\r
158 UINT8 *RomInMemory;\r
159 UINT8 CodeType;\r
160\r
161 RomSize = PciDevice->RomSize;\r
162\r
163 Indicator = 0;\r
164 RomImageSize = 0;\r
165 RomInMemory = NULL;\r
10590588 166 CodeType = 0xFF;\r
167\r
168 //\r
169 // Get the RomBarIndex\r
170 //\r
171\r
172 //\r
173 // 0x30\r
174 //\r
bc14bdb3 175 RomBarIndex = PCI_EXPANSION_ROM_BASE;\r
10590588 176 if (IS_PCI_BRIDGE (&(PciDevice->Pci))) {\r
177 //\r
178 // if is ppb\r
179 //\r
180\r
181 //\r
182 // 0x38\r
183 //\r
184 RomBarIndex = PCI_BRIDGE_ROMBAR;\r
185 }\r
186 //\r
187 // Allocate memory for Rom header and PCIR\r
188 //\r
189 RomHeader = AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER));\r
190 if (RomHeader == NULL) {\r
191 return EFI_OUT_OF_RESOURCES;\r
192 }\r
193\r
194 RomPcir = AllocatePool (sizeof (PCI_DATA_STRUCTURE));\r
195 if (RomPcir == NULL) {\r
196 gBS->FreePool (RomHeader);\r
197 return EFI_OUT_OF_RESOURCES;\r
198 }\r
199\r
200 RomBar = (UINT32)ReservedMemoryBase; \r
201\r
202 //\r
203 // Enable RomBar\r
204 //\r
205 RomDecode (PciDevice, RomBarIndex, RomBar, TRUE);\r
206\r
207 RomBarOffset = RomBar;\r
208 retStatus = EFI_NOT_FOUND;\r
209 FirstCheck = TRUE;\r
210\r
211 do {\r
212 PciDevice->PciRootBridgeIo->Mem.Read (\r
213 PciDevice->PciRootBridgeIo,\r
214 EfiPciWidthUint8,\r
215 RomBarOffset,\r
216 sizeof (PCI_EXPANSION_ROM_HEADER),\r
217 (UINT8 *) RomHeader\r
218 );\r
219\r
220 if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
221 RomBarOffset = RomBarOffset + 512;\r
222 if (FirstCheck) {\r
223 break;\r
224 } else {\r
225 RomImageSize = RomImageSize + 512;\r
226 continue;\r
227 }\r
228 }\r
229\r
230 FirstCheck = FALSE;\r
231 OffsetPcir = RomHeader->PcirOffset;\r
232 PciDevice->PciRootBridgeIo->Mem.Read (\r
233 PciDevice->PciRootBridgeIo,\r
234 EfiPciWidthUint8,\r
235 RomBarOffset + OffsetPcir,\r
236 sizeof (PCI_DATA_STRUCTURE),\r
237 (UINT8 *) RomPcir\r
238 );\r
239 if (RomPcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {\r
240 CodeType = PCI_CODE_TYPE_PCAT_IMAGE;\r
241 }\r
242 Indicator = RomPcir->Indicator;\r
243 RomImageSize = RomImageSize + RomPcir->ImageLength * 512;\r
244 RomBarOffset = RomBarOffset + RomPcir->ImageLength * 512;\r
245 } while (((Indicator & 0x80) == 0x00) && ((RomBarOffset - RomBar) < RomSize));\r
246\r
247 //\r
248 // Some Legacy Cards do not report the correct ImageLength so used the maximum\r
249 // of the legacy length and the PCIR Image Length\r
250 //\r
251 if (CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {\r
252 RomImageSize = MAX(RomImageSize, (((EFI_LEGACY_EXPANSION_ROM_HEADER *)RomHeader)->Size512 * 512));\r
253 }\r
254\r
255 if (RomImageSize > 0) {\r
256 retStatus = EFI_SUCCESS;\r
257 Image = AllocatePool ((UINT32) RomImageSize);\r
258 if (Image == NULL) {\r
259 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);\r
260 gBS->FreePool (RomHeader);\r
261 gBS->FreePool (RomPcir);\r
262 return EFI_OUT_OF_RESOURCES;\r
263 }\r
264 \r
265 //\r
266 // Copy Rom image into memory\r
267 //\r
268 PciDevice->PciRootBridgeIo->Mem.Read (\r
269 PciDevice->PciRootBridgeIo,\r
270 EfiPciWidthUint8,\r
271 RomBar,\r
272 (UINT32) RomImageSize,\r
273 Image\r
274 );\r
275 RomInMemory = Image;\r
276 }\r
277\r
278 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);\r
279\r
280 PciDevice->PciIo.RomSize = RomImageSize;\r
281 PciDevice->PciIo.RomImage = RomInMemory;\r
282\r
283 //\r
284 // Free allocated memory\r
285 //\r
286 gBS->FreePool (RomHeader);\r
287 gBS->FreePool (RomPcir);\r
288\r
289 return retStatus;\r
290}\r
291\r
292EFI_STATUS\r
293RomDecode (\r
294 IN PCI_IO_DEVICE *PciDevice,\r
295 IN UINT8 RomBarIndex,\r
296 IN UINT32 RomBar,\r
297 IN BOOLEAN Enable\r
298 )\r
299/*++\r
300\r
301Routine Description:\r
302\r
303Arguments:\r
304\r
305Returns:\r
306\r
307--*/\r
308{\r
309 UINT16 CommandValue;\r
310 UINT32 Value32;\r
311 UINT64 Address;\r
312 //EFI_STATUS Status;\r
313 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
314 \r
315 PciRootBridgeIo = PciDevice->PciRootBridgeIo;\r
316 if (Enable) {\r
317 Address = EFI_PCI_ADDRESS (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, RomBarIndex);\r
318 //\r
319 // set the Rom base address: now is hardcode\r
320 //\r
321 PciRootBridgeIo->Pci.Write(\r
322 PciRootBridgeIo, \r
323 EfiPciWidthUint32, \r
324 Address, \r
325 1, \r
326 &RomBar);\r
327 \r
328 //\r
329 // enable its decoder\r
330 //\r
331 Value32 = RomBar | 0x1;\r
332 PciRootBridgeIo->Pci.Write(\r
333 PciRootBridgeIo, \r
334 EfiPciWidthUint32, \r
335 Address, \r
336 1, \r
337 &Value32);\r
338 \r
339 //\r
340 //setting the memory space bit in the function's command register\r
341 //\r
342 Address = EFI_PCI_ADDRESS (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, 0x04);\r
343 PciRootBridgeIo->Pci.Read(\r
344 PciRootBridgeIo, \r
345 EfiPciWidthUint16, \r
346 Address, \r
347 1, \r
348 &CommandValue);\r
349 \r
350 CommandValue = (UINT16)(CommandValue | 0x0002); //0x0003\r
351 PciRootBridgeIo->Pci.Write(\r
352 PciRootBridgeIo, \r
353 EfiPciWidthUint16, \r
354 Address, \r
355 1, \r
356 &CommandValue);\r
357 } else {\r
358 //\r
359 // disable rom decode\r
360 // \r
361 Address = EFI_PCI_ADDRESS (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, RomBarIndex);\r
362 Value32 = 0xfffffffe;\r
363 PciRootBridgeIo->Pci.Write(\r
364 PciRootBridgeIo, \r
365 EfiPciWidthUint32, \r
366 Address, \r
367 1, \r
368 &Value32);\r
369 }\r
370\r
371 return EFI_SUCCESS;\r
372\r
373}\r
374\r
375EFI_STATUS\r
376ProcessOpRomImage (\r
377 PCI_IO_DEVICE *PciDevice\r
378 )\r
379/*++\r
380\r
381Routine Description:\r
382\r
383 Process the oprom image.\r
384 \r
385Arguments:\r
386 PciDevice A pointer to a pci device.\r
387\r
388Returns:\r
389\r
390 EFI Status.\r
391 \r
392--*/\r
393{\r
394 UINT8 Indicator;\r
395 UINT32 ImageSize;\r
396 UINT16 ImageOffset;\r
397 VOID *RomBar;\r
398 UINT8 *RomBarOffset;\r
399 EFI_HANDLE ImageHandle;\r
400 EFI_STATUS Status;\r
401 EFI_STATUS retStatus;\r
402 BOOLEAN FirstCheck;\r
403 BOOLEAN SkipImage;\r
404 UINT32 DestinationSize;\r
405 UINT32 ScratchSize;\r
406 UINT8 *Scratch;\r
407 VOID *ImageBuffer;\r
408 VOID *DecompressedImageBuffer;\r
409 UINT32 ImageLength;\r
410 EFI_DECOMPRESS_PROTOCOL *Decompress;\r
411 EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader;\r
412 PCI_DATA_STRUCTURE *Pcir;\r
413\r
414 Indicator = 0;\r
415\r
416 //\r
417 // Get the Address of the Rom image\r
418 //\r
419 RomBar = PciDevice->PciIo.RomImage;\r
420 RomBarOffset = (UINT8 *) RomBar;\r
421 retStatus = EFI_NOT_FOUND;\r
422 FirstCheck = TRUE;\r
423\r
424 do {\r
425 EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset;\r
426 if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
427 RomBarOffset = RomBarOffset + 512;\r
428 if (FirstCheck) {\r
429 break;\r
430 } else {\r
431 continue;\r
432 }\r
433 }\r
434\r
435 FirstCheck = FALSE;\r
436 Pcir = (PCI_DATA_STRUCTURE *) (RomBarOffset + EfiRomHeader->PcirOffset);\r
437 ImageSize = (UINT32) (Pcir->ImageLength * 512);\r
438 Indicator = Pcir->Indicator;\r
439\r
440 if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) && \r
441 (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE)) {\r
442\r
443 if ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||\r
444 (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)) {\r
445\r
446 ImageOffset = EfiRomHeader->EfiImageHeaderOffset;\r
447 ImageSize = (UINT32) (EfiRomHeader->InitializationSize * 512);\r
448\r
449 ImageBuffer = (VOID *) (RomBarOffset + ImageOffset);\r
450 ImageLength = ImageSize - (UINT32)ImageOffset;\r
451 DecompressedImageBuffer = NULL;\r
452\r
453 //\r
454 // decompress here if needed\r
455 //\r
456 SkipImage = FALSE;\r
457 if (EfiRomHeader->CompressionType > EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {\r
458 SkipImage = TRUE;\r
459 }\r
460\r
461 if (EfiRomHeader->CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {\r
462 Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress);\r
463 if (EFI_ERROR (Status)) {\r
464 SkipImage = TRUE;\r
465 } else {\r
466 SkipImage = TRUE;\r
467 Status = Decompress->GetInfo (\r
468 Decompress,\r
469 ImageBuffer,\r
470 ImageLength,\r
471 &DestinationSize,\r
472 &ScratchSize\r
473 );\r
474 if (!EFI_ERROR (Status)) {\r
475 DecompressedImageBuffer = NULL;\r
476 DecompressedImageBuffer = AllocatePool (DestinationSize);\r
477 if (DecompressedImageBuffer != NULL) {\r
478 Scratch = AllocatePool (ScratchSize);\r
479 if (Scratch != NULL) {\r
480 Status = Decompress->Decompress (\r
481 Decompress,\r
482 ImageBuffer,\r
483 ImageLength,\r
484 DecompressedImageBuffer,\r
485 DestinationSize,\r
486 Scratch,\r
487 ScratchSize\r
488 );\r
489 if (!EFI_ERROR (Status)) {\r
490 ImageBuffer = DecompressedImageBuffer;\r
491 ImageLength = DestinationSize;\r
492 SkipImage = FALSE;\r
493 }\r
494\r
495 gBS->FreePool (Scratch);\r
496 }\r
497 }\r
498 }\r
499 }\r
500 }\r
501\r
502 if (!SkipImage) {\r
503 //\r
504 // load image and start image\r
505 //\r
506 Status = gBS->LoadImage (\r
507 FALSE,\r
508 gPciBusDriverBinding.DriverBindingHandle,\r
509 NULL,\r
510 ImageBuffer,\r
511 ImageLength,\r
512 &ImageHandle\r
513 );\r
514 if (!EFI_ERROR (Status)) {\r
515 Status = gBS->StartImage (ImageHandle, NULL, NULL);\r
516 if (!EFI_ERROR (Status)) {\r
517 AddDriver (PciDevice, ImageHandle);\r
518 retStatus = EFI_SUCCESS;\r
519 }\r
520 }\r
521 }\r
522\r
523 RomBarOffset = RomBarOffset + ImageSize;\r
524 } else {\r
525 RomBarOffset = RomBarOffset + ImageSize;\r
526 }\r
527 } else {\r
528 RomBarOffset = RomBarOffset + ImageSize;\r
529 }\r
530\r
531 } while (((Indicator & 0x80) == 0x00) && ((UINTN) (RomBarOffset - (UINT8 *) RomBar) < PciDevice->RomSize));\r
532\r
533 return retStatus;\r
534\r
535}\r