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