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