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