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