mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-26 05:30:48 +00:00 
			
		
		
		
	 aa5f60ae41
			
		
	
	
		aa5f60ae41
		
	
	
	
	
		
			
			There are cases that the operands of an expression are all with rank less
than UINT64/INT64 and the result of the expression is explicitly cast to
UINT64/INT64 to fit the target size.
An example will be:
UINT32 a,b;
// a and b can be any unsigned int type with rank less than UINT64, like
// UINT8, UINT16, etc.
UINT64 c;
c = (UINT64) (a + b);
Some static code checkers may warn that the expression result might
overflow within the rank of "int" (integer promotions) and the result is
then cast to a bigger size.
The commit refines codes by the following rules:
1). When the expression is possible to overflow the range of unsigned int/
int:
c = (UINT64)a + b;
2). When the expression will not overflow within the rank of "int", remove
the explicit type casts:
c = a + b;
3). When the expression will be cast to pointer of possible greater size:
UINT32 a,b;
VOID *c;
c = (VOID *)(UINTN)(a + b); --> c = (VOID *)((UINTN)a + b);
4). When one side of a comparison expression contains only operands with
rank less than UINT32:
UINT8 a;
UINT16 b;
UINTN c;
if ((UINTN)(a + b) > c) {...} --> if (((UINT32)a + b) > c) {...}
For rule 4), if we remove the 'UINTN' type cast like:
if (a + b > c) {...}
The VS compiler will complain with warning C4018 (signed/unsigned
mismatch, level 3 warning) due to promoting 'a + b' to type 'int'.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Hao Wu <hao.a.wu@intel.com>
Reviewed-by: Jeff Fan <jeff.fan@intel.com>
		
	
			
		
			
				
	
	
		
			963 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			963 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Helper Routines that use a PXE-enabled NIC option ROM.
 | |
|  
 | |
| Copyright (c) 1999 - 2017, 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 "BiosSnp16.h"
 | |
| 
 | |
| #define TO_SEGMENT(x)   ((UINT16) (RShiftU64 ((UINT32)(UINTN) (x), 4) & 0xF000))
 | |
| #define TO_OFFSET(x)    ((UINT16) ((UINT32)(UINTN) (x) & 0xFFFF))
 | |
| #define PARAGRAPH_SIZE  0x10
 | |
| #define IVT_BASE        0x00000000
 | |
| 
 | |
| #pragma pack(1)
 | |
| typedef struct {
 | |
|   UINT16  Signature;          ///< 0xaa55
 | |
|   UINT8   ROMlength;          ///< size of this ROM in 512 byte blocks
 | |
|   UINT8   InitEntryPoint[4];  ///< a jump to the initialization routine
 | |
|   UINT8   Reserved[0xf];      ///< various
 | |
|   UINT16  PxeRomIdOffset;     ///< offset of UNDI, $BC$, or BUSD ROM ID structure
 | |
|   UINT16  PcirHeaderOffset;   ///< offset of PCI Expansion Header
 | |
|   UINT16  PnpHeaderOffset;    ///< offset of Plug and Play Expansion Header
 | |
| } OPTION_ROM_HEADER;
 | |
| #pragma pack()
 | |
| 
 | |
| UINT32 CachedVectorAddress[0x100];
 | |
| 
 | |
| /**
 | |
|  Cache Interrupt verctor address converted from IVT number.
 | |
| 
 | |
|  @param VectorNumber  IVT number
 | |
|  
 | |
|  @retval EFI_SUCCESS Success to operation.
 | |
| **/
 | |
| EFI_STATUS
 | |
| CacheVectorAddress (
 | |
|   UINT8   VectorNumber
 | |
|   )
 | |
| {
 | |
|   UINT32  *Address;
 | |
| 
 | |
|   Address                          = (UINT32 *) ((UINTN) IVT_BASE + VectorNumber * 4);
 | |
|   CachedVectorAddress[VectorNumber] = *Address;
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  Get interrupt vector address according to IVT number. 
 | |
|   
 | |
|  @param VectorNumber    Given IVT number
 | |
|  
 | |
|  @return cached interrupt vector address.
 | |
| **/
 | |
| EFI_STATUS
 | |
| RestoreCachedVectorAddress (
 | |
|   UINT8   VectorNumber
 | |
|   )
 | |
| {
 | |
|   UINT32  *Address;
 | |
| 
 | |
|   Address  = (UINT32 *) ((UINTN) IVT_BASE + VectorNumber * 4);
 | |
|   *Address = CachedVectorAddress[VectorNumber];
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  Print Undi loader table. 
 | |
| 
 | |
|  @param UndiLoaderStructure Point to Undi Loader table structure. 
 | |
|  
 | |
| **/
 | |
| VOID
 | |
| Print_Undi_Loader_Table (
 | |
|   VOID *UndiLoaderStructure
 | |
|   )
 | |
| {
 | |
|   UNDI_LOADER_T *DisplayPointer;
 | |
| 
 | |
|   DisplayPointer = (UNDI_LOADER_T *) UndiLoaderStructure;
 | |
| 
 | |
|   DEBUG ((DEBUG_NET, "Before Parsing the table contents, the table itself lives\n"));
 | |
|   DEBUG ((DEBUG_NET, "\tat the address 0x%X\n\r", (UINT32)(UINTN) UndiLoaderStructure));
 | |
| 
 | |
|   DEBUG ((DEBUG_NET, "\n\rStatus = 0x%X\n\r", DisplayPointer->Status));
 | |
|   DEBUG ((DEBUG_NET, "\t_AX_= 0x%X\n\r", DisplayPointer->Ax));
 | |
|   DEBUG ((DEBUG_NET, "\t_BX_= 0x%X\n\r", DisplayPointer->Bx));
 | |
|   DEBUG ((DEBUG_NET, "\t_DX_= 0x%X\n\r", DisplayPointer->Dx));
 | |
|   DEBUG ((DEBUG_NET, "\t_DI_= 0x%X\n\r", DisplayPointer->Di));
 | |
|   DEBUG ((DEBUG_NET, "\t_ES_= 0x%X\n\r", DisplayPointer->Es));
 | |
|   DEBUG ((DEBUG_NET, "\tUNDI_DS= 0x%X\n\r", DisplayPointer->Undi_Ds));
 | |
|   DEBUG ((DEBUG_NET, "\tUNDI_CS= 0x%X\n\r", DisplayPointer->Undi_Cs));
 | |
|   DEBUG ((DEBUG_NET, "\tPXEptr:SEG= 0x%X\n\r", (UINT16) DisplayPointer->PXEptr.Segment));
 | |
|   DEBUG ((DEBUG_NET, "\tPXEptr:OFF= 0x%X\n\r", (UINT16) DisplayPointer->PXEptr.Offset));
 | |
|   DEBUG ((DEBUG_NET, "\tPXENVptr:SEG= 0x%X\n\r", (UINT16) DisplayPointer->PXENVptr.Segment));
 | |
|   DEBUG ((DEBUG_NET, "\tPXENVptr:OFF= 0x%X\n\r", (UINT16) DisplayPointer->PXENVptr.Offset));
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Simple table dumper.  The ROMID table is necessary in order to effect
 | |
|   the "Early UNDI" trick.  Herein, the UNDI layer can be loaded in the
 | |
|   pre-boot phase without having to download a Network Boot Program 
 | |
|   across the wire.  It is required in the implementation in that we
 | |
|   are not using PXE.
 | |
| 
 | |
|   @param RomIDStructure Point to RomID structure.
 | |
|  
 | |
| **/
 | |
| VOID
 | |
| Print_ROMID_Table (
 | |
|   IN VOID *RomIDStructure
 | |
|   )
 | |
| {
 | |
|   UNDI_ROMID_T  *DisplayPointer;
 | |
| 
 | |
|   DisplayPointer = (UNDI_ROMID_T *) RomIDStructure;
 | |
| 
 | |
|   DEBUG ((DEBUG_NET, "Before Parsing the table contents, the table itself lives\n"));
 | |
|   DEBUG ((DEBUG_NET, "\tat the address 0x%X\n\r", (UINT32)(UINTN) RomIDStructure));
 | |
| 
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "\n\rROMID %c%c%c%c\n\r",
 | |
|     DisplayPointer->Signature[0],
 | |
|     DisplayPointer->Signature[1],
 | |
|     DisplayPointer->Signature[2],
 | |
|     DisplayPointer->Signature[3])
 | |
|     );
 | |
| 
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "Length of this structure in bytes = 0x%X\n\r",
 | |
|     DisplayPointer->StructLength)
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "Use to make byte checksum of this structure == zero is = 0x%X\n\r",
 | |
|     DisplayPointer->StructCksum)
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "Structure format revision number= 0x%X\n\r",
 | |
|     DisplayPointer->StructRev)
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "API Revision number = 0x%X 0x%X 0x%X\n\r",
 | |
|     DisplayPointer->UNDI_Rev[0],
 | |
|     DisplayPointer->UNDI_Rev[1],
 | |
|     DisplayPointer->UNDI_Rev[2])
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "Offset of UNDI loader routine in the option ROM image= 0x%X\n\r",
 | |
|     DisplayPointer->UNDI_Loader)
 | |
|     );
 | |
|   DEBUG ((DEBUG_NET, "From the data above, the absolute entry point of the UNDI loader is\n\r"));
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "\tat address 0x%X\n\r",
 | |
|     (UINT32) (DisplayPointer->UNDI_Loader + ((UINT32) (UINTN)(DisplayPointer - 0x20) & 0xFFFF0)))
 | |
|     );
 | |
|   DEBUG ((DEBUG_NET, "Minimum stack segment size, in bytes,\n\r"));
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "needed to load and run the UNDI= 0x%X \n\r",
 | |
|     DisplayPointer->StackSize)
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "UNDI runtime code and data = 0x%X\n\r",
 | |
|     DisplayPointer->DataSize)
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "Segment size = 0x%X\n\r",
 | |
|     DisplayPointer->CodeSize)
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "\n\rBus Type =  %c%c%c%c\n\r",
 | |
|     DisplayPointer->BusType[0],
 | |
|     DisplayPointer->BusType[1],
 | |
|     DisplayPointer->BusType[2],
 | |
|     DisplayPointer->BusType[3])
 | |
|     );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Print PXE table.
 | |
| 
 | |
|   @param PxeTable Point to PXE table structure
 | |
|   
 | |
| **/
 | |
| VOID
 | |
| Print_PXE_Table (
 | |
|   IN VOID*  PxeTable
 | |
|   )
 | |
| {
 | |
|   PXE_T *DisplayPointer;
 | |
|   UINTN Index;
 | |
|   UINT8 *Dptr;
 | |
| 
 | |
|   DisplayPointer  = (PXE_T *) PxeTable;
 | |
|   Dptr            = (UINT8 *) PxeTable;
 | |
| 
 | |
|   DEBUG ((DEBUG_NET, "This is the PXE table at address 0x%X\n\r", PxeTable));
 | |
| 
 | |
|   DEBUG ((DEBUG_NET, "A dump of the 0x%X bytes is:\n\r", sizeof (PXE_T)));
 | |
| 
 | |
|   for (Index = 0; Index < sizeof (PXE_T); Index++) {
 | |
|     if ((Index % 0x10) == 0) {
 | |
|       DEBUG ((DEBUG_NET, "\t\n\r"));
 | |
|     }
 | |
| 
 | |
|     DEBUG ((DEBUG_NET, " 0x%X  ", *Dptr++));
 | |
|   }
 | |
| 
 | |
|   DEBUG ((DEBUG_NET, "\n\r"));
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "\n\rPXE %c%c%c%c%c%c\n\r",
 | |
|     DisplayPointer->Signature[0],
 | |
|     DisplayPointer->Signature[1],
 | |
|     DisplayPointer->Signature[2],
 | |
|     DisplayPointer->Signature[3])
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "Length of this structure in bytes = 0x%X\n\r",
 | |
|     DisplayPointer->StructLength)
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "Use to make byte checksum of this  structure == zero is = 0x%X\n\r",
 | |
|     DisplayPointer->StructCksum)
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "Structure format revision number = 0x%X\n\r",
 | |
|     DisplayPointer->StructRev)
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "Must be zero, is equal to 0x%X\n\r",
 | |
|     DisplayPointer->Reserved1)
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "Far pointer to UNDI ROMID = 0x%X\n\r",
 | |
|     (UINT32) (DisplayPointer->Undi.Segment << 0x4 | DisplayPointer->Undi.Offset))
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "Far pointer to base-code ROMID = 0x%X\n\r",
 | |
|     (UINT32) ((DisplayPointer->Base.Segment << 0x04) | DisplayPointer->Base.Offset))
 | |
|     );
 | |
|   DEBUG ((DEBUG_NET, "16bit stack segment API entry point.  This will be seg:off in \n\r"));
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "real mode and sel:off in 16:16 protected mode = 0x%X:0x%X\n\r",
 | |
|     DisplayPointer->EntryPointSP.Segment,
 | |
|     DisplayPointer->EntryPointSP.Offset)
 | |
|     );
 | |
| 
 | |
|   DEBUG ((DEBUG_NET, "\n\tNOTE to the implementer\n\tThis is the entry to use for call-ins\n\r"));
 | |
| 
 | |
|   DEBUG ((DEBUG_NET, "32bit stack Segment API entry point.  This will be sel:off. \n\r"));
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "In real mode, sel == 0 = 0x%X:0x%X\n\r",
 | |
|     DisplayPointer->EntryPointESP.Segment,
 | |
|     DisplayPointer->EntryPointESP.Offset)
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "Reserved2 value, must be zero, is equal to 0x%X\n\r",
 | |
|     DisplayPointer->Reserved2)
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "Number of segment descriptors in this structur = 0x%X\n\r",
 | |
|     (UINT8) DisplayPointer->SegDescCnt)
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "First segment descriptor in GDT assigned to PXE = 0x%X\n\r",
 | |
|     (UINT16) DisplayPointer->FirstSelector)
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "The Stack is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
 | |
|     (UINT16) DisplayPointer->Stack.Seg_Addr,
 | |
|     (UINT32) DisplayPointer->Stack.Phy_Addr,
 | |
|     (UINT16) DisplayPointer->Stack.Seg_Size)
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "The UNDIData is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
 | |
|     (UINT16) DisplayPointer->UNDIData.Seg_Addr,
 | |
|     (UINT32) DisplayPointer->UNDIData.Phy_Addr,
 | |
|     (UINT16) DisplayPointer->UNDIData.Seg_Size)
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "The UNDICodeWrite is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
 | |
|     (UINT16) DisplayPointer->UNDICode.Seg_Addr,
 | |
|     (UINT32) DisplayPointer->UNDICode.Phy_Addr,
 | |
|     (UINT16) DisplayPointer->UNDICode.Seg_Size)
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "The Stack is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
 | |
|     (UINT16) DisplayPointer->UNDICodeWrite.Seg_Addr,
 | |
|     (UINT32) DisplayPointer->UNDICodeWrite.Phy_Addr,
 | |
|     (UINT16) DisplayPointer->UNDICodeWrite.Seg_Size)
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "The BC_Data is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
 | |
|     (UINT16) DisplayPointer->BC_Data.Seg_Addr,
 | |
|     (UINT32) DisplayPointer->BC_Data.Phy_Addr,
 | |
|     (UINT16) DisplayPointer->BC_Data.Seg_Size)
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "The BC_Code is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
 | |
|     (UINT16) DisplayPointer->BC_Code.Seg_Addr,
 | |
|     (UINT32) DisplayPointer->BC_Code.Phy_Addr,
 | |
|     (UINT16) DisplayPointer->BC_Code.Seg_Size)
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "The BC_CodeWrite is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
 | |
|     (UINT16) DisplayPointer->BC_CodeWrite.Seg_Addr,
 | |
|     (UINT32) DisplayPointer->BC_CodeWrite.Phy_Addr,
 | |
|     (UINT16) DisplayPointer->BC_CodeWrite.Seg_Size)
 | |
|     );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Print PXENV table.
 | |
| 
 | |
|   @param PxenvTable Point to PXENV
 | |
|   
 | |
| **/
 | |
| VOID
 | |
| Print_PXENV_Table (
 | |
|   IN VOID *PxenvTable
 | |
|   )
 | |
| {
 | |
|   PXENV_T *DisplayPointer;
 | |
| 
 | |
|   DisplayPointer = (PXENV_T *) PxenvTable;
 | |
| 
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "\n\rPXENV+ %c%c%c%c%c%c\n\r",
 | |
|     DisplayPointer->Signature[0],
 | |
|     DisplayPointer->Signature[1],
 | |
|     DisplayPointer->Signature[2],
 | |
|     DisplayPointer->Signature[3],
 | |
|     DisplayPointer->Signature[4],
 | |
|     DisplayPointer->Signature[5])
 | |
|     );
 | |
| 
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "PXE version number.  \n\r\tLSB is minor version.  \n\r\tMSB is major version = 0x%X\n\r",
 | |
|     DisplayPointer->Version)
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "Length of PXE-2.0 Entry Point structure in bytes = 0x%X\n\r",
 | |
|     DisplayPointer->StructLength)
 | |
|     );
 | |
|   DEBUG ((DEBUG_NET, "Used to make structure checksum equal zero is now = 0x%X\n\r", DisplayPointer->StructCksum));
 | |
|   DEBUG ((DEBUG_NET, "Real mode API entry point  segment:Offset.  = 0x%X\n\r", DisplayPointer->RMEntry));
 | |
|   DEBUG ((DEBUG_NET, "Protected mode API entry point = 0x%X\n\r", DisplayPointer->PMEntryOff));
 | |
|   DEBUG ((DEBUG_NET, " segment:Offset.  This will always be zero.  \n\r"));
 | |
|   DEBUG ((DEBUG_NET, "Protected mode API calls = 0x%X\n\r", DisplayPointer->PMEntrySeg));
 | |
|   DEBUG ((DEBUG_NET, "Real mode stack segment = 0x%X\n\r", DisplayPointer->StackSeg));
 | |
|   DEBUG ((DEBUG_NET, "Stack segment size in bytes = 0x%X\n\r", DisplayPointer->StackSize));
 | |
|   DEBUG ((DEBUG_NET, "Real mode base-code code segment = 0x%X\n\r", DisplayPointer->BaseCodeSeg));
 | |
|   DEBUG ((DEBUG_NET, "Base-code code segment size = 0x%X\n\r", DisplayPointer->BaseCodeSize));
 | |
|   DEBUG ((DEBUG_NET, "Real mode base-code data segment = 0x%X\n\r", DisplayPointer->BaseDataSeg));
 | |
|   DEBUG ((DEBUG_NET, "Base-code data segment size = 0x%X\n\r", DisplayPointer->BaseDataSize));
 | |
| 
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "UNDI code segment size in bytes = 0x%X\n\r",
 | |
|     DisplayPointer->UNDICodeSize)
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "Real mode segment:Offset pointer \n\r\tto PXE Runtime ID structure, address = 0x%X\n\r",
 | |
|     DisplayPointer->RuntimePtr)
 | |
|     );
 | |
|   DEBUG (
 | |
|     (
 | |
|     DEBUG_NET,
 | |
|     "From above, we have a linear address of 0x%X\n\r",
 | |
|     (UINT32)
 | |
|     (
 | |
|     ((UINT32)(UINTN)(DisplayPointer->RuntimePtr) & 0xFFFF) +
 | |
|     (((UINT32)(UINTN)(DisplayPointer->RuntimePtr) & 0xFFFF0000) >> 12)
 | |
|     )
 | |
|     )
 | |
|     );
 | |
| }
 | |
| 
 | |
| 
 | |
| #define OPTION_ROM_PTR  ((OPTION_ROM_HEADER *) RomAddress)
 | |
| 
 | |
| /**
 | |
|   If available, launch the BaseCode from a NIC option ROM.
 | |
|   This should install the !PXE and PXENV+ structures in memory for
 | |
|   subsequent use.
 | |
|   
 | |
| 
 | |
|   @param SimpleNetworkDevice    Simple network device instance
 | |
|   @param RomAddress             The ROM base address for NIC rom.
 | |
|   
 | |
|   @retval EFI_NOT_FOUND         The check sum does not match 
 | |
|   @retval EFI_NOT_FOUND         Rom ID offset is wrong 
 | |
|   @retval EFI_NOT_FOUND         No Rom ID structure is found 
 | |
| **/
 | |
| EFI_STATUS
 | |
| LaunchBaseCode (
 | |
|   EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice,
 | |
|   UINTN                   RomAddress
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS            Status;
 | |
|   EFI_IA32_REGISTER_SET InOutRegs;
 | |
|   UNDI_ROMID_T          *RomIdTableAddress;
 | |
|   UNDI_LOADER_T         *UndiLoaderTable;
 | |
|   UINT16                Segment;
 | |
|   UINT16                *StackPointer;
 | |
|   VOID                  *Buffer;
 | |
|   UINTN                 Size;
 | |
|   PXE_T                 *Pxe;
 | |
|   UINT32                RomLength;
 | |
|   UINTN                 PciSegment;
 | |
|   UINTN                 Bus;
 | |
|   UINTN                 Device;
 | |
|   UINTN                 Function;
 | |
|   BOOLEAN               ThunkFailed;
 | |
| 
 | |
|   DEBUG ((DEBUG_NET, "\n\r\n\rCheck for the UNDI ROMID Signature\n\r"));
 | |
| 
 | |
|   //
 | |
|   // paranoia - check structures for validity
 | |
|   //
 | |
|   RomLength = OPTION_ROM_PTR->ROMlength << 9;
 | |
|   if (CalculateSum8 ((UINT8 *) RomAddress, RomLength) != 0) {
 | |
|     DEBUG ((DEBUG_ERROR, "ROM Header Checksum Error\n\r"));
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   RomIdTableAddress = (UNDI_ROMID_T *) (RomAddress + OPTION_ROM_PTR->PxeRomIdOffset);
 | |
| 
 | |
|   if (((UINT32)OPTION_ROM_PTR->PxeRomIdOffset + RomIdTableAddress->StructLength) > RomLength) {
 | |
|     DEBUG ((DEBUG_ERROR, "ROM ID Offset Error\n\r"));
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
|   //
 | |
|   // see if this is a header for an UNDI ROM ID structure (vs. a $BC$ or BUSD type)
 | |
|   //
 | |
|   if (CompareMem (RomIdTableAddress->Signature, UNDI_ROMID_SIG, sizeof RomIdTableAddress->Signature) != 0) {
 | |
|     DEBUG ((DEBUG_ERROR, "No ROM ID Structure found....\n\r"));
 | |
|     return EFI_NOT_FOUND;
 | |
|     //
 | |
|     // its not - keep looking
 | |
|     //
 | |
|   }
 | |
| 
 | |
|   if (CalculateSum8 ((UINT8 *) RomIdTableAddress, RomIdTableAddress->StructLength) != 0) {
 | |
|     DEBUG ((DEBUG_ERROR, "ROM ID Checksum Error\n\r"));
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   Print_ROMID_Table (RomIdTableAddress);
 | |
| 
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "The ROM ID is located at 0x%X\n\r",
 | |
|     RomIdTableAddress)
 | |
|     );
 | |
| 
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "With an UNDI Loader located at 0x%X\n\r",
 | |
|     RomAddress + RomIdTableAddress->UNDI_Loader)
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // found an UNDI ROM ID structure
 | |
|   //
 | |
|   SimpleNetworkDevice->Nii.ImageAddr  = RomAddress;
 | |
|   SimpleNetworkDevice->Nii.ImageSize  = RomLength;
 | |
|   SimpleNetworkDevice->Nii.MajorVer   = RomIdTableAddress->UNDI_Rev[2];
 | |
|   SimpleNetworkDevice->Nii.MinorVer   = RomIdTableAddress->UNDI_Rev[1];
 | |
| 
 | |
|   DEBUG ((DEBUG_NET, "Allocate area for the UNDI_LOADER_T structure\n\r"));
 | |
|   //
 | |
|   // Allocate 1 page below 1MB to put real mode thunk code in
 | |
|   //
 | |
|   // Undi Loader Table is a PXE Specification prescribed data structure
 | |
|   // that is used to transfer information into and out of the Undi layer.
 | |
|   // Note how it must be located below 1 MB.
 | |
|   //
 | |
|   SimpleNetworkDevice->UndiLoaderTablePages = EFI_SIZE_TO_PAGES (PARAGRAPH_SIZE + sizeof (UNDI_LOADER_T));
 | |
|   Status = BiosSnp16AllocatePagesBelowOneMb (
 | |
|             SimpleNetworkDevice->UndiLoaderTablePages,
 | |
|             &SimpleNetworkDevice->UndiLoaderTable
 | |
|             );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   UndiLoaderTable = SimpleNetworkDevice->UndiLoaderTable;
 | |
| 
 | |
|   DEBUG ((DEBUG_NET, "Allocate area for the real-mode stack whose sole purpose\n\r"));
 | |
|   DEBUG ((DEBUG_NET, "in life right now is to store a SEG:OFFSET combo pair that\n\r"));
 | |
|   DEBUG ((DEBUG_NET, "points to an Undi_Loader_t table structure\n\r"));
 | |
| 
 | |
|   Size    = 0x100;
 | |
|   Status  = gBS->AllocatePool (EfiLoaderData, Size, &Buffer);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // Now we want to put a pointer to the Under Loader Table in our MemPage
 | |
|   // Buffer.  This will be the argument stack for the call into the Undi Loader
 | |
|   //
 | |
|   StackPointer    = (UINT16 *) Buffer;
 | |
|   *StackPointer++ = TO_OFFSET (UndiLoaderTable);
 | |
|   //
 | |
|   // push the OFFSET
 | |
|   //
 | |
|   *StackPointer++ = TO_SEGMENT (UndiLoaderTable);
 | |
|   //
 | |
|   // push the SEGMENT
 | |
|   //
 | |
|   StackPointer = (UINT16 *) Buffer;
 | |
|   //
 | |
|   // reset the stack pointer
 | |
|   //
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "After the fixups, the stack pointer is 0x%X\n\r",
 | |
|     (UINT64)(UINTN) StackPointer)
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // Allocate memory for the Deployed UNDI.
 | |
|   // The UNDI is essentially telling us how much space it needs, and
 | |
|   // it is up to the EFI driver to allocate sufficient, boot-time
 | |
|   // persistent resources for the call
 | |
|   //
 | |
|   SimpleNetworkDevice->DestinationDataSegmentPages = EFI_SIZE_TO_PAGES (RomIdTableAddress->DataSize);
 | |
|   Status = BiosSnp16AllocatePagesBelowOneMb (
 | |
|             SimpleNetworkDevice->DestinationDataSegmentPages,
 | |
|             &SimpleNetworkDevice->DestinationDataSegment
 | |
|             );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   UndiLoaderTable->Undi_Ds = (UINT16) ((UINTN) SimpleNetworkDevice->DestinationDataSegment >> 4);
 | |
| 
 | |
|   //
 | |
|   // Allocate memory for the Deployed UNDI stack
 | |
|   // The UNDI is essentially telling us how much space it needs, and
 | |
|   // it is up to the EFI driver to allocate sufficient, boot-time
 | |
|   // persistent resources for the call
 | |
|   //
 | |
|   SimpleNetworkDevice->DestinationStackSegmentPages = EFI_SIZE_TO_PAGES (RomIdTableAddress->StackSize);
 | |
|   Status = BiosSnp16AllocatePagesBelowOneMb (
 | |
|             SimpleNetworkDevice->DestinationStackSegmentPages,
 | |
|             &SimpleNetworkDevice->DestinationStackSegment
 | |
|             );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // Allocate memory for the Deployed UNDI.
 | |
|   // The UNDI is essentially telling us how much space it needs, and
 | |
|   // it is up to the EFI driver to allocate sufficient, boot-time
 | |
|   // persistent resources for the call
 | |
|   //
 | |
|   SimpleNetworkDevice->DestinationCodeSegmentPages = EFI_SIZE_TO_PAGES (RomIdTableAddress->CodeSize);
 | |
|   Status = BiosSnp16AllocatePagesBelowOneMb (
 | |
|             SimpleNetworkDevice->DestinationCodeSegmentPages,
 | |
|             &SimpleNetworkDevice->DestinationCodeSegment
 | |
|             );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   UndiLoaderTable->Undi_Cs = (UINT16) ((UINTN) SimpleNetworkDevice->DestinationCodeSegment >> 4);
 | |
| 
 | |
|   //
 | |
|   // these are in the Input and Output Parameter to be sent to the UNDI Loader code
 | |
|   //
 | |
|   UndiLoaderTable->Status = 0xAA55;
 | |
|   //
 | |
|   // -------------------- Changed by Michael_Huang@3Com.com -----------------
 | |
|   // UndiLoaderTable->_AX is AX value when UNDI ROM is initialized by BIOS, it is the PCI bus device
 | |
|   // function of the NIC. Please refer to PXE Spec for detail info.
 | |
|   // old code is:
 | |
|   // UndiLoaderTable->Ax       = 0x0;
 | |
|   // -----------------------------------------------------------------------
 | |
|   //
 | |
|   SimpleNetworkDevice->PciIo->GetLocation (
 | |
|                                 SimpleNetworkDevice->PciIo,
 | |
|                                 &PciSegment,
 | |
|                                 &Bus,
 | |
|                                 &Device,
 | |
|                                 &Function
 | |
|                                 );
 | |
|   UndiLoaderTable->Ax = (UINT16) ((Bus << 0x8) | (Device << 0x3) | (Function));
 | |
|   UndiLoaderTable->Bx = 0x0;
 | |
|   UndiLoaderTable->Dx = 0x0;
 | |
|   UndiLoaderTable->Di = 0x0;
 | |
|   UndiLoaderTable->Es = 0x0;
 | |
| 
 | |
|   //
 | |
|   // set these OUT values to zero in order to ensure that
 | |
|   // uninitialized memory is not mistaken for display data
 | |
|   //
 | |
|   UndiLoaderTable->PXEptr.Offset    = 0;
 | |
|   UndiLoaderTable->PXEptr.Segment   = 0;
 | |
|   UndiLoaderTable->PXENVptr.Segment = 0;
 | |
|   UndiLoaderTable->PXENVptr.Offset  = 0;
 | |
| 
 | |
|   DEBUG (
 | |
|     (DEBUG_INIT,
 | |
|     "The NIC is located at Bus 0x%X, Device 0x%X, Function 0x%X\n\r",
 | |
|     Bus,
 | |
|     Device,
 | |
|     Function)
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // These are the values that set up the ACTUAL IA32 machine state, whether in
 | |
|   // Real16 in EFI32 or the IVE for IA64
 | |
|   // register values are unused except for CS:IP and SS:SP
 | |
|   //
 | |
|   InOutRegs.X.AX  = 0;
 | |
|   InOutRegs.X.BX  = 0;
 | |
|   InOutRegs.X.CX  = 0;
 | |
|   InOutRegs.X.DX  = 0;
 | |
|   InOutRegs.X.SI  = 0;
 | |
|   InOutRegs.X.DI  = 0;
 | |
|   InOutRegs.X.BP  = 0;
 | |
|   InOutRegs.X.DS  = 0;
 | |
|   InOutRegs.X.ES  = 0;
 | |
|   //
 | |
|   // just to be clean
 | |
|   //
 | |
|   DEBUG ((DEBUG_NET, "The way this game works is that the SS:SP +4 should point\n\r"));
 | |
|   DEBUG ((DEBUG_NET, "to the contents of the UndiLoaderTable\n\r"));
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "The Undi Loader Table is at address = 0x%X\n\r",
 | |
|     (UINT32)(UINTN) UndiLoaderTable)
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "The segment and offsets are 0x%X and 0x%X, resp\n",
 | |
|     TO_SEGMENT (UndiLoaderTable),
 | |
|     TO_OFFSET (UndiLoaderTable))
 | |
|     );
 | |
| 
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "The Linear Address of the UNDI Loader entry is 0x%X\n",
 | |
|     RomAddress + RomIdTableAddress->UNDI_Loader)
 | |
|     );
 | |
| 
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "The Address offset of the UNDI Loader entry is 0x%X\n",
 | |
|     RomIdTableAddress->UNDI_Loader)
 | |
|     );
 | |
| 
 | |
|   DEBUG ((DEBUG_NET, "Before the call, we have...\n\r"));
 | |
|   Print_Undi_Loader_Table (UndiLoaderTable);
 | |
| 
 | |
|   Segment = ((UINT16) (RShiftU64 (RomAddress, 4) & 0xFFFF));
 | |
|   DEBUG ((DEBUG_NET, "The Segment of the call is 0x%X\n\r", Segment));
 | |
| 
 | |
|   //
 | |
|   // make the call into the UNDI Code
 | |
|   //
 | |
|   DEBUG ((DEBUG_INIT, "Make the call into the UNDI code now\n\r"));
 | |
| 
 | |
|   DEBUG ((DEBUG_NET, "\nThe 20-BIt address of the Call, and the location \n\r"));
 | |
|   DEBUG ((DEBUG_NET, "\twhere we should be able to set a breakpoint is \n\r"));
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "\t\t0x%X, from SEG:OFF 0x%X:0x%X\n\r\n\r",
 | |
|     Segment * 0x10 + RomIdTableAddress->UNDI_Loader,
 | |
|     Segment,
 | |
|     RomIdTableAddress->UNDI_Loader)
 | |
|     );
 | |
| 
 | |
|   ThunkFailed = SimpleNetworkDevice->LegacyBios->FarCall86 (
 | |
|                                                    SimpleNetworkDevice->LegacyBios,
 | |
|                                                    Segment,  // Input segment
 | |
|                                                    (UINT16) RomIdTableAddress->UNDI_Loader,  // Offset
 | |
|                                                    &InOutRegs,                               // Ptr to Regs
 | |
|                                                    Buffer,                                   // Reference to Stack
 | |
|                                                    Size                                      // Size of the Stack
 | |
|                                                    );
 | |
|   if (ThunkFailed) {
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
| 
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "The return code UndiLoaderTable->Status is = 0x%X\n\r",
 | |
|     UndiLoaderTable->Status)
 | |
|     );
 | |
|   DEBUG (
 | |
|     (DEBUG_NET,
 | |
|     "This error code should match eax, which is = 0x%X\n\r",
 | |
|     InOutRegs.X.AX)
 | |
|     );
 | |
| 
 | |
|   if ((UndiLoaderTable->Status != 0) || (InOutRegs.X.AX != PXENV_EXIT_SUCCESS)) {
 | |
|     DEBUG ((DEBUG_NET, "LaunchBaseCode exits with error, RomAddress = 0x%X\n\r", RomAddress));
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
| 
 | |
|   DEBUG ((DEBUG_NET, "Now returned from the UNDI code\n\r"));
 | |
| 
 | |
|   DEBUG ((DEBUG_NET, "After the call, we have...\n\r"));
 | |
|   Print_Undi_Loader_Table (UndiLoaderTable);
 | |
| 
 | |
|   DEBUG ((DEBUG_NET, "Display the PXENV+ and !PXE tables exported by NIC\n\r"));
 | |
|   Print_PXENV_Table ((VOID *)(((UINTN)UndiLoaderTable->PXENVptr.Segment << 4) | UndiLoaderTable->PXENVptr.Offset));
 | |
|   Print_PXE_Table ((VOID *)(((UINTN)UndiLoaderTable->PXEptr.Segment << 4) + UndiLoaderTable->PXEptr.Offset));
 | |
| 
 | |
|   Pxe = (PXE_T *)(((UINTN)UndiLoaderTable->PXEptr.Segment << 4) + UndiLoaderTable->PXEptr.Offset);
 | |
|   SimpleNetworkDevice->Nii.Id = (UINT64)(UINTN) Pxe;
 | |
| 
 | |
|   gBS->FreePool (Buffer);
 | |
| 
 | |
|   //
 | |
|   // paranoia - make sure a valid !PXE structure
 | |
|   //
 | |
|   if (CompareMem (Pxe->Signature, PXE_SIG, sizeof Pxe->Signature) != 0) {
 | |
|     DEBUG ((DEBUG_ERROR, "!PXE Structure not found....\n\r"));
 | |
|     return EFI_NOT_FOUND;
 | |
|     //
 | |
|     // its not - keep looking
 | |
|     //
 | |
|   }
 | |
| 
 | |
|   if (CalculateSum8 ((UINT8 *) Pxe, Pxe->StructLength) != 0) {
 | |
|     DEBUG ((DEBUG_ERROR, "!PXE Checksum Error\n\r"));
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   if (Pxe->StructLength < (UINT8 *) &Pxe->FirstSelector - (UINT8 *) Pxe->Signature) {
 | |
|     DEBUG ((DEBUG_ERROR, "!PXE Length Error\n\r"));
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   if ((((UINTN) Pxe->Undi.Segment) << 4) + Pxe->Undi.Offset != (UINTN) RomIdTableAddress) {
 | |
|     DEBUG ((DEBUG_ERROR, "!PXE RomId Address Error\n\r"));
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
|   //
 | |
|   // This is the magic to bind the global PXE interface
 | |
|   // This dirtiness is for non-protocol shrouded access
 | |
|   //
 | |
|   SimpleNetworkDevice->PxeEntrySegment = Pxe->EntryPointSP.Segment;
 | |
| 
 | |
|   if (SimpleNetworkDevice->PxeEntrySegment == 0) {
 | |
|     DEBUG ((DEBUG_ERROR, "!PXE EntryPointSP segment Error\n\r"));
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   SimpleNetworkDevice->PxeEntryOffset = Pxe->EntryPointSP.Offset;
 | |
| 
 | |
|   DEBUG (
 | |
|     (
 | |
|     DEBUG_NET, "The entry point is 0x%X:0x%X\n\r", SimpleNetworkDevice->PxeEntrySegment, SimpleNetworkDevice->
 | |
|     PxeEntryOffset
 | |
|     )
 | |
|     );
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Effect the Far Call into the PXE Layer
 | |
| 
 | |
|   Note: When using a 32-bit stack segment do not push 32-bit words onto the stack. The PXE API
 | |
|   services will not work, unless there are three 16-bit parameters pushed onto the stack.
 | |
|       push DS                                 ;Far pointer to parameter structure
 | |
|       push offset pxe_data_call_struct        ;is pushed onto stack.
 | |
|       push Index                              ;UINT16 is pushed onto stack.
 | |
|       call dword ptr (s_PXE ptr es:[di]).EntryPointSP
 | |
|       add sp, 6 ;Caller cleans up stack.  
 | |
| 
 | |
|   @param SimpleNetworkDevice    Device instance for simple network
 | |
|   @param Table                 Point to parameter/retun value table for legacy far call
 | |
|   @param TableSize              The size of parameter/return value table
 | |
|   @param CallIndex              The index of legacy call.
 | |
|   
 | |
|   @return EFI_STATUS 
 | |
| **/
 | |
| EFI_STATUS
 | |
| MakePxeCall (
 | |
|   EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice,
 | |
|   IN OUT VOID             *Table,
 | |
|   IN UINTN                TableSize,
 | |
|   IN UINT16               CallIndex
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS            Status;
 | |
|   EFI_IA32_REGISTER_SET InOutRegs;
 | |
|   UINT16                *BPtr;
 | |
|   VOID                  *Buffer;
 | |
|   UINTN                 Size;
 | |
|   VOID                  *MemPageAddress;
 | |
|   UINTN                 Index;
 | |
|   BOOLEAN               ThunkFailed;
 | |
| 
 | |
|   DEBUG ((DEBUG_NET, "MakePxeCall(CallIndex = %02x, Table = %X, TableSize = %d)\n", CallIndex, Table, TableSize));
 | |
| 
 | |
|   if (SimpleNetworkDevice->PxeEntrySegment == 0 && SimpleNetworkDevice->PxeEntryOffset == 0) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
| 
 | |
|   //
 | |
|   // Allocate a transient data structure for the argument table
 | |
|   // This table needs to have the input XXX_t structure copied into here.
 | |
|   // The PXE UNDI can only grab this table when it's below one-MB, and
 | |
|   // this implementation will not try to push this table on the stack
 | |
|   // (although this is a possible optimization path since EFI always allocates
 | |
|   // 4K as a minimum page size...............)
 | |
|   //
 | |
|   Status = BiosSnp16AllocatePagesBelowOneMb (
 | |
|             TableSize / EFI_PAGE_SIZE + 1,
 | |
|             &MemPageAddress
 | |
|             );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // Copy the > 1MB pool table to a sub-1MB buffer
 | |
|   //
 | |
|   CopyMem (MemPageAddress, Table, TableSize);
 | |
| 
 | |
|   //
 | |
|   // Allocate space for IA-32 register context
 | |
|   //
 | |
|   ZeroMem (&InOutRegs, sizeof (InOutRegs));
 | |
|   InOutRegs.X.ES  = SimpleNetworkDevice->PxeEntrySegment;
 | |
|   InOutRegs.X.DI  = SimpleNetworkDevice->PxeEntryOffset;
 | |
| 
 | |
|   //
 | |
|   // The game here is to build the stack which will subsequently
 | |
|   // get copied down below 1 MB by the FarCall primitive.
 | |
|   // This is now our working stack
 | |
|   //
 | |
|   Size = 6;
 | |
|   Status = gBS->AllocatePool (
 | |
|                   EfiRuntimeServicesData,
 | |
|                   Size,
 | |
|                   &Buffer
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   BPtr    = (UINT16 *) Buffer;
 | |
|   *BPtr++ = CallIndex;
 | |
|   //
 | |
|   // SP + 2
 | |
|   //
 | |
|   *BPtr++ = TO_OFFSET (MemPageAddress);
 | |
|   *BPtr++ = TO_SEGMENT (MemPageAddress);
 | |
| 
 | |
|   DEBUG ((DEBUG_NET, "State before FarCall86\n"));
 | |
|   DEBUG ((DEBUG_NET, "The Buffer is at 0x%X\n\r", Buffer));
 | |
|   BPtr = (UINT16 *) Buffer;
 | |
|   DEBUG ((DEBUG_NET, "  Buffer  = %04X %04X %04X", *BPtr, *(BPtr + 1), *(BPtr + 2)));
 | |
|   DEBUG ((DEBUG_NET, "  MemPage = "));
 | |
|   for (Index = 0; Index < TableSize; Index++) {
 | |
|     DEBUG ((DEBUG_NET, " %02x", *((UINT8 *) MemPageAddress + Index)));
 | |
|   }
 | |
| 
 | |
|   DEBUG ((DEBUG_NET, "\n"));
 | |
| 
 | |
|   ThunkFailed = SimpleNetworkDevice->LegacyBios->FarCall86 (
 | |
|                                                    SimpleNetworkDevice->LegacyBios,
 | |
|                                                    SimpleNetworkDevice->PxeEntrySegment, // Input segment
 | |
|                                                    SimpleNetworkDevice->PxeEntryOffset,
 | |
|                                                    &InOutRegs,                           // Ptr to Regs
 | |
|                                                    Buffer,                               // Reference to Stack
 | |
|                                                    6                                     // Size of the Stack
 | |
|                                                    );
 | |
|   if (ThunkFailed) {
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
| 
 | |
|   DEBUG ((DEBUG_NET, "State after FarCall86\n"));
 | |
|   DEBUG ((DEBUG_NET, "The Buffer is at 0x%X\n\r", Buffer));
 | |
|   BPtr = (UINT16 *) Buffer;
 | |
|   DEBUG ((DEBUG_NET, "  Buffer  = %04X %04X %04X", *BPtr, *(BPtr + 1), *(BPtr + 2)));
 | |
|   DEBUG ((DEBUG_NET, "  MemPage = "));
 | |
|   for (Index = 0; Index < TableSize; Index++) {
 | |
|     DEBUG ((DEBUG_NET, " %02x", *((UINT8 *) MemPageAddress + Index)));
 | |
|   }
 | |
| 
 | |
|   DEBUG ((DEBUG_NET, "\n"));
 | |
| 
 | |
|   //
 | |
|   // Copy the sub 1MB table to > 1MB table
 | |
|   //
 | |
|   CopyMem (Table, MemPageAddress, TableSize);
 | |
| 
 | |
|   //
 | |
|   // For PXE UNDI call, AX contains the return status.
 | |
|   // Convert the PXE UNDI Status to EFI_STATUS type
 | |
|   //
 | |
|   if (InOutRegs.X.AX == PXENV_EXIT_SUCCESS) {
 | |
|     Status = EFI_SUCCESS;
 | |
|   } else {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|   }
 | |
|   //
 | |
|   // Clean up house
 | |
|   //
 | |
|   gBS->FreePool (Buffer);
 | |
|   gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) MemPageAddress, TableSize / EFI_PAGE_SIZE + 1);
 | |
| 
 | |
|   return Status;
 | |
| }
 |