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