Home | History | Annotate | Download | only in LegacyBiosDxe
      1 /** @file
      2 
      3 Copyright (c) 2006 - 2015, 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/Pci.h>
     18 
     19 #define BOOT_LEGACY_OS              0
     20 #define BOOT_EFI_OS                 1
     21 #define BOOT_UNCONVENTIONAL_DEVICE  2
     22 
     23 UINT32              mLoadOptionsSize    = 0;
     24 UINTN               mBootMode           = BOOT_LEGACY_OS;
     25 VOID                *mLoadOptions       = NULL;
     26 BBS_BBS_DEVICE_PATH *mBbsDevicePathPtr  = NULL;
     27 BBS_BBS_DEVICE_PATH mBbsDevicePathNode;
     28 UDC_ATTRIBUTES      mAttributes         = { 0, 0, 0, 0 };
     29 UINTN               mBbsEntry           = 0;
     30 VOID                *mBeerData          = NULL;
     31 VOID                *mServiceAreaData   = NULL;
     32 UINT64              mLowWater           = 0xffffffffffffffffULL;
     33 
     34 extern BBS_TABLE           *mBbsTable;
     35 
     36 extern VOID                  *mRuntimeSmbiosEntryPoint;
     37 extern EFI_PHYSICAL_ADDRESS  mReserveSmbiosEntryPoint;
     38 extern EFI_PHYSICAL_ADDRESS  mStructureTableAddress;
     39 
     40 /**
     41   Print the BBS Table.
     42 
     43   @param BbsTable   The BBS table.
     44 
     45 
     46 **/
     47 VOID
     48 PrintBbsTable (
     49   IN BBS_TABLE *BbsTable
     50   )
     51 {
     52   UINT16 Index;
     53   UINT16 SubIndex;
     54   CHAR8  *String;
     55 
     56   DEBUG ((EFI_D_INFO, "\n"));
     57   DEBUG ((EFI_D_INFO, " NO  Prio bb/dd/ff cl/sc Type Stat segm:offs mfgs:mfgo dess:deso\n"));
     58   DEBUG ((EFI_D_INFO, "=================================================================\n"));
     59   for (Index = 0; Index < MAX_BBS_ENTRIES; Index++) {
     60     //
     61     // Filter
     62     //
     63     if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {
     64       continue;
     65     }
     66 
     67     DEBUG ((
     68       EFI_D_INFO,
     69       " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x",
     70       (UINTN) Index,
     71       (UINTN) BbsTable[Index].BootPriority,
     72       (UINTN) BbsTable[Index].Bus,
     73       (UINTN) BbsTable[Index].Device,
     74       (UINTN) BbsTable[Index].Function,
     75       (UINTN) BbsTable[Index].Class,
     76       (UINTN) BbsTable[Index].SubClass,
     77       (UINTN) BbsTable[Index].DeviceType,
     78       (UINTN) * (UINT16 *) &BbsTable[Index].StatusFlags
     79       ));
     80     DEBUG ((
     81       EFI_D_INFO,
     82       " %04x:%04x %04x:%04x %04x:%04x",
     83       (UINTN) BbsTable[Index].BootHandlerSegment,
     84       (UINTN) BbsTable[Index].BootHandlerOffset,
     85       (UINTN) BbsTable[Index].MfgStringSegment,
     86       (UINTN) BbsTable[Index].MfgStringOffset,
     87       (UINTN) BbsTable[Index].DescStringSegment,
     88       (UINTN) BbsTable[Index].DescStringOffset
     89       ));
     90 
     91     //
     92     // Print DescString
     93     //
     94     String = (CHAR8 *)(UINTN)((BbsTable[Index].DescStringSegment << 4) + BbsTable[Index].DescStringOffset);
     95     if (String != NULL) {
     96       DEBUG ((EFI_D_INFO," ("));
     97       for (SubIndex = 0; String[SubIndex] != 0; SubIndex++) {
     98         DEBUG ((EFI_D_INFO, "%c", String[SubIndex]));
     99       }
    100       DEBUG ((EFI_D_INFO,")"));
    101     }
    102     DEBUG ((EFI_D_INFO,"\n"));
    103   }
    104 
    105   DEBUG ((EFI_D_INFO, "\n"));
    106 
    107   return ;
    108 }
    109 
    110 /**
    111   Print the BBS Table.
    112 
    113   @param HddInfo   The HddInfo table.
    114 
    115 
    116 **/
    117 VOID
    118 PrintHddInfo (
    119   IN HDD_INFO *HddInfo
    120   )
    121 {
    122   UINTN Index;
    123 
    124   DEBUG ((EFI_D_INFO, "\n"));
    125   for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {
    126     DEBUG ((EFI_D_INFO, "Index - %04x\n", Index));
    127     DEBUG ((EFI_D_INFO, "  Status    - %04x\n", (UINTN)HddInfo[Index].Status));
    128     DEBUG ((EFI_D_INFO, "  B/D/F     - %02x/%02x/%02x\n", (UINTN)HddInfo[Index].Bus, (UINTN)HddInfo[Index].Device, (UINTN)HddInfo[Index].Function));
    129     DEBUG ((EFI_D_INFO, "  Command   - %04x\n", HddInfo[Index].CommandBaseAddress));
    130     DEBUG ((EFI_D_INFO, "  Control   - %04x\n", HddInfo[Index].ControlBaseAddress));
    131     DEBUG ((EFI_D_INFO, "  BusMaster - %04x\n", HddInfo[Index].BusMasterAddress));
    132     DEBUG ((EFI_D_INFO, "  HddIrq    - %02x\n", HddInfo[Index].HddIrq));
    133     DEBUG ((EFI_D_INFO, "  IdentifyDrive[0].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[0].Raw[0]));
    134     DEBUG ((EFI_D_INFO, "  IdentifyDrive[1].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[1].Raw[0]));
    135   }
    136 
    137   DEBUG ((EFI_D_INFO, "\n"));
    138 
    139   return ;
    140 }
    141 
    142 /**
    143   Print the PCI Interrupt Line and Interrupt Pin registers.
    144 **/
    145 VOID
    146 PrintPciInterruptRegister (
    147   VOID
    148   )
    149 {
    150   EFI_STATUS                  Status;
    151   UINTN                       Index;
    152   EFI_HANDLE                  *Handles;
    153   UINTN                       HandleNum;
    154   EFI_PCI_IO_PROTOCOL         *PciIo;
    155   UINT8                       Interrupt[2];
    156   UINTN                       Segment;
    157   UINTN                       Bus;
    158   UINTN                       Device;
    159   UINTN                       Function;
    160 
    161   gBS->LocateHandleBuffer (
    162          ByProtocol,
    163          &gEfiPciIoProtocolGuid,
    164          NULL,
    165          &HandleNum,
    166          &Handles
    167          );
    168 
    169   Bus      = 0;
    170   Device   = 0;
    171   Function = 0;
    172 
    173   DEBUG ((EFI_D_INFO, "\n"));
    174   DEBUG ((EFI_D_INFO, " bb/dd/ff interrupt line interrupt pin\n"));
    175   DEBUG ((EFI_D_INFO, "======================================\n"));
    176   for (Index = 0; Index < HandleNum; Index++) {
    177     Status = gBS->HandleProtocol (Handles[Index], &gEfiPciIoProtocolGuid, (VOID **) &PciIo);
    178     if (!EFI_ERROR (Status)) {
    179       Status = PciIo->Pci.Read (
    180                             PciIo,
    181                             EfiPciIoWidthUint8,
    182                             PCI_INT_LINE_OFFSET,
    183                             2,
    184                             Interrupt
    185                             );
    186     }
    187     if (!EFI_ERROR (Status)) {
    188       Status = PciIo->GetLocation (
    189                         PciIo,
    190                         &Segment,
    191                         &Bus,
    192                         &Device,
    193                         &Function
    194                         );
    195     }
    196     if (!EFI_ERROR (Status)) {
    197       DEBUG ((EFI_D_INFO, " %02x/%02x/%02x 0x%02x           0x%02x\n",
    198               Bus, Device, Function, Interrupt[0], Interrupt[1]));
    199     }
    200   }
    201   DEBUG ((EFI_D_INFO, "\n"));
    202 
    203   if (Handles != NULL) {
    204     FreePool (Handles);
    205   }
    206 }
    207 
    208 /**
    209   Identify drive data must be updated to actual parameters before boot.
    210 
    211   @param  IdentifyDriveData       ATA Identify Data
    212 
    213 **/
    214 VOID
    215 UpdateIdentifyDriveData (
    216   IN  UINT8     *IdentifyDriveData
    217   );
    218 
    219 /**
    220   Update SIO data.
    221 
    222   @param  Private                 Legacy BIOS Instance data
    223 
    224   @retval EFI_SUCCESS             Removable media not present
    225 
    226 **/
    227 EFI_STATUS
    228 UpdateSioData (
    229   IN  LEGACY_BIOS_INSTANCE      *Private
    230   )
    231 {
    232   EFI_STATUS                          Status;
    233   UINTN                               Index;
    234   UINTN                               Index1;
    235   UINT8                               LegacyInterrupts[16];
    236   EFI_LEGACY_IRQ_ROUTING_ENTRY        *RoutingTable;
    237   UINTN                               RoutingTableEntries;
    238   EFI_LEGACY_IRQ_PRIORITY_TABLE_ENTRY *IrqPriorityTable;
    239   UINTN                               NumberPriorityEntries;
    240   EFI_TO_COMPATIBILITY16_BOOT_TABLE   *EfiToLegacy16BootTable;
    241   UINT8                               HddIrq;
    242   UINT16                              LegacyInt;
    243   UINT16                              LegMask;
    244   UINT32                              Register;
    245   UINTN                               HandleCount;
    246   EFI_HANDLE                          *HandleBuffer;
    247   EFI_ISA_IO_PROTOCOL                 *IsaIo;
    248 
    249   LegacyInt               = 0;
    250   HandleBuffer            = NULL;
    251 
    252   EfiToLegacy16BootTable  = &Private->IntThunk->EfiToLegacy16BootTable;
    253   LegacyBiosBuildSioData (Private);
    254   SetMem (LegacyInterrupts, sizeof (LegacyInterrupts), 0);
    255 
    256   //
    257   // Create list of legacy interrupts.
    258   //
    259   for (Index = 0; Index < 4; Index++) {
    260     LegacyInterrupts[Index] = EfiToLegacy16BootTable->SioData.Serial[Index].Irq;
    261   }
    262 
    263   for (Index = 4; Index < 7; Index++) {
    264     LegacyInterrupts[Index] = EfiToLegacy16BootTable->SioData.Parallel[Index - 4].Irq;
    265   }
    266 
    267   LegacyInterrupts[7] = EfiToLegacy16BootTable->SioData.Floppy.Irq;
    268 
    269   //
    270   // Get Legacy Hdd IRQs. If native mode treat as PCI
    271   //
    272   for (Index = 0; Index < 2; Index++) {
    273     HddIrq = EfiToLegacy16BootTable->HddInfo[Index].HddIrq;
    274     if ((HddIrq != 0) && ((HddIrq == 15) || (HddIrq == 14))) {
    275       LegacyInterrupts[Index + 8] = HddIrq;
    276     }
    277   }
    278 
    279   Private->LegacyBiosPlatform->GetRoutingTable (
    280                                 Private->LegacyBiosPlatform,
    281                                 (VOID *) &RoutingTable,
    282                                 &RoutingTableEntries,
    283                                 NULL,
    284                                 NULL,
    285                                 (VOID **) &IrqPriorityTable,
    286                                 &NumberPriorityEntries
    287                                 );
    288   //
    289   // Remove legacy interrupts from the list of PCI interrupts available.
    290   //
    291   for (Index = 0; Index <= 0x0b; Index++) {
    292     for (Index1 = 0; Index1 <= NumberPriorityEntries; Index1++) {
    293       if (LegacyInterrupts[Index] != 0) {
    294         LegacyInt = (UINT16) (LegacyInt | (1 << LegacyInterrupts[Index]));
    295         if (LegacyInterrupts[Index] == IrqPriorityTable[Index1].Irq) {
    296           IrqPriorityTable[Index1].Used = LEGACY_USED;
    297         }
    298       }
    299     }
    300   }
    301 
    302   Private->Legacy8259->GetMask (
    303                         Private->Legacy8259,
    304                         &LegMask,
    305                         NULL,
    306                         NULL,
    307                         NULL
    308                         );
    309 
    310   //
    311   // Set SIO interrupts and disable mouse. Let mouse driver
    312   // re-enable it.
    313   //
    314   LegMask = (UINT16) ((LegMask &~LegacyInt) | 0x1000);
    315   Private->Legacy8259->SetMask (
    316                         Private->Legacy8259,
    317                         &LegMask,
    318                         NULL,
    319                         NULL,
    320                         NULL
    321                         );
    322 
    323   //
    324   // Disable mouse in keyboard controller
    325   //
    326   Register = 0xA7;
    327   Status = gBS->LocateHandleBuffer (
    328                   ByProtocol,
    329                   &gEfiIsaIoProtocolGuid,
    330                   NULL,
    331                   &HandleCount,
    332                   &HandleBuffer
    333                   );
    334   if (EFI_ERROR (Status)) {
    335     return Status;
    336   }
    337 
    338   for (Index = 0; Index < HandleCount; Index++) {
    339     Status = gBS->HandleProtocol (
    340                     HandleBuffer[Index],
    341                     &gEfiIsaIoProtocolGuid,
    342                     (VOID **) &IsaIo
    343                     );
    344     ASSERT_EFI_ERROR (Status);
    345     IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, 0x64, 1, &Register);
    346 
    347   }
    348 
    349   if (HandleBuffer != NULL) {
    350     FreePool (HandleBuffer);
    351   }
    352 
    353   return EFI_SUCCESS;
    354 
    355 }
    356 
    357 /**
    358   Identify drive data must be updated to actual parameters before boot.
    359   This requires updating the checksum, if it exists.
    360 
    361   @param  IdentifyDriveData       ATA Identify Data
    362   @param  Checksum                checksum of the ATA Identify Data
    363 
    364   @retval EFI_SUCCESS             checksum calculated
    365   @retval EFI_SECURITY_VIOLATION  IdentifyData invalid
    366 
    367 **/
    368 EFI_STATUS
    369 CalculateIdentifyDriveChecksum (
    370   IN  UINT8     *IdentifyDriveData,
    371   OUT UINT8     *Checksum
    372   )
    373 {
    374   UINTN Index;
    375   UINT8 LocalChecksum;
    376   LocalChecksum = 0;
    377   *Checksum     = 0;
    378   if (IdentifyDriveData[510] != 0xA5) {
    379     return EFI_SECURITY_VIOLATION;
    380   }
    381 
    382   for (Index = 0; Index < 512; Index++) {
    383     LocalChecksum = (UINT8) (LocalChecksum + IdentifyDriveData[Index]);
    384   }
    385 
    386   *Checksum = LocalChecksum;
    387   return EFI_SUCCESS;
    388 }
    389 
    390 
    391 /**
    392   Identify drive data must be updated to actual parameters before boot.
    393 
    394   @param  IdentifyDriveData       ATA Identify Data
    395 
    396 
    397 **/
    398 VOID
    399 UpdateIdentifyDriveData (
    400   IN  UINT8     *IdentifyDriveData
    401   )
    402 {
    403   UINT16          NumberCylinders;
    404   UINT16          NumberHeads;
    405   UINT16          NumberSectorsTrack;
    406   UINT32          CapacityInSectors;
    407   UINT8           OriginalChecksum;
    408   UINT8           FinalChecksum;
    409   EFI_STATUS      Status;
    410   ATAPI_IDENTIFY  *ReadInfo;
    411 
    412   //
    413   // Status indicates if Integrity byte is correct. Checksum should be
    414   // 0 if valid.
    415   //
    416   ReadInfo  = (ATAPI_IDENTIFY *) IdentifyDriveData;
    417   Status    = CalculateIdentifyDriveChecksum (IdentifyDriveData, &OriginalChecksum);
    418   if (OriginalChecksum != 0) {
    419     Status = EFI_SECURITY_VIOLATION;
    420   }
    421   //
    422   // If NumberCylinders = 0 then do data(Controller present but don drive attached).
    423   //
    424   NumberCylinders = ReadInfo->Raw[1];
    425   if (NumberCylinders != 0) {
    426     ReadInfo->Raw[54]   = NumberCylinders;
    427 
    428     NumberHeads         = ReadInfo->Raw[3];
    429     ReadInfo->Raw[55]   = NumberHeads;
    430 
    431     NumberSectorsTrack  = ReadInfo->Raw[6];
    432     ReadInfo->Raw[56]   = NumberSectorsTrack;
    433 
    434     //
    435     // Copy Multisector info and set valid bit.
    436     //
    437     ReadInfo->Raw[59] = (UINT16) (ReadInfo->Raw[47] + 0x100);
    438     CapacityInSectors = (UINT32) ((UINT32) (NumberCylinders) * (UINT32) (NumberHeads) * (UINT32) (NumberSectorsTrack));
    439     ReadInfo->Raw[57] = (UINT16) (CapacityInSectors >> 16);
    440     ReadInfo->Raw[58] = (UINT16) (CapacityInSectors & 0xffff);
    441     if (Status == EFI_SUCCESS) {
    442       //
    443       // Forece checksum byte to 0 and get new checksum.
    444       //
    445       ReadInfo->Raw[255] &= 0xff;
    446       CalculateIdentifyDriveChecksum (IdentifyDriveData, &FinalChecksum);
    447 
    448       //
    449       // Force new checksum such that sum is 0.
    450       //
    451       FinalChecksum = (UINT8) ((UINT8)0 - FinalChecksum);
    452       ReadInfo->Raw[255] = (UINT16) (ReadInfo->Raw[255] | (FinalChecksum << 8));
    453     }
    454   }
    455 }
    456 
    457 /**
    458   Identify drive data must be updated to actual parameters before boot.
    459   Do for all drives.
    460 
    461   @param  Private                 Legacy BIOS Instance data
    462 
    463 
    464 **/
    465 VOID
    466 UpdateAllIdentifyDriveData (
    467   IN LEGACY_BIOS_INSTANCE                 *Private
    468   )
    469 {
    470   UINTN     Index;
    471   HDD_INFO  *HddInfo;
    472 
    473   HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0];
    474 
    475   for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {
    476     //
    477     // Each controller can have 2 devices. Update for each device
    478     //
    479     if ((HddInfo[Index].Status & HDD_MASTER_IDE) != 0) {
    480       UpdateIdentifyDriveData ((UINT8 *) (&HddInfo[Index].IdentifyDrive[0].Raw[0]));
    481     }
    482 
    483     if ((HddInfo[Index].Status & HDD_SLAVE_IDE) != 0) {
    484       UpdateIdentifyDriveData ((UINT8 *) (&HddInfo[Index].IdentifyDrive[1].Raw[0]));
    485     }
    486   }
    487 }
    488 
    489 /**
    490   Enable ide controller.  This gets disabled when LegacyBoot.c is about
    491   to run the Option ROMs.
    492 
    493   @param  Private        Legacy BIOS Instance data
    494 
    495 
    496 **/
    497 VOID
    498 EnableIdeController (
    499   IN LEGACY_BIOS_INSTANCE              *Private
    500   )
    501 {
    502   EFI_PCI_IO_PROTOCOL *PciIo;
    503   EFI_STATUS          Status;
    504   EFI_HANDLE          IdeController;
    505   UINT8               ByteBuffer;
    506   UINTN               HandleCount;
    507   EFI_HANDLE          *HandleBuffer;
    508 
    509   Status = Private->LegacyBiosPlatform->GetPlatformHandle (
    510                                           Private->LegacyBiosPlatform,
    511                                           EfiGetPlatformIdeHandle,
    512                                           0,
    513                                           &HandleBuffer,
    514                                           &HandleCount,
    515                                           NULL
    516                                           );
    517   if (!EFI_ERROR (Status)) {
    518     IdeController = HandleBuffer[0];
    519     Status = gBS->HandleProtocol (
    520                     IdeController,
    521                     &gEfiPciIoProtocolGuid,
    522                     (VOID **) &PciIo
    523                     );
    524     ByteBuffer = 0x1f;
    525     if (!EFI_ERROR (Status)) {
    526       PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x04, 1, &ByteBuffer);
    527     }
    528   }
    529 }
    530 
    531 
    532 /**
    533   Enable ide controller.  This gets disabled when LegacyBoot.c is about
    534   to run the Option ROMs.
    535 
    536   @param  Private                 Legacy BIOS Instance data
    537 
    538 
    539 **/
    540 VOID
    541 EnableAllControllers (
    542   IN LEGACY_BIOS_INSTANCE              *Private
    543   )
    544 {
    545   UINTN               HandleCount;
    546   EFI_HANDLE          *HandleBuffer;
    547   UINTN               Index;
    548   EFI_PCI_IO_PROTOCOL *PciIo;
    549   PCI_TYPE01          PciConfigHeader;
    550   EFI_STATUS          Status;
    551 
    552   //
    553   //
    554   //
    555   EnableIdeController (Private);
    556 
    557   //
    558   // Assumption is table is built from low bus to high bus numbers.
    559   //
    560   Status = gBS->LocateHandleBuffer (
    561                   ByProtocol,
    562                   &gEfiPciIoProtocolGuid,
    563                   NULL,
    564                   &HandleCount,
    565                   &HandleBuffer
    566                   );
    567   ASSERT_EFI_ERROR (Status);
    568 
    569   for (Index = 0; Index < HandleCount; Index++) {
    570     Status = gBS->HandleProtocol (
    571                     HandleBuffer[Index],
    572                     &gEfiPciIoProtocolGuid,
    573                     (VOID **) &PciIo
    574                     );
    575     ASSERT_EFI_ERROR (Status);
    576 
    577     PciIo->Pci.Read (
    578                 PciIo,
    579                 EfiPciIoWidthUint32,
    580                 0,
    581                 sizeof (PciConfigHeader) / sizeof (UINT32),
    582                 &PciConfigHeader
    583                 );
    584 
    585     //
    586     // We do not enable PPB here. This is for HotPlug Consideration.
    587     // The Platform HotPlug Driver is responsible for Padding enough hot plug
    588     // resources. It is also responsible for enable this bridge. If it
    589     // does not pad it. It will cause some early Windows fail to installation.
    590     // If the platform driver does not pad resource for PPB, PPB should be in
    591     // un-enabled state to let Windows know that this PPB is not configured by
    592     // BIOS. So Windows will allocate default resource for PPB.
    593     //
    594     // The reason for why we enable the command register is:
    595     // The CSM will use the IO bar to detect some IRQ status, if the command
    596     // is disabled, the IO resource will be out of scope.
    597     // For example:
    598     // We installed a legacy IRQ handle for a PCI IDE controller. When IRQ
    599     // comes up, the handle will check the IO space to identify is the
    600     // controller generated the IRQ source.
    601     // If the IO command is not enabled, the IRQ handler will has wrong
    602     // information. It will cause IRQ storm when the correctly IRQ handler fails
    603     // to run.
    604     //
    605     if (!(IS_PCI_VGA (&PciConfigHeader)     ||
    606           IS_PCI_OLD_VGA (&PciConfigHeader) ||
    607           IS_PCI_IDE (&PciConfigHeader)     ||
    608           IS_PCI_P2P (&PciConfigHeader)     ||
    609           IS_PCI_P2P_SUB (&PciConfigHeader) ||
    610           IS_PCI_LPC (&PciConfigHeader)     )) {
    611 
    612       PciConfigHeader.Hdr.Command |= 0x1f;
    613 
    614       PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 4, 1, &PciConfigHeader.Hdr.Command);
    615     }
    616   }
    617 }
    618 
    619 /**
    620   The following routines are identical in operation, so combine
    621   for code compaction:
    622   EfiGetPlatformBinaryGetMpTable
    623   EfiGetPlatformBinaryGetOemIntData
    624   EfiGetPlatformBinaryGetOem32Data
    625   EfiGetPlatformBinaryGetOem16Data
    626 
    627   @param  This                    Protocol instance pointer.
    628   @param  Id                      Table/Data identifier
    629 
    630   @retval EFI_SUCCESS             Success
    631   @retval EFI_INVALID_PARAMETER   Invalid ID
    632   @retval EFI_OUT_OF_RESOURCES    no resource to get data or table
    633 
    634 **/
    635 EFI_STATUS
    636 LegacyGetDataOrTable (
    637   IN EFI_LEGACY_BIOS_PROTOCOL         *This,
    638   IN EFI_GET_PLATFORM_INFO_MODE       Id
    639   )
    640 {
    641   VOID                              *Table;
    642   UINT32                            TablePtr;
    643   UINTN                             TableSize;
    644   UINTN                             Alignment;
    645   UINTN                             Location;
    646   EFI_STATUS                        Status;
    647   EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
    648   EFI_COMPATIBILITY16_TABLE         *Legacy16Table;
    649   EFI_IA32_REGISTER_SET             Regs;
    650   LEGACY_BIOS_INSTANCE              *Private;
    651 
    652   Private             = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
    653 
    654   LegacyBiosPlatform  = Private->LegacyBiosPlatform;
    655   Legacy16Table       = Private->Legacy16Table;
    656 
    657   //
    658   // Phase 1 - get an address allocated in 16-bit code
    659   //
    660   while (TRUE) {
    661     switch (Id) {
    662     case EfiGetPlatformBinaryMpTable:
    663     case EfiGetPlatformBinaryOemIntData:
    664     case EfiGetPlatformBinaryOem32Data:
    665     case EfiGetPlatformBinaryOem16Data:
    666       {
    667         Status = LegacyBiosPlatform->GetPlatformInfo (
    668                                       LegacyBiosPlatform,
    669                                       Id,
    670                                       (VOID *) &Table,
    671                                       &TableSize,
    672                                       &Location,
    673                                       &Alignment,
    674                                       0,
    675                                       0
    676                                       );
    677         DEBUG ((EFI_D_INFO, "LegacyGetDataOrTable - ID: %x, %r\n", (UINTN)Id, Status));
    678         DEBUG ((EFI_D_INFO, "  Table - %x, Size - %x, Location - %x, Alignment - %x\n", (UINTN)Table, (UINTN)TableSize, (UINTN)Location, (UINTN)Alignment));
    679         break;
    680       }
    681 
    682     default:
    683       {
    684         return EFI_INVALID_PARAMETER;
    685       }
    686     }
    687 
    688     if (EFI_ERROR (Status)) {
    689       return Status;
    690     }
    691 
    692     ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
    693     Regs.X.AX = Legacy16GetTableAddress;
    694     Regs.X.CX = (UINT16) TableSize;
    695     Regs.X.BX = (UINT16) Location;
    696     Regs.X.DX = (UINT16) Alignment;
    697     Private->LegacyBios.FarCall86 (
    698       This,
    699       Private->Legacy16CallSegment,
    700       Private->Legacy16CallOffset,
    701       &Regs,
    702       NULL,
    703       0
    704       );
    705 
    706     if (Regs.X.AX != 0) {
    707       DEBUG ((EFI_D_ERROR, "Table ID %x length insufficient\n", Id));
    708       return EFI_OUT_OF_RESOURCES;
    709     } else {
    710       break;
    711     }
    712   }
    713   //
    714   // Phase 2 Call routine second time with address to allow address adjustment
    715   //
    716   Status = LegacyBiosPlatform->GetPlatformInfo (
    717                                 LegacyBiosPlatform,
    718                                 Id,
    719                                 (VOID *) &Table,
    720                                 &TableSize,
    721                                 &Location,
    722                                 &Alignment,
    723                                 Regs.X.DS,
    724                                 Regs.X.BX
    725                                 );
    726   switch (Id) {
    727   case EfiGetPlatformBinaryMpTable:
    728     {
    729       Legacy16Table->MpTablePtr     = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
    730       Legacy16Table->MpTableLength  = (UINT32)TableSize;
    731       DEBUG ((EFI_D_INFO, "MP table in legacy region - %x\n", (UINTN)Legacy16Table->MpTablePtr));
    732       break;
    733     }
    734 
    735   case EfiGetPlatformBinaryOemIntData:
    736     {
    737 
    738       Legacy16Table->OemIntSegment  = Regs.X.DS;
    739       Legacy16Table->OemIntOffset   = Regs.X.BX;
    740       DEBUG ((EFI_D_INFO, "OemInt table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->OemIntSegment, (UINTN)Legacy16Table->OemIntOffset));
    741       break;
    742     }
    743 
    744   case EfiGetPlatformBinaryOem32Data:
    745     {
    746       Legacy16Table->Oem32Segment = Regs.X.DS;
    747       Legacy16Table->Oem32Offset  = Regs.X.BX;
    748       DEBUG ((EFI_D_INFO, "Oem32 table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->Oem32Segment, (UINTN)Legacy16Table->Oem32Offset));
    749       break;
    750     }
    751 
    752   case EfiGetPlatformBinaryOem16Data:
    753     {
    754       //
    755       //          Legacy16Table->Oem16Segment = Regs.X.DS;
    756       //          Legacy16Table->Oem16Offset  = Regs.X.BX;
    757       DEBUG ((EFI_D_INFO, "Oem16 table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->Oem16Segment, (UINTN)Legacy16Table->Oem16Offset));
    758       break;
    759     }
    760 
    761   default:
    762     {
    763       return EFI_INVALID_PARAMETER;
    764     }
    765   }
    766 
    767   if (EFI_ERROR (Status)) {
    768     return Status;
    769   }
    770   //
    771   // Phase 3 Copy table to final location
    772   //
    773   TablePtr = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
    774 
    775   CopyMem (
    776     (VOID *) (UINTN)TablePtr,
    777     Table,
    778     TableSize
    779     );
    780 
    781   return EFI_SUCCESS;
    782 }
    783 
    784 /**
    785   Copy SMBIOS table to EfiReservedMemoryType of memory for legacy boot.
    786 
    787 **/
    788 VOID
    789 CreateSmbiosTableInReservedMemory (
    790   VOID
    791   )
    792 {
    793   SMBIOS_TABLE_ENTRY_POINT    *EntryPointStructure;
    794 
    795   if ((mRuntimeSmbiosEntryPoint == NULL) ||
    796       (mReserveSmbiosEntryPoint == 0) ||
    797       (mStructureTableAddress == 0)) {
    798     return;
    799   }
    800 
    801   EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *) mRuntimeSmbiosEntryPoint;
    802 
    803   //
    804   // Copy SMBIOS Entry Point Structure
    805   //
    806   CopyMem (
    807     (VOID *)(UINTN) mReserveSmbiosEntryPoint,
    808     EntryPointStructure,
    809     EntryPointStructure->EntryPointLength
    810   );
    811 
    812   //
    813   // Copy SMBIOS Structure Table into EfiReservedMemoryType memory
    814   //
    815   CopyMem (
    816     (VOID *)(UINTN) mStructureTableAddress,
    817     (VOID *)(UINTN) EntryPointStructure->TableAddress,
    818     EntryPointStructure->TableLength
    819   );
    820 
    821   //
    822   // Update TableAddress in Entry Point Structure
    823   //
    824   EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *)(UINTN) mReserveSmbiosEntryPoint;
    825   EntryPointStructure->TableAddress = (UINT32)(UINTN) mStructureTableAddress;
    826 
    827   //
    828   // Fixup checksums in the Entry Point Structure
    829   //
    830   EntryPointStructure->IntermediateChecksum = 0;
    831   EntryPointStructure->EntryPointStructureChecksum = 0;
    832 
    833   EntryPointStructure->IntermediateChecksum =
    834     CalculateCheckSum8 (
    835       (UINT8 *) EntryPointStructure + OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT, IntermediateAnchorString),
    836       EntryPointStructure->EntryPointLength - OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT, IntermediateAnchorString)
    837       );
    838   EntryPointStructure->EntryPointStructureChecksum =
    839     CalculateCheckSum8 ((UINT8 *) EntryPointStructure, EntryPointStructure->EntryPointLength);
    840 }
    841 
    842 /**
    843   Assign drive number to legacy HDD drives prior to booting an EFI
    844   aware OS so the OS can access drives without an EFI driver.
    845   Note: BBS compliant drives ARE NOT available until this call by
    846   either shell or EFI.
    847 
    848   @param  This                    Protocol instance pointer.
    849 
    850   @retval EFI_SUCCESS             Drive numbers assigned
    851 
    852 **/
    853 EFI_STATUS
    854 GenericLegacyBoot (
    855   IN EFI_LEGACY_BIOS_PROTOCOL           *This
    856   )
    857 {
    858   EFI_STATUS                        Status;
    859   LEGACY_BIOS_INSTANCE              *Private;
    860   EFI_IA32_REGISTER_SET             Regs;
    861   EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
    862   EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
    863   UINTN                             CopySize;
    864   VOID                              *AcpiPtr;
    865   HDD_INFO                          *HddInfo;
    866   HDD_INFO                          *LocalHddInfo;
    867   UINTN                             Index;
    868   EFI_COMPATIBILITY16_TABLE         *Legacy16Table;
    869   UINT32                            *BdaPtr;
    870   UINT16                            HddCount;
    871   UINT16                            BbsCount;
    872   BBS_TABLE                         *LocalBbsTable;
    873   UINT32                            *BaseVectorMaster;
    874   EFI_TIME                          BootTime;
    875   UINT32                            LocalTime;
    876   EFI_HANDLE                        IdeController;
    877   UINTN                             HandleCount;
    878   EFI_HANDLE                        *HandleBuffer;
    879   VOID                              *AcpiTable;
    880   UINTN                             ShadowAddress;
    881   UINT32                            Granularity;
    882 
    883   LocalHddInfo  = NULL;
    884   HddCount      = 0;
    885   BbsCount      = 0;
    886   LocalBbsTable = NULL;
    887 
    888   Private       = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
    889   DEBUG_CODE (
    890     DEBUG ((EFI_D_ERROR, "Start of legacy boot\n"));
    891   );
    892 
    893   Legacy16Table                         = Private->Legacy16Table;
    894   EfiToLegacy16BootTable                = &Private->IntThunk->EfiToLegacy16BootTable;
    895   HddInfo = &EfiToLegacy16BootTable->HddInfo[0];
    896 
    897   LegacyBiosPlatform = Private->LegacyBiosPlatform;
    898 
    899   EfiToLegacy16BootTable->MajorVersion = EFI_TO_LEGACY_MAJOR_VERSION;
    900   EfiToLegacy16BootTable->MinorVersion = EFI_TO_LEGACY_MINOR_VERSION;
    901 
    902   //
    903   // If booting to a legacy OS then force HDD drives to the appropriate
    904   // boot mode by calling GetIdeHandle.
    905   // A reconnect -r can force all HDDs back to native mode.
    906   //
    907   IdeController = NULL;
    908   if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
    909     Status = LegacyBiosPlatform->GetPlatformHandle (
    910                                   Private->LegacyBiosPlatform,
    911                                   EfiGetPlatformIdeHandle,
    912                                   0,
    913                                   &HandleBuffer,
    914                                   &HandleCount,
    915                                   NULL
    916                                   );
    917     if (!EFI_ERROR (Status)) {
    918       IdeController = HandleBuffer[0];
    919     }
    920   }
    921   //
    922   // Unlock the Legacy BIOS region
    923   //
    924   Private->LegacyRegion->UnLock (
    925                            Private->LegacyRegion,
    926                            0xE0000,
    927                            0x20000,
    928                            &Granularity
    929                            );
    930 
    931   //
    932   // Reconstruct the Legacy16 boot memory map
    933   //
    934   LegacyBiosBuildE820 (Private, &CopySize);
    935   if (CopySize > Private->Legacy16Table->E820Length) {
    936     ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
    937     Regs.X.AX = Legacy16GetTableAddress;
    938     Regs.X.CX = (UINT16) CopySize;
    939     Private->LegacyBios.FarCall86 (
    940       &Private->LegacyBios,
    941       Private->Legacy16Table->Compatibility16CallSegment,
    942       Private->Legacy16Table->Compatibility16CallOffset,
    943       &Regs,
    944       NULL,
    945       0
    946       );
    947 
    948     Private->Legacy16Table->E820Pointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
    949     Private->Legacy16Table->E820Length  = (UINT32) CopySize;
    950     if (Regs.X.AX != 0) {
    951       DEBUG ((EFI_D_ERROR, "Legacy16 E820 length insufficient\n"));
    952     } else {
    953       CopyMem (
    954         (VOID *)(UINTN) Private->Legacy16Table->E820Pointer,
    955         Private->E820Table,
    956         CopySize
    957         );
    958     }
    959   } else {
    960     CopyMem (
    961       (VOID *)(UINTN) Private->Legacy16Table->E820Pointer,
    962       Private->E820Table,
    963       CopySize
    964       );
    965     Private->Legacy16Table->E820Length = (UINT32) CopySize;
    966   }
    967 
    968   //
    969   // We do not ASSERT if SmbiosTable not found. It is possbile that a platform does not produce SmbiosTable.
    970   //
    971   if (mReserveSmbiosEntryPoint == 0) {
    972     DEBUG ((EFI_D_INFO, "Smbios table is not found!\n"));
    973   }
    974   CreateSmbiosTableInReservedMemory ();
    975   EfiToLegacy16BootTable->SmbiosTable = (UINT32)(UINTN)mReserveSmbiosEntryPoint;
    976 
    977   AcpiTable = NULL;
    978   Status = EfiGetSystemConfigurationTable (
    979              &gEfiAcpi20TableGuid,
    980              &AcpiTable
    981              );
    982   if (EFI_ERROR (Status)) {
    983     Status = EfiGetSystemConfigurationTable (
    984                &gEfiAcpi10TableGuid,
    985                &AcpiTable
    986                );
    987   }
    988   //
    989   // We do not ASSERT if AcpiTable not found. It is possbile that a platform does not produce AcpiTable.
    990   //
    991   if (AcpiTable == NULL) {
    992     DEBUG ((EFI_D_INFO, "ACPI table is not found!\n"));
    993   }
    994   EfiToLegacy16BootTable->AcpiTable = (UINT32)(UINTN)AcpiTable;
    995 
    996   //
    997   // Get RSD Ptr table rev at offset 15 decimal
    998   // Rev = 0 Length is 20 decimal
    999   // Rev != 0 Length is UINT32 at offset 20 decimal
   1000   //
   1001   if (AcpiTable != NULL) {
   1002 
   1003     AcpiPtr = AcpiTable;
   1004     if (*((UINT8 *) AcpiPtr + 15) == 0) {
   1005       CopySize = 20;
   1006     } else {
   1007       AcpiPtr   = ((UINT8 *) AcpiPtr + 20);
   1008       CopySize  = (*(UINT32 *) AcpiPtr);
   1009     }
   1010 
   1011     CopyMem (
   1012       (VOID *)(UINTN) Private->Legacy16Table->AcpiRsdPtrPointer,
   1013       AcpiTable,
   1014       CopySize
   1015       );
   1016   }
   1017   //
   1018   // Make sure all PCI Interrupt Line register are programmed to match 8259
   1019   //
   1020   PciProgramAllInterruptLineRegisters (Private);
   1021 
   1022   //
   1023   // Unlock the Legacy BIOS region as PciProgramAllInterruptLineRegisters
   1024   // can lock it.
   1025   //
   1026   Private->LegacyRegion->UnLock (
   1027                            Private->LegacyRegion,
   1028                            Private->BiosStart,
   1029                            Private->LegacyBiosImageSize,
   1030                            &Granularity
   1031                            );
   1032 
   1033   //
   1034   // Configure Legacy Device Magic
   1035   //
   1036   // Only do this code if booting legacy OS
   1037   //
   1038   if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
   1039     UpdateSioData (Private);
   1040   }
   1041   //
   1042   // Setup BDA and EBDA standard areas before Legacy Boot
   1043   //
   1044   LegacyBiosCompleteBdaBeforeBoot (Private);
   1045   LegacyBiosCompleteStandardCmosBeforeBoot (Private);
   1046 
   1047   //
   1048   // We must build IDE data, if it hasn't been done, before PciShadowRoms
   1049   // to insure EFI drivers are connected.
   1050   //
   1051   LegacyBiosBuildIdeData (Private, &HddInfo, 1);
   1052   UpdateAllIdentifyDriveData (Private);
   1053 
   1054   //
   1055   // Clear IO BAR, if IDE controller in legacy mode.
   1056   //
   1057   InitLegacyIdeController (IdeController);
   1058 
   1059   //
   1060   // Generate number of ticks since midnight for BDA. DOS requires this
   1061   // for its time. We have to make assumptions as to how long following
   1062   // code takes since after PciShadowRoms PciIo is gone. Place result in
   1063   // 40:6C-6F
   1064   //
   1065   // Adjust value by 1 second.
   1066   //
   1067   gRT->GetTime (&BootTime, NULL);
   1068   LocalTime = BootTime.Hour * 3600 + BootTime.Minute * 60 + BootTime.Second;
   1069   LocalTime += 1;
   1070 
   1071   //
   1072   // Multiply result by 18.2 for number of ticks since midnight.
   1073   // Use 182/10 to avoid floating point math.
   1074   //
   1075   LocalTime = (LocalTime * 182) / 10;
   1076   BdaPtr    = (UINT32 *) (UINTN)0x46C;
   1077   *BdaPtr   = LocalTime;
   1078 
   1079   //
   1080   // Shadow PCI ROMs. We must do this near the end since this will kick
   1081   // of Native EFI drivers that may be needed to collect info for Legacy16
   1082   //
   1083   //  WARNING: PciIo is gone after this call.
   1084   //
   1085   PciShadowRoms (Private);
   1086 
   1087   //
   1088   // Shadow PXE base code, BIS etc.
   1089   //
   1090   Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xc0000, 0x40000, &Granularity);
   1091   ShadowAddress = Private->OptionRom;
   1092   Private->LegacyBiosPlatform->PlatformHooks (
   1093                                  Private->LegacyBiosPlatform,
   1094                                  EfiPlatformHookShadowServiceRoms,
   1095                                  0,
   1096                                  0,
   1097                                  &ShadowAddress,
   1098                                  Legacy16Table,
   1099                                  NULL
   1100                                  );
   1101   Private->OptionRom = (UINT32)ShadowAddress;
   1102   //
   1103   // Register Legacy SMI Handler
   1104   //
   1105   LegacyBiosPlatform->SmmInit (
   1106                         LegacyBiosPlatform,
   1107                         EfiToLegacy16BootTable
   1108                         );
   1109 
   1110   //
   1111   // Let platform code know the boot options
   1112   //
   1113   LegacyBiosGetBbsInfo (
   1114     This,
   1115     &HddCount,
   1116     &LocalHddInfo,
   1117     &BbsCount,
   1118     &LocalBbsTable
   1119     );
   1120 
   1121   DEBUG_CODE (
   1122     PrintPciInterruptRegister ();
   1123     PrintBbsTable (LocalBbsTable);
   1124     PrintHddInfo (LocalHddInfo);
   1125     );
   1126   //
   1127   // If drive wasn't spun up then BuildIdeData may have found new drives.
   1128   // Need to update BBS boot priority.
   1129   //
   1130   for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {
   1131     if ((LocalHddInfo[Index].IdentifyDrive[0].Raw[0] != 0) &&
   1132         (LocalBbsTable[2 * Index + 1].BootPriority == BBS_IGNORE_ENTRY)
   1133         ) {
   1134       LocalBbsTable[2 * Index + 1].BootPriority = BBS_UNPRIORITIZED_ENTRY;
   1135     }
   1136 
   1137     if ((LocalHddInfo[Index].IdentifyDrive[1].Raw[0] != 0) &&
   1138         (LocalBbsTable[2 * Index + 2].BootPriority == BBS_IGNORE_ENTRY)
   1139         ) {
   1140       LocalBbsTable[2 * Index + 2].BootPriority = BBS_UNPRIORITIZED_ENTRY;
   1141     }
   1142   }
   1143 
   1144   Private->LegacyRegion->UnLock (
   1145                            Private->LegacyRegion,
   1146                            0xc0000,
   1147                            0x40000,
   1148                            &Granularity
   1149                            );
   1150 
   1151   LegacyBiosPlatform->PrepareToBoot (
   1152                         LegacyBiosPlatform,
   1153                         mBbsDevicePathPtr,
   1154                         mBbsTable,
   1155                         mLoadOptionsSize,
   1156                         mLoadOptions,
   1157                         (VOID *) &Private->IntThunk->EfiToLegacy16BootTable
   1158                         );
   1159 
   1160   //
   1161   // If no boot device return to BDS
   1162   //
   1163   if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
   1164     for (Index = 0; Index < BbsCount; Index++){
   1165       if ((LocalBbsTable[Index].BootPriority != BBS_DO_NOT_BOOT_FROM) &&
   1166           (LocalBbsTable[Index].BootPriority != BBS_UNPRIORITIZED_ENTRY) &&
   1167           (LocalBbsTable[Index].BootPriority != BBS_IGNORE_ENTRY)) {
   1168         break;
   1169       }
   1170     }
   1171     if (Index == BbsCount) {
   1172       return EFI_DEVICE_ERROR;
   1173     }
   1174   }
   1175   //
   1176   // Let the Legacy16 code know the device path type for legacy boot
   1177   //
   1178   EfiToLegacy16BootTable->DevicePathType = mBbsDevicePathPtr->DeviceType;
   1179 
   1180   //
   1181   // Copy MP table, if it exists.
   1182   //
   1183   LegacyGetDataOrTable (This, EfiGetPlatformBinaryMpTable);
   1184 
   1185   if (!Private->LegacyBootEntered) {
   1186     //
   1187     // Copy OEM INT Data, if it exists. Note: This code treats any data
   1188     // as a bag of bits and knows nothing of the contents nor cares.
   1189     // Contents are IBV specific.
   1190     //
   1191     LegacyGetDataOrTable (This, EfiGetPlatformBinaryOemIntData);
   1192 
   1193     //
   1194     // Copy OEM16 Data, if it exists.Note: This code treats any data
   1195     // as a bag of bits and knows nothing of the contents nor cares.
   1196     // Contents are IBV specific.
   1197     //
   1198     LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem16Data);
   1199 
   1200     //
   1201     // Copy OEM32 Data, if it exists.Note: This code treats any data
   1202     // as a bag of bits and knows nothing of the contents nor cares.
   1203     // Contents are IBV specific.
   1204     //
   1205     LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem32Data);
   1206   }
   1207 
   1208   //
   1209   // Call into Legacy16 code to prepare for INT 19h
   1210   //
   1211   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
   1212   Regs.X.AX = Legacy16PrepareToBoot;
   1213 
   1214   //
   1215   // Pass in handoff data
   1216   //
   1217   Regs.X.ES = NORMALIZE_EFI_SEGMENT ((UINTN)EfiToLegacy16BootTable);
   1218   Regs.X.BX = NORMALIZE_EFI_OFFSET ((UINTN)EfiToLegacy16BootTable);
   1219 
   1220   Private->LegacyBios.FarCall86 (
   1221     This,
   1222     Private->Legacy16CallSegment,
   1223     Private->Legacy16CallOffset,
   1224     &Regs,
   1225     NULL,
   1226     0
   1227     );
   1228 
   1229   if (Regs.X.AX != 0) {
   1230     return EFI_DEVICE_ERROR;
   1231   }
   1232   //
   1233   // Lock the Legacy BIOS region
   1234   //
   1235   Private->LegacyRegion->Lock (
   1236                            Private->LegacyRegion,
   1237                            0xc0000,
   1238                            0x40000,
   1239                            &Granularity
   1240                            );
   1241 
   1242   if ((Private->Legacy16Table->TableLength >= OFFSET_OF (EFI_COMPATIBILITY16_TABLE, HiPermanentMemoryAddress)) &&
   1243       ((Private->Legacy16Table->UmaAddress != 0) && (Private->Legacy16Table->UmaSize != 0))) {
   1244     //
   1245     // Here we could reduce UmaAddress down as far as Private->OptionRom, taking into
   1246     // account the granularity of the access control.
   1247     //
   1248     DEBUG((EFI_D_INFO, "Unlocking UMB RAM region 0x%x-0x%x\n", Private->Legacy16Table->UmaAddress,
   1249                         Private->Legacy16Table->UmaAddress + Private->Legacy16Table->UmaSize));
   1250 
   1251     Private->LegacyRegion->UnLock (
   1252                              Private->LegacyRegion,
   1253                              Private->Legacy16Table->UmaAddress,
   1254                              Private->Legacy16Table->UmaSize,
   1255                              &Granularity
   1256                              );
   1257   }
   1258 
   1259   //
   1260   // Lock attributes of the Legacy Region if chipset supports
   1261   //
   1262   Private->LegacyRegion->BootLock (
   1263                            Private->LegacyRegion,
   1264                            0xc0000,
   1265                            0x40000,
   1266                            &Granularity
   1267                            );
   1268 
   1269   //
   1270   // Call into Legacy16 code to do the INT 19h
   1271   //
   1272   EnableAllControllers (Private);
   1273   if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
   1274 
   1275     //
   1276     // Signal all the events that are waiting on EVT_SIGNAL_LEGACY_BOOT
   1277     //
   1278     EfiSignalEventLegacyBoot ();
   1279 
   1280     //
   1281     // Report Status Code to indicate legacy boot event was signalled
   1282     //
   1283     REPORT_STATUS_CODE (
   1284       EFI_PROGRESS_CODE,
   1285       (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_LEGACY_BOOT_EVENT)
   1286       );
   1287 
   1288     DEBUG ((EFI_D_INFO, "Legacy INT19 Boot...\n"));
   1289 
   1290     //
   1291     // Disable DXE Timer while executing in real mode
   1292     //
   1293     Private->Timer->SetTimerPeriod (Private->Timer, 0);
   1294 
   1295     //
   1296     // Save and disable interrupt of debug timer
   1297     //
   1298     SaveAndSetDebugTimerInterrupt (FALSE);
   1299 
   1300 
   1301     //
   1302     // Put the 8259 into its legacy mode by reprogramming the vector bases
   1303     //
   1304     Private->Legacy8259->SetVectorBase (Private->Legacy8259, LEGACY_MODE_BASE_VECTOR_MASTER, LEGACY_MODE_BASE_VECTOR_SLAVE);
   1305     //
   1306     // PC History
   1307     //   The original PC used INT8-F for master PIC. Since these mapped over
   1308     //   processor exceptions TIANO moved the master PIC to INT68-6F.
   1309     // We need to set these back to the Legacy16 unexpected interrupt(saved
   1310     // in LegacyBios.c) since some OS see that these have values different from
   1311     // what is expected and invoke them. Since the legacy OS corrupts EFI
   1312     // memory, there is no handler for these interrupts and OS blows up.
   1313     //
   1314     // We need to save the TIANO values for the rare case that the Legacy16
   1315     // code cannot boot but knows memory hasn't been destroyed.
   1316     //
   1317     // To compound the problem, video takes over one of these INTS and must be
   1318     // be left.
   1319     // @bug - determine if video hooks INT(in which case we must find new
   1320     //          set of TIANO vectors) or takes it over.
   1321     //
   1322     //
   1323     BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
   1324     for (Index = 0; Index < 8; Index++) {
   1325       Private->ThunkSavedInt[Index] = BaseVectorMaster[Index];
   1326       if (Private->ThunkSeg == (UINT16) (BaseVectorMaster[Index] >> 16)) {
   1327         BaseVectorMaster[Index] = (UINT32) (Private->BiosUnexpectedInt);
   1328       }
   1329     }
   1330 
   1331     ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
   1332     Regs.X.AX = Legacy16Boot;
   1333 
   1334     Private->LegacyBios.FarCall86 (
   1335       This,
   1336       Private->Legacy16CallSegment,
   1337       Private->Legacy16CallOffset,
   1338       &Regs,
   1339       NULL,
   1340       0
   1341       );
   1342 
   1343     BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
   1344     for (Index = 0; Index < 8; Index++) {
   1345       BaseVectorMaster[Index] = Private->ThunkSavedInt[Index];
   1346     }
   1347   }
   1348   Private->LegacyBootEntered = TRUE;
   1349   if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
   1350     //
   1351     // Should never return unless never passed control to 0:7c00(first stage
   1352     // OS loader) and only then if no bootable device found.
   1353     //
   1354     return EFI_DEVICE_ERROR;
   1355   } else {
   1356     //
   1357     // If boot to EFI then expect to return to caller
   1358     //
   1359     return EFI_SUCCESS;
   1360   }
   1361 }
   1362 
   1363 
   1364 /**
   1365   Assign drive number to legacy HDD drives prior to booting an EFI
   1366   aware OS so the OS can access drives without an EFI driver.
   1367   Note: BBS compliant drives ARE NOT available until this call by
   1368   either shell or EFI.
   1369 
   1370   @param  This                    Protocol instance pointer.
   1371   @param  BbsCount                Number of BBS_TABLE structures
   1372   @param  BbsTable                List BBS entries
   1373 
   1374   @retval EFI_SUCCESS             Drive numbers assigned
   1375 
   1376 **/
   1377 EFI_STATUS
   1378 EFIAPI
   1379 LegacyBiosPrepareToBootEfi (
   1380   IN EFI_LEGACY_BIOS_PROTOCOL         *This,
   1381   OUT UINT16                          *BbsCount,
   1382   OUT BBS_TABLE                       **BbsTable
   1383   )
   1384 {
   1385   EFI_STATUS                        Status;
   1386   EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
   1387   LEGACY_BIOS_INSTANCE              *Private;
   1388 
   1389   Private                 = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
   1390   EfiToLegacy16BootTable  = &Private->IntThunk->EfiToLegacy16BootTable;
   1391   mBootMode               = BOOT_EFI_OS;
   1392   mBbsDevicePathPtr       = NULL;
   1393   Status                  = GenericLegacyBoot (This);
   1394   *BbsTable               = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;
   1395   *BbsCount               = (UINT16) (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE));
   1396   return Status;
   1397 }
   1398 
   1399 /**
   1400   To boot from an unconventional device like parties and/or execute HDD diagnostics.
   1401 
   1402   @param  This            Protocol instance pointer.
   1403   @param  Attributes      How to interpret the other input parameters
   1404   @param  BbsEntry        The 0-based index into the BbsTable for the parent
   1405                           device.
   1406   @param  BeerData        Pointer to the 128 bytes of ram BEER data.
   1407   @param  ServiceAreaData Pointer to the 64 bytes of raw Service Area data. The
   1408                           caller must provide a pointer to the specific Service
   1409                           Area and not the start all Service Areas.
   1410 
   1411   @retval EFI_INVALID_PARAMETER if error. Does NOT return if no error.
   1412 
   1413 ***/
   1414 EFI_STATUS
   1415 EFIAPI
   1416 LegacyBiosBootUnconventionalDevice (
   1417   IN EFI_LEGACY_BIOS_PROTOCOL         *This,
   1418   IN UDC_ATTRIBUTES                   Attributes,
   1419   IN UINTN                            BbsEntry,
   1420   IN VOID                             *BeerData,
   1421   IN VOID                             *ServiceAreaData
   1422   )
   1423 {
   1424   EFI_STATUS                        Status;
   1425   EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
   1426   LEGACY_BIOS_INSTANCE              *Private;
   1427   UD_TABLE                          *UcdTable;
   1428   UINTN                             Index;
   1429   UINT16                            BootPriority;
   1430   BBS_TABLE                         *BbsTable;
   1431 
   1432   BootPriority = 0;
   1433   Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
   1434   mBootMode = BOOT_UNCONVENTIONAL_DEVICE;
   1435   mBbsDevicePathPtr = &mBbsDevicePathNode;
   1436   mAttributes = Attributes;
   1437   mBbsEntry = BbsEntry;
   1438   mBeerData = BeerData, mServiceAreaData = ServiceAreaData;
   1439 
   1440   EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
   1441 
   1442   //
   1443   // Do input parameter checking
   1444   //
   1445   if ((Attributes.DirectoryServiceValidity == 0) &&
   1446       (Attributes.RabcaUsedFlag == 0) &&
   1447       (Attributes.ExecuteHddDiagnosticsFlag == 0)
   1448       ) {
   1449     return EFI_INVALID_PARAMETER;
   1450   }
   1451 
   1452   if (((Attributes.DirectoryServiceValidity != 0) && (ServiceAreaData == NULL)) ||
   1453       (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag) != 0) && (BeerData == NULL))
   1454       ) {
   1455     return EFI_INVALID_PARAMETER;
   1456   }
   1457 
   1458   UcdTable = (UD_TABLE *) AllocatePool (
   1459 														sizeof (UD_TABLE)
   1460 														);
   1461   if (NULL == UcdTable) {
   1462     return EFI_OUT_OF_RESOURCES;
   1463   }
   1464 
   1465   EfiToLegacy16BootTable->UnconventionalDeviceTable = (UINT32)(UINTN)UcdTable;
   1466   UcdTable->Attributes = Attributes;
   1467   UcdTable->BbsTableEntryNumberForParentDevice = (UINT8) BbsEntry;
   1468   //
   1469   // Force all existing BBS entries to DoNotBoot. This allows 16-bit CSM
   1470   // to assign drive numbers but bot boot from. Only newly created entries
   1471   // will be valid.
   1472   //
   1473   BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;
   1474   for (Index = 0; Index < EfiToLegacy16BootTable->NumberBbsEntries; Index++) {
   1475     BbsTable[Index].BootPriority = BBS_DO_NOT_BOOT_FROM;
   1476   }
   1477   //
   1478   // If parent is onboard IDE then assign controller & device number
   1479   // else they are 0.
   1480   //
   1481   if (BbsEntry < MAX_IDE_CONTROLLER * 2) {
   1482     UcdTable->DeviceNumber = (UINT8) ((BbsEntry - 1) % 2);
   1483   }
   1484 
   1485   if (BeerData != NULL) {
   1486     CopyMem (
   1487       (VOID *) UcdTable->BeerData,
   1488       BeerData,
   1489       (UINTN) 128
   1490       );
   1491   }
   1492 
   1493   if (ServiceAreaData != NULL) {
   1494     CopyMem (
   1495       (VOID *) UcdTable->ServiceAreaData,
   1496       ServiceAreaData,
   1497       (UINTN) 64
   1498       );
   1499   }
   1500   //
   1501   // For each new entry do the following:
   1502   //   1. Increment current number of BBS entries
   1503   //   2. Copy parent entry to new entry.
   1504   //   3. Zero out BootHandler Offset & segment
   1505   //   4. Set appropriate device type. BEV(0x80) for HDD diagnostics
   1506   //      and Floppy(0x01) for PARTIES boot.
   1507   //   5. Assign new priority.
   1508   //
   1509   if ((Attributes.ExecuteHddDiagnosticsFlag) != 0) {
   1510     EfiToLegacy16BootTable->NumberBbsEntries += 1;
   1511 
   1512     CopyMem (
   1513       (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority,
   1514       (VOID *) &BbsTable[BbsEntry].BootPriority,
   1515       sizeof (BBS_TABLE)
   1516       );
   1517 
   1518     BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset  = 0;
   1519     BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0;
   1520     BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType         = 0x80;
   1521 
   1522     UcdTable->BbsTableEntryNumberForHddDiag = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1);
   1523 
   1524     BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority;
   1525     BootPriority += 1;
   1526 
   1527     //
   1528     // Set device type as BBS_TYPE_DEV for PARTIES diagnostic
   1529     //
   1530     mBbsDevicePathNode.DeviceType = BBS_TYPE_BEV;
   1531   }
   1532 
   1533   if (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag)) != 0) {
   1534     EfiToLegacy16BootTable->NumberBbsEntries += 1;
   1535     CopyMem (
   1536       (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority,
   1537       (VOID *) &BbsTable[BbsEntry].BootPriority,
   1538       sizeof (BBS_TABLE)
   1539       );
   1540 
   1541     BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset  = 0;
   1542     BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0;
   1543     BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType         = 0x01;
   1544     UcdTable->BbsTableEntryNumberForBoot = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1);
   1545     BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority;
   1546 
   1547     //
   1548     // Set device type as BBS_TYPE_FLOPPY for PARTIES boot as floppy
   1549     //
   1550     mBbsDevicePathNode.DeviceType = BBS_TYPE_FLOPPY;
   1551   }
   1552   //
   1553   // Build the BBS Device Path for this boot selection
   1554   //
   1555   mBbsDevicePathNode.Header.Type    = BBS_DEVICE_PATH;
   1556   mBbsDevicePathNode.Header.SubType = BBS_BBS_DP;
   1557   SetDevicePathNodeLength (&mBbsDevicePathNode.Header, sizeof (BBS_BBS_DEVICE_PATH));
   1558   mBbsDevicePathNode.StatusFlag = 0;
   1559   mBbsDevicePathNode.String[0]  = 0;
   1560 
   1561   Status                        = GenericLegacyBoot (This);
   1562   return Status;
   1563 }
   1564 
   1565 /**
   1566   Attempt to legacy boot the BootOption. If the EFI contexted has been
   1567   compromised this function will not return.
   1568 
   1569   @param  This             Protocol instance pointer.
   1570   @param  BbsDevicePath    EFI Device Path from BootXXXX variable.
   1571   @param  LoadOptionsSize  Size of LoadOption in size.
   1572   @param  LoadOptions      LoadOption from BootXXXX variable
   1573 
   1574   @retval EFI_SUCCESS      Removable media not present
   1575 
   1576 **/
   1577 EFI_STATUS
   1578 EFIAPI
   1579 LegacyBiosLegacyBoot (
   1580   IN EFI_LEGACY_BIOS_PROTOCOL           *This,
   1581   IN  BBS_BBS_DEVICE_PATH               *BbsDevicePath,
   1582   IN  UINT32                            LoadOptionsSize,
   1583   IN  VOID                              *LoadOptions
   1584   )
   1585 {
   1586   EFI_STATUS  Status;
   1587 
   1588   mBbsDevicePathPtr = BbsDevicePath;
   1589   mLoadOptionsSize  = LoadOptionsSize;
   1590   mLoadOptions      = LoadOptions;
   1591   mBootMode         = BOOT_LEGACY_OS;
   1592   Status            = GenericLegacyBoot (This);
   1593 
   1594   return Status;
   1595 }
   1596 
   1597 /**
   1598   Convert EFI Memory Type to E820 Memory Type.
   1599 
   1600   @param  Type  EFI Memory Type
   1601 
   1602   @return ACPI Memory Type for EFI Memory Type
   1603 
   1604 **/
   1605 EFI_ACPI_MEMORY_TYPE
   1606 EfiMemoryTypeToE820Type (
   1607   IN  UINT32    Type
   1608   )
   1609 {
   1610   switch (Type) {
   1611   case EfiLoaderCode:
   1612   case EfiLoaderData:
   1613   case EfiBootServicesCode:
   1614   case EfiBootServicesData:
   1615   case EfiConventionalMemory:
   1616   //
   1617   // The memory of EfiRuntimeServicesCode and EfiRuntimeServicesData are
   1618   // usable memory for legacy OS, because legacy OS is not aware of EFI runtime concept.
   1619   // In ACPI specification, EfiRuntimeServiceCode and EfiRuntimeServiceData
   1620   // should be mapped to AddressRangeReserved. This statement is for UEFI OS, not for legacy OS.
   1621   //
   1622   case EfiRuntimeServicesCode:
   1623   case EfiRuntimeServicesData:
   1624     return EfiAcpiAddressRangeMemory;
   1625 
   1626   case EfiPersistentMemory:
   1627     return EfiAddressRangePersistentMemory;
   1628 
   1629   case EfiACPIReclaimMemory:
   1630     return EfiAcpiAddressRangeACPI;
   1631 
   1632   case EfiACPIMemoryNVS:
   1633     return EfiAcpiAddressRangeNVS;
   1634 
   1635   //
   1636   // All other types map to reserved.
   1637   // Adding the code just waists FLASH space.
   1638   //
   1639   //  case  EfiReservedMemoryType:
   1640   //  case  EfiUnusableMemory:
   1641   //  case  EfiMemoryMappedIO:
   1642   //  case  EfiMemoryMappedIOPortSpace:
   1643   //  case  EfiPalCode:
   1644   //
   1645   default:
   1646     return EfiAcpiAddressRangeReserved;
   1647   }
   1648 }
   1649 
   1650 /**
   1651   Build the E820 table.
   1652 
   1653   @param  Private  Legacy BIOS Instance data
   1654   @param  Size     Size of E820 Table
   1655 
   1656   @retval EFI_SUCCESS  It should always work.
   1657 
   1658 **/
   1659 EFI_STATUS
   1660 LegacyBiosBuildE820 (
   1661   IN  LEGACY_BIOS_INSTANCE    *Private,
   1662   OUT UINTN                   *Size
   1663   )
   1664 {
   1665   EFI_STATUS                  Status;
   1666   EFI_E820_ENTRY64            *E820Table;
   1667   EFI_MEMORY_DESCRIPTOR       *EfiMemoryMap;
   1668   EFI_MEMORY_DESCRIPTOR       *EfiMemoryMapEnd;
   1669   EFI_MEMORY_DESCRIPTOR       *EfiEntry;
   1670   EFI_MEMORY_DESCRIPTOR       *NextEfiEntry;
   1671   EFI_MEMORY_DESCRIPTOR       TempEfiEntry;
   1672   UINTN                       EfiMemoryMapSize;
   1673   UINTN                       EfiMapKey;
   1674   UINTN                       EfiDescriptorSize;
   1675   UINT32                      EfiDescriptorVersion;
   1676   UINTN                       Index;
   1677   EFI_PEI_HOB_POINTERS        Hob;
   1678   EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
   1679   UINTN                       TempIndex;
   1680   UINTN                       IndexSort;
   1681   UINTN                       TempNextIndex;
   1682   EFI_E820_ENTRY64            TempE820;
   1683   EFI_ACPI_MEMORY_TYPE        TempType;
   1684   BOOLEAN                     ChangedFlag;
   1685   UINTN                       Above1MIndex;
   1686   UINT64                      MemoryBlockLength;
   1687 
   1688   E820Table = (EFI_E820_ENTRY64 *) Private->E820Table;
   1689 
   1690   //
   1691   // Get the EFI memory map.
   1692   //
   1693   EfiMemoryMapSize  = 0;
   1694   EfiMemoryMap      = NULL;
   1695   Status = gBS->GetMemoryMap (
   1696                   &EfiMemoryMapSize,
   1697                   EfiMemoryMap,
   1698                   &EfiMapKey,
   1699                   &EfiDescriptorSize,
   1700                   &EfiDescriptorVersion
   1701                   );
   1702   ASSERT (Status == EFI_BUFFER_TOO_SMALL);
   1703 
   1704   do {
   1705     //
   1706     // Use size returned back plus 1 descriptor for the AllocatePool.
   1707     // We don't just multiply by 2 since the "for" loop below terminates on
   1708     // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize
   1709     // we process bogus entries and create bogus E820 entries.
   1710     //
   1711     EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (EfiMemoryMapSize);
   1712     ASSERT (EfiMemoryMap != NULL);
   1713     Status = gBS->GetMemoryMap (
   1714                     &EfiMemoryMapSize,
   1715                     EfiMemoryMap,
   1716                     &EfiMapKey,
   1717                     &EfiDescriptorSize,
   1718                     &EfiDescriptorVersion
   1719                     );
   1720     if (EFI_ERROR (Status)) {
   1721       FreePool (EfiMemoryMap);
   1722     }
   1723   } while (Status == EFI_BUFFER_TOO_SMALL);
   1724 
   1725   ASSERT_EFI_ERROR (Status);
   1726 
   1727   //
   1728   // Punch in the E820 table for memory less than 1 MB.
   1729   // Assume ZeroMem () has been done on data structure.
   1730   //
   1731   //
   1732   // First entry is 0 to (640k - EBDA)
   1733   //
   1734   E820Table[0].BaseAddr  = 0;
   1735   E820Table[0].Length    = (UINT64) ((*(UINT16 *) (UINTN)0x40E) << 4);
   1736   E820Table[0].Type      = EfiAcpiAddressRangeMemory;
   1737 
   1738   //
   1739   // Second entry is (640k - EBDA) to 640k
   1740   //
   1741   E820Table[1].BaseAddr  = E820Table[0].Length;
   1742   E820Table[1].Length    = (UINT64) ((640 * 1024) - E820Table[0].Length);
   1743   E820Table[1].Type      = EfiAcpiAddressRangeReserved;
   1744 
   1745   //
   1746   // Third Entry is legacy BIOS
   1747   // DO NOT CLAIM region from 0xA0000-0xDFFFF. OS can use free areas
   1748   // to page in memory under 1MB.
   1749   // Omit region from 0xE0000 to start of BIOS, if any. This can be
   1750   // used for a multiple reasons including OPROMS.
   1751   //
   1752 
   1753   //
   1754   // The CSM binary image size is not the actually size that CSM binary used,
   1755   // to avoid memory corrupt, we declare the 0E0000 - 0FFFFF is used by CSM binary.
   1756   //
   1757   E820Table[2].BaseAddr  = 0xE0000;
   1758   E820Table[2].Length    = 0x20000;
   1759   E820Table[2].Type      = EfiAcpiAddressRangeReserved;
   1760 
   1761   Above1MIndex = 2;
   1762 
   1763   //
   1764   // Process the EFI map to produce E820 map;
   1765   //
   1766 
   1767   //
   1768   // Sort memory map from low to high
   1769   //
   1770   EfiEntry        = EfiMemoryMap;
   1771   NextEfiEntry    = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
   1772   EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);
   1773   while (EfiEntry < EfiMemoryMapEnd) {
   1774     while (NextEfiEntry < EfiMemoryMapEnd) {
   1775       if (EfiEntry->PhysicalStart > NextEfiEntry->PhysicalStart) {
   1776         CopyMem (&TempEfiEntry, EfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
   1777         CopyMem (EfiEntry, NextEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
   1778         CopyMem (NextEfiEntry, &TempEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
   1779       }
   1780 
   1781       NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (NextEfiEntry, EfiDescriptorSize);
   1782     }
   1783 
   1784     EfiEntry      = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
   1785     NextEfiEntry  = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
   1786   }
   1787 
   1788   EfiEntry        = EfiMemoryMap;
   1789   EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);
   1790   for (Index = Above1MIndex; (EfiEntry < EfiMemoryMapEnd) && (Index < EFI_MAX_E820_ENTRY - 1); ) {
   1791     MemoryBlockLength = (UINT64) (LShiftU64 (EfiEntry->NumberOfPages, 12));
   1792     if ((EfiEntry->PhysicalStart + MemoryBlockLength) < 0x100000) {
   1793       //
   1794       // Skip the memory block is under 1MB
   1795       //
   1796     } else {
   1797       if (EfiEntry->PhysicalStart < 0x100000) {
   1798         //
   1799         // When the memory block spans below 1MB, ensure the memory block start address is at least 1MB
   1800         //
   1801         MemoryBlockLength       -= 0x100000 - EfiEntry->PhysicalStart;
   1802         EfiEntry->PhysicalStart =  0x100000;
   1803       }
   1804 
   1805       //
   1806       // Convert memory type to E820 type
   1807       //
   1808       TempType = EfiMemoryTypeToE820Type (EfiEntry->Type);
   1809 
   1810       if ((E820Table[Index].Type == TempType) && (EfiEntry->PhysicalStart == (E820Table[Index].BaseAddr + E820Table[Index].Length))) {
   1811         //
   1812         // Grow an existing entry
   1813         //
   1814         E820Table[Index].Length += MemoryBlockLength;
   1815       } else {
   1816         //
   1817         // Make a new entry
   1818         //
   1819         ++Index;
   1820         E820Table[Index].BaseAddr  = EfiEntry->PhysicalStart;
   1821         E820Table[Index].Length    = MemoryBlockLength;
   1822         E820Table[Index].Type      = TempType;
   1823       }
   1824     }
   1825     EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
   1826   }
   1827 
   1828   FreePool (EfiMemoryMap);
   1829 
   1830   //
   1831   // Process the reserved memory map to produce E820 map ;
   1832   //
   1833   for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
   1834     if (Hob.Raw != NULL && GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
   1835       ResourceHob = Hob.ResourceDescriptor;
   1836       if (((ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_MAPPED_IO) ||
   1837           (ResourceHob->ResourceType == EFI_RESOURCE_FIRMWARE_DEVICE)  ||
   1838           (ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_RESERVED)    ) &&
   1839           (ResourceHob->PhysicalStart > 0x100000) &&
   1840           (Index < EFI_MAX_E820_ENTRY - 1)) {
   1841         ++Index;
   1842         E820Table[Index].BaseAddr  = ResourceHob->PhysicalStart;
   1843         E820Table[Index].Length    = ResourceHob->ResourceLength;
   1844         E820Table[Index].Type      = EfiAcpiAddressRangeReserved;
   1845       }
   1846     }
   1847   }
   1848 
   1849   Index ++;
   1850   Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index;
   1851   Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index;
   1852   Private->NumberE820Entries = (UINT32)Index;
   1853   *Size = (UINTN) (Index * sizeof (EFI_E820_ENTRY64));
   1854 
   1855   //
   1856   // Sort E820Table from low to high
   1857   //
   1858   for (TempIndex = 0; TempIndex < Index; TempIndex++) {
   1859     ChangedFlag = FALSE;
   1860     for (TempNextIndex = 1; TempNextIndex < Index - TempIndex; TempNextIndex++) {
   1861       if (E820Table[TempNextIndex - 1].BaseAddr > E820Table[TempNextIndex].BaseAddr) {
   1862         ChangedFlag                       = TRUE;
   1863         TempE820.BaseAddr                 = E820Table[TempNextIndex - 1].BaseAddr;
   1864         TempE820.Length                   = E820Table[TempNextIndex - 1].Length;
   1865         TempE820.Type                     = E820Table[TempNextIndex - 1].Type;
   1866 
   1867         E820Table[TempNextIndex - 1].BaseAddr  = E820Table[TempNextIndex].BaseAddr;
   1868         E820Table[TempNextIndex - 1].Length    = E820Table[TempNextIndex].Length;
   1869         E820Table[TempNextIndex - 1].Type      = E820Table[TempNextIndex].Type;
   1870 
   1871         E820Table[TempNextIndex].BaseAddr      = TempE820.BaseAddr;
   1872         E820Table[TempNextIndex].Length        = TempE820.Length;
   1873         E820Table[TempNextIndex].Type          = TempE820.Type;
   1874       }
   1875     }
   1876 
   1877     if (!ChangedFlag) {
   1878       break;
   1879     }
   1880   }
   1881 
   1882   //
   1883   // Remove the overlap range
   1884   //
   1885   for (TempIndex = 1; TempIndex < Index; TempIndex++) {
   1886     if (E820Table[TempIndex - 1].BaseAddr <= E820Table[TempIndex].BaseAddr &&
   1887         ((E820Table[TempIndex - 1].BaseAddr + E820Table[TempIndex - 1].Length) >=
   1888          (E820Table[TempIndex].BaseAddr +E820Table[TempIndex].Length))) {
   1889         //
   1890         //Overlap range is found
   1891         //
   1892         ASSERT (E820Table[TempIndex - 1].Type == E820Table[TempIndex].Type);
   1893 
   1894         if (TempIndex == Index - 1) {
   1895           E820Table[TempIndex].BaseAddr = 0;
   1896           E820Table[TempIndex].Length   = 0;
   1897           E820Table[TempIndex].Type     = (EFI_ACPI_MEMORY_TYPE) 0;
   1898           Index--;
   1899           break;
   1900         } else {
   1901           for (IndexSort = TempIndex; IndexSort < Index - 1; IndexSort ++) {
   1902             E820Table[IndexSort].BaseAddr = E820Table[IndexSort + 1].BaseAddr;
   1903             E820Table[IndexSort].Length   = E820Table[IndexSort + 1].Length;
   1904             E820Table[IndexSort].Type     = E820Table[IndexSort + 1].Type;
   1905           }
   1906           Index--;
   1907        }
   1908     }
   1909   }
   1910 
   1911 
   1912 
   1913   Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index;
   1914   Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index;
   1915   Private->NumberE820Entries = (UINT32)Index;
   1916   *Size = (UINTN) (Index * sizeof (EFI_E820_ENTRY64));
   1917 
   1918   //
   1919   // Determine OS usable memory above 1Mb
   1920   //
   1921   Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb = 0x0000;
   1922   for (TempIndex = Above1MIndex; TempIndex < Index; TempIndex++) {
   1923     if (E820Table[TempIndex].BaseAddr >= 0x100000 && E820Table[TempIndex].BaseAddr < 0x100000000ULL) { // not include above 4G memory
   1924       //
   1925       // ACPIReclaimMemory is also usable memory for ACPI OS, after OS dumps all ACPI tables.
   1926       //
   1927       if ((E820Table[TempIndex].Type == EfiAcpiAddressRangeMemory) || (E820Table[TempIndex].Type == EfiAcpiAddressRangeACPI)) {
   1928         Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb += (UINT32) (E820Table[TempIndex].Length);
   1929       } else {
   1930         break; // break at first not normal memory, because SMM may use reserved memory.
   1931       }
   1932     }
   1933   }
   1934 
   1935   Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb = Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb;
   1936 
   1937   //
   1938   // Print DEBUG information
   1939   //
   1940   for (TempIndex = 0; TempIndex < Index; TempIndex++) {
   1941     DEBUG((EFI_D_INFO, "E820[%2d]: 0x%16lx ---- 0x%16lx, Type = 0x%x \n",
   1942       TempIndex,
   1943       E820Table[TempIndex].BaseAddr,
   1944       (E820Table[TempIndex].BaseAddr + E820Table[TempIndex].Length),
   1945       E820Table[TempIndex].Type
   1946       ));
   1947   }
   1948 
   1949   return EFI_SUCCESS;
   1950 }
   1951 
   1952 
   1953 /**
   1954   Fill in the standard BDA and EBDA stuff prior to legacy Boot
   1955 
   1956   @param  Private      Legacy BIOS Instance data
   1957 
   1958   @retval EFI_SUCCESS  It should always work.
   1959 
   1960 **/
   1961 EFI_STATUS
   1962 LegacyBiosCompleteBdaBeforeBoot (
   1963   IN  LEGACY_BIOS_INSTANCE    *Private
   1964   )
   1965 {
   1966   BDA_STRUC                   *Bda;
   1967   UINT16                      MachineConfig;
   1968   DEVICE_PRODUCER_DATA_HEADER *SioPtr;
   1969 
   1970   Bda           = (BDA_STRUC *) ((UINTN) 0x400);
   1971   MachineConfig = 0;
   1972 
   1973   SioPtr        = &(Private->IntThunk->EfiToLegacy16BootTable.SioData);
   1974   Bda->Com1     = SioPtr->Serial[0].Address;
   1975   Bda->Com2     = SioPtr->Serial[1].Address;
   1976   Bda->Com3     = SioPtr->Serial[2].Address;
   1977   Bda->Com4     = SioPtr->Serial[3].Address;
   1978 
   1979   if (SioPtr->Serial[0].Address != 0x00) {
   1980     MachineConfig += 0x200;
   1981   }
   1982 
   1983   if (SioPtr->Serial[1].Address != 0x00) {
   1984     MachineConfig += 0x200;
   1985   }
   1986 
   1987   if (SioPtr->Serial[2].Address != 0x00) {
   1988     MachineConfig += 0x200;
   1989   }
   1990 
   1991   if (SioPtr->Serial[3].Address != 0x00) {
   1992     MachineConfig += 0x200;
   1993   }
   1994 
   1995   Bda->Lpt1 = SioPtr->Parallel[0].Address;
   1996   Bda->Lpt2 = SioPtr->Parallel[1].Address;
   1997   Bda->Lpt3 = SioPtr->Parallel[2].Address;
   1998 
   1999   if (SioPtr->Parallel[0].Address != 0x00) {
   2000     MachineConfig += 0x4000;
   2001   }
   2002 
   2003   if (SioPtr->Parallel[1].Address != 0x00) {
   2004     MachineConfig += 0x4000;
   2005   }
   2006 
   2007   if (SioPtr->Parallel[2].Address != 0x00) {
   2008     MachineConfig += 0x4000;
   2009   }
   2010 
   2011   Bda->NumberOfDrives = (UINT8) (Bda->NumberOfDrives + Private->IdeDriveCount);
   2012   if (SioPtr->Floppy.NumberOfFloppy != 0x00) {
   2013     MachineConfig     = (UINT16) (MachineConfig + 0x01 + (SioPtr->Floppy.NumberOfFloppy - 1) * 0x40);
   2014     Bda->FloppyXRate  = 0x07;
   2015   }
   2016 
   2017   Bda->Lpt1_2Timeout  = 0x1414;
   2018   Bda->Lpt3_4Timeout  = 0x1414;
   2019   Bda->Com1_2Timeout  = 0x0101;
   2020   Bda->Com3_4Timeout  = 0x0101;
   2021 
   2022   //
   2023   // Force VGA and Coprocessor, indicate 101/102 keyboard
   2024   //
   2025   MachineConfig       = (UINT16) (MachineConfig + 0x00 + 0x02 + (SioPtr->MousePresent * 0x04));
   2026   Bda->MachineConfig  = MachineConfig;
   2027 
   2028   return EFI_SUCCESS;
   2029 }
   2030 
   2031 /**
   2032   Fill in the standard BDA for Keyboard LEDs
   2033 
   2034   @param  This         Protocol instance pointer.
   2035   @param  Leds         Current LED status
   2036 
   2037   @retval EFI_SUCCESS  It should always work.
   2038 
   2039 **/
   2040 EFI_STATUS
   2041 EFIAPI
   2042 LegacyBiosUpdateKeyboardLedStatus (
   2043   IN EFI_LEGACY_BIOS_PROTOCOL           *This,
   2044   IN  UINT8                             Leds
   2045   )
   2046 {
   2047   LEGACY_BIOS_INSTANCE  *Private;
   2048   BDA_STRUC             *Bda;
   2049   UINT8                 LocalLeds;
   2050   EFI_IA32_REGISTER_SET Regs;
   2051 
   2052   Bda                 = (BDA_STRUC *) ((UINTN) 0x400);
   2053 
   2054   Private             = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
   2055   LocalLeds           = Leds;
   2056   Bda->LedStatus      = (UINT8) ((Bda->LedStatus &~0x07) | LocalLeds);
   2057   LocalLeds           = (UINT8) (LocalLeds << 4);
   2058   Bda->ShiftStatus    = (UINT8) ((Bda->ShiftStatus &~0x70) | LocalLeds);
   2059   LocalLeds           = (UINT8) (Leds & 0x20);
   2060   Bda->KeyboardStatus = (UINT8) ((Bda->KeyboardStatus &~0x20) | LocalLeds);
   2061   //
   2062   // Call into Legacy16 code to allow it to do any processing
   2063   //
   2064   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
   2065   Regs.X.AX = Legacy16SetKeyboardLeds;
   2066   Regs.H.CL = Leds;
   2067 
   2068   Private->LegacyBios.FarCall86 (
   2069     &Private->LegacyBios,
   2070     Private->Legacy16Table->Compatibility16CallSegment,
   2071     Private->Legacy16Table->Compatibility16CallOffset,
   2072     &Regs,
   2073     NULL,
   2074     0
   2075     );
   2076 
   2077   return EFI_SUCCESS;
   2078 }
   2079 
   2080 
   2081 /**
   2082   Fill in the standard CMOS stuff prior to legacy Boot
   2083 
   2084   @param  Private      Legacy BIOS Instance data
   2085 
   2086   @retval EFI_SUCCESS  It should always work.
   2087 
   2088 **/
   2089 EFI_STATUS
   2090 LegacyBiosCompleteStandardCmosBeforeBoot (
   2091   IN  LEGACY_BIOS_INSTANCE    *Private
   2092   )
   2093 {
   2094   UINT8   Bda;
   2095   UINT8   Floppy;
   2096   UINT32  Size;
   2097 
   2098   //
   2099   // Update CMOS locations
   2100   // 10 floppy
   2101   // 12,19,1A - ignore as OS don't use them and there is no standard due
   2102   //            to large capacity drives
   2103   // CMOS 14 = BDA 40:10 plus bit 3(display enabled)
   2104   //
   2105   Bda = (UINT8)(*((UINT8 *)((UINTN)0x410)) | BIT3);
   2106 
   2107   //
   2108   // Force display enabled
   2109   //
   2110   Floppy = 0x00;
   2111   if ((Bda & BIT0) != 0) {
   2112     Floppy = BIT6;
   2113   }
   2114 
   2115   //
   2116   // Check if 2.88MB floppy set
   2117   //
   2118   if ((Bda & (BIT7 | BIT6)) != 0) {
   2119     Floppy = (UINT8)(Floppy | BIT1);
   2120   }
   2121 
   2122   LegacyWriteStandardCmos (CMOS_10, Floppy);
   2123   LegacyWriteStandardCmos (CMOS_14, Bda);
   2124 
   2125   //
   2126   // Force Status Register A to set rate selection bits and divider
   2127   //
   2128   LegacyWriteStandardCmos (CMOS_0A, 0x26);
   2129 
   2130   //
   2131   // redo memory size since it can change
   2132   //
   2133   Size = (15 * SIZE_1MB) >> 10;
   2134   if (Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb < (15 * SIZE_1MB)) {
   2135     Size  = Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb >> 10;
   2136   }
   2137 
   2138   LegacyWriteStandardCmos (CMOS_17, (UINT8)(Size & 0xFF));
   2139   LegacyWriteStandardCmos (CMOS_30, (UINT8)(Size & 0xFF));
   2140   LegacyWriteStandardCmos (CMOS_18, (UINT8)(Size >> 8));
   2141   LegacyWriteStandardCmos (CMOS_31, (UINT8)(Size >> 8));
   2142 
   2143   LegacyCalculateWriteStandardCmosChecksum ();
   2144 
   2145   return EFI_SUCCESS;
   2146 }
   2147 
   2148 /**
   2149   Relocate this image under 4G memory for IPF.
   2150 
   2151   @param  ImageHandle  Handle of driver image.
   2152   @param  SystemTable  Pointer to system table.
   2153 
   2154   @retval EFI_SUCCESS  Image successfully relocated.
   2155   @retval EFI_ABORTED  Failed to relocate image.
   2156 
   2157 **/
   2158 EFI_STATUS
   2159 RelocateImageUnder4GIfNeeded (
   2160   IN EFI_HANDLE           ImageHandle,
   2161   IN EFI_SYSTEM_TABLE     *SystemTable
   2162   )
   2163 {
   2164   return EFI_SUCCESS;
   2165 }
   2166