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