]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.c
Enhance the error handling.
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciBusDxe / PciOptionRomSupport.c
CommitLineData
9060e3ec 1/** @file\r
2 PCI Rom supporting funtions implementation for PCI Bus module.\r
3\r
eaaf8693 4Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
cd5ebaa0 5This program and the accompanying materials\r
9060e3ec 6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "PciBus.h"\r
16\r
17/**\r
18 Load the EFI Image from Option ROM\r
19\r
20 @param PciIoDevice PCI IO device instance.\r
21 @param FilePath The file path of the EFI Image\r
22 @param BufferSize On input the size of Buffer in bytes. On output with a return\r
23 code of EFI_SUCCESS, the amount of data transferred to Buffer.\r
24 On output with a return code of EFI_BUFFER_TOO_SMALL,\r
25 the size of Buffer required to retrieve the requested file.\r
26 @param Buffer The memory buffer to transfer the file to. If Buffer is NULL,\r
27 then no the size of the requested file is returned in BufferSize.\r
28\r
29 @retval EFI_SUCCESS The file was loaded.\r
30 @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or\r
31 BufferSize is NULL.\r
32 @retval EFI_NOT_FOUND Not found PCI Option Rom on PCI device.\r
33 @retval EFI_DEVICE_ERROR Failed to decompress PCI Option Rom image.\r
34 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.\r
35 BufferSize has been updated with the size needed to complete the request.\r
36**/\r
37EFI_STATUS\r
38LocalLoadFile2 (\r
39 IN PCI_IO_DEVICE *PciIoDevice,\r
40 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
41 IN OUT UINTN *BufferSize,\r
42 IN VOID *Buffer OPTIONAL\r
43 )\r
44{\r
45 EFI_STATUS Status;\r
46 MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH *EfiOpRomImageNode;\r
47 EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader;\r
48 PCI_DATA_STRUCTURE *Pcir;\r
49 UINT32 ImageSize;\r
50 UINT8 *ImageBuffer;\r
51 UINT32 ImageLength;\r
52 UINT32 DestinationSize;\r
53 UINT32 ScratchSize;\r
54 VOID *Scratch;\r
55 EFI_DECOMPRESS_PROTOCOL *Decompress;\r
56\r
57 EfiOpRomImageNode = (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH *) FilePath;\r
58 if ((EfiOpRomImageNode == NULL) ||\r
59 (DevicePathType (FilePath) != MEDIA_DEVICE_PATH) ||\r
60 (DevicePathSubType (FilePath) != MEDIA_RELATIVE_OFFSET_RANGE_DP) ||\r
61 (DevicePathNodeLength (FilePath) != sizeof (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH)) ||\r
62 (!IsDevicePathEnd (NextDevicePathNode (FilePath))) ||\r
63 (EfiOpRomImageNode->StartingOffset > EfiOpRomImageNode->EndingOffset) ||\r
64 (EfiOpRomImageNode->EndingOffset >= PciIoDevice->RomSize) ||\r
65 (BufferSize == NULL)\r
66 ) {\r
67 return EFI_INVALID_PARAMETER;\r
68 }\r
69\r
70 EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) (\r
71 (UINT8 *) PciIoDevice->PciIo.RomImage + EfiOpRomImageNode->StartingOffset\r
72 );\r
73 if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
74 return EFI_NOT_FOUND;\r
75 }\r
76\r
77\r
78 Pcir = (PCI_DATA_STRUCTURE *) ((UINT8 *) EfiRomHeader + EfiRomHeader->PcirOffset);\r
79\r
80\r
81 if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) &&\r
82 (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) &&\r
83 ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||\r
84 (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)) &&\r
85 (EfiRomHeader->CompressionType <= EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED)\r
86 ) {\r
87\r
88 ImageSize = (UINT32) EfiRomHeader->InitializationSize * 512;\r
89 ImageBuffer = (UINT8 *) EfiRomHeader + EfiRomHeader->EfiImageHeaderOffset;\r
90 ImageLength = ImageSize - EfiRomHeader->EfiImageHeaderOffset;\r
91\r
92 if (EfiRomHeader->CompressionType != EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {\r
93 //\r
94 // Uncompressed: Copy the EFI Image directly to user's buffer\r
95 //\r
96 if (Buffer == NULL || *BufferSize < ImageLength) {\r
97 *BufferSize = ImageLength;\r
98 return EFI_BUFFER_TOO_SMALL;\r
99 }\r
100\r
101 *BufferSize = ImageLength;\r
102 CopyMem (Buffer, ImageBuffer, ImageLength);\r
103 return EFI_SUCCESS;\r
104\r
105 } else {\r
106 //\r
107 // Compressed: Uncompress before copying\r
108 //\r
109 Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress);\r
110 if (EFI_ERROR (Status)) {\r
111 return EFI_DEVICE_ERROR;\r
112 }\r
113 Status = Decompress->GetInfo (\r
114 Decompress,\r
115 ImageBuffer,\r
116 ImageLength,\r
117 &DestinationSize,\r
118 &ScratchSize\r
119 );\r
120 if (EFI_ERROR (Status)) {\r
121 return EFI_DEVICE_ERROR;\r
122 }\r
123\r
124 if (Buffer == NULL || *BufferSize < DestinationSize) {\r
125 *BufferSize = DestinationSize;\r
126 return EFI_BUFFER_TOO_SMALL;\r
127 }\r
128\r
129 *BufferSize = DestinationSize;\r
130 Scratch = AllocatePool (ScratchSize);\r
131 if (Scratch == NULL) {\r
132 return EFI_DEVICE_ERROR;\r
133 }\r
134\r
135 Status = Decompress->Decompress (\r
136 Decompress,\r
137 ImageBuffer,\r
138 ImageLength,\r
139 Buffer,\r
140 DestinationSize,\r
141 Scratch,\r
142 ScratchSize\r
143 );\r
144 FreePool (Scratch);\r
145\r
146 if (EFI_ERROR (Status)) {\r
147 return EFI_DEVICE_ERROR;\r
148 }\r
149 return EFI_SUCCESS;\r
150 }\r
151 }\r
152\r
153 return EFI_NOT_FOUND;\r
154}\r
155\r
156/**\r
157 Initialize a PCI LoadFile2 instance.\r
158\r
159 @param PciIoDevice PCI IO Device.\r
160\r
161**/\r
162VOID\r
163InitializePciLoadFile2 (\r
164 IN PCI_IO_DEVICE *PciIoDevice\r
165 )\r
166{\r
167 PciIoDevice->LoadFile2.LoadFile = LoadFile2;\r
168}\r
169\r
170/**\r
171 Causes the driver to load a specified file.\r
172\r
173 @param This Indicates a pointer to the calling context.\r
174 @param FilePath The device specific path of the file to load.\r
175 @param BootPolicy Should always be FALSE.\r
176 @param BufferSize On input the size of Buffer in bytes. On output with a return\r
177 code of EFI_SUCCESS, the amount of data transferred to Buffer.\r
178 On output with a return code of EFI_BUFFER_TOO_SMALL,\r
179 the size of Buffer required to retrieve the requested file.\r
180 @param Buffer The memory buffer to transfer the file to. If Buffer is NULL,\r
181 then no the size of the requested file is returned in BufferSize.\r
182\r
183 @retval EFI_SUCCESS The file was loaded.\r
184 @retval EFI_UNSUPPORTED BootPolicy is TRUE.\r
185 @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or\r
186 BufferSize is NULL.\r
187 @retval EFI_NOT_FOUND Not found PCI Option Rom on PCI device.\r
188 @retval EFI_DEVICE_ERROR Failed to decompress PCI Option Rom image.\r
189 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.\r
190 BufferSize has been updated with the size needed to complete the request.\r
191\r
192**/\r
193EFI_STATUS\r
194EFIAPI\r
195LoadFile2 (\r
196 IN EFI_LOAD_FILE2_PROTOCOL *This,\r
197 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
198 IN BOOLEAN BootPolicy,\r
199 IN OUT UINTN *BufferSize,\r
200 IN VOID *Buffer OPTIONAL\r
201 )\r
202{\r
203 PCI_IO_DEVICE *PciIoDevice;\r
204\r
205 if (BootPolicy) {\r
206 return EFI_UNSUPPORTED;\r
207 }\r
208 PciIoDevice = PCI_IO_DEVICE_FROM_LOAD_FILE2_THIS (This);\r
209\r
210 return LocalLoadFile2 (\r
211 PciIoDevice,\r
212 FilePath,\r
213 BufferSize,\r
214 Buffer\r
215 );\r
216}\r
217\r
218/**\r
219 Get Pci device's oprom information.\r
220\r
221 @param PciIoDevice Input Pci device instance.\r
222 Output Pci device instance with updated OptionRom size.\r
223\r
224 @retval EFI_NOT_FOUND Pci device has not Option Rom.\r
225 @retval EFI_SUCCESS Pci device has Option Rom.\r
226\r
227**/\r
228EFI_STATUS\r
229GetOpRomInfo (\r
230 IN OUT PCI_IO_DEVICE *PciIoDevice\r
231 )\r
232{\r
233 UINT8 RomBarIndex;\r
234 UINT32 AllOnes;\r
235 UINT64 Address;\r
236 EFI_STATUS Status;\r
237 UINT8 Bus;\r
238 UINT8 Device;\r
239 UINT8 Function;\r
240 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
241\r
242 Bus = PciIoDevice->BusNumber;\r
243 Device = PciIoDevice->DeviceNumber;\r
244 Function = PciIoDevice->FunctionNumber;\r
245\r
246 PciRootBridgeIo = PciIoDevice->PciRootBridgeIo;\r
247\r
248 //\r
249 // Offset is 0x30 if is not ppb\r
250 //\r
251\r
252 //\r
253 // 0x30\r
254 //\r
255 RomBarIndex = PCI_EXPANSION_ROM_BASE;\r
256\r
257 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
258 //\r
259 // If is ppb, 0x38\r
260 //\r
261 RomBarIndex = PCI_BRIDGE_ROMBAR;\r
262 }\r
263 //\r
264 // The bit0 is 0 to prevent the enabling of the Rom address decoder\r
265 //\r
266 AllOnes = 0xfffffffe;\r
267 Address = EFI_PCI_ADDRESS (Bus, Device, Function, RomBarIndex);\r
268\r
269 Status = PciRootBridgeIo->Pci.Write (\r
270 PciRootBridgeIo,\r
271 EfiPciWidthUint32,\r
272 Address,\r
273 1,\r
274 &AllOnes\r
275 );\r
276 if (EFI_ERROR (Status)) {\r
277 return EFI_NOT_FOUND;\r
278 }\r
279\r
280 //\r
281 // Read back\r
282 //\r
283 Status = PciRootBridgeIo->Pci.Read(\r
284 PciRootBridgeIo,\r
285 EfiPciWidthUint32,\r
286 Address,\r
287 1,\r
288 &AllOnes\r
289 );\r
290 if (EFI_ERROR (Status)) {\r
291 return EFI_NOT_FOUND;\r
292 }\r
293\r
294 //\r
295 // Bits [1, 10] are reserved\r
296 //\r
297 AllOnes &= 0xFFFFF800;\r
298 if ((AllOnes == 0) || (AllOnes == 0xFFFFF800)) {\r
299 return EFI_NOT_FOUND;\r
300 }\r
301\r
302 PciIoDevice->RomSize = (UINT64) ((~AllOnes) + 1);\r
303 return EFI_SUCCESS;\r
304}\r
305\r
306/**\r
307 Check if the RomImage contains EFI Images.\r
308\r
309 @param RomImage The ROM address of Image for check.\r
310 @param RomSize Size of ROM for check.\r
311\r
312 @retval TRUE ROM contain EFI Image.\r
313 @retval FALSE ROM not contain EFI Image.\r
314\r
315**/\r
316BOOLEAN\r
317ContainEfiImage (\r
318 IN VOID *RomImage,\r
319 IN UINT64 RomSize\r
320 )\r
321{\r
322 PCI_EXPANSION_ROM_HEADER *RomHeader;\r
323 PCI_DATA_STRUCTURE *RomPcir;\r
324 BOOLEAN FirstCheck;\r
325\r
326 FirstCheck = TRUE;\r
327 RomHeader = RomImage;\r
328\r
329 while ((UINT8 *) RomHeader < (UINT8 *) RomImage + RomSize) {\r
330 if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
331 if (FirstCheck) {\r
332 return FALSE;\r
333 } else {\r
334 RomHeader = (PCI_EXPANSION_ROM_HEADER *) ((UINT8 *) RomHeader + 512);\r
335 continue;\r
336 }\r
337 }\r
338\r
339 FirstCheck = FALSE;\r
340 RomPcir = (PCI_DATA_STRUCTURE *) ((UINT8 *) RomHeader + RomHeader->PcirOffset);\r
341\r
342 if (RomPcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) {\r
343 return TRUE;\r
344 }\r
345\r
346 RomHeader = (PCI_EXPANSION_ROM_HEADER *) ((UINT8 *) RomHeader + RomPcir->Length * 512);\r
347 }\r
348\r
349 return FALSE;\r
350}\r
351\r
352\r
353/**\r
354 Load Option Rom image for specified PCI device.\r
355\r
356 @param PciDevice Pci device instance.\r
357 @param RomBase Base address of Option Rom.\r
358\r
359 @retval EFI_OUT_OF_RESOURCES No enough memory to hold image.\r
360 @retval EFI_SUCESS Successfully loaded Option Rom.\r
361\r
362**/\r
363EFI_STATUS\r
364LoadOpRomImage (\r
365 IN PCI_IO_DEVICE *PciDevice,\r
366 IN UINT64 RomBase\r
367 )\r
368{\r
369 UINT8 RomBarIndex;\r
370 UINT8 Indicator;\r
371 UINT16 OffsetPcir;\r
372 UINT32 RomBarOffset;\r
373 UINT32 RomBar;\r
374 EFI_STATUS RetStatus;\r
375 BOOLEAN FirstCheck;\r
376 UINT8 *Image;\r
377 PCI_EXPANSION_ROM_HEADER *RomHeader;\r
378 PCI_DATA_STRUCTURE *RomPcir;\r
379 UINT64 RomSize;\r
380 UINT64 RomImageSize;\r
381 UINT8 *RomInMemory;\r
382 UINT8 CodeType;\r
383\r
384 RomSize = PciDevice->RomSize;\r
385\r
386 Indicator = 0;\r
387 RomImageSize = 0;\r
388 RomInMemory = NULL;\r
389 CodeType = 0xFF;\r
390\r
391 //\r
392 // Get the RomBarIndex\r
393 //\r
394\r
395 //\r
396 // 0x30\r
397 //\r
398 RomBarIndex = PCI_EXPANSION_ROM_BASE;\r
399 if (IS_PCI_BRIDGE (&(PciDevice->Pci))) {\r
400 //\r
401 // if is ppb\r
402 //\r
403\r
404 //\r
405 // 0x38\r
406 //\r
407 RomBarIndex = PCI_BRIDGE_ROMBAR;\r
408 }\r
409 //\r
410 // Allocate memory for Rom header and PCIR\r
411 //\r
412 RomHeader = AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER));\r
413 if (RomHeader == NULL) {\r
414 return EFI_OUT_OF_RESOURCES;\r
415 }\r
416\r
417 RomPcir = AllocatePool (sizeof (PCI_DATA_STRUCTURE));\r
418 if (RomPcir == NULL) {\r
419 FreePool (RomHeader);\r
420 return EFI_OUT_OF_RESOURCES;\r
421 }\r
422\r
423 RomBar = (UINT32) RomBase;\r
424\r
425 //\r
426 // Enable RomBar\r
427 //\r
428 RomDecode (PciDevice, RomBarIndex, RomBar, TRUE);\r
429\r
430 RomBarOffset = RomBar;\r
431 RetStatus = EFI_NOT_FOUND;\r
432 FirstCheck = TRUE;\r
433\r
434 do {\r
435 PciDevice->PciRootBridgeIo->Mem.Read (\r
436 PciDevice->PciRootBridgeIo,\r
437 EfiPciWidthUint8,\r
438 RomBarOffset,\r
439 sizeof (PCI_EXPANSION_ROM_HEADER),\r
440 (UINT8 *) RomHeader\r
441 );\r
442\r
443 if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
444 RomBarOffset = RomBarOffset + 512;\r
445 if (FirstCheck) {\r
446 break;\r
447 } else {\r
448 RomImageSize = RomImageSize + 512;\r
449 continue;\r
450 }\r
451 }\r
452\r
453 FirstCheck = FALSE;\r
454 OffsetPcir = RomHeader->PcirOffset;\r
455 PciDevice->PciRootBridgeIo->Mem.Read (\r
456 PciDevice->PciRootBridgeIo,\r
457 EfiPciWidthUint8,\r
458 RomBarOffset + OffsetPcir,\r
459 sizeof (PCI_DATA_STRUCTURE),\r
460 (UINT8 *) RomPcir\r
461 );\r
462 if (RomPcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {\r
463 CodeType = PCI_CODE_TYPE_PCAT_IMAGE;\r
464 }\r
465 Indicator = RomPcir->Indicator;\r
466 RomImageSize = RomImageSize + RomPcir->ImageLength * 512;\r
467 RomBarOffset = RomBarOffset + RomPcir->ImageLength * 512;\r
468 } while (((Indicator & 0x80) == 0x00) && ((RomBarOffset - RomBar) < RomSize));\r
469\r
470 //\r
471 // Some Legacy Cards do not report the correct ImageLength so used the maximum\r
472 // of the legacy length and the PCIR Image Length\r
473 //\r
474 if (CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {\r
475 RomImageSize = MAX(RomImageSize, (((EFI_LEGACY_EXPANSION_ROM_HEADER *)RomHeader)->Size512 * 512));\r
476 }\r
477\r
478 if (RomImageSize > 0) {\r
479 RetStatus = EFI_SUCCESS;\r
480 Image = AllocatePool ((UINT32) RomImageSize);\r
481 if (Image == NULL) {\r
482 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);\r
483 FreePool (RomHeader);\r
484 FreePool (RomPcir);\r
485 return EFI_OUT_OF_RESOURCES;\r
486 }\r
487\r
488 //\r
489 // Copy Rom image into memory\r
490 //\r
491 PciDevice->PciRootBridgeIo->Mem.Read (\r
492 PciDevice->PciRootBridgeIo,\r
493 EfiPciWidthUint8,\r
494 RomBar,\r
495 (UINT32) RomImageSize,\r
496 Image\r
497 );\r
498 RomInMemory = Image;\r
499 }\r
500\r
501 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);\r
502\r
4ed4e19c 503 PciDevice->EmbeddedRom = TRUE;\r
9060e3ec 504 PciDevice->PciIo.RomSize = RomImageSize;\r
505 PciDevice->PciIo.RomImage = RomInMemory;\r
506\r
507 //\r
508 // For OpROM read from PCI device:\r
509 // Add the Rom Image to internal database for later PCI light enumeration\r
510 //\r
511 PciRomAddImageMapping (\r
512 NULL,\r
513 PciDevice->PciRootBridgeIo->SegmentNumber,\r
514 PciDevice->BusNumber,\r
515 PciDevice->DeviceNumber,\r
516 PciDevice->FunctionNumber,\r
517 (UINT64) (UINTN) PciDevice->PciIo.RomImage,\r
518 PciDevice->PciIo.RomSize\r
519 );\r
520\r
521 //\r
522 // Free allocated memory\r
523 //\r
524 FreePool (RomHeader);\r
525 FreePool (RomPcir);\r
526\r
527 return RetStatus;\r
528}\r
529\r
530/**\r
531 Enable/Disable Option Rom decode.\r
532\r
533 @param PciDevice Pci device instance.\r
534 @param RomBarIndex The BAR index of the standard PCI Configuration header to use as the\r
535 base address for resource range. The legal range for this field is 0..5.\r
536 @param RomBar Base address of Option Rom.\r
537 @param Enable Flag for enable/disable decode.\r
538\r
539**/\r
540VOID\r
541RomDecode (\r
542 IN PCI_IO_DEVICE *PciDevice,\r
543 IN UINT8 RomBarIndex,\r
544 IN UINT32 RomBar,\r
545 IN BOOLEAN Enable\r
546 )\r
547{\r
548 UINT32 Value32;\r
549 UINT32 Offset;\r
6989af71 550 UINT32 OffsetMax;\r
9060e3ec 551 EFI_PCI_IO_PROTOCOL *PciIo;\r
552\r
553 PciIo = &PciDevice->PciIo;\r
554 if (Enable) {\r
555 //\r
556 // Clear all bars\r
557 //\r
6989af71
RN
558 OffsetMax = 0x24;\r
559 if (IS_PCI_BRIDGE(&PciDevice->Pci)) {\r
560 OffsetMax = 0x14;\r
561 }\r
562\r
563 for (Offset = 0x10; Offset <= OffsetMax; Offset += sizeof (UINT32)) {\r
9060e3ec 564 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllZero);\r
565 }\r
566\r
567 //\r
568 // set the Rom base address: now is hardcode\r
569 // enable its decoder\r
570 //\r
571 Value32 = RomBar | 0x1;\r
572 PciIo->Pci.Write (\r
573 PciIo,\r
574 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,\r
575 RomBarIndex,\r
576 1,\r
577 &Value32\r
578 );\r
579\r
580 //\r
581 // Programe all upstream bridge\r
582 //\r
583 ProgrameUpstreamBridgeForRom(PciDevice, RomBar, TRUE);\r
584\r
585 //\r
586 // Setting the memory space bit in the function's command register\r
587 //\r
588 PCI_ENABLE_COMMAND_REGISTER(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);\r
589\r
590 } else {\r
591\r
592 //\r
593 // disable command register decode to memory\r
594 //\r
595 PCI_DISABLE_COMMAND_REGISTER(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);\r
596\r
597 //\r
598 // Destroy the programmed bar in all the upstream bridge.\r
599 //\r
600 ProgrameUpstreamBridgeForRom(PciDevice, RomBar, FALSE);\r
601\r
602 //\r
603 // disable rom decode\r
604 //\r
605 Value32 = 0xFFFFFFFE;\r
606 PciIo->Pci.Write (\r
607 PciIo,\r
608 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,\r
609 RomBarIndex,\r
610 1,\r
611 &Value32\r
612 );\r
613\r
614 }\r
615}\r
616\r
617/**\r
618 Load and start the Option Rom image.\r
619\r
620 @param PciDevice Pci device instance.\r
621\r
622 @retval EFI_SUCCESS Successfully loaded and started PCI Option Rom image.\r
623 @retval EFI_NOT_FOUND Failed to process PCI Option Rom image.\r
624\r
625**/\r
626EFI_STATUS\r
627ProcessOpRomImage (\r
628 IN PCI_IO_DEVICE *PciDevice\r
629 )\r
630{\r
631 UINT8 Indicator;\r
632 UINT32 ImageSize;\r
633 VOID *RomBar;\r
634 UINT8 *RomBarOffset;\r
635 EFI_HANDLE ImageHandle;\r
636 EFI_STATUS Status;\r
637 EFI_STATUS RetStatus;\r
638 BOOLEAN FirstCheck;\r
639 EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader;\r
640 PCI_DATA_STRUCTURE *Pcir;\r
641 EFI_DEVICE_PATH_PROTOCOL *PciOptionRomImageDevicePath;\r
642 MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH EfiOpRomImageNode;\r
643 VOID *Buffer;\r
644 UINTN BufferSize;\r
645\r
646 Indicator = 0;\r
647\r
648 //\r
649 // Get the Address of the Option Rom image\r
650 //\r
651 RomBar = PciDevice->PciIo.RomImage;\r
652 RomBarOffset = (UINT8 *) RomBar;\r
653 RetStatus = EFI_NOT_FOUND;\r
654 FirstCheck = TRUE;\r
655\r
656 do {\r
657 EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset;\r
658 if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
659 RomBarOffset += 512;\r
660 if (FirstCheck) {\r
661 break;\r
662 } else {\r
663 continue;\r
664 }\r
665 }\r
666\r
667 FirstCheck = FALSE;\r
668 Pcir = (PCI_DATA_STRUCTURE *) (RomBarOffset + EfiRomHeader->PcirOffset);\r
669 ImageSize = (UINT32) (Pcir->ImageLength * 512);\r
670 Indicator = Pcir->Indicator;\r
671\r
a93e23f9 672 //\r
673 // Skip the image if it is not an EFI PCI Option ROM image\r
674 //\r
675 if (Pcir->CodeType != PCI_CODE_TYPE_EFI_IMAGE) {\r
676 goto NextImage;\r
677 }\r
678\r
679 //\r
680 // Skip the EFI PCI Option ROM image if its machine type is not supported\r
681 //\r
682 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (EfiRomHeader->EfiMachineType)) {\r
683 goto NextImage;\r
684 }\r
685\r
686 //\r
687 // Ignore the EFI PCI Option ROM image if it is an EFI application\r
688 //\r
689 if (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {\r
690 goto NextImage;\r
691 }\r
692\r
9060e3ec 693 //\r
694 // Create Pci Option Rom Image device path header\r
695 //\r
696 EfiOpRomImageNode.Header.Type = MEDIA_DEVICE_PATH;\r
697 EfiOpRomImageNode.Header.SubType = MEDIA_RELATIVE_OFFSET_RANGE_DP;\r
698 SetDevicePathNodeLength (&EfiOpRomImageNode.Header, sizeof (EfiOpRomImageNode));\r
699 EfiOpRomImageNode.StartingOffset = (UINTN) RomBarOffset - (UINTN) RomBar;\r
700 EfiOpRomImageNode.EndingOffset = (UINTN) RomBarOffset + ImageSize - 1 - (UINTN) RomBar;\r
701\r
702 PciOptionRomImageDevicePath = AppendDevicePathNode (PciDevice->DevicePath, &EfiOpRomImageNode.Header);\r
703 ASSERT (PciOptionRomImageDevicePath != NULL);\r
704\r
705 //\r
706 // load image and start image\r
707 //\r
708 BufferSize = 0;\r
709 Buffer = NULL;\r
9060e3ec 710 ImageHandle = NULL;\r
711\r
a93e23f9 712 Status = gBS->LoadImage (\r
713 FALSE,\r
714 gPciBusDriverBinding.DriverBindingHandle,\r
715 PciOptionRomImageDevicePath,\r
716 Buffer,\r
717 BufferSize,\r
718 &ImageHandle\r
719 );\r
9060e3ec 720\r
721 FreePool (PciOptionRomImageDevicePath);\r
722\r
723 if (!EFI_ERROR (Status)) {\r
724 Status = gBS->StartImage (ImageHandle, NULL, NULL);\r
725 if (!EFI_ERROR (Status)) {\r
726 AddDriver (PciDevice, ImageHandle);\r
727 PciRomAddImageMapping (\r
728 ImageHandle,\r
729 PciDevice->PciRootBridgeIo->SegmentNumber,\r
730 PciDevice->BusNumber,\r
731 PciDevice->DeviceNumber,\r
732 PciDevice->FunctionNumber,\r
733 (UINT64) (UINTN) PciDevice->PciIo.RomImage,\r
734 PciDevice->PciIo.RomSize\r
735 );\r
736 RetStatus = EFI_SUCCESS;\r
737 }\r
738 }\r
739\r
a93e23f9 740NextImage:\r
9060e3ec 741 RomBarOffset += ImageSize;\r
742\r
743 } while (((Indicator & 0x80) == 0x00) && ((UINTN) (RomBarOffset - (UINT8 *) RomBar) < PciDevice->RomSize));\r
744\r
745 return RetStatus;\r
746}\r
747\r