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