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