Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Elvin Li <elvin.li@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15789 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1155 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1155 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
| 
 | |
| Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
 | |
| 
 | |
| This program and the accompanying materials
 | |
| are licensed and made available under the terms and conditions
 | |
| of the BSD License which accompanies this distribution.  The
 | |
| full text of the license may be found at
 | |
| http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "LegacyBiosInterface.h"
 | |
| 
 | |
| #define PHYSICAL_ADDRESS_TO_POINTER(Address)  ((VOID *) ((UINTN) Address))
 | |
| 
 | |
| //
 | |
| // define maximum number of HDD system supports
 | |
| //
 | |
| #define MAX_HDD_ENTRIES 0x30
 | |
| 
 | |
| //
 | |
| // Module Global:
 | |
| //  Since this driver will only ever produce one instance of the Private Data
 | |
| //  protocol you are not required to dynamically allocate the PrivateData.
 | |
| //
 | |
| LEGACY_BIOS_INSTANCE  mPrivateData;
 | |
| 
 | |
| //
 | |
| // The SMBIOS table in EfiRuntimeServicesData memory
 | |
| //
 | |
| VOID                  *mRuntimeSmbiosEntryPoint = NULL;
 | |
| 
 | |
| //
 | |
| // The SMBIOS table in EfiReservedMemoryType memory
 | |
| //
 | |
| EFI_PHYSICAL_ADDRESS  mReserveSmbiosEntryPoint = 0;
 | |
| EFI_PHYSICAL_ADDRESS  mStructureTableAddress   = 0;
 | |
| UINTN                 mStructureTablePages     = 0;
 | |
| 
 | |
| /**
 | |
|   Do an AllocatePages () of type AllocateMaxAddress for EfiBootServicesCode
 | |
|   memory.
 | |
| 
 | |
|   @param  AllocateType               Allocated Legacy Memory Type
 | |
|   @param  StartPageAddress           Start address of range
 | |
|   @param  Pages                      Number of pages to allocate
 | |
|   @param  Result                     Result of allocation
 | |
| 
 | |
|   @retval EFI_SUCCESS                Legacy16 code loaded
 | |
|   @retval Other                      No protocol installed, unload driver.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| AllocateLegacyMemory (
 | |
|   IN  EFI_ALLOCATE_TYPE         AllocateType,
 | |
|   IN  EFI_PHYSICAL_ADDRESS      StartPageAddress,
 | |
|   IN  UINTN                     Pages,
 | |
|   OUT EFI_PHYSICAL_ADDRESS      *Result
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS            Status;
 | |
|   EFI_PHYSICAL_ADDRESS  MemPage;
 | |
| 
 | |
|   //
 | |
|   // Allocate Pages of memory less <= StartPageAddress
 | |
|   //
 | |
|   MemPage = (EFI_PHYSICAL_ADDRESS) (UINTN) StartPageAddress;
 | |
|   Status = gBS->AllocatePages (
 | |
|                   AllocateType,
 | |
|                   EfiBootServicesCode,
 | |
|                   Pages,
 | |
|                   &MemPage
 | |
|                   );
 | |
|   //
 | |
|   // Do not ASSERT on Status error but let caller decide since some cases
 | |
|   // memory is already taken but that is ok.
 | |
|   //
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     *Result = (EFI_PHYSICAL_ADDRESS) (UINTN) MemPage;
 | |
|   }
 | |
|   //
 | |
|   // If reach here the status = EFI_SUCCESS
 | |
|   //
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   This function is called when EFI needs to reserve an area in the 0xE0000 or 0xF0000
 | |
|   64 KB blocks.
 | |
| 
 | |
|   Note: inconsistency with the Framework CSM spec. Per the spec, this function may be
 | |
|   invoked only once. This limitation is relaxed to allow multiple calls in this implemenation.
 | |
| 
 | |
|   @param  This                       Protocol instance pointer.
 | |
|   @param  LegacyMemorySize           Size of required region
 | |
|   @param  Region                     Region to use. 00 = Either 0xE0000 or 0xF0000
 | |
|                                      block Bit0 = 1 0xF0000 block Bit1 = 1 0xE0000
 | |
|                                      block
 | |
|   @param  Alignment                  Address alignment. Bit mapped. First non-zero
 | |
|                                      bit from right is alignment.
 | |
|   @param  LegacyMemoryAddress        Region Assigned
 | |
| 
 | |
|   @retval EFI_SUCCESS                Region assigned
 | |
|   @retval EFI_ACCESS_DENIED          Procedure previously invoked
 | |
|   @retval Other                      Region not assigned
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| LegacyBiosGetLegacyRegion (
 | |
|   IN    EFI_LEGACY_BIOS_PROTOCOL *This,
 | |
|   IN    UINTN                    LegacyMemorySize,
 | |
|   IN    UINTN                    Region,
 | |
|   IN    UINTN                    Alignment,
 | |
|   OUT   VOID                     **LegacyMemoryAddress
 | |
|   )
 | |
| {
 | |
| 
 | |
|   LEGACY_BIOS_INSTANCE  *Private;
 | |
|   EFI_IA32_REGISTER_SET Regs;
 | |
|   EFI_STATUS            Status;
 | |
|   UINT32                Granularity;
 | |
| 
 | |
|   Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
 | |
|   Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);
 | |
| 
 | |
|   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
 | |
|   Regs.X.AX = Legacy16GetTableAddress;
 | |
|   Regs.X.BX = (UINT16) Region;
 | |
|   Regs.X.CX = (UINT16) LegacyMemorySize;
 | |
|   Regs.X.DX = (UINT16) Alignment;
 | |
|   Private->LegacyBios.FarCall86 (
 | |
|      &Private->LegacyBios,
 | |
|      Private->Legacy16CallSegment,
 | |
|      Private->Legacy16CallOffset,
 | |
|      &Regs,
 | |
|      NULL,
 | |
|      0
 | |
|      );
 | |
| 
 | |
|   if (Regs.X.AX == 0) {
 | |
|     *LegacyMemoryAddress  = (VOID *) (UINTN) ((Regs.X.DS << 4) + Regs.X.BX);
 | |
|     Status = EFI_SUCCESS;
 | |
|   } else {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
 | |
|   Private->LegacyRegion->Lock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   This function is called when copying data to the region assigned by
 | |
|   EFI_LEGACY_BIOS_PROTOCOL.GetLegacyRegion().
 | |
| 
 | |
|   @param  This                       Protocol instance pointer.
 | |
|   @param  LegacyMemorySize           Size of data to copy
 | |
|   @param  LegacyMemoryAddress        Legacy Region destination address Note: must
 | |
|                                      be in region assigned by
 | |
|                                      LegacyBiosGetLegacyRegion
 | |
|   @param  LegacyMemorySourceAddress  Source of data
 | |
| 
 | |
|   @retval EFI_SUCCESS                The data was copied successfully.
 | |
|   @retval EFI_ACCESS_DENIED          Either the starting or ending address is out of bounds.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| LegacyBiosCopyLegacyRegion (
 | |
|   IN EFI_LEGACY_BIOS_PROTOCOL *This,
 | |
|   IN    UINTN                 LegacyMemorySize,
 | |
|   IN    VOID                  *LegacyMemoryAddress,
 | |
|   IN    VOID                  *LegacyMemorySourceAddress
 | |
|   )
 | |
| {
 | |
| 
 | |
|   LEGACY_BIOS_INSTANCE  *Private;
 | |
|   UINT32                Granularity;
 | |
| 
 | |
|   if ((LegacyMemoryAddress < (VOID *)(UINTN)0xE0000 ) ||
 | |
|       ((UINTN) LegacyMemoryAddress + LegacyMemorySize > (UINTN) 0x100000)
 | |
|         ) {
 | |
|     return EFI_ACCESS_DENIED;
 | |
|   }
 | |
|   //
 | |
|   // There is no protection from writes over lapping if this function is
 | |
|   // called multiple times.
 | |
|   //
 | |
|   Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
 | |
|   Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);
 | |
|   CopyMem (LegacyMemoryAddress, LegacyMemorySourceAddress, LegacyMemorySize);
 | |
| 
 | |
|   Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
 | |
|   Private->LegacyRegion->Lock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Find Legacy16 BIOS image in the FLASH device and shadow it into memory. Find
 | |
|   the $EFI table in the shadow area. Thunk into the Legacy16 code after it had
 | |
|   been shadowed.
 | |
| 
 | |
|   @param  Private                    Legacy BIOS context data
 | |
| 
 | |
|   @retval EFI_SUCCESS                Legacy16 code loaded
 | |
|   @retval Other                      No protocol installed, unload driver.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ShadowAndStartLegacy16 (
 | |
|   IN  LEGACY_BIOS_INSTANCE  *Private
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                        Status;
 | |
|   UINT8                             *Ptr;
 | |
|   UINT8                             *PtrEnd;
 | |
|   BOOLEAN                           Done;
 | |
|   EFI_COMPATIBILITY16_TABLE         *Table;
 | |
|   UINT8                             CheckSum;
 | |
|   EFI_IA32_REGISTER_SET             Regs;
 | |
|   EFI_TO_COMPATIBILITY16_INIT_TABLE *EfiToLegacy16InitTable;
 | |
|   EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
 | |
|   VOID                              *LegacyBiosImage;
 | |
|   UINTN                             LegacyBiosImageSize;
 | |
|   UINTN                             E820Size;
 | |
|   UINT32                            *ClearPtr;
 | |
|   BBS_TABLE                         *BbsTable;
 | |
|   LEGACY_EFI_HDD_TABLE              *LegacyEfiHddTable;
 | |
|   UINTN                             Index;
 | |
|   UINT32                            TpmPointer;
 | |
|   VOID                              *TpmBinaryImage;
 | |
|   UINTN                             TpmBinaryImageSize;
 | |
|   UINTN                             Location;
 | |
|   UINTN                             Alignment;
 | |
|   UINTN                             TempData;
 | |
|   EFI_PHYSICAL_ADDRESS              Address;
 | |
|   UINT16                            OldMask;
 | |
|   UINT16                            NewMask;
 | |
|   UINT32                            Granularity;
 | |
|   EFI_GCD_MEMORY_SPACE_DESCRIPTOR   Descriptor;
 | |
| 
 | |
|   Location  = 0;
 | |
|   Alignment = 0;
 | |
| 
 | |
|   //
 | |
|   // we allocate the C/D/E/F segment as RT code so no one will use it any more.
 | |
|   //
 | |
|   Address = 0xC0000;
 | |
|   gDS->GetMemorySpaceDescriptor (Address, &Descriptor);
 | |
|   if (Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) {
 | |
|     //
 | |
|     // If it is already reserved, we should be safe, or else we allocate it.
 | |
|     //
 | |
|     Status = gBS->AllocatePages (
 | |
|                     AllocateAddress,
 | |
|                     EfiRuntimeServicesCode,
 | |
|                     0x40000/EFI_PAGE_SIZE,
 | |
|                     &Address
 | |
|                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // Bugbug: need to figure out whether C/D/E/F segment should be marked as reserved memory.
 | |
|       // 
 | |
|       DEBUG ((DEBUG_ERROR, "Failed to allocate the C/D/E/F segment Status = %r", Status));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // start testtest
 | |
|   //    GetTimerValue (&Ticker);
 | |
|   //
 | |
|   //  gRT->SetVariable (L"StartLegacy",
 | |
|   //                    &gEfiGlobalVariableGuid,
 | |
|   //                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
 | |
|   //                    sizeof (UINT64),
 | |
|   //                    (VOID *)&Ticker
 | |
|   //                    );
 | |
|   // end testtest
 | |
|   //
 | |
|   EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
 | |
|   Status = Private->LegacyBiosPlatform->GetPlatformInfo (
 | |
|                                           Private->LegacyBiosPlatform,
 | |
|                                           EfiGetPlatformBinarySystemRom,
 | |
|                                           &LegacyBiosImage,
 | |
|                                           &LegacyBiosImageSize,
 | |
|                                           &Location,
 | |
|                                           &Alignment,
 | |
|                                           0,
 | |
|                                           0
 | |
|                                           );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   Private->BiosStart            = (UINT32) (0x100000 - LegacyBiosImageSize);
 | |
|   Private->OptionRom            = 0xc0000;
 | |
|   Private->LegacyBiosImageSize  = (UINT32) LegacyBiosImageSize;
 | |
| 
 | |
|   //
 | |
|   // Can only shadow into memory allocated for legacy useage.
 | |
|   //
 | |
|   ASSERT (Private->BiosStart > Private->OptionRom);
 | |
| 
 | |
|   //
 | |
|   // Shadow Legacy BIOS. Turn on memory and copy image
 | |
|   //
 | |
|   Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xc0000, 0x40000, &Granularity);
 | |
| 
 | |
|   ClearPtr = (VOID *) ((UINTN) 0xc0000);
 | |
| 
 | |
|   //
 | |
|   // Initialize region from 0xc0000 to start of BIOS to all ffs. This allows unused
 | |
|   // regions to be used by EMM386 etc.
 | |
|   //
 | |
|   SetMem ((VOID *) ClearPtr, (UINTN) (0x40000 - LegacyBiosImageSize), 0xff);
 | |
| 
 | |
|   TempData = Private->BiosStart;
 | |
| 
 | |
|   CopyMem (
 | |
|     (VOID *) TempData,
 | |
|     LegacyBiosImage,
 | |
|     (UINTN) LegacyBiosImageSize
 | |
|     );
 | |
| 
 | |
|   Private->Cpu->FlushDataCache (Private->Cpu, 0xc0000, 0x40000, EfiCpuFlushTypeWriteBackInvalidate);
 | |
| 
 | |
|   //
 | |
|   // Search for Legacy16 table in Shadowed ROM
 | |
|   //
 | |
|   Done  = FALSE;
 | |
|   Table = NULL;
 | |
|   for (Ptr = (UINT8 *) TempData; Ptr < (UINT8 *) ((UINTN) 0x100000) && !Done; Ptr += 0x10) {
 | |
|     if (*(UINT32 *) Ptr == SIGNATURE_32 ('I', 'F', 'E', '$')) {
 | |
|       Table   = (EFI_COMPATIBILITY16_TABLE *) Ptr;
 | |
|       PtrEnd  = Ptr + Table->TableLength;
 | |
|       for (CheckSum = 0; Ptr < PtrEnd; Ptr++) {
 | |
|         CheckSum = (UINT8) (CheckSum +*Ptr);
 | |
|       }
 | |
| 
 | |
|       Done = TRUE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (Table == NULL) {
 | |
|     DEBUG ((EFI_D_ERROR, "No Legacy16 table found\n"));
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   if (!Done) {
 | |
|     //
 | |
|     // Legacy16 table header checksum error.
 | |
|     //
 | |
|     DEBUG ((EFI_D_ERROR, "Legacy16 table found with bad talbe header checksum\n"));
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Remember location of the Legacy16 table
 | |
|   //
 | |
|   Private->Legacy16Table            = Table;
 | |
|   Private->Legacy16CallSegment      = Table->Compatibility16CallSegment;
 | |
|   Private->Legacy16CallOffset       = Table->Compatibility16CallOffset;
 | |
|   EfiToLegacy16InitTable            = &Private->IntThunk->EfiToLegacy16InitTable;
 | |
|   Private->Legacy16InitPtr          = EfiToLegacy16InitTable;
 | |
|   Private->Legacy16BootPtr          = &Private->IntThunk->EfiToLegacy16BootTable;
 | |
|   Private->InternalIrqRoutingTable  = NULL;
 | |
|   Private->NumberIrqRoutingEntries  = 0;
 | |
|   Private->BbsTablePtr              = NULL;
 | |
|   Private->LegacyEfiHddTable        = NULL;
 | |
|   Private->DiskEnd                  = 0;
 | |
|   Private->Disk4075                 = 0;
 | |
|   Private->HddTablePtr              = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo;
 | |
|   Private->NumberHddControllers     = MAX_IDE_CONTROLLER;
 | |
|   Private->Dump[0]                  = 'D';
 | |
|   Private->Dump[1]                  = 'U';
 | |
|   Private->Dump[2]                  = 'M';
 | |
|   Private->Dump[3]                  = 'P';
 | |
| 
 | |
|   ZeroMem (
 | |
|     Private->Legacy16BootPtr,
 | |
|     sizeof (EFI_TO_COMPATIBILITY16_BOOT_TABLE)
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // Store away a copy of the EFI System Table
 | |
|   //
 | |
|   Table->EfiSystemTable = (UINT32) (UINTN) gST;
 | |
| 
 | |
|   //
 | |
|   // IPF CSM integration -Bug
 | |
|   //
 | |
|   // Construct the Legacy16 boot memory map. This sets up number of
 | |
|   // E820 entries.
 | |
|   //
 | |
|   LegacyBiosBuildE820 (Private, &E820Size);
 | |
|   //
 | |
|   // Initialize BDA and EBDA standard values needed to load Legacy16 code
 | |
|   //
 | |
|   LegacyBiosInitBda (Private);
 | |
|   LegacyBiosInitCmos (Private);
 | |
| 
 | |
|   //
 | |
|   // All legacy interrupt should be masked when do initialization work from legacy 16 code.
 | |
|   //
 | |
|   Private->Legacy8259->GetMask(Private->Legacy8259, &OldMask, NULL, NULL, NULL);
 | |
|   NewMask = 0xFFFF;
 | |
|   Private->Legacy8259->SetMask(Private->Legacy8259, &NewMask, NULL, NULL, NULL);
 | |
|   
 | |
|   //
 | |
|   // Call into Legacy16 code to do an INIT
 | |
|   //
 | |
|   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
 | |
|   Regs.X.AX = Legacy16InitializeYourself;
 | |
|   Regs.X.ES = EFI_SEGMENT (*((UINT32 *) &EfiToLegacy16InitTable));
 | |
|   Regs.X.BX = EFI_OFFSET (*((UINT32 *) &EfiToLegacy16InitTable));
 | |
| 
 | |
|   Private->LegacyBios.FarCall86 (
 | |
|     &Private->LegacyBios,
 | |
|     Table->Compatibility16CallSegment,
 | |
|     Table->Compatibility16CallOffset,
 | |
|     &Regs,
 | |
|     NULL,
 | |
|     0
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // Restore original legacy interrupt mask value
 | |
|   //
 | |
|   Private->Legacy8259->SetMask(Private->Legacy8259, &OldMask, NULL, NULL, NULL);
 | |
|   
 | |
|   if (Regs.X.AX != 0) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // start testtest
 | |
|   //  GetTimerValue (&Ticker);
 | |
|   //
 | |
|   //  gRT->SetVariable (L"BackFromInitYourself",
 | |
|   //                    &gEfiGlobalVariableGuid,
 | |
|   //                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
 | |
|   //                    sizeof (UINT64),
 | |
|   //                    (VOID *)&Ticker
 | |
|   //                    );
 | |
|   // end testtest
 | |
|   //
 | |
|   // Copy E820 table after InitializeYourself is completed
 | |
|   //
 | |
|   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
 | |
|   Regs.X.AX = Legacy16GetTableAddress;
 | |
|   Regs.X.CX = (UINT16) E820Size;
 | |
|   Regs.X.DX = 1;
 | |
|   Private->LegacyBios.FarCall86 (
 | |
|     &Private->LegacyBios,
 | |
|     Table->Compatibility16CallSegment,
 | |
|     Table->Compatibility16CallOffset,
 | |
|     &Regs,
 | |
|     NULL,
 | |
|     0
 | |
|     );
 | |
| 
 | |
|   Table->E820Pointer  = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
 | |
|   Table->E820Length   = (UINT32) E820Size;
 | |
|   if (Regs.X.AX != 0) {
 | |
|     DEBUG ((EFI_D_ERROR, "Legacy16 E820 length insufficient\n"));
 | |
|   } else {
 | |
|     TempData = Table->E820Pointer;
 | |
|     CopyMem ((VOID *) TempData, Private->E820Table, E820Size);
 | |
|   }
 | |
|   //
 | |
|   // Get PnPInstallationCheck Info.
 | |
|   //
 | |
|   Private->PnPInstallationCheckSegment  = Table->PnPInstallationCheckSegment;
 | |
|   Private->PnPInstallationCheckOffset   = Table->PnPInstallationCheckOffset;
 | |
| 
 | |
|   //
 | |
|   // Check if PCI Express is supported. If yes, Save base address.
 | |
|   //
 | |
|   Status = Private->LegacyBiosPlatform->GetPlatformInfo (
 | |
|                                           Private->LegacyBiosPlatform,
 | |
|                                           EfiGetPlatformPciExpressBase,
 | |
|                                           NULL,
 | |
|                                           NULL,
 | |
|                                           &Location,
 | |
|                                           &Alignment,
 | |
|                                           0,
 | |
|                                           0
 | |
|                                           );
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     Private->Legacy16Table->PciExpressBase  = (UINT32)Location;
 | |
|     Location = 0;
 | |
|   }
 | |
|   //
 | |
|   // Check if TPM is supported. If yes get a region in E0000,F0000 to copy it
 | |
|   // into, copy it and update pointer to binary image. This needs to be
 | |
|   // done prior to any OPROM for security purposes.
 | |
|   //
 | |
|   Status = Private->LegacyBiosPlatform->GetPlatformInfo (
 | |
|                                           Private->LegacyBiosPlatform,
 | |
|                                           EfiGetPlatformBinaryTpmBinary,
 | |
|                                           &TpmBinaryImage,
 | |
|                                           &TpmBinaryImageSize,
 | |
|                                           &Location,
 | |
|                                           &Alignment,
 | |
|                                           0,
 | |
|                                           0
 | |
|                                           );
 | |
|   if (!EFI_ERROR (Status)) {
 | |
| 
 | |
|     ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
 | |
|     Regs.X.AX = Legacy16GetTableAddress;
 | |
|     Regs.X.CX = (UINT16) TpmBinaryImageSize;
 | |
|     Regs.X.DX = 1;
 | |
|     Private->LegacyBios.FarCall86 (
 | |
|       &Private->LegacyBios,
 | |
|       Table->Compatibility16CallSegment,
 | |
|       Table->Compatibility16CallOffset,
 | |
|       &Regs,
 | |
|       NULL,
 | |
|       0
 | |
|       );
 | |
| 
 | |
|     TpmPointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
 | |
|     if (Regs.X.AX != 0) {
 | |
|       DEBUG ((EFI_D_ERROR, "TPM cannot be loaded\n"));
 | |
|     } else {
 | |
|       CopyMem ((VOID *) (UINTN)TpmPointer, TpmBinaryImage, TpmBinaryImageSize);
 | |
|       Table->TpmSegment = Regs.X.DS;
 | |
|       Table->TpmOffset  = Regs.X.BX;
 | |
| 
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // Lock the Legacy BIOS region
 | |
|   //
 | |
|   Private->Cpu->FlushDataCache (Private->Cpu, Private->BiosStart, (UINT32) LegacyBiosImageSize, EfiCpuFlushTypeWriteBackInvalidate);
 | |
|   Private->LegacyRegion->Lock (Private->LegacyRegion, Private->BiosStart, (UINT32) LegacyBiosImageSize, &Granularity);
 | |
| 
 | |
|   //
 | |
|   // Get the BbsTable from LOW_MEMORY_THUNK
 | |
|   //
 | |
|   BbsTable = (BBS_TABLE *)(UINTN)Private->IntThunk->BbsTable;
 | |
|   ZeroMem ((VOID *)BbsTable, sizeof (Private->IntThunk->BbsTable));
 | |
| 
 | |
|   EfiToLegacy16BootTable->BbsTable  = (UINT32)(UINTN)BbsTable;
 | |
|   Private->BbsTablePtr              = (VOID *) BbsTable;
 | |
|   //
 | |
|   // Skip Floppy and possible onboard IDE drives
 | |
|   //
 | |
|   EfiToLegacy16BootTable->NumberBbsEntries = 1 + 2 * MAX_IDE_CONTROLLER;
 | |
| 
 | |
|   for (Index = 0; Index < (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE)); Index++) {
 | |
|     BbsTable[Index].BootPriority = BBS_IGNORE_ENTRY;
 | |
|   }
 | |
|   //
 | |
|   // Allocate space for Legacy HDD table
 | |
|   //
 | |
|   LegacyEfiHddTable = (LEGACY_EFI_HDD_TABLE *) AllocateZeroPool ((UINTN) MAX_HDD_ENTRIES * sizeof (LEGACY_EFI_HDD_TABLE));
 | |
|   ASSERT (LegacyEfiHddTable);
 | |
| 
 | |
|   Private->LegacyEfiHddTable      = LegacyEfiHddTable;
 | |
|   Private->LegacyEfiHddTableIndex = 0x00;
 | |
| 
 | |
|   //
 | |
|   // start testtest
 | |
|   //  GetTimerValue (&Ticker);
 | |
|   //
 | |
|   //  gRT->SetVariable (L"EndOfLoadFv",
 | |
|   //                    &gEfiGlobalVariableGuid,
 | |
|   //                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
 | |
|   //                    sizeof (UINT64),
 | |
|   //                    (VOID *)&Ticker
 | |
|   //                    );
 | |
|   // end testtest
 | |
|   //
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Shadow all legacy16 OPROMs that haven't been shadowed.
 | |
|   Warning: Use this with caution. This routine disconnects all EFI
 | |
|   drivers. If used externally then caller must re-connect EFI
 | |
|   drivers.
 | |
| 
 | |
|   @param  This                    Protocol instance pointer.
 | |
| 
 | |
|   @retval EFI_SUCCESS             OPROMs shadowed
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| LegacyBiosShadowAllLegacyOproms (
 | |
|   IN EFI_LEGACY_BIOS_PROTOCOL *This
 | |
|   )
 | |
| {
 | |
|   LEGACY_BIOS_INSTANCE  *Private;
 | |
| 
 | |
|   //
 | |
|   //  EFI_LEGACY_BIOS_PLATFORM_PROTOCOL    *LegacyBiosPlatform;
 | |
|   //  EFI_LEGACY16_TABLE                   *Legacy16Table;
 | |
|   //
 | |
|   Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
 | |
| 
 | |
|   //
 | |
|   //  LegacyBiosPlatform       = Private->LegacyBiosPlatform;
 | |
|   //  Legacy16Table            = Private->Legacy16Table;
 | |
|   //
 | |
|   // Shadow PCI ROMs. We must do this near the end since this will kick
 | |
|   // of Native EFI drivers that may be needed to collect info for Legacy16
 | |
|   //
 | |
|   //  WARNING: PciIo is gone after this call.
 | |
|   //
 | |
|   PciProgramAllInterruptLineRegisters (Private);
 | |
| 
 | |
|   PciShadowRoms (Private);
 | |
| 
 | |
|   //
 | |
|   // Shadow PXE base code, BIS etc.
 | |
|   //
 | |
|   //  LegacyBiosPlatform->ShadowServiceRoms (LegacyBiosPlatform,
 | |
|   //                       &Private->OptionRom,
 | |
|   //                       Legacy16Table);
 | |
|   //
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get the PCI BIOS interface version.
 | |
| 
 | |
|   @param  Private  Driver private data.
 | |
| 
 | |
|   @return The PCI interface version number in Binary Coded Decimal (BCD) format.
 | |
|           E.g.: 0x0210 indicates 2.10, 0x0300 indicates 3.00
 | |
| 
 | |
| **/
 | |
| UINT16
 | |
| GetPciInterfaceVersion (
 | |
|   IN LEGACY_BIOS_INSTANCE *Private
 | |
|   )
 | |
| {
 | |
|   EFI_IA32_REGISTER_SET Reg;
 | |
|   BOOLEAN               ThunkFailed;
 | |
|   UINT16                PciInterfaceVersion;
 | |
| 
 | |
|   PciInterfaceVersion = 0;
 | |
|   
 | |
|   Reg.X.AX = 0xB101;
 | |
|   Reg.E.EDI = 0;
 | |
| 
 | |
|   ThunkFailed = Private->LegacyBios.Int86 (&Private->LegacyBios, 0x1A, &Reg);
 | |
|   if (!ThunkFailed) {
 | |
|     //
 | |
|     // From PCI Firmware 3.0 Specification:
 | |
|     //   If the CARRY FLAG [CF] is cleared and AH is set to 00h, it is still necessary to examine the
 | |
|     //   contents of [EDX] for the presence of the string "PCI" + (trailing space) to fully validate the
 | |
|     //   presence of the PCI function set. [BX] will further indicate the version level, with enough
 | |
|     //   granularity to allow for incremental changes in the code that don't affect the function interface.
 | |
|     //   Version numbers are stored as Binary Coded Decimal (BCD) values. For example, Version 2.10
 | |
|     //   would be returned as a 02h in the [BH] registers and 10h in the [BL] registers.
 | |
|     //
 | |
|     if ((Reg.X.Flags.CF == 0) && (Reg.H.AH == 0) && (Reg.E.EDX == SIGNATURE_32 ('P', 'C', 'I', ' '))) {
 | |
|       PciInterfaceVersion = Reg.X.BX;
 | |
|     }
 | |
|   }
 | |
|   return PciInterfaceVersion;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Callback function to calculate SMBIOS table size, and allocate memory for SMBIOS table.
 | |
|   SMBIOS table will be copied into EfiReservedMemoryType memory in legacy boot path.
 | |
| 
 | |
|   @param  Event                 Event whose notification function is being invoked.
 | |
|   @param  Context               The pointer to the notification function's context,
 | |
|                                 which is implementation-dependent.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| InstallSmbiosEventCallback (
 | |
|   IN EFI_EVENT                Event,
 | |
|   IN VOID                     *Context
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                  Status;
 | |
|   SMBIOS_TABLE_ENTRY_POINT    *EntryPointStructure;
 | |
|   
 | |
|   //
 | |
|   // Get SMBIOS table from EFI configuration table
 | |
|   //
 | |
|   Status = EfiGetSystemConfigurationTable (
 | |
|             &gEfiSmbiosTableGuid,
 | |
|             &mRuntimeSmbiosEntryPoint
 | |
|             );
 | |
|   if ((EFI_ERROR (Status)) || (mRuntimeSmbiosEntryPoint == NULL)) {
 | |
|     return;
 | |
|   }
 | |
|   
 | |
|   EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *) mRuntimeSmbiosEntryPoint;
 | |
| 
 | |
|   //
 | |
|   // Allocate memory for SMBIOS Entry Point Structure.
 | |
|   // CSM framework spec requires SMBIOS table below 4GB in EFI_TO_COMPATIBILITY16_BOOT_TABLE.
 | |
|   //
 | |
|   if (mReserveSmbiosEntryPoint == 0) {
 | |
|     //
 | |
|     // Entrypoint structure with fixed size is allocated only once.
 | |
|     //
 | |
|     mReserveSmbiosEntryPoint = SIZE_4GB - 1;
 | |
|     Status = gBS->AllocatePages (
 | |
|                     AllocateMaxAddress,
 | |
|                     EfiReservedMemoryType,
 | |
|                     EFI_SIZE_TO_PAGES ((UINTN) (EntryPointStructure->EntryPointLength)),
 | |
|                     &mReserveSmbiosEntryPoint
 | |
|                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       mReserveSmbiosEntryPoint = 0;
 | |
|       return;
 | |
|     }
 | |
|     DEBUG ((EFI_D_INFO, "Allocate memory for Smbios Entry Point Structure\n"));
 | |
|   }
 | |
|   
 | |
|   if ((mStructureTableAddress != 0) && 
 | |
|       (mStructureTablePages < (UINTN) EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength))) {
 | |
|     //
 | |
|     // If original buffer is not enough for the new SMBIOS table, free original buffer and re-allocate
 | |
|     //
 | |
|     gBS->FreePages (mStructureTableAddress, mStructureTablePages);
 | |
|     mStructureTableAddress = 0;
 | |
|     mStructureTablePages   = 0;
 | |
|     DEBUG ((EFI_D_INFO, "Original size is not enough. Re-allocate the memory.\n"));
 | |
|   }
 | |
|   
 | |
|   if (mStructureTableAddress == 0) {
 | |
|     //
 | |
|     // Allocate reserved memory below 4GB.
 | |
|     // Smbios spec requires the structure table is below 4GB.
 | |
|     //
 | |
|     mStructureTableAddress = SIZE_4GB - 1;
 | |
|     mStructureTablePages   = EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength);
 | |
|     Status = gBS->AllocatePages (
 | |
|                     AllocateMaxAddress,
 | |
|                     EfiReservedMemoryType,
 | |
|                     mStructureTablePages,
 | |
|                     &mStructureTableAddress
 | |
|                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       gBS->FreePages (
 | |
|         mReserveSmbiosEntryPoint, 
 | |
|         EFI_SIZE_TO_PAGES ((UINTN) (EntryPointStructure->EntryPointLength))
 | |
|         );
 | |
|       mReserveSmbiosEntryPoint = 0;
 | |
|       mStructureTableAddress   = 0;
 | |
|       mStructureTablePages     = 0;
 | |
|       return;
 | |
|     }
 | |
|     DEBUG ((EFI_D_INFO, "Allocate memory for Smbios Structure Table\n"));
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Install Driver to produce Legacy BIOS protocol.
 | |
| 
 | |
|   @param  ImageHandle  Handle of driver image.
 | |
|   @param  SystemTable  Pointer to system table.
 | |
| 
 | |
|   @retval EFI_SUCCESS  Legacy BIOS protocol installed
 | |
|   @retval No protocol installed, unload driver.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| LegacyBiosInstall (
 | |
|   IN EFI_HANDLE           ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE     *SystemTable
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                         Status;
 | |
|   LEGACY_BIOS_INSTANCE               *Private;
 | |
|   EFI_TO_COMPATIBILITY16_INIT_TABLE  *EfiToLegacy16InitTable;
 | |
|   EFI_PHYSICAL_ADDRESS               MemoryAddress;
 | |
|   EFI_PHYSICAL_ADDRESS               EbdaReservedBaseAddress;
 | |
|   VOID                               *MemoryPtr;
 | |
|   EFI_PHYSICAL_ADDRESS               MemoryAddressUnder1MB;
 | |
|   UINTN                              Index;
 | |
|   UINT32                             *BaseVectorMaster;
 | |
|   EFI_PHYSICAL_ADDRESS               StartAddress;
 | |
|   UINT32                             *ClearPtr;
 | |
|   EFI_PHYSICAL_ADDRESS               MemStart;
 | |
|   UINT32                             IntRedirCode;
 | |
|   UINT32                             Granularity;
 | |
|   BOOLEAN                            DecodeOn;
 | |
|   UINT32                             MemorySize;
 | |
|   EFI_GCD_MEMORY_SPACE_DESCRIPTOR    Descriptor;
 | |
|   UINT64                             Length;
 | |
|   UINT8                              *SecureBoot;
 | |
|   EFI_EVENT                          InstallSmbiosEvent;
 | |
| 
 | |
|   //
 | |
|   // Load this driver's image to memory
 | |
|   //
 | |
|   Status = RelocateImageUnder4GIfNeeded (ImageHandle, SystemTable);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // When UEFI Secure Boot is enabled, CSM module will not start any more.
 | |
|   //
 | |
|   SecureBoot = NULL;
 | |
|   GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBoot, NULL);
 | |
|   if ((SecureBoot != NULL) && (*SecureBoot == SECURE_BOOT_MODE_ENABLE)) {
 | |
|     FreePool (SecureBoot);
 | |
|     return EFI_SECURITY_VIOLATION;
 | |
|   }
 | |
|   
 | |
|   if (SecureBoot != NULL) {
 | |
|     FreePool (SecureBoot);
 | |
|   }
 | |
| 
 | |
|   Private = &mPrivateData;
 | |
|   ZeroMem (Private, sizeof (LEGACY_BIOS_INSTANCE));
 | |
| 
 | |
|   //
 | |
|   // Grab a copy of all the protocols we depend on. Any error would
 | |
|   // be a dispatcher bug!.
 | |
|   //
 | |
|   Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &Private->Cpu);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   Status = gBS->LocateProtocol (&gEfiTimerArchProtocolGuid, NULL, (VOID **) &Private->Timer);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   Status = gBS->LocateProtocol (&gEfiLegacyRegion2ProtocolGuid, NULL, (VOID **) &Private->LegacyRegion);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   Status = gBS->LocateProtocol (&gEfiLegacyBiosPlatformProtocolGuid, NULL, (VOID **) &Private->LegacyBiosPlatform);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **) &Private->Legacy8259);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   Status = gBS->LocateProtocol (&gEfiLegacyInterruptProtocolGuid, NULL, (VOID **) &Private->LegacyInterrupt);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   // Locate Memory Test Protocol if exists
 | |
|   //
 | |
|   Status = gBS->LocateProtocol (
 | |
|                   &gEfiGenericMemTestProtocolGuid,
 | |
|                   NULL,
 | |
|                   (VOID **) &Private->GenericMemoryTest
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   // Make sure all memory from 0-640K is tested
 | |
|   //
 | |
|   for (StartAddress = 0; StartAddress < 0xa0000; ) {
 | |
|     gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor);
 | |
|     if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) {
 | |
|       StartAddress = Descriptor.BaseAddress + Descriptor.Length;
 | |
|       continue;
 | |
|     }
 | |
|     Length = MIN (Descriptor.Length, 0xa0000 - StartAddress);
 | |
|     Private->GenericMemoryTest->CompatibleRangeTest (
 | |
|                                   Private->GenericMemoryTest,
 | |
|                                   StartAddress,
 | |
|                                   Length
 | |
|                                   );
 | |
|     StartAddress = StartAddress + Length;
 | |
|   }
 | |
|   //
 | |
|   // Make sure all memory from 1MB to 16MB is tested and added to memory map
 | |
|   //
 | |
|   for (StartAddress = BASE_1MB; StartAddress < BASE_16MB; ) {
 | |
|     gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor);
 | |
|     if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) {
 | |
|       StartAddress = Descriptor.BaseAddress + Descriptor.Length;
 | |
|       continue;
 | |
|     }
 | |
|     Length = MIN (Descriptor.Length, BASE_16MB - StartAddress);
 | |
|     Private->GenericMemoryTest->CompatibleRangeTest (
 | |
|                                   Private->GenericMemoryTest,
 | |
|                                   StartAddress,
 | |
|                                   Length
 | |
|                                   );
 | |
|     StartAddress = StartAddress + Length;
 | |
|   }
 | |
| 
 | |
|   Private->Signature = LEGACY_BIOS_INSTANCE_SIGNATURE;
 | |
| 
 | |
|   Private->LegacyBios.Int86 = LegacyBiosInt86;
 | |
|   Private->LegacyBios.FarCall86 = LegacyBiosFarCall86;
 | |
|   Private->LegacyBios.CheckPciRom = LegacyBiosCheckPciRom;
 | |
|   Private->LegacyBios.InstallPciRom = LegacyBiosInstallPciRom;
 | |
|   Private->LegacyBios.LegacyBoot = LegacyBiosLegacyBoot;
 | |
|   Private->LegacyBios.UpdateKeyboardLedStatus = LegacyBiosUpdateKeyboardLedStatus;
 | |
|   Private->LegacyBios.GetBbsInfo = LegacyBiosGetBbsInfo;
 | |
|   Private->LegacyBios.ShadowAllLegacyOproms = LegacyBiosShadowAllLegacyOproms;
 | |
|   Private->LegacyBios.PrepareToBootEfi = LegacyBiosPrepareToBootEfi;
 | |
|   Private->LegacyBios.GetLegacyRegion = LegacyBiosGetLegacyRegion;
 | |
|   Private->LegacyBios.CopyLegacyRegion = LegacyBiosCopyLegacyRegion;
 | |
|   Private->LegacyBios.BootUnconventionalDevice = LegacyBiosBootUnconventionalDevice;
 | |
| 
 | |
|   Private->ImageHandle = ImageHandle;
 | |
| 
 | |
|   //
 | |
|   // Enable read attribute of legacy region.
 | |
|   //
 | |
|   DecodeOn = TRUE;
 | |
|   Private->LegacyRegion->Decode (
 | |
|                            Private->LegacyRegion,
 | |
|                            0xc0000,
 | |
|                            0x40000,
 | |
|                            &Granularity,
 | |
|                            &DecodeOn
 | |
|                            );
 | |
|   //
 | |
|   // Set Cachebility for legacy region
 | |
|   // BUGBUG: Comments about this legacy region cacheability setting
 | |
|   //         This setting will make D865GCHProduction CSM Unhappy
 | |
|   //
 | |
|   if (PcdGetBool (PcdLegacyBiosCacheLegacyRegion)) {
 | |
|     gDS->SetMemorySpaceAttributes (
 | |
|            0x0,
 | |
|            0xA0000,
 | |
|            EFI_MEMORY_WB
 | |
|            );
 | |
|     gDS->SetMemorySpaceAttributes (
 | |
|            0xc0000,
 | |
|            0x40000,
 | |
|            EFI_MEMORY_WB
 | |
|            );
 | |
|   }
 | |
| 
 | |
|   gDS->SetMemorySpaceAttributes (
 | |
|          0xA0000,
 | |
|          0x20000,
 | |
|          EFI_MEMORY_UC
 | |
|          );
 | |
| 
 | |
|   //
 | |
|   // Allocate 0 - 4K for real mode interupt vectors and BDA.
 | |
|   //
 | |
|   AllocateLegacyMemory (
 | |
|     AllocateAddress,
 | |
|     0,
 | |
|     1,
 | |
|     &MemoryAddress
 | |
|     );
 | |
|   ASSERT (MemoryAddress == 0x000000000);
 | |
| 
 | |
|   ClearPtr = (VOID *) ((UINTN) 0x0000);
 | |
| 
 | |
|   //
 | |
|   // Initialize region from 0x0000 to 4k. This initializes interrupt vector
 | |
|   // range.
 | |
|   //
 | |
|   gBS->SetMem ((VOID *) ClearPtr, 0x400, INITIAL_VALUE_BELOW_1K);
 | |
|   ZeroMem ((VOID *) ((UINTN)ClearPtr + 0x400), 0xC00);
 | |
| 
 | |
|   //
 | |
|   // Allocate pages for OPROM usage
 | |
|   //
 | |
|   MemorySize = PcdGet32 (PcdEbdaReservedMemorySize);
 | |
|   ASSERT ((MemorySize & 0xFFF) == 0);
 | |
| 
 | |
|   Status = AllocateLegacyMemory (
 | |
|              AllocateAddress,
 | |
|              CONVENTIONAL_MEMORY_TOP - MemorySize,
 | |
|              EFI_SIZE_TO_PAGES (MemorySize),
 | |
|              &MemoryAddress
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   ZeroMem ((VOID *) ((UINTN) MemoryAddress), MemorySize);
 | |
| 
 | |
|   //
 | |
|   // Allocate all 32k chunks from 0x60000 ~ 0x88000 for Legacy OPROMs that
 | |
|   // don't use PMM but look for zeroed memory. Note that various non-BBS
 | |
|   // OpROMs expect different areas to be free
 | |
|   //
 | |
|   EbdaReservedBaseAddress = MemoryAddress;
 | |
|   MemoryAddress = PcdGet32 (PcdOpromReservedMemoryBase);
 | |
|   MemorySize    = PcdGet32 (PcdOpromReservedMemorySize);
 | |
|   //
 | |
|   // Check if base address and size for reserved memory are 4KB aligned.
 | |
|   //
 | |
|   ASSERT ((MemoryAddress & 0xFFF) == 0);
 | |
|   ASSERT ((MemorySize & 0xFFF) == 0);
 | |
|   //
 | |
|   // Check if the reserved memory is below EBDA reserved range.
 | |
|   //
 | |
|   ASSERT ((MemoryAddress < EbdaReservedBaseAddress) && ((MemoryAddress + MemorySize - 1) < EbdaReservedBaseAddress));
 | |
|   for (MemStart = MemoryAddress; MemStart < MemoryAddress + MemorySize; MemStart += 0x1000) {
 | |
|     Status = AllocateLegacyMemory (
 | |
|                AllocateAddress,
 | |
|                MemStart,
 | |
|                1,
 | |
|                &StartAddress
 | |
|                );
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       MemoryPtr = (VOID *) ((UINTN) StartAddress);
 | |
|       ZeroMem (MemoryPtr, 0x1000);
 | |
|     } else {
 | |
|       DEBUG ((EFI_D_ERROR, "WARNING: Allocate legacy memory fail for SCSI card - %x\n", MemStart));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Allocate low PMM memory and zero it out
 | |
|   //
 | |
|   MemorySize = PcdGet32 (PcdLowPmmMemorySize);
 | |
|   ASSERT ((MemorySize & 0xFFF) == 0);  
 | |
|   Status = AllocateLegacyMemory (
 | |
|              AllocateMaxAddress,
 | |
|              CONVENTIONAL_MEMORY_TOP,
 | |
|              EFI_SIZE_TO_PAGES (MemorySize),
 | |
|              &MemoryAddressUnder1MB
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   ZeroMem ((VOID *) ((UINTN) MemoryAddressUnder1MB), MemorySize);
 | |
| 
 | |
|   //
 | |
|   // Allocate space for thunker and Init Thunker
 | |
|   //
 | |
|   Status = AllocateLegacyMemory (
 | |
|              AllocateMaxAddress,
 | |
|              CONVENTIONAL_MEMORY_TOP,
 | |
|              (sizeof (LOW_MEMORY_THUNK) / EFI_PAGE_SIZE) + 2,
 | |
|              &MemoryAddress
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
|   Private->IntThunk                   = (LOW_MEMORY_THUNK *) (UINTN) MemoryAddress;
 | |
|   EfiToLegacy16InitTable                   = &Private->IntThunk->EfiToLegacy16InitTable;
 | |
|   EfiToLegacy16InitTable->ThunkStart       = (UINT32) (EFI_PHYSICAL_ADDRESS) (UINTN) MemoryAddress;
 | |
|   EfiToLegacy16InitTable->ThunkSizeInBytes = (UINT32) (sizeof (LOW_MEMORY_THUNK));
 | |
| 
 | |
|   Status = LegacyBiosInitializeThunk (Private);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   // Init the legacy memory map in memory < 1 MB.
 | |
|   //
 | |
|   EfiToLegacy16InitTable->BiosLessThan1MB         = (UINT32) MemoryAddressUnder1MB;
 | |
|   EfiToLegacy16InitTable->LowPmmMemory            = (UINT32) MemoryAddressUnder1MB;
 | |
|   EfiToLegacy16InitTable->LowPmmMemorySizeInBytes = MemorySize;
 | |
| 
 | |
|   MemorySize = PcdGet32 (PcdHighPmmMemorySize);
 | |
|   ASSERT ((MemorySize & 0xFFF) == 0);
 | |
|   //
 | |
|   // Allocate high PMM Memory under 16 MB
 | |
|   //   
 | |
|   Status = AllocateLegacyMemory (
 | |
|              AllocateMaxAddress,
 | |
|              0x1000000,
 | |
|              EFI_SIZE_TO_PAGES (MemorySize),
 | |
|              &MemoryAddress
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // If it fails, allocate high PMM Memory under 4GB
 | |
|     //   
 | |
|     Status = AllocateLegacyMemory (
 | |
|                AllocateMaxAddress,
 | |
|                0xFFFFFFFF,
 | |
|                EFI_SIZE_TO_PAGES (MemorySize),
 | |
|                &MemoryAddress
 | |
|                );    
 | |
|   }
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     EfiToLegacy16InitTable->HiPmmMemory            = (UINT32) (EFI_PHYSICAL_ADDRESS) (UINTN) MemoryAddress;
 | |
|     EfiToLegacy16InitTable->HiPmmMemorySizeInBytes = MemorySize;
 | |
|   } 
 | |
| 
 | |
|   //
 | |
|   //  ShutdownAPs();
 | |
|   //
 | |
|   // Start the Legacy BIOS;
 | |
|   //
 | |
|   Status = ShadowAndStartLegacy16 (Private);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // Initialize interrupt redirection code and entries;
 | |
|   // IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f.
 | |
|   //
 | |
|   CopyMem (
 | |
|          Private->IntThunk->InterruptRedirectionCode,
 | |
|          (VOID *) (UINTN) InterruptRedirectionTemplate,
 | |
|          sizeof (Private->IntThunk->InterruptRedirectionCode)
 | |
|          );
 | |
| 
 | |
|   //
 | |
|   // Save Unexpected interrupt vector so can restore it just prior to boot
 | |
|   //
 | |
|   BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
 | |
|   Private->BiosUnexpectedInt = BaseVectorMaster[0];
 | |
|   IntRedirCode = (UINT32) (UINTN) Private->IntThunk->InterruptRedirectionCode;
 | |
|   for (Index = 0; Index < 8; Index++) {
 | |
|     BaseVectorMaster[Index] = (EFI_SEGMENT (IntRedirCode + Index * 4) << 16) | EFI_OFFSET (IntRedirCode + Index * 4);
 | |
|   }
 | |
|   //
 | |
|   // Save EFI value
 | |
|   //
 | |
|   Private->ThunkSeg = (UINT16) (EFI_SEGMENT (IntRedirCode));
 | |
|   
 | |
|   //
 | |
|   // Allocate reserved memory for SMBIOS table used in legacy boot if SMBIOS table exists
 | |
|   //
 | |
|   InstallSmbiosEventCallback (NULL, NULL);
 | |
| 
 | |
|   //
 | |
|   // Create callback function to update the size of reserved memory after LegacyBiosDxe starts
 | |
|   //
 | |
|   Status = gBS->CreateEventEx (
 | |
|                   EVT_NOTIFY_SIGNAL,
 | |
|                   TPL_NOTIFY,
 | |
|                   InstallSmbiosEventCallback,
 | |
|                   NULL,
 | |
|                   &gEfiSmbiosTableGuid,
 | |
|                   &InstallSmbiosEvent
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);  
 | |
| 
 | |
|   //
 | |
|   // Make a new handle and install the protocol
 | |
|   //
 | |
|   Private->Handle = NULL;
 | |
|   Status = gBS->InstallProtocolInterface (
 | |
|                   &Private->Handle,
 | |
|                   &gEfiLegacyBiosProtocolGuid,
 | |
|                   EFI_NATIVE_INTERFACE,
 | |
|                   &Private->LegacyBios
 | |
|                   );
 | |
|   Private->Csm16PciInterfaceVersion = GetPciInterfaceVersion (Private);
 | |
|   
 | |
|   DEBUG ((EFI_D_INFO, "CSM16 PCI BIOS Interface Version: %02x.%02x\n", 
 | |
|           (UINT8) (Private->Csm16PciInterfaceVersion >> 8), 
 | |
|           (UINT8) Private->Csm16PciInterfaceVersion
 | |
|         ));
 | |
|   ASSERT (Private->Csm16PciInterfaceVersion != 0);
 | |
|   return Status;
 | |
| }
 |