/** @file
Helper Routines that use a PXE-enabled NIC option ROM.
Copyright (c) 1999 - 2010, 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
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"
#pragma pack(1)
typedef struct {
#pragma pack()
/**
Cache Interrupt verctor address converted from IVT number.
@param VectorNumber IVT number
@retval EFI_SUCCESS Success to operation.
**/
)
{
return EFI_SUCCESS;
}
/**
Get interrupt vector address according to IVT number.
@param VectorNumber Given IVT number
@return cached interrupt vector address.
**/
)
{
return EFI_SUCCESS;
}
/**
Print Undi loader table.
@param UndiLoaderStructure Point to Undi Loader table structure.
**/
)
{
}
/**
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.
**/
)
{
DEBUG (
"\n\rROMID %c%c%c%c\n\r",
DisplayPointer->Signature[0],
);
DEBUG (
"Length of this structure in bytes = 0x%X\n\r",
);
DEBUG (
"Use to make byte checksum of this structure == zero is = 0x%X\n\r",
);
DEBUG (
"Structure format revision number= 0x%X\n\r",
);
DEBUG (
"API Revision number = 0x%X 0x%X 0x%X\n\r",
DisplayPointer->UNDI_Rev[0],
);
DEBUG (
"Offset of UNDI loader routine in the option ROM image= 0x%X\n\r",
);
DEBUG (
"\tat address 0x%X\n\r",
);
DEBUG (
"needed to load and run the UNDI= 0x%X \n\r",
);
DEBUG (
"UNDI runtime code and data = 0x%X\n\r",
);
DEBUG (
"Segment size = 0x%X\n\r",
);
DEBUG (
"\n\rBus Type = %c%c%c%c\n\r",
DisplayPointer->BusType[0],
);
}
/**
Print PXE table.
@param PxeTable Point to PXE table structure
**/
)
{
if ((Index % 0x10) == 0) {
}
}
DEBUG (
"\n\rPXE %c%c%c%c%c%c\n\r",
DisplayPointer->Signature[0],
);
DEBUG (
"Length of this structure in bytes = 0x%X\n\r",
);
DEBUG (
"Use to make byte checksum of this structure == zero is = 0x%X\n\r",
);
DEBUG (
"Structure format revision number = 0x%X\n\r",
);
DEBUG (
"Must be zero, is equal to 0x%X\n\r",
);
DEBUG (
"Far pointer to UNDI ROMID = 0x%X\n\r",
);
DEBUG (
"Far pointer to base-code ROMID = 0x%X\n\r",
);
DEBUG (
"real mode and sel:off in 16:16 protected mode = 0x%X:0x%X\n\r",
);
DEBUG (
"In real mode, sel == 0 = 0x%X:0x%X\n\r",
);
DEBUG (
"Reserved2 value, must be zero, is equal to 0x%X\n\r",
);
DEBUG (
"Number of segment descriptors in this structur = 0x%X\n\r",
);
DEBUG (
"First segment descriptor in GDT assigned to PXE = 0x%X\n\r",
);
DEBUG (
"The Stack is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
);
DEBUG (
"The UNDIData is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
);
DEBUG (
"The UNDICodeWrite is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
);
DEBUG (
"The Stack is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
);
DEBUG (
"The BC_Data is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
);
DEBUG (
"The BC_Code is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
);
DEBUG (
"The BC_CodeWrite is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
);
}
/**
Print PXENV table.
@param PxenvTable Point to PXENV
**/
)
{
DEBUG (
"\n\rPXENV+ %c%c%c%c%c%c\n\r",
DisplayPointer->Signature[0],
);
DEBUG (
"PXE version number. \n\r\tLSB is minor version. \n\r\tMSB is major version = 0x%X\n\r",
);
DEBUG (
"Length of PXE-2.0 Entry Point structure in bytes = 0x%X\n\r",
);
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 (
"UNDI code segment size in bytes = 0x%X\n\r",
);
DEBUG (
"Real mode segment:Offset pointer \n\r\tto PXE Runtime ID structure, address = 0x%X\n\r",
);
DEBUG (
(
"From above, we have a linear address of 0x%X\n\r",
(UINT32)
(
)
)
);
}
/**
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
**/
)
{
//
// paranoia - check structures for validity
//
return EFI_NOT_FOUND;
}
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) {
return EFI_NOT_FOUND;
//
// its not - keep looking
//
}
return EFI_NOT_FOUND;
}
DEBUG (
"The ROM ID is located at 0x%X\n\r",
);
DEBUG (
"With an UNDI Loader located at 0x%X\n\r",
);
//
// found an UNDI ROM ID structure
//
//
// 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));
);
return EFI_OUT_OF_RESOURCES;
}
Size = 0x100;
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
//
//
// push the OFFSET
//
//
// push the SEGMENT
//
//
// reset the stack pointer
//
DEBUG (
"After the fixups, the stack pointer is 0x%X\n\r",
);
//
// 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
//
);
return Status;
}
//
// 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);
);
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
//
);
return Status;
}
//
// these are in the Input and Output Parameter to be sent to the UNDI Loader code
//
//
// -------------------- 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;
// -----------------------------------------------------------------------
//
&Bus,
&Device,
);
//
// set these OUT values to zero in order to ensure that
// uninitialized memory is not mistaken for display data
//
DEBUG (
"The NIC is located at Bus 0x%X, Device 0x%X, Function 0x%X\n\r",
Bus,
);
//
// 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
//
//
// just to be clean
//
DEBUG (
"The Undi Loader Table is at address = 0x%X\n\r",
);
DEBUG (
"The segment and offsets are 0x%X and 0x%X, resp\n",
);
DEBUG (
"The Linear Address of the UNDI Loader entry is 0x%X\n",
);
DEBUG (
"The Address offset of the UNDI Loader entry is 0x%X\n",
);
//
// make the call into the UNDI Code
//
DEBUG (
"\t\t0x%X, from SEG:OFF 0x%X:0x%X\n\r\n\r",
);
Segment, // Input segment
&InOutRegs, // Ptr to Regs
Buffer, // Reference to Stack
Size // Size of the Stack
);
if (ThunkFailed) {
return EFI_ABORTED;
}
DEBUG (
"The return code UndiLoaderTable->Status is = 0x%X\n\r",
);
DEBUG (
"This error code should match eax, which is = 0x%X\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));
//
// FreePool (Buffer);
// paranoia - make sure a valid !PXE structure
//
return EFI_NOT_FOUND;
//
// its not - keep looking
//
}
return EFI_NOT_FOUND;
}
return EFI_NOT_FOUND;
}
return EFI_NOT_FOUND;
}
//
// This is the magic to bind the global PXE interface
// This dirtiness is for non-protocol shrouded access
//
if (SimpleNetworkDevice->PxeEntrySegment == 0) {
return EFI_NOT_FOUND;
}
DEBUG (
(
DEBUG_NET, "The entry point is 0x%X:0x%X\n\r", SimpleNetworkDevice->PxeEntrySegment, SimpleNetworkDevice->
)
);
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 CallIndex The index of legacy call.
@return EFI_STATUS
**/
)
{
DEBUG ((DEBUG_NET, "MakePxeCall(CallIndex = %02x, Table = %X, TableSize = %d)\n", CallIndex, Table, TableSize));
return EFI_DEVICE_ERROR;
}
//
// 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...............)
//
);
return Status;
}
//
// Copy the > 1MB pool table to a sub-1MB buffer
//
//
// Allocate space for IA-32 register context
//
//
// 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;
Size,
);
return Status;
}
//
// SP + 2
//
}
&InOutRegs, // Ptr to Regs
Buffer, // Reference to Stack
6 // Size of the Stack
);
if (ThunkFailed) {
return EFI_ABORTED;
}
}
//
// Copy the sub 1MB table to > 1MB table
//
//
// For PXE UNDI call, AX contains the return status.
// Convert the PXE UNDI Status to EFI_STATUS type
//
} else {
}
//
// Clean up house
//
return Status;
}