Home | History | Annotate | Download | only in LegacyBiosDxe
      1 /** @file
      2 
      3 Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
      4 
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions
      7 of the BSD License which accompanies this distribution.  The
      8 full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "LegacyBiosInterface.h"
     17 
     18 #define PHYSICAL_ADDRESS_TO_POINTER(Address)  ((VOID *) ((UINTN) Address))
     19 
     20 //
     21 // define maximum number of HDD system supports
     22 //
     23 #define MAX_HDD_ENTRIES 0x30
     24 
     25 //
     26 // Module Global:
     27 //  Since this driver will only ever produce one instance of the Private Data
     28 //  protocol you are not required to dynamically allocate the PrivateData.
     29 //
     30 LEGACY_BIOS_INSTANCE  mPrivateData;
     31 
     32 //
     33 // The SMBIOS table in EfiRuntimeServicesData memory
     34 //
     35 VOID                  *mRuntimeSmbiosEntryPoint = NULL;
     36 
     37 //
     38 // The SMBIOS table in EfiReservedMemoryType memory
     39 //
     40 EFI_PHYSICAL_ADDRESS  mReserveSmbiosEntryPoint = 0;
     41 EFI_PHYSICAL_ADDRESS  mStructureTableAddress   = 0;
     42 UINTN                 mStructureTablePages     = 0;
     43 
     44 /**
     45   Do an AllocatePages () of type AllocateMaxAddress for EfiBootServicesCode
     46   memory.
     47 
     48   @param  AllocateType               Allocated Legacy Memory Type
     49   @param  StartPageAddress           Start address of range
     50   @param  Pages                      Number of pages to allocate
     51   @param  Result                     Result of allocation
     52 
     53   @retval EFI_SUCCESS                Legacy16 code loaded
     54   @retval Other                      No protocol installed, unload driver.
     55 
     56 **/
     57 EFI_STATUS
     58 AllocateLegacyMemory (
     59   IN  EFI_ALLOCATE_TYPE         AllocateType,
     60   IN  EFI_PHYSICAL_ADDRESS      StartPageAddress,
     61   IN  UINTN                     Pages,
     62   OUT EFI_PHYSICAL_ADDRESS      *Result
     63   )
     64 {
     65   EFI_STATUS            Status;
     66   EFI_PHYSICAL_ADDRESS  MemPage;
     67 
     68   //
     69   // Allocate Pages of memory less <= StartPageAddress
     70   //
     71   MemPage = (EFI_PHYSICAL_ADDRESS) (UINTN) StartPageAddress;
     72   Status = gBS->AllocatePages (
     73                   AllocateType,
     74                   EfiBootServicesCode,
     75                   Pages,
     76                   &MemPage
     77                   );
     78   //
     79   // Do not ASSERT on Status error but let caller decide since some cases
     80   // memory is already taken but that is ok.
     81   //
     82   if (!EFI_ERROR (Status)) {
     83     *Result = (EFI_PHYSICAL_ADDRESS) (UINTN) MemPage;
     84   }
     85   //
     86   // If reach here the status = EFI_SUCCESS
     87   //
     88   return Status;
     89 }
     90 
     91 
     92 /**
     93   This function is called when EFI needs to reserve an area in the 0xE0000 or 0xF0000
     94   64 KB blocks.
     95 
     96   Note: inconsistency with the Framework CSM spec. Per the spec, this function may be
     97   invoked only once. This limitation is relaxed to allow multiple calls in this implemenation.
     98 
     99   @param  This                       Protocol instance pointer.
    100   @param  LegacyMemorySize           Size of required region
    101   @param  Region                     Region to use. 00 = Either 0xE0000 or 0xF0000
    102                                      block Bit0 = 1 0xF0000 block Bit1 = 1 0xE0000
    103                                      block
    104   @param  Alignment                  Address alignment. Bit mapped. First non-zero
    105                                      bit from right is alignment.
    106   @param  LegacyMemoryAddress        Region Assigned
    107 
    108   @retval EFI_SUCCESS                Region assigned
    109   @retval EFI_ACCESS_DENIED          Procedure previously invoked
    110   @retval Other                      Region not assigned
    111 
    112 **/
    113 EFI_STATUS
    114 EFIAPI
    115 LegacyBiosGetLegacyRegion (
    116   IN    EFI_LEGACY_BIOS_PROTOCOL *This,
    117   IN    UINTN                    LegacyMemorySize,
    118   IN    UINTN                    Region,
    119   IN    UINTN                    Alignment,
    120   OUT   VOID                     **LegacyMemoryAddress
    121   )
    122 {
    123 
    124   LEGACY_BIOS_INSTANCE  *Private;
    125   EFI_IA32_REGISTER_SET Regs;
    126   EFI_STATUS            Status;
    127   UINT32                Granularity;
    128 
    129   Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
    130   Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);
    131 
    132   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
    133   Regs.X.AX = Legacy16GetTableAddress;
    134   Regs.X.BX = (UINT16) Region;
    135   Regs.X.CX = (UINT16) LegacyMemorySize;
    136   Regs.X.DX = (UINT16) Alignment;
    137   Private->LegacyBios.FarCall86 (
    138      &Private->LegacyBios,
    139      Private->Legacy16CallSegment,
    140      Private->Legacy16CallOffset,
    141      &Regs,
    142      NULL,
    143      0
    144      );
    145 
    146   if (Regs.X.AX == 0) {
    147     *LegacyMemoryAddress  = (VOID *) (UINTN) ((Regs.X.DS << 4) + Regs.X.BX);
    148     Status = EFI_SUCCESS;
    149   } else {
    150     Status = EFI_OUT_OF_RESOURCES;
    151   }
    152 
    153   Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
    154   Private->LegacyRegion->Lock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);
    155 
    156   return Status;
    157 }
    158 
    159 
    160 /**
    161   This function is called when copying data to the region assigned by
    162   EFI_LEGACY_BIOS_PROTOCOL.GetLegacyRegion().
    163 
    164   @param  This                       Protocol instance pointer.
    165   @param  LegacyMemorySize           Size of data to copy
    166   @param  LegacyMemoryAddress        Legacy Region destination address Note: must
    167                                      be in region assigned by
    168                                      LegacyBiosGetLegacyRegion
    169   @param  LegacyMemorySourceAddress  Source of data
    170 
    171   @retval EFI_SUCCESS                The data was copied successfully.
    172   @retval EFI_ACCESS_DENIED          Either the starting or ending address is out of bounds.
    173 **/
    174 EFI_STATUS
    175 EFIAPI
    176 LegacyBiosCopyLegacyRegion (
    177   IN EFI_LEGACY_BIOS_PROTOCOL *This,
    178   IN    UINTN                 LegacyMemorySize,
    179   IN    VOID                  *LegacyMemoryAddress,
    180   IN    VOID                  *LegacyMemorySourceAddress
    181   )
    182 {
    183 
    184   LEGACY_BIOS_INSTANCE  *Private;
    185   UINT32                Granularity;
    186 
    187   if ((LegacyMemoryAddress < (VOID *)(UINTN)0xE0000 ) ||
    188       ((UINTN) LegacyMemoryAddress + LegacyMemorySize > (UINTN) 0x100000)
    189         ) {
    190     return EFI_ACCESS_DENIED;
    191   }
    192   //
    193   // There is no protection from writes over lapping if this function is
    194   // called multiple times.
    195   //
    196   Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
    197   Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);
    198   CopyMem (LegacyMemoryAddress, LegacyMemorySourceAddress, LegacyMemorySize);
    199 
    200   Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
    201   Private->LegacyRegion->Lock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);
    202 
    203   return EFI_SUCCESS;
    204 }
    205 
    206 
    207 /**
    208   Find Legacy16 BIOS image in the FLASH device and shadow it into memory. Find
    209   the $EFI table in the shadow area. Thunk into the Legacy16 code after it had
    210   been shadowed.
    211 
    212   @param  Private                    Legacy BIOS context data
    213 
    214   @retval EFI_SUCCESS                Legacy16 code loaded
    215   @retval Other                      No protocol installed, unload driver.
    216 
    217 **/
    218 EFI_STATUS
    219 ShadowAndStartLegacy16 (
    220   IN  LEGACY_BIOS_INSTANCE  *Private
    221   )
    222 {
    223   EFI_STATUS                        Status;
    224   UINT8                             *Ptr;
    225   UINT8                             *PtrEnd;
    226   BOOLEAN                           Done;
    227   EFI_COMPATIBILITY16_TABLE         *Table;
    228   UINT8                             CheckSum;
    229   EFI_IA32_REGISTER_SET             Regs;
    230   EFI_TO_COMPATIBILITY16_INIT_TABLE *EfiToLegacy16InitTable;
    231   EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
    232   VOID                              *LegacyBiosImage;
    233   UINTN                             LegacyBiosImageSize;
    234   UINTN                             E820Size;
    235   UINT32                            *ClearPtr;
    236   BBS_TABLE                         *BbsTable;
    237   LEGACY_EFI_HDD_TABLE              *LegacyEfiHddTable;
    238   UINTN                             Index;
    239   UINT32                            TpmPointer;
    240   VOID                              *TpmBinaryImage;
    241   UINTN                             TpmBinaryImageSize;
    242   UINTN                             Location;
    243   UINTN                             Alignment;
    244   UINTN                             TempData;
    245   EFI_PHYSICAL_ADDRESS              Address;
    246   UINT16                            OldMask;
    247   UINT16                            NewMask;
    248   UINT32                            Granularity;
    249   EFI_GCD_MEMORY_SPACE_DESCRIPTOR   Descriptor;
    250 
    251   Location  = 0;
    252   Alignment = 0;
    253 
    254   //
    255   // we allocate the C/D/E/F segment as RT code so no one will use it any more.
    256   //
    257   Address = 0xC0000;
    258   gDS->GetMemorySpaceDescriptor (Address, &Descriptor);
    259   if (Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) {
    260     //
    261     // If it is already reserved, we should be safe, or else we allocate it.
    262     //
    263     Status = gBS->AllocatePages (
    264                     AllocateAddress,
    265                     EfiRuntimeServicesCode,
    266                     0x40000/EFI_PAGE_SIZE,
    267                     &Address
    268                     );
    269     if (EFI_ERROR (Status)) {
    270       //
    271       // Bugbug: need to figure out whether C/D/E/F segment should be marked as reserved memory.
    272       //
    273       DEBUG ((DEBUG_ERROR, "Failed to allocate the C/D/E/F segment Status = %r", Status));
    274     }
    275   }
    276 
    277   //
    278   // start testtest
    279   //    GetTimerValue (&Ticker);
    280   //
    281   //  gRT->SetVariable (L"StartLegacy",
    282   //                    &gEfiGlobalVariableGuid,
    283   //                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
    284   //                    sizeof (UINT64),
    285   //                    (VOID *)&Ticker
    286   //                    );
    287   // end testtest
    288   //
    289   EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
    290   Status = Private->LegacyBiosPlatform->GetPlatformInfo (
    291                                           Private->LegacyBiosPlatform,
    292                                           EfiGetPlatformBinarySystemRom,
    293                                           &LegacyBiosImage,
    294                                           &LegacyBiosImageSize,
    295                                           &Location,
    296                                           &Alignment,
    297                                           0,
    298                                           0
    299                                           );
    300   if (EFI_ERROR (Status)) {
    301     return Status;
    302   }
    303 
    304   Private->BiosStart            = (UINT32) (0x100000 - LegacyBiosImageSize);
    305   Private->OptionRom            = 0xc0000;
    306   Private->LegacyBiosImageSize  = (UINT32) LegacyBiosImageSize;
    307 
    308   //
    309   // Can only shadow into memory allocated for legacy useage.
    310   //
    311   ASSERT (Private->BiosStart > Private->OptionRom);
    312 
    313   //
    314   // Shadow Legacy BIOS. Turn on memory and copy image
    315   //
    316   Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xc0000, 0x40000, &Granularity);
    317 
    318   ClearPtr = (VOID *) ((UINTN) 0xc0000);
    319 
    320   //
    321   // Initialize region from 0xc0000 to start of BIOS to all ffs. This allows unused
    322   // regions to be used by EMM386 etc.
    323   //
    324   SetMem ((VOID *) ClearPtr, (UINTN) (0x40000 - LegacyBiosImageSize), 0xff);
    325 
    326   TempData = Private->BiosStart;
    327 
    328   CopyMem (
    329     (VOID *) TempData,
    330     LegacyBiosImage,
    331     (UINTN) LegacyBiosImageSize
    332     );
    333 
    334   Private->Cpu->FlushDataCache (Private->Cpu, 0xc0000, 0x40000, EfiCpuFlushTypeWriteBackInvalidate);
    335 
    336   //
    337   // Search for Legacy16 table in Shadowed ROM
    338   //
    339   Done  = FALSE;
    340   Table = NULL;
    341   for (Ptr = (UINT8 *) TempData; Ptr < (UINT8 *) ((UINTN) 0x100000) && !Done; Ptr += 0x10) {
    342     if (*(UINT32 *) Ptr == SIGNATURE_32 ('I', 'F', 'E', '$')) {
    343       Table   = (EFI_COMPATIBILITY16_TABLE *) Ptr;
    344       PtrEnd  = Ptr + Table->TableLength;
    345       for (CheckSum = 0; Ptr < PtrEnd; Ptr++) {
    346         CheckSum = (UINT8) (CheckSum +*Ptr);
    347       }
    348 
    349       Done = TRUE;
    350     }
    351   }
    352 
    353   if (Table == NULL) {
    354     DEBUG ((EFI_D_ERROR, "No Legacy16 table found\n"));
    355     return EFI_NOT_FOUND;
    356   }
    357 
    358   if (!Done) {
    359     //
    360     // Legacy16 table header checksum error.
    361     //
    362     DEBUG ((EFI_D_ERROR, "Legacy16 table found with bad talbe header checksum\n"));
    363   }
    364 
    365   //
    366   // Remember location of the Legacy16 table
    367   //
    368   Private->Legacy16Table            = Table;
    369   Private->Legacy16CallSegment      = Table->Compatibility16CallSegment;
    370   Private->Legacy16CallOffset       = Table->Compatibility16CallOffset;
    371   EfiToLegacy16InitTable            = &Private->IntThunk->EfiToLegacy16InitTable;
    372   Private->Legacy16InitPtr          = EfiToLegacy16InitTable;
    373   Private->Legacy16BootPtr          = &Private->IntThunk->EfiToLegacy16BootTable;
    374   Private->InternalIrqRoutingTable  = NULL;
    375   Private->NumberIrqRoutingEntries  = 0;
    376   Private->BbsTablePtr              = NULL;
    377   Private->LegacyEfiHddTable        = NULL;
    378   Private->DiskEnd                  = 0;
    379   Private->Disk4075                 = 0;
    380   Private->HddTablePtr              = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo;
    381   Private->NumberHddControllers     = MAX_IDE_CONTROLLER;
    382   Private->Dump[0]                  = 'D';
    383   Private->Dump[1]                  = 'U';
    384   Private->Dump[2]                  = 'M';
    385   Private->Dump[3]                  = 'P';
    386 
    387   ZeroMem (
    388     Private->Legacy16BootPtr,
    389     sizeof (EFI_TO_COMPATIBILITY16_BOOT_TABLE)
    390     );
    391 
    392   //
    393   // Store away a copy of the EFI System Table
    394   //
    395   Table->EfiSystemTable = (UINT32) (UINTN) gST;
    396 
    397   //
    398   // IPF CSM integration -Bug
    399   //
    400   // Construct the Legacy16 boot memory map. This sets up number of
    401   // E820 entries.
    402   //
    403   LegacyBiosBuildE820 (Private, &E820Size);
    404   //
    405   // Initialize BDA and EBDA standard values needed to load Legacy16 code
    406   //
    407   LegacyBiosInitBda (Private);
    408   LegacyBiosInitCmos (Private);
    409 
    410   //
    411   // All legacy interrupt should be masked when do initialization work from legacy 16 code.
    412   //
    413   Private->Legacy8259->GetMask(Private->Legacy8259, &OldMask, NULL, NULL, NULL);
    414   NewMask = 0xFFFF;
    415   Private->Legacy8259->SetMask(Private->Legacy8259, &NewMask, NULL, NULL, NULL);
    416 
    417   //
    418   // Call into Legacy16 code to do an INIT
    419   //
    420   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
    421   Regs.X.AX = Legacy16InitializeYourself;
    422   Regs.X.ES = EFI_SEGMENT (*((UINT32 *) &EfiToLegacy16InitTable));
    423   Regs.X.BX = EFI_OFFSET (*((UINT32 *) &EfiToLegacy16InitTable));
    424 
    425   Private->LegacyBios.FarCall86 (
    426     &Private->LegacyBios,
    427     Table->Compatibility16CallSegment,
    428     Table->Compatibility16CallOffset,
    429     &Regs,
    430     NULL,
    431     0
    432     );
    433 
    434   //
    435   // Restore original legacy interrupt mask value
    436   //
    437   Private->Legacy8259->SetMask(Private->Legacy8259, &OldMask, NULL, NULL, NULL);
    438 
    439   if (Regs.X.AX != 0) {
    440     return EFI_DEVICE_ERROR;
    441   }
    442 
    443   //
    444   // start testtest
    445   //  GetTimerValue (&Ticker);
    446   //
    447   //  gRT->SetVariable (L"BackFromInitYourself",
    448   //                    &gEfiGlobalVariableGuid,
    449   //                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
    450   //                    sizeof (UINT64),
    451   //                    (VOID *)&Ticker
    452   //                    );
    453   // end testtest
    454   //
    455   // Copy E820 table after InitializeYourself is completed
    456   //
    457   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
    458   Regs.X.AX = Legacy16GetTableAddress;
    459   Regs.X.CX = (UINT16) E820Size;
    460   Regs.X.DX = 1;
    461   Private->LegacyBios.FarCall86 (
    462     &Private->LegacyBios,
    463     Table->Compatibility16CallSegment,
    464     Table->Compatibility16CallOffset,
    465     &Regs,
    466     NULL,
    467     0
    468     );
    469 
    470   Table->E820Pointer  = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
    471   Table->E820Length   = (UINT32) E820Size;
    472   if (Regs.X.AX != 0) {
    473     DEBUG ((EFI_D_ERROR, "Legacy16 E820 length insufficient\n"));
    474   } else {
    475     TempData = Table->E820Pointer;
    476     CopyMem ((VOID *) TempData, Private->E820Table, E820Size);
    477   }
    478   //
    479   // Get PnPInstallationCheck Info.
    480   //
    481   Private->PnPInstallationCheckSegment  = Table->PnPInstallationCheckSegment;
    482   Private->PnPInstallationCheckOffset   = Table->PnPInstallationCheckOffset;
    483 
    484   //
    485   // Check if PCI Express is supported. If yes, Save base address.
    486   //
    487   Status = Private->LegacyBiosPlatform->GetPlatformInfo (
    488                                           Private->LegacyBiosPlatform,
    489                                           EfiGetPlatformPciExpressBase,
    490                                           NULL,
    491                                           NULL,
    492                                           &Location,
    493                                           &Alignment,
    494                                           0,
    495                                           0
    496                                           );
    497   if (!EFI_ERROR (Status)) {
    498     Private->Legacy16Table->PciExpressBase  = (UINT32)Location;
    499     Location = 0;
    500   }
    501   //
    502   // Check if TPM is supported. If yes get a region in E0000,F0000 to copy it
    503   // into, copy it and update pointer to binary image. This needs to be
    504   // done prior to any OPROM for security purposes.
    505   //
    506   Status = Private->LegacyBiosPlatform->GetPlatformInfo (
    507                                           Private->LegacyBiosPlatform,
    508                                           EfiGetPlatformBinaryTpmBinary,
    509                                           &TpmBinaryImage,
    510                                           &TpmBinaryImageSize,
    511                                           &Location,
    512                                           &Alignment,
    513                                           0,
    514                                           0
    515                                           );
    516   if (!EFI_ERROR (Status)) {
    517 
    518     ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
    519     Regs.X.AX = Legacy16GetTableAddress;
    520     Regs.X.CX = (UINT16) TpmBinaryImageSize;
    521     Regs.X.DX = 1;
    522     Private->LegacyBios.FarCall86 (
    523       &Private->LegacyBios,
    524       Table->Compatibility16CallSegment,
    525       Table->Compatibility16CallOffset,
    526       &Regs,
    527       NULL,
    528       0
    529       );
    530 
    531     TpmPointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
    532     if (Regs.X.AX != 0) {
    533       DEBUG ((EFI_D_ERROR, "TPM cannot be loaded\n"));
    534     } else {
    535       CopyMem ((VOID *) (UINTN)TpmPointer, TpmBinaryImage, TpmBinaryImageSize);
    536       Table->TpmSegment = Regs.X.DS;
    537       Table->TpmOffset  = Regs.X.BX;
    538 
    539     }
    540   }
    541   //
    542   // Lock the Legacy BIOS region
    543   //
    544   Private->Cpu->FlushDataCache (Private->Cpu, Private->BiosStart, (UINT32) LegacyBiosImageSize, EfiCpuFlushTypeWriteBackInvalidate);
    545   Private->LegacyRegion->Lock (Private->LegacyRegion, Private->BiosStart, (UINT32) LegacyBiosImageSize, &Granularity);
    546 
    547   //
    548   // Get the BbsTable from LOW_MEMORY_THUNK
    549   //
    550   BbsTable = (BBS_TABLE *)(UINTN)Private->IntThunk->BbsTable;
    551   ZeroMem ((VOID *)BbsTable, sizeof (Private->IntThunk->BbsTable));
    552 
    553   EfiToLegacy16BootTable->BbsTable  = (UINT32)(UINTN)BbsTable;
    554   Private->BbsTablePtr              = (VOID *) BbsTable;
    555   //
    556   // Skip Floppy and possible onboard IDE drives
    557   //
    558   EfiToLegacy16BootTable->NumberBbsEntries = 1 + 2 * MAX_IDE_CONTROLLER;
    559 
    560   for (Index = 0; Index < (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE)); Index++) {
    561     BbsTable[Index].BootPriority = BBS_IGNORE_ENTRY;
    562   }
    563   //
    564   // Allocate space for Legacy HDD table
    565   //
    566   LegacyEfiHddTable = (LEGACY_EFI_HDD_TABLE *) AllocateZeroPool ((UINTN) MAX_HDD_ENTRIES * sizeof (LEGACY_EFI_HDD_TABLE));
    567   ASSERT (LegacyEfiHddTable);
    568 
    569   Private->LegacyEfiHddTable      = LegacyEfiHddTable;
    570   Private->LegacyEfiHddTableIndex = 0x00;
    571 
    572   //
    573   // start testtest
    574   //  GetTimerValue (&Ticker);
    575   //
    576   //  gRT->SetVariable (L"EndOfLoadFv",
    577   //                    &gEfiGlobalVariableGuid,
    578   //                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
    579   //                    sizeof (UINT64),
    580   //                    (VOID *)&Ticker
    581   //                    );
    582   // end testtest
    583   //
    584   return EFI_SUCCESS;
    585 }
    586 
    587 /**
    588   Shadow all legacy16 OPROMs that haven't been shadowed.
    589   Warning: Use this with caution. This routine disconnects all EFI
    590   drivers. If used externally then caller must re-connect EFI
    591   drivers.
    592 
    593   @param  This                    Protocol instance pointer.
    594 
    595   @retval EFI_SUCCESS             OPROMs shadowed
    596 
    597 **/
    598 EFI_STATUS
    599 EFIAPI
    600 LegacyBiosShadowAllLegacyOproms (
    601   IN EFI_LEGACY_BIOS_PROTOCOL *This
    602   )
    603 {
    604   LEGACY_BIOS_INSTANCE  *Private;
    605 
    606   //
    607   //  EFI_LEGACY_BIOS_PLATFORM_PROTOCOL    *LegacyBiosPlatform;
    608   //  EFI_LEGACY16_TABLE                   *Legacy16Table;
    609   //
    610   Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
    611 
    612   //
    613   //  LegacyBiosPlatform       = Private->LegacyBiosPlatform;
    614   //  Legacy16Table            = Private->Legacy16Table;
    615   //
    616   // Shadow PCI ROMs. We must do this near the end since this will kick
    617   // of Native EFI drivers that may be needed to collect info for Legacy16
    618   //
    619   //  WARNING: PciIo is gone after this call.
    620   //
    621   PciProgramAllInterruptLineRegisters (Private);
    622 
    623   PciShadowRoms (Private);
    624 
    625   //
    626   // Shadow PXE base code, BIS etc.
    627   //
    628   //  LegacyBiosPlatform->ShadowServiceRoms (LegacyBiosPlatform,
    629   //                       &Private->OptionRom,
    630   //                       Legacy16Table);
    631   //
    632   return EFI_SUCCESS;
    633 }
    634 
    635 /**
    636   Get the PCI BIOS interface version.
    637 
    638   @param  Private  Driver private data.
    639 
    640   @return The PCI interface version number in Binary Coded Decimal (BCD) format.
    641           E.g.: 0x0210 indicates 2.10, 0x0300 indicates 3.00
    642 
    643 **/
    644 UINT16
    645 GetPciInterfaceVersion (
    646   IN LEGACY_BIOS_INSTANCE *Private
    647   )
    648 {
    649   EFI_IA32_REGISTER_SET Reg;
    650   BOOLEAN               ThunkFailed;
    651   UINT16                PciInterfaceVersion;
    652 
    653   PciInterfaceVersion = 0;
    654 
    655   Reg.X.AX = 0xB101;
    656   Reg.E.EDI = 0;
    657 
    658   ThunkFailed = Private->LegacyBios.Int86 (&Private->LegacyBios, 0x1A, &Reg);
    659   if (!ThunkFailed) {
    660     //
    661     // From PCI Firmware 3.0 Specification:
    662     //   If the CARRY FLAG [CF] is cleared and AH is set to 00h, it is still necessary to examine the
    663     //   contents of [EDX] for the presence of the string "PCI" + (trailing space) to fully validate the
    664     //   presence of the PCI function set. [BX] will further indicate the version level, with enough
    665     //   granularity to allow for incremental changes in the code that don't affect the function interface.
    666     //   Version numbers are stored as Binary Coded Decimal (BCD) values. For example, Version 2.10
    667     //   would be returned as a 02h in the [BH] registers and 10h in the [BL] registers.
    668     //
    669     if ((Reg.X.Flags.CF == 0) && (Reg.H.AH == 0) && (Reg.E.EDX == SIGNATURE_32 ('P', 'C', 'I', ' '))) {
    670       PciInterfaceVersion = Reg.X.BX;
    671     }
    672   }
    673   return PciInterfaceVersion;
    674 }
    675 
    676 /**
    677   Callback function to calculate SMBIOS table size, and allocate memory for SMBIOS table.
    678   SMBIOS table will be copied into EfiReservedMemoryType memory in legacy boot path.
    679 
    680   @param  Event                 Event whose notification function is being invoked.
    681   @param  Context               The pointer to the notification function's context,
    682                                 which is implementation-dependent.
    683 
    684 **/
    685 VOID
    686 EFIAPI
    687 InstallSmbiosEventCallback (
    688   IN EFI_EVENT                Event,
    689   IN VOID                     *Context
    690   )
    691 {
    692   EFI_STATUS                  Status;
    693   SMBIOS_TABLE_ENTRY_POINT    *EntryPointStructure;
    694 
    695   //
    696   // Get SMBIOS table from EFI configuration table
    697   //
    698   Status = EfiGetSystemConfigurationTable (
    699             &gEfiSmbiosTableGuid,
    700             &mRuntimeSmbiosEntryPoint
    701             );
    702   if ((EFI_ERROR (Status)) || (mRuntimeSmbiosEntryPoint == NULL)) {
    703     return;
    704   }
    705 
    706   EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *) mRuntimeSmbiosEntryPoint;
    707 
    708   //
    709   // Allocate memory for SMBIOS Entry Point Structure.
    710   // CSM framework spec requires SMBIOS table below 4GB in EFI_TO_COMPATIBILITY16_BOOT_TABLE.
    711   //
    712   if (mReserveSmbiosEntryPoint == 0) {
    713     //
    714     // Entrypoint structure with fixed size is allocated only once.
    715     //
    716     mReserveSmbiosEntryPoint = SIZE_4GB - 1;
    717     Status = gBS->AllocatePages (
    718                     AllocateMaxAddress,
    719                     EfiReservedMemoryType,
    720                     EFI_SIZE_TO_PAGES ((UINTN) (EntryPointStructure->EntryPointLength)),
    721                     &mReserveSmbiosEntryPoint
    722                     );
    723     if (EFI_ERROR (Status)) {
    724       mReserveSmbiosEntryPoint = 0;
    725       return;
    726     }
    727     DEBUG ((EFI_D_INFO, "Allocate memory for Smbios Entry Point Structure\n"));
    728   }
    729 
    730   if ((mStructureTableAddress != 0) &&
    731       (mStructureTablePages < (UINTN) EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength))) {
    732     //
    733     // If original buffer is not enough for the new SMBIOS table, free original buffer and re-allocate
    734     //
    735     gBS->FreePages (mStructureTableAddress, mStructureTablePages);
    736     mStructureTableAddress = 0;
    737     mStructureTablePages   = 0;
    738     DEBUG ((EFI_D_INFO, "Original size is not enough. Re-allocate the memory.\n"));
    739   }
    740 
    741   if (mStructureTableAddress == 0) {
    742     //
    743     // Allocate reserved memory below 4GB.
    744     // Smbios spec requires the structure table is below 4GB.
    745     //
    746     mStructureTableAddress = SIZE_4GB - 1;
    747     mStructureTablePages   = EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength);
    748     Status = gBS->AllocatePages (
    749                     AllocateMaxAddress,
    750                     EfiReservedMemoryType,
    751                     mStructureTablePages,
    752                     &mStructureTableAddress
    753                     );
    754     if (EFI_ERROR (Status)) {
    755       gBS->FreePages (
    756         mReserveSmbiosEntryPoint,
    757         EFI_SIZE_TO_PAGES ((UINTN) (EntryPointStructure->EntryPointLength))
    758         );
    759       mReserveSmbiosEntryPoint = 0;
    760       mStructureTableAddress   = 0;
    761       mStructureTablePages     = 0;
    762       return;
    763     }
    764     DEBUG ((EFI_D_INFO, "Allocate memory for Smbios Structure Table\n"));
    765   }
    766 }
    767 
    768 /**
    769   Install Driver to produce Legacy BIOS protocol.
    770 
    771   @param  ImageHandle  Handle of driver image.
    772   @param  SystemTable  Pointer to system table.
    773 
    774   @retval EFI_SUCCESS  Legacy BIOS protocol installed
    775   @retval No protocol installed, unload driver.
    776 
    777 **/
    778 EFI_STATUS
    779 EFIAPI
    780 LegacyBiosInstall (
    781   IN EFI_HANDLE           ImageHandle,
    782   IN EFI_SYSTEM_TABLE     *SystemTable
    783   )
    784 {
    785   EFI_STATUS                         Status;
    786   LEGACY_BIOS_INSTANCE               *Private;
    787   EFI_TO_COMPATIBILITY16_INIT_TABLE  *EfiToLegacy16InitTable;
    788   EFI_PHYSICAL_ADDRESS               MemoryAddress;
    789   EFI_PHYSICAL_ADDRESS               EbdaReservedBaseAddress;
    790   VOID                               *MemoryPtr;
    791   EFI_PHYSICAL_ADDRESS               MemoryAddressUnder1MB;
    792   UINTN                              Index;
    793   UINT32                             *BaseVectorMaster;
    794   EFI_PHYSICAL_ADDRESS               StartAddress;
    795   UINT32                             *ClearPtr;
    796   EFI_PHYSICAL_ADDRESS               MemStart;
    797   UINT32                             IntRedirCode;
    798   UINT32                             Granularity;
    799   BOOLEAN                            DecodeOn;
    800   UINT32                             MemorySize;
    801   EFI_GCD_MEMORY_SPACE_DESCRIPTOR    Descriptor;
    802   UINT64                             Length;
    803   UINT8                              *SecureBoot;
    804   EFI_EVENT                          InstallSmbiosEvent;
    805 
    806   //
    807   // Load this driver's image to memory
    808   //
    809   Status = RelocateImageUnder4GIfNeeded (ImageHandle, SystemTable);
    810   if (EFI_ERROR (Status)) {
    811     return Status;
    812   }
    813 
    814   //
    815   // When UEFI Secure Boot is enabled, CSM module will not start any more.
    816   //
    817   SecureBoot = NULL;
    818   GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBoot, NULL);
    819   if ((SecureBoot != NULL) && (*SecureBoot == SECURE_BOOT_MODE_ENABLE)) {
    820     FreePool (SecureBoot);
    821     return EFI_SECURITY_VIOLATION;
    822   }
    823 
    824   if (SecureBoot != NULL) {
    825     FreePool (SecureBoot);
    826   }
    827 
    828   Private = &mPrivateData;
    829   ZeroMem (Private, sizeof (LEGACY_BIOS_INSTANCE));
    830 
    831   //
    832   // Grab a copy of all the protocols we depend on. Any error would
    833   // be a dispatcher bug!.
    834   //
    835   Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &Private->Cpu);
    836   ASSERT_EFI_ERROR (Status);
    837 
    838   Status = gBS->LocateProtocol (&gEfiTimerArchProtocolGuid, NULL, (VOID **) &Private->Timer);
    839   ASSERT_EFI_ERROR (Status);
    840 
    841   Status = gBS->LocateProtocol (&gEfiLegacyRegion2ProtocolGuid, NULL, (VOID **) &Private->LegacyRegion);
    842   ASSERT_EFI_ERROR (Status);
    843 
    844   Status = gBS->LocateProtocol (&gEfiLegacyBiosPlatformProtocolGuid, NULL, (VOID **) &Private->LegacyBiosPlatform);
    845   ASSERT_EFI_ERROR (Status);
    846 
    847   Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **) &Private->Legacy8259);
    848   ASSERT_EFI_ERROR (Status);
    849 
    850   Status = gBS->LocateProtocol (&gEfiLegacyInterruptProtocolGuid, NULL, (VOID **) &Private->LegacyInterrupt);
    851   ASSERT_EFI_ERROR (Status);
    852 
    853   //
    854   // Locate Memory Test Protocol if exists
    855   //
    856   Status = gBS->LocateProtocol (
    857                   &gEfiGenericMemTestProtocolGuid,
    858                   NULL,
    859                   (VOID **) &Private->GenericMemoryTest
    860                   );
    861   ASSERT_EFI_ERROR (Status);
    862 
    863   //
    864   // Make sure all memory from 0-640K is tested
    865   //
    866   for (StartAddress = 0; StartAddress < 0xa0000; ) {
    867     gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor);
    868     if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) {
    869       StartAddress = Descriptor.BaseAddress + Descriptor.Length;
    870       continue;
    871     }
    872     Length = MIN (Descriptor.Length, 0xa0000 - StartAddress);
    873     Private->GenericMemoryTest->CompatibleRangeTest (
    874                                   Private->GenericMemoryTest,
    875                                   StartAddress,
    876                                   Length
    877                                   );
    878     StartAddress = StartAddress + Length;
    879   }
    880   //
    881   // Make sure all memory from 1MB to 16MB is tested and added to memory map
    882   //
    883   for (StartAddress = BASE_1MB; StartAddress < BASE_16MB; ) {
    884     gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor);
    885     if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) {
    886       StartAddress = Descriptor.BaseAddress + Descriptor.Length;
    887       continue;
    888     }
    889     Length = MIN (Descriptor.Length, BASE_16MB - StartAddress);
    890     Private->GenericMemoryTest->CompatibleRangeTest (
    891                                   Private->GenericMemoryTest,
    892                                   StartAddress,
    893                                   Length
    894                                   );
    895     StartAddress = StartAddress + Length;
    896   }
    897 
    898   Private->Signature = LEGACY_BIOS_INSTANCE_SIGNATURE;
    899 
    900   Private->LegacyBios.Int86 = LegacyBiosInt86;
    901   Private->LegacyBios.FarCall86 = LegacyBiosFarCall86;
    902   Private->LegacyBios.CheckPciRom = LegacyBiosCheckPciRom;
    903   Private->LegacyBios.InstallPciRom = LegacyBiosInstallPciRom;
    904   Private->LegacyBios.LegacyBoot = LegacyBiosLegacyBoot;
    905   Private->LegacyBios.UpdateKeyboardLedStatus = LegacyBiosUpdateKeyboardLedStatus;
    906   Private->LegacyBios.GetBbsInfo = LegacyBiosGetBbsInfo;
    907   Private->LegacyBios.ShadowAllLegacyOproms = LegacyBiosShadowAllLegacyOproms;
    908   Private->LegacyBios.PrepareToBootEfi = LegacyBiosPrepareToBootEfi;
    909   Private->LegacyBios.GetLegacyRegion = LegacyBiosGetLegacyRegion;
    910   Private->LegacyBios.CopyLegacyRegion = LegacyBiosCopyLegacyRegion;
    911   Private->LegacyBios.BootUnconventionalDevice = LegacyBiosBootUnconventionalDevice;
    912 
    913   Private->ImageHandle = ImageHandle;
    914 
    915   //
    916   // Enable read attribute of legacy region.
    917   //
    918   DecodeOn = TRUE;
    919   Private->LegacyRegion->Decode (
    920                            Private->LegacyRegion,
    921                            0xc0000,
    922                            0x40000,
    923                            &Granularity,
    924                            &DecodeOn
    925                            );
    926   //
    927   // Set Cachebility for legacy region
    928   // BUGBUG: Comments about this legacy region cacheability setting
    929   //         This setting will make D865GCHProduction CSM Unhappy
    930   //
    931   if (PcdGetBool (PcdLegacyBiosCacheLegacyRegion)) {
    932     gDS->SetMemorySpaceAttributes (
    933            0x0,
    934            0xA0000,
    935            EFI_MEMORY_WB
    936            );
    937     gDS->SetMemorySpaceAttributes (
    938            0xc0000,
    939            0x40000,
    940            EFI_MEMORY_WB
    941            );
    942   }
    943 
    944   gDS->SetMemorySpaceAttributes (
    945          0xA0000,
    946          0x20000,
    947          EFI_MEMORY_UC
    948          );
    949 
    950   //
    951   // Allocate 0 - 4K for real mode interupt vectors and BDA.
    952   //
    953   AllocateLegacyMemory (
    954     AllocateAddress,
    955     0,
    956     1,
    957     &MemoryAddress
    958     );
    959   ASSERT (MemoryAddress == 0x000000000);
    960 
    961   ClearPtr = (VOID *) ((UINTN) 0x0000);
    962 
    963   //
    964   // Initialize region from 0x0000 to 4k. This initializes interrupt vector
    965   // range.
    966   //
    967   gBS->SetMem ((VOID *) ClearPtr, 0x400, INITIAL_VALUE_BELOW_1K);
    968   ZeroMem ((VOID *) ((UINTN)ClearPtr + 0x400), 0xC00);
    969 
    970   //
    971   // Allocate pages for OPROM usage
    972   //
    973   MemorySize = PcdGet32 (PcdEbdaReservedMemorySize);
    974   ASSERT ((MemorySize & 0xFFF) == 0);
    975 
    976   Status = AllocateLegacyMemory (
    977              AllocateAddress,
    978              CONVENTIONAL_MEMORY_TOP - MemorySize,
    979              EFI_SIZE_TO_PAGES (MemorySize),
    980              &MemoryAddress
    981              );
    982   ASSERT_EFI_ERROR (Status);
    983 
    984   ZeroMem ((VOID *) ((UINTN) MemoryAddress), MemorySize);
    985 
    986   //
    987   // Allocate all 32k chunks from 0x60000 ~ 0x88000 for Legacy OPROMs that
    988   // don't use PMM but look for zeroed memory. Note that various non-BBS
    989   // OpROMs expect different areas to be free
    990   //
    991   EbdaReservedBaseAddress = MemoryAddress;
    992   MemoryAddress = PcdGet32 (PcdOpromReservedMemoryBase);
    993   MemorySize    = PcdGet32 (PcdOpromReservedMemorySize);
    994   //
    995   // Check if base address and size for reserved memory are 4KB aligned.
    996   //
    997   ASSERT ((MemoryAddress & 0xFFF) == 0);
    998   ASSERT ((MemorySize & 0xFFF) == 0);
    999   //
   1000   // Check if the reserved memory is below EBDA reserved range.
   1001   //
   1002   ASSERT ((MemoryAddress < EbdaReservedBaseAddress) && ((MemoryAddress + MemorySize - 1) < EbdaReservedBaseAddress));
   1003   for (MemStart = MemoryAddress; MemStart < MemoryAddress + MemorySize; MemStart += 0x1000) {
   1004     Status = AllocateLegacyMemory (
   1005                AllocateAddress,
   1006                MemStart,
   1007                1,
   1008                &StartAddress
   1009                );
   1010     if (!EFI_ERROR (Status)) {
   1011       MemoryPtr = (VOID *) ((UINTN) StartAddress);
   1012       ZeroMem (MemoryPtr, 0x1000);
   1013     } else {
   1014       DEBUG ((EFI_D_ERROR, "WARNING: Allocate legacy memory fail for SCSI card - %x\n", MemStart));
   1015     }
   1016   }
   1017 
   1018   //
   1019   // Allocate low PMM memory and zero it out
   1020   //
   1021   MemorySize = PcdGet32 (PcdLowPmmMemorySize);
   1022   ASSERT ((MemorySize & 0xFFF) == 0);
   1023   Status = AllocateLegacyMemory (
   1024              AllocateMaxAddress,
   1025              CONVENTIONAL_MEMORY_TOP,
   1026              EFI_SIZE_TO_PAGES (MemorySize),
   1027              &MemoryAddressUnder1MB
   1028              );
   1029   ASSERT_EFI_ERROR (Status);
   1030 
   1031   ZeroMem ((VOID *) ((UINTN) MemoryAddressUnder1MB), MemorySize);
   1032 
   1033   //
   1034   // Allocate space for thunker and Init Thunker
   1035   //
   1036   Status = AllocateLegacyMemory (
   1037              AllocateMaxAddress,
   1038              CONVENTIONAL_MEMORY_TOP,
   1039              (sizeof (LOW_MEMORY_THUNK) / EFI_PAGE_SIZE) + 2,
   1040              &MemoryAddress
   1041              );
   1042   ASSERT_EFI_ERROR (Status);
   1043   Private->IntThunk                   = (LOW_MEMORY_THUNK *) (UINTN) MemoryAddress;
   1044   EfiToLegacy16InitTable                   = &Private->IntThunk->EfiToLegacy16InitTable;
   1045   EfiToLegacy16InitTable->ThunkStart       = (UINT32) (EFI_PHYSICAL_ADDRESS) (UINTN) MemoryAddress;
   1046   EfiToLegacy16InitTable->ThunkSizeInBytes = (UINT32) (sizeof (LOW_MEMORY_THUNK));
   1047 
   1048   Status = LegacyBiosInitializeThunk (Private);
   1049   ASSERT_EFI_ERROR (Status);
   1050 
   1051   //
   1052   // Init the legacy memory map in memory < 1 MB.
   1053   //
   1054   EfiToLegacy16InitTable->BiosLessThan1MB         = (UINT32) MemoryAddressUnder1MB;
   1055   EfiToLegacy16InitTable->LowPmmMemory            = (UINT32) MemoryAddressUnder1MB;
   1056   EfiToLegacy16InitTable->LowPmmMemorySizeInBytes = MemorySize;
   1057 
   1058   MemorySize = PcdGet32 (PcdHighPmmMemorySize);
   1059   ASSERT ((MemorySize & 0xFFF) == 0);
   1060   //
   1061   // Allocate high PMM Memory under 16 MB
   1062   //
   1063   Status = AllocateLegacyMemory (
   1064              AllocateMaxAddress,
   1065              0x1000000,
   1066              EFI_SIZE_TO_PAGES (MemorySize),
   1067              &MemoryAddress
   1068              );
   1069   if (EFI_ERROR (Status)) {
   1070     //
   1071     // If it fails, allocate high PMM Memory under 4GB
   1072     //
   1073     Status = AllocateLegacyMemory (
   1074                AllocateMaxAddress,
   1075                0xFFFFFFFF,
   1076                EFI_SIZE_TO_PAGES (MemorySize),
   1077                &MemoryAddress
   1078                );
   1079   }
   1080   if (!EFI_ERROR (Status)) {
   1081     EfiToLegacy16InitTable->HiPmmMemory            = (UINT32) (EFI_PHYSICAL_ADDRESS) (UINTN) MemoryAddress;
   1082     EfiToLegacy16InitTable->HiPmmMemorySizeInBytes = MemorySize;
   1083   }
   1084 
   1085   //
   1086   //  ShutdownAPs();
   1087   //
   1088   // Start the Legacy BIOS;
   1089   //
   1090   Status = ShadowAndStartLegacy16 (Private);
   1091   if (EFI_ERROR (Status)) {
   1092     return Status;
   1093   }
   1094   //
   1095   // Initialize interrupt redirection code and entries;
   1096   // IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f.
   1097   //
   1098   CopyMem (
   1099          Private->IntThunk->InterruptRedirectionCode,
   1100          (VOID *) (UINTN) InterruptRedirectionTemplate,
   1101          sizeof (Private->IntThunk->InterruptRedirectionCode)
   1102          );
   1103 
   1104   //
   1105   // Save Unexpected interrupt vector so can restore it just prior to boot
   1106   //
   1107   BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
   1108   Private->BiosUnexpectedInt = BaseVectorMaster[0];
   1109   IntRedirCode = (UINT32) (UINTN) Private->IntThunk->InterruptRedirectionCode;
   1110   for (Index = 0; Index < 8; Index++) {
   1111     BaseVectorMaster[Index] = (EFI_SEGMENT (IntRedirCode + Index * 4) << 16) | EFI_OFFSET (IntRedirCode + Index * 4);
   1112   }
   1113   //
   1114   // Save EFI value
   1115   //
   1116   Private->ThunkSeg = (UINT16) (EFI_SEGMENT (IntRedirCode));
   1117 
   1118   //
   1119   // Allocate reserved memory for SMBIOS table used in legacy boot if SMBIOS table exists
   1120   //
   1121   InstallSmbiosEventCallback (NULL, NULL);
   1122 
   1123   //
   1124   // Create callback function to update the size of reserved memory after LegacyBiosDxe starts
   1125   //
   1126   Status = gBS->CreateEventEx (
   1127                   EVT_NOTIFY_SIGNAL,
   1128                   TPL_NOTIFY,
   1129                   InstallSmbiosEventCallback,
   1130                   NULL,
   1131                   &gEfiSmbiosTableGuid,
   1132                   &InstallSmbiosEvent
   1133                   );
   1134   ASSERT_EFI_ERROR (Status);
   1135 
   1136   //
   1137   // Make a new handle and install the protocol
   1138   //
   1139   Private->Handle = NULL;
   1140   Status = gBS->InstallProtocolInterface (
   1141                   &Private->Handle,
   1142                   &gEfiLegacyBiosProtocolGuid,
   1143                   EFI_NATIVE_INTERFACE,
   1144                   &Private->LegacyBios
   1145                   );
   1146   Private->Csm16PciInterfaceVersion = GetPciInterfaceVersion (Private);
   1147 
   1148   DEBUG ((EFI_D_INFO, "CSM16 PCI BIOS Interface Version: %02x.%02x\n",
   1149           (UINT8) (Private->Csm16PciInterfaceVersion >> 8),
   1150           (UINT8) Private->Csm16PciInterfaceVersion
   1151         ));
   1152   ASSERT (Private->Csm16PciInterfaceVersion != 0);
   1153   return Status;
   1154 }
   1155