]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyPci.c
Add RomImage pointer NULL check.
[mirror_edk2.git] / IntelFrameworkModulePkg / Csm / LegacyBiosDxe / LegacyPci.c
CommitLineData
bcecde14 1/** @file\r
2\r
3Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
4\r
5This program and the accompanying materials\r
6are licensed and made available under the terms and conditions\r
7of the BSD License which accompanies this distribution. The\r
8full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "LegacyBiosInterface.h"\r
17#include <IndustryStandard/Pci30.h>\r
18\r
19#define PCI_START_ADDRESS(x) (((x) + 0x7ff) & ~0x7ff)\r
20\r
21#define MAX_BRIDGE_INDEX 0x20\r
22typedef struct {\r
23 UINTN PciSegment;\r
24 UINTN PciBus;\r
25 UINTN PciDevice;\r
26 UINTN PciFunction;\r
27 UINT8 PrimaryBus;\r
28 UINT8 SecondaryBus;\r
29 UINT8 SubordinateBus;\r
30} BRIDGE_TABLE;\r
31\r
32#define ROM_MAX_ENTRIES 24\r
33BRIDGE_TABLE Bridges[MAX_BRIDGE_INDEX];\r
34UINTN SortedBridgeIndex[MAX_BRIDGE_INDEX];\r
35UINTN NumberOfBridges;\r
36LEGACY_PNP_EXPANSION_HEADER *mBasePnpPtr;\r
37UINT16 mBbsRomSegment;\r
38UINTN mHandleCount;\r
39EFI_HANDLE mVgaHandle;\r
40BOOLEAN mIgnoreBbsUpdateFlag;\r
41BOOLEAN mVgaInstallationInProgress = FALSE;\r
42UINT32 mRomCount = 0x00;\r
43ROM_INSTANCE_ENTRY mRomEntry[ROM_MAX_ENTRIES];\r
44\r
45\r
46/**\r
47 Query shadowed legacy ROM parameters registered by RomShadow() previously.\r
48\r
49 @param PciHandle PCI device whos ROM has been shadowed\r
50 @param DiskStart DiskStart value from EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom\r
51 @param DiskEnd DiskEnd value from EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom\r
52 @param RomShadowAddress Address where ROM was shadowed\r
53 @param ShadowedSize Runtime size of ROM\r
54\r
55 @retval EFI_SUCCESS Query Logging successful.\r
56 @retval EFI_NOT_FOUND No logged data found about PciHandle.\r
57\r
58**/\r
59EFI_STATUS\r
60GetShadowedRomParameters (\r
61 IN EFI_HANDLE PciHandle,\r
62 OUT UINT8 *DiskStart, OPTIONAL\r
63 OUT UINT8 *DiskEnd, OPTIONAL\r
64 OUT VOID **RomShadowAddress, OPTIONAL\r
65 OUT UINTN *ShadowedSize OPTIONAL\r
66 )\r
67{\r
68 EFI_STATUS Status;\r
69 EFI_PCI_IO_PROTOCOL *PciIo;\r
70 UINTN Index;\r
71 UINTN PciSegment;\r
72 UINTN PciBus;\r
73 UINTN PciDevice;\r
74 UINTN PciFunction;\r
75\r
76 //\r
77 // Get the PCI I/O Protocol on PciHandle\r
78 //\r
79 Status = gBS->HandleProtocol (\r
80 PciHandle,\r
81 &gEfiPciIoProtocolGuid,\r
82 (VOID **) &PciIo\r
83 );\r
84 if (EFI_ERROR (Status)) {\r
85 return Status;\r
86 }\r
87\r
88 //\r
89 // Get the location of the PCI device\r
90 //\r
91 PciIo->GetLocation (\r
92 PciIo,\r
93 &PciSegment,\r
94 &PciBus,\r
95 &PciDevice,\r
96 &PciFunction\r
97 );\r
98\r
99 for(Index = 0; Index < mRomCount; Index++) {\r
100 if ((mRomEntry[Index].PciSegment == PciSegment) &&\r
101 (mRomEntry[Index].PciBus == PciBus) &&\r
102 (mRomEntry[Index].PciDevice == PciDevice) &&\r
103 (mRomEntry[Index].PciFunction == PciFunction)) {\r
104 break;\r
105 }\r
106 }\r
107\r
108 if (Index == mRomCount) {\r
109 return EFI_NOT_FOUND;\r
110 }\r
111\r
112 if (DiskStart != NULL) {\r
113 *DiskStart = mRomEntry[Index].DiskStart;\r
114 }\r
115\r
116 if (DiskEnd != NULL) {\r
117 *DiskEnd = mRomEntry[Index].DiskEnd;\r
118 }\r
119\r
120 if (RomShadowAddress != NULL) {\r
121 *RomShadowAddress = (VOID *)(UINTN)mRomEntry[Index].ShadowAddress;\r
122 }\r
123\r
124 if (ShadowedSize != NULL) {\r
125 *ShadowedSize = mRomEntry[Index].ShadowedSize;\r
126 }\r
127\r
128 return EFI_SUCCESS;\r
129}\r
130\r
131/**\r
132 Every legacy ROM that is shadowed by the Legacy BIOS driver will be\r
133 registered into this API so that the policy code can know what has\r
134 happend\r
135\r
136 @param PciHandle PCI device whos ROM is being shadowed\r
137 @param ShadowAddress Address that ROM was shadowed\r
138 @param ShadowedSize Runtime size of ROM\r
139 @param DiskStart DiskStart value from\r
140 EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom\r
141 @param DiskEnd DiskEnd value from\r
142 EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom\r
143\r
144 @retval EFI_SUCCESS Logging successful.\r
145 @retval EFI_OUT_OF_RESOURCES No remaining room for registering another option\r
146 ROM.\r
147\r
148**/\r
149EFI_STATUS\r
150RomShadow (\r
151 IN EFI_HANDLE PciHandle,\r
152 IN UINT32 ShadowAddress,\r
153 IN UINT32 ShadowedSize, \r
154 IN UINT8 DiskStart,\r
155 IN UINT8 DiskEnd\r
156 )\r
157{\r
158 EFI_STATUS Status;\r
159 EFI_PCI_IO_PROTOCOL *PciIo;\r
160\r
161 //\r
162 // See if there is room to register another option ROM\r
163 //\r
164 if (mRomCount >= ROM_MAX_ENTRIES) {\r
165 return EFI_OUT_OF_RESOURCES;\r
166 }\r
167 //\r
168 // Get the PCI I/O Protocol on PciHandle\r
169 //\r
170 Status = gBS->HandleProtocol (\r
171 PciHandle,\r
172 &gEfiPciIoProtocolGuid,\r
173 (VOID **) &PciIo\r
174 );\r
175 if (EFI_ERROR (Status)) {\r
176 return Status;\r
177 }\r
178 //\r
179 // Get the location of the PCI device\r
180 //\r
181 PciIo->GetLocation (\r
182 PciIo,\r
183 &mRomEntry[mRomCount].PciSegment,\r
184 &mRomEntry[mRomCount].PciBus,\r
185 &mRomEntry[mRomCount].PciDevice,\r
186 &mRomEntry[mRomCount].PciFunction\r
187 );\r
188 mRomEntry[mRomCount].ShadowAddress = ShadowAddress;\r
189 mRomEntry[mRomCount].ShadowedSize = ShadowedSize;\r
190 mRomEntry[mRomCount].DiskStart = DiskStart;\r
191 mRomEntry[mRomCount].DiskEnd = DiskEnd;\r
192\r
193 mRomCount++;\r
194\r
195 return EFI_SUCCESS;\r
196}\r
197\r
198\r
199/**\r
200 Return EFI_SUCCESS if PciHandle has had a legacy BIOS ROM shadowed. This\r
201 information represents every call to RomShadow ()\r
202\r
203 @param PciHandle PCI device to get status for\r
204\r
205 @retval EFI_SUCCESS Legacy ROM loaded for this device\r
206 @retval EFI_NOT_FOUND No Legacy ROM loaded for this device\r
207\r
208**/\r
209EFI_STATUS\r
210IsLegacyRom (\r
211 IN EFI_HANDLE PciHandle\r
212 )\r
213{\r
214 EFI_STATUS Status;\r
215 EFI_PCI_IO_PROTOCOL *PciIo;\r
216 UINTN Index;\r
217 UINTN Segment;\r
218 UINTN Bus;\r
219 UINTN Device;\r
220 UINTN Function;\r
221\r
222 //\r
223 // Get the PCI I/O Protocol on PciHandle\r
224 //\r
225 Status = gBS->HandleProtocol (\r
226 PciHandle,\r
227 &gEfiPciIoProtocolGuid,\r
228 (VOID **) &PciIo\r
229 );\r
230 if (EFI_ERROR (Status)) {\r
231 return Status;\r
232 }\r
233 //\r
234 // Get the location of the PCI device\r
235 //\r
236 PciIo->GetLocation (\r
237 PciIo,\r
238 &Segment,\r
239 &Bus,\r
240 &Device,\r
241 &Function\r
242 );\r
243\r
244 //\r
245 // See if the option ROM from PciHandle has been previously posted\r
246 //\r
247 for (Index = 0; Index < mRomCount; Index++) {\r
248 if (mRomEntry[Index].PciSegment == Segment &&\r
249 mRomEntry[Index].PciBus == Bus &&\r
250 mRomEntry[Index].PciDevice == Device &&\r
251 mRomEntry[Index].PciFunction == Function\r
252 ) {\r
253 return EFI_SUCCESS;\r
254 }\r
255 }\r
256\r
257 return EFI_NOT_FOUND;\r
258}\r
259\r
260/**\r
261 Find the PC-AT ROM Image in the raw PCI Option ROM. Also return the \r
262 related information from the header.\r
263\r
264 @param Csm16Revision The PCI interface version of underlying CSM16\r
265 @param VendorId Vendor ID of the PCI device\r
266 @param DeviceId Device ID of the PCI device\r
267 @param Rom On input pointing to beginning of the raw PCI OpROM\r
268 On output pointing to the first legacy PCI OpROM\r
269 @param ImageSize On input is the size of Raw PCI Rom\r
270 On output is the size of the first legacy PCI ROM\r
271 @param MaxRuntimeImageLength The max runtime image length only valid if OpRomRevision >= 3\r
272 @param OpRomRevision Revision of the PCI Rom\r
273 @param ConfigUtilityCodeHeader Pointer to Configuration Utility Code Header\r
274\r
275 @retval EFI_SUCCESS Successfully find the legacy PCI ROM\r
276 @retval EFI_NOT_FOUND Failed to find the legacy PCI ROM\r
277\r
278**/\r
279EFI_STATUS\r
280GetPciLegacyRom (\r
281 IN UINT16 Csm16Revision,\r
282 IN UINT16 VendorId,\r
283 IN UINT16 DeviceId,\r
284 IN OUT VOID **Rom,\r
285 IN OUT UINTN *ImageSize,\r
286 OUT UINTN *MaxRuntimeImageLength, OPTIONAL\r
287 OUT UINT8 *OpRomRevision, OPTIONAL\r
288 OUT VOID **ConfigUtilityCodeHeader OPTIONAL\r
289 )\r
290{\r
291 BOOLEAN Match;\r
292 UINT16 *DeviceIdList;\r
293 EFI_PCI_ROM_HEADER RomHeader;\r
294 PCI_3_0_DATA_STRUCTURE *Pcir;\r
295 VOID *BackupImage;\r
296 VOID *BestImage;\r
297\r
298\r
299 if (*ImageSize < sizeof (EFI_PCI_ROM_HEADER)) {\r
300 return EFI_NOT_FOUND;\r
301 }\r
302\r
303 BestImage = NULL;\r
304 BackupImage = NULL;\r
305 RomHeader.Raw = *Rom;\r
306 while (RomHeader.Generic->Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
307 if (*ImageSize < \r
308 RomHeader.Raw - (UINT8 *) *Rom + RomHeader.Generic->PcirOffset + sizeof (PCI_DATA_STRUCTURE)\r
309 ) {\r
310 return EFI_NOT_FOUND;\r
311 }\r
312\r
313 Pcir = (PCI_3_0_DATA_STRUCTURE *) (RomHeader.Raw + RomHeader.Generic->PcirOffset);\r
314\r
315 if (Pcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {\r
316 Match = FALSE;\r
317 if (Pcir->VendorId == VendorId) {\r
318 if (Pcir->DeviceId == DeviceId) {\r
319 Match = TRUE;\r
320 } else if ((Pcir->Revision >= 3) && (Pcir->DeviceListOffset != 0)) {\r
321 DeviceIdList = (UINT16 *)(((UINT8 *) Pcir) + Pcir->DeviceListOffset);\r
322 //\r
323 // Checking the device list\r
324 //\r
325 while (*DeviceIdList != 0) {\r
326 if (*DeviceIdList == DeviceId) {\r
327 Match = TRUE;\r
328 break;\r
329 }\r
330 DeviceIdList ++;\r
331 }\r
332 }\r
333 }\r
334\r
335 if (Match) {\r
336 if (Csm16Revision >= 0x0300) {\r
337 //\r
338 // Case 1: CSM16 3.0\r
339 //\r
340 if (Pcir->Revision >= 3) {\r
341 //\r
342 // case 1.1: meets OpRom 3.0\r
343 // Perfect!!!\r
344 //\r
345 BestImage = RomHeader.Raw;\r
346 break;\r
347 } else {\r
348 //\r
349 // case 1.2: meets OpRom 2.x\r
350 // Store it and try to find the OpRom 3.0\r
351 //\r
352 BackupImage = RomHeader.Raw;\r
353 }\r
354 } else {\r
355 //\r
356 // Case 2: CSM16 2.x\r
357 //\r
358 if (Pcir->Revision >= 3) {\r
359 //\r
360 // case 2.1: meets OpRom 3.0\r
361 // Store it and try to find the OpRom 2.x\r
362 //\r
363 BackupImage = RomHeader.Raw;\r
364 } else {\r
365 //\r
366 // case 2.2: meets OpRom 2.x\r
367 // Perfect!!!\r
368 //\r
369 BestImage = RomHeader.Raw;\r
370 break;\r
371 }\r
372 }\r
373 } else {\r
374 DEBUG ((EFI_D_ERROR, "GetPciLegacyRom - OpRom not match (%04x-%04x)\n", (UINTN)VendorId, (UINTN)DeviceId));\r
375 }\r
376 }\r
377 \r
378 if ((Pcir->Indicator & 0x80) == 0x80) {\r
379 break;\r
380 } else {\r
381 RomHeader.Raw += 512 * Pcir->ImageLength;\r
382 }\r
383 }\r
384\r
385 if (BestImage == NULL) {\r
386 if (BackupImage == NULL) {\r
387 return EFI_NOT_FOUND;\r
388 }\r
389 //\r
390 // The versions of CSM16 and OpRom don't match exactly\r
391 //\r
392 BestImage = BackupImage;\r
393 }\r
394 RomHeader.Raw = BestImage;\r
395 Pcir = (PCI_3_0_DATA_STRUCTURE *) (RomHeader.Raw + RomHeader.Generic->PcirOffset);\r
396 *Rom = BestImage;\r
397 *ImageSize = Pcir->ImageLength * 512;\r
398\r
399 if (MaxRuntimeImageLength != NULL) {\r
400 if (Pcir->Revision < 3) {\r
401 *MaxRuntimeImageLength = 0;\r
402 } else {\r
403 *MaxRuntimeImageLength = Pcir->MaxRuntimeImageLength * 512;\r
404 }\r
405 }\r
406\r
407 if (OpRomRevision != NULL) {\r
408 // \r
409 // Optional return PCI Data Structure revision\r
410 //\r
411 if (Pcir->Length >= 0x1C) {\r
412 *OpRomRevision = Pcir->Revision;\r
413 } else {\r
414 *OpRomRevision = 0;\r
415 }\r
416 }\r
417\r
418 if (ConfigUtilityCodeHeader != NULL) {\r
419 //\r
420 // Optional return ConfigUtilityCodeHeaderOffset supported by the PC-AT ROM\r
421 //\r
422 if ((Pcir->Revision < 3) || (Pcir->ConfigUtilityCodeHeaderOffset == 0)) {\r
423 *ConfigUtilityCodeHeader = NULL;\r
424 } else {\r
425 *ConfigUtilityCodeHeader = RomHeader.Raw + Pcir->ConfigUtilityCodeHeaderOffset;\r
426 }\r
427 }\r
428\r
429 return EFI_SUCCESS;\r
430}\r
431\r
432/**\r
433 Build a table of bridge info for PIRQ translation.\r
434\r
435 @param RoutingTable RoutingTable obtained from Platform.\r
436 @param RoutingTableEntries Number of RoutingTable entries.\r
437\r
438 @retval EFI_SUCCESS New Subordinate bus.\r
439 @retval EFI_NOT_FOUND No more Subordinate busses.\r
440\r
441**/\r
442EFI_STATUS\r
443CreateBridgeTable (\r
444 IN EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable,\r
445 IN UINTN RoutingTableEntries\r
446 )\r
447{\r
448 EFI_STATUS Status;\r
449 UINTN HandleCount;\r
450 EFI_HANDLE *HandleBuffer;\r
451 UINTN BridgeIndex;\r
452 UINTN Index;\r
453 UINTN Index1;\r
454 EFI_PCI_IO_PROTOCOL *PciIo;\r
455 PCI_TYPE01 PciConfigHeader;\r
456 BRIDGE_TABLE SlotBridges[MAX_BRIDGE_INDEX];\r
457 UINTN SlotBridgeIndex;\r
458\r
459 BridgeIndex = 0x00;\r
460 SlotBridgeIndex = 0x00;\r
461\r
462 //\r
463 // Assumption is table is built from low bus to high bus numbers.\r
464 //\r
465 Status = gBS->LocateHandleBuffer (\r
466 ByProtocol,\r
467 &gEfiPciIoProtocolGuid,\r
468 NULL,\r
469 &HandleCount,\r
470 &HandleBuffer\r
471 );\r
472 if (EFI_ERROR (Status)) {\r
473 return EFI_NOT_FOUND;\r
474 }\r
475 for (Index = 0; Index < HandleCount; Index++) {\r
476 Status = gBS->HandleProtocol (\r
477 HandleBuffer[Index],\r
478 &gEfiPciIoProtocolGuid,\r
479 (VOID **) &PciIo\r
480 );\r
481 if (EFI_ERROR (Status)) {\r
482 continue;\r
483 }\r
484\r
485 PciIo->Pci.Read (\r
486 PciIo,\r
487 EfiPciIoWidthUint32,\r
488 0,\r
489 sizeof (PciConfigHeader) / sizeof (UINT32),\r
490 &PciConfigHeader\r
491 );\r
492\r
493 if (IS_PCI_P2P (&PciConfigHeader) && (BridgeIndex < MAX_BRIDGE_INDEX)) {\r
494 PciIo->GetLocation (\r
495 PciIo,\r
496 &Bridges[BridgeIndex].PciSegment,\r
497 &Bridges[BridgeIndex].PciBus,\r
498 &Bridges[BridgeIndex].PciDevice,\r
499 &Bridges[BridgeIndex].PciFunction\r
500 );\r
501\r
502 Bridges[BridgeIndex].PrimaryBus = PciConfigHeader.Bridge.PrimaryBus;\r
503\r
504 Bridges[BridgeIndex].SecondaryBus = PciConfigHeader.Bridge.SecondaryBus;\r
505\r
506 Bridges[BridgeIndex].SubordinateBus = PciConfigHeader.Bridge.SubordinateBus;\r
507\r
508 for (Index1 = 0; Index1 < RoutingTableEntries; Index1++){\r
509 //\r
510 // Test whether we have found the Bridge in the slot, must be the one that directly interfaced to the board\r
511 // Once we find one, store it in the SlotBridges[]\r
512 //\r
513 if ((RoutingTable[Index1].Slot != 0) && (Bridges[BridgeIndex].PrimaryBus == RoutingTable[Index1].Bus)\r
514 && ((Bridges[BridgeIndex].PciDevice << 3) == RoutingTable[Index1].Device)) {\r
515 CopyMem (&SlotBridges[SlotBridgeIndex], &Bridges[BridgeIndex], sizeof (BRIDGE_TABLE));\r
516 SlotBridgeIndex++;\r
517\r
518 break;\r
519 }\r
520 }\r
521\r
522 ++BridgeIndex;\r
523 }\r
524 }\r
525\r
526 //\r
527 // Pack up Bridges by removing those useless ones\r
528 //\r
529 for (Index = 0; Index < BridgeIndex;){\r
530 for (Index1 = 0; Index1 < SlotBridgeIndex; Index1++) {\r
531 if (((Bridges[Index].PciBus == SlotBridges[Index1].PrimaryBus) && (Bridges[Index].PciDevice == SlotBridges[Index1].PciDevice)) ||\r
532 ((Bridges[Index].PciBus >= SlotBridges[Index1].SecondaryBus) && (Bridges[Index].PciBus <= SlotBridges[Index1].SubordinateBus))) {\r
533 //\r
534 // We have found one that meets our criteria\r
535 //\r
536 Index++;\r
537 break;\r
538 }\r
539 }\r
540\r
541 //\r
542 // This one doesn't meet criteria, pack it\r
543 //\r
544 if (Index1 >= SlotBridgeIndex) {\r
545 for (Index1 = Index; BridgeIndex > 1 && Index1 < BridgeIndex - 1 ; Index1++) {\r
546 CopyMem (&Bridges[Index1], &Bridges[Index1 + 1], sizeof (BRIDGE_TABLE));\r
547 }\r
548\r
549 BridgeIndex--;\r
550 }\r
551 }\r
552\r
553 NumberOfBridges = BridgeIndex;\r
554\r
555 //\r
556 // Sort bridges low to high by Secondary bus followed by subordinate bus\r
557 //\r
558 if (NumberOfBridges > 1) {\r
559 Index = 0;\r
560 do {\r
561 SortedBridgeIndex[Index] = Index;\r
562 ++Index;\r
563 } while (Index < NumberOfBridges);\r
564\r
565 for (Index = 0; Index < NumberOfBridges - 1; Index++) {\r
566 for (Index1 = Index + 1; Index1 < NumberOfBridges; Index1++) {\r
567 if (Bridges[Index].SecondaryBus > Bridges[Index1].SecondaryBus) {\r
568 SortedBridgeIndex[Index] = Index1;\r
569 SortedBridgeIndex[Index1] = Index;\r
570 }\r
571\r
572 if ((Bridges[Index].SecondaryBus == Bridges[Index1].SecondaryBus) &&\r
573 (Bridges[Index].SubordinateBus > Bridges[Index1].SubordinateBus)\r
574 ) {\r
575 SortedBridgeIndex[Index] = Index1;\r
576 SortedBridgeIndex[Index1] = Index;\r
577 }\r
578 }\r
579 }\r
580 }\r
581 FreePool (HandleBuffer);\r
582 return EFI_SUCCESS;\r
583}\r
584\r
585\r
586/**\r
587 Find base Bridge for device.\r
588\r
589 @param Private Legacy BIOS Instance data\r
590 @param PciBus Input = Bus of device.\r
591 @param PciDevice Input = Device.\r
592 @param RoutingTable The platform specific routing table\r
593 @param RoutingTableEntries Number of entries in table\r
594\r
595 @retval EFI_SUCCESS At base bus.\r
596 @retval EFI_NOT_FOUND Behind a bridge.\r
597\r
598**/\r
599EFI_STATUS\r
600GetBaseBus (\r
601 IN LEGACY_BIOS_INSTANCE *Private,\r
602 IN UINTN PciBus,\r
603 IN UINTN PciDevice,\r
604 IN EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable,\r
605 IN UINTN RoutingTableEntries\r
606 )\r
607{\r
608 UINTN Index;\r
609 for (Index = 0; Index < RoutingTableEntries; Index++) {\r
610 if ((RoutingTable[Index].Bus == PciBus) && (RoutingTable[Index].Device == (PciDevice << 3))) {\r
611 return EFI_SUCCESS;\r
612 }\r
613 }\r
614\r
615 return EFI_NOT_FOUND;\r
616}\r
617\r
618/**\r
619 Translate PIRQ through busses\r
620\r
621 @param Private Legacy BIOS Instance data\r
622 @param PciBus Input = Bus of device. Output = Translated Bus\r
623 @param PciDevice Input = Device. Output = Translated Device\r
624 @param PciFunction Input = Function. Output = Translated Function\r
625 @param PirqIndex Input = Original PIRQ index. If single function\r
626 device then 0, otherwise 0-3.\r
627 Output = Translated Index\r
628\r
629 @retval EFI_SUCCESS Pirq successfully translated.\r
630 @retval EFI_NOT_FOUND The device is not behind any known bridge.\r
631\r
632**/\r
633EFI_STATUS\r
634TranslateBusPirq (\r
635 IN LEGACY_BIOS_INSTANCE *Private,\r
636 IN OUT UINTN *PciBus,\r
637 IN OUT UINTN *PciDevice,\r
638 IN OUT UINTN *PciFunction,\r
639 IN OUT UINT8 *PirqIndex\r
640 )\r
641{\r
642 /*\r
643 This routine traverses the PCI busses from base slot\r
644 and translates the PIRQ register to the appropriate one.\r
645\r
646 Example:\r
647\r
648 Bus 0, Device 1 is PCI-PCI bridge that all PCI slots reside on.\r
649 Primary bus# = 0\r
650 Secondary bus # = 1\r
651 Subordinate bus # is highest bus # behind this bus\r
652 Bus 1, Device 0 is Slot 0 and is not a bridge.\r
653 Bus 1, Device 1 is Slot 1 and is a bridge.\r
654 Slot PIRQ routing is A,B,C,D.\r
655 Primary bus # = 1\r
656 Secondary bus # = 2\r
657 Subordinate bus # = 5\r
658 Bus 2, Device 6 is a bridge. It has no bridges behind it.\r
659 Primary bus # = 2\r
660 Secondary bus # = 3\r
661 Subordinate bus # = 3\r
662 Bridge PIRQ routing is C,D,A,B\r
663 Bus 2, Device 7 is a bridge. It has 1 bridge behind it.\r
664 Primary bus # = 2\r
665 Secondary bus = 4 Device 6 takes bus 2.\r
666 Subordinate bus = 5.\r
667 Bridge PIRQ routing is D,A,B,C\r
668 Bus 4, Device 2 is a bridge. It has no bridges behind it.\r
669 Primary bus # = 4\r
670 Secondary bus # = 5\r
671 Subordinate bus = 5\r
672 Bridge PIRQ routing is B,C,D,A\r
673 Bus 5, Device 1 is to be programmed.\r
674 Device PIRQ routing is C,D,A,B\r
675\r
676\r
677Search busses starting from slot bus for final bus >= Secondary bus and\r
678final bus <= Suborninate bus. Assumption is bus entries increase in bus\r
679number.\r
680Starting PIRQ is A,B,C,D.\r
681Bus 2, Device 7 satisfies search criteria. Rotate (A,B,C,D) left by device\r
682 7 modulo 4 giving (D,A,B,C).\r
683Bus 4, Device 2 satisfies search criteria. Rotate (D,A,B,C) left by 2 giving\r
684 (B,C,D,A).\r
685No other busses match criteria. Device to be programmed is Bus 5, Device 1.\r
686Rotate (B,C,D,A) by 1 giving C,D,A,B. Translated PIRQ is C.\r
687\r
688*/\r
689 UINTN LocalBus;\r
690 UINTN LocalDevice;\r
691 UINTN BaseBus;\r
692 UINTN BaseDevice;\r
693 UINTN BaseFunction;\r
694 UINT8 LocalPirqIndex;\r
695 BOOLEAN BaseIndexFlag;\r
696 UINTN BridgeIndex;\r
697 UINTN SBridgeIndex;\r
698 BaseIndexFlag = FALSE;\r
699 BridgeIndex = 0x00;\r
700\r
701 LocalPirqIndex = *PirqIndex;\r
702 LocalBus = *PciBus;\r
703 LocalDevice = *PciDevice;\r
704 BaseBus = *PciBus;\r
705 BaseDevice = *PciDevice;\r
706 BaseFunction = *PciFunction;\r
707\r
708 //\r
709 // LocalPirqIndex list PIRQs in rotated fashion\r
710 // = 0 A,B,C,D\r
711 // = 1 B,C,D,A\r
712 // = 2 C,D,A,B\r
713 // = 3 D,A,B,C\r
714 //\r
715\r
716 for (BridgeIndex = 0; BridgeIndex < NumberOfBridges; BridgeIndex++) {\r
717 SBridgeIndex = SortedBridgeIndex[BridgeIndex];\r
718 //\r
719 // Check if device behind this bridge\r
720 //\r
721 if ((LocalBus >= Bridges[SBridgeIndex].SecondaryBus) && (LocalBus <= Bridges[SBridgeIndex].SubordinateBus)) {\r
722 //\r
723 // If BaseIndexFlag = FALSE then have found base bridge, i.e\r
724 // bridge in slot. Save info for use by IRQ routing table.\r
725 //\r
726 if (!BaseIndexFlag) {\r
727 BaseBus = Bridges[SBridgeIndex].PciBus;\r
728 BaseDevice = Bridges[SBridgeIndex].PciDevice;\r
729 BaseFunction = Bridges[SBridgeIndex].PciFunction;\r
730 BaseIndexFlag = TRUE;\r
731 } else {\r
732 LocalPirqIndex = (UINT8) ((LocalPirqIndex + (UINT8)Bridges[SBridgeIndex].PciDevice)%4);\r
733 }\r
734\r
735 //\r
736 // Check if at device. If not get new PCI location & PIRQ\r
737 //\r
738 if (Bridges[SBridgeIndex].SecondaryBus == (UINT8) LocalBus) {\r
739 //\r
740 // Translate PIRQ\r
741 //\r
742 LocalPirqIndex = (UINT8) ((LocalPirqIndex + (UINT8) (LocalDevice)) % 4);\r
743 break;\r
744 }\r
745 }\r
746 }\r
747\r
748 //\r
749 // In case we fail to find the Bridge just above us, this is some potential error and we want to warn the user\r
750 //\r
751 if(BridgeIndex >= NumberOfBridges){\r
752 DEBUG ((EFI_D_ERROR, "Cannot Find IRQ Routing for Bus %d, Device %d, Function %d\n", *PciBus, *PciDevice, *PciFunction));\r
753 }\r
754\r
755 *PirqIndex = LocalPirqIndex;\r
756 *PciBus = BaseBus;\r
757 *PciDevice = BaseDevice;\r
758 *PciFunction = BaseFunction;\r
759\r
760 return EFI_SUCCESS;\r
761}\r
762\r
763\r
764/**\r
765 Copy the $PIR table as required.\r
766\r
767 @param Private Legacy BIOS Instance data\r
768 @param RoutingTable Pointer to IRQ routing table\r
769 @param RoutingTableEntries IRQ routing table entries\r
770 @param PirqTable Pointer to $PIR table\r
771 @param PirqTableSize Length of table\r
772\r
773**/\r
774VOID\r
775CopyPirqTable (\r
776 IN LEGACY_BIOS_INSTANCE *Private,\r
777 IN EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable,\r
778 IN UINTN RoutingTableEntries,\r
779 IN EFI_LEGACY_PIRQ_TABLE_HEADER *PirqTable,\r
780 IN UINTN PirqTableSize\r
781 )\r
782{\r
783 EFI_IA32_REGISTER_SET Regs;\r
784 UINT32 Granularity;\r
785\r
786 //\r
787 // Copy $PIR table, if it exists.\r
788 //\r
789 if (PirqTable != NULL) {\r
790 Private->LegacyRegion->UnLock (\r
791 Private->LegacyRegion,\r
792 0xE0000,\r
793 0x20000,\r
794 &Granularity\r
795 );\r
796\r
797 Private->InternalIrqRoutingTable = RoutingTable;\r
798 Private->NumberIrqRoutingEntries = (UINT16) (RoutingTableEntries);\r
799 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
800\r
801 Regs.X.AX = Legacy16GetTableAddress;\r
802 Regs.X.CX = (UINT16) PirqTableSize;\r
803 //\r
804 // Allocate at F segment according to PCI IRQ Routing Table Specification\r
805 //\r
806 Regs.X.BX = (UINT16) 0x1;\r
807 //\r
808 // 16-byte boundary alignment requirement according to \r
809 // PCI IRQ Routing Table Specification\r
810 //\r
811 Regs.X.DX = 0x10;\r
812 Private->LegacyBios.FarCall86 (\r
813 &Private->LegacyBios,\r
814 Private->Legacy16CallSegment,\r
815 Private->Legacy16CallOffset,\r
816 &Regs,\r
817 NULL,\r
818 0\r
819 );\r
820\r
821 Private->Legacy16Table->IrqRoutingTablePointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);\r
822 if (Regs.X.AX != 0) {\r
823 DEBUG ((EFI_D_ERROR, "PIRQ table length insufficient - %x\n", PirqTableSize));\r
824 } else {\r
825 DEBUG ((EFI_D_INFO, "PIRQ table in legacy region - %x\n", Private->Legacy16Table->IrqRoutingTablePointer)); \r
826 Private->Legacy16Table->IrqRoutingTableLength = (UINT32)PirqTableSize;\r
827 CopyMem (\r
828 (VOID *) (UINTN)Private->Legacy16Table->IrqRoutingTablePointer,\r
829 PirqTable,\r
830 PirqTableSize\r
831 );\r
832 }\r
833\r
834 Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);\r
835 Private->LegacyRegion->Lock (\r
836 Private->LegacyRegion,\r
837 0xE0000,\r
838 0x20000,\r
839 &Granularity\r
840 );\r
841 }\r
842\r
843 Private->PciInterruptLine = TRUE;\r
844 mHandleCount = 0;\r
845}\r
846\r
847/**\r
848 Dump EFI_LEGACY_INSTALL_PCI_HANDLER structure information.\r
849\r
850 @param PciHandle The pointer to EFI_LEGACY_INSTALL_PCI_HANDLER structure\r
851\r
852**/\r
853VOID\r
854DumpPciHandle (\r
855 IN EFI_LEGACY_INSTALL_PCI_HANDLER *PciHandle\r
856 )\r
857{\r
858 DEBUG ((EFI_D_INFO, "PciBus - %02x\n", (UINTN)PciHandle->PciBus));\r
859 DEBUG ((EFI_D_INFO, "PciDeviceFun - %02x\n", (UINTN)PciHandle->PciDeviceFun));\r
860 DEBUG ((EFI_D_INFO, "PciSegment - %02x\n", (UINTN)PciHandle->PciSegment));\r
861 DEBUG ((EFI_D_INFO, "PciClass - %02x\n", (UINTN)PciHandle->PciClass));\r
862 DEBUG ((EFI_D_INFO, "PciSubclass - %02x\n", (UINTN)PciHandle->PciSubclass));\r
863 DEBUG ((EFI_D_INFO, "PciInterface - %02x\n", (UINTN)PciHandle->PciInterface));\r
864\r
865 DEBUG ((EFI_D_INFO, "PrimaryIrq - %02x\n", (UINTN)PciHandle->PrimaryIrq));\r
866 DEBUG ((EFI_D_INFO, "PrimaryReserved - %02x\n", (UINTN)PciHandle->PrimaryReserved));\r
867 DEBUG ((EFI_D_INFO, "PrimaryControl - %04x\n", (UINTN)PciHandle->PrimaryControl));\r
868 DEBUG ((EFI_D_INFO, "PrimaryBase - %04x\n", (UINTN)PciHandle->PrimaryBase));\r
869 DEBUG ((EFI_D_INFO, "PrimaryBusMaster - %04x\n", (UINTN)PciHandle->PrimaryBusMaster));\r
870\r
871 DEBUG ((EFI_D_INFO, "SecondaryIrq - %02x\n", (UINTN)PciHandle->SecondaryIrq));\r
872 DEBUG ((EFI_D_INFO, "SecondaryReserved - %02x\n", (UINTN)PciHandle->SecondaryReserved));\r
873 DEBUG ((EFI_D_INFO, "SecondaryControl - %04x\n", (UINTN)PciHandle->SecondaryControl));\r
874 DEBUG ((EFI_D_INFO, "SecondaryBase - %04x\n", (UINTN)PciHandle->SecondaryBase));\r
875 DEBUG ((EFI_D_INFO, "SecondaryBusMaster - %04x\n", (UINTN)PciHandle->SecondaryBusMaster));\r
876 return;\r
877}\r
878\r
879/**\r
880 Copy the $PIR table as required.\r
881\r
882 @param Private Legacy BIOS Instance data\r
883 @param PciIo Pointer to PCI_IO protocol\r
884 @param PciIrq Pci IRQ number\r
885 @param PciConfigHeader Type00 Pci configuration header\r
886\r
887**/\r
888VOID\r
889InstallLegacyIrqHandler (\r
890 IN LEGACY_BIOS_INSTANCE *Private,\r
891 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
892 IN UINT8 PciIrq,\r
893 IN PCI_TYPE00 *PciConfigHeader\r
894 )\r
895{\r
896 EFI_IA32_REGISTER_SET Regs;\r
897 UINT16 LegMask;\r
898 UINTN PciSegment;\r
899 UINTN PciBus;\r
900 UINTN PciDevice;\r
901 UINTN PciFunction;\r
902 EFI_LEGACY_8259_PROTOCOL *Legacy8259;\r
903 UINT16 PrimaryMaster;\r
904 UINT16 SecondaryMaster;\r
905 UINTN TempData;\r
906 UINTN RegisterAddress;\r
907 UINT32 Granularity;\r
908\r
909 PrimaryMaster = 0;\r
910 SecondaryMaster = 0;\r
911 Legacy8259 = Private->Legacy8259;\r
912 //\r
913 // Disable interrupt in PIC, in case shared, to prevent an\r
914 // interrupt from occuring.\r
915 //\r
916 Legacy8259->GetMask (\r
917 Legacy8259,\r
918 &LegMask,\r
919 NULL,\r
920 NULL,\r
921 NULL\r
922 );\r
923\r
924 LegMask = (UINT16) (LegMask | (UINT16) (1 << PciIrq));\r
925\r
926 Legacy8259->SetMask (\r
927 Legacy8259,\r
928 &LegMask,\r
929 NULL,\r
930 NULL,\r
931 NULL\r
932 );\r
933\r
934 PciIo->GetLocation (\r
935 PciIo,\r
936 &PciSegment,\r
937 &PciBus,\r
938 &PciDevice,\r
939 &PciFunction\r
940 );\r
941 Private->IntThunk->PciHandler.PciBus = (UINT8) PciBus;\r
942 Private->IntThunk->PciHandler.PciDeviceFun = (UINT8) ((PciDevice << 3) + PciFunction);\r
943 Private->IntThunk->PciHandler.PciSegment = (UINT8) PciSegment;\r
944 Private->IntThunk->PciHandler.PciClass = PciConfigHeader->Hdr.ClassCode[2];\r
945 Private->IntThunk->PciHandler.PciSubclass = PciConfigHeader->Hdr.ClassCode[1];\r
946 Private->IntThunk->PciHandler.PciInterface = PciConfigHeader->Hdr.ClassCode[0];\r
947\r
948 //\r
949 // Use native mode base address registers in two cases:\r
950 // 1. Programming Interface (PI) register indicates Primary Controller is\r
951 // in native mode OR\r
952 // 2. PCI device Sub Class Code is not IDE\r
953 //\r
954 Private->IntThunk->PciHandler.PrimaryBusMaster = (UINT16)(PciConfigHeader->Device.Bar[4] & 0xfffc);\r
955 if (((PciConfigHeader->Hdr.ClassCode[0] & 0x01) != 0) || (PciConfigHeader->Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE)) {\r
956 Private->IntThunk->PciHandler.PrimaryIrq = PciIrq;\r
957 Private->IntThunk->PciHandler.PrimaryBase = (UINT16) (PciConfigHeader->Device.Bar[0] & 0xfffc);\r
958 Private->IntThunk->PciHandler.PrimaryControl = (UINT16) ((PciConfigHeader->Device.Bar[1] & 0xfffc) + 2);\r
959 } else {\r
960 Private->IntThunk->PciHandler.PrimaryIrq = 14;\r
961 Private->IntThunk->PciHandler.PrimaryBase = 0x1f0;\r
962 Private->IntThunk->PciHandler.PrimaryControl = 0x3f6;\r
963 }\r
964 //\r
965 // Secondary controller data\r
966 //\r
967 if (Private->IntThunk->PciHandler.PrimaryBusMaster != 0) {\r
968 Private->IntThunk->PciHandler.SecondaryBusMaster = (UINT16) ((PciConfigHeader->Device.Bar[4] & 0xfffc) + 8);\r
969 PrimaryMaster = (UINT16) (Private->IntThunk->PciHandler.PrimaryBusMaster + 2);\r
970 SecondaryMaster = (UINT16) (Private->IntThunk->PciHandler.SecondaryBusMaster + 2);\r
971\r
972 //\r
973 // Clear pending interrupts in Bus Master registers\r
974 //\r
975 IoWrite16 (PrimaryMaster, 0x04);\r
976 IoWrite16 (SecondaryMaster, 0x04);\r
977\r
978 }\r
979\r
980 //\r
981 // Use native mode base address registers in two cases:\r
982 // 1. Programming Interface (PI) register indicates Secondary Controller is\r
983 // in native mode OR\r
984 // 2. PCI device Sub Class Code is not IDE\r
985 //\r
986 if (((PciConfigHeader->Hdr.ClassCode[0] & 0x04) != 0) || (PciConfigHeader->Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE)) {\r
987 Private->IntThunk->PciHandler.SecondaryIrq = PciIrq;\r
988 Private->IntThunk->PciHandler.SecondaryBase = (UINT16) (PciConfigHeader->Device.Bar[2] & 0xfffc);\r
989 Private->IntThunk->PciHandler.SecondaryControl = (UINT16) ((PciConfigHeader->Device.Bar[3] & 0xfffc) + 2);\r
990 } else {\r
991\r
992 Private->IntThunk->PciHandler.SecondaryIrq = 15;\r
993 Private->IntThunk->PciHandler.SecondaryBase = 0x170;\r
994 Private->IntThunk->PciHandler.SecondaryControl = 0x376;\r
995 }\r
996\r
997 //\r
998 // Clear pending interrupts in IDE Command Block Status reg before we\r
999 // Thunk to CSM16 below. Don't want a pending Interrupt before we\r
1000 // install the handlers as wierd corruption would occur and hang system.\r
1001 //\r
1002 //\r
1003 // Read IDE CMD blk status reg to clear out any pending interrupts.\r
1004 // Do here for Primary and Secondary IDE channels\r
1005 //\r
1006 RegisterAddress = (UINT16)Private->IntThunk->PciHandler.PrimaryBase + 0x07;\r
1007 IoRead8 (RegisterAddress);\r
1008 RegisterAddress = (UINT16)Private->IntThunk->PciHandler.SecondaryBase + 0x07;\r
1009 IoRead8 (RegisterAddress);\r
1010\r
1011 Private->IntThunk->PciHandler.PrimaryReserved = 0;\r
1012 Private->IntThunk->PciHandler.SecondaryReserved = 0;\r
1013 Private->LegacyRegion->UnLock (\r
1014 Private->LegacyRegion,\r
1015 0xE0000,\r
1016 0x20000,\r
1017 &Granularity\r
1018 );\r
1019\r
1020 Regs.X.AX = Legacy16InstallPciHandler;\r
1021 TempData = (UINTN) &Private->IntThunk->PciHandler;\r
1022 Regs.X.ES = EFI_SEGMENT ((UINT32) TempData);\r
1023 Regs.X.BX = EFI_OFFSET ((UINT32) TempData);\r
1024\r
1025 DumpPciHandle (&Private->IntThunk->PciHandler);\r
1026\r
1027 Private->LegacyBios.FarCall86 (\r
1028 &Private->LegacyBios,\r
1029 Private->Legacy16CallSegment,\r
1030 Private->Legacy16CallOffset,\r
1031 &Regs,\r
1032 NULL,\r
1033 0\r
1034 );\r
1035\r
1036 Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);\r
1037 Private->LegacyRegion->Lock (\r
1038 Private->LegacyRegion,\r
1039 0xE0000,\r
1040 0x20000,\r
1041 &Granularity\r
1042 );\r
1043\r
1044}\r
1045\r
1046\r
1047/**\r
1048 Program the interrupt routing register in all the PCI devices. On a PC AT system\r
1049 this register contains the 8259 IRQ vector that matches it's PCI interrupt.\r
1050\r
1051 @param Private Legacy BIOS Instance data\r
1052\r
1053 @retval EFI_SUCCESS Succeed.\r
1054 @retval EFI_ALREADY_STARTED All PCI devices have been processed.\r
1055\r
1056**/\r
1057EFI_STATUS\r
1058PciProgramAllInterruptLineRegisters (\r
1059 IN LEGACY_BIOS_INSTANCE *Private\r
1060 )\r
1061{\r
1062 EFI_STATUS Status;\r
1063 EFI_PCI_IO_PROTOCOL *PciIo;\r
1064 EFI_LEGACY_8259_PROTOCOL *Legacy8259;\r
1065 EFI_LEGACY_INTERRUPT_PROTOCOL *LegacyInterrupt;\r
1066 EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;\r
1067 UINT8 InterruptPin;\r
1068 UINTN Index;\r
1069 UINTN HandleCount;\r
1070 EFI_HANDLE *HandleBuffer;\r
1071 UINTN MassStorageHandleCount;\r
1072 EFI_HANDLE *MassStorageHandleBuffer;\r
1073 UINTN MassStorageHandleIndex;\r
1074 UINT8 PciIrq;\r
1075 UINT16 Command;\r
1076 UINTN PciSegment;\r
1077 UINTN PciBus;\r
1078 UINTN PciDevice;\r
1079 UINTN PciFunction;\r
1080 EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable;\r
1081 UINTN RoutingTableEntries;\r
1082 UINT16 LegMask;\r
1083 UINT16 LegEdgeLevel;\r
1084 PCI_TYPE00 PciConfigHeader;\r
1085 EFI_LEGACY_PIRQ_TABLE_HEADER *PirqTable;\r
1086 UINTN PirqTableSize;\r
1087 UINTN Flags;\r
1088 HDD_INFO *HddInfo;\r
1089 UINT64 Supports;\r
1090\r
1091 //\r
1092 // Note - This routine use to return immediately if Private->PciInterruptLine\r
1093 // was true. Routine changed since resets etc can cause not all\r
1094 // PciIo protocols to be registered the first time through.\r
1095 // New algorithm is to do the copy $PIR table on first pass and save\r
1096 // HandleCount on first pass. If subsequent passes LocateHandleBuffer gives\r
1097 // a larger handle count then proceed with body of function else return\r
1098 // EFI_ALREADY_STARTED. In addition check if PCI device InterruptLine != 0.\r
1099 // If zero then function unprogrammed else skip function.\r
1100 //\r
1101 Legacy8259 = Private->Legacy8259;\r
1102 LegacyInterrupt = Private->LegacyInterrupt;\r
1103 LegacyBiosPlatform = Private->LegacyBiosPlatform;\r
1104\r
1105 LegacyBiosPlatform->GetRoutingTable (\r
1106 Private->LegacyBiosPlatform,\r
1107 (VOID *) &RoutingTable,\r
1108 &RoutingTableEntries,\r
1109 (VOID *) &PirqTable,\r
1110 &PirqTableSize,\r
1111 NULL,\r
1112 NULL\r
1113 );\r
1114 CreateBridgeTable (RoutingTable, RoutingTableEntries);\r
1115\r
1116 if (!Private->PciInterruptLine) {\r
1117 CopyPirqTable (\r
1118 Private,\r
1119 RoutingTable,\r
1120 RoutingTableEntries,\r
1121 PirqTable,\r
1122 PirqTableSize\r
1123 );\r
1124 }\r
1125\r
1126 Status = gBS->LocateHandleBuffer (\r
1127 ByProtocol,\r
1128 &gEfiPciIoProtocolGuid,\r
1129 NULL,\r
1130 &HandleCount,\r
1131 &HandleBuffer\r
1132 );\r
1133 if (EFI_ERROR (Status)) {\r
1134 return EFI_NOT_FOUND;\r
1135 }\r
1136 if (HandleCount == mHandleCount) {\r
1137 FreePool (HandleBuffer);\r
1138 return EFI_ALREADY_STARTED;\r
1139 }\r
1140\r
1141 if (mHandleCount == 0x00) {\r
1142 mHandleCount = HandleCount;\r
1143 }\r
1144\r
1145 for (Index = 0; Index < HandleCount; Index++) {\r
1146 //\r
1147 // If VGA then only do VGA to allow drives fore time to spin up\r
1148 // otherwise assign PCI IRQs to all potential devices.\r
1149 //\r
1150 if ((mVgaInstallationInProgress) && (HandleBuffer[Index] != mVgaHandle)) {\r
1151 continue;\r
1152 } else {\r
1153 //\r
1154 // Force code to go through all handles next time called if video.\r
1155 // This will catch case where HandleCount doesn't change but want\r
1156 // to get drive info etc.\r
1157 //\r
1158 mHandleCount = 0x00;\r
1159 }\r
1160\r
1161 Status = gBS->HandleProtocol (\r
1162 HandleBuffer[Index],\r
1163 &gEfiPciIoProtocolGuid,\r
1164 (VOID **) &PciIo\r
1165 );\r
1166 ASSERT_EFI_ERROR (Status);\r
1167\r
1168 //\r
1169 // Test whether the device can be enabled or not.\r
1170 // If it can't be enabled, then just skip it to avoid further operation.\r
1171 //\r
1172 PciIo->Pci.Read (\r
1173 PciIo,\r
1174 EfiPciIoWidthUint32,\r
1175 0,\r
1176 sizeof (PciConfigHeader) / sizeof (UINT32),\r
1177 &PciConfigHeader\r
1178 );\r
1179 Command = PciConfigHeader.Hdr.Command;\r
1180\r
1181 //\r
1182 // Note PciIo->Attributes does not program the PCI command register\r
1183 //\r
1184 Status = PciIo->Attributes (\r
1185 PciIo,\r
1186 EfiPciIoAttributeOperationSupported,\r
1187 0,\r
1188 &Supports\r
1189 );\r
1190 if (!EFI_ERROR (Status)) {\r
1191 Supports &= EFI_PCI_DEVICE_ENABLE;\r
1192 Status = PciIo->Attributes (\r
1193 PciIo,\r
1194 EfiPciIoAttributeOperationEnable,\r
1195 Supports,\r
1196 NULL\r
1197 );\r
1198 }\r
1199 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x04, 1, &Command);\r
1200\r
1201 if (EFI_ERROR (Status)) {\r
1202 continue;\r
1203 }\r
1204\r
1205 InterruptPin = PciConfigHeader.Device.InterruptPin;\r
1206\r
1207 if ((InterruptPin != 0) && (PciConfigHeader.Device.InterruptLine == PCI_INT_LINE_UNKNOWN)) {\r
1208 PciIo->GetLocation (\r
1209 PciIo,\r
1210 &PciSegment,\r
1211 &PciBus,\r
1212 &PciDevice,\r
1213 &PciFunction\r
1214 );\r
1215 //\r
1216 // Translate PIRQ index back thru busses to slot bus with InterruptPin\r
1217 // zero based\r
1218 //\r
1219 InterruptPin -= 1;\r
1220\r
1221 Status = GetBaseBus (\r
1222 Private,\r
1223 PciBus,\r
1224 PciDevice,\r
1225 RoutingTable,\r
1226 RoutingTableEntries\r
1227 );\r
1228\r
1229 if (Status == EFI_NOT_FOUND) {\r
1230 TranslateBusPirq (\r
1231 Private,\r
1232 &PciBus,\r
1233 &PciDevice,\r
1234 &PciFunction,\r
1235 &InterruptPin\r
1236 );\r
1237 }\r
1238 //\r
1239 // Translate InterruptPin(0-3) into PIRQ\r
1240 //\r
1241 Status = LegacyBiosPlatform->TranslatePirq (\r
1242 LegacyBiosPlatform,\r
1243 PciBus,\r
1244 (PciDevice << 3),\r
1245 PciFunction,\r
1246 &InterruptPin,\r
1247 &PciIrq\r
1248 );\r
1249 //\r
1250 // TranslatePirq() should never fail or we are in trouble\r
1251 // If it does return failure status, check your PIRQ routing table to see if some item is missing or incorrect\r
1252 //\r
1253 if (EFI_ERROR (Status)) {\r
1254 DEBUG ((EFI_D_ERROR, "Translate Pirq Failed - Status = %r\n ", Status));\r
1255 continue;\r
1256 }\r
1257\r
1258 LegacyInterrupt->WritePirq (\r
1259 LegacyInterrupt,\r
1260 InterruptPin,\r
1261 PciIrq\r
1262 );\r
1263\r
1264 //\r
1265 // Check if device has an OPROM associated with it.\r
1266 // If not invoke special 16-bit function, to allow 16-bit\r
1267 // code to install an interrupt handler.\r
1268 //\r
1269 Status = LegacyBiosCheckPciRom (\r
1270 &Private->LegacyBios,\r
1271 HandleBuffer[Index],\r
1272 NULL,\r
1273 NULL,\r
1274 &Flags\r
1275 );\r
1276 if ((EFI_ERROR (Status)) && (PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE)) {\r
1277 //\r
1278 // Device has no OPROM associated with it and is a mass storage\r
1279 // device. It needs to have an PCI IRQ handler installed. To\r
1280 // correctly install the handler we need to insure device is\r
1281 // connected. The device may just have register itself but not\r
1282 // been connected. Re-read PCI config space after as it can\r
1283 // change\r
1284 //\r
1285 //\r
1286 // Get IDE Handle. If matches handle then skip ConnectController\r
1287 // since ConnectController may force native mode and we don't\r
1288 // want that for primary IDE controller\r
1289 //\r
1290 MassStorageHandleCount = 0;\r
1291 MassStorageHandleBuffer = NULL;\r
1292 LegacyBiosPlatform->GetPlatformHandle (\r
1293 Private->LegacyBiosPlatform,\r
1294 EfiGetPlatformIdeHandle,\r
1295 0,\r
1296 &MassStorageHandleBuffer,\r
1297 &MassStorageHandleCount,\r
1298 NULL\r
1299 );\r
1300\r
1301 HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0];\r
1302\r
1303 LegacyBiosBuildIdeData (Private, &HddInfo, 0);\r
1304 PciIo->Pci.Read (\r
1305 PciIo,\r
1306 EfiPciIoWidthUint32,\r
1307 0,\r
1308 sizeof (PciConfigHeader) / sizeof (UINT32),\r
1309 &PciConfigHeader\r
1310 );\r
1311\r
1312 for (MassStorageHandleIndex = 0; MassStorageHandleIndex < MassStorageHandleCount; MassStorageHandleIndex++) {\r
1313 if (MassStorageHandleBuffer[MassStorageHandleIndex] == HandleBuffer[Index]) {\r
1314 //\r
1315 // InstallLegacyIrqHandler according to Platform requirement\r
1316 //\r
1317 InstallLegacyIrqHandler (\r
1318 Private,\r
1319 PciIo,\r
1320 PciIrq,\r
1321 &PciConfigHeader\r
1322 );\r
1323 break;\r
1324 }\r
1325 }\r
1326 }\r
1327 //\r
1328 // Write InterruptPin and enable 8259.\r
1329 //\r
1330 PciIo->Pci.Write (\r
1331 PciIo,\r
1332 EfiPciIoWidthUint8,\r
1333 0x3c,\r
1334 1,\r
1335 &PciIrq\r
1336 );\r
1337 Private->IntThunk->EfiToLegacy16BootTable.PciIrqMask = (UINT16) (Private->IntThunk->EfiToLegacy16BootTable.PciIrqMask | (UINT16) (1 << PciIrq));\r
1338\r
1339 Legacy8259->GetMask (\r
1340 Legacy8259,\r
1341 &LegMask,\r
1342 &LegEdgeLevel,\r
1343 NULL,\r
1344 NULL\r
1345 );\r
1346\r
1347 LegMask = (UINT16) (LegMask & (UINT16)~(1 << PciIrq));\r
1348 LegEdgeLevel = (UINT16) (LegEdgeLevel | (UINT16) (1 << PciIrq));\r
1349 Legacy8259->SetMask (\r
1350 Legacy8259,\r
1351 &LegMask,\r
1352 &LegEdgeLevel,\r
1353 NULL,\r
1354 NULL\r
1355 );\r
1356 }\r
1357 }\r
1358 FreePool (HandleBuffer);\r
1359 return EFI_SUCCESS;\r
1360}\r
1361\r
1362\r
1363/**\r
1364 Find & verify PnP Expansion header in ROM image\r
1365\r
1366 @param Private Protocol instance pointer.\r
1367 @param FirstHeader 1 = Find first header, 0 = Find successive headers\r
1368 @param PnpPtr Input Rom start if FirstHeader =1, Current Header\r
1369 otherwise Output Next header, if it exists\r
1370\r
1371 @retval EFI_SUCCESS Next Header found at BasePnpPtr\r
1372 @retval EFI_NOT_FOUND No more headers\r
1373\r
1374**/\r
1375EFI_STATUS\r
1376FindNextPnpExpansionHeader (\r
1377 IN LEGACY_BIOS_INSTANCE *Private,\r
1378 IN BOOLEAN FirstHeader,\r
1379 IN OUT LEGACY_PNP_EXPANSION_HEADER **PnpPtr\r
1380\r
1381 )\r
1382{\r
1383 UINTN TempData;\r
1384 LEGACY_PNP_EXPANSION_HEADER *LocalPnpPtr;\r
1385 LocalPnpPtr = *PnpPtr;\r
1386 if (FirstHeader == FIRST_INSTANCE) {\r
1387 mBasePnpPtr = LocalPnpPtr;\r
1388 mBbsRomSegment = (UINT16) ((UINTN) mBasePnpPtr >> 4);\r
1389 //\r
1390 // Offset 0x1a gives offset to PnP expansion header for the first\r
1391 // instance, there after the structure gives the offset to the next\r
1392 // structure\r
1393 //\r
1394 LocalPnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) ((UINT8 *) LocalPnpPtr + 0x1a);\r
1395 TempData = (*((UINT16 *) LocalPnpPtr));\r
1396 } else {\r
1397 TempData = (UINT16) LocalPnpPtr->NextHeader;\r
1398 }\r
1399\r
1400 LocalPnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) (((UINT8 *) mBasePnpPtr + TempData));\r
1401\r
1402 //\r
1403 // Search for PnP table in Shadowed ROM\r
1404 //\r
1405 *PnpPtr = LocalPnpPtr;\r
1406 if (*(UINT32 *) LocalPnpPtr == SIGNATURE_32 ('$', 'P', 'n', 'P')) {\r
1407 return EFI_SUCCESS;\r
1408 } else {\r
1409 return EFI_NOT_FOUND;\r
1410 }\r
1411}\r
1412\r
1413\r
1414/**\r
1415 Update list of Bev or BCV table entries.\r
1416\r
1417 @param Private Protocol instance pointer.\r
1418 @param RomStart Table of ROM start address in RAM/ROM. PciIo _\r
1419 Handle to PCI IO for this device\r
1420 @param PciIo Instance of PCI I/O Protocol\r
1421\r
1422 @retval EFI_SUCCESS Always should succeed.\r
1423\r
1424**/\r
1425EFI_STATUS\r
1426UpdateBevBcvTable (\r
1427 IN LEGACY_BIOS_INSTANCE *Private,\r
1428 IN EFI_LEGACY_EXPANSION_ROM_HEADER *RomStart,\r
1429 IN EFI_PCI_IO_PROTOCOL *PciIo\r
1430 )\r
1431{\r
1432 VOID *RomEnd;\r
1433 BBS_TABLE *BbsTable;\r
1434 UINTN BbsIndex;\r
1435 EFI_LEGACY_EXPANSION_ROM_HEADER *PciPtr;\r
1436 LEGACY_PNP_EXPANSION_HEADER *PnpPtr;\r
1437 BOOLEAN Instance;\r
1438 EFI_STATUS Status;\r
1439 UINTN Segment;\r
1440 UINTN Bus;\r
1441 UINTN Device;\r
1442 UINTN Function;\r
1443 UINT8 Class;\r
1444 UINT16 DeviceType;\r
1445 Segment = 0;\r
1446 Bus = 0;\r
1447 Device = 0;\r
1448 Function = 0;\r
1449 Class = 0;\r
1450 DeviceType = BBS_UNKNOWN;\r
1451\r
1452 //\r
1453 // Skip floppy and 2*onboard IDE controller entries(Master/Slave per\r
1454 // controller).\r
1455 //\r
1456 BbsIndex = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;\r
1457\r
1458 BbsTable = (BBS_TABLE*)(UINTN) Private->IntThunk->EfiToLegacy16BootTable.BbsTable;\r
1459 PnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) RomStart;\r
1460 PciPtr = (EFI_LEGACY_EXPANSION_ROM_HEADER *) RomStart;\r
1461\r
1462 RomEnd = (VOID *) (PciPtr->Size512 * 512 + (UINTN) PciPtr);\r
1463 Instance = FIRST_INSTANCE;\r
1464 //\r
1465 // OPROMs like PXE may not be tied to a piece of hardware and thus\r
1466 // don't have a PciIo associated with them\r
1467 //\r
1468 if (PciIo != NULL) {\r
1469 PciIo->GetLocation (\r
1470 PciIo,\r
1471 &Segment,\r
1472 &Bus,\r
1473 &Device,\r
1474 &Function\r
1475 );\r
1476 PciIo->Pci.Read (\r
1477 PciIo,\r
1478 EfiPciIoWidthUint8,\r
1479 0x0b,\r
1480 1,\r
1481 &Class\r
1482 );\r
1483\r
1484 if (Class == PCI_CLASS_MASS_STORAGE) {\r
1485 DeviceType = BBS_HARDDISK;\r
1486 } else {\r
1487 if (Class == PCI_CLASS_NETWORK) {\r
1488 DeviceType = BBS_EMBED_NETWORK;\r
1489 }\r
1490 }\r
1491 }\r
1492\r
1493 if (PciPtr >= (EFI_LEGACY_EXPANSION_ROM_HEADER *) ((UINTN) 0xc8000)) {\r
1494 while (TRUE) {\r
1495 Status = FindNextPnpExpansionHeader (Private, Instance, &PnpPtr);\r
1496 Instance = NOT_FIRST_INSTANCE;\r
1497 if (EFI_ERROR (Status)) {\r
1498 break;\r
1499 }\r
1500 //\r
1501 // There can be additional $PnP headers within the OPROM.\r
1502 // Example: SCSI can have one per drive.\r
1503 //\r
1504 BbsTable[BbsIndex].BootPriority = BBS_UNPRIORITIZED_ENTRY;\r
1505 BbsTable[BbsIndex].DeviceType = DeviceType;\r
1506 BbsTable[BbsIndex].Bus = (UINT32) Bus;\r
1507 BbsTable[BbsIndex].Device = (UINT32) Device;\r
1508 BbsTable[BbsIndex].Function = (UINT32) Function;\r
1509 BbsTable[BbsIndex].StatusFlags.OldPosition = 0;\r
1510 BbsTable[BbsIndex].StatusFlags.Reserved1 = 0;\r
1511 BbsTable[BbsIndex].StatusFlags.Enabled = 0;\r
1512 BbsTable[BbsIndex].StatusFlags.Failed = 0;\r
1513 BbsTable[BbsIndex].StatusFlags.MediaPresent = 0;\r
1514 BbsTable[BbsIndex].StatusFlags.Reserved2 = 0;\r
1515 BbsTable[BbsIndex].Class = PnpPtr->Class;\r
1516 BbsTable[BbsIndex].SubClass = PnpPtr->SubClass;\r
1517 BbsTable[BbsIndex].DescStringOffset = PnpPtr->ProductNamePointer;\r
1518 BbsTable[BbsIndex].DescStringSegment = mBbsRomSegment;\r
1519 BbsTable[BbsIndex].MfgStringOffset = PnpPtr->MfgPointer;\r
1520 BbsTable[BbsIndex].MfgStringSegment = mBbsRomSegment;\r
1521 BbsTable[BbsIndex].BootHandlerSegment = mBbsRomSegment;\r
1522\r
1523 //\r
1524 // Have seen case where PXE base code have PnP expansion ROM\r
1525 // header but no Bcv or Bev vectors.\r
1526 //\r
1527 if (PnpPtr->Bcv != 0) {\r
1528 BbsTable[BbsIndex].BootHandlerOffset = PnpPtr->Bcv;\r
1529 ++BbsIndex;\r
1530 }\r
1531\r
1532 if (PnpPtr->Bev != 0) {\r
1533 BbsTable[BbsIndex].BootHandlerOffset = PnpPtr->Bev;\r
1534 BbsTable[BbsIndex].DeviceType = BBS_BEV_DEVICE;\r
1535 ++BbsIndex;\r
1536 }\r
1537\r
1538 if ((PnpPtr == (LEGACY_PNP_EXPANSION_HEADER *) PciPtr) || (PnpPtr > (LEGACY_PNP_EXPANSION_HEADER *) RomEnd)) {\r
1539 break;\r
1540 }\r
1541 }\r
1542 }\r
1543\r
1544 BbsTable[BbsIndex].BootPriority = BBS_IGNORE_ENTRY;\r
1545 Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries = (UINT32) BbsIndex;\r
1546 return EFI_SUCCESS;\r
1547}\r
1548\r
1549\r
1550/**\r
1551 Shadow all the PCI legacy ROMs. Use data from the Legacy BIOS Protocol\r
1552 to chose the order. Skip any devices that have already have legacy\r
1553 BIOS run.\r
1554\r
1555 @param Private Protocol instance pointer.\r
1556\r
1557 @retval EFI_SUCCESS Succeed.\r
1558 @retval EFI_UNSUPPORTED Cannot get VGA device handle.\r
1559\r
1560**/\r
1561EFI_STATUS\r
1562PciShadowRoms (\r
1563 IN LEGACY_BIOS_INSTANCE *Private\r
1564 )\r
1565{\r
1566 EFI_STATUS Status;\r
1567 EFI_PCI_IO_PROTOCOL *PciIo;\r
1568 PCI_TYPE00 Pci;\r
1569 UINTN Index;\r
1570 UINTN HandleCount;\r
1571 EFI_HANDLE *HandleBuffer;\r
1572 EFI_HANDLE VgaHandle;\r
1573 EFI_HANDLE FirstHandle;\r
1574 VOID **RomStart;\r
1575 UINTN Flags;\r
1576 PCI_TYPE00 PciConfigHeader;\r
1577 UINT16 *Command;\r
1578 UINT64 Supports;\r
1579\r
1580 //\r
1581 // Make the VGA device first\r
1582 //\r
1583 Status = Private->LegacyBiosPlatform->GetPlatformHandle (\r
1584 Private->LegacyBiosPlatform,\r
1585 EfiGetPlatformVgaHandle,\r
1586 0,\r
1587 &HandleBuffer,\r
1588 &HandleCount,\r
1589 NULL\r
1590 ); \r
1591 if (EFI_ERROR (Status)) {\r
1592 return EFI_UNSUPPORTED;\r
1593 }\r
1594 \r
1595 VgaHandle = HandleBuffer[0];\r
1596\r
1597 Status = gBS->LocateHandleBuffer (\r
1598 ByProtocol,\r
1599 &gEfiPciIoProtocolGuid,\r
1600 NULL,\r
1601 &HandleCount,\r
1602 &HandleBuffer\r
1603 );\r
1604\r
1605 if (EFI_ERROR (Status)) {\r
1606 return Status;\r
1607 }\r
1608 //\r
1609 // Place the VGA handle as first.\r
1610 //\r
1611 for (Index = 0; Index < HandleCount; Index++) {\r
1612 if (HandleBuffer[Index] == VgaHandle) {\r
1613 FirstHandle = HandleBuffer[0];\r
1614 HandleBuffer[0] = HandleBuffer[Index];\r
1615 HandleBuffer[Index] = FirstHandle;\r
1616 break;\r
1617 }\r
1618 }\r
1619 //\r
1620 // Allocate memory to save Command WORD from each device. We do this\r
1621 // to restore devices to same state as EFI after switching to legacy.\r
1622 //\r
1623 Command = (UINT16 *) AllocatePool (\r
1624 sizeof (UINT16) * (HandleCount + 1)\r
1625 );\r
1626 if (NULL == Command) {\r
1627 FreePool (HandleBuffer);\r
1628 return EFI_OUT_OF_RESOURCES;\r
1629 }\r
1630 //\r
1631 // Disconnect all EFI devices first. This covers cases where alegacy BIOS\r
1632 // may control multiple PCI devices.\r
1633 //\r
1634 for (Index = 0; Index < HandleCount; Index++) {\r
1635\r
1636 Status = gBS->HandleProtocol (\r
1637 HandleBuffer[Index],\r
1638 &gEfiPciIoProtocolGuid,\r
1639 (VOID **) &PciIo\r
1640 );\r
1641 ASSERT_EFI_ERROR (Status);\r
1642\r
1643 //\r
1644 // Save command register for "connect" loop\r
1645 //\r
1646 PciIo->Pci.Read (\r
1647 PciIo,\r
1648 EfiPciIoWidthUint32,\r
1649 0,\r
1650 sizeof (PciConfigHeader) / sizeof (UINT32),\r
1651 &PciConfigHeader\r
1652 );\r
1653 Command[Index] = PciConfigHeader.Hdr.Command;\r
1654 //\r
1655 // Skip any device that already has a legacy ROM run\r
1656 //\r
1657 Status = IsLegacyRom (HandleBuffer[Index]);\r
1658 if (!EFI_ERROR (Status)) {\r
1659 continue;\r
1660 }\r
1661 //\r
1662 // Stop EFI Drivers with oprom.\r
1663 //\r
1664 gBS->DisconnectController (\r
1665 HandleBuffer[Index],\r
1666 NULL,\r
1667 NULL\r
1668 );\r
1669 }\r
1670 //\r
1671 // For every device that has not had a legacy ROM started. Start a legacy ROM.\r
1672 //\r
1673 for (Index = 0; Index < HandleCount; Index++) {\r
1674\r
1675 Status = gBS->HandleProtocol (\r
1676 HandleBuffer[Index],\r
1677 &gEfiPciIoProtocolGuid,\r
1678 (VOID **) &PciIo\r
1679 );\r
1680\r
1681 ASSERT_EFI_ERROR (Status);\r
1682\r
1683 //\r
1684 // Here make sure if one VGA have been shadowed,\r
1685 // then wil not shadowed another one.\r
1686 //\r
1687 PciIo->Pci.Read (\r
1688 PciIo,\r
1689 EfiPciIoWidthUint32,\r
1690 0,\r
1691 sizeof (Pci) / sizeof (UINT32),\r
1692 &Pci\r
1693 );\r
1694 \r
1695 //\r
1696 // Only one Video OPROM can be given control in BIOS phase. If there are multiple Video devices, \r
1697 // one will work in legacy mode (OPROM will be given control) and \r
1698 // other Video devices will work in native mode (OS driver will handle these devices).\r
1699 // \r
1700 if (IS_PCI_DISPLAY (&Pci) && Index != 0) { \r
1701 continue;\r
1702 }\r
1703 //\r
1704 // Skip any device that already has a legacy ROM run\r
1705 //\r
1706 Status = IsLegacyRom (HandleBuffer[Index]);\r
1707 if (!EFI_ERROR (Status)) {\r
1708 continue;\r
1709 }\r
1710 //\r
1711 // Install legacy ROM\r
1712 //\r
1713 Status = LegacyBiosInstallPciRom (\r
1714 &Private->LegacyBios,\r
1715 HandleBuffer[Index],\r
1716 NULL,\r
1717 &Flags,\r
1718 NULL,\r
1719 NULL,\r
1720 (VOID **) &RomStart,\r
1721 NULL\r
1722 );\r
1723 if (EFI_ERROR (Status)) {\r
1724 if (!((Status == EFI_UNSUPPORTED) && (Flags == NO_ROM))) {\r
1725 continue;\r
1726 }\r
1727 }\r
1728 //\r
1729 // Restore Command register so legacy has same devices enabled or disabled\r
1730 // as EFI.\r
1731 // If Flags = NO_ROM use command register as is. This covers the\r
1732 // following cases:\r
1733 // Device has no ROMs associated with it.\r
1734 // Device has ROM associated with it but was already\r
1735 // installed.\r
1736 // = ROM_FOUND but not VALID_LEGACY_ROM, disable it.\r
1737 // = ROM_FOUND and VALID_LEGACY_ROM, enable it.\r
1738 //\r
1739 if ((Flags & ROM_FOUND) == ROM_FOUND) {\r
1740 if ((Flags & VALID_LEGACY_ROM) == 0) {\r
1741 Command[Index] = 0;\r
1742 } else {\r
1743 //\r
1744 // For several VGAs, only one of them can be enabled.\r
1745 //\r
1746 Status = PciIo->Attributes (\r
1747 PciIo,\r
1748 EfiPciIoAttributeOperationSupported,\r
1749 0,\r
1750 &Supports\r
1751 );\r
1752 if (!EFI_ERROR (Status)) {\r
1753 Supports &= EFI_PCI_DEVICE_ENABLE;\r
1754 Status = PciIo->Attributes (\r
1755 PciIo,\r
1756 EfiPciIoAttributeOperationEnable,\r
1757 Supports,\r
1758 NULL\r
1759 );\r
1760 }\r
1761 if (!EFI_ERROR (Status)) {\r
1762 Command[Index] = 0x1f;\r
1763 }\r
1764 }\r
1765 }\r
1766\r
1767 PciIo->Pci.Write (\r
1768 PciIo,\r
1769 EfiPciIoWidthUint16,\r
1770 0x04,\r
1771 1,\r
1772 &Command[Index]\r
1773 );\r
1774 }\r
1775\r
1776 FreePool (Command);\r
1777 FreePool (HandleBuffer);\r
1778 return EFI_SUCCESS;\r
1779}\r
1780\r
1781\r
1782/**\r
1783 Test to see if a legacy PCI ROM exists for this device. Optionally return\r
1784 the Legacy ROM instance for this PCI device.\r
1785\r
1786 @param This Protocol instance pointer.\r
1787 @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will\r
1788 be loaded\r
1789 @param RomImage Return the legacy PCI ROM for this device\r
1790 @param RomSize Size of ROM Image\r
1791 @param Flags Indicates if ROM found and if PC-AT.\r
1792\r
1793 @retval EFI_SUCCESS Legacy Option ROM availible for this device\r
1794 @retval EFI_UNSUPPORTED Legacy Option ROM not supported.\r
1795\r
1796**/\r
1797EFI_STATUS\r
1798EFIAPI\r
1799LegacyBiosCheckPciRom (\r
1800 IN EFI_LEGACY_BIOS_PROTOCOL *This,\r
1801 IN EFI_HANDLE PciHandle,\r
1802 OUT VOID **RomImage, OPTIONAL\r
1803 OUT UINTN *RomSize, OPTIONAL\r
1804 OUT UINTN *Flags\r
1805 )\r
1806{\r
1807 return LegacyBiosCheckPciRomEx (\r
1808 This,\r
1809 PciHandle,\r
1810 RomImage,\r
1811 RomSize,\r
1812 NULL,\r
1813 Flags,\r
1814 NULL,\r
1815 NULL\r
1816 );\r
1817\r
1818}\r
1819\r
1820/**\r
1821\r
1822 Routine Description:\r
1823 Test to see if a legacy PCI ROM exists for this device. Optionally return\r
1824 the Legacy ROM instance for this PCI device.\r
1825\r
1826 @param[in] This Protocol instance pointer.\r
1827 @param[in] PciHandle The PCI PC-AT OPROM from this devices ROM BAR will be loaded\r
1828 @param[out] RomImage Return the legacy PCI ROM for this device\r
1829 @param[out] RomSize Size of ROM Image\r
1830 @param[out] RuntimeImageLength Runtime size of ROM Image\r
1831 @param[out] Flags Indicates if ROM found and if PC-AT.\r
1832 @param[out] OpromRevision Revision of the PCI Rom\r
1833 @param[out] ConfigUtilityCodeHeaderPointer of Configuration Utility Code Header\r
1834\r
1835 @return EFI_SUCCESS Legacy Option ROM availible for this device\r
1836 @return EFI_ALREADY_STARTED This device is already managed by its Oprom\r
1837 @return EFI_UNSUPPORTED Legacy Option ROM not supported.\r
1838\r
1839**/\r
1840EFI_STATUS\r
1841LegacyBiosCheckPciRomEx (\r
1842 IN EFI_LEGACY_BIOS_PROTOCOL *This,\r
1843 IN EFI_HANDLE PciHandle,\r
1844 OUT VOID **RomImage, OPTIONAL\r
1845 OUT UINTN *RomSize, OPTIONAL\r
1846 OUT UINTN *RuntimeImageLength, OPTIONAL\r
1847 OUT UINTN *Flags, OPTIONAL\r
1848 OUT UINT8 *OpromRevision, OPTIONAL\r
1849 OUT VOID **ConfigUtilityCodeHeader OPTIONAL\r
1850 )\r
1851{\r
1852 EFI_STATUS Status;\r
1853 LEGACY_BIOS_INSTANCE *Private;\r
1854 EFI_PCI_IO_PROTOCOL *PciIo;\r
1855 UINTN LocalRomSize;\r
1856 VOID *LocalRomImage;\r
1857 PCI_TYPE00 PciConfigHeader;\r
1858 VOID *LocalConfigUtilityCodeHeader;\r
1859\r
1860 *Flags = NO_ROM;\r
1861 Status = gBS->HandleProtocol (\r
1862 PciHandle,\r
1863 &gEfiPciIoProtocolGuid,\r
1864 (VOID **) &PciIo\r
1865 );\r
1866 if (EFI_ERROR (Status)) {\r
1867 return EFI_UNSUPPORTED;\r
1868 }\r
1869\r
1870 //\r
1871 // See if the option ROM for PciHandle has already been executed\r
1872 //\r
1873 Status = IsLegacyRom (PciHandle);\r
1874 if (!EFI_ERROR (Status)) {\r
1875 *Flags |= (ROM_FOUND | VALID_LEGACY_ROM);\r
1876 return EFI_SUCCESS;\r
1877 }\r
1878 //\r
1879 // Check for PCI ROM Bar\r
1880 //\r
1881 LocalRomSize = (UINTN) PciIo->RomSize;\r
1882 LocalRomImage = PciIo->RomImage;\r
1883 if (LocalRomSize != 0) {\r
1884 *Flags |= ROM_FOUND;\r
1885 }\r
1886\r
1887 //\r
1888 // PCI specification states you should check VendorId and Device Id.\r
1889 //\r
1890 PciIo->Pci.Read (\r
1891 PciIo,\r
1892 EfiPciIoWidthUint32,\r
1893 0,\r
1894 sizeof (PciConfigHeader) / sizeof (UINT32),\r
1895 &PciConfigHeader\r
1896 );\r
1897\r
1898 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
1899 Status = GetPciLegacyRom (\r
1900 Private->Csm16PciInterfaceVersion,\r
1901 PciConfigHeader.Hdr.VendorId,\r
1902 PciConfigHeader.Hdr.DeviceId,\r
1903 &LocalRomImage,\r
1904 &LocalRomSize,\r
1905 RuntimeImageLength,\r
1906 OpromRevision,\r
1907 &LocalConfigUtilityCodeHeader\r
1908 );\r
1909 if (EFI_ERROR (Status)) {\r
1910 return EFI_UNSUPPORTED;\r
1911 }\r
1912\r
1913 *Flags |= VALID_LEGACY_ROM;\r
1914\r
1915 //\r
1916 // See if Configuration Utility Code Header valid\r
1917 //\r
1918 if (LocalConfigUtilityCodeHeader != NULL) {\r
1919 *Flags |= ROM_WITH_CONFIG;\r
1920 }\r
1921\r
1922 if (ConfigUtilityCodeHeader != NULL) {\r
1923 *ConfigUtilityCodeHeader = LocalConfigUtilityCodeHeader;\r
1924 }\r
1925\r
1926 if (RomImage != NULL) {\r
1927 *RomImage = LocalRomImage;\r
1928 }\r
1929\r
1930 if (RomSize != NULL) {\r
1931 *RomSize = LocalRomSize;\r
1932 }\r
1933\r
1934 return EFI_SUCCESS;\r
1935}\r
1936\r
1937/**\r
1938 Load a legacy PC-AT OPROM on the PciHandle device. Return information\r
1939 about how many disks were added by the OPROM and the shadow address and\r
1940 size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:\r
1941\r
1942 @retval EFI_SUCCESS Legacy ROM loaded for this device\r
1943 @retval EFI_NOT_FOUND No PS2 Keyboard found\r
1944\r
1945**/\r
1946EFI_STATUS\r
1947EnablePs2Keyboard (\r
1948 VOID\r
1949 )\r
1950{\r
1951 EFI_STATUS Status;\r
1952 EFI_HANDLE *HandleBuffer;\r
1953 UINTN HandleCount;\r
1954 EFI_ISA_IO_PROTOCOL *IsaIo;\r
1955 UINTN Index;\r
1956\r
1957 //\r
1958 // Get SimpleTextIn and find PS2 controller\r
1959 //\r
1960 Status = gBS->LocateHandleBuffer (\r
1961 ByProtocol,\r
1962 &gEfiSimpleTextInProtocolGuid,\r
1963 NULL,\r
1964 &HandleCount,\r
1965 &HandleBuffer\r
1966 );\r
1967 if (EFI_ERROR (Status)) {\r
1968 return EFI_NOT_FOUND;\r
1969 }\r
1970 for (Index = 0; Index < HandleCount; Index++) {\r
1971 //\r
1972 // Open the IO Abstraction(s) needed to perform the supported test\r
1973 //\r
1974 Status = gBS->OpenProtocol (\r
1975 HandleBuffer[Index],\r
1976 &gEfiIsaIoProtocolGuid,\r
1977 (VOID **) &IsaIo,\r
1978 NULL,\r
1979 HandleBuffer[Index],\r
1980 EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL\r
1981 );\r
1982\r
1983 if (!EFI_ERROR (Status)) {\r
1984 //\r
1985 // Use the ISA I/O Protocol to see if Controller is the Keyboard\r
1986 // controller\r
1987 //\r
1988 if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x303) || IsaIo->ResourceList->Device.UID != 0) {\r
1989 Status = EFI_UNSUPPORTED;\r
1990 }\r
1991\r
1992 gBS->CloseProtocol (\r
1993 HandleBuffer[Index],\r
1994 &gEfiIsaIoProtocolGuid,\r
1995 NULL,\r
1996 HandleBuffer[Index]\r
1997 );\r
1998 }\r
1999\r
2000 if (!EFI_ERROR (Status)) {\r
2001 gBS->ConnectController (HandleBuffer[Index], NULL, NULL, FALSE);\r
2002 }\r
2003 }\r
2004 FreePool (HandleBuffer);\r
2005 return EFI_SUCCESS;\r
2006}\r
2007\r
2008\r
2009/**\r
2010 Load a legacy PC-AT OpROM for VGA controller.\r
2011\r
2012 @param Private Driver private data.\r
2013\r
2014 @retval EFI_SUCCESS Legacy ROM successfully installed for this device.\r
2015 @retval EFI_DEVICE_ERROR No VGA device handle found, or native EFI video\r
2016 driver cannot be successfully disconnected, or VGA\r
2017 thunk driver cannot be successfully connected.\r
2018\r
2019**/\r
2020EFI_STATUS\r
2021LegacyBiosInstallVgaRom (\r
2022 IN LEGACY_BIOS_INSTANCE *Private\r
2023 )\r
2024{\r
2025 EFI_STATUS Status;\r
2026 EFI_HANDLE VgaHandle;\r
2027 UINTN HandleCount;\r
2028 EFI_HANDLE *HandleBuffer;\r
2029 EFI_HANDLE *ConnectHandleBuffer;\r
2030 EFI_PCI_IO_PROTOCOL *PciIo;\r
2031 PCI_TYPE00 PciConfigHeader;\r
2032 UINT64 Supports;\r
2033 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;\r
2034 UINTN EntryCount;\r
2035 UINTN Index;\r
2036 VOID *Interface;\r
2037\r
2038 //\r
2039 // EfiLegacyBiosGuild attached to a device implies that there is a legacy\r
2040 // BIOS associated with that device.\r
2041 //\r
2042 // There are 3 cases to consider.\r
2043 // Case 1: No EFI driver is controlling the video.\r
2044 // Action: Return EFI_SUCCESS from DisconnectController, search\r
2045 // video thunk driver, and connect it.\r
2046 // Case 2: EFI driver is controlling the video and EfiLegacyBiosGuid is\r
2047 // not on the image handle.\r
2048 // Action: Disconnect EFI driver.\r
2049 // ConnectController for video thunk\r
2050 // Case 3: EFI driver is controlling the video and EfiLegacyBiosGuid is\r
2051 // on the image handle.\r
2052 // Action: Do nothing and set Private->VgaInstalled = TRUE.\r
2053 // Then this routine is not called any more.\r
2054 //\r
2055 //\r
2056 // Get the VGA device.\r
2057 //\r
2058 Status = Private->LegacyBiosPlatform->GetPlatformHandle (\r
2059 Private->LegacyBiosPlatform,\r
2060 EfiGetPlatformVgaHandle,\r
2061 0,\r
2062 &HandleBuffer,\r
2063 &HandleCount,\r
2064 NULL\r
2065 );\r
2066 if (EFI_ERROR (Status)) {\r
2067 return EFI_DEVICE_ERROR;\r
2068 }\r
2069\r
2070 VgaHandle = HandleBuffer[0];\r
2071\r
2072 //\r
2073 // Check whether video thunk driver already starts.\r
2074 //\r
2075 Status = gBS->OpenProtocolInformation (\r
2076 VgaHandle,\r
2077 &gEfiPciIoProtocolGuid,\r
2078 &OpenInfoBuffer,\r
2079 &EntryCount\r
2080 );\r
2081 if (EFI_ERROR (Status)) {\r
2082 return Status;\r
2083 }\r
2084 \r
2085 for (Index = 0; Index < EntryCount; Index++) {\r
2086 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {\r
2087 Status = gBS->HandleProtocol (\r
2088 OpenInfoBuffer[Index].AgentHandle,\r
2089 &gEfiLegacyBiosGuid,\r
2090 (VOID **) &Interface\r
2091 );\r
2092 if (!EFI_ERROR (Status)) {\r
2093 //\r
2094 // This should be video thunk driver which is managing video device\r
2095 // So it need not start again\r
2096 //\r
2097 DEBUG ((EFI_D_INFO, "Video thunk driver already start! Return!\n"));\r
2098 Private->VgaInstalled = TRUE;\r
2099 return EFI_SUCCESS;\r
2100 }\r
2101 }\r
2102 }\r
2103 \r
2104 //\r
2105 // Kick off the native EFI driver\r
2106 //\r
2107 Status = gBS->DisconnectController (\r
2108 VgaHandle,\r
2109 NULL,\r
2110 NULL\r
2111 );\r
2112 if (EFI_ERROR (Status)) {\r
2113 if (Status != EFI_NOT_FOUND) {\r
2114 return EFI_DEVICE_ERROR;\r
2115 } else {\r
2116 return Status;\r
2117 }\r
2118 }\r
2119 //\r
2120 // Find all the Thunk Driver\r
2121 //\r
2122 HandleBuffer = NULL;\r
2123 Status = gBS->LocateHandleBuffer (\r
2124 ByProtocol,\r
2125 &gEfiLegacyBiosGuid,\r
2126 NULL,\r
2127 &HandleCount,\r
2128 &HandleBuffer\r
2129 );\r
2130 ASSERT_EFI_ERROR (Status);\r
2131 ConnectHandleBuffer = (EFI_HANDLE *) AllocatePool (sizeof (EFI_HANDLE) * (HandleCount + 1));\r
2132 ASSERT (ConnectHandleBuffer != NULL);\r
2133\r
2134 CopyMem (\r
2135 ConnectHandleBuffer,\r
2136 HandleBuffer,\r
2137 sizeof (EFI_HANDLE) * HandleCount\r
2138 );\r
2139 ConnectHandleBuffer[HandleCount] = NULL;\r
2140\r
2141 FreePool (HandleBuffer);\r
2142\r
2143 //\r
2144 // Enable the device and make sure VGA cycles are being forwarded to this VGA device\r
2145 //\r
2146 Status = gBS->HandleProtocol (\r
2147 VgaHandle,\r
2148 &gEfiPciIoProtocolGuid,\r
2149 (VOID **) &PciIo\r
2150 );\r
2151 ASSERT_EFI_ERROR (Status);\r
2152 PciIo->Pci.Read (\r
2153 PciIo,\r
2154 EfiPciIoWidthUint32,\r
2155 0,\r
2156 sizeof (PciConfigHeader) / sizeof (UINT32),\r
2157 &PciConfigHeader\r
2158 );\r
2159\r
2160 Status = PciIo->Attributes (\r
2161 PciIo,\r
2162 EfiPciIoAttributeOperationSupported,\r
2163 0,\r
2164 &Supports\r
2165 );\r
2166 if (!EFI_ERROR (Status)) {\r
2167 Supports &= EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | \\r
2168 EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16;\r
2169 Status = PciIo->Attributes (\r
2170 PciIo,\r
2171 EfiPciIoAttributeOperationEnable,\r
2172 Supports,\r
2173 NULL\r
2174 );\r
2175 }\r
2176\r
2177 if (Status == EFI_SUCCESS) {\r
2178 Private->VgaInstalled = TRUE;\r
2179\r
2180 //\r
2181 // Attach the VGA thunk driver.\r
2182 // Assume the video is installed. This prevents potential of infinite recursion.\r
2183 //\r
2184 Status = gBS->ConnectController (\r
2185 VgaHandle,\r
2186 ConnectHandleBuffer,\r
2187 NULL,\r
2188 TRUE\r
2189 );\r
2190 }\r
2191\r
2192 FreePool (ConnectHandleBuffer);\r
2193\r
2194 if (EFI_ERROR (Status)) {\r
2195\r
2196 Private->VgaInstalled = FALSE;\r
2197\r
2198 //\r
2199 // Reconnect the EFI VGA driver.\r
2200 //\r
2201 gBS->ConnectController (VgaHandle, NULL, NULL, TRUE);\r
2202 return EFI_DEVICE_ERROR;\r
2203 }\r
2204\r
2205 return EFI_SUCCESS;\r
2206}\r
2207\r
2208\r
2209/**\r
2210 Load a legacy PC-AT OpROM.\r
2211\r
2212 @param This Protocol instance pointer.\r
2213 @param Private Driver's private data.\r
2214 @param PciHandle The EFI handle for the PCI device. It could be\r
2215 NULL if the OpROM image is not associated with\r
2216 any device.\r
2217 @param OpromRevision The revision of PCI PC-AT ROM image.\r
2218 @param RomImage Pointer to PCI PC-AT ROM image header. It must not\r
2219 be NULL.\r
2220 @param ImageSize Size of the PCI PC-AT ROM image.\r
2221 @param RuntimeImageLength On input is the max runtime image length indicated by the PCIR structure\r
2222 On output is the actual runtime image length\r
2223 @param DiskStart Disk number of first device hooked by the ROM. If\r
2224 DiskStart is the same as DiskEnd no disked were\r
2225 hooked.\r
2226 @param DiskEnd Disk number of the last device hooked by the ROM.\r
2227 @param RomShadowAddress Shadow address of PC-AT ROM\r
2228\r
2229 @retval EFI_SUCCESS Legacy ROM loaded for this device\r
2230 @retval EFI_OUT_OF_RESOURCES No more space for this ROM\r
2231\r
2232**/\r
2233EFI_STATUS\r
2234EFIAPI\r
2235LegacyBiosInstallRom (\r
2236 IN EFI_LEGACY_BIOS_PROTOCOL *This,\r
2237 IN LEGACY_BIOS_INSTANCE *Private,\r
2238 IN EFI_HANDLE PciHandle,\r
2239 IN UINT8 OpromRevision,\r
2240 IN VOID *RomImage,\r
2241 IN UINTN ImageSize,\r
2242 IN OUT UINTN *RuntimeImageLength,\r
2243 OUT UINT8 *DiskStart, OPTIONAL\r
2244 OUT UINT8 *DiskEnd, OPTIONAL\r
2245 OUT VOID **RomShadowAddress OPTIONAL\r
2246 )\r
2247{\r
2248 EFI_STATUS Status;\r
2249 EFI_STATUS PciEnableStatus;\r
2250 EFI_PCI_IO_PROTOCOL *PciIo;\r
2251 UINT8 LocalDiskStart;\r
2252 UINT8 LocalDiskEnd;\r
2253 UINTN Segment;\r
2254 UINTN Bus;\r
2255 UINTN Device;\r
2256 UINTN Function;\r
2257 EFI_IA32_REGISTER_SET Regs;\r
2258 UINT8 VideoMode;\r
2259 EFI_TIME BootTime;\r
2260 UINT32 *BdaPtr;\r
2261 UINT32 LocalTime;\r
2262 UINT32 StartBbsIndex;\r
2263 UINT32 EndBbsIndex;\r
2264 UINTN TempData;\r
2265 UINTN InitAddress;\r
2266 UINTN RuntimeAddress;\r
2267 EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
2268 UINT32 Granularity;\r
2269\r
2270 PciIo = NULL;\r
2271 LocalDiskStart = 0;\r
2272 LocalDiskEnd = 0;\r
2273 Segment = 0;\r
2274 Bus = 0;\r
2275 Device = 0;\r
2276 Function = 0;\r
2277 VideoMode = 0;\r
2278 PhysicalAddress = 0;\r
2279\r
2280 PciProgramAllInterruptLineRegisters (Private);\r
2281\r
2282 if ((OpromRevision >= 3) && (Private->Csm16PciInterfaceVersion >= 0x0300)) {\r
2283 //\r
2284 // CSM16 3.0 meets PCI 3.0 OpROM\r
2285 // first test if there is enough space for its INIT code\r
2286 //\r
2287 PhysicalAddress = CONVENTIONAL_MEMORY_TOP;\r
2288 Status = gBS->AllocatePages (\r
2289 AllocateMaxAddress,\r
2290 EfiBootServicesCode,\r
2291 EFI_SIZE_TO_PAGES (ImageSize),\r
2292 &PhysicalAddress\r
2293 );\r
2294 \r
2295 if (EFI_ERROR (Status)) {\r
2296 DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));\r
2297 return EFI_OUT_OF_RESOURCES;\r
2298 }\r
2299 InitAddress = (UINTN) PhysicalAddress;\r
2300 //\r
2301 // then test if there is enough space for its RT code\r
2302 //\r
2303 RuntimeAddress = Private->OptionRom;\r
2304 if (RuntimeAddress + *RuntimeImageLength > mEndOpromShadowAddress) {\r
2305 DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));\r
2306 gBS->FreePages (PhysicalAddress, EFI_SIZE_TO_PAGES (ImageSize));\r
2307 return EFI_OUT_OF_RESOURCES;\r
2308 }\r
2309 } else {\r
2310 // CSM16 3.0 meets PCI 2.x OpROM\r
2311 // CSM16 2.x meets PCI 2.x/3.0 OpROM\r
2312 // test if there is enough space for its INIT code\r
2313 //\r
2314 InitAddress = PCI_START_ADDRESS (Private->OptionRom);\r
2315 if (InitAddress + ImageSize > mEndOpromShadowAddress) {\r
2316 DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));\r
2317 return EFI_OUT_OF_RESOURCES;\r
2318 }\r
2319\r
2320 RuntimeAddress = InitAddress;\r
2321 }\r
2322\r
2323 Private->LegacyRegion->UnLock (\r
2324 Private->LegacyRegion,\r
2325 0xE0000,\r
2326 0x20000,\r
2327 &Granularity\r
2328 );\r
2329\r
2330 Private->LegacyRegion->UnLock (\r
2331 Private->LegacyRegion,\r
2332 (UINT32) RuntimeAddress,\r
2333 (UINT32) ImageSize,\r
2334 &Granularity\r
2335 );\r
2336 \r
2337 DEBUG ((EFI_D_INFO, " Shadowing OpROM init/runtime/isize = %x/%x/%x\n", InitAddress, RuntimeAddress, ImageSize));\r
2338\r
2339 CopyMem ((VOID *) InitAddress, RomImage, ImageSize);\r
2340\r
2341 //\r
2342 // Read the highest disk number "installed: and assume a new disk will\r
2343 // show up on the first drive past the current value.\r
2344 // There are several considerations here:\r
2345 // 1. Non-BBS compliant drives will change 40:75 but 16-bit CSM will undo\r
2346 // the change until boot selection time frame.\r
2347 // 2. BBS compliants drives will not change 40:75 until boot time.\r
2348 // 3. Onboard IDE controllers will change 40:75\r
2349 //\r
2350 LocalDiskStart = (UINT8) ((*(UINT8 *) ((UINTN) 0x475)) + 0x80);\r
2351 if ((Private->Disk4075 + 0x80) < LocalDiskStart) {\r
2352 //\r
2353 // Update table since onboard IDE drives found\r
2354 //\r
2355 Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment = 0xff;\r
2356 Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus = 0xff;\r
2357 Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice = 0xff;\r
2358 Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction = 0xff;\r
2359 Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber = (UINT8) (Private->Disk4075 + 0x80);\r
2360 Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = LocalDiskStart;\r
2361 Private->LegacyEfiHddTableIndex ++;\r
2362 Private->Disk4075 = (UINT8) (LocalDiskStart & 0x7f);\r
2363 Private->DiskEnd = LocalDiskStart;\r
2364 }\r
2365\r
2366 if (PciHandle != mVgaHandle) {\r
2367\r
2368 EnablePs2Keyboard ();\r
2369\r
2370 //\r
2371 // Store current mode settings since PrepareToScanRom may change mode.\r
2372 //\r
2373 VideoMode = *(UINT8 *) ((UINTN) 0x449);\r
2374 }\r
2375 //\r
2376 // Notify the platform that we are about to scan the ROM\r
2377 //\r
2378 Status = Private->LegacyBiosPlatform->PlatformHooks (\r
2379 Private->LegacyBiosPlatform,\r
2380 EfiPlatformHookPrepareToScanRom,\r
2381 0,\r
2382 PciHandle,\r
2383 &InitAddress,\r
2384 NULL,\r
2385 NULL\r
2386 );\r
2387\r
2388 //\r
2389 // If Status returned is EFI_UNSUPPORTED then abort due to platform\r
2390 // policy.\r
2391 //\r
2392 if (Status == EFI_UNSUPPORTED) {\r
2393 goto Done;\r
2394 }\r
2395\r
2396 //\r
2397 // Report corresponding status code\r
2398 //\r
2399 REPORT_STATUS_CODE (\r
2400 EFI_PROGRESS_CODE,\r
2401 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_CSM_LEGACY_ROM_INIT)\r
2402 );\r
2403\r
2404 //\r
2405 // Generate number of ticks since midnight for BDA. Some OPROMs require\r
2406 // this. Place result in 40:6C-6F\r
2407 //\r
2408 gRT->GetTime (&BootTime, NULL);\r
2409 LocalTime = BootTime.Hour * 3600 + BootTime.Minute * 60 + BootTime.Second;\r
2410 \r
2411 //\r
2412 // Multiply result by 18.2 for number of ticks since midnight.\r
2413 // Use 182/10 to avoid floating point math.\r
2414 //\r
2415 LocalTime = (LocalTime * 182) / 10;\r
2416 BdaPtr = (UINT32 *) ((UINTN) 0x46C);\r
2417 *BdaPtr = LocalTime;\r
2418 \r
2419 //\r
2420 // Pass in handoff data\r
2421 //\r
2422 PciEnableStatus = EFI_UNSUPPORTED;\r
2423 ZeroMem (&Regs, sizeof (Regs));\r
2424 if (PciHandle != NULL) {\r
2425 \r
2426 Status = gBS->HandleProtocol (\r
2427 PciHandle,\r
2428 &gEfiPciIoProtocolGuid,\r
2429 (VOID **) &PciIo\r
2430 );\r
2431 ASSERT_EFI_ERROR (Status);\r
2432 \r
2433 //\r
2434 // Enable command register.\r
2435 //\r
2436 PciEnableStatus = PciIo->Attributes (\r
2437 PciIo,\r
2438 EfiPciIoAttributeOperationEnable,\r
2439 EFI_PCI_DEVICE_ENABLE,\r
2440 NULL\r
2441 );\r
2442 \r
2443 PciIo->GetLocation (\r
2444 PciIo,\r
2445 &Segment,\r
2446 &Bus,\r
2447 &Device,\r
2448 &Function\r
2449 );\r
2450 DEBUG ((EFI_D_INFO, "Shadowing OpROM on the PCI device %x/%x/%x\n", Bus, Device, Function));\r
2451 }\r
2452 \r
2453 mIgnoreBbsUpdateFlag = FALSE;\r
2454 Regs.X.AX = Legacy16DispatchOprom;\r
2455 \r
2456 //\r
2457 // Generate DispatchOpRomTable data\r
2458 //\r
2459 Private->IntThunk->DispatchOpromTable.PnPInstallationCheckSegment = Private->Legacy16Table->PnPInstallationCheckSegment;\r
2460 Private->IntThunk->DispatchOpromTable.PnPInstallationCheckOffset = Private->Legacy16Table->PnPInstallationCheckOffset;\r
2461 Private->IntThunk->DispatchOpromTable.OpromSegment = (UINT16) (InitAddress >> 4);\r
2462 Private->IntThunk->DispatchOpromTable.PciBus = (UINT8) Bus;\r
2463 Private->IntThunk->DispatchOpromTable.PciDeviceFunction = (UINT8) ((Device << 3) | Function);\r
2464 Private->IntThunk->DispatchOpromTable.NumberBbsEntries = (UINT8) Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;\r
2465 Private->IntThunk->DispatchOpromTable.BbsTablePointer = (UINT32) (UINTN) Private->BbsTablePtr;\r
2466 Private->IntThunk->DispatchOpromTable.RuntimeSegment = (UINT16)((OpromRevision < 3) ? 0xffff : (RuntimeAddress >> 4));\r
2467 TempData = (UINTN) &Private->IntThunk->DispatchOpromTable;\r
2468 Regs.X.ES = EFI_SEGMENT ((UINT32) TempData);\r
2469 Regs.X.BX = EFI_OFFSET ((UINT32) TempData);\r
2470 //\r
2471 // Skip dispatching ROM for those PCI devices that can not be enabled by PciIo->Attributes\r
2472 // Otherwise, it may cause the system to hang in some cases\r
2473 //\r
2474 if (!EFI_ERROR (PciEnableStatus)) {\r
2475 DEBUG ((EFI_D_INFO, " Legacy16DispatchOprom - %02x/%02x/%02x\n", Bus, Device, Function));\r
2476 Private->LegacyBios.FarCall86 (\r
2477 &Private->LegacyBios,\r
2478 Private->Legacy16CallSegment,\r
2479 Private->Legacy16CallOffset,\r
2480 &Regs,\r
2481 NULL,\r
2482 0\r
2483 );\r
2484 } else {\r
2485 Regs.X.BX = 0;\r
2486 }\r
2487 \r
2488 if (Private->IntThunk->DispatchOpromTable.NumberBbsEntries != (UINT8) Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries) {\r
2489 Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries = (UINT8) Private->IntThunk->DispatchOpromTable.NumberBbsEntries;\r
2490 mIgnoreBbsUpdateFlag = TRUE;\r
2491 }\r
2492 //\r
2493 // Check if non-BBS compliant drives found\r
2494 //\r
2495 if (Regs.X.BX != 0) {\r
2496 LocalDiskEnd = (UINT8) (LocalDiskStart + Regs.H.BL);\r
2497 Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment = (UINT8) Segment;\r
2498 Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus = (UINT8) Bus;\r
2499 Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice = (UINT8) Device;\r
2500 Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction = (UINT8) Function;\r
2501 Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber = Private->DiskEnd;\r
2502 Private->DiskEnd = LocalDiskEnd;\r
2503 Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = Private->DiskEnd;\r
2504 Private->LegacyEfiHddTableIndex += 1;\r
2505 }\r
2506 //\r
2507 // Skip video mode set, if installing VGA\r
2508 //\r
2509 if (PciHandle != mVgaHandle) {\r
2510 //\r
2511 // Set mode settings since PrepareToScanRom may change mode\r
2512 //\r
2513 Regs.H.AH = 0x00;\r
2514 Regs.H.AL = VideoMode;\r
2515 Private->LegacyBios.Int86 (&Private->LegacyBios, 0x10, &Regs);\r
2516 }\r
2517 //\r
2518 // Regs.X.AX from the adapter initializion is ignored since some adapters\r
2519 // do not follow the standard of setting AX = 0 on success.\r
2520 //\r
2521 //\r
2522 // The ROM could have updated it's size so we need to read again.\r
2523 //\r
2524 *RuntimeImageLength = ((EFI_LEGACY_EXPANSION_ROM_HEADER *) (RuntimeAddress))->Size512 * 512;\r
2525 DEBUG ((EFI_D_INFO, " fsize = %x\n", *RuntimeImageLength));\r
2526\r
2527 //\r
2528 // If OpROM runs in 2.0 mode\r
2529 //\r
2530 if (PhysicalAddress == 0) {\r
2531 if (*RuntimeImageLength < ImageSize) {\r
2532 //\r
2533 // Make area from end of shadowed rom to end of original rom all ffs\r
2534 //\r
2535 gBS->SetMem ((VOID *) (InitAddress + *RuntimeImageLength), ImageSize - *RuntimeImageLength, 0xff);\r
2536 }\r
2537 }\r
2538\r
2539 LocalDiskEnd = (UINT8) ((*(UINT8 *) ((UINTN) 0x475)) + 0x80);\r
2540 \r
2541 //\r
2542 // Allow platform to perform any required actions after the\r
2543 // OPROM has been initialized.\r
2544 //\r
2545 Status = Private->LegacyBiosPlatform->PlatformHooks (\r
2546 Private->LegacyBiosPlatform,\r
2547 EfiPlatformHookAfterRomInit,\r
2548 0,\r
2549 PciHandle,\r
2550 &RuntimeAddress,\r
2551 NULL,\r
2552 NULL\r
2553 );\r
2554 if (PciHandle != NULL) {\r
2555 //\r
2556 // If no PCI Handle then no header or Bevs.\r
2557 //\r
2558 if ((*RuntimeImageLength != 0) && (!mIgnoreBbsUpdateFlag)) {\r
2559 StartBbsIndex = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;\r
2560 TempData = RuntimeAddress;\r
2561 UpdateBevBcvTable (\r
2562 Private,\r
2563 (EFI_LEGACY_EXPANSION_ROM_HEADER *) TempData,\r
2564 PciIo\r
2565 );\r
2566 EndBbsIndex = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;\r
2567 LocalDiskEnd = (UINT8) (LocalDiskStart + (UINT8) (EndBbsIndex - StartBbsIndex));\r
2568 if (LocalDiskEnd != LocalDiskStart) {\r
2569 Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment = (UINT8) Segment;\r
2570 Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus = (UINT8) Bus;\r
2571 Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice = (UINT8) Device;\r
2572 Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction = (UINT8) Function;\r
2573 Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber = Private->DiskEnd;\r
2574 Private->DiskEnd = LocalDiskEnd;\r
2575 Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = Private->DiskEnd;\r
2576 Private->LegacyEfiHddTableIndex += 1;\r
2577 }\r
2578 }\r
2579 //\r
2580 // Mark PCI device as having a legacy BIOS ROM loaded.\r
2581 //\r
2582 RomShadow (\r
2583 PciHandle,\r
2584 (UINT32) RuntimeAddress,\r
2585 (UINT32) *RuntimeImageLength,\r
2586 LocalDiskStart,\r
2587 LocalDiskEnd\r
2588 );\r
2589 }\r
2590\r
2591 //\r
2592 // Stuff caller's OPTIONAL return parameters.\r
2593 //\r
2594 if (RomShadowAddress != NULL) {\r
2595 *RomShadowAddress = (VOID *) RuntimeAddress;\r
2596 }\r
2597\r
2598 if (DiskStart != NULL) {\r
2599 *DiskStart = LocalDiskStart;\r
2600 }\r
2601\r
2602 if (DiskEnd != NULL) {\r
2603 *DiskEnd = LocalDiskEnd;\r
2604 }\r
2605\r
2606 Private->OptionRom = (UINT32) (RuntimeAddress + *RuntimeImageLength);\r
2607\r
2608 Status = EFI_SUCCESS;\r
2609 \r
2610Done:\r
2611 if (PhysicalAddress != 0) {\r
2612 //\r
2613 // Free pages when OpROM is 3.0\r
2614 //\r
2615 gBS->FreePages (PhysicalAddress, EFI_SIZE_TO_PAGES (ImageSize));\r
2616 }\r
2617\r
2618 //\r
2619 // Insure all shadowed areas are locked\r
2620 //\r
2621 Private->LegacyRegion->Lock (\r
2622 Private->LegacyRegion,\r
2623 0xC0000,\r
2624 0x40000,\r
2625 &Granularity\r
2626 );\r
2627\r
2628 return Status;\r
2629}\r
2630\r
2631/**\r
2632 Load a legacy PC-AT OPROM on the PciHandle device. Return information\r
2633 about how many disks were added by the OPROM and the shadow address and\r
2634 size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:\r
2635\r
2636 @param This Protocol instance pointer.\r
2637 @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will\r
2638 be loaded. This value is NULL if RomImage is\r
2639 non-NULL. This is the normal case.\r
2640 @param RomImage A PCI PC-AT ROM image. This argument is non-NULL\r
2641 if there is no hardware associated with the ROM\r
2642 and thus no PciHandle, otherwise is must be NULL.\r
2643 Example is PXE base code.\r
2644 @param Flags Indicates if ROM found and if PC-AT.\r
2645 @param DiskStart Disk number of first device hooked by the ROM. If\r
2646 DiskStart is the same as DiskEnd no disked were\r
2647 hooked.\r
2648 @param DiskEnd Disk number of the last device hooked by the ROM.\r
2649 @param RomShadowAddress Shadow address of PC-AT ROM\r
2650 @param RomShadowedSize Size of RomShadowAddress in bytes\r
2651\r
2652 @retval EFI_SUCCESS Legacy ROM loaded for this device\r
2653 @retval EFI_INVALID_PARAMETER PciHandle not found\r
2654 @retval EFI_UNSUPPORTED There is no PCI ROM in the ROM BAR or no onboard\r
2655 ROM\r
2656\r
2657**/\r
2658EFI_STATUS\r
2659EFIAPI\r
2660LegacyBiosInstallPciRom (\r
2661 IN EFI_LEGACY_BIOS_PROTOCOL * This,\r
2662 IN EFI_HANDLE PciHandle,\r
2663 IN VOID **RomImage,\r
2664 OUT UINTN *Flags,\r
2665 OUT UINT8 *DiskStart, OPTIONAL\r
2666 OUT UINT8 *DiskEnd, OPTIONAL\r
2667 OUT VOID **RomShadowAddress, OPTIONAL\r
2668 OUT UINT32 *RomShadowedSize OPTIONAL\r
2669 )\r
2670{\r
2671 EFI_STATUS Status;\r
2672 LEGACY_BIOS_INSTANCE *Private;\r
2673 VOID *LocalRomImage;\r
2674 UINTN ImageSize;\r
2675 UINTN RuntimeImageLength;\r
2676 EFI_PCI_IO_PROTOCOL *PciIo;\r
2677 PCI_TYPE01 PciConfigHeader;\r
2678 UINTN HandleCount;\r
2679 EFI_HANDLE *HandleBuffer;\r
2680 UINTN PciSegment;\r
2681 UINTN PciBus;\r
2682 UINTN PciDevice;\r
2683 UINTN PciFunction;\r
2684 UINTN LastBus;\r
2685 UINTN Index;\r
2686 UINT8 OpromRevision;\r
2687 UINT32 Granularity;\r
2688 PCI_3_0_DATA_STRUCTURE *Pcir;\r
2689\r
2690 OpromRevision = 0;\r
2691\r
2692 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
2693 if (Private->Legacy16Table->LastPciBus == 0) {\r
2694 //\r
2695 // Get last bus number if not already found\r
2696 //\r
2697 Status = gBS->LocateHandleBuffer (\r
2698 ByProtocol,\r
2699 &gEfiPciIoProtocolGuid,\r
2700 NULL,\r
2701 &HandleCount,\r
2702 &HandleBuffer\r
2703 );\r
2704\r
2705 LastBus = 0;\r
2706 for (Index = 0; Index < HandleCount; Index++) {\r
2707 Status = gBS->HandleProtocol (\r
2708 HandleBuffer[Index],\r
2709 &gEfiPciIoProtocolGuid,\r
2710 (VOID **) &PciIo\r
2711 );\r
2712 if (EFI_ERROR (Status)) {\r
2713 continue;\r
2714 }\r
2715\r
2716 Status = PciIo->GetLocation (\r
2717 PciIo,\r
2718 &PciSegment,\r
2719 &PciBus,\r
2720 &PciDevice,\r
2721 &PciFunction\r
2722 );\r
2723 if (PciBus > LastBus) {\r
2724 LastBus = PciBus;\r
2725 }\r
2726 }\r
2727\r
2728 Private->LegacyRegion->UnLock (\r
2729 Private->LegacyRegion,\r
2730 0xE0000,\r
2731 0x20000,\r
2732 &Granularity\r
2733 );\r
2734 Private->Legacy16Table->LastPciBus = (UINT8) LastBus;\r
2735 Private->LegacyRegion->Lock (\r
2736 Private->LegacyRegion,\r
2737 0xE0000,\r
2738 0x20000,\r
2739 &Granularity\r
2740 );\r
2741 }\r
2742\r
2743 *Flags = 0;\r
2744 if ((PciHandle != NULL) && (RomImage == NULL)) {\r
2745 //\r
2746 // If PciHandle has OpRom to Execute \r
2747 // and OpRom are all associated with Hardware\r
2748 //\r
2749 Status = gBS->HandleProtocol (\r
2750 PciHandle,\r
2751 &gEfiPciIoProtocolGuid,\r
2752 (VOID **) &PciIo\r
2753 );\r
2754\r
2755 if (!EFI_ERROR (Status)) {\r
2756 PciIo->Pci.Read (\r
2757 PciIo,\r
2758 EfiPciIoWidthUint32,\r
2759 0,\r
2760 sizeof (PciConfigHeader) / sizeof (UINT32),\r
2761 &PciConfigHeader\r
2762 );\r
2763\r
2764 //\r
2765 // if video installed & OPROM is video return\r
2766 //\r
2767 if (\r
2768 (\r
2769 ((PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_OLD) &&\r
2770 (PciConfigHeader.Hdr.ClassCode[1] == PCI_CLASS_OLD_VGA))\r
2771 ||\r
2772 ((PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_DISPLAY) &&\r
2773 (PciConfigHeader.Hdr.ClassCode[1] == PCI_CLASS_DISPLAY_VGA))\r
2774 )\r
2775 &&\r
2776 (!Private->VgaInstalled)\r
2777 ) {\r
2778 mVgaInstallationInProgress = TRUE;\r
2779\r
2780 //\r
2781 // return EFI_UNSUPPORTED;\r
2782 //\r
2783 }\r
2784 }\r
2785 //\r
2786 // To run any legacy image, the VGA needs to be installed first.\r
2787 // if installing the video, then don't need the thunk as already installed.\r
2788 //\r
2789 Status = Private->LegacyBiosPlatform->GetPlatformHandle (\r
2790 Private->LegacyBiosPlatform,\r
2791 EfiGetPlatformVgaHandle,\r
2792 0,\r
2793 &HandleBuffer,\r
2794 &HandleCount,\r
2795 NULL\r
2796 );\r
2797\r
2798 if (!EFI_ERROR (Status)) {\r
2799 mVgaHandle = HandleBuffer[0];\r
2800 if ((!Private->VgaInstalled) && (PciHandle != mVgaHandle)) {\r
2801 //\r
2802 // A return status of EFI_NOT_FOUND is considered valid (No EFI\r
2803 // driver is controlling video.\r
2804 //\r
2805 mVgaInstallationInProgress = TRUE;\r
2806 Status = LegacyBiosInstallVgaRom (Private);\r
2807 if (EFI_ERROR (Status)) {\r
2808 if (Status != EFI_NOT_FOUND) {\r
2809 mVgaInstallationInProgress = FALSE;\r
2810 return Status;\r
2811 }\r
2812 } else {\r
2813 mVgaInstallationInProgress = FALSE;\r
2814 }\r
2815 }\r
2816 }\r
2817 //\r
2818 // See if the option ROM for PciHandle has already been executed\r
2819 //\r
2820 Status = IsLegacyRom (PciHandle);\r
2821\r
2822 if (!EFI_ERROR (Status)) {\r
2823 mVgaInstallationInProgress = FALSE;\r
2824 GetShadowedRomParameters (\r
2825 PciHandle,\r
2826 DiskStart,\r
2827 DiskEnd,\r
2828 RomShadowAddress,\r
2829 (UINTN *) RomShadowedSize\r
2830 );\r
2831 return EFI_SUCCESS;\r
2832 }\r
2833\r
2834 Status = LegacyBiosCheckPciRomEx (\r
2835 &Private->LegacyBios,\r
2836 PciHandle,\r
2837 &LocalRomImage,\r
2838 &ImageSize,\r
2839 &RuntimeImageLength,\r
2840 Flags,\r
2841 &OpromRevision,\r
2842 NULL\r
2843 );\r
2844 if (EFI_ERROR (Status)) {\r
2845 //\r
2846 // There is no PCI ROM in the ROM BAR or no onboard ROM\r
2847 //\r
2848 mVgaInstallationInProgress = FALSE;\r
2849 return EFI_UNSUPPORTED;\r
2850 }\r
2851 } else {\r
16adc276 2852 if ((RomImage == NULL) || (*RomImage == NULL)) {\r
bcecde14 2853 //\r
2854 // If PciHandle is NULL, and no OpRom is to be associated\r
2855 //\r
2856 mVgaInstallationInProgress = FALSE;\r
2857 return EFI_UNSUPPORTED;\r
2858 }\r
2859\r
2860 LocalRomImage = *RomImage;\r
2861 Pcir = (PCI_3_0_DATA_STRUCTURE *)\r
2862 ((UINT8 *) LocalRomImage + ((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->PcirOffset);\r
2863 ImageSize = Pcir->ImageLength * 512;\r
2864 if (Pcir->Length >= 0x1C) {\r
2865 OpromRevision = Pcir->Revision;\r
2866 } else {\r
2867 OpromRevision = 0;\r
2868 }\r
2869 if (Pcir->Revision < 3) {\r
2870 RuntimeImageLength = 0;\r
2871 } else {\r
2872 RuntimeImageLength = Pcir->MaxRuntimeImageLength * 512;\r
2873 }\r
2874 }\r
2875 //\r
2876 // Shadow and initialize the OpROM.\r
2877 //\r
2878 ASSERT (Private->TraceIndex < 0x200);\r
2879 Private->Trace[Private->TraceIndex] = LEGACY_PCI_TRACE_000;\r
2880 Private->TraceIndex ++;\r
2881 Private->TraceIndex = (UINT16) (Private->TraceIndex % 0x200);\r
2882 Status = LegacyBiosInstallRom (\r
2883 This,\r
2884 Private,\r
2885 PciHandle,\r
2886 OpromRevision,\r
2887 LocalRomImage,\r
2888 ImageSize,\r
2889 &RuntimeImageLength,\r
2890 DiskStart,\r
2891 DiskEnd,\r
2892 RomShadowAddress\r
2893 );\r
2894 if (RomShadowedSize != NULL) {\r
2895 *RomShadowedSize = (UINT32) RuntimeImageLength;\r
2896 }\r
2897\r
2898 mVgaInstallationInProgress = FALSE;\r
2899 return Status;\r
2900}\r
2901\r