Home | History | Annotate | Download | only in CsmSupportLib
      1 /** @file
      2   Legacy BIOS Platform support
      3 
      4   Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
      5 
      6   This program and the accompanying materials are
      7   licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The 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 "LegacyPlatform.h"
     17 
     18 EFI_SETUP_BBS_MAP mSetupBbsMap[] = {
     19   { 1, 2,     1, 1 },     // ATA HardDrive
     20   { 2, 3,     1, 1 },     // ATAPI CDROM
     21   { 3, 0x80,  2, 0 },     // PXE
     22   { 4, 1,     0, 6 },     // USB Floppy
     23   { 4, 2,     0, 6 },     // USB HDD
     24   { 4, 3,     0, 6 },     // USB CD
     25   { 4, 1,     0, 0 },     // USB ZIP Bugbug since Class/SubClass code is uninitialized
     26   { 4, 2,     0, 0 }      // USB ZIP Bugbug since Class/SubClass code is uninitialized
     27 };
     28 
     29 //
     30 // Global variables for System ROMs
     31 //
     32 #define SYSTEM_ROM_FILE_GUID \
     33 { 0x1547B4F3, 0x3E8A, 0x4FEF, { 0x81, 0xC8, 0x32, 0x8E, 0xD6, 0x47, 0xAB, 0x1A } }
     34 
     35 #define NULL_ROM_FILE_GUID \
     36 { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }
     37 
     38 SYSTEM_ROM_TABLE mSystemRomTable[] = {
     39   { SYSTEM_ROM_FILE_GUID,  1 },
     40   { NULL_ROM_FILE_GUID,    0 }
     41 };
     42 
     43 EFI_HANDLE  mVgaHandles[0x20];
     44 EFI_HANDLE  mDiskHandles[0x20];
     45 EFI_HANDLE  mIsaHandles[0x20];
     46 
     47 EFI_LEGACY_IRQ_PRIORITY_TABLE_ENTRY IrqPriorityTable[MAX_IRQ_PRIORITY_ENTRIES] = {
     48   {0x0B,0},
     49   {0x09,0},
     50   {0x0A,0},
     51   {0x05,0},
     52   {0x07,0},
     53   {0x00,0},
     54   {0x00,0}
     55 };
     56 
     57 //
     58 // PIRQ Table
     59 // - Slot numbering will be used to update the bus number and determine bridge
     60 //   to check to get bus number.  The Slot number - 1 is an index into a decode
     61 //   table to get the bridge information.
     62 //
     63 EFI_LEGACY_PIRQ_TABLE PirqTableHead = {
     64   {
     65     EFI_LEGACY_PIRQ_TABLE_SIGNATURE, // UINT32  Signature
     66     0x00,             // UINT8   MinorVersion
     67     0x01,             // UINT8   MajorVersion
     68     0x0000,           // UINT16  TableSize
     69     0x00,             // UINT8   Bus
     70     0x08,             // UINT8   DevFun
     71     0x0000,           // UINT16  PciOnlyIrq
     72     0x8086,           // UINT16  CompatibleVid
     73     0x122e,           // UINT16  CompatibleDid
     74     0x00000000,       // UINT32  Miniport
     75     {                 // UINT8   Reserved[11]
     76       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     77       0x00, 0x00, 0x00
     78     },
     79     0x00,             // UINT8   Checksum
     80   },
     81   {
     82     //           -- Pin 1 --   -- Pin 2 --   -- Pin 3 --   -- Pin 4 --
     83     // Bus  Dev   Reg   Map     Reg   Map     Reg   Map     Reg   Map
     84     //
     85     {0x00,0x08,{{0x60,0xDEB8},{0x61,0xDEB8},{0x62,0xDEB8},{0x63,0xDEB8}},0x00,0x00},
     86     {0x00,0x10,{{0x61,0xDEB8},{0x62,0xDEB8},{0x63,0xDEB8},{0x60,0xDEB8}},0x01,0x00},
     87     {0x00,0x18,{{0x62,0xDEB8},{0x63,0xDEB8},{0x60,0xDEB8},{0x61,0xDEB8}},0x02,0x00},
     88     {0x00,0x20,{{0x63,0xDEB8},{0x60,0xDEB8},{0x61,0xDEB8},{0x62,0xDEB8}},0x03,0x00},
     89     {0x00,0x28,{{0x60,0xDEB8},{0x61,0xDEB8},{0x62,0xDEB8},{0x63,0xDEB8}},0x04,0x00},
     90     {0x00,0x30,{{0x61,0xDEB8},{0x62,0xDEB8},{0x63,0xDEB8},{0x60,0xDEB8}},0x05,0x00},
     91   }
     92 };
     93 
     94 LEGACY_BIOS_PLATFORM_INSTANCE       mPrivateData;
     95 EFI_HANDLE                          mImageHandle = NULL;
     96 
     97 /**
     98   Return the handles and assorted information for the specified PCI Class code
     99 
    100   @param[in]     PciClasses    Array of PCI_CLASS_RECORD to find terminated with ClassCode 0xff
    101   @param[in,out] DeviceTable   Table to place handles etc in.
    102   @param[in,out] DeviceIndex   Number of devices found
    103   @param[in]     DeviceFlags   FALSE if a valid legacy ROM is required, TRUE otherwise.
    104 
    105   @retval EFI_SUCCESS     One or more devices found
    106   @retval EFI_NOT_FOUND   No device found
    107 
    108 **/
    109 EFI_STATUS
    110 FindAllDeviceTypes (
    111   IN       PCI_CLASS_RECORD      *PciClasses,
    112   IN OUT   DEVICE_STRUCTURE      *DeviceTable,
    113   IN OUT   UINT16                *DeviceIndex,
    114   IN       BOOLEAN               DeviceFlags
    115   )
    116 {
    117   UINTN                       HandleCount;
    118   EFI_HANDLE                  *HandleBuffer;
    119   UINTN                       Index;
    120   UINTN                       StartIndex;
    121   PCI_TYPE00                  PciConfigHeader;
    122   EFI_PCI_IO_PROTOCOL         *PciIo;
    123   EFI_LEGACY_BIOS_PROTOCOL    *LegacyBios;
    124   UINTN                       Flags;
    125   EFI_STATUS                  Status;
    126   UINTN                       Index2;
    127 
    128   //
    129   // Get legacy BIOS protocol as it is required to deal with Option ROMs.
    130   //
    131   StartIndex = *DeviceIndex;
    132   Status = gBS->LocateProtocol (
    133                   &gEfiLegacyBiosProtocolGuid,
    134                   NULL,
    135                   (VOID**)&LegacyBios
    136                   );
    137   ASSERT_EFI_ERROR (Status);
    138 
    139   //
    140   // Get all PCI handles and check them to generate a list of matching devices.
    141   //
    142   gBS->LocateHandleBuffer (
    143          ByProtocol,
    144          &gEfiPciIoProtocolGuid,
    145          NULL,
    146          &HandleCount,
    147          &HandleBuffer
    148          );
    149   for (Index = 0; Index < HandleCount; Index++) {
    150     gBS->HandleProtocol (
    151            HandleBuffer[Index],
    152            &gEfiPciIoProtocolGuid,
    153            (VOID**)&PciIo
    154            );
    155     PciIo->Pci.Read (
    156                  PciIo,
    157                  EfiPciIoWidthUint32,
    158                  0,
    159                  sizeof (PciConfigHeader) / sizeof (UINT32),
    160                  &PciConfigHeader
    161                  );
    162     for (Index2 = 0; PciClasses[Index2].Class != 0xff; Index2++) {
    163         if ((PciConfigHeader.Hdr.ClassCode[2] == PciClasses[Index2].Class) &&
    164             (PciConfigHeader.Hdr.ClassCode[1] == PciClasses[Index2].SubClass)) {
    165         LegacyBios->CheckPciRom (
    166                       LegacyBios,
    167                       HandleBuffer[Index],
    168                       NULL,
    169                       NULL,
    170                       &Flags
    171                       );
    172 
    173         //
    174         // Verify that results of OPROM check match request.
    175         // The two valid requests are:
    176         //   DeviceFlags = 0 require a valid legacy ROM
    177         //   DeviceFlags = 1 require either no ROM or a valid legacy ROM
    178         //
    179         if (
    180             ((DeviceFlags != 0) && (Flags == NO_ROM)) ||
    181             ((Flags & (ROM_FOUND | VALID_LEGACY_ROM)) == (ROM_FOUND | VALID_LEGACY_ROM))
    182            ) {
    183           DeviceTable->Handle = HandleBuffer[Index];
    184           DeviceTable->Vid    = PciConfigHeader.Hdr.VendorId;
    185           DeviceTable->Did    = PciConfigHeader.Hdr.DeviceId;
    186           DeviceTable->SvId   = PciConfigHeader.Device.SubsystemVendorID;
    187           DeviceTable->SysId  = PciConfigHeader.Device.SubsystemID;
    188           ++ *DeviceIndex;
    189           DeviceTable++;
    190         }
    191       }
    192     }
    193   }
    194 
    195   //
    196   // Free any allocated buffers
    197   //
    198   gBS->FreePool (HandleBuffer);
    199 
    200   if (*DeviceIndex != StartIndex) {
    201     return EFI_SUCCESS;
    202   } else {
    203     return EFI_NOT_FOUND;
    204   }
    205 }
    206 
    207 /**
    208   Load and initialize the Legacy BIOS SMM handler.
    209 
    210   @param  This                   The protocol instance pointer.
    211   @param  EfiToLegacy16BootTable A pointer to Legacy16 boot table.
    212 
    213   @retval EFI_SUCCESS           SMM code loaded.
    214   @retval EFI_DEVICE_ERROR      SMM code failed to load
    215 
    216 **/
    217 EFI_STATUS
    218 EFIAPI
    219 SmmInit (
    220   IN  EFI_LEGACY_BIOS_PLATFORM_PROTOCOL           *This,
    221   IN  VOID                                        *EfiToLegacy16BootTable
    222   )
    223 {
    224   return EFI_SUCCESS;
    225 }
    226 
    227 /**
    228   Finds the device path that should be used as the primary display adapter.
    229 
    230   @param  VgaHandle - The handle of the video device
    231 
    232 **/
    233 VOID
    234 GetSelectedVgaDeviceInfo (
    235   OUT EFI_HANDLE                *VgaHandle
    236   )
    237 {
    238   EFI_STATUS                Status;
    239   UINTN                     HandleCount;
    240   EFI_HANDLE                *HandleBuffer;
    241   UINTN                     Index;
    242   EFI_PCI_IO_PROTOCOL       *PciIo;
    243   PCI_TYPE00                Pci;
    244   UINT8                     MinBus;
    245   UINT8                     MaxBus;
    246   UINTN                     Segment;
    247   UINTN                     Bus;
    248   UINTN                     Device;
    249   UINTN                     Function;
    250   UINTN                     SelectedAddress;
    251   UINTN                     CurrentAddress;
    252 
    253   //
    254   // Initialize return to 'not found' state
    255   //
    256   *VgaHandle = NULL;
    257 
    258   //
    259   // Initialize variable states.  This is important for selecting the VGA
    260   // device if multiple devices exist behind a single bridge.
    261   //
    262   HandleCount = 0;
    263   HandleBuffer = NULL;
    264   SelectedAddress = PCI_LIB_ADDRESS(0xff, 0x1f, 0x7, 0);
    265 
    266   //
    267   // The bus range to search for a VGA device in.
    268   //
    269   MinBus = MaxBus = 0;
    270 
    271   //
    272   // Start to check all the pci io to find all possible VGA device
    273   //
    274   HandleCount = 0;
    275   HandleBuffer = NULL;
    276   Status = gBS->LocateHandleBuffer (
    277                   ByProtocol,
    278                   &gEfiPciIoProtocolGuid,
    279                   NULL,
    280                   &HandleCount,
    281                   &HandleBuffer
    282                   );
    283   if (EFI_ERROR (Status)) {
    284     return;
    285   }
    286 
    287   for (Index = 0; Index < HandleCount; Index++) {
    288     Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID**)&PciIo);
    289     if (!EFI_ERROR (Status)) {
    290       //
    291       // Detemine if this is in the correct bus range.
    292       //
    293       Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);
    294       if (EFI_ERROR(Status) || (Bus < MinBus || Bus > MaxBus)) {
    295         continue;
    296       }
    297 
    298       //
    299       // Read device information.
    300       //
    301       Status = PciIo->Pci.Read (
    302                         PciIo,
    303                         EfiPciIoWidthUint32,
    304                         0,
    305                         sizeof (Pci) / sizeof (UINT32),
    306                         &Pci
    307                         );
    308       if (EFI_ERROR (Status)) {
    309         continue;
    310       }
    311 
    312       //
    313       // Make sure the device is a VGA device.
    314       //
    315       if (!IS_PCI_VGA (&Pci)) {
    316         continue;
    317       }
    318       DEBUG ((EFI_D_INFO,
    319         "PCI VGA: 0x%04x:0x%04x\n",
    320         Pci.Hdr.VendorId,
    321         Pci.Hdr.DeviceId
    322         ));
    323 
    324       //
    325       // Currently we use the lowest numbered bus/device/function if multiple
    326       // devices are found in the target bus range.
    327       //
    328       CurrentAddress = PCI_LIB_ADDRESS(Bus, Device, Function, 0);
    329       if (CurrentAddress < SelectedAddress) {
    330         SelectedAddress = CurrentAddress;
    331         *VgaHandle = HandleBuffer[Index];
    332       }
    333     }
    334   }
    335 
    336   FreePool (HandleBuffer);
    337 }
    338 
    339 
    340 /**
    341   Returns a buffer of handles for the requested subfunction.
    342 
    343   @param  This                  The protocol instance pointer.
    344   @param  Mode                  Specifies what handle to return. See EFI_GET_PLATFORM_HANDLE_MODE enum.
    345   @param  Type                  Mode specific. See EFI_GET_PLATFORM_HANDLE_MODE enum.
    346   @param  HandleBuffer          Mode specific. See EFI_GET_PLATFORM_HANDLE_MODE enum.
    347   @param  HandleCount           Mode specific. See EFI_GET_PLATFORM_HANDLE_MODE enum.
    348   @param  AdditionalData        Mode specific. See EFI_GET_PLATFORM_HANDLE_MODE enum.
    349 
    350   @retval EFI_SUCCESS           Handle is valid.
    351   @retval EFI_UNSUPPORTED       Mode is not supported on the platform.
    352   @retval EFI_NOT_FOUND         Handle is not known.
    353 
    354 **/
    355 EFI_STATUS
    356 EFIAPI
    357 GetPlatformHandle (
    358   IN  EFI_LEGACY_BIOS_PLATFORM_PROTOCOL           *This,
    359   IN  EFI_GET_PLATFORM_HANDLE_MODE                Mode,
    360   IN  UINT16                                      Type,
    361   OUT EFI_HANDLE                                  **HandleBuffer,
    362   OUT UINTN                                       *HandleCount,
    363   OUT VOID                                        **AdditionalData OPTIONAL
    364   )
    365 {
    366   DEVICE_STRUCTURE    LocalDevice[0x40];
    367   UINT32              LocalIndex;
    368   UINT32              Index;
    369   DEVICE_STRUCTURE    TempDevice;
    370   EFI_STATUS          Status;
    371   EFI_PCI_IO_PROTOCOL *PciIo;
    372   UINTN               Segment;
    373   UINTN               Bus;
    374   UINTN               Device;
    375   UINTN               Function;
    376   HDD_INFO            *HddInfo;
    377   PCI_TYPE00          PciConfigHeader;
    378   UINT32              HddIndex;
    379   EFI_HANDLE          IdeHandle;
    380   EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;
    381   PCI_CLASS_RECORD    ClassLists[10];
    382   UINTN               PriorityIndex;
    383 
    384   static BOOLEAN      bConnected = FALSE;
    385 
    386   LocalIndex  = 0x00;
    387   HddInfo     = NULL;
    388   HddIndex    = 0;
    389 
    390   Status = gBS->LocateProtocol (
    391                   &gEfiLegacyBiosProtocolGuid,
    392                   NULL,
    393                   (VOID**)&LegacyBios
    394                   );
    395 
    396   //
    397   // Process mode specific operations
    398   //
    399   switch (Mode) {
    400     case EfiGetPlatformVgaHandle:
    401       //
    402       // Get the handle for the currently selected VGA device.
    403       //
    404       GetSelectedVgaDeviceInfo (&mVgaHandles[0]);
    405       *HandleBuffer = &mVgaHandles[0];
    406       *HandleCount  = (mVgaHandles[0] != NULL) ? 1 : 0;
    407       return EFI_SUCCESS;
    408     case EfiGetPlatformIdeHandle:
    409       IdeHandle  = NULL;
    410       if (AdditionalData != NULL) {
    411         HddInfo = (HDD_INFO *) *AdditionalData;
    412       }
    413 
    414       //
    415       // Locate all found block io devices
    416       //
    417       ClassLists[0].Class    = PCI_CLASS_MASS_STORAGE;
    418       ClassLists[0].SubClass = PCI_CLASS_MASS_STORAGE_SCSI;
    419       ClassLists[1].Class    = PCI_CLASS_MASS_STORAGE;
    420       ClassLists[1].SubClass = PCI_CLASS_MASS_STORAGE_IDE;
    421       ClassLists[2].Class    = PCI_CLASS_MASS_STORAGE;
    422       ClassLists[2].SubClass = PCI_CLASS_MASS_STORAGE_RAID;
    423       ClassLists[3].Class    = PCI_CLASS_MASS_STORAGE;
    424       ClassLists[3].SubClass = PCI_CLASS_MASS_STORAGE_SATADPA;
    425       ClassLists[4].Class    = 0xff;
    426       FindAllDeviceTypes (ClassLists, LocalDevice, (UINT16 *) &LocalIndex, TRUE);
    427       if (LocalIndex == 0) {
    428         return EFI_NOT_FOUND;
    429       }
    430 
    431       //
    432       // Make sure all IDE controllers are connected. This is necessary
    433       // in NO_CONFIG_CHANGE boot path to ensure IDE controller is correctly
    434       // initialized and all IDE drives are enumerated
    435       //
    436       if (!bConnected) {
    437         for (Index = 0; Index < LocalIndex; Index++) {
    438           gBS->ConnectController (LocalDevice[Index].Handle, NULL, NULL, TRUE);
    439         }
    440       }
    441 
    442       //
    443       // Locate onboard controllers.
    444       //
    445       for (Index = 0; Index < LocalIndex; Index++) {
    446         if (LocalDevice[Index].Vid == V_INTEL_VENDOR_ID) {
    447           if (LocalDevice[Index].Did == V_PIIX4_IDE_DEVICE_ID) {
    448             IdeHandle = LocalDevice[Index].Handle;
    449           }
    450         }
    451       }
    452 
    453       //
    454       // Set the IDE contorller as primary devices.
    455       //
    456       PriorityIndex = 0;
    457       for (Index = 0; Index < LocalIndex; Index++) {
    458         if (LocalDevice[Index].Handle == IdeHandle && PriorityIndex == 0) {
    459           TempDevice = LocalDevice[PriorityIndex];
    460           LocalDevice[PriorityIndex] = LocalDevice[Index];
    461           LocalDevice[Index] = TempDevice;
    462           PriorityIndex++;
    463           break;
    464         }
    465       }
    466 
    467       //
    468       // Copy over handles and update return values.
    469       //
    470       for (Index = 0; Index < LocalIndex; Index++) {
    471         mDiskHandles[Index] = LocalDevice[Index].Handle;
    472       }
    473       *HandleBuffer = &mDiskHandles[0];
    474       *HandleCount  = LocalIndex;
    475 
    476       //
    477       // We have connected all IDE controllers once. No more needed
    478       //
    479       bConnected = TRUE;
    480 
    481       //
    482       // Log all onboard controllers.
    483       //
    484       for (Index = 0; (Index < LocalIndex) && (AdditionalData != NULL); Index++) {
    485         if ((LocalDevice[Index].Handle != NULL) &&
    486             (LocalDevice[Index].Handle == IdeHandle)) {
    487           Status = gBS->HandleProtocol (
    488                           LocalDevice[Index].Handle,
    489                           &gEfiPciIoProtocolGuid,
    490                           (VOID **) &PciIo
    491                           );
    492           PciIo->Pci.Read (
    493                        PciIo,
    494                        EfiPciIoWidthUint32,
    495                        0,
    496                        sizeof (PciConfigHeader) / sizeof (UINT32),
    497                        &PciConfigHeader
    498                        );
    499           if (!EFI_ERROR (Status)) {
    500             PciIo->GetLocation (
    501                      PciIo,
    502                      &Segment,
    503                      &Bus,
    504                      &Device,
    505                      &Function
    506                      );
    507 
    508             //
    509             // Be sure to only fill out correct information based on platform
    510             // configureation.
    511             //
    512             HddInfo[HddIndex].Status        |= HDD_PRIMARY;
    513             HddInfo[HddIndex].Bus           = (UINT32)Bus;
    514             HddInfo[HddIndex].Device        = (UINT32)Device;
    515             HddInfo[HddIndex].Function      = (UINT32)Function;
    516             HddInfo[HddIndex + 1].Status    |= HDD_SECONDARY;
    517             HddInfo[HddIndex + 1].Bus       = (UINT32)Bus;
    518             HddInfo[HddIndex + 1].Device    = (UINT32)Device;
    519             HddInfo[HddIndex + 1].Function  = (UINT32)Function;
    520 
    521             //
    522             // Primary controller data
    523             //
    524             if ((PciConfigHeader.Hdr.ClassCode[0] & 0x01) != 0) {
    525               HddInfo[HddIndex].CommandBaseAddress =
    526                 (UINT16)(PciConfigHeader.Device.Bar[0] & 0xfffc);
    527               HddInfo[HddIndex].ControlBaseAddress =
    528                 (UINT16)((PciConfigHeader.Device.Bar[1] & 0xfffc)+2);
    529               HddInfo[HddIndex].BusMasterAddress =
    530                 (UINT16)(PciConfigHeader.Device.Bar[4] & 0xfffc);
    531               HddInfo[HddIndex].HddIrq = PciConfigHeader.Device.InterruptLine;
    532             } else {
    533               HddInfo[HddIndex].HddIrq = 14;
    534               HddInfo[HddIndex].CommandBaseAddress = 0x1f0;
    535               HddInfo[HddIndex].ControlBaseAddress = 0x3f6;
    536               HddInfo[HddIndex].BusMasterAddress = 0;
    537             }
    538             HddIndex++;
    539 
    540             //
    541             // Secondary controller data
    542             //
    543             if ((PciConfigHeader.Hdr.ClassCode[0] & 0x04) != 0) {
    544               HddInfo[HddIndex].CommandBaseAddress =
    545                 (UINT16)(PciConfigHeader.Device.Bar[2] & 0xfffc);
    546               HddInfo[HddIndex].ControlBaseAddress =
    547                 (UINT16)((PciConfigHeader.Device.Bar[3] & 0xfffc)+2);
    548               HddInfo[HddIndex].BusMasterAddress =
    549                 (UINT16)(HddInfo[HddIndex].BusMasterAddress + 8);
    550               HddInfo[HddIndex].HddIrq = PciConfigHeader.Device.InterruptLine;
    551             } else {
    552               HddInfo[HddIndex].HddIrq = 15;
    553               HddInfo[HddIndex].CommandBaseAddress = 0x170;
    554               HddInfo[HddIndex].ControlBaseAddress = 0x376;
    555               HddInfo[HddIndex].BusMasterAddress = 0;
    556             }
    557             HddIndex++;
    558           }
    559         }
    560       }
    561       return EFI_SUCCESS;
    562     case EfiGetPlatformIsaBusHandle:
    563       ClassLists[0].Class    = (UINT8) PCI_CLASS_BRIDGE;
    564       ClassLists[0].SubClass = (UINT8) PCI_CLASS_BRIDGE_ISA_PDECODE;
    565       ClassLists[1].Class    = (UINT8) PCI_CLASS_BRIDGE;
    566       ClassLists[1].SubClass = (UINT8) PCI_CLASS_BRIDGE_ISA;
    567       ClassLists[2].Class    = 0xff;
    568 
    569       //
    570       // Locate all found block io devices
    571       //
    572       FindAllDeviceTypes (ClassLists, LocalDevice, (UINT16 *) (&LocalIndex), TRUE);
    573       if (LocalIndex == 0) {
    574         return EFI_NOT_FOUND;
    575       }
    576 
    577       //
    578       // Find our ISA bridge.
    579       //
    580       for (Index = 0; Index < LocalIndex; Index++) {
    581         if (LocalDevice[Index].Vid == V_INTEL_VENDOR_ID) {
    582           TempDevice          = LocalDevice[0];
    583           LocalDevice[0]      = LocalDevice[Index];
    584           LocalDevice[Index]  = TempDevice;
    585         }
    586       }
    587 
    588       //
    589       // Perform copy and update return values.
    590       //
    591       for (Index = 0; Index < LocalIndex; Index++) {
    592         mIsaHandles[Index] = LocalDevice[Index].Handle;
    593       }
    594       *HandleBuffer = &mIsaHandles[0];
    595       *HandleCount  = LocalIndex;
    596       return EFI_SUCCESS;
    597     case EfiGetPlatformUsbHandle:
    598     default:
    599       return EFI_UNSUPPORTED;
    600   };
    601 }
    602 
    603 /**
    604   Allows platform to perform any required action after a LegacyBios operation.
    605   Invokes the specific sub function specified by Mode.
    606 
    607   @param  This                  The protocol instance pointer.
    608   @param  Mode                  Specifies what handle to return. See EFI_GET_PLATFORM_HOOK_MODE enum.
    609   @param  Type                  Mode specific.  See EFI_GET_PLATFORM_HOOK_MODE enum.
    610   @param  DeviceHandle          Mode specific.  See EFI_GET_PLATFORM_HOOK_MODE enum.
    611   @param  ShadowAddress         Mode specific.  See EFI_GET_PLATFORM_HOOK_MODE enum.
    612   @param  Compatibility16Table  Mode specific.  See EFI_GET_PLATFORM_HOOK_MODE enum.
    613   @param  AdditionalData        Mode specific.  See EFI_GET_PLATFORM_HOOK_MODE enum.
    614 
    615   @retval EFI_SUCCESS           The operation performed successfully. Mode specific.
    616   @retval EFI_UNSUPPORTED       Mode is not supported on the platform.
    617 
    618 **/
    619 EFI_STATUS
    620 EFIAPI
    621 PlatformHooks (
    622   IN       EFI_LEGACY_BIOS_PLATFORM_PROTOCOL     *This,
    623   IN       EFI_GET_PLATFORM_HOOK_MODE            Mode,
    624   IN       UINT16                                Type,
    625      OUT   EFI_HANDLE                            DeviceHandle, OPTIONAL
    626   IN OUT   UINTN                                 *Shadowaddress, OPTIONAL
    627   IN       EFI_COMPATIBILITY16_TABLE             *Compatibility16Table, OPTIONAL
    628      OUT   VOID                                  **AdditionalData OPTIONAL
    629   )
    630 {
    631   EFI_IA32_REGISTER_SET     Regs;
    632   EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;
    633   EFI_STATUS                Status;
    634 
    635   switch (Mode) {
    636     case EfiPlatformHookPrepareToScanRom:
    637       Status = gBS->LocateProtocol (
    638                       &gEfiLegacyBiosProtocolGuid,
    639                       NULL,
    640                       (VOID**)&LegacyBios
    641                       );
    642 
    643       //
    644       // Set the 80x25 Text VGA Mode
    645       //
    646       Regs.H.AH = 0x00;
    647       Regs.H.AL = 0x03;
    648       Status = LegacyBios->Int86 (LegacyBios, 0x10, &Regs);
    649       return Status;
    650     case EfiPlatformHookShadowServiceRoms:
    651       return EFI_SUCCESS;
    652     case EfiPlatformHookAfterRomInit:
    653     default:
    654       return EFI_UNSUPPORTED;
    655   };
    656 }
    657 
    658 /**
    659   Returns information associated with PCI IRQ routing.
    660   This function returns the following information associated with PCI IRQ routing:
    661     * An IRQ routing table and number of entries in the table.
    662     * The $PIR table and its size.
    663     * A list of PCI IRQs and the priority order to assign them.
    664 
    665   @param  This                    The protocol instance pointer.
    666   @param  RoutingTable            The pointer to PCI IRQ Routing table.
    667                                   This location is the $PIR table minus the header.
    668   @param  RoutingTableEntries     The number of entries in table.
    669   @param  LocalPirqTable          $PIR table.
    670   @param  PirqTableSize           $PIR table size.
    671   @param  LocalIrqPriorityTable   A list of interrupts in priority order to assign.
    672   @param  IrqPriorityTableEntries The number of entries in the priority table.
    673 
    674   @retval EFI_SUCCESS           Data was successfully returned.
    675 
    676 **/
    677 EFI_STATUS
    678 EFIAPI
    679 GetRoutingTable (
    680   IN  EFI_LEGACY_BIOS_PLATFORM_PROTOCOL           *This,
    681   OUT VOID                                        **RoutingTable,
    682   OUT UINTN                                       *RoutingTableEntries,
    683   OUT VOID                                        **LocalPirqTable, OPTIONAL
    684   OUT UINTN                                       *PirqTableSize, OPTIONAL
    685   OUT VOID                                        **LocalIrqPriorityTable, OPTIONAL
    686   OUT UINTN                                       *IrqPriorityTableEntries OPTIONAL
    687   )
    688 {
    689   UINT16                        PTableSize;
    690   UINT32                        Index;
    691   UINT8                         Bus;
    692   UINT8                         Device;
    693   UINT8                         Function;
    694   UINT8                         Checksum;
    695   UINT8                         *Ptr;
    696   EFI_STATUS                    Status;
    697   EFI_LEGACY_INTERRUPT_PROTOCOL *LegacyInterrupt;
    698 
    699   Checksum = 0;
    700 
    701   if (LocalPirqTable != NULL) {
    702     PTableSize = sizeof (EFI_LEGACY_PIRQ_TABLE_HEADER) +
    703                  sizeof (EFI_LEGACY_IRQ_ROUTING_ENTRY) * MAX_IRQ_ROUTING_ENTRIES;
    704 
    705     Status = gBS->LocateProtocol (
    706                     &gEfiLegacyInterruptProtocolGuid,
    707                     NULL,
    708                     (VOID**)&LegacyInterrupt
    709                     );
    710     ASSERT_EFI_ERROR (Status);
    711     LegacyInterrupt->GetLocation (
    712                        LegacyInterrupt,
    713                        &Bus,
    714                        &Device,
    715                        &Function
    716                        );
    717 
    718     //
    719     // Update fields in $PIR table header
    720     //
    721     PirqTableHead.PirqTable.TableSize = PTableSize;
    722     PirqTableHead.PirqTable.Bus       = Bus;
    723     PirqTableHead.PirqTable.DevFun    = (UINT8) ((Device << 3) + Function);
    724     Ptr = (UINT8 *) (&PirqTableHead);
    725 
    726     //
    727     // Calculate checksum.
    728     //
    729     for (Index = 0; Index < PTableSize; Index++) {
    730       Checksum = (UINT8) (Checksum + (UINT8) *Ptr);
    731       Ptr += 1;
    732     }
    733     Checksum                          = (UINT8) (0x00 - Checksum);
    734     PirqTableHead.PirqTable.Checksum  = Checksum;
    735 
    736     //
    737     // Update return values.
    738     //
    739     *LocalPirqTable                   = (VOID *) (&PirqTableHead);
    740     *PirqTableSize                    = PTableSize;
    741   }
    742 
    743   //
    744   // More items to return.
    745   //
    746   *RoutingTable         = PirqTableHead.IrqRoutingEntry;
    747   *RoutingTableEntries  = MAX_IRQ_ROUTING_ENTRIES;
    748   if (LocalIrqPriorityTable != NULL) {
    749     *LocalIrqPriorityTable    = IrqPriorityTable;
    750     *IrqPriorityTableEntries  = MAX_IRQ_PRIORITY_ENTRIES;
    751   }
    752 
    753   return EFI_SUCCESS;
    754 }
    755 
    756 /**
    757   Finds the binary data or other platform information.
    758 
    759   @param  This                  The protocol instance pointer.
    760   @param  Mode                  Specifies what data to return. See See EFI_GET_PLATFORM_INFO_MODE enum.
    761   @param  Table                 Mode specific.  See EFI_GET_PLATFORM_INFO_MODE enum.
    762   @param  TableSize             Mode specific.  See EFI_GET_PLATFORM_INFO_MODE enum.
    763   @param  Location              Mode specific.  See EFI_GET_PLATFORM_INFO_MODE enum.
    764   @param  Alignment             Mode specific.  See EFI_GET_PLATFORM_INFO_MODE enum.
    765   @param  LegacySegment         Mode specific.  See EFI_GET_PLATFORM_INFO_MODE enum.
    766   @param  LegacyOffset          Mode specific.  See EFI_GET_PLATFORM_INFO_MODE enum.
    767 
    768   @retval EFI_SUCCESS           Data returned successfully.
    769   @retval EFI_UNSUPPORTED       Mode is not supported on the platform.
    770   @retval EFI_NOT_FOUND         Binary image or table not found.
    771 
    772 **/
    773 EFI_STATUS
    774 EFIAPI
    775 GetPlatformInfo (
    776   IN  EFI_LEGACY_BIOS_PLATFORM_PROTOCOL           *This,
    777   IN  EFI_GET_PLATFORM_INFO_MODE                  Mode,
    778   OUT VOID                                        **Table,
    779   OUT UINTN                                       *TableSize,
    780   OUT UINTN                                       *Location,
    781   OUT UINTN                                       *Alignment,
    782   IN  UINT16                                      LegacySegment,
    783   IN  UINT16                                      LegacyOffset
    784   )
    785 {
    786   EFI_STATUS                    Status;
    787   UINTN                         Index;
    788 
    789   switch (Mode) {
    790     case EfiGetPlatformBinarySystemRom:
    791       //
    792       // Loop through table of System rom descriptions
    793       //
    794       for (Index = 0; mSystemRomTable[Index].Valid != 0; Index++) {
    795         Status = GetSectionFromFv (
    796                    &mSystemRomTable[Index].FileName,
    797                    EFI_SECTION_RAW,
    798                    0,
    799                    Table,
    800                    (UINTN *) TableSize
    801                    );
    802         if (EFI_ERROR (Status)) {
    803           continue;
    804         }
    805         return EFI_SUCCESS;
    806       }
    807 
    808       return EFI_NOT_FOUND;
    809     case EfiGetPlatformBinaryOem16Data:
    810     case EfiGetPlatformBinaryMpTable:
    811     case EfiGetPlatformBinaryOemIntData:
    812     case EfiGetPlatformBinaryOem32Data:
    813     case EfiGetPlatformBinaryTpmBinary:
    814     case EfiGetPlatformPciExpressBase:
    815     default:
    816       return EFI_UNSUPPORTED;
    817   };
    818 }
    819 
    820 /**
    821   Translates the given PIRQ accounting for bridge.
    822   This function translates the given PIRQ back through all buses, if required,
    823   and returns the true PIRQ and associated IRQ.
    824 
    825   @param  This                  The protocol instance pointer.
    826   @param  PciBus                The PCI bus number for this device.
    827   @param  PciDevice             The PCI device number for this device.
    828   @param  PciFunction           The PCI function number for this device.
    829   @param  Pirq                  Input is PIRQ reported by device, and output is true PIRQ.
    830   @param  PciIrq                The IRQ already assigned to the PIRQ, or the IRQ to be
    831                                 assigned to the PIRQ.
    832 
    833   @retval EFI_SUCCESS           The PIRQ was translated.
    834 
    835 **/
    836 EFI_STATUS
    837 EFIAPI
    838 TranslatePirq (
    839   IN        EFI_LEGACY_BIOS_PLATFORM_PROTOCOL           *This,
    840   IN        UINTN                                       PciBus,
    841   IN        UINTN                                       PciDevice,
    842   IN        UINTN                                       PciFunction,
    843   IN  OUT   UINT8                                       *Pirq,
    844       OUT   UINT8                                       *PciIrq
    845   )
    846 {
    847   EFI_LEGACY_INTERRUPT_PROTOCOL      *LegacyInterrupt;
    848   EFI_STATUS                         Status;
    849   UINTN                              Index;
    850   UINTN                              Index1;
    851   UINT8                              LocalPirq;
    852   UINT8                              PirqData;
    853   UINT8                              MatchData;
    854 
    855   Status = gBS->LocateProtocol (
    856                   &gEfiLegacyInterruptProtocolGuid,
    857                   NULL,
    858                   (VOID**)&LegacyInterrupt
    859                   );
    860   ASSERT_EFI_ERROR (Status);
    861   LocalPirq = (UINT8) (*Pirq);
    862 
    863   for (Index = 0; Index < MAX_IRQ_ROUTING_ENTRIES; Index++) {
    864     if ((PirqTableHead.IrqRoutingEntry[Index].Bus == PciBus) &&
    865         (PirqTableHead.IrqRoutingEntry[Index].Device == PciDevice)) {
    866       LocalPirq = (UINT8) (PirqTableHead.IrqRoutingEntry[Index].PirqEntry[LocalPirq].Pirq & 0x0f);
    867       if (LocalPirq > 4) {
    868         LocalPirq -= 4;
    869       }
    870 
    871       LegacyInterrupt->ReadPirq (LegacyInterrupt, LocalPirq, &PirqData);
    872       MatchData = PCI_UNUSED;
    873       while (PirqData == 0) {
    874         for (Index1 = 0; Index1 < MAX_IRQ_PRIORITY_ENTRIES; Index1++) {
    875           if ((IrqPriorityTable[Index1].Used == MatchData) &&
    876               (IrqPriorityTable[Index1].Irq != 0)) {
    877             PirqData = IrqPriorityTable[Index1].Irq;
    878             IrqPriorityTable[Index1].Used = 0xff;
    879             LegacyInterrupt->WritePirq (
    880                                LegacyInterrupt,
    881                                LocalPirq,
    882                                PirqData
    883                                );
    884             break;
    885           }
    886         }
    887 
    888         if (PirqData == 0) {
    889 
    890           //
    891           // No unused interrpts, so start reusing them.
    892           //
    893           MatchData = (UINT8) (~MatchData);
    894         }
    895       }
    896 
    897       *PciIrq = PirqData;
    898       *Pirq   = LocalPirq;
    899     }
    900   }
    901 
    902   return EFI_SUCCESS;
    903 }
    904 
    905 
    906 /**
    907   Attempt to legacy boot the BootOption. If the EFI contexted has been
    908   compromised this function will not return.
    909 
    910   @param  This                   The protocol instance pointer.
    911   @param  BbsDevicePath          The EFI Device Path from BootXXXX variable.
    912   @param  BbsTable               The Internal BBS table.
    913   @param  LoadOptionSize         The size of LoadOption in size.
    914   @param  LoadOption             The LoadOption from BootXXXX variable
    915   @param  EfiToLegacy16BootTable A pointer to BootTable structure
    916 
    917   @retval EFI_SUCCESS           Ready to boot.
    918 
    919 **/
    920 EFI_STATUS
    921 EFIAPI
    922 PrepareToBoot (
    923   IN  EFI_LEGACY_BIOS_PLATFORM_PROTOCOL           *This,
    924   IN  BBS_BBS_DEVICE_PATH                         *BbsDevicePath,
    925   IN  VOID                                        *BbsTable,
    926   IN  UINT32                                      LoadOptionsSize,
    927   IN  VOID                                        *LoadOptions,
    928   IN  VOID                                        *EfiToLegacy16BootTable
    929   )
    930 {
    931   BBS_TABLE                           *LocalBbsTable;
    932   EFI_TO_COMPATIBILITY16_BOOT_TABLE   *Legacy16BootTable;
    933   DEVICE_PRODUCER_DATA_HEADER         *SioPtr;
    934   UINT16                              DevicePathType;
    935   UINT16                              Index;
    936   UINT16                              Priority;
    937 
    938   //
    939   // Initialize values
    940   //
    941   Priority = 0;
    942   Legacy16BootTable = (EFI_TO_COMPATIBILITY16_BOOT_TABLE*) EfiToLegacy16BootTable;
    943 
    944   //
    945   // Set how Gate A20 is gated by hardware
    946   //
    947   SioPtr                  = &Legacy16BootTable->SioData;
    948   SioPtr->Flags.A20Kybd   = 1;
    949   SioPtr->Flags.A20Port90 = 1;
    950   SioPtr->MousePresent    = 1;
    951 
    952   LocalBbsTable           = BbsTable;
    953 
    954   //
    955   // There are 2 cases that must be covered.
    956   // Case 1: Booting to a legacy OS - BbsDevicePath is non-NULL.
    957   // Case 2: Booting to an EFI aware OS - BbsDevicePath is NULL.
    958   //         We need to perform the PrepareToBoot function to assign
    959   //         drive numbers to HDD devices to allow the shell or EFI
    960   //         to access them.
    961   //
    962   if (BbsDevicePath != NULL) {
    963     DevicePathType = BbsDevicePath->DeviceType;
    964   } else {
    965     DevicePathType = BBS_HARDDISK;
    966   }
    967 
    968   //
    969   // Skip the boot devices where priority is set by BDS and set the next one
    970   //
    971   for (Index = 0; Index < Legacy16BootTable->NumberBbsEntries; Index++) {
    972     if ((LocalBbsTable[Index].BootPriority != BBS_UNPRIORITIZED_ENTRY) &&
    973         (LocalBbsTable[Index].BootPriority != BBS_IGNORE_ENTRY) &&
    974         (LocalBbsTable[Index].BootPriority != BBS_LOWEST_PRIORITY) &&
    975         (Priority <= LocalBbsTable[Index].BootPriority)) {
    976       Priority = (UINT16) (LocalBbsTable[Index].BootPriority + 1);
    977     }
    978   }
    979 
    980   switch (DevicePathType) {
    981     case BBS_FLOPPY:
    982     case BBS_HARDDISK:
    983     case BBS_CDROM:
    984     case BBS_EMBED_NETWORK:
    985       for (Index = 0; Index < Legacy16BootTable->NumberBbsEntries; Index++) {
    986         if ((LocalBbsTable[Index].BootPriority == BBS_UNPRIORITIZED_ENTRY) &&
    987             (LocalBbsTable[Index].DeviceType == DevicePathType)) {
    988           LocalBbsTable[Index].BootPriority = Priority;
    989           ++Priority;
    990         }
    991       }
    992       break;
    993     case BBS_BEV_DEVICE:
    994       for (Index = 0; Index < Legacy16BootTable->NumberBbsEntries; Index++) {
    995         if ((LocalBbsTable[Index].BootPriority == BBS_UNPRIORITIZED_ENTRY) &&
    996             (LocalBbsTable[Index].Class == 01) &&
    997             (LocalBbsTable[Index].SubClass == 01)) {
    998           LocalBbsTable[Index].BootPriority = Priority;
    999           ++Priority;
   1000         }
   1001       }
   1002       break;
   1003     case BBS_USB:
   1004     case BBS_PCMCIA:
   1005     case BBS_UNKNOWN:
   1006     default:
   1007       break;
   1008   };
   1009 
   1010   //
   1011   // Set priority for rest of devices
   1012   //
   1013   for (Index = 0; Index < Legacy16BootTable->NumberBbsEntries; Index++) {
   1014     if (LocalBbsTable[Index].BootPriority == BBS_UNPRIORITIZED_ENTRY) {
   1015       LocalBbsTable[Index].BootPriority = Priority;
   1016       ++Priority;
   1017     }
   1018   }
   1019 
   1020   return EFI_SUCCESS;
   1021 }
   1022 
   1023 
   1024 /**
   1025   Initialize Legacy Platform support
   1026 
   1027   @retval EFI_SUCCESS   Successfully initialized
   1028 
   1029 **/
   1030 EFI_STATUS
   1031 LegacyBiosPlatformInstall (
   1032   VOID
   1033   )
   1034 {
   1035   EFI_STATUS                           Status;
   1036   LEGACY_BIOS_PLATFORM_INSTANCE        *Private;
   1037 
   1038   mImageHandle = gImageHandle;
   1039   Private = &mPrivateData;
   1040 
   1041   //
   1042   // Grab a copy of all the protocols we depend on.
   1043   //
   1044   Private->Signature = LEGACY_BIOS_PLATFORM_INSTANCE_SIGNATURE;
   1045   Private->LegacyBiosPlatform.GetPlatformInfo   = GetPlatformInfo;
   1046   Private->LegacyBiosPlatform.GetPlatformHandle = GetPlatformHandle;
   1047   Private->LegacyBiosPlatform.SmmInit           = SmmInit;
   1048   Private->LegacyBiosPlatform.PlatformHooks     = PlatformHooks;
   1049   Private->LegacyBiosPlatform.GetRoutingTable   = GetRoutingTable;
   1050   Private->LegacyBiosPlatform.TranslatePirq     = TranslatePirq;
   1051   Private->LegacyBiosPlatform.PrepareToBoot     = PrepareToBoot;
   1052   Private->ImageHandle = gImageHandle;
   1053 
   1054   //
   1055   // Make a new handle and install the protocol
   1056   //
   1057   Private->Handle = NULL;
   1058   Status = gBS->InstallProtocolInterface (
   1059                   &Private->Handle,
   1060                   &gEfiLegacyBiosPlatformProtocolGuid,
   1061                   EFI_NATIVE_INTERFACE,
   1062                   &Private->LegacyBiosPlatform
   1063                   );
   1064   return Status;
   1065 }
   1066 
   1067